Merge "mfd: timpani-codec: Making AUXPGA gain register as uncacheable" into msm-3.0
diff --git a/Documentation/arm/msm/tz_log.txt b/Documentation/arm/msm/tz_log.txt
new file mode 100644
index 0000000..280865d
--- /dev/null
+++ b/Documentation/arm/msm/tz_log.txt
@@ -0,0 +1,132 @@
+Introduction:
+=============
+
+The tz_log driver is a platform device driver that exposes a debugfs
+interface for accessing and displaying diagnostic information related
+to secure code (Trustzone).
+
+The Secure code (Trustzone) will store the diagnostic data in 4KB of
+IMEM. The address of this IMEM region varies from platform. The
+diagnostic data encodes information related to secure code boot-up,
+reset, interrupt and other attributes in a specific format as shown
+below:
+
+ ----------------------------
+ | |
+ | General info |
+ | (Magic #, CPU cnt etc) |
+ | |
+ ----------------------------
+ | |
+ | VMID info |
+ | |
+ ----------------------------
+ | |
+ | Boot info (per CPU) |
+ | |
+ ----------------------------
+ | |
+ | Reset info (per CPU) |
+ | |
+ ----------------------------
+ | |
+ | Interrupt info (per CPU) |
+ | |
+ ----------------------------
+ | |
+ | Data logged by TZ |
+ | |
+ ----------------------------
+
+During the initialization of the driver module, this 4KB of IMEM
+is remapped for access by kernel. Further more, an additonal 4KB
+memory is allocated for storing the formatted data that will be
+displayed by the debugfs interface.
+
+Once the device is booted up and HLOS is up, the standard debugfs
+interface is used to read out and display this information that
+was logged in by secure code in a specific format as shown below.
+
+Debugfs is typically mounted with a command like:
+ mount -t debugfs none /sys/kernel/debug
+(Or an equivalent /etc/fstab line).
+
+Note that the debugfs API is exported GPL-only to modules.
+
+Software description
+====================
+
+The tz_log module is a Linux platform device driver with a debugfs
+interface. The goal of this module is to provide a way to peek into
+the Trustzone diagnostic information to help debug issues with
+Trustzone. Although, this tz_log platform device driver will be
+compiled into the kernel, the debugfs entries will not be exposed
+unless Trustzone is supported by the platform.
+
+
+On loading the tz_log driver, tzdbgfs_init() is invoked. tzdbgfs_init()
+initializes the tz_log debugfs interface. The following is done in
+this initialization call.
+
+(1) Create a directory "tzdbg", to hold a set of debugfs files
+
+(2) Create the following debugfs files in the "tzdbg" directory
+- boot_info
+ Contains information on the warm boot jump address
+- reset_info
+ Contains information on the cause of a CPU reset, number of
+ resets occurred on a specific CPU
+- interrupt_info
+ Contains information on the number of IRQ and FIQ Interrupts
+ (with a brief description), interrupts fired and the number
+ of times it is fired on a specific CPU.
+- general_info
+ Contains information on number of CPUs supported, magic number,
+ version number.
+- vmid_info
+ Contains information on VMID supported, with a brief description
+- log
+ Debug information (ASCII text) that is logged by Trustzone
+
+Following are the set of file operation defines and register
+- read()
+- open()
+
+(3) Remap the IMEM region where the secure code diagnostic information
+is stored.
+
+(4) Allocate 4KB buffer for storing the formatted information
+to be displayed
+
+When the tz_log driver is unloaded the tz_log debugfs entries are
+explicitly removed.
+
+
+Power Management
+================
+
+n/a
+
+Security
+========
+
+None
+
+Interface
+=========
+
+This module will create debugfs files under sys/kernel/debug which
+contains information that can be displayed by using the "cat" command.
+
+
+Dependencies
+============
+
+This driver interacts with Trustzone operating environment, thus depends
+on the TZBSP supported architecture. It also depends on debugfs.
+
+
+To do
+=====
+
+TBD
diff --git a/Documentation/devicetree/bindings/mmc/msm_sdcc.txt b/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
new file mode 100644
index 0000000..4fb653e
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
@@ -0,0 +1,40 @@
+Qualcomm Secure Digital Card Controller (SDCC)
+
+Secure Digital Card Controller provides host interface to
+SD/MMC/SDIO cards.
+
+Required properties:
+ - compatible : should be "qcom,msm-sdcc"
+ - reg : should contain SDCC, BAM register map.
+ - interrupts : should contain SDCC core interrupt.
+ - qcom,sdcc-clk-rates : specifies supported SDCC clock frequencies, Units - Hz.
+ - qcom,sdcc-sup-voltages: specifies supported voltage ranges for card. Should always be
+ specified in pairs (min, max), Units - mV.
+
+Optional Properties:
+ - cell-index - defines slot ID.
+ - qcom,sdcc-bus-width - defines the bus I/O width that controller supports.
+ - qcom,sdcc-wp-gpio - defines write protect switch gpio.
+ - qcom,sdcc-wp-polarity - specifies the polarity of wp switch.
+ - qcom,sdcc-cd-gpio - defines card detect gpio number.
+ - qcom,sdcc-cd-polarity - specifies the polarity of cd gpio.
+ - qcom,sdcc-nonremovable - specifies whether the card in slot is
+ hot pluggable or hard wired.
+ - qcom,sdcc-disable_cmd23 - disable sending CMD23 to card when controller can't support it.
+
+Example:
+
+ qcom,sdcc@F9600000 {
+ /* SDC1 used as eMMC slot */
+ cell-index = <1>;
+ compatible = "qcom,msm-sdcc";
+ reg = <0xF9600000 0x800 // SDCC register interface
+ 0xF9600800 0x1800 // DML register interface
+ 0xF9602000 0x2000> // BAM register interface
+
+ interrupts = <123>;
+ qcom,sdcc-clk-rates = <400000 24000000 48000000>;
+ qcom,sdcc-sup-voltages = <2700 3300>;
+ qcom,sdcc-bus-width = <8>; //8-bit wide
+ qcom,sdcc-nonremovable;
+};
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
new file mode 100644
index 0000000..c1399ae
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -0,0 +1,51 @@
+MSM SoC HSUSB controllers
+
+OTG:
+
+Required properties :
+- compatible : should be "qcom,hsusb-otg"
+- regs : offset and length of the register set in the memory map
+- interrupts: IRQ line
+- qcom,hsusb-otg-phy-type: PHY type can be one of
+ 1 - Chipidea 45nm PHY
+ 2 - Synopsis 28nm PHY
+- qcom,hsusb-otg-mode: Operational mode. Can be one of
+ 1 - Peripheral only mode
+ 2 - Host only mode
+ 3 - OTG mode
+ Based on the mode, OTG driver registers platform devices for
+ gadget and host.
+- qcom,hsusb-otg-control: OTG control (VBUS and ID notifications)
+ can be one of
+ 1 - PHY control
+ 2 - PMIC control
+ 3 - User control (via debugfs)
+
+Optional properties :
+- qcom,hsusb-otg-default-mode: The default USB mode after boot-up.
+ Applicable only when OTG is controlled by user. Can be one of
+ 0 - None. Low power mode
+ 1 - Peripheral
+ 2 - Host
+- qcom,hsusb-otg-phy-init-seq: PHY configuration sequence. val, reg pairs
+ terminate with -1
+- qcom,hsusb-otg-power-budget: VBUS power budget in mA
+ 0 will be treated as 500mA
+- qcom,hsusb-otg-pclk-src-name: The source of pclk
+- qcom,hsusb-otg-pmic-id-irq: ID, routed to PMIC IRQ number
+
+Example HSUSB OTG controller device node :
+ usb@F9690000 {
+ compatible = "qcom,hsusb-otg";
+ reg = <0xF9690000 0x400>;
+ interrupts = <134>;
+
+ qcom,hsusb-otg-phy-type = <2>;
+ qcom,hsusb-otg-mode = <1>;
+ qcom,hsusb-otg-otg-control = <1>;
+ qcom,hsusb-otg-default-mode = <2>;
+ qcom,hsusb-otg-phy-init-seq = <0x01 0x90 0xFFFFFFFF>;
+ qcom,hsusb-otg-power-budget = <500>;
+ qcom,hsusb-otg-pclk-src-name = "dfab_usb_clk";
+ qcom,hsusb-otg-pmic-id-irq = <47>
+ };
diff --git a/Documentation/genlock.txt b/Documentation/genlock.txt
new file mode 100644
index 0000000..d3a44e2
--- /dev/null
+++ b/Documentation/genlock.txt
@@ -0,0 +1,161 @@
+Introduction
+
+'genlock' is an in-kernel API and optional userspace interface for a generic
+cross-process locking mechanism. The API is designed for situations where
+multiple user space processes and/or kernel drivers need to coordinate access
+to a shared resource, such as a graphics buffer. The API was designed with
+graphics buffers in mind, but is sufficiently generic to allow it to be
+independently used with different types of resources. The chief advantage
+of genlock over other cross-process locking mechanisms is that the resources
+can be accessed by both userspace and kernel drivers which allows resources
+to be locked or unlocked by asynchronous events in the kernel without the
+intervention of user space.
+
+As an example, consider a graphics buffer that is shared between a rendering
+application and a compositing window manager. The application renders into a
+buffer. That buffer is reused by the compositing window manager as a texture.
+To avoid corruption, access to the buffer needs to be restricted so that one
+is not drawing on the surface while the other is reading. Locks can be
+explicitly added between the rendering stages in the processes, but explicit
+locks require that the application wait for rendering and purposely release the
+lock. An implicit release triggered by an asynchronous event from the GPU
+kernel driver, however, will let execution continue without requiring the
+intercession of user space.
+
+SW Goals
+
+The genlock API implements exclusive write locks and shared read locks meaning
+that there can only be one writer at a time, but multiple readers. Processes
+that are unable to acquire a lock can be optionally blocked until the resource
+becomes available.
+
+Locks are shared between processes. Each process will have its own private
+instance for a lock known as a handle. Handles can be shared between user
+space and kernel space to allow a kernel driver to unlock or lock a buffer
+on behalf of a user process.
+
+Kernel API
+
+Access to the genlock API can either be via the in-kernel API or via an
+optional character device (/dev/genlock). The character device is primarily
+to be used for legacy resource sharing APIs that cannot be easily changed.
+New resource sharing APIs from this point should implement a scheme specific
+wrapper for locking.
+
+To create or attach to an existing lock, a process or kernel driver must first
+create a handle. Each handle is linked to a single lock at any time. An entityi
+may have multiple handles, each associated with a different lock. Once a handle
+has been created, the owner may create a new lock or attach an existing lock
+that has been exported from a different handle.
+
+Once the handle has a lock attached, the owning process may attempt to lock the
+buffer for read or write. Write locks are exclusive, meaning that only one
+process may acquire it at any given time. Read locks are shared, meaning that
+multiple readers can hold the lock at the same time. Attempts to acquire a read
+lock with a writer active or a write lock with one or more readers or writers
+active will typically cause the process to block until the lock is acquired.
+When the lock is released, all waiting processes will be woken up. Ownership
+of the lock is reference counted, meaning that any one owner can "lock"
+multiple times. The lock will only be released from the owner when all the
+references to the lock are released via unlock.
+
+The owner of a write lock may atomically convert the lock into a read lock
+(which will wake up other processes waiting for a read lock) without first
+releasing the lock. The owner would simply issue a new request for a read lock.
+However, the owner of a read lock cannot convert it into a write lock in the
+same manner. To switch from a read lock to a write lock, the owner must
+release the lock and then try to reacquire it.
+
+These are the in-kernel API calls that drivers can use to create and
+manipulate handles and locks. Handles can either be created and managed
+completely inside of kernel space, or shared from user space via a file
+descriptor.
+
+* struct genlock_handle *genlock_get_handle(void)
+Create a new handle.
+
+* struct genlock_handle * genlock_get_handle_fd(int fd)
+Given a valid file descriptor, return the handle associated with that
+descriptor.
+
+* void genlock_put_handle(struct genlock_handle *)
+Release a handle.
+
+* struct genlock * genlock_create_lock(struct genlock_handle *)
+Create a new lock and attach it to the handle.
+
+* struct genlock * genlock_attach_lock(struct genlock_handle *handle, int fd)
+Given a valid file descriptor, get the lock associated with it and attach it to
+the handle.
+
+* void genlock_release_lock(struct genlock_handle *)
+Release a lock attached to a handle.
+
+* int genlock_lock(struct genlock_handle *, int op, int flags, u32 timeout)
+Lock or unlock the lock attached to the handle. A zero timeout value will
+be treated just like if the GENOCK_NOBLOCK flag is passed; if the lock
+can be acquired without blocking then do so otherwise return -EAGAIN.
+Function returns -ETIMEDOUT if the timeout expired or 0 if the lock was
+acquired.
+
+* int genlock_wait(struct genloc_handle *, u32 timeout)
+Wait for a lock held by the handle to go to the unlocked state. A non-zero
+timeout value must be passed. Returns -ETIMEDOUT if the timeout expired or
+0 if the lock is in an unlocked state.
+
+Character Device
+
+Opening an instance to the /dev/genlock character device will automatically
+create a new handle. All ioctl functions with the exception of NEW and
+RELEASE use the following parameter structure:
+
+struct genlock_lock {
+ int fd; /* Returned by EXPORT, used by ATTACH */
+ int op; /* Used by LOCK */
+ int flags; /* used by LOCK */
+ u32 timeout; /* Used by LOCK and WAIT */
+}
+
+*GENLOCK_IOC_NEW
+Create a new lock and attaches it to the handle. Returns -EINVAL if the handle
+already has a lock attached (use GENLOCK_IOC_RELEASE to remove it). Returns
+-ENOMEM if the memory for the lock can not be allocated. No data is passed
+from the user for this ioctl.
+
+*GENLOCK_IOC_EXPORT
+Export the currently attached lock to a file descriptor. The file descriptor
+is returned in genlock_lock.fd.
+
+*GENLOCK_IOC_ATTACH
+Attach an exported lock file descriptor to the current handle. Return -EINVAL
+if the handle already has a lock attached (use GENLOCK_IOC_RELEASE to remove
+it). Pass the file descriptor in genlock_lock.fd.
+
+*GENLOCK_IOC_LOCK
+Lock or unlock the attached lock. Pass the desired operation in
+genlock_lock.op:
+ * GENLOCK_WRLOCK - write lock
+ * GENLOCK_RDLOCK - read lock
+ * GENLOCK_UNLOCK - unlock an existing lock
+
+Pass flags in genlock_lock.flags:
+ * GENLOCK_NOBLOCK - Do not block if the lock is already taken
+
+Pass a timeout value in milliseconds in genlock_lock.timeout.
+genlock_lock.flags and genlock_lock.timeout are not used for UNLOCK.
+Returns -EINVAL if no lock is attached, -EAGAIN if the lock is taken and
+NOBLOCK is specified or if the timeout value is zero, -ETIMEDOUT if the timeout
+expires or 0 if the lock was successful.
+
+* GENLOCK_IOC_WAIT
+Wait for the lock attached to the handle to be released (i.e. goes to unlock).
+This is mainly used for a thread that needs to wait for a peer to release a
+lock on the same shared handle. A non-zero timeout value in milliseconds is
+passed in genlock_lock.timeout. Returns 0 when the lock has been released,
+-EINVAL if a zero timeout is passed, or -ETIMEDOUT if the timeout expires.
+
+* GENLOCK_IOC_RELEASE
+Use this to release an existing lock. This is useful if you wish to attach a
+different lock to the same handle. You do not need to call this under normal
+circumstances; when the handle is closed the reference to the lock is released.
+No data is passed from the user for this ioctl.
diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt
index b24875b..22852b3 100644
--- a/Documentation/power/runtime_pm.txt
+++ b/Documentation/power/runtime_pm.txt
@@ -469,6 +469,7 @@
pm_runtime_resume()
pm_runtime_get_sync()
pm_runtime_put_sync_suspend()
+pm_runtime_put_sync_autosuspend()
5. Run-time PM Initialization, Device Probing and Removal
diff --git a/Documentation/sound/alsa/compress/snd_compress_data.txt b/Documentation/sound/alsa/compress/snd_compress_data.txt
new file mode 100644
index 0000000..98e2cc9
--- /dev/null
+++ b/Documentation/sound/alsa/compress/snd_compress_data.txt
@@ -0,0 +1,187 @@
+ snd_compress_data.txt
+ =====================
+ Pierre-Louis.Bossart <pierre-louis.bossart@linux.intel.com>
+ Vinod Koul <vinod.koul@linux.intel.com>
+
+Overview
+
+Since its early days, the ALSA API was defined with PCM support or
+constant bitrates payloads such as IEC61937 in mind. Arguments and
+returned values in frames are the norm, making it a challenge to
+extend the existing API to compressed data streams.
+
+In recent years, audio digital signal processors (DSP) were integrated
+in system-on-chip designs, and DSPs are also integrated in audio
+codecs. Processing compressed data on such DSPs results in a dramatic
+reduction of power consumption compared to host-based
+processing. Support for such hardware has not been very good in Linux,
+mostly because of a lack of a generic API available in the mainline
+kernel.
+
+Rather than requiring a compability break with an API change of the
+ALSA PCM interface, a new 'Compressed Data' API is introduced to
+provide a control and data-streaming interface for audio DSPs.
+
+The design of this API was inspired by the 2-year experience with the
+Intel Moorestown SOC, with many corrections required to upstream the
+API in the mainline kernel instead of the staging tree and make it
+usable by others.
+
+Requirements
+
+The main requirements are:
+
+- separation between byte counts and time. Compressed formats may have
+ a header per file, per frame, or no header at all. The payload size
+ may vary from frame-to-frame. As a result, it is not possible to
+ estimate reliably the duration of audio buffers when handling
+ compressed data. Dedicated mechanisms are required to allow for
+ reliable audio-video synchronization, which requires precise
+ reporting of the number of samples rendered at any given time.
+
+- Handling of multiple formats. PCM data only requires a specification
+ of the sampling rate, number of channels and bits per sample. In
+ contrast, compressed data comes in a variety of formats. Audio DSPs
+ may also provide support for a limited number of audio encoders and
+ decoders embedded in firmware, or may support more choices through
+ dynamic download of libraries.
+
+- Focus on main formats. This API provides support for the most
+ popular formats used for audio and video capture and playback. It is
+ likely that as audio compression technology advances, new formats
+ will be added.
+
+- Handling of multiple configurations. Even for a given format like
+ AAC, some implementations may support AAC multichannel but HE-AAC
+ stereo. Likewise WMA10 level M3 may require too much memory and cpu
+ cycles. The new API needs to provide a generic way of listing these
+ formats.
+
+- Rendering/Grabbing only. This API does not provide any means of
+ hardware acceleration, where PCM samples are provided back to
+ user-space for additional processing. This API focuses instead on
+ streaming compressed data to a DSP, with the assumption that the
+ decoded samples are routed to a physical output or logical back-end.
+
+ - Complexity hiding. Existing user-space multimedia frameworks all
+ have existing enums/structures for each compressed format. This new
+ API assumes the existence of a platform-specific compatibility layer
+ to expose, translate and make use of the capabilities of the audio
+ DSP, eg. Android HAL or PulseAudio sinks. By construction, regular
+ applications are not supposed to make use of this API.
+
+
+Design
+
+The new API shares a number of concepts with with the PCM API for flow
+control. Start, pause, resume, drain and stop commands have the same
+semantics no matter what the content is.
+
+The concept of memory ring buffer divided in a set of fragments is
+borrowed from the ALSA PCM API. However, only sizes in bytes can be
+specified.
+
+Seeks/trick modes are assumed to be handled by the host.
+
+The notion of rewinds/forwards is not supported. Data committed to the
+ring buffer cannot be invalidated, except when dropping all buffers.
+
+The Compressed Data API does not make any assumptions on how the data
+is transmitted to the audio DSP. DMA transfers from main memory to an
+embedded audio cluster or to a SPI interface for external DSPs are
+possible. As in the ALSA PCM case, a core set of routines is exposed;
+each driver implementer will have to write support for a set of
+mandatory routines and possibly make use of optional ones.
+
+The main additions are
+
+- get_codecs
+This routine returns the list of audio formats supported. Querying the
+codecs on a capture stream will return encoders, decoders will be
+listed for playback streams.
+
+- get_codec_caps
+For each codec, this routine returns a list of capabilities. The
+intent is to make sure all the capabilities correspond to valid
+settings, and to minimize the risks of configuration failures. For
+example, for a complex codec such as AAC, the number of channels
+supported may depend on a specific profile. If the capabilities were
+exposed with a single descriptor, it may happen that a specific
+combination of profiles/channels/formats may not be
+supported. Likewise, embedded DSPs have limited memory and cpu cycles,
+it is likely that some implementations make the list of capabilities
+dynamic and dependent on existing workloads.
+
+- set_params
+This routine sets the configuration chosen for a specific codec. The
+most important field in the parameters is the codec type; in most
+cases decoders will ignore other fields, while encoders will strictly
+comply to the settings
+
+- get_params
+This routines returns the actual settings used by the DSP. Changes to
+the settings should remain the exception.
+
+- get_timestamp
+The timestamp becomes a multiple field structure. It lists the number
+of bytes transferred, the number of samples processed and the number
+of samples rendered/grabbed. All these values can be used to determine
+the avarage bitrate, figure out if the ring buffer needs to be
+refilled or the delay due to decoding/encoding/io on the DSP.
+
+Note that the list of codecs/profiles/modes was derived from the
+OpenMAX AL specification instead of reinventing the wheel.
+Modifications include:
+- Addition of FLAC and IEC formats
+- Merge of encoder/decoder capabilities
+- Profiles/modes listed as bitmasks to make descriptors more compact
+- Addition of set_params for decoders (missing in OpenMAX AL)
+- Addition of AMR/AMR-WB encoding modes (missing in OpenMAX AL)
+- Addition of format information for WMA
+- Addition of encoding options when required (derived from OpenMAX IL)
+- Addition of rateControlSupported (missing in OpenMAX AL)
+
+Not supported:
+
+- Support for VoIP/circuit-switched calls is not the target of this
+ API. Support for dynamic bit-rate changes would require a tight
+ coupling between the DSP and the host stack, limiting power savings.
+
+- Packet-loss concealment is not supported. This would require an
+ additional interface to let the decoder synthesize data when frames
+ are lost during transmission. This may be added in the future.
+
+- Volume control/routing is not handled by this API. Devices exposing a
+ compressed data interface will be considered as regular ALSA devices
+
+Instead,
+ offloaded processing will be considered as regular ALSA devices;
+ volume changes and routing information will be provided with regular
+ ALSA kcontrols.
+
+- Embedded audio effects. Such effects should be enabled in the same
+ manner, no matter if the input was PCM or compressed.
+
+- multichannel IEC encoding. Unclear if this is required.
+
+- Encoding/decoding acceleration is not supported as mentioned
+ above. It is possible to route the output of a decoder to a capture
+ stream, or even implement transcoding capabilities. This routing
+ would be enabled with ALSA kcontrols.
+
+- Audio policy/resource management. This API does not provide any
+ hooks to query the utilization of the audio DSP, nor any premption
+ mechanisms.
+
+- No notion of underun/overrun. Since the bytes written are compressed
+ in nature and data written/read doesn't translate directly to
+ rendered output in time, this does not deal with underrun/overun and
+ maybe dealt in user-library
+
+Credits:
+- Mark Brown and Liam Girdwood for discussions on the need for this API
+- Harsha Priya for her work on intel_sst compressed API
+- Rakesh Ughreja for valuable feedback
+- Sing Nallasellan, Sikkandar Madar and Prasanna Samaga for
+ demonstrating and quantifying the benefits of audio offload on a
+ real platform.
diff --git a/Documentation/virtual/lguest/lguest.c b/Documentation/virtual/lguest/lguest.c
index cd9d6af..aec80e5 100644
--- a/Documentation/virtual/lguest/lguest.c
+++ b/Documentation/virtual/lguest/lguest.c
@@ -2008,6 +2008,9 @@
/* We use a simple helper to copy the arguments separated by spaces. */
concat((char *)(boot + 1), argv+optind+2);
+ /* Set kernel alignment to 16M (CONFIG_PHYSICAL_ALIGN) */
+ boot->hdr.kernel_alignment = 0x1000000;
+
/* Boot protocol version: 2.07 supports the fields for lguest. */
boot->hdr.version = 0x207;
diff --git a/Makefile b/Makefile
index 800a54b..535dfae 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 3
PATCHLEVEL = 0
-SUBLEVEL = 1
+SUBLEVEL = 8
EXTRAVERSION =
NAME = Sneaky Weasel
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index f34719f..2097e0a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1344,6 +1344,20 @@
source "drivers/pcmcia/Kconfig"
+config ARM_ERRATA_764369
+ bool "ARM errata: Data cache line maintenance operation by MVA may not succeed"
+ depends on CPU_V7 && SMP
+ help
+ This option enables the workaround for erratum 764369
+ affecting Cortex-A9 MPCore with two or more processors (all
+ current revisions). Under certain timing circumstances, a data
+ cache line maintenance operation by MVA targeting an Inner
+ Shareable memory region may fail to proceed up to either the
+ Point of Coherency or to the Point of Unification of the
+ system. This workaround adds a DSB instruction before the
+ relevant cache maintenance functions and sets a specific bit
+ in the diagnostic control register of the SCU.
+
endmenu
menu "Kernel Features"
@@ -1396,6 +1410,12 @@
help
This option enables support for the ARM system coherency unit
+config ARM_ARCH_TIMER
+ bool "Architected timer support"
+ select TICK_ONESHOT
+ help
+ This option enables support for the ARM architected timer
+
config HAVE_ARM_TWD
bool
depends on SMP
@@ -1614,6 +1634,12 @@
def_bool n
depends on SPARSEMEM
+config ARCH_ENABLE_MEMORY_HOTPLUG
+ def_bool n
+
+config ARCH_ENABLE_MEMORY_HOTREMOVE
+ def_bool n
+
config FORCE_MAX_ZONEORDER
int "Maximum zone order" if ARCH_SHMOBILE
range 11 64 if ARCH_SHMOBILE
diff --git a/arch/arm/boot/dts/msmcopper.dts b/arch/arm/boot/dts/msmcopper.dts
index 52c0b66..6561c71 100644
--- a/arch/arm/boot/dts/msmcopper.dts
+++ b/arch/arm/boot/dts/msmcopper.dts
@@ -15,9 +15,59 @@
<0xF9002000 0x1000>;
};
- serial@F9684000 {
+ timer {
+ compatible = "qcom,msm-qtimer";
+ interrupts = <18>;
+ };
+
+ serial@F991F000 {
compatible = "qcom,msm-lsuart-v14";
- reg = <0xF9684000 0x1000>;
+ reg = <0xF991F000 0x1000>;
interrupts = <109>;
};
+
+ usb@F9A55000 {
+ compatible = "qcom,hsusb-otg";
+ reg = <0xF9A55000 0x400>;
+ interrupts = <134>;
+
+ qcom,hsusb-otg-phy-type = <2>;
+ qcom,hsusb-otg-mode = <1>;
+ qcom,hsusb-otg-otg-control = <1>;
+ };
+
+ qcom,sdcc@F980B000 {
+ cell-index = <1>;
+ compatible = "qcom,msm-sdcc";
+ reg = <0xF980B000 0x1000>;
+ interrupts = <123>;
+
+ qcom,sdcc-clk-rates = <400000 24000000 48000000>;
+ qcom,sdcc-sup-voltages = <3300 3300>;
+ qcom,sdcc-bus-width = <8>;
+ qcom,sdcc-nonremovable;
+ qcom,sdcc-disable_cmd23;
+ };
+
+ qcom,sdcc@F984B000 {
+ cell-index = <3>;
+ compatible = "qcom,msm-sdcc";
+ reg = <0xF984B000 0x1000>;
+ interrupts = <127>;
+
+ qcom,sdcc-clk-rates = <400000 24000000 48000000>;
+ qcom,sdcc-sup-voltages = <3300 3300>;
+ qcom,sdcc-bus-width = <4>;
+ qcom,sdcc-disable_cmd23;
+ };
+
+ qcom,sps@F9980000 {
+ compatible = "qcom,msm_sps";
+ reg = <0xF9984000 0x15000>,
+ <0xF9999000 0xB000>;
+ interrupts = <94>;
+
+ qcom,bam-dma-res-pipes = <6>;
+ };
+
};
diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig
index 66ed0c3..ad180b2 100644
--- a/arch/arm/common/Kconfig
+++ b/arch/arm/common/Kconfig
@@ -49,12 +49,11 @@
bool "FIQ Mode Serial Debugger"
select FIQ
select FIQ_GLUE
- select KERNEL_DEBUGGER_CORE
default n
help
The FIQ serial debugger can accept commands even when the
kernel is unresponsive due to being stuck with interrupts
- disabled. Depends on the kernel debugger core in drivers/misc.
+ disabled.
config FIQ_DEBUGGER_NO_SLEEP
diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
index 3ab5d76..6f25cf2 100644
--- a/arch/arm/common/Makefile
+++ b/arch/arm/common/Makefile
@@ -19,3 +19,4 @@
obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp.o
obj-$(CONFIG_FIQ_GLUE) += fiq_glue.o fiq_glue_setup.o
obj-$(CONFIG_FIQ_DEBUGGER) += fiq_debugger.o
+obj-$(CONFIG_CP_ACCESS) += cpaccess.o
diff --git a/arch/arm/common/cpaccess.c b/arch/arm/common/cpaccess.c
index d3d0537..e71e318 100644
--- a/arch/arm/common/cpaccess.c
+++ b/arch/arm/common/cpaccess.c
@@ -29,6 +29,7 @@
#include <linux/smp.h>
#include <asm/cacheflush.h>
#include <asm/smp_plat.h>
+#include <asm/mmu_writeable.h>
#ifdef CONFIG_ARCH_MSM_KRAIT
#include <mach/msm-krait-l2-accessors.h>
@@ -191,16 +192,11 @@
(per_cpu(cp_param.cp, cpu) << 8);
/*
- * Grab address of the Dummy function, insert MRC/MCR
- * instruction and a return instruction ("bx lr"). Do
- * a D cache clean and I cache invalidate after inserting
- * new code.
+ * Grab address of the Dummy function, write the MRC/MCR
+ * instruction, ensuring cache coherency.
*/
p_opcode = (unsigned long *)&cpaccess_dummy;
- *p_opcode++ = opcode;
- *p_opcode-- = 0xE12FFF1E;
- __cpuc_coherent_kern_range((unsigned long)p_opcode,
- ((unsigned long)p_opcode + (sizeof(long) * 2)));
+ mem_text_write_kernel_word(p_opcode, opcode);
#ifdef CONFIG_SMP
/*
diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c
index 080f69e..3ed18ae 100644
--- a/arch/arm/common/fiq_debugger.c
+++ b/arch/arm/common/fiq_debugger.c
@@ -22,12 +22,12 @@
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
-#include <linux/kernel_debugger.h>
#include <linux/kernel_stat.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/smp.h>
#include <linux/timer.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
@@ -53,6 +53,7 @@
struct fiq_glue_handler handler;
int fiq;
+ int uart_irq;
int signal_irq;
int wakeup_irq;
bool wakeup_irq_no_set_wake;
@@ -71,7 +72,8 @@
bool debug_enable;
bool ignore_next_wakeup_irq;
struct timer_list sleep_timer;
- bool uart_clk_enabled;
+ spinlock_t sleep_timer_lock;
+ bool uart_enabled;
struct wake_lock debugger_wake_lock;
bool console_enable;
int current_cpu;
@@ -84,6 +86,7 @@
struct tty_struct *tty;
int tty_open_count;
struct fiq_debugger_ringbuf *tty_rbuf;
+ bool syslog_dumping;
#endif
unsigned int last_irqs[NR_IRQS];
@@ -130,18 +133,42 @@
}
#endif
+static bool inline debug_have_fiq(struct fiq_debugger_state *state)
+{
+ return (state->fiq >= 0);
+}
+
static void debug_force_irq(struct fiq_debugger_state *state)
{
unsigned int irq = state->signal_irq;
- if (state->pdata->force_irq)
+
+ if (WARN_ON(!debug_have_fiq(state)))
+ return;
+ if (state->pdata->force_irq) {
state->pdata->force_irq(state->pdev, irq);
- else {
+ } else {
struct irq_chip *chip = irq_get_chip(irq);
if (chip && chip->irq_retrigger)
chip->irq_retrigger(irq_get_irq_data(irq));
}
}
+static void debug_uart_enable(struct fiq_debugger_state *state)
+{
+ if (state->clk)
+ clk_enable(state->clk);
+ if (state->pdata->uart_enable)
+ state->pdata->uart_enable(state->pdev);
+}
+
+static void debug_uart_disable(struct fiq_debugger_state *state)
+{
+ if (state->pdata->uart_disable)
+ state->pdata->uart_disable(state->pdev);
+ if (state->clk)
+ clk_disable(state->clk);
+}
+
static void debug_uart_flush(struct fiq_debugger_state *state)
{
if (state->pdata->uart_flush)
@@ -447,6 +474,81 @@
tail = user_backtrace(state, tail);
}
+static void do_ps(struct fiq_debugger_state *state)
+{
+ struct task_struct *g;
+ struct task_struct *p;
+ unsigned task_state;
+ static const char stat_nam[] = "RSDTtZX";
+
+ debug_printf(state, "pid ppid prio task pc\n");
+ read_lock(&tasklist_lock);
+ do_each_thread(g, p) {
+ task_state = p->state ? __ffs(p->state) + 1 : 0;
+ debug_printf(state,
+ "%5d %5d %4d ", p->pid, p->parent->pid, p->prio);
+ debug_printf(state, "%-13.13s %c", p->comm,
+ task_state >= sizeof(stat_nam) ? '?' : stat_nam[task_state]);
+ if (task_state == TASK_RUNNING)
+ debug_printf(state, " running\n");
+ else
+ debug_printf(state, " %08lx\n", thread_saved_pc(p));
+ } while_each_thread(g, p);
+ read_unlock(&tasklist_lock);
+}
+
+#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE
+static void begin_syslog_dump(struct fiq_debugger_state *state)
+{
+ state->syslog_dumping = true;
+}
+
+static void end_syslog_dump(struct fiq_debugger_state *state)
+{
+ state->syslog_dumping = false;
+}
+#else
+extern int do_syslog(int type, char __user *bug, int count);
+static void begin_syslog_dump(struct fiq_debugger_state *state)
+{
+ do_syslog(5 /* clear */, NULL, 0);
+}
+
+static void end_syslog_dump(struct fiq_debugger_state *state)
+{
+ char buf[128];
+ int ret;
+ int idx = 0;
+
+ while (1) {
+ ret = log_buf_copy(buf, idx, sizeof(buf) - 1);
+ if (ret <= 0)
+ break;
+ buf[ret] = 0;
+ debug_printf(state, "%s", buf);
+ idx += ret;
+ }
+}
+#endif
+
+static void do_sysrq(struct fiq_debugger_state *state, char rq)
+{
+ begin_syslog_dump(state);
+ handle_sysrq(rq);
+ end_syslog_dump(state);
+}
+
+/* This function CANNOT be called in FIQ context */
+static void debug_irq_exec(struct fiq_debugger_state *state, char *cmd)
+{
+ if (!strcmp(cmd, "ps"))
+ do_ps(state);
+ if (!strcmp(cmd, "sysrq"))
+ do_sysrq(state, 'h');
+ if (!strncmp(cmd, "sysrq ", 6))
+ do_sysrq(state, cmd[6]);
+}
+
static void debug_help(struct fiq_debugger_state *state)
{
debug_printf(state, "FIQ Debugger commands:\n"
@@ -463,16 +565,34 @@
" console Switch terminal to console\n"
" cpu Current CPU\n"
" cpu <number> Switch to CPU<number>\n");
- if (!state->debug_busy) {
- strcpy(state->debug_cmd, "help");
- state->debug_busy = 1;
- debug_force_irq(state);
- }
+ debug_printf(state, " ps Process list\n"
+ " sysrq sysrq options\n"
+ " sysrq <param> Execute sysrq with <param>\n");
}
-static void debug_exec(struct fiq_debugger_state *state,
+static void take_affinity(void *info)
+{
+ struct fiq_debugger_state *state = info;
+ struct cpumask cpumask;
+
+ cpumask_clear(&cpumask);
+ cpumask_set_cpu(get_cpu(), &cpumask);
+
+ irq_set_affinity(state->uart_irq, &cpumask);
+}
+
+static void switch_cpu(struct fiq_debugger_state *state, int cpu)
+{
+ if (!debug_have_fiq(state))
+ smp_call_function_single(cpu, take_affinity, state, false);
+ state->current_cpu = cpu;
+}
+
+static bool debug_fiq_exec(struct fiq_debugger_state *state,
const char *cmd, unsigned *regs, void *svc_sp)
{
+ bool signal_helper = false;
+
if (!strcmp(cmd, "help") || !strcmp(cmd, "?")) {
debug_help(state);
} else if (!strcmp(cmd, "pc")) {
@@ -494,8 +614,10 @@
debug_printf(state, "%s\n", linux_banner);
} else if (!strcmp(cmd, "sleep")) {
state->no_sleep = false;
+ debug_printf(state, "enabling sleep\n");
} else if (!strcmp(cmd, "nosleep")) {
state->no_sleep = true;
+ debug_printf(state, "disabling sleep\n");
} else if (!strcmp(cmd, "console")) {
state->console_enable = true;
debug_printf(state, "console mode\n");
@@ -504,7 +626,7 @@
} else if (!strncmp(cmd, "cpu ", 4)) {
unsigned long cpu = 0;
if (strict_strtoul(cmd + 4, 10, &cpu) == 0)
- state->current_cpu = cpu;
+ switch_cpu(state, cpu);
else
debug_printf(state, "invalid cpu\n");
debug_printf(state, "cpu %d\n", state->current_cpu);
@@ -518,30 +640,49 @@
state->debug_busy = 1;
}
- debug_force_irq(state);
-
- return;
+ return true;
}
if (!state->console_enable)
debug_prompt(state);
+
+ return signal_helper;
}
static void sleep_timer_expired(unsigned long data)
{
struct fiq_debugger_state *state = (struct fiq_debugger_state *)data;
+ unsigned long flags;
- if (state->uart_clk_enabled && !state->no_sleep) {
- if (state->debug_enable) {
+ spin_lock_irqsave(&state->sleep_timer_lock, flags);
+ if (state->uart_enabled && !state->no_sleep) {
+ if (state->debug_enable && !state->console_enable) {
state->debug_enable = false;
debug_printf_nfiq(state, "suspending fiq debugger\n");
}
state->ignore_next_wakeup_irq = true;
- if (state->clk)
- clk_disable(state->clk);
- state->uart_clk_enabled = false;
+ debug_uart_disable(state);
+ state->uart_enabled = false;
enable_wakeup_irq(state);
}
wake_unlock(&state->debugger_wake_lock);
+ spin_unlock_irqrestore(&state->sleep_timer_lock, flags);
+}
+
+static void handle_wakeup(struct fiq_debugger_state *state)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&state->sleep_timer_lock, flags);
+ if (state->wakeup_irq >= 0 && state->ignore_next_wakeup_irq) {
+ state->ignore_next_wakeup_irq = false;
+ } else if (!state->uart_enabled) {
+ wake_lock(&state->debugger_wake_lock);
+ debug_uart_enable(state);
+ state->uart_enabled = true;
+ disable_wakeup_irq(state);
+ mod_timer(&state->sleep_timer, jiffies + HZ / 2);
+ }
+ spin_unlock_irqrestore(&state->sleep_timer_lock, flags);
}
static irqreturn_t wakeup_irq_handler(int irq, void *dev)
@@ -550,35 +691,28 @@
if (!state->no_sleep)
debug_puts(state, "WAKEUP\n");
- if (state->ignore_next_wakeup_irq)
- state->ignore_next_wakeup_irq = false;
- else if (!state->uart_clk_enabled) {
- wake_lock(&state->debugger_wake_lock);
- if (state->clk)
- clk_enable(state->clk);
- state->uart_clk_enabled = true;
- disable_wakeup_irq(state);
- mod_timer(&state->sleep_timer, jiffies + HZ / 2);
- }
+ handle_wakeup(state);
+
return IRQ_HANDLED;
}
-static irqreturn_t debug_irq(int irq, void *dev)
-{
- struct fiq_debugger_state *state = dev;
- if (state->pdata->force_irq_ack)
- state->pdata->force_irq_ack(state->pdev, state->signal_irq);
+static void debug_handle_irq_context(struct fiq_debugger_state *state)
+{
if (!state->no_sleep) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&state->sleep_timer_lock, flags);
wake_lock(&state->debugger_wake_lock);
mod_timer(&state->sleep_timer, jiffies + HZ * 5);
+ spin_unlock_irqrestore(&state->sleep_timer_lock, flags);
}
#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE)
if (state->tty) {
int i;
int count = fiq_debugger_ringbuf_level(state->tty_rbuf);
for (i = 0; i < count; i++) {
- int c = fiq_debugger_ringbuf_peek(state->tty_rbuf, i);
+ int c = fiq_debugger_ringbuf_peek(state->tty_rbuf, 0);
tty_insert_flip_char(state->tty, c, TTY_NORMAL);
if (!fiq_debugger_ringbuf_consume(state->tty_rbuf, 1))
pr_warn("fiq tty failed to consume byte\n");
@@ -587,16 +721,10 @@
}
#endif
if (state->debug_busy) {
- struct kdbg_ctxt ctxt;
-
- ctxt.printf = debug_printf_nfiq;
- ctxt.cookie = state;
- kernel_debugger(&ctxt, state->debug_cmd);
+ debug_irq_exec(state, state->debug_cmd);
debug_prompt(state);
-
state->debug_busy = 0;
}
- return IRQ_HANDLED;
}
static int debug_getc(struct fiq_debugger_state *state)
@@ -604,30 +732,29 @@
return state->pdata->uart_getc(state->pdev);
}
-static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp)
+static bool debug_handle_uart_interrupt(struct fiq_debugger_state *state,
+ int this_cpu, void *regs, void *svc_sp)
{
- struct fiq_debugger_state *state =
- container_of(h, struct fiq_debugger_state, handler);
int c;
static int last_c;
int count = 0;
- unsigned int this_cpu = THREAD_INFO(svc_sp)->cpu;
+ bool signal_helper = false;
if (this_cpu != state->current_cpu) {
if (state->in_fiq)
- return;
+ return false;
if (atomic_inc_return(&state->unhandled_fiq_count) !=
MAX_UNHANDLED_FIQ_COUNT)
- return;
+ return false;
debug_printf(state, "fiq_debugger: cpu %d not responding, "
"reverting to cpu %d\n", state->current_cpu,
this_cpu);
atomic_set(&state->unhandled_fiq_count, 0);
- state->current_cpu = this_cpu;
- return;
+ switch_cpu(state, this_cpu);
+ return false;
}
state->in_fiq = true;
@@ -648,7 +775,7 @@
#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE
} else if (state->console_enable && state->tty_rbuf) {
fiq_debugger_ringbuf_push(state->tty_rbuf, c);
- debug_force_irq(state);
+ signal_helper = true;
#endif
} else if ((c >= ' ') && (c < 127)) {
if (state->debug_count < (DEBUG_MAX - 1)) {
@@ -670,8 +797,9 @@
if (state->debug_count) {
state->debug_buf[state->debug_count] = 0;
state->debug_count = 0;
- debug_exec(state, state->debug_buf,
- regs, svc_sp);
+ signal_helper |=
+ debug_fiq_exec(state, state->debug_buf,
+ regs, svc_sp);
} else {
debug_prompt(state);
}
@@ -684,10 +812,63 @@
/* poke sleep timer if necessary */
if (state->debug_enable && !state->no_sleep)
- debug_force_irq(state);
+ signal_helper = true;
atomic_set(&state->unhandled_fiq_count, 0);
state->in_fiq = false;
+
+ return signal_helper;
+}
+
+static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp)
+{
+ struct fiq_debugger_state *state =
+ container_of(h, struct fiq_debugger_state, handler);
+ unsigned int this_cpu = THREAD_INFO(svc_sp)->cpu;
+ bool need_irq;
+
+ need_irq = debug_handle_uart_interrupt(state, this_cpu, regs, svc_sp);
+ if (need_irq)
+ debug_force_irq(state);
+}
+
+/*
+ * When not using FIQs, we only use this single interrupt as an entry point.
+ * This just effectively takes over the UART interrupt and does all the work
+ * in this context.
+ */
+static irqreturn_t debug_uart_irq(int irq, void *dev)
+{
+ struct fiq_debugger_state *state = dev;
+ bool not_done;
+
+ handle_wakeup(state);
+
+ /* handle the debugger irq in regular context */
+ not_done = debug_handle_uart_interrupt(state, smp_processor_id(),
+ get_irq_regs(),
+ current_thread_info());
+ if (not_done)
+ debug_handle_irq_context(state);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * If FIQs are used, not everything can happen in fiq context.
+ * FIQ handler does what it can and then signals this interrupt to finish the
+ * job in irq context.
+ */
+static irqreturn_t debug_signal_irq(int irq, void *dev)
+{
+ struct fiq_debugger_state *state = dev;
+
+ if (state->pdata->force_irq_ack)
+ state->pdata->force_irq_ack(state->pdev, state->signal_irq);
+
+ debug_handle_irq_context(state);
+
+ return IRQ_HANDLED;
}
static void debug_resume(struct fiq_glue_handler *h)
@@ -714,15 +895,17 @@
state = container_of(co, struct fiq_debugger_state, console);
- if (!state->console_enable)
+ if (!state->console_enable && !state->syslog_dumping)
return;
+ debug_uart_enable(state);
while (count--) {
if (*s == '\n')
state->pdata->uart_putc(state->pdev, '\r');
state->pdata->uart_putc(state->pdev, *s++);
}
debug_uart_flush(state);
+ debug_uart_disable(state);
}
static struct console fiq_debugger_console = {
@@ -759,12 +942,10 @@
if (!state->console_enable)
return count;
- if (state->clk)
- clk_enable(state->clk);
+ debug_uart_enable(state);
for (i = 0; i < count; i++)
state->pdata->uart_putc(state->pdev, *buf++);
- if (state->clk)
- clk_disable(state->clk);
+ debug_uart_disable(state);
return count;
}
@@ -829,18 +1010,51 @@
}
#endif
+static int fiq_debugger_dev_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fiq_debugger_state *state = platform_get_drvdata(pdev);
+
+ if (state->pdata->uart_dev_suspend)
+ return state->pdata->uart_dev_suspend(pdev);
+ return 0;
+}
+
+static int fiq_debugger_dev_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fiq_debugger_state *state = platform_get_drvdata(pdev);
+
+ if (state->pdata->uart_dev_resume)
+ return state->pdata->uart_dev_resume(pdev);
+ return 0;
+}
+
static int fiq_debugger_probe(struct platform_device *pdev)
{
int ret;
struct fiq_debugger_pdata *pdata = dev_get_platdata(&pdev->dev);
struct fiq_debugger_state *state;
+ int fiq;
+ int uart_irq;
- if (!pdata->uart_getc || !pdata->uart_putc || !pdata->fiq_enable)
+ if (!pdata->uart_getc || !pdata->uart_putc)
+ return -EINVAL;
+ if ((pdata->uart_enable && !pdata->uart_disable) ||
+ (!pdata->uart_enable && pdata->uart_disable))
+ return -EINVAL;
+
+ fiq = platform_get_irq_byname(pdev, "fiq");
+ uart_irq = platform_get_irq_byname(pdev, "uart_irq");
+
+ /* uart_irq mode and fiq mode are mutually exclusive, but one of them
+ * is required */
+ if ((uart_irq < 0 && fiq < 0) || (uart_irq >= 0 && fiq >= 0))
+ return -EINVAL;
+ if (fiq >= 0 && !pdata->fiq_enable)
return -EINVAL;
state = kzalloc(sizeof(*state), GFP_KERNEL);
- state->handler.fiq = debug_fiq;
- state->handler.resume = debug_resume;
setup_timer(&state->sleep_timer, sleep_timer_expired,
(unsigned long)state);
state->pdata = pdata;
@@ -849,11 +1063,16 @@
state->debug_enable = initial_debug_enable;
state->console_enable = initial_console_enable;
- state->fiq = platform_get_irq_byname(pdev, "fiq");
+ state->fiq = fiq;
+ state->uart_irq = uart_irq;
state->signal_irq = platform_get_irq_byname(pdev, "signal");
state->wakeup_irq = platform_get_irq_byname(pdev, "wakeup");
- if (state->wakeup_irq < 0)
+ platform_set_drvdata(pdev, state);
+
+ spin_lock_init(&state->sleep_timer_lock);
+
+ if (state->wakeup_irq < 0 && debug_have_fiq(state))
state->no_sleep = true;
state->ignore_next_wakeup_irq = !state->no_sleep;
@@ -864,6 +1083,10 @@
if (IS_ERR(state->clk))
state->clk = NULL;
+ /* do not call pdata->uart_enable here since uart_init may still
+ * need to do some initialization before uart_enable can work.
+ * So, only try to manage the clock during init.
+ */
if (state->clk)
clk_enable(state->clk);
@@ -876,21 +1099,39 @@
debug_printf_nfiq(state, "<hit enter %sto activate fiq debugger>\n",
state->no_sleep ? "" : "twice ");
- ret = fiq_glue_register_handler(&state->handler);
- if (ret) {
- pr_err("serial_debugger: could not install fiq handler\n");
- goto err_register_fiq;
- }
+ if (debug_have_fiq(state)) {
+ state->handler.fiq = debug_fiq;
+ state->handler.resume = debug_resume;
+ ret = fiq_glue_register_handler(&state->handler);
+ if (ret) {
+ pr_err("%s: could not install fiq handler\n", __func__);
+ goto err_register_fiq;
+ }
- pdata->fiq_enable(pdev, state->fiq, 1);
+ pdata->fiq_enable(pdev, state->fiq, 1);
+ } else {
+ ret = request_irq(state->uart_irq, debug_uart_irq,
+ IRQF_NO_SUSPEND, "debug", state);
+ if (ret) {
+ pr_err("%s: could not install irq handler\n", __func__);
+ goto err_register_irq;
+ }
+
+ /* for irq-only mode, we want this irq to wake us up, if it
+ * can.
+ */
+ enable_irq_wake(state->uart_irq);
+ }
if (state->clk)
clk_disable(state->clk);
- ret = request_irq(state->signal_irq, debug_irq,
- IRQF_TRIGGER_RISING, "debug", state);
- if (ret)
- pr_err("serial_debugger: could not install signal_irq");
+ if (state->signal_irq >= 0) {
+ ret = request_irq(state->signal_irq, debug_signal_irq,
+ IRQF_TRIGGER_RISING, "debug-signal", state);
+ if (ret)
+ pr_err("serial_debugger: could not install signal_irq");
+ }
if (state->wakeup_irq >= 0) {
ret = request_irq(state->wakeup_irq, wakeup_irq_handler,
@@ -910,7 +1151,7 @@
}
}
if (state->no_sleep)
- wakeup_irq_handler(state->wakeup_irq, state);
+ handle_wakeup(state);
#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE)
state->console = fiq_debugger_console;
@@ -919,19 +1160,32 @@
#endif
return 0;
+err_register_irq:
err_register_fiq:
if (pdata->uart_free)
pdata->uart_free(pdev);
err_uart_init:
- kfree(state);
+ if (state->clk)
+ clk_disable(state->clk);
if (state->clk)
clk_put(state->clk);
+ wake_lock_destroy(&state->debugger_wake_lock);
+ platform_set_drvdata(pdev, NULL);
+ kfree(state);
return ret;
}
+static const struct dev_pm_ops fiq_debugger_dev_pm_ops = {
+ .suspend = fiq_debugger_dev_suspend,
+ .resume = fiq_debugger_dev_resume,
+};
+
static struct platform_driver fiq_debugger_driver = {
- .probe = fiq_debugger_probe,
- .driver.name = "fiq_debugger",
+ .probe = fiq_debugger_probe,
+ .driver = {
+ .name = "fiq_debugger",
+ .pm = &fiq_debugger_dev_pm_ops,
+ },
};
static int __init fiq_debugger_init(void)
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index dbf3427..fea7044 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -26,6 +26,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/smp.h>
+#include <linux/cpu_pm.h>
#include <linux/cpumask.h>
#include <linux/io.h>
#include <linux/syscore_ops.h>
@@ -35,22 +36,11 @@
#include <asm/hardware/gic.h>
#include <asm/system.h>
-static DEFINE_SPINLOCK(irq_controller_lock);
+static DEFINE_RAW_SPINLOCK(irq_controller_lock);
/* Address of GIC 0 CPU interface */
void __iomem *gic_cpu_base_addr __read_mostly;
-struct gic_chip_data {
- unsigned int irq_offset;
- void __iomem *dist_base;
- void __iomem *cpu_base;
- unsigned int max_irq;
-#ifdef CONFIG_PM
- unsigned int wakeup_irqs[32];
- unsigned int enabled_irqs[32];
-#endif
-};
-
/*
* Supported arch specific GIC irq extension.
* Default make them NULL.
@@ -96,23 +86,22 @@
{
u32 mask = 1 << (d->irq % 32);
- spin_lock(&irq_controller_lock);
+ raw_spin_lock(&irq_controller_lock);
writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
if (gic_arch_extn.irq_mask)
gic_arch_extn.irq_mask(d);
- spin_unlock(&irq_controller_lock);
-
+ raw_spin_unlock(&irq_controller_lock);
}
static void gic_unmask_irq(struct irq_data *d)
{
u32 mask = 1 << (d->irq % 32);
- spin_lock(&irq_controller_lock);
+ raw_spin_lock(&irq_controller_lock);
if (gic_arch_extn.irq_unmask)
gic_arch_extn.irq_unmask(d);
writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
- spin_unlock(&irq_controller_lock);
+ raw_spin_unlock(&irq_controller_lock);
}
static void gic_disable_irq(struct irq_data *d)
@@ -160,13 +149,13 @@
if (!msm_show_resume_irq_mask)
return;
- spin_lock(&irq_controller_lock);
+ raw_spin_lock(&irq_controller_lock);
for (i = 0; i * 32 < gic->max_irq; i++) {
enabled = readl_relaxed(base + GIC_DIST_ENABLE_CLEAR + i * 4);
pending[i] = readl_relaxed(base + GIC_DIST_PENDING_SET + i * 4);
pending[i] &= enabled;
}
- spin_unlock(&irq_controller_lock);
+ raw_spin_unlock(&irq_controller_lock);
for (i = find_first_bit(pending, gic->max_irq);
i < gic->max_irq;
@@ -216,9 +205,9 @@
static void gic_eoi_irq(struct irq_data *d)
{
if (gic_arch_extn.irq_eoi) {
- spin_lock(&irq_controller_lock);
+ raw_spin_lock(&irq_controller_lock);
gic_arch_extn.irq_eoi(d);
- spin_unlock(&irq_controller_lock);
+ raw_spin_unlock(&irq_controller_lock);
}
writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
@@ -242,7 +231,7 @@
if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
return -EINVAL;
- spin_lock(&irq_controller_lock);
+ raw_spin_lock(&irq_controller_lock);
if (gic_arch_extn.irq_set_type)
gic_arch_extn.irq_set_type(d, type);
@@ -267,7 +256,7 @@
if (enabled)
writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
- spin_unlock(&irq_controller_lock);
+ raw_spin_unlock(&irq_controller_lock);
return 0;
}
@@ -287,22 +276,21 @@
{
void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3);
unsigned int shift = (d->irq % 4) * 8;
- unsigned int cpu = cpumask_first(mask_val);
+ unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
u32 val, mask, bit;
- if (cpu >= 8)
+ if (cpu >= 8 || cpu >= nr_cpu_ids)
return -EINVAL;
mask = 0xff << shift;
- bit = 1 << (cpu + shift);
+ bit = 1 << (cpu_logical_map(cpu) + shift);
- spin_lock(&irq_controller_lock);
- d->node = cpu;
+ raw_spin_lock(&irq_controller_lock);
val = readl_relaxed(reg) & ~mask;
writel_relaxed(val | bit, reg);
- spin_unlock(&irq_controller_lock);
+ raw_spin_unlock(&irq_controller_lock);
- return 0;
+ return IRQ_SET_MASK_OK;
}
#endif
@@ -347,9 +335,9 @@
chained_irq_enter(chip, desc);
- spin_lock(&irq_controller_lock);
+ raw_spin_lock(&irq_controller_lock);
status = readl_relaxed(chip_data->cpu_base + GIC_CPU_INTACK);
- spin_unlock(&irq_controller_lock);
+ raw_spin_unlock(&irq_controller_lock);
gic_irq = (status & 0x3ff);
if (gic_irq == 1023)
@@ -392,9 +380,15 @@
unsigned int irq_start)
{
unsigned int gic_irqs, irq_limit, i;
+ u32 cpumask;
void __iomem *base = gic->dist_base;
- u32 cpumask = 1 << smp_processor_id();
+ u32 cpu = 0;
+#ifdef CONFIG_SMP
+ cpu = cpu_logical_map(smp_processor_id());
+#endif
+
+ cpumask = 1 << cpu;
cpumask |= cpumask << 8;
cpumask |= cpumask << 16;
@@ -409,6 +403,8 @@
if (gic_irqs > 1020)
gic_irqs = 1020;
+ gic->gic_irqs = gic_irqs;
+
/*
* Set all global interrupts to be level triggered, active low.
*/
@@ -480,6 +476,189 @@
mb();
}
+#ifdef CONFIG_CPU_PM
+/*
+ * Saves the GIC distributor registers during suspend or idle. Must be called
+ * with interrupts disabled but before powering down the GIC. After calling
+ * this function, no interrupts will be delivered by the GIC, and another
+ * platform-specific wakeup source must be enabled.
+ */
+static void gic_dist_save(unsigned int gic_nr)
+{
+ unsigned int gic_irqs;
+ void __iomem *dist_base;
+ int i;
+
+ if (gic_nr >= MAX_GIC_NR)
+ BUG();
+
+ gic_irqs = gic_data[gic_nr].gic_irqs;
+ dist_base = gic_data[gic_nr].dist_base;
+
+ if (!dist_base)
+ return;
+
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
+ gic_data[gic_nr].saved_spi_conf[i] =
+ readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
+
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
+ gic_data[gic_nr].saved_spi_target[i] =
+ readl_relaxed(dist_base + GIC_DIST_TARGET + i * 4);
+
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
+ gic_data[gic_nr].saved_spi_enable[i] =
+ readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
+}
+
+/*
+ * Restores the GIC distributor registers during resume or when coming out of
+ * idle. Must be called before enabling interrupts. If a level interrupt
+ * that occured while the GIC was suspended is still present, it will be
+ * handled normally, but any edge interrupts that occured will not be seen by
+ * the GIC and need to be handled by the platform-specific wakeup source.
+ */
+static void gic_dist_restore(unsigned int gic_nr)
+{
+ unsigned int gic_irqs;
+ unsigned int i;
+ void __iomem *dist_base;
+
+ if (gic_nr >= MAX_GIC_NR)
+ BUG();
+
+ gic_irqs = gic_data[gic_nr].gic_irqs;
+ dist_base = gic_data[gic_nr].dist_base;
+
+ if (!dist_base)
+ return;
+
+ writel_relaxed(0, dist_base + GIC_DIST_CTRL);
+
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
+ writel_relaxed(gic_data[gic_nr].saved_spi_conf[i],
+ dist_base + GIC_DIST_CONFIG + i * 4);
+
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
+ writel_relaxed(0xa0a0a0a0,
+ dist_base + GIC_DIST_PRI + i * 4);
+
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
+ writel_relaxed(gic_data[gic_nr].saved_spi_target[i],
+ dist_base + GIC_DIST_TARGET + i * 4);
+
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
+ writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
+ dist_base + GIC_DIST_ENABLE_SET + i * 4);
+
+ writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+}
+
+static void gic_cpu_save(unsigned int gic_nr)
+{
+ int i;
+ u32 *ptr;
+ void __iomem *dist_base;
+ void __iomem *cpu_base;
+
+ if (gic_nr >= MAX_GIC_NR)
+ BUG();
+
+ dist_base = gic_data[gic_nr].dist_base;
+ cpu_base = gic_data[gic_nr].cpu_base;
+
+ if (!dist_base || !cpu_base)
+ return;
+
+ ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
+ for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
+ ptr[i] = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
+
+ ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
+ for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
+ ptr[i] = readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
+
+}
+
+static void gic_cpu_restore(unsigned int gic_nr)
+{
+ int i;
+ u32 *ptr;
+ void __iomem *dist_base;
+ void __iomem *cpu_base;
+
+ if (gic_nr >= MAX_GIC_NR)
+ BUG();
+
+ dist_base = gic_data[gic_nr].dist_base;
+ cpu_base = gic_data[gic_nr].cpu_base;
+
+ if (!dist_base || !cpu_base)
+ return;
+
+ ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
+ for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
+ writel_relaxed(ptr[i], dist_base + GIC_DIST_ENABLE_SET + i * 4);
+
+ ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
+ for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
+ writel_relaxed(ptr[i], dist_base + GIC_DIST_CONFIG + i * 4);
+
+ for (i = 0; i < DIV_ROUND_UP(32, 4); i++)
+ writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
+
+ writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
+ writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+}
+
+static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v)
+{
+ int i;
+
+ for (i = 0; i < MAX_GIC_NR; i++) {
+ switch (cmd) {
+ case CPU_PM_ENTER:
+ gic_cpu_save(i);
+ break;
+ case CPU_PM_ENTER_FAILED:
+ case CPU_PM_EXIT:
+ gic_cpu_restore(i);
+ break;
+ case CPU_CLUSTER_PM_ENTER:
+ gic_dist_save(i);
+ break;
+ case CPU_CLUSTER_PM_ENTER_FAILED:
+ case CPU_CLUSTER_PM_EXIT:
+ gic_dist_restore(i);
+ break;
+ }
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block gic_notifier_block = {
+ .notifier_call = gic_notifier,
+};
+
+static void __init gic_pm_init(struct gic_chip_data *gic)
+{
+ gic->saved_ppi_enable = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4,
+ sizeof(u32));
+ BUG_ON(!gic->saved_ppi_enable);
+
+ gic->saved_ppi_conf = __alloc_percpu(DIV_ROUND_UP(32, 16) * 4,
+ sizeof(u32));
+ BUG_ON(!gic->saved_ppi_conf);
+
+ cpu_pm_register_notifier(&gic_notifier_block);
+}
+#else
+static void __init gic_pm_init(struct gic_chip_data *gic)
+{
+}
+#endif
+
void __init gic_init(unsigned int gic_nr, unsigned int irq_start,
void __iomem *dist_base, void __iomem *cpu_base)
{
@@ -495,8 +674,10 @@
if (gic_nr == 0)
gic_cpu_base_addr = cpu_base;
+ gic_chip.flags |= gic_arch_extn.flags;
gic_dist_init(gic, irq_start);
gic_cpu_init(gic);
+ gic_pm_init(gic);
}
void __cpuinit gic_secondary_init(unsigned int gic_nr)
@@ -519,7 +700,12 @@
#ifdef CONFIG_SMP
void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
{
- unsigned long map = *cpus_addr(*mask);
+ int cpu;
+ unsigned long map = 0;
+
+ /* Convert our logical CPU mask into a physical one. */
+ for_each_cpu(cpu, mask)
+ map |= 1 << cpu_logical_map(cpu);
/*
* Ensure that stores to Normal memory are visible to the
@@ -542,7 +728,7 @@
u32 mask, val;
WARN_ON(!irqs_disabled());
- spin_lock(&irq_controller_lock);
+ raw_spin_lock(&irq_controller_lock);
mask = 1 << (gic_irq(d) % 32);
val = readl(gic_dist_base(d) +
GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
@@ -550,7 +736,7 @@
WARN_ON(val & mask);
val = readl(gic_dist_base(d) +
GIC_DIST_PENDING_SET + (gic_irq(d) / 32) * 4);
- spin_unlock(&irq_controller_lock);
+ raw_spin_unlock(&irq_controller_lock);
return (bool) (val & mask);
}
@@ -563,7 +749,7 @@
u32 mask, val;
WARN_ON(!irqs_disabled());
- spin_lock(&irq_controller_lock);
+ raw_spin_lock(&irq_controller_lock);
mask = 1 << (gic_irq(d) % 32);
val = readl(gic_dist_base(d) +
GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
@@ -571,5 +757,5 @@
WARN_ON(val & mask);
writel(mask, gic_dist_base(d) +
GIC_DIST_PENDING_CLEAR + (gic_irq(d) / 32) * 4);
- spin_unlock(&irq_controller_lock);
+ raw_spin_unlock(&irq_controller_lock);
}
diff --git a/arch/arm/configs/fsm9xxx-perf_defconfig b/arch/arm/configs/fsm9xxx-perf_defconfig
index b6bc4f1..92d401c 100644
--- a/arch/arm/configs/fsm9xxx-perf_defconfig
+++ b/arch/arm/configs/fsm9xxx-perf_defconfig
@@ -26,7 +26,6 @@
CONFIG_MSM7X00A_USE_DG_TIMER=y
CONFIG_MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT=y
CONFIG_MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT=y
-CONFIG_MSM_JTAG_V7=y
CONFIG_MSM_SMD=y
CONFIG_MSM_SMD_PKG3=y
# CONFIG_MSM_SMD_DEBUG is not set
@@ -35,6 +34,7 @@
# CONFIG_MSM_HW3D is not set
# CONFIG_QSD_AUDIO is not set
# CONFIG_SURF_FFA_GPIO_KEYPAD is not set
+CONFIG_MSM_JTAG_V7=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_VMSPLIT_2G=y
@@ -134,6 +134,8 @@
CONFIG_POWER_SUPPLY=y
CONFIG_SENSORS_MSM_ADC=y
CONFIG_PMIC8058=y
+# CONFIG_MFD_PM8XXX_PWM is not set
+# CONFIG_MFD_PM8XXX_MISC is not set
CONFIG_REGULATOR=y
CONFIG_REGULATOR_PM8058_XO=y
# CONFIG_USB_SUPPORT is not set
diff --git a/arch/arm/configs/fsm9xxx_defconfig b/arch/arm/configs/fsm9xxx_defconfig
index dd9797a..ebff2d2 100644
--- a/arch/arm/configs/fsm9xxx_defconfig
+++ b/arch/arm/configs/fsm9xxx_defconfig
@@ -132,6 +132,8 @@
CONFIG_POWER_SUPPLY=y
CONFIG_SENSORS_MSM_ADC=y
CONFIG_PMIC8058=y
+# CONFIG_MFD_PM8XXX_PWM is not set
+# CONFIG_MFD_PM8XXX_MISC is not set
CONFIG_REGULATOR=y
CONFIG_REGULATOR_PM8058_XO=y
# CONFIG_USB_SUPPORT is not set
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index 9fb4615..4d4c27f 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -32,6 +32,7 @@
CONFIG_ARCH_MSMCOPPER=y
CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_DEBUG_MSMCOPPER_UART=y
CONFIG_CPU_HAS_L2_PMU=y
# CONFIG_MSM_JTAG_V7 is not set
# CONFIG_MSM_FIQ_SUPPORT is not set
@@ -43,6 +44,7 @@
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
# CONFIG_SMP_ON_UP is not set
+CONFIG_ARM_ARCH_TIMER=y
CONFIG_PREEMPT=y
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
@@ -54,6 +56,7 @@
CONFIG_NEON=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
# CONFIG_SUSPEND is not set
+CONFIG_HOTPLUG_CPU=y
CONFIG_NET=y
CONFIG_UNIX=y
CONFIG_INET=y
@@ -95,7 +98,17 @@
# CONFIG_HWMON is not set
# CONFIG_MFD_SUPPORT is not set
# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_CI13XXX_MSM=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
+CONFIG_MMC_MSM=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
# CONFIG_LEDS_MSM_PMIC is not set
@@ -109,6 +122,9 @@
CONFIG_ANDROID_TIMED_GPIO=y
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
CONFIG_MSM_SSBI=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_BAMDMA=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
@@ -131,6 +147,8 @@
CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_LL=y
+CONFIG_EARLY_PRINTK=y
CONFIG_KEYS=y
CONFIG_CRYPTO_AUTHENC=y
CONFIG_CRYPTO_CBC=y
diff --git a/arch/arm/configs/msm7627-perf_defconfig b/arch/arm/configs/msm7627-perf_defconfig
index 78eeadd..0f2ffc1 100644
--- a/arch/arm/configs/msm7627-perf_defconfig
+++ b/arch/arm/configs/msm7627-perf_defconfig
@@ -255,6 +255,7 @@
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
CONFIG_MMC_PARANOID_SD_INIT=y
CONFIG_MMC_BLOCK_MINORS=32
# CONFIG_MMC_BLOCK_BOUNCE is not set
diff --git a/arch/arm/configs/msm7627_defconfig b/arch/arm/configs/msm7627_defconfig
index 7da4daf..d1d0e66 100644
--- a/arch/arm/configs/msm7627_defconfig
+++ b/arch/arm/configs/msm7627_defconfig
@@ -253,6 +253,7 @@
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
CONFIG_MMC_PARANOID_SD_INIT=y
CONFIG_MMC_BLOCK_MINORS=32
# CONFIG_MMC_BLOCK_BOUNCE is not set
@@ -288,13 +289,17 @@
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
+CONFIG_LOCKUP_DETECTOR=y
CONFIG_DETECT_HUNG_TASK=y
CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_SPINLOCK=y
CONFIG_DEBUG_MUTEXES=y
CONFIG_DEBUG_SPINLOCK_SLEEP=y
CONFIG_DEBUG_STACK_USAGE=y
CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_LIST=y
CONFIG_LATENCYTOP=y
+CONFIG_DEBUG_PAGEALLOC=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
CONFIG_CRYPTO_SHA256=y
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 83d0828..342aad6 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -31,7 +31,6 @@
# CONFIG_MACH_MSM7X27_FFA is not set
# CONFIG_MSM_STACKED_MEMORY is not set
CONFIG_MSM7X00A_USE_DG_TIMER=y
-# CONFIG_MSM_JTAG_V7 is not set
# CONFIG_MSM_FIQ_SUPPORT is not set
CONFIG_MSM_SMD=y
CONFIG_MSM_SMD_PKG4=y
@@ -45,6 +44,7 @@
# CONFIG_MSM_HW3D is not set
CONFIG_MSM7X27A_AUDIO=y
CONFIG_MSM_DMA_TEST=y
+# CONFIG_MSM_JTAG_V7 is not set
CONFIG_BT_MSM_PINTEST=y
CONFIG_MSM_RPC_VIBRATOR=y
CONFIG_PM8XXX_RPC_VIBRATOR=y
@@ -104,6 +104,7 @@
CONFIG_NF_CONNTRACK_SIP=y
CONFIG_NF_CONNTRACK_TFTP=y
CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
CONFIG_NETFILTER_XT_TARGET_MARK=y
@@ -119,10 +120,11 @@
CONFIG_NETFILTER_XT_MATCH_LIMIT=y
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
-CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
CONFIG_NETFILTER_XT_MATCH_STATE=y
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
CONFIG_NETFILTER_XT_MATCH_STRING=y
@@ -140,9 +142,11 @@
CONFIG_IP_NF_TARGET_MASQUERADE=y
CONFIG_IP_NF_TARGET_NETMAP=y
CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
CONFIG_IP_NF_ARPTABLES=y
CONFIG_IP_NF_ARPFILTER=y
CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP6_NF_IPTABLES=y
CONFIG_BT=y
CONFIG_BT_L2CAP=y
CONFIG_BT_SCO=y
@@ -160,6 +164,8 @@
CONFIG_CFG80211=y
# CONFIG_CFG80211_WEXT is not set
CONFIG_RFKILL=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
CONFIG_MTD=y
CONFIG_MTD_TESTS=m
CONFIG_MTD_CMDLINE_PARTS=y
@@ -312,9 +318,6 @@
CONFIG_DEBUG_SHIRQ=y
# CONFIG_SCHED_DEBUG is not set
CONFIG_TIMER_STATS=y
-CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_MUTEXES=y
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
CONFIG_DEBUG_STACK_USAGE=y
CONFIG_DEBUG_INFO=y
# CONFIG_FTRACE is not set
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index dcbca79..c524759 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -30,7 +30,6 @@
# CONFIG_MACH_MSM7X27_FFA is not set
# CONFIG_MSM_STACKED_MEMORY is not set
CONFIG_MSM7X00A_USE_DG_TIMER=y
-# CONFIG_MSM_JTAG_V7 is not set
# CONFIG_MSM_FIQ_SUPPORT is not set
CONFIG_MSM_SMD=y
CONFIG_MSM_SMD_PKG4=y
@@ -44,6 +43,7 @@
# CONFIG_MSM_HW3D is not set
CONFIG_MSM7X27A_AUDIO=y
CONFIG_MSM_DMA_TEST=y
+# CONFIG_MSM_JTAG_V7 is not set
CONFIG_BT_MSM_PINTEST=y
CONFIG_MSM_RPC_VIBRATOR=y
CONFIG_PM8XXX_RPC_VIBRATOR=y
@@ -102,6 +102,7 @@
CONFIG_NF_CONNTRACK_SIP=y
CONFIG_NF_CONNTRACK_TFTP=y
CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
CONFIG_NETFILTER_XT_TARGET_MARK=y
@@ -117,10 +118,11 @@
CONFIG_NETFILTER_XT_MATCH_LIMIT=y
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
-CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
CONFIG_NETFILTER_XT_MATCH_STATE=y
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
CONFIG_NETFILTER_XT_MATCH_STRING=y
@@ -138,9 +140,11 @@
CONFIG_IP_NF_TARGET_MASQUERADE=y
CONFIG_IP_NF_TARGET_NETMAP=y
CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
CONFIG_IP_NF_ARPTABLES=y
CONFIG_IP_NF_ARPFILTER=y
CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP6_NF_IPTABLES=y
CONFIG_BT=y
CONFIG_BT_L2CAP=y
CONFIG_BT_SCO=y
@@ -158,6 +162,8 @@
CONFIG_CFG80211=y
# CONFIG_CFG80211_WEXT is not set
CONFIG_RFKILL=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
CONFIG_MTD=y
CONFIG_MTD_TESTS=m
CONFIG_MTD_CMDLINE_PARTS=y
@@ -305,6 +311,7 @@
CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_SHIRQ=y
+CONFIG_LOCKUP_DETECTOR=y
CONFIG_DETECT_HUNG_TASK=y
CONFIG_TIMER_STATS=y
CONFIG_DEBUG_SPINLOCK=y
@@ -312,7 +319,9 @@
CONFIG_DEBUG_SPINLOCK_SLEEP=y
CONFIG_DEBUG_STACK_USAGE=y
CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_LIST=y
CONFIG_LATENCYTOP=y
+CONFIG_DEBUG_PAGEALLOC=y
# CONFIG_FTRACE is not set
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
diff --git a/arch/arm/configs/msm7630-perf_defconfig b/arch/arm/configs/msm7630-perf_defconfig
index 56710d7..e5fec35 100644
--- a/arch/arm/configs/msm7630-perf_defconfig
+++ b/arch/arm/configs/msm7630-perf_defconfig
@@ -26,7 +26,6 @@
CONFIG_ARCH_MSM=y
CONFIG_ARCH_MSM7X30=y
# CONFIG_MSM_STACKED_MEMORY is not set
-# CONFIG_MSM_JTAG_V7 is not set
CONFIG_MSM_SMD=y
CONFIG_MSM_SMD_PKG3=y
CONFIG_MSM_SDIO_DMUX=y
@@ -41,6 +40,7 @@
CONFIG_MSM_MEMORY_LOW_POWER_MODE_IDLE_RETENTION=y
CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN=y
CONFIG_MSM_IDLE_WAIT_ON_MODEM=2000
+# CONFIG_MSM_JTAG_V7 is not set
CONFIG_MSM_STANDALONE_POWER_COLLAPSE=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
@@ -99,6 +99,7 @@
CONFIG_NF_CONNTRACK_SIP=y
CONFIG_NF_CONNTRACK_TFTP=y
CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
CONFIG_NETFILTER_XT_TARGET_MARK=y
@@ -115,10 +116,11 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
-CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
CONFIG_NETFILTER_XT_MATCH_STATE=y
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
CONFIG_NETFILTER_XT_MATCH_STRING=y
@@ -176,6 +178,8 @@
# CONFIG_CFG80211_WEXT is not set
# CONFIG_WIRELESS_EXT_SYSFS is not set
CONFIG_RFKILL=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
CONFIG_MTD=y
CONFIG_MTD_TESTS=m
CONFIG_MTD_CMDLINE_PARTS=y
@@ -187,7 +191,7 @@
CONFIG_BLK_DEV_RAM_SIZE=16384
CONFIG_MISC_DEVICES=y
CONFIG_HAPTIC_ISA1200=y
-CONFIG_PMIC8058_UPL=y
+CONFIG_PMIC8XXX_UPL=y
CONFIG_SCSI=y
CONFIG_SCSI_TGT=y
CONFIG_BLK_DEV_SD=y
@@ -216,6 +220,8 @@
CONFIG_INPUT_EVDEV=y
CONFIG_INPUT_EVBUG=m
# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_PMIC8XXX=y
+# CONFIG_KEYBOARD_PMIC8058 is not set
# CONFIG_INPUT_MOUSE is not set
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_MSM=y
@@ -249,6 +255,9 @@
CONFIG_MARIMBA_CORE=y
CONFIG_MARIMBA_CODEC=y
CONFIG_TIMPANI_CODEC=y
+# CONFIG_MFD_PM8XXX_DEBUG is not set
+# CONFIG_MFD_PM8XXX_PWM is not set
+# CONFIG_MFD_PM8XXX_MISC is not set
CONFIG_MEDIA_SUPPORT=y
CONFIG_VIDEO_DEV=y
# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
@@ -314,6 +323,7 @@
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
CONFIG_MMC_PARANOID_SD_INIT=y
CONFIG_MMC_BLOCK_MINORS=32
# CONFIG_MMC_BLOCK_BOUNCE is not set
diff --git a/arch/arm/configs/msm7630_defconfig b/arch/arm/configs/msm7630_defconfig
index 115ce98..6e3290b 100644
--- a/arch/arm/configs/msm7630_defconfig
+++ b/arch/arm/configs/msm7630_defconfig
@@ -98,6 +98,7 @@
CONFIG_NF_CONNTRACK_SIP=y
CONFIG_NF_CONNTRACK_TFTP=y
CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
CONFIG_NETFILTER_XT_TARGET_MARK=y
@@ -114,10 +115,11 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
-CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
CONFIG_NETFILTER_XT_MATCH_STATE=y
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
CONFIG_NETFILTER_XT_MATCH_STRING=y
@@ -175,6 +177,8 @@
# CONFIG_CFG80211_WEXT is not set
# CONFIG_WIRELESS_EXT_SYSFS is not set
CONFIG_RFKILL=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
CONFIG_MTD=y
CONFIG_MTD_TESTS=m
CONFIG_MTD_CMDLINE_PARTS=y
@@ -186,7 +190,7 @@
CONFIG_BLK_DEV_RAM_SIZE=16384
CONFIG_MISC_DEVICES=y
CONFIG_HAPTIC_ISA1200=y
-CONFIG_PMIC8058_UPL=y
+CONFIG_PMIC8XXX_UPL=y
CONFIG_SCSI=y
CONFIG_SCSI_TGT=y
CONFIG_BLK_DEV_SD=y
@@ -215,6 +219,8 @@
CONFIG_INPUT_EVDEV=y
CONFIG_INPUT_EVBUG=m
# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_PMIC8XXX=y
+# CONFIG_KEYBOARD_PMIC8058 is not set
# CONFIG_INPUT_MOUSE is not set
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_MSM=y
@@ -248,6 +254,9 @@
CONFIG_MARIMBA_CORE=y
CONFIG_MARIMBA_CODEC=y
CONFIG_TIMPANI_CODEC=y
+# CONFIG_MFD_PM8XXX_DEBUG is not set
+# CONFIG_MFD_PM8XXX_PWM is not set
+# CONFIG_MFD_PM8XXX_MISC is not set
CONFIG_MSM_KGSL=y
CONFIG_VIDEO_OUTPUT_CONTROL=y
CONFIG_FB=y
@@ -300,6 +309,7 @@
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
CONFIG_MMC_PARANOID_SD_INIT=y
CONFIG_MMC_BLOCK_MINORS=32
# CONFIG_MMC_BLOCK_BOUNCE is not set
@@ -341,6 +351,7 @@
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
+CONFIG_LOCKUP_DETECTOR=y
CONFIG_DETECT_HUNG_TASK=y
CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
@@ -349,6 +360,8 @@
CONFIG_DEBUG_SPINLOCK_SLEEP=y
CONFIG_DEBUG_STACK_USAGE=y
CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_LIST=y
+CONFIG_DEBUG_PAGEALLOC=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
CONFIG_CRYPTO_SHA256=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index de58931..01150aa 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -25,6 +25,7 @@
# CONFIG_SLUB_DEBUG is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
@@ -43,7 +44,6 @@
CONFIG_MSM7X00A_USE_DG_TIMER=y
CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE=y
CONFIG_MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT=y
-# CONFIG_MSM_JTAG_V7 is not set
# CONFIG_MSM_FIQ_SUPPORT is not set
# CONFIG_MSM_PROC_COMM is not set
CONFIG_MSM_SMD=y
@@ -67,6 +67,7 @@
CONFIG_MSM_RPM_STATS_LOG=y
CONFIG_MSM_WATCHDOG=y
CONFIG_MSM_DLOAD_MODE=y
+# CONFIG_MSM_JTAG_V7 is not set
CONFIG_MSM_ETM=y
CONFIG_MSM_SLEEP_STATS=y
CONFIG_MSM_GSBI9_UART=y
@@ -132,6 +133,7 @@
CONFIG_NF_CONNTRACK_SIP=y
CONFIG_NF_CONNTRACK_TFTP=y
CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
CONFIG_NETFILTER_XT_TARGET_MARK=y
@@ -149,10 +151,11 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
-CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
CONFIG_NETFILTER_XT_MATCH_STATE=y
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
CONFIG_NETFILTER_XT_MATCH_STRING=y
@@ -215,6 +218,8 @@
# CONFIG_CFG80211_WEXT is not set
# CONFIG_WIRELESS_EXT_SYSFS is not set
CONFIG_RFKILL=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_MISC_DEVICES=y
@@ -222,10 +227,9 @@
CONFIG_TSIF=m
CONFIG_TSIF_CHRDEV=m
CONFIG_HAPTIC_ISA1200=y
-CONFIG_PMIC8058_VIBRATOR=y
-CONFIG_PMIC8058_UPL=y
+CONFIG_PMIC8XXX_VIBRATOR=y
+CONFIG_PMIC8XXX_UPL=y
CONFIG_PMIC8058_XOADC=y
-CONFIG_PMIC8058_MISC=y
CONFIG_TZCOM=y
CONFIG_SCSI=y
CONFIG_SCSI_TGT=y
@@ -262,6 +266,8 @@
CONFIG_INPUT_KEYRESET=y
CONFIG_KEYBOARD_GPIO=y
CONFIG_KEYBOARD_MATRIX=y
+CONFIG_KEYBOARD_PMIC8XXX=y
+# CONFIG_KEYBOARD_PMIC8058 is not set
CONFIG_INPUT_JOYSTICK=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH=y
@@ -269,7 +275,7 @@
CONFIG_TOUCHSCREEN_CYTTSP_I2C=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=y
-CONFIG_PMIC8058_PWRKEY=y
+CONFIG_INPUT_PMIC8XXX_PWRKEY=y
CONFIG_PMIC8058_OTHC=y
CONFIG_SERIAL_MSM_HS=y
CONFIG_SERIAL_MSM_HSL=y
@@ -300,11 +306,14 @@
CONFIG_THERMAL=y
CONFIG_THERMAL_HWMON=y
CONFIG_THERMAL_PM8901=y
-CONFIG_THERMAL_PM8058=y
CONFIG_THERMAL_TSENS=y
+CONFIG_THERMAL_PM8XXX=y
CONFIG_PMIC8058=y
+CONFIG_PMIC8901=y
CONFIG_MARIMBA_CORE=y
CONFIG_TIMPANI_CODEC=y
+# CONFIG_MFD_PM8XXX_PWM is not set
+CONFIG_MFD_PM8XXX_BATT_ALARM=y
CONFIG_MEDIA_SUPPORT=y
CONFIG_VIDEO_DEV=y
# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
@@ -324,7 +333,6 @@
CONFIG_FB_MSM_TRIPLE_BUFFER=y
CONFIG_FB_MSM_MDP40=y
CONFIG_FB_MSM_OVERLAY=y
-CONFIG_FB_MSM_OVERLAY_WRITEBACK=y
CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT=y
CONFIG_FB_MSM_HDMI_MSM_PANEL=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
@@ -364,6 +372,7 @@
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
CONFIG_MMC_EMBEDDED_SDIO=y
CONFIG_MMC_PARANOID_SD_INIT=y
CONFIG_MMC_BLOCK_MINORS=32
@@ -387,7 +396,7 @@
CONFIG_SWITCH_GPIO=y
CONFIG_RTC_CLASS=y
# CONFIG_RTC_DRV_MSM is not set
-CONFIG_RTC_PM8058=y
+CONFIG_RTC_DRV_PM8XXX=y
CONFIG_STAGING=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
@@ -417,12 +426,10 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
# CONFIG_SCHED_DEBUG is not set
CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_PREEMPT is not set
-# CONFIG_STACKTRACE is not set
CONFIG_DEBUG_INFO=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index 6d99df7..7b2fede 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -123,6 +123,7 @@
CONFIG_NF_CONNTRACK_SIP=y
CONFIG_NF_CONNTRACK_TFTP=y
CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
CONFIG_NETFILTER_XT_TARGET_MARK=y
@@ -140,10 +141,11 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
-CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
CONFIG_NETFILTER_XT_MATCH_STATE=y
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
CONFIG_NETFILTER_XT_MATCH_STRING=y
@@ -206,18 +208,18 @@
# CONFIG_CFG80211_WEXT is not set
# CONFIG_WIRELESS_EXT_SYSFS is not set
CONFIG_RFKILL=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_MISC_DEVICES=y
-CONFIG_KERNEL_DEBUGGER_CORE=y
CONFIG_UID_STAT=y
CONFIG_TSIF=m
CONFIG_TSIF_CHRDEV=m
CONFIG_HAPTIC_ISA1200=y
-CONFIG_PMIC8058_VIBRATOR=y
-CONFIG_PMIC8058_UPL=y
+CONFIG_PMIC8XXX_VIBRATOR=y
+CONFIG_PMIC8XXX_UPL=y
CONFIG_PMIC8058_XOADC=y
-CONFIG_PMIC8058_MISC=y
CONFIG_TZCOM=y
CONFIG_SCSI=y
CONFIG_SCSI_TGT=y
@@ -254,6 +256,8 @@
CONFIG_INPUT_KEYRESET=y
CONFIG_KEYBOARD_GPIO=y
CONFIG_KEYBOARD_MATRIX=y
+CONFIG_KEYBOARD_PMIC8XXX=y
+# CONFIG_KEYBOARD_PMIC8058 is not set
CONFIG_INPUT_JOYSTICK=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH=y
@@ -261,7 +265,7 @@
CONFIG_TOUCHSCREEN_CYTTSP_I2C=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=y
-CONFIG_PMIC8058_PWRKEY=y
+CONFIG_INPUT_PMIC8XXX_PWRKEY=y
CONFIG_PMIC8058_OTHC=y
CONFIG_SERIAL_MSM_HS=y
CONFIG_SERIAL_MSM_HSL=y
@@ -291,11 +295,14 @@
CONFIG_SENSORS_MSM_ADC=y
CONFIG_THERMAL=y
CONFIG_THERMAL_PM8901=y
-CONFIG_THERMAL_PM8058=y
CONFIG_THERMAL_TSENS=y
+CONFIG_THERMAL_PM8XXX=y
CONFIG_PMIC8058=y
+CONFIG_PMIC8901=y
CONFIG_MARIMBA_CORE=y
CONFIG_TIMPANI_CODEC=y
+# CONFIG_MFD_PM8XXX_PWM is not set
+CONFIG_MFD_PM8XXX_BATT_ALARM=y
CONFIG_MEDIA_SUPPORT=y
CONFIG_VIDEO_DEV=y
# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
@@ -313,7 +320,6 @@
CONFIG_FB_MSM_TRIPLE_BUFFER=y
CONFIG_FB_MSM_MDP40=y
CONFIG_FB_MSM_OVERLAY=y
-CONFIG_FB_MSM_OVERLAY_WRITEBACK=y
CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT=y
CONFIG_FB_MSM_HDMI_MSM_PANEL=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
@@ -351,6 +357,7 @@
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
CONFIG_MMC_EMBEDDED_SDIO=y
CONFIG_MMC_PARANOID_SD_INIT=y
CONFIG_MMC_BLOCK_MINORS=32
@@ -374,7 +381,7 @@
CONFIG_SWITCH_GPIO=y
CONFIG_RTC_CLASS=y
# CONFIG_RTC_DRV_MSM is not set
-CONFIG_RTC_PM8058=y
+CONFIG_RTC_DRV_PM8XXX=y
CONFIG_STAGING=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
@@ -405,8 +412,10 @@
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_KERNEL=y
+CONFIG_LOCKUP_DETECTOR=y
CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
+CONFIG_SLUB_DEBUG_ON=y
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_PROVE_LOCKING=y
CONFIG_DEBUG_SPINLOCK_SLEEP=y
@@ -414,7 +423,9 @@
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_VM=y
CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_LIST=y
CONFIG_DEBUG_SG=y
+CONFIG_DEBUG_PAGEALLOC=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
CONFIG_DEBUG_LL=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
old mode 100755
new mode 100644
index c41f64c..9f3d72b
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -26,6 +26,7 @@
CONFIG_EMBEDDED=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
@@ -44,24 +45,27 @@
CONFIG_MACH_MSM8930_CDP=y
CONFIG_MACH_MSM8930_MTP=y
CONFIG_MACH_MSM8930_FLUID=y
+CONFIG_MACH_MSM8627_CDP=y
+CONFIG_MACH_MSM8627_MTP=y
CONFIG_MACH_APQ8064_SIM=y
CONFIG_MACH_APQ8064_RUMI3=y
# CONFIG_MSM_STACKED_MEMORY is not set
CONFIG_KERNEL_PMEM_EBI_REGION=y
-# CONFIG_MSM_JTAG_V7 is not set
# CONFIG_MSM_FIQ_SUPPORT is not set
# CONFIG_MSM_PROC_COMM is not set
CONFIG_MSM_SMD=y
CONFIG_MSM_SMD_PKG4=y
-CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
CONFIG_MSM_BAM_DMUX=y
CONFIG_MSM_DSPS=y
CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
# CONFIG_MSM_HW3D is not set
+CONFIG_MSM_PIL_QDSP6V4=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
CONFIG_MSM_MODEM_8960=y
CONFIG_MSM_LPASS_8960=y
CONFIG_MSM_WCNSS_SSR_8960=y
+CONFIG_MSM_TZ_LOG=y
CONFIG_MSM_RPM_LOG=y
CONFIG_MSM_RPM_STATS_LOG=y
CONFIG_MSM_BUS_SCALING=y
@@ -71,6 +75,7 @@
CONFIG_MSM_QDSS=y
CONFIG_MSM_SLEEP_STATS=y
CONFIG_STRICT_MEMORY_RWX=y
+CONFIG_MSM_SHOW_RESUME_IRQ=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
@@ -79,6 +84,7 @@
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_CP_ACCESS=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
@@ -102,7 +108,6 @@
# CONFIG_INET_XFRM_MODE_TUNNEL is not set
# CONFIG_INET_XFRM_MODE_BEET is not set
# CONFIG_INET_LRO is not set
-CONFIG_INET_DIAG=y
CONFIG_IPV6=y
CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
@@ -131,6 +136,7 @@
CONFIG_NF_CONNTRACK_SIP=y
CONFIG_NF_CONNTRACK_TFTP=y
CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
CONFIG_NETFILTER_XT_TARGET_MARK=y
@@ -147,10 +153,11 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
-CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
CONFIG_NETFILTER_XT_MATCH_STATE=y
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
CONFIG_NETFILTER_XT_MATCH_STRING=y
@@ -197,11 +204,13 @@
CONFIG_BT_BNEP_PROTO_FILTER=y
CONFIG_BT_HIDP=y
CONFIG_BT_HCISMD=y
+CONFIG_CFG80211=y
+# CONFIG_CFG80211_WEXT is not set
CONFIG_RFKILL=y
-CONFIG_RFKILL_PM=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
-CONFIG_MISC_DEVICES=y
CONFIG_HAPTIC_ISA1200=y
CONFIG_PMIC8XXX_VIBRATOR=y
CONFIG_TZCOM=y
@@ -227,8 +236,7 @@
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
CONFIG_WCNSS_CORE=m
-CONFIG_CFG80211=y
-CONFIG_CFG80211_WEXT=n
+CONFIG_USB_USBNET=y
CONFIG_SLIP=y
CONFIG_SLIP_COMPRESSED=y
CONFIG_SLIP_MODE_SLIP6=y
@@ -268,7 +276,7 @@
CONFIG_ISL9519_CHARGER=y
CONFIG_PM8921_CHARGER=y
CONFIG_PM8921_BMS=y
-CONFIG_SENSORS_PM8921_ADC=y
+CONFIG_SENSORS_PM8XXX_ADC=y
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8960=y
CONFIG_THERMAL_PM8XXX=y
@@ -300,7 +308,6 @@
CONFIG_FB_MSM_TRIPLE_BUFFER=y
CONFIG_FB_MSM_MDP40=y
CONFIG_FB_MSM_OVERLAY=y
-CONFIG_FB_MSM_OVERLAY_WRITEBACK=y
CONFIG_FB_MSM_MIPI_PANEL_DETECT=y
CONFIG_FB_MSM_HDMI_MSM_PANEL=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
@@ -338,7 +345,7 @@
CONFIG_USB_SERIAL_QUALCOMM=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
CONFIG_USB_QCOM_DIAG_BRIDGE=y
-CONFIG_USB_QCOM_DUN_BRIDGE=y
+CONFIG_USB_QCOM_MDM_BRIDGE=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_DEBUG_FILES=y
CONFIG_USB_GADGET_CI13XXX_MSM=y
@@ -359,7 +366,6 @@
CONFIG_MMC_MSM_SDC3_WP_SUPPORT=y
CONFIG_MMC_MSM_SPS_SUPPORT=y
CONFIG_LEDS_PM8XXX=y
-# CONFIG_LEDS_MSM_PMIC is not set
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_SWITCH=y
@@ -396,7 +402,6 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
CONFIG_LOCKUP_DETECTOR=y
# CONFIG_SCHED_DEBUG is not set
@@ -410,6 +415,7 @@
CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_DEBUG_LIST=y
CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_ENABLE_DEFAULT_TRACERS=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
CONFIG_CRYPTO_SHA256=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index 67d0057..003f9c1 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -26,7 +26,6 @@
CONFIG_EMBEDDED=y
# CONFIG_PERF_EVENTS is not set
CONFIG_PROFILING=y
-CONFIG_OPROFILE=m
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
@@ -36,12 +35,12 @@
CONFIG_MACH_MSM9615_MTP=y
# CONFIG_MSM_STACKED_MEMORY is not set
CONFIG_CPU_HAS_L2_PMU=y
-# CONFIG_MSM_JTAG_V7 is not set
# CONFIG_MSM_FIQ_SUPPORT is not set
# CONFIG_MSM_PROC_COMM is not set
CONFIG_MSM_SMD=y
CONFIG_MSM_SMD_PKG4=y
CONFIG_MSM_BAM_DMUX=y
+# CONFIG_MSM_RESET_MODEM is not set
CONFIG_MSM_IPC_ROUTER=y
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
@@ -49,8 +48,11 @@
CONFIG_MSM_MODEM_8960=y
CONFIG_MSM_LPASS_8960=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_MSM_BUS_SCALING=y
+CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED=y
CONFIG_MSM_WATCHDOG=y
CONFIG_MSM_DLOAD_MODE=y
+# CONFIG_MSM_JTAG_V7 is not set
CONFIG_SWP_EMULATE=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
@@ -92,16 +94,26 @@
CONFIG_BLK_DEV_RAM=y
CONFIG_MISC_DEVICES=y
# CONFIG_ANDROID_PMEM is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
CONFIG_NETDEVICES=y
-CONFIG_HOSTAP=m
+CONFIG_HOSTAP=y
# CONFIG_MSM_RMNET is not set
CONFIG_MSM_RMNET_BAM=y
# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=y
-CONFIG_INPUT_GPIO=m
CONFIG_INPUT_PMIC8XXX_PWRKEY=y
CONFIG_SERIO_LIBPS2=y
CONFIG_SERIAL_MSM=y
@@ -131,9 +143,29 @@
CONFIG_REGULATOR_GPIO=y
# CONFIG_HID_SUPPORT is not set
CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_EHSET=y
+CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DEBUG=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_CI13XXX_MSM=y
CONFIG_USB_G_ANDROID=y
+CONFIG_RMNET_SMD_CTL_CHANNEL="DATA36_CNTL"
+CONFIG_RMNET_SMD_DATA_CHANNEL="DATA36"
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
CONFIG_MMC_UNSAFE_RESUME=y
@@ -184,11 +216,10 @@
CONFIG_CRYPTO_MD5=y
CONFIG_CRYPTO_SHA1=y
CONFIG_CRYPTO_SHA256=y
-CONFIG_CRYPTO_AES=y
-CONFIG_CRYPTO_ARC4=y
CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=m
CONFIG_CRYPTO_DEV_QCEDEV=m
diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h
new file mode 100644
index 0000000..e82217f
--- /dev/null
+++ b/arch/arm/include/asm/arch_timer.h
@@ -0,0 +1,8 @@
+#ifndef __ASMARM_ARCH_TIMER_H
+#define __ASMARM_ARCH_TIMER_H
+
+struct resource;
+
+int arch_timer_register(struct resource *res, int res_nr);
+
+#endif
diff --git a/arch/arm/include/asm/dma.h b/arch/arm/include/asm/dma.h
index 4200554..8a54b7d 100644
--- a/arch/arm/include/asm/dma.h
+++ b/arch/arm/include/asm/dma.h
@@ -33,18 +33,18 @@
#define DMA_MODE_CASCADE 0xc0
#define DMA_AUTOINIT 0x10
-extern spinlock_t dma_spin_lock;
+extern raw_spinlock_t dma_spin_lock;
static inline unsigned long claim_dma_lock(void)
{
unsigned long flags;
- spin_lock_irqsave(&dma_spin_lock, flags);
+ raw_spin_lock_irqsave(&dma_spin_lock, flags);
return flags;
}
static inline void release_dma_lock(unsigned long flags)
{
- spin_unlock_irqrestore(&dma_spin_lock, flags);
+ raw_spin_unlock_irqrestore(&dma_spin_lock, flags);
}
/* Clear the 'DMA Pointer Flip Flop'.
diff --git a/arch/arm/include/asm/fiq_debugger.h b/arch/arm/include/asm/fiq_debugger.h
index e711b57..4d27488 100644
--- a/arch/arm/include/asm/fiq_debugger.h
+++ b/arch/arm/include/asm/fiq_debugger.h
@@ -27,6 +27,19 @@
#define FIQ_DEBUGGER_SIGNAL_IRQ_NAME "signal"
#define FIQ_DEBUGGER_WAKEUP_IRQ_NAME "wakeup"
+/**
+ * struct fiq_debugger_pdata - fiq debugger platform data
+ * @uart_resume: used to restore uart state right before enabling
+ * the fiq.
+ * @uart_enable: Do the work necessary to communicate with the uart
+ * hw (enable clocks, etc.). This must be ref-counted.
+ * @uart_disable: Do the work necessary to disable the uart hw
+ * (disable clocks, etc.). This must be ref-counted.
+ * @uart_dev_suspend: called during PM suspend, generally not needed
+ * for real fiq mode debugger.
+ * @uart_dev_resume: called during PM resume, generally not needed
+ * for real fiq mode debugger.
+ */
struct fiq_debugger_pdata {
int (*uart_init)(struct platform_device *pdev);
void (*uart_free)(struct platform_device *pdev);
@@ -34,6 +47,11 @@
int (*uart_getc)(struct platform_device *pdev);
void (*uart_putc)(struct platform_device *pdev, unsigned int c);
void (*uart_flush)(struct platform_device *pdev);
+ void (*uart_enable)(struct platform_device *pdev);
+ void (*uart_disable)(struct platform_device *pdev);
+
+ int (*uart_dev_suspend)(struct platform_device *pdev);
+ int (*uart_dev_resume)(struct platform_device *pdev);
void (*fiq_enable)(struct platform_device *pdev, unsigned int fiq,
bool enable);
diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
index 8c73900..253cc86 100644
--- a/arch/arm/include/asm/futex.h
+++ b/arch/arm/include/asm/futex.h
@@ -25,17 +25,17 @@
#ifdef CONFIG_SMP
-#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
+#define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \
smp_mb(); \
__asm__ __volatile__( \
- "1: ldrex %1, [%2]\n" \
+ "1: ldrex %1, [%3]\n" \
" " insn "\n" \
- "2: strex %1, %0, [%2]\n" \
- " teq %1, #0\n" \
+ "2: strex %2, %0, [%3]\n" \
+ " teq %2, #0\n" \
" bne 1b\n" \
" mov %0, #0\n" \
- __futex_atomic_ex_table("%4") \
- : "=&r" (ret), "=&r" (oldval) \
+ __futex_atomic_ex_table("%5") \
+ : "=&r" (ret), "=&r" (oldval), "=&r" (tmp) \
: "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \
: "cc", "memory")
@@ -73,14 +73,14 @@
#include <linux/preempt.h>
#include <asm/domain.h>
-#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
+#define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \
__asm__ __volatile__( \
- "1: " T(ldr) " %1, [%2]\n" \
+ "1: " T(ldr) " %1, [%3]\n" \
" " insn "\n" \
- "2: " T(str) " %0, [%2]\n" \
+ "2: " T(str) " %0, [%3]\n" \
" mov %0, #0\n" \
- __futex_atomic_ex_table("%4") \
- : "=&r" (ret), "=&r" (oldval) \
+ __futex_atomic_ex_table("%5") \
+ : "=&r" (ret), "=&r" (oldval), "=&r" (tmp) \
: "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \
: "cc", "memory")
@@ -117,7 +117,7 @@
int cmp = (encoded_op >> 24) & 15;
int oparg = (encoded_op << 8) >> 20;
int cmparg = (encoded_op << 20) >> 20;
- int oldval = 0, ret;
+ int oldval = 0, ret, tmp;
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;
@@ -129,19 +129,19 @@
switch (op) {
case FUTEX_OP_SET:
- __futex_atomic_op("mov %0, %3", ret, oldval, uaddr, oparg);
+ __futex_atomic_op("mov %0, %4", ret, oldval, tmp, uaddr, oparg);
break;
case FUTEX_OP_ADD:
- __futex_atomic_op("add %0, %1, %3", ret, oldval, uaddr, oparg);
+ __futex_atomic_op("add %0, %1, %4", ret, oldval, tmp, uaddr, oparg);
break;
case FUTEX_OP_OR:
- __futex_atomic_op("orr %0, %1, %3", ret, oldval, uaddr, oparg);
+ __futex_atomic_op("orr %0, %1, %4", ret, oldval, tmp, uaddr, oparg);
break;
case FUTEX_OP_ANDN:
- __futex_atomic_op("and %0, %1, %3", ret, oldval, uaddr, ~oparg);
+ __futex_atomic_op("and %0, %1, %4", ret, oldval, tmp, uaddr, ~oparg);
break;
case FUTEX_OP_XOR:
- __futex_atomic_op("eor %0, %1, %3", ret, oldval, uaddr, oparg);
+ __futex_atomic_op("eor %0, %1, %4", ret, oldval, tmp, uaddr, oparg);
break;
default:
ret = -ENOSYS;
diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h
index 2635c8b..41c8c06 100644
--- a/arch/arm/include/asm/hardirq.h
+++ b/arch/arm/include/asm/hardirq.h
@@ -5,7 +5,7 @@
#include <linux/threads.h>
#include <asm/irq.h>
-#define NR_IPI 6
+#define NR_IPI 7
typedef struct {
unsigned int __softirq_pending;
diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h
index 1fc2f49..49106e1 100644
--- a/arch/arm/include/asm/hardware/cache-l2x0.h
+++ b/arch/arm/include/asm/hardware/cache-l2x0.h
@@ -57,6 +57,7 @@
#define L2X0_STNDBY_MODE_EN (1 << 0)
/* Registers shifts and masks */
+#define L2X0_CACHE_ID_REV_MASK (0x3f)
#define L2X0_CACHE_ID_PART_MASK (0xf << 6)
#define L2X0_CACHE_ID_PART_L210 (1 << 6)
#define L2X0_CACHE_ID_PART_L220 (2 << 6)
@@ -65,7 +66,7 @@
#define L2X0_AUX_CTRL_MASK 0xc0000fff
#define L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT 16
#define L2X0_AUX_CTRL_WAY_SIZE_SHIFT 17
-#define L2X0_AUX_CTRL_WAY_SIZE_MASK (0x3 << 17)
+#define L2X0_AUX_CTRL_WAY_SIZE_MASK (0x7 << 17)
#define L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT 22
#define L2X0_AUX_CTRL_NS_LOCKDOWN_SHIFT 26
#define L2X0_AUX_CTRL_NS_INT_CTRL_SHIFT 27
@@ -74,6 +75,8 @@
#define L2X0_AUX_CTRL_EARLY_BRESP_SHIFT 30
#define L2X0_AUX_CTRL_EVNT_MON_BUS_EN_SHIFT 20
+#define REV_PL310_R2P0 4
+
#ifndef __ASSEMBLY__
extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask);
extern void l2x0_suspend(void);
diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h
index 27adea3..9491ab3 100644
--- a/arch/arm/include/asm/hardware/gic.h
+++ b/arch/arm/include/asm/hardware/gic.h
@@ -43,6 +43,25 @@
void gic_enable_ppi(unsigned int);
bool gic_is_spi_pending(unsigned int irq);
void gic_clear_spi_pending(unsigned int irq);
+
+struct gic_chip_data {
+ unsigned int irq_offset;
+ void __iomem *dist_base;
+ void __iomem *cpu_base;
+ unsigned int max_irq;
+#ifdef CONFIG_PM
+ unsigned int wakeup_irqs[32];
+ unsigned int enabled_irqs[32];
+#endif
+#ifdef CONFIG_CPU_PM
+ u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)];
+ u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)];
+ u32 saved_spi_target[DIV_ROUND_UP(1020, 4)];
+ u32 __percpu *saved_ppi_enable;
+ u32 __percpu *saved_ppi_conf;
+#endif
+ unsigned int gic_irqs;
+};
#endif
#endif
diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h
index 5a526af..a565633 100644
--- a/arch/arm/include/asm/irq.h
+++ b/arch/arm/include/asm/irq.h
@@ -26,6 +26,9 @@
void handle_IRQ(unsigned int, struct pt_regs *);
void init_IRQ(void);
+void arch_trigger_all_cpu_backtrace(void);
+#define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace
+
#endif
#endif
diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h
index b4ffe9d..1496565 100644
--- a/arch/arm/include/asm/mmu.h
+++ b/arch/arm/include/asm/mmu.h
@@ -6,7 +6,7 @@
typedef struct {
#ifdef CONFIG_CPU_HAS_ASID
unsigned int id;
- spinlock_t id_lock;
+ raw_spinlock_t id_lock;
#endif
unsigned int kvm_seq;
} mm_context_t;
@@ -16,7 +16,7 @@
/* init_mm.context.id_lock should be initialized. */
#define INIT_MM_CONTEXT(name) \
- .context.id_lock = __SPIN_LOCK_UNLOCKED(name.context.id_lock),
+ .context.id_lock = __RAW_SPIN_LOCK_UNLOCKED(name.context.id_lock),
#else
#define ASID(mm) (0)
#endif
diff --git a/arch/arm/include/asm/mmu_writeable.h b/arch/arm/include/asm/mmu_writeable.h
index b3ce39b..96d348c 100644
--- a/arch/arm/include/asm/mmu_writeable.h
+++ b/arch/arm/include/asm/mmu_writeable.h
@@ -26,4 +26,6 @@
static inline void mem_text_writeable_spinunlock(unsigned long *flags) {};
#endif
+void mem_text_write_kernel_word(unsigned long *addr, unsigned long word);
+
#endif
diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h
index 0e1fd19..87d1bed 100644
--- a/arch/arm/include/asm/perf_event.h
+++ b/arch/arm/include/asm/perf_event.h
@@ -24,6 +24,8 @@
ARM_PERF_PMU_ID_V6MP,
ARM_PERF_PMU_ID_CA8,
ARM_PERF_PMU_ID_CA9,
+ ARM_PERF_PMU_ID_CA5,
+ ARM_PERF_PMU_ID_CA15,
ARM_PERF_PMU_ID_SCORPION,
ARM_PERF_PMU_ID_SCORPIONMP,
ARM_PERF_PMU_ID_KRAIT,
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index cbb2f45..9693d47 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -485,15 +485,8 @@
* remap a physical page `pfn' of size `size' with page protection `prot'
* into virtual address `from'
*/
-#ifndef HAS_ARCH_IO_REMAP_PFN_RANGE
#define io_remap_pfn_range(vma,from,pfn,size,prot) \
remap_pfn_range(vma,from,pfn,size,prot)
-#else
-extern int arch_io_remap_pfn_range(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn, unsigned long size, pgprot_t prot);
-#define io_remap_pfn_range(vma,from,pfn,size,prot) \
- arch_io_remap_pfn_range(vma,from,pfn,size,prot)
-#endif
-
#define pgtable_cache_init() do { } while (0)
diff --git a/arch/arm/include/asm/setup.h b/arch/arm/include/asm/setup.h
index 7ef3a30..7dac1d4 100644
--- a/arch/arm/include/asm/setup.h
+++ b/arch/arm/include/asm/setup.h
@@ -211,7 +211,8 @@
for (iter = 0; iter < (mi)->nr_banks; iter++)
#define bank_pfn_start(bank) __phys_to_pfn((bank)->start)
-#define bank_pfn_end(bank) __phys_to_pfn((bank)->start + (bank)->size)
+#define bank_pfn_end(bank) (__phys_to_pfn((bank)->start) + \
+ __phys_to_pfn((bank)->size))
#define bank_pfn_size(bank) ((bank)->size >> PAGE_SHIFT)
#define bank_phys_start(bank) (bank)->start
#define bank_phys_end(bank) ((bank)->start + (bank)->size)
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 787b12d..8145184 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -71,6 +71,12 @@
extern void platform_smp_prepare_cpus(unsigned int);
/*
+ * Logical CPU mapping.
+ */
+extern int __cpu_logical_map[NR_CPUS];
+#define cpu_logical_map(cpu) __cpu_logical_map[cpu]
+
+/*
* Initial data for bringing up a secondary CPU.
*/
struct secondary_data {
@@ -98,4 +104,6 @@
*/
extern void show_local_irqs(struct seq_file *, int);
+extern void smp_send_all_cpu_backtrace(void);
+
#endif /* ifndef __ASM_ARM_SMP_H */
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index a5b31af..c77c2fb 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -34,6 +34,7 @@
obj-$(CONFIG_SMP) += smp.o smp_tlb.o
obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o
obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o
+obj-$(CONFIG_ARM_ARCH_TIMER) += arch_timer.o
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
new file mode 100644
index 0000000..0cd27bc
--- /dev/null
+++ b/arch/arm/kernel/arch_timer.c
@@ -0,0 +1,354 @@
+/*
+ * linux/arch/arm/kernel/arch_timer.c
+ *
+ * Copyright (C) 2011 ARM Ltd.
+ * 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
+ * published by the Free Software Foundation.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timex.h>
+#include <linux/device.h>
+#include <linux/smp.h>
+#include <linux/cpu.h>
+#include <linux/jiffies.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <asm/cputype.h>
+#include <asm/sched_clock.h>
+#include <asm/hardware/gic.h>
+
+static struct irqaction arch_irqaction[2];
+static unsigned long arch_timer_rate;
+static int arch_timer_ppi;
+static int arch_timer_ppi2;
+static DEFINE_CLOCK_DATA(cd);
+
+static struct clock_event_device __percpu *arch_timer_evt;
+
+/*
+ * Architected system timer support.
+ */
+
+#define ARCH_TIMER_CTRL_ENABLE (1 << 0)
+#define ARCH_TIMER_CTRL_IT_MASK (1 << 1)
+
+#define ARCH_TIMER_REG_CTRL 0
+#define ARCH_TIMER_REG_FREQ 1
+#define ARCH_TIMER_REG_TVAL 2
+
+static void arch_timer_reg_write(int reg, u32 val)
+{
+ switch (reg) {
+ case ARCH_TIMER_REG_CTRL:
+ asm volatile("mcr p15, 0, %0, c14, c2, 1" : : "r" (val));
+ break;
+ case ARCH_TIMER_REG_TVAL:
+ asm volatile("mcr p15, 0, %0, c14, c2, 0" : : "r" (val));
+ break;
+ }
+
+ isb();
+}
+
+static u32 arch_timer_reg_read(int reg)
+{
+ u32 val;
+
+ switch (reg) {
+ case ARCH_TIMER_REG_CTRL:
+ asm volatile("mrc p15, 0, %0, c14, c2, 1" : "=r" (val));
+ break;
+ case ARCH_TIMER_REG_FREQ:
+ asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (val));
+ break;
+ case ARCH_TIMER_REG_TVAL:
+ asm volatile("mrc p15, 0, %0, c14, c2, 0" : "=r" (val));
+ break;
+ default:
+ BUG();
+ }
+
+ return val;
+}
+
+static irqreturn_t arch_timer_handler(int irq, void *dev_id)
+{
+ struct clock_event_device *evt;
+ unsigned long ctrl;
+
+ ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
+ if (ctrl & 0x4) {
+ ctrl |= ARCH_TIMER_CTRL_IT_MASK;
+ arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
+ evt = per_cpu_ptr(arch_timer_evt, smp_processor_id());
+ evt->event_handler(evt);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static void arch_timer_stop(void)
+{
+ unsigned long ctrl;
+
+ ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
+ ctrl &= ~ARCH_TIMER_CTRL_ENABLE;
+ arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
+}
+
+static void arch_timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *clk)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ arch_timer_stop();
+ break;
+ default:
+ break;
+ }
+}
+
+static int arch_timer_set_next_event(unsigned long evt,
+ struct clock_event_device *unused)
+{
+ unsigned long ctrl;
+
+ ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
+ ctrl |= ARCH_TIMER_CTRL_ENABLE;
+ ctrl &= ~ARCH_TIMER_CTRL_IT_MASK;
+
+ arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
+ arch_timer_reg_write(ARCH_TIMER_REG_TVAL, evt);
+
+ return 0;
+}
+
+static void __cpuinit arch_timer_setup(void *data)
+{
+ struct clock_event_device *clk = data;
+
+ /* Be safe... */
+ arch_timer_stop();
+
+ clk->features = CLOCK_EVT_FEAT_ONESHOT;
+ clk->name = "arch_sys_timer";
+ clk->rating = 450;
+ clk->set_mode = arch_timer_set_mode;
+ clk->set_next_event = arch_timer_set_next_event;
+ clk->irq = arch_timer_ppi;
+ clk->cpumask = cpumask_of(smp_processor_id());
+
+ clockevents_config_and_register(clk, arch_timer_rate,
+ 0xf, 0x7fffffff);
+
+ gic_enable_ppi(arch_timer_ppi);
+ if (arch_timer_ppi2 > 0)
+ gic_enable_ppi(arch_timer_ppi2);
+}
+
+/* Is the optional system timer available? */
+static int local_timer_is_architected(void)
+{
+ return (cpu_architecture() >= CPU_ARCH_ARMv7) &&
+ ((read_cpuid_ext(CPUID_EXT_PFR1) >> 16) & 0xf) == 1;
+}
+
+static int arch_timer_available(void)
+{
+ unsigned long freq;
+
+ if (!local_timer_is_architected())
+ return -ENXIO;
+
+ if (arch_timer_rate == 0) {
+ arch_timer_reg_write(ARCH_TIMER_REG_CTRL, 0);
+ freq = arch_timer_reg_read(ARCH_TIMER_REG_FREQ);
+
+ /* Check the timer frequency. */
+ if (freq == 0) {
+ pr_warn("Architected timer frequency not available\n");
+ return -EINVAL;
+ }
+
+ arch_timer_rate = freq;
+ pr_info("Architected local timer running at %lu.%02luMHz.\n",
+ arch_timer_rate / 1000000, (arch_timer_rate % 100000) / 100);
+ }
+
+ return 0;
+}
+
+static inline cycle_t arch_counter_get_cntpct(void)
+{
+ u32 cvall, cvalh;
+
+ asm volatile("mrrc p15, 0, %0, %1, c14" : "=r" (cvall), "=r" (cvalh));
+
+ return ((u64) cvalh << 32) | cvall;
+}
+
+static inline cycle_t arch_counter_get_cntvct(void)
+{
+ u32 cvall, cvalh;
+
+ asm volatile("mrrc p15, 1, %0, %1, c14" : "=r" (cvall), "=r" (cvalh));
+
+ return ((u64) cvalh << 32) | cvall;
+}
+
+static cycle_t arch_counter_read(struct clocksource *cs)
+{
+ return arch_counter_get_cntpct();
+}
+
+#ifdef ARCH_HAS_READ_CURRENT_TIMER
+int read_current_timer(unsigned long *timer_val)
+{
+ *timer_val = (unsigned long)arch_counter_get_cntpct();
+ return 0;
+}
+#endif
+
+static struct clocksource clocksource_counter = {
+ .name = "arch_sys_counter",
+ .rating = 400,
+ .read = arch_counter_read,
+ .mask = CLOCKSOURCE_MASK(56),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static u32 arch_counter_get_cntvct32(void)
+{
+ cycle_t cntvct;
+
+ cntvct = arch_counter_get_cntvct();
+
+ /*
+ * The sched_clock infrastructure only knows about counters
+ * with at most 32bits. Forget about the upper 24 bits for the
+ * time being...
+ */
+ return (u32)(cntvct & (u32)~0);
+}
+
+unsigned long long notrace sched_clock(void)
+{
+ return cyc_to_sched_clock(&cd, arch_counter_get_cntvct32(), (u32)~0);
+}
+
+static void notrace arch_timer_update_sched_clock(void)
+{
+ update_sched_clock(&cd, arch_counter_get_cntvct32(), (u32)~0);
+}
+
+static void __cpuinit arch_timer_teardown(void *data)
+{
+ struct clock_event_device *clk = data;
+ pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",
+ clk->irq, smp_processor_id());
+ if (!smp_processor_id()) {
+ remove_irq(arch_timer_ppi, &arch_irqaction[0]);
+ if (arch_timer_ppi2 > 0)
+ remove_irq(arch_timer_ppi2, &arch_irqaction[1]);
+ }
+ arch_timer_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
+}
+
+static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *data)
+{
+ int cpu = (int)data;
+ struct clock_event_device *clk = per_cpu_ptr(arch_timer_evt, cpu);
+
+ switch(action) {
+ case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
+ smp_call_function_single(cpu, arch_timer_setup, clk, 1);
+ break;
+
+ case CPU_DOWN_PREPARE:
+ case CPU_DOWN_PREPARE_FROZEN:
+ smp_call_function_single(cpu, arch_timer_teardown, clk, 1);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata arch_timer_cpu_nb = {
+ .notifier_call = arch_timer_cpu_notify,
+};
+
+int __init arch_timer_register(struct resource *res, int res_nr)
+{
+ struct irqaction *irqa;
+ unsigned int cpu = smp_processor_id();
+ int err;
+
+ if (!res_nr || res[0].start < 0 || !(res[0].flags & IORESOURCE_IRQ))
+ return -EINVAL;
+
+ err = arch_timer_available();
+ if (err)
+ return err;
+
+ arch_timer_evt = alloc_percpu(struct clock_event_device);
+ if (!arch_timer_evt)
+ return -ENOMEM;
+
+ arch_timer_ppi = res[0].start;
+ if (res_nr > 1 && (res[1].flags & IORESOURCE_IRQ))
+ arch_timer_ppi2 = res[1].start;
+
+ clocksource_register_hz(&clocksource_counter, arch_timer_rate);
+
+ init_sched_clock(&cd, arch_timer_update_sched_clock, 32,
+ arch_timer_rate);
+
+#ifdef ARCH_HAS_READ_CURRENT_TIMER
+ set_delay_fn(read_current_timer_delay_loop);
+#endif
+
+ irqa = &arch_irqaction[0];
+ irqa->name = "arch_sys_timer";
+ irqa->flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_HIGH;
+ irqa->handler = arch_timer_handler;
+ irqa->dev_id = per_cpu_ptr(arch_timer_evt, cpu);
+ irqa->irq = arch_timer_ppi;
+ err = setup_irq(arch_timer_ppi, irqa);
+ if (err) {
+ pr_err("%s: can't register interrupt %d (%d)\n",
+ irqa->name, irqa->irq, err);
+ return err;
+ }
+
+ if (arch_timer_ppi2 > 0) {
+ irqa = &arch_irqaction[1];
+ irqa->name = "arch_sys_timer";
+ irqa->flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_HIGH;
+ irqa->handler = arch_timer_handler;
+ irqa->dev_id = per_cpu_ptr(arch_timer_evt, cpu);
+ irqa->irq = arch_timer_ppi2;
+ err = setup_irq(arch_timer_ppi2, irqa);
+ if (err)
+ pr_warn("%s: can't register interrupt %d (%d)\n",
+ irqa->name, irqa->irq, err);
+ }
+
+ /* Immediately configure the timer on the boot CPU */
+ arch_timer_setup(per_cpu_ptr(arch_timer_evt, cpu));
+
+ register_cpu_notifier(&arch_timer_cpu_nb);
+
+ return 0;
+}
diff --git a/arch/arm/kernel/dma.c b/arch/arm/kernel/dma.c
index 2c4a185..7b829d9 100644
--- a/arch/arm/kernel/dma.c
+++ b/arch/arm/kernel/dma.c
@@ -23,7 +23,7 @@
#include <asm/mach/dma.h>
-DEFINE_SPINLOCK(dma_spin_lock);
+DEFINE_RAW_SPINLOCK(dma_spin_lock);
EXPORT_SYMBOL(dma_spin_lock);
static dma_t *dma_chan[MAX_DMA_CHANNELS];
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index 4ef97a0..5bd484f 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -144,54 +144,63 @@
#ifdef CONFIG_HOTPLUG_CPU
-static bool migrate_one_irq(struct irq_data *d)
+static bool migrate_one_irq(struct irq_desc *desc)
{
- unsigned int cpu = cpumask_any_and(d->affinity, cpu_online_mask);
+ struct irq_data *d = irq_desc_get_irq_data(desc);
+ const struct cpumask *affinity = d->affinity;
+ struct irq_chip *c;
bool ret = false;
- if (cpu >= nr_cpu_ids) {
- cpu = cpumask_any(cpu_online_mask);
+ /*
+ * If this is a per-CPU interrupt, or the affinity does not
+ * include this CPU, then we have nothing to do.
+ */
+ if (irqd_is_per_cpu(d) || !cpumask_test_cpu(smp_processor_id(), affinity))
+ return false;
+
+ if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) {
+ affinity = cpu_online_mask;
ret = true;
}
- pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", d->irq, d->node, cpu);
-
- d->chip->irq_set_affinity(d, cpumask_of(cpu), true);
+ c = irq_data_get_irq_chip(d);
+ if (c->irq_set_affinity)
+ c->irq_set_affinity(d, affinity, true);
+ else
+ pr_debug("IRQ%u: unable to set affinity\n", d->irq);
return ret;
}
/*
- * The CPU has been marked offline. Migrate IRQs off this CPU. If
- * the affinity settings do not allow other CPUs, force them onto any
+ * The current CPU has been marked offline. Migrate IRQs off this CPU.
+ * If the affinity settings do not allow other CPUs, force them onto any
* available CPU.
+ *
+ * Note: we must iterate over all IRQs, whether they have an attached
+ * action structure or not, as we need to get chained interrupts too.
*/
void migrate_irqs(void)
{
- unsigned int i, cpu = smp_processor_id();
+ unsigned int i;
struct irq_desc *desc;
unsigned long flags;
local_irq_save(flags);
for_each_irq_desc(i, desc) {
- struct irq_data *d = &desc->irq_data;
bool affinity_broken = false;
+ if (!desc)
+ continue;
+
raw_spin_lock(&desc->lock);
- do {
- if (desc->action == NULL)
- break;
-
- if (d->node != cpu)
- break;
-
- affinity_broken = migrate_one_irq(d);
- } while (0);
+ affinity_broken = migrate_one_irq(desc);
raw_spin_unlock(&desc->lock);
if (affinity_broken && printk_ratelimit())
- pr_warning("IRQ%u no longer affine to CPU%u\n", i, cpu);
+ pr_warning("IRQ%u no longer affine to CPU%u\n", i,
+ smp_processor_id());
}
local_irq_restore(flags);
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index c9982829..b59ad93 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -26,6 +26,7 @@
#include <asm/irq_regs.h>
#include <asm/pmu.h>
#include <asm/stacktrace.h>
+#include <linux/cpu_pm.h>
static struct platform_device *pmu_device;
@@ -82,10 +83,12 @@
struct hw_perf_event *hwc);
u32 (*read_counter)(int idx);
void (*write_counter)(int idx, u32 val);
+ int (*set_event_filter) (struct hw_perf_event *evt,
+ struct perf_event_attr *attr);
void (*start)(void);
void (*stop)(void);
void (*reset)(void *);
- const unsigned (*cache_map)[PERF_COUNT_HW_CACHE_MAX]
+ unsigned (*cache_map)[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_COUNT_HW_CACHE_RESULT_MAX];
const unsigned (*event_map)[PERF_COUNT_HW_MAX];
@@ -472,6 +475,13 @@
pmu_device = NULL;
}
+static int
+event_requires_mode_exclusion(struct perf_event_attr *attr)
+{
+ return attr->exclude_idle || attr->exclude_user ||
+ attr->exclude_kernel || attr->exclude_hv;
+}
+
static atomic_t active_events = ATOMIC_INIT(0);
static DEFINE_MUTEX(pmu_reserve_mutex);
@@ -508,17 +518,6 @@
return mapping;
}
- /*
- * Check whether we need to exclude the counter from certain modes.
- * The ARM performance counters are on all of the time so if someone
- * has asked us for some excludes then we have to fail.
- */
- if (event->attr.exclude_kernel || event->attr.exclude_user ||
- event->attr.exclude_hv || event->attr.exclude_idle) {
- pr_debug("ARM performance counters do not support "
- "mode exclusion\n");
- return -EPERM;
- }
/*
* We don't assign an index until we actually place the event onto
@@ -534,13 +533,23 @@
* the event mapping and the counter to use. The counter to use is
* also the indx and the config_base is the event type.
*/
- hwc->config_base = (unsigned long)mapping;
- hwc->config = 0;
- hwc->event_base = 0;
+ hwc->config_base = 0;
+ hwc->config = 0;
+ hwc->event_base = 0;
+
+ if ((!armpmu->set_event_filter ||
+ armpmu->set_event_filter(hwc, &event->attr)) &&
+ event_requires_mode_exclusion(&event->attr)) {
+ pr_debug("ARM performance counters do not support "
+ "mode exclusion\n");
+ return -EPERM;
+ }
+
+ hwc->config_base |= (unsigned long)mapping;
if (!hwc->sample_period) {
hwc->sample_period = armpmu->max_period;
- hwc->last_period = hwc->sample_period;
+ hwc->last_period = hwc->sample_period;
local64_set(&hwc->period_left, hwc->sample_period);
}
@@ -643,6 +652,30 @@
#include "perf_event_msm_krait.c"
#include "perf_event_msm_krait_l2.c"
+static int perf_cpu_pm_notifier(struct notifier_block *self, unsigned long cmd,
+ void *v)
+{
+ switch (cmd) {
+ case CPU_PM_ENTER:
+ perf_pmu_disable(&pmu);
+ break;
+
+ case CPU_PM_ENTER_FAILED:
+ case CPU_PM_EXIT:
+ if (armpmu && armpmu->reset)
+ armpmu->reset(NULL);
+ perf_pmu_enable(&pmu);
+
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block perf_cpu_pm_notifier_block = {
+ .notifier_call = perf_cpu_pm_notifier,
+};
+
/*
* Ensure the PMU has sane values out of reset.
* This requires SMP to be available, so exists as a separate initcall.
@@ -680,6 +713,12 @@
case 0xC090: /* Cortex-A9 */
armpmu = armv7_a9_pmu_init();
break;
+ case 0xC050: /* Cortex-A5 */
+ armpmu = armv7_a5_pmu_init();
+ break;
+ case 0xC0F0: /* Cortex-A15 */
+ armpmu = armv7_a15_pmu_init();
+ break;
}
/* Intel CPUs [xscale]. */
} else if (0x69 == implementor) {
@@ -719,6 +758,8 @@
perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
+ cpu_pm_register_notifier(&perf_cpu_pm_notifier_block);
+
return 0;
}
early_initcall(init_hw_perf_events);
diff --git a/arch/arm/kernel/perf_event_msm.c b/arch/arm/kernel/perf_event_msm.c
index 579cd3b..b40a226 100644
--- a/arch/arm/kernel/perf_event_msm.c
+++ b/arch/arm/kernel/perf_event_msm.c
@@ -128,7 +128,7 @@
[PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_CLOCK_CYCLES,
};
-static const unsigned armv7_scorpion_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+static unsigned armv7_scorpion_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
[C(L1D)] = {
@@ -585,6 +585,8 @@
*/
if (idx != ARMV7_CYCLE_COUNTER) {
val = hwc->config_base;
+ val &= ARMV7_EVTYPE_EVENT;
+
if (val > 0x40) {
event = get_scorpion_evtinfo(val, &evtinfo);
if (event == -EINVAL)
@@ -624,6 +626,8 @@
*/
if (idx != ARMV7_CYCLE_COUNTER) {
val = hwc->config_base;
+ val &= ARMV7_EVTYPE_EVENT;
+
if (val < 0x40) {
armv7_pmnc_write_evtsel(idx, hwc->config_base);
} else {
@@ -682,6 +686,26 @@
}
#endif
+static void scorpion_pmu_reset(void *info)
+{
+ u32 idx, nb_cnt = armpmu->num_events;
+
+ /* Stop all counters and their interrupts */
+ for (idx = 1; idx < nb_cnt; ++idx) {
+ armv7_pmnc_disable_counter(idx);
+ armv7_pmnc_disable_intens(idx);
+ }
+
+ /* Clear all pmresrs */
+ scorpion_clear_pmuregs();
+
+ /* Reset irq stat reg */
+ armv7_pmnc_getreset_flags();
+
+ /* Reset all ctrs to 0 */
+ armv7_pmnc_write(ARMV7_PMNC_P | ARMV7_PMNC_C);
+}
+
static struct arm_pmu scorpion_pmu = {
.handle_irq = armv7pmu_handle_irq,
#ifdef CONFIG_SMP
@@ -696,6 +720,7 @@
.get_event_idx = armv7pmu_get_event_idx,
.start = armv7pmu_start,
.stop = armv7pmu_stop,
+ .reset = scorpion_pmu_reset,
.max_period = (1LLU << 32) - 1,
};
diff --git a/arch/arm/kernel/perf_event_msm_krait.c b/arch/arm/kernel/perf_event_msm_krait.c
index 1e77489..cf1f1ee 100644
--- a/arch/arm/kernel/perf_event_msm_krait.c
+++ b/arch/arm/kernel/perf_event_msm_krait.c
@@ -15,20 +15,44 @@
#ifdef CONFIG_CPU_V7
#define KRAIT_EVT_PREFIX 1
-#define KRAIT_MAX_L1_REG 2
+#define KRAIT_VENUMEVT_PREFIX 2
/*
event encoding: prccg
- p = prefix (1 for Krait L1)
+ p = prefix (1 for Krait L1) (2 for Krait VeNum events)
r = register
cc = code
g = group
*/
-#define KRAIT_L1_ICACHE_MISS 0x10010
-#define KRAIT_L1_ICACHE_ACCESS 0x10011
-#define KRAIT_DTLB_ACCESS 0x121B2
-#define KRAIT_ITLB_ACCESS 0x121C0
-u32 evt_type_base[] = {0x4c, 0x50, 0x54};
+#define KRAIT_L1_ICACHE_ACCESS 0x10011
+#define KRAIT_L1_ICACHE_MISS 0x10010
+
+#define KRAIT_P1_L1_ITLB_ACCESS 0x121b2
+#define KRAIT_P1_L1_DTLB_ACCESS 0x121c0
+
+#define KRAIT_P2_L1_ITLB_ACCESS 0x12222
+#define KRAIT_P2_L1_DTLB_ACCESS 0x12210
+
+#define KRAIT_EVENT_MASK 0xfffff
+#define KRAIT_MODE_EXCL_MASK 0xc0000000
+
+u32 evt_type_base[][4] = {
+ {0x4c, 0x50, 0x54}, /* Pass 1 */
+ {0xcc, 0xd0, 0xd4, 0xd8}, /* Pass 2 */
+};
+
+#define KRAIT_MIDR_PASS1 0x510F04D0
+#define KRAIT_MIDR_MASK 0xfffffff0
+
+/*
+ * This offset is used to calculate the index
+ * into evt_type_base[][] and krait_functions[]
+ */
+#define VENUM_BASE_OFFSET 3
+
+/* Krait Pass 1 has 3 groups, Pass 2 has 4 */
+static u32 krait_ver, evt_index;
+static u32 krait_max_l1_reg;
static const unsigned armv7_krait_perf_map[PERF_COUNT_HW_MAX] = {
[PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES,
@@ -40,7 +64,7 @@
[PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_CLOCK_CYCLES,
};
-static const unsigned armv7_krait_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+static unsigned armv7_krait_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
[C(L1D)] = {
@@ -93,11 +117,11 @@
},
[C(DTLB)] = {
[C(OP_READ)] = {
- [C(RESULT_ACCESS)] = KRAIT_DTLB_ACCESS,
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_WRITE)] = {
- [C(RESULT_ACCESS)] = KRAIT_DTLB_ACCESS,
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_PREFETCH)] = {
@@ -107,11 +131,11 @@
},
[C(ITLB)] = {
[C(OP_READ)] = {
- [C(RESULT_ACCESS)] = KRAIT_ITLB_ACCESS,
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_WRITE)] = {
- [C(RESULT_ACCESS)] = KRAIT_ITLB_ACCESS,
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_PREFETCH)] = {
@@ -170,17 +194,26 @@
u8 group;
prefix = (krait_evt_type & 0xF0000) >> 16;
- reg = (krait_evt_type & 0x0F000) >> 12;
- code = (krait_evt_type & 0x00FF0) >> 4;
- group = krait_evt_type & 0x0000F;
+ reg = (krait_evt_type & 0x0F000) >> 12;
+ code = (krait_evt_type & 0x00FF0) >> 4;
+ group = krait_evt_type & 0x0000F;
- if ((prefix != KRAIT_EVT_PREFIX) || (group > 3) ||
- (reg > KRAIT_MAX_L1_REG))
+ if ((group > 3) || (reg > krait_max_l1_reg))
return -EINVAL;
+ if (prefix != KRAIT_EVT_PREFIX && prefix != KRAIT_VENUMEVT_PREFIX)
+ return -EINVAL;
+
+ if (prefix == KRAIT_VENUMEVT_PREFIX) {
+ if ((code & 0xe0) || krait_ver != 2)
+ return -EINVAL;
+ else
+ reg += VENUM_BASE_OFFSET;
+ }
+
evtinfo->group_setval = 0x80000000 | (code << (group * 8));
evtinfo->groupcode = reg;
- evtinfo->armv7_evt_type = evt_type_base[reg] | group;
+ evtinfo->armv7_evt_type = evt_type_base[evt_index][reg] | group;
return evtinfo->armv7_evt_type;
}
@@ -224,9 +257,59 @@
asm volatile("mcr p15, 1, %0, c9, c15, 2" : : "r" (val));
}
+static u32 krait_read_vmresr0(void)
+{
+ u32 val;
+
+ asm volatile ("mrc p10, 7, %0, c11, c0, 0" : "=r" (val));
+ return val;
+}
+
+static void krait_write_vmresr0(u32 val)
+{
+ asm volatile ("mcr p10, 7, %0, c11, c0, 0" : : "r" (val));
+}
+
+static DEFINE_PER_CPU(u32, venum_orig_val);
+static DEFINE_PER_CPU(u32, fp_orig_val);
+
+static void krait_pre_vmresr0(void)
+{
+ u32 venum_new_val;
+ u32 fp_new_val;
+ u32 v_orig_val;
+ u32 f_orig_val;
+
+ /* CPACR Enable CP10 access */
+ v_orig_val = get_copro_access();
+ venum_new_val = v_orig_val | CPACC_SVC(10);
+ set_copro_access(venum_new_val);
+ /* Store orig venum val */
+ __get_cpu_var(venum_orig_val) = v_orig_val;
+
+ /* Enable FPEXC */
+ f_orig_val = fmrx(FPEXC);
+ fp_new_val = f_orig_val | FPEXC_EN;
+ fmxr(FPEXC, fp_new_val);
+ /* Store orig fp val */
+ __get_cpu_var(fp_orig_val) = f_orig_val;
+
+}
+
+static void krait_post_vmresr0(void)
+{
+ /* Restore FPEXC */
+ fmxr(FPEXC, __get_cpu_var(fp_orig_val));
+ isb();
+ /* Restore CPACR */
+ set_copro_access(__get_cpu_var(venum_orig_val));
+}
+
struct krait_access_funcs {
u32 (*read) (void);
void (*write) (u32);
+ void (*pre) (void);
+ void (*post) (void);
};
/*
@@ -235,9 +318,11 @@
* Having the following array modularizes the code for doing that.
*/
struct krait_access_funcs krait_functions[] = {
- {krait_read_pmresr0, krait_write_pmresr0},
- {krait_read_pmresr1, krait_write_pmresr1},
- {krait_read_pmresr2, krait_write_pmresr2},
+ {krait_read_pmresr0, krait_write_pmresr0, NULL, NULL},
+ {krait_read_pmresr1, krait_write_pmresr1, NULL, NULL},
+ {krait_read_pmresr2, krait_write_pmresr2, NULL, NULL},
+ {krait_read_vmresr0, krait_write_vmresr0, krait_pre_vmresr0,
+ krait_post_vmresr0},
};
static inline u32 krait_get_columnmask(u32 evt_code)
@@ -252,9 +337,15 @@
{
u32 val;
+ if (krait_functions[gr].pre)
+ krait_functions[gr].pre();
+
val = krait_get_columnmask(evt_code) & krait_functions[gr].read();
val = val | setval;
krait_functions[gr].write(val);
+
+ if (krait_functions[gr].post)
+ krait_functions[gr].post();
}
static void krait_clear_pmuregs(void)
@@ -262,15 +353,25 @@
krait_write_pmresr0(0);
krait_write_pmresr1(0);
krait_write_pmresr2(0);
+
+ krait_pre_vmresr0();
+ krait_write_vmresr0(0);
+ krait_post_vmresr0();
}
static void krait_clearpmu(u32 grp, u32 val, u32 evt_code)
{
u32 new_pmuval;
+ if (krait_functions[grp].pre)
+ krait_functions[grp].pre();
+
new_pmuval = krait_functions[grp].read() &
krait_get_columnmask(evt_code);
krait_functions[grp].write(new_pmuval);
+
+ if (krait_functions[grp].post)
+ krait_functions[grp].post();
}
static void krait_pmu_disable_event(struct hw_perf_event *hwc, int idx)
@@ -293,6 +394,8 @@
*/
if (idx != ARMV7_CYCLE_COUNTER) {
val = hwc->config_base;
+ val &= KRAIT_EVENT_MASK;
+
if (val > 0x40) {
event = get_krait_evtinfo(val, &evtinfo);
if (event == -EINVAL)
@@ -332,6 +435,8 @@
*/
if (idx != ARMV7_CYCLE_COUNTER) {
val = hwc->config_base;
+ val &= KRAIT_EVENT_MASK;
+
if (val < 0x40) {
armv7_pmnc_write_evtsel(idx, hwc->config_base);
} else {
@@ -339,6 +444,10 @@
if (event == -EINVAL)
goto krait_out;
+
+ /* Restore Mode-exclusion bits */
+ event |= (hwc->config_base & KRAIT_MODE_EXCL_MASK);
+
/*
* Set event (if destined for PMNx counters)
* We don't need to set the event if it's a cycle count
@@ -363,6 +472,26 @@
raw_spin_unlock_irqrestore(&pmu_lock, flags);
}
+static void krait_pmu_reset(void *info)
+{
+ u32 idx, nb_cnt = armpmu->num_events;
+
+ /* Stop all counters and their interrupts */
+ for (idx = 1; idx < nb_cnt; ++idx) {
+ armv7_pmnc_disable_counter(idx);
+ armv7_pmnc_disable_intens(idx);
+ }
+
+ /* Clear all pmresrs */
+ krait_clear_pmuregs();
+
+ /* Reset irq stat reg */
+ armv7_pmnc_getreset_flags();
+
+ /* Reset all ctrs to 0 */
+ armv7_pmnc_write(ARMV7_PMNC_P | ARMV7_PMNC_C);
+}
+
static struct arm_pmu krait_pmu = {
.handle_irq = armv7pmu_handle_irq,
#ifdef CONFIG_SMP
@@ -377,9 +506,23 @@
.get_event_idx = armv7pmu_get_event_idx,
.start = armv7pmu_start,
.stop = armv7pmu_stop,
+ .reset = krait_pmu_reset,
.max_period = (1LLU << 32) - 1,
};
+int get_krait_ver(void)
+{
+ int ver = 0;
+ int midr = read_cpuid_id();
+
+ if ((midr & KRAIT_MIDR_MASK) != KRAIT_MIDR_PASS1)
+ ver = 2;
+
+ pr_debug("krait_ver: %d, midr: %x\n", ver, midr);
+
+ return ver;
+}
+
static const struct arm_pmu *__init armv7_krait_pmu_init(void)
{
krait_pmu.id = ARM_PERF_PMU_ID_KRAIT;
@@ -388,6 +531,44 @@
krait_pmu.event_map = &armv7_krait_perf_map;
krait_pmu.num_events = armv7_read_num_pmnc_events();
krait_clear_pmuregs();
+
+ krait_ver = get_krait_ver();
+
+ if (krait_ver > 0) {
+ evt_index = 1;
+ krait_max_l1_reg = 3;
+
+ krait_pmu.set_event_filter = armv7pmu_set_event_filter,
+
+ armv7_krait_perf_cache_map[C(ITLB)]
+ [C(OP_READ)]
+ [C(RESULT_ACCESS)] = KRAIT_P2_L1_ITLB_ACCESS;
+ armv7_krait_perf_cache_map[C(ITLB)]
+ [C(OP_WRITE)]
+ [C(RESULT_ACCESS)] = KRAIT_P2_L1_ITLB_ACCESS;
+ armv7_krait_perf_cache_map[C(DTLB)]
+ [C(OP_READ)]
+ [C(RESULT_ACCESS)] = KRAIT_P2_L1_DTLB_ACCESS;
+ armv7_krait_perf_cache_map[C(DTLB)]
+ [C(OP_WRITE)]
+ [C(RESULT_ACCESS)] = KRAIT_P2_L1_DTLB_ACCESS;
+ } else {
+ evt_index = 0;
+ krait_max_l1_reg = 2;
+ armv7_krait_perf_cache_map[C(ITLB)]
+ [C(OP_READ)]
+ [C(RESULT_ACCESS)] = KRAIT_P1_L1_ITLB_ACCESS;
+ armv7_krait_perf_cache_map[C(ITLB)]
+ [C(OP_WRITE)]
+ [C(RESULT_ACCESS)] = KRAIT_P1_L1_ITLB_ACCESS;
+ armv7_krait_perf_cache_map[C(DTLB)]
+ [C(OP_READ)]
+ [C(RESULT_ACCESS)] = KRAIT_P1_L1_DTLB_ACCESS;
+ armv7_krait_perf_cache_map[C(DTLB)]
+ [C(OP_WRITE)]
+ [C(RESULT_ACCESS)] = KRAIT_P1_L1_DTLB_ACCESS;
+ }
+
return &krait_pmu;
}
diff --git a/arch/arm/kernel/perf_event_msm_krait_l2.c b/arch/arm/kernel/perf_event_msm_krait_l2.c
index 0512e64..c8b48a8 100644
--- a/arch/arm/kernel/perf_event_msm_krait_l2.c
+++ b/arch/arm/kernel/perf_event_msm_krait_l2.c
@@ -584,10 +584,15 @@
return err;
}
- hwc->config_base = event->attr.config;
hwc->config = 0;
hwc->event_base = 0;
+ /* Check if we came via perf default syms */
+ if (event->attr.config == PERF_COUNT_HW_L2_CYCLES)
+ hwc->config_base = L2CYCLE_CTR_RAW_CODE;
+ else
+ hwc->config_base = event->attr.config;
+
/* Only one CPU can control the cycle counter */
if (hwc->config_base == L2CYCLE_CTR_RAW_CODE) {
/* Check if its already running */
diff --git a/arch/arm/kernel/perf_event_msm_l2.c b/arch/arm/kernel/perf_event_msm_l2.c
index 3cb251b..33fb5bf 100644
--- a/arch/arm/kernel/perf_event_msm_l2.c
+++ b/arch/arm/kernel/perf_event_msm_l2.c
@@ -10,7 +10,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-#ifdef CONFIG_ARCH_MSM8x60
+#ifdef CONFIG_ARCH_MSM8X60
#include <linux/irq.h>
@@ -20,6 +20,8 @@
#define BB_L2CYCLE_CTR_EVENT_IDX 4
#define BB_L2CYCLE_CTR_RAW_CODE 0xfe
#define SCORPIONL2_PMNC_E (1 << 0) /* Enable all counters */
+#define SCORPION_L2_EVT_PREFIX 3
+#define SCORPION_MAX_L2_REG 4
/*
* Lock to protect r/m/w sequences to the L2 PMU.
@@ -365,6 +367,26 @@
struct bb_l2_scorp_evt *evtinfo)
{
u32 idx;
+ u8 prefix;
+ u8 reg;
+ u8 code;
+ u8 group;
+
+ prefix = (evt_type & 0xF0000) >> 16;
+ if (prefix == SCORPION_L2_EVT_PREFIX) {
+ reg = (evt_type & 0x0F000) >> 12;
+ code = (evt_type & 0x00FF0) >> 4;
+ group = evt_type & 0x0000F;
+
+ if ((group > 3) || (reg > SCORPION_MAX_L2_REG))
+ return BB_L2_INV_EVTYPE;
+
+ evtinfo->val = 0x80000000 | (code << (group * 8));
+ evtinfo->grp = reg;
+ evtinfo->evt_type_act = group | (reg << 2);
+ return evtinfo->evt_type_act;
+ }
+
if (evt_type < BB_L2_EVT_START_IDX || evt_type >= BB_L2_MAX_EVT)
return BB_L2_INV_EVTYPE;
idx = evt_type - BB_L2_EVT_START_IDX;
@@ -911,10 +933,15 @@
return err;
}
- hwc->config_base = event->attr.config & 0xff;
hwc->config = 0;
hwc->event_base = 0;
+ /* Check if we came via perf default syms */
+ if (event->attr.config == PERF_COUNT_HW_L2_CYCLES)
+ hwc->config_base = BB_L2CYCLE_CTR_RAW_CODE;
+ else
+ hwc->config_base = event->attr.config;
+
/* Only one CPU can control the cycle counter */
if (hwc->config_base == BB_L2CYCLE_CTR_RAW_CODE) {
/* Check if its already running */
diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c
index f1e8dd9..0635b7e 100644
--- a/arch/arm/kernel/perf_event_v6.c
+++ b/arch/arm/kernel/perf_event_v6.c
@@ -74,7 +74,7 @@
[PERF_COUNT_HW_BUS_CYCLES] = HW_OP_UNSUPPORTED,
};
-static const unsigned armv6_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+static unsigned armv6_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
[C(L1D)] = {
@@ -213,7 +213,7 @@
[PERF_COUNT_HW_BUS_CYCLES] = HW_OP_UNSUPPORTED,
};
-static const unsigned armv6mpcore_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+static unsigned armv6mpcore_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
[C(L1D)] = {
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index 01b1145..277f1ce 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -153,6 +153,39 @@
ARMV7_PERFCTR_PLE_RQST_PROG = 0xA5
};
+/* ARMv7 Cortex-A5 specific event types */
+enum armv7_a5_perf_types {
+ ARMV7_PERFCTR_IRQ_TAKEN = 0x86,
+ ARMV7_PERFCTR_FIQ_TAKEN = 0x87,
+
+ ARMV7_PERFCTR_EXT_MEM_RQST = 0xc0,
+ ARMV7_PERFCTR_NC_EXT_MEM_RQST = 0xc1,
+ ARMV7_PERFCTR_PREFETCH_LINEFILL = 0xc2,
+ ARMV7_PERFCTR_PREFETCH_LINEFILL_DROP = 0xc3,
+ ARMV7_PERFCTR_ENTER_READ_ALLOC = 0xc4,
+ ARMV7_PERFCTR_READ_ALLOC = 0xc5,
+
+ ARMV7_PERFCTR_STALL_SB_FULL = 0xc9,
+};
+
+/* ARMv7 Cortex-A15 specific event types */
+enum armv7_a15_perf_types {
+ ARMV7_PERFCTR_L1_DCACHE_READ_ACCESS = 0x40,
+ ARMV7_PERFCTR_L1_DCACHE_WRITE_ACCESS = 0x41,
+ ARMV7_PERFCTR_L1_DCACHE_READ_REFILL = 0x42,
+ ARMV7_PERFCTR_L1_DCACHE_WRITE_REFILL = 0x43,
+
+ ARMV7_PERFCTR_L1_DTLB_READ_REFILL = 0x4C,
+ ARMV7_PERFCTR_L1_DTLB_WRITE_REFILL = 0x4D,
+
+ ARMV7_PERFCTR_L2_DCACHE_READ_ACCESS = 0x50,
+ ARMV7_PERFCTR_L2_DCACHE_WRITE_ACCESS = 0x51,
+ ARMV7_PERFCTR_L2_DCACHE_READ_REFILL = 0x52,
+ ARMV7_PERFCTR_L2_DCACHE_WRITE_REFILL = 0x53,
+
+ ARMV7_PERFCTR_SPEC_PC_WRITE = 0x76,
+};
+
/*
* Cortex-A8 HW events mapping
*
@@ -170,7 +203,7 @@
[PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_CLOCK_CYCLES,
};
-static const unsigned armv7_a8_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+static unsigned armv7_a8_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
[C(L1D)] = {
@@ -274,14 +307,14 @@
[PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES,
[PERF_COUNT_HW_INSTRUCTIONS] =
ARMV7_PERFCTR_INST_OUT_OF_RENAME_STAGE,
- [PERF_COUNT_HW_CACHE_REFERENCES] = ARMV7_PERFCTR_COHERENT_LINE_HIT,
- [PERF_COUNT_HW_CACHE_MISSES] = ARMV7_PERFCTR_COHERENT_LINE_MISS,
+ [PERF_COUNT_HW_CACHE_REFERENCES] = ARMV7_PERFCTR_DCACHE_ACCESS,
+ [PERF_COUNT_HW_CACHE_MISSES] = ARMV7_PERFCTR_DCACHE_REFILL,
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_PC_WRITE,
[PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
[PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_CLOCK_CYCLES,
};
-static const unsigned armv7_a9_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+static unsigned armv7_a9_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
[C(L1D)] = {
@@ -379,6 +412,242 @@
};
/*
+ * Cortex-A5 HW events mapping
+ */
+static const unsigned armv7_a5_perf_map[PERF_COUNT_HW_MAX] = {
+ [PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES,
+ [PERF_COUNT_HW_INSTRUCTIONS] = ARMV7_PERFCTR_INSTR_EXECUTED,
+ [PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED,
+ [PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED,
+ [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_PC_WRITE,
+ [PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
+ [PERF_COUNT_HW_BUS_CYCLES] = HW_OP_UNSUPPORTED,
+};
+
+static unsigned armv7_a5_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+ [PERF_COUNT_HW_CACHE_OP_MAX]
+ [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+ [C(L1D)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)]
+ = ARMV7_PERFCTR_DCACHE_ACCESS,
+ [C(RESULT_MISS)]
+ = ARMV7_PERFCTR_DCACHE_REFILL,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)]
+ = ARMV7_PERFCTR_DCACHE_ACCESS,
+ [C(RESULT_MISS)]
+ = ARMV7_PERFCTR_DCACHE_REFILL,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)]
+ = ARMV7_PERFCTR_PREFETCH_LINEFILL,
+ [C(RESULT_MISS)]
+ = ARMV7_PERFCTR_PREFETCH_LINEFILL_DROP,
+ },
+ },
+ [C(L1I)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS,
+ [C(RESULT_MISS)] = ARMV7_PERFCTR_IFETCH_MISS,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS,
+ [C(RESULT_MISS)] = ARMV7_PERFCTR_IFETCH_MISS,
+ },
+ /*
+ * The prefetch counters don't differentiate between the I
+ * side and the D side.
+ */
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)]
+ = ARMV7_PERFCTR_PREFETCH_LINEFILL,
+ [C(RESULT_MISS)]
+ = ARMV7_PERFCTR_PREFETCH_LINEFILL_DROP,
+ },
+ },
+ [C(LL)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ },
+ [C(DTLB)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ },
+ [C(ITLB)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ },
+ [C(BPU)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED,
+ [C(RESULT_MISS)]
+ = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED,
+ [C(RESULT_MISS)]
+ = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ },
+};
+
+/*
+ * Cortex-A15 HW events mapping
+ */
+static const unsigned armv7_a15_perf_map[PERF_COUNT_HW_MAX] = {
+ [PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES,
+ [PERF_COUNT_HW_INSTRUCTIONS] = ARMV7_PERFCTR_INSTR_EXECUTED,
+ [PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED,
+ [PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED,
+ [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_SPEC_PC_WRITE,
+ [PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
+ [PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_BUS_CYCLES,
+};
+
+static unsigned armv7_a15_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+ [PERF_COUNT_HW_CACHE_OP_MAX]
+ [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+ [C(L1D)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)]
+ = ARMV7_PERFCTR_L1_DCACHE_READ_ACCESS,
+ [C(RESULT_MISS)]
+ = ARMV7_PERFCTR_L1_DCACHE_READ_REFILL,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)]
+ = ARMV7_PERFCTR_L1_DCACHE_WRITE_ACCESS,
+ [C(RESULT_MISS)]
+ = ARMV7_PERFCTR_L1_DCACHE_WRITE_REFILL,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ },
+ [C(L1I)] = {
+ /*
+ * Not all performance counters differentiate between read
+ * and write accesses/misses so we're not always strictly
+ * correct, but it's the best we can do. Writes and reads get
+ * combined in these cases.
+ */
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS,
+ [C(RESULT_MISS)] = ARMV7_PERFCTR_IFETCH_MISS,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS,
+ [C(RESULT_MISS)] = ARMV7_PERFCTR_IFETCH_MISS,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ },
+ [C(LL)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)]
+ = ARMV7_PERFCTR_L2_DCACHE_READ_ACCESS,
+ [C(RESULT_MISS)]
+ = ARMV7_PERFCTR_L2_DCACHE_READ_REFILL,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)]
+ = ARMV7_PERFCTR_L2_DCACHE_WRITE_ACCESS,
+ [C(RESULT_MISS)]
+ = ARMV7_PERFCTR_L2_DCACHE_WRITE_REFILL,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ },
+ [C(DTLB)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)]
+ = ARMV7_PERFCTR_L1_DTLB_READ_REFILL,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)]
+ = ARMV7_PERFCTR_L1_DTLB_WRITE_REFILL,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ },
+ [C(ITLB)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ },
+ [C(BPU)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED,
+ [C(RESULT_MISS)]
+ = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED,
+ [C(RESULT_MISS)]
+ = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ },
+};
+
+/*
* Perf Events counters
*/
enum armv7_counters {
@@ -446,7 +715,8 @@
/*
* EVTSEL: Event selection reg
*/
-#define ARMV7_EVTSEL_MASK 0xff /* Mask for writable bits */
+#define ARMV7_EVTYPE_EVENT 0xff /* Mask for writable bits */
+#define ARMV7_EVTYPE_MASK 0xc00000ff
/*
* SELECT: Counter selection reg
@@ -461,6 +731,39 @@
#define ARMV7_FLAG_MASK 0xffffffff /* Mask for writable bits */
#define ARMV7_OVERFLOWED_MASK ARMV7_FLAG_MASK
+/*
+ * Event filters for PMUv2
+ */
+#define ARMV7_EXCLUDE_PL1 (1 << 31)
+#define ARMV7_EXCLUDE_USER (1 << 30)
+#define ARMV7_INCLUDE_HYP (1 << 27)
+
+/*
+ * Add an event filter to a given event. This will only work for PMUv2 PMUs.
+ */
+int armv7pmu_set_event_filter(struct hw_perf_event *event,
+ struct perf_event_attr *attr)
+{
+ unsigned long config_base = 0;
+
+ if (attr->exclude_idle)
+ return -EPERM;
+ if (attr->exclude_user)
+ config_base |= ARMV7_EXCLUDE_USER;
+ if (attr->exclude_kernel)
+ config_base |= ARMV7_EXCLUDE_PL1;
+ if (!attr->exclude_hv)
+ config_base |= ARMV7_INCLUDE_HYP;
+
+ /*
+ * Install the filter into config_base as this is used to
+ * construct the event type.
+ */
+ event->config_base = config_base;
+
+ return 0;
+}
+
static inline unsigned long armv7_pmnc_read(void)
{
u32 val;
@@ -546,7 +849,8 @@
static inline void armv7_pmnc_write_evtsel(unsigned int idx, u32 val)
{
if (armv7_pmnc_select_counter(idx) == idx) {
- val &= ARMV7_EVTSEL_MASK;
+ val &= ARMV7_EVTYPE_MASK;
+
asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
}
}
@@ -707,7 +1011,7 @@
* Set event (if destined for PMNx counters)
* We don't need to set the event if it's a cycle count
*/
- if (idx != ARMV7_CYCLE_COUNTER)
+ if (armpmu->set_event_filter || idx != ARMV7_CYCLE_COUNTER)
armv7_pmnc_write_evtsel(idx, hwc->config_base);
/*
@@ -832,9 +1136,11 @@
struct hw_perf_event *event)
{
int idx;
+ unsigned long evtype = event->config_base & ARMV7_EVTYPE_EVENT;
+
/* Always place a cycle counter into the cycle counter. */
- if (event->config_base == ARMV7_PERFCTR_CPU_CYCLES) {
+ if (evtype == ARMV7_PERFCTR_CPU_CYCLES) {
if (test_and_set_bit(ARMV7_CYCLE_COUNTER, cpuc->used_mask))
return -EAGAIN;
@@ -910,6 +1216,26 @@
armv7pmu.num_events = armv7_read_num_pmnc_events();
return &armv7pmu;
}
+
+static const struct arm_pmu *__init armv7_a5_pmu_init(void)
+{
+ armv7pmu.id = ARM_PERF_PMU_ID_CA5;
+ armv7pmu.name = "ARMv7 Cortex-A5";
+ armv7pmu.cache_map = &armv7_a5_perf_cache_map;
+ armv7pmu.event_map = &armv7_a5_perf_map;
+ armv7pmu.num_events = armv7_read_num_pmnc_events();
+ return &armv7pmu;
+}
+
+static const struct arm_pmu *__init armv7_a15_pmu_init(void)
+{
+ armv7pmu.id = ARM_PERF_PMU_ID_CA15;
+ armv7pmu.name = "ARMv7 Cortex-A15";
+ armv7pmu.cache_map = &armv7_a15_perf_cache_map;
+ armv7pmu.event_map = &armv7_a15_perf_map;
+ armv7pmu.num_events = armv7_read_num_pmnc_events();
+ return &armv7pmu;
+}
#else
static const struct arm_pmu *__init armv7_a8_pmu_init(void)
{
@@ -920,4 +1246,14 @@
{
return NULL;
}
+
+static const struct arm_pmu *__init armv7_a5_pmu_init(void)
+{
+ return NULL;
+}
+
+static const struct arm_pmu *__init armv7_a15_pmu_init(void)
+{
+ return NULL;
+}
#endif /* CONFIG_CPU_V7 */
diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c
index 39affbe..21977cf 100644
--- a/arch/arm/kernel/perf_event_xscale.c
+++ b/arch/arm/kernel/perf_event_xscale.c
@@ -57,7 +57,7 @@
[PERF_COUNT_HW_BUS_CYCLES] = HW_OP_UNSUPPORTED,
};
-static const unsigned xscale_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+static unsigned xscale_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
[C(L1D)] = {
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 34fca2e..4ee00c8 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -62,6 +62,18 @@
#include <mach/system.h>
+#ifdef CONFIG_SMP
+void arch_trigger_all_cpu_backtrace(void)
+{
+ smp_send_all_cpu_backtrace();
+}
+#else
+void arch_trigger_all_cpu_backtrace(void)
+{
+ dump_stack();
+}
+#endif
+
void disable_hlt(void)
{
hlt_counter++;
@@ -142,6 +154,9 @@
/* Push out any further dirty data, and ensure cache is empty */
flush_cache_all();
+ /*Push out the dirty data from external caches */
+ outer_disable();
+
/*
* Now call the architecture specific reboot code.
*/
@@ -236,8 +251,8 @@
local_irq_enable();
}
}
- idle_notifier_call_chain(IDLE_END);
tick_nohz_restart_sched_tick();
+ idle_notifier_call_chain(IDLE_END);
preempt_enable_no_resched();
schedule();
preempt_disable();
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 1455efe..9fe0964 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -39,6 +39,7 @@
#include <asm/tlbflush.h>
#include <asm/ptrace.h>
#include <asm/localtimer.h>
+#include <asm/smp_plat.h>
/*
* as from 2.5, kernels no longer have an init_tasks structure
@@ -54,6 +55,7 @@
IPI_CALL_FUNC,
IPI_CALL_FUNC_SINGLE,
IPI_CPU_STOP,
+ IPI_CPU_BACKTRACE,
};
int __cpuinit __cpu_up(unsigned int cpu)
@@ -215,7 +217,7 @@
pr_err("CPU%u: cpu didn't die\n", cpu);
return;
}
- printk(KERN_NOTICE "CPU%u: shutdown\n", cpu);
+ pr_debug("CPU%u: shutdown\n", cpu);
if (!platform_cpu_kill(cpu))
printk("CPU%u: unable to kill\n", cpu);
@@ -260,6 +262,20 @@
}
#endif /* CONFIG_HOTPLUG_CPU */
+int __cpu_logical_map[NR_CPUS];
+
+void __init smp_setup_processor_id(void)
+{
+ int i;
+ u32 cpu = is_smp() ? read_cpuid_mpidr() & 0xff : 0;
+
+ cpu_logical_map(0) = cpu;
+ for (i = 1; i < NR_CPUS; ++i)
+ cpu_logical_map(i) = i == cpu ? 0 : i;
+
+ printk(KERN_INFO "Booting Linux on physical CPU %d\n", cpu);
+}
+
/*
* Called by both boot and secondaries to move global data into
* per-processor storage.
@@ -280,7 +296,7 @@
struct mm_struct *mm = &init_mm;
unsigned int cpu = smp_processor_id();
- printk("CPU%u: Booted secondary processor\n", cpu);
+ pr_debug("CPU%u: Booted secondary processor\n", cpu);
/*
* All kernel threads share the same mm context; grab a
@@ -407,6 +423,7 @@
S(IPI_CALL_FUNC, "Function call interrupts"),
S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"),
S(IPI_CPU_STOP, "CPU stop interrupts"),
+ S(IPI_CPU_BACKTRACE, "CPU backtrace"),
};
void show_ipi_list(struct seq_file *p, int prec)
@@ -533,7 +550,7 @@
}
#endif
-static DEFINE_SPINLOCK(stop_lock);
+static DEFINE_RAW_SPINLOCK(stop_lock);
/*
* ipi_cpu_stop - handle IPI from smp_send_stop()
@@ -542,10 +559,10 @@
{
if (system_state == SYSTEM_BOOTING ||
system_state == SYSTEM_RUNNING) {
- spin_lock(&stop_lock);
+ raw_spin_lock(&stop_lock);
printk(KERN_CRIT "CPU%u: stopping\n", cpu);
dump_stack();
- spin_unlock(&stop_lock);
+ raw_spin_unlock(&stop_lock);
}
set_cpu_online(cpu, false);
@@ -557,6 +574,58 @@
cpu_relax();
}
+static cpumask_t backtrace_mask;
+static DEFINE_RAW_SPINLOCK(backtrace_lock);
+
+/* "in progress" flag of arch_trigger_all_cpu_backtrace */
+static unsigned long backtrace_flag;
+
+void smp_send_all_cpu_backtrace(void)
+{
+ unsigned int this_cpu = smp_processor_id();
+ int i;
+
+ if (test_and_set_bit(0, &backtrace_flag))
+ /*
+ * If there is already a trigger_all_cpu_backtrace() in progress
+ * (backtrace_flag == 1), don't output double cpu dump infos.
+ */
+ return;
+
+ cpumask_copy(&backtrace_mask, cpu_online_mask);
+ cpu_clear(this_cpu, backtrace_mask);
+
+ pr_info("Backtrace for cpu %d (current):\n", this_cpu);
+ dump_stack();
+
+ pr_info("\nsending IPI to all other CPUs:\n");
+ smp_cross_call(&backtrace_mask, IPI_CPU_BACKTRACE);
+
+ /* Wait for up to 10 seconds for all other CPUs to do the backtrace */
+ for (i = 0; i < 10 * 1000; i++) {
+ if (cpumask_empty(&backtrace_mask))
+ break;
+ mdelay(1);
+ }
+
+ clear_bit(0, &backtrace_flag);
+ smp_mb__after_clear_bit();
+}
+
+/*
+ * ipi_cpu_backtrace - handle IPI from smp_send_all_cpu_backtrace()
+ */
+static void ipi_cpu_backtrace(unsigned int cpu, struct pt_regs *regs)
+{
+ if (cpu_isset(cpu, backtrace_mask)) {
+ raw_spin_lock(&backtrace_lock);
+ pr_warning("IPI backtrace for cpu %d\n", cpu);
+ show_regs(regs);
+ raw_spin_unlock(&backtrace_lock);
+ cpu_clear(cpu, backtrace_mask);
+ }
+}
+
/*
* Main handler for inter-processor interrupts
*/
@@ -597,6 +666,10 @@
ipi_cpu_stop(cpu);
break;
+ case IPI_CPU_BACKTRACE:
+ ipi_cpu_backtrace(cpu, regs);
+ break;
+
default:
printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
cpu, ipinr);
diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c
index a1e757c..cb7dd40 100644
--- a/arch/arm/kernel/smp_scu.c
+++ b/arch/arm/kernel/smp_scu.c
@@ -13,6 +13,7 @@
#include <asm/smp_scu.h>
#include <asm/cacheflush.h>
+#include <asm/cputype.h>
#define SCU_CTRL 0x00
#define SCU_CONFIG 0x04
@@ -36,6 +37,15 @@
{
u32 scu_ctrl;
+#ifdef CONFIG_ARM_ERRATA_764369
+ /* Cortex-A9 only */
+ if ((read_cpuid(CPUID_ID) & 0xff0ffff0) == 0x410fc090) {
+ scu_ctrl = __raw_readl(scu_base + 0x30);
+ if (!(scu_ctrl & 1))
+ __raw_writel(scu_ctrl | 0x1, scu_base + 0x30);
+ }
+#endif
+
scu_ctrl = __raw_readl(scu_base + SCU_CTRL);
/* already enabled? */
if (scu_ctrl & 1)
diff --git a/arch/arm/kernel/swp_emulate.c b/arch/arm/kernel/swp_emulate.c
index 40ee7e5..7669848 100644
--- a/arch/arm/kernel/swp_emulate.c
+++ b/arch/arm/kernel/swp_emulate.c
@@ -173,6 +173,57 @@
return res;
}
+static int check_condition(struct pt_regs *regs, unsigned int insn)
+{
+ unsigned int base_cond, neg, cond = 0;
+ unsigned int cpsr_z, cpsr_c, cpsr_n, cpsr_v;
+
+ cpsr_n = (regs->ARM_cpsr & PSR_N_BIT) ? 1 : 0;
+ cpsr_z = (regs->ARM_cpsr & PSR_Z_BIT) ? 1 : 0;
+ cpsr_c = (regs->ARM_cpsr & PSR_C_BIT) ? 1 : 0;
+ cpsr_v = (regs->ARM_cpsr & PSR_V_BIT) ? 1 : 0;
+
+ /* Upper 3 bits indicate condition, lower bit incicates negation */
+ base_cond = insn >> 29;
+ neg = insn & BIT(28) ? 1 : 0;
+
+ switch (base_cond) {
+ case 0x0: /* equal */
+ cond = cpsr_z;
+ break;
+
+ case 0x1: /* carry set */
+ cond = cpsr_c;
+ break;
+
+ case 0x2: /* minus / negative */
+ cond = cpsr_n;
+ break;
+
+ case 0x3: /* overflow */
+ cond = cpsr_v;
+ break;
+
+ case 0x4: /* unsigned higher */
+ cond = (cpsr_c == 1) && (cpsr_z == 0);
+ break;
+
+ case 0x5: /* signed greater / equal */
+ cond = (cpsr_n == cpsr_v);
+ break;
+
+ case 0x6: /* signed greater */
+ cond = (cpsr_z == 0) && (cpsr_n == cpsr_v);
+ break;
+
+ case 0x7: /* always */
+ cond = 1;
+ break;
+ };
+
+ return cond && !neg;
+}
+
/*
* swp_handler logs the id of calling process, dissects the instruction, sanity
* checks the memory location, calls emulate_swpX for the actual operation and
@@ -191,6 +242,12 @@
previous_pid = current->pid;
}
+ /* Ignore the instruction if it fails its condition code check */
+ if (!check_condition(regs, instr)) {
+ regs->ARM_pc += 4;
+ return 0;
+ }
+
address = regs->uregs[EXTRACT_REG_NUM(instr, RN_OFFSET)];
data = regs->uregs[EXTRACT_REG_NUM(instr, RT2_OFFSET)];
destreg = EXTRACT_REG_NUM(instr, RT_OFFSET);
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index aaca029..c063c56 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -255,7 +255,7 @@
return ret;
}
-static DEFINE_SPINLOCK(die_lock);
+static DEFINE_RAW_SPINLOCK(die_lock);
/*
* This function is protected against re-entrancy.
@@ -267,7 +267,7 @@
oops_enter();
- spin_lock_irq(&die_lock);
+ raw_spin_lock_irq(&die_lock);
console_verbose();
bust_spinlocks(1);
ret = __die(str, err, thread, regs);
@@ -277,7 +277,7 @@
bust_spinlocks(0);
add_taint(TAINT_DIE);
- spin_unlock_irq(&die_lock);
+ raw_spin_unlock_irq(&die_lock);
oops_exit();
if (in_interrupt())
@@ -302,24 +302,24 @@
}
static LIST_HEAD(undef_hook);
-static DEFINE_SPINLOCK(undef_lock);
+static DEFINE_RAW_SPINLOCK(undef_lock);
void register_undef_hook(struct undef_hook *hook)
{
unsigned long flags;
- spin_lock_irqsave(&undef_lock, flags);
+ raw_spin_lock_irqsave(&undef_lock, flags);
list_add(&hook->node, &undef_hook);
- spin_unlock_irqrestore(&undef_lock, flags);
+ raw_spin_unlock_irqrestore(&undef_lock, flags);
}
void unregister_undef_hook(struct undef_hook *hook)
{
unsigned long flags;
- spin_lock_irqsave(&undef_lock, flags);
+ raw_spin_lock_irqsave(&undef_lock, flags);
list_del(&hook->node);
- spin_unlock_irqrestore(&undef_lock, flags);
+ raw_spin_unlock_irqrestore(&undef_lock, flags);
}
static int call_undef_hook(struct pt_regs *regs, unsigned int instr)
@@ -328,12 +328,12 @@
unsigned long flags;
int (*fn)(struct pt_regs *regs, unsigned int instr) = NULL;
- spin_lock_irqsave(&undef_lock, flags);
+ raw_spin_lock_irqsave(&undef_lock, flags);
list_for_each_entry(hook, &undef_hook, node)
if ((instr & hook->instr_mask) == hook->instr_val &&
(regs->ARM_cpsr & hook->cpsr_mask) == hook->cpsr_val)
fn = hook->fn;
- spin_unlock_irqrestore(&undef_lock, flags);
+ raw_spin_unlock_irqrestore(&undef_lock, flags);
return fn ? fn(regs, instr) : 1;
}
diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index a7b41bf..e83cc86 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -115,6 +115,32 @@
},
};
+#ifdef CONFIG_MTD
+static void da850_evm_m25p80_notify_add(struct mtd_info *mtd)
+{
+ char *mac_addr = davinci_soc_info.emac_pdata->mac_addr;
+ size_t retlen;
+
+ if (!strcmp(mtd->name, "MAC-Address")) {
+ mtd->read(mtd, 0, ETH_ALEN, &retlen, mac_addr);
+ if (retlen == ETH_ALEN)
+ pr_info("Read MAC addr from SPI Flash: %pM\n",
+ mac_addr);
+ }
+}
+
+static struct mtd_notifier da850evm_spi_notifier = {
+ .add = da850_evm_m25p80_notify_add,
+};
+
+static void da850_evm_setup_mac_addr(void)
+{
+ register_mtd_user(&da850evm_spi_notifier);
+}
+#else
+static void da850_evm_setup_mac_addr(void) { }
+#endif
+
static struct mtd_partition da850_evm_norflash_partition[] = {
{
.name = "bootloaders + env",
@@ -1237,6 +1263,8 @@
if (ret)
pr_warning("da850_evm_init: spi 1 registration failed: %d\n",
ret);
+
+ da850_evm_setup_mac_addr();
}
#ifdef CONFIG_SERIAL_8250_CONSOLE
diff --git a/arch/arm/mach-davinci/sleep.S b/arch/arm/mach-davinci/sleep.S
index fb5e72b..5f1e045 100644
--- a/arch/arm/mach-davinci/sleep.S
+++ b/arch/arm/mach-davinci/sleep.S
@@ -217,7 +217,11 @@
ENDPROC(davinci_ddr_psc_config)
CACHE_FLUSH:
- .word arm926_flush_kern_cache_all
+#ifdef CONFIG_CPU_V6
+ .word v6_flush_kern_cache_all
+#else
+ .word arm926_flush_kern_cache_all
+#endif
ENTRY(davinci_cpu_suspend_sz)
.word . - davinci_cpu_suspend
diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c
index 5ed51b8..cf7e598 100644
--- a/arch/arm/mach-dove/common.c
+++ b/arch/arm/mach-dove/common.c
@@ -160,7 +160,7 @@
void __init dove_spi1_init(void)
{
- orion_spi_init(DOVE_SPI1_PHYS_BASE, get_tclk());
+ orion_spi_1_init(DOVE_SPI1_PHYS_BASE, get_tclk());
}
/*****************************************************************************
diff --git a/arch/arm/mach-footbridge/include/mach/hardware.h b/arch/arm/mach-footbridge/include/mach/hardware.h
index b6fdf23..14db5a0 100644
--- a/arch/arm/mach-footbridge/include/mach/hardware.h
+++ b/arch/arm/mach-footbridge/include/mach/hardware.h
@@ -93,7 +93,7 @@
#define CPLD_FLASH_WR_ENABLE 1
#ifndef __ASSEMBLY__
-extern spinlock_t nw_gpio_lock;
+extern raw_spinlock_t nw_gpio_lock;
extern void nw_gpio_modify_op(unsigned int mask, unsigned int set);
extern void nw_gpio_modify_io(unsigned int mask, unsigned int in);
extern unsigned int nw_gpio_read(void);
diff --git a/arch/arm/mach-footbridge/netwinder-hw.c b/arch/arm/mach-footbridge/netwinder-hw.c
index 06e514f..5b73190 100644
--- a/arch/arm/mach-footbridge/netwinder-hw.c
+++ b/arch/arm/mach-footbridge/netwinder-hw.c
@@ -68,7 +68,7 @@
/*
* This is a lock for accessing ports GP1_IO_BASE and GP2_IO_BASE
*/
-DEFINE_SPINLOCK(nw_gpio_lock);
+DEFINE_RAW_SPINLOCK(nw_gpio_lock);
EXPORT_SYMBOL(nw_gpio_lock);
static unsigned int current_gpio_op;
@@ -327,9 +327,9 @@
/*
* Set Group1/Group2 outputs
*/
- spin_lock_irqsave(&nw_gpio_lock, flags);
+ raw_spin_lock_irqsave(&nw_gpio_lock, flags);
nw_gpio_modify_op(-1, GPIO_RED_LED | GPIO_FAN);
- spin_unlock_irqrestore(&nw_gpio_lock, flags);
+ raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
}
/*
@@ -390,9 +390,9 @@
{
unsigned long flags;
- spin_lock_irqsave(&nw_gpio_lock, flags);
+ raw_spin_lock_irqsave(&nw_gpio_lock, flags);
nw_cpld_modify(-1, CPLD_UNMUTE | CPLD_7111_DISABLE);
- spin_unlock_irqrestore(&nw_gpio_lock, flags);
+ raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
}
static unsigned char rwa_unlock[] __initdata =
@@ -616,9 +616,9 @@
cpld_init();
rwa010_init();
- spin_lock_irqsave(&nw_gpio_lock, flags);
+ raw_spin_lock_irqsave(&nw_gpio_lock, flags);
nw_gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, DEFAULT_LEDS);
- spin_unlock_irqrestore(&nw_gpio_lock, flags);
+ raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
}
return 0;
}
diff --git a/arch/arm/mach-footbridge/netwinder-leds.c b/arch/arm/mach-footbridge/netwinder-leds.c
index 00269fe..e57102e 100644
--- a/arch/arm/mach-footbridge/netwinder-leds.c
+++ b/arch/arm/mach-footbridge/netwinder-leds.c
@@ -31,13 +31,13 @@
static char led_state;
static char hw_led_state;
-static DEFINE_SPINLOCK(leds_lock);
+static DEFINE_RAW_SPINLOCK(leds_lock);
static void netwinder_leds_event(led_event_t evt)
{
unsigned long flags;
- spin_lock_irqsave(&leds_lock, flags);
+ raw_spin_lock_irqsave(&leds_lock, flags);
switch (evt) {
case led_start:
@@ -117,12 +117,12 @@
break;
}
- spin_unlock_irqrestore(&leds_lock, flags);
+ raw_spin_unlock_irqrestore(&leds_lock, flags);
if (led_state & LED_STATE_ENABLED) {
- spin_lock_irqsave(&nw_gpio_lock, flags);
+ raw_spin_lock_irqsave(&nw_gpio_lock, flags);
nw_gpio_modify_op(GPIO_RED_LED | GPIO_GREEN_LED, hw_led_state);
- spin_unlock_irqrestore(&nw_gpio_lock, flags);
+ raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
}
}
diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c
index 77315b9..0c20cf6 100644
--- a/arch/arm/mach-integrator/core.c
+++ b/arch/arm/mach-integrator/core.c
@@ -205,7 +205,7 @@
#define CM_CTRL IO_ADDRESS(INTEGRATOR_HDR_CTRL)
-static DEFINE_SPINLOCK(cm_lock);
+static DEFINE_RAW_SPINLOCK(cm_lock);
/**
* cm_control - update the CM_CTRL register.
@@ -217,10 +217,10 @@
unsigned long flags;
u32 val;
- spin_lock_irqsave(&cm_lock, flags);
+ raw_spin_lock_irqsave(&cm_lock, flags);
val = readl(CM_CTRL) & ~mask;
writel(val | set, CM_CTRL);
- spin_unlock_irqrestore(&cm_lock, flags);
+ raw_spin_unlock_irqrestore(&cm_lock, flags);
}
EXPORT_SYMBOL(cm_control);
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
index 2fbbdd5..fcf0ae9 100644
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -337,15 +337,15 @@
static void integrator_clocksource_init(u32 khz)
{
void __iomem *base = (void __iomem *)TIMER2_VA_BASE;
- u32 ctrl = TIMER_CTRL_ENABLE;
+ u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
if (khz >= 1500) {
khz /= 16;
- ctrl = TIMER_CTRL_DIV16;
+ ctrl |= TIMER_CTRL_DIV16;
}
- writel(ctrl, base + TIMER_CTRL);
writel(0xffff, base + TIMER_LOAD);
+ writel(ctrl, base + TIMER_CTRL);
clocksource_mmio_init(base + TIMER_VALUE, "timer2",
khz * 1000, 200, 16, clocksource_mmio_readl_down);
diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c
index 6467d99..a9b90a0 100644
--- a/arch/arm/mach-integrator/pci_v3.c
+++ b/arch/arm/mach-integrator/pci_v3.c
@@ -163,7 +163,7 @@
* 7:2 register number
*
*/
-static DEFINE_SPINLOCK(v3_lock);
+static DEFINE_RAW_SPINLOCK(v3_lock);
#define PCI_BUS_NONMEM_START 0x00000000
#define PCI_BUS_NONMEM_SIZE SZ_256M
@@ -284,7 +284,7 @@
unsigned long flags;
u32 v;
- spin_lock_irqsave(&v3_lock, flags);
+ raw_spin_lock_irqsave(&v3_lock, flags);
addr = v3_open_config_window(bus, devfn, where);
switch (size) {
@@ -302,7 +302,7 @@
}
v3_close_config_window();
- spin_unlock_irqrestore(&v3_lock, flags);
+ raw_spin_unlock_irqrestore(&v3_lock, flags);
*val = v;
return PCIBIOS_SUCCESSFUL;
@@ -314,7 +314,7 @@
unsigned long addr;
unsigned long flags;
- spin_lock_irqsave(&v3_lock, flags);
+ raw_spin_lock_irqsave(&v3_lock, flags);
addr = v3_open_config_window(bus, devfn, where);
switch (size) {
@@ -335,7 +335,7 @@
}
v3_close_config_window();
- spin_unlock_irqrestore(&v3_lock, flags);
+ raw_spin_unlock_irqrestore(&v3_lock, flags);
return PCIBIOS_SUCCESSFUL;
}
@@ -510,7 +510,7 @@
hook_fault_code(8, v3_pci_fault, SIGBUS, 0, "external abort on non-linefetch");
hook_fault_code(10, v3_pci_fault, SIGBUS, 0, "external abort on non-linefetch");
- spin_lock_irqsave(&v3_lock, flags);
+ raw_spin_lock_irqsave(&v3_lock, flags);
/*
* Unlock V3 registers, but only if they were previously locked.
@@ -583,7 +583,7 @@
printk(KERN_ERR "PCI: unable to grab PCI error "
"interrupt: %d\n", ret);
- spin_unlock_irqrestore(&v3_lock, flags);
+ raw_spin_unlock_irqrestore(&v3_lock, flags);
}
void __init pci_v3_postinit(void)
diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c
index e9a5893..ab19445 100644
--- a/arch/arm/mach-ixp4xx/common-pci.c
+++ b/arch/arm/mach-ixp4xx/common-pci.c
@@ -54,7 +54,7 @@
* these transactions are atomic or we will end up
* with corrupt data on the bus or in a driver.
*/
-static DEFINE_SPINLOCK(ixp4xx_pci_lock);
+static DEFINE_RAW_SPINLOCK(ixp4xx_pci_lock);
/*
* Read from PCI config space
@@ -62,10 +62,10 @@
static void crp_read(u32 ad_cbe, u32 *data)
{
unsigned long flags;
- spin_lock_irqsave(&ixp4xx_pci_lock, flags);
+ raw_spin_lock_irqsave(&ixp4xx_pci_lock, flags);
*PCI_CRP_AD_CBE = ad_cbe;
*data = *PCI_CRP_RDATA;
- spin_unlock_irqrestore(&ixp4xx_pci_lock, flags);
+ raw_spin_unlock_irqrestore(&ixp4xx_pci_lock, flags);
}
/*
@@ -74,10 +74,10 @@
static void crp_write(u32 ad_cbe, u32 data)
{
unsigned long flags;
- spin_lock_irqsave(&ixp4xx_pci_lock, flags);
+ raw_spin_lock_irqsave(&ixp4xx_pci_lock, flags);
*PCI_CRP_AD_CBE = CRP_AD_CBE_WRITE | ad_cbe;
*PCI_CRP_WDATA = data;
- spin_unlock_irqrestore(&ixp4xx_pci_lock, flags);
+ raw_spin_unlock_irqrestore(&ixp4xx_pci_lock, flags);
}
static inline int check_master_abort(void)
@@ -101,7 +101,7 @@
int retval = 0;
int i;
- spin_lock_irqsave(&ixp4xx_pci_lock, flags);
+ raw_spin_lock_irqsave(&ixp4xx_pci_lock, flags);
*PCI_NP_AD = addr;
@@ -118,7 +118,7 @@
if(check_master_abort())
retval = 1;
- spin_unlock_irqrestore(&ixp4xx_pci_lock, flags);
+ raw_spin_unlock_irqrestore(&ixp4xx_pci_lock, flags);
return retval;
}
@@ -127,7 +127,7 @@
unsigned long flags;
int retval = 0;
- spin_lock_irqsave(&ixp4xx_pci_lock, flags);
+ raw_spin_lock_irqsave(&ixp4xx_pci_lock, flags);
*PCI_NP_AD = addr;
@@ -140,7 +140,7 @@
if(check_master_abort())
retval = 1;
- spin_unlock_irqrestore(&ixp4xx_pci_lock, flags);
+ raw_spin_unlock_irqrestore(&ixp4xx_pci_lock, flags);
return retval;
}
@@ -149,7 +149,7 @@
unsigned long flags;
int retval = 0;
- spin_lock_irqsave(&ixp4xx_pci_lock, flags);
+ raw_spin_lock_irqsave(&ixp4xx_pci_lock, flags);
*PCI_NP_AD = addr;
@@ -162,7 +162,7 @@
if(check_master_abort())
retval = 1;
- spin_unlock_irqrestore(&ixp4xx_pci_lock, flags);
+ raw_spin_unlock_irqrestore(&ixp4xx_pci_lock, flags);
return retval;
}
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 2d681fa..0078ebc 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -146,7 +146,7 @@
select MIGRATION
select ARCH_MEMORY_PROBE
select ARCH_MEMORY_REMOVE
- select DONT_RESERVE_FROM_MOVABLE_ZONE
+ select FIX_MOVABLE_ZONE
config ARCH_MSM8930
bool "MSM8930"
@@ -177,7 +177,7 @@
select MIGRATION
select ARCH_MEMORY_PROBE
select ARCH_MEMORY_REMOVE
- select DONT_RESERVE_FROM_MOVABLE_ZONE
+ select FIX_MOVABLE_ZONE
select MSM_ULTRASOUND
config ARCH_APQ8064
@@ -190,6 +190,9 @@
select MSM_SCM if SMP
select MSM_GPIOMUX
select MSM_REMOTE_SPINLOCK_SFPB
+ select MSM_PIL
+ select MSM_QDSP6_APR
+ select MSM_AUDIO_QDSP6 if SND_SOC
config ARCH_MSMCOPPER
bool "MSM Copper"
@@ -252,6 +255,7 @@
config ARCH_MSM_KRAIT
bool
+ select ARM_L1_CACHE_SHIFT_6
config MSM_SMP
bool
@@ -604,6 +608,18 @@
help
Support for the Qualcomm MSM8930 FLUID device.
+config MACH_MSM8627_CDP
+ depends on ARCH_MSM8930
+ bool "MSM8627 CDP"
+ help
+ Support for the Qualcomm MSM8627 CDP device.
+
+config MACH_MSM8627_MTP
+ depends on ARCH_MSM8930
+ bool "MSM8627 MTP"
+ help
+ Support for the Qualcomm MSM8627 MTP device.
+
config MACH_MSM9615_CDP
depends on ARCH_MSM9615
bool "MSM9615 CDP"
@@ -712,9 +728,21 @@
bool "6.2.20 + New ADSP"
endchoice
+config MSM_HAS_DEBUG_UART_HS
+ bool
+ help
+ Say Y here if high speed MSM UART is present.
+
+config MSM_HAS_DEBUG_UART_HS_V14
+ bool
+ select MSM_HAS_DEBUG_UART_HS
+ help
+ Say Y here if high speed MSM UART v1.4 is present.
+
config DEBUG_MSM8930_UART
bool "Kernel low-level debugging messages via MSM 8930 UART"
depends on ARCH_MSM8930 && DEBUG_LL
+ select MSM_HAS_DEBUG_UART_HS
help
Say Y here if you want the debug print routines to direct
their output to the serial port on MSM 8930 devices.
@@ -747,6 +775,7 @@
config DEBUG_MSM8660_UART
bool "Kernel low-level debugging messages via MSM 8660 UART"
depends on ARCH_MSM8X60
+ select MSM_HAS_DEBUG_UART_HS
help
Say Y here if you want the debug print routines to direct
their output to the serial port on MSM 8660 devices.
@@ -755,9 +784,18 @@
bool "Kernel low-level debugging messages via MSM 8960 UART"
depends on ARCH_MSM8960
select DEBUG_MSM8930_UART
+ select MSM_HAS_DEBUG_UART_HS
help
Say Y here if you want the debug print routines to direct
their output to the serial port on MSM 8960 devices.
+
+ config DEBUG_MSMCOPPER_UART
+ bool "Kernel low-level debugging messages via MSM Copper UART"
+ depends on ARCH_MSMCOPPER
+ select MSM_HAS_DEBUG_UART_HS_V14
+ help
+ Say Y here if you want the debug print routines to direct
+ their output to the serial port on MSM Copper devices.
endchoice
choice
@@ -1536,6 +1574,14 @@
Say yes to support these devices.
+config MSM_PIL_QDSP6V4
+ tristate "QDSP6v4 (Hexagon) Boot Support"
+ depends on MSM_PIL
+ help
+ Support for booting and shutting down QDSP6v4 processors (hexagon).
+ The QDSP6 is a low power DSP used in audio, modem firmware, and modem
+ software applications.
+
config MSM_SCM
bool "Secure Channel Manager (SCM) support"
default n
@@ -1604,6 +1650,14 @@
allocate physical memory which is used by bus performance hardware to
dump performance data.
+config MSM_TZ_LOG
+ tristate "MSM Trust Zone (TZ) Log Driver"
+ depends on DEBUG_FS
+ help
+ This option enables a driver with a debugfs interface for messages
+ produced by the Secure code (Trust zone). These messages provide
+ diagnostic information about TZ operation.
+
config MSM_RPM_LOG
tristate "MSM Resource Power Manager Log Driver"
depends on DEBUG_FS
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 60259ca..05f4ab4 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -1,4 +1,7 @@
-obj-y += io.o dma.o memory.o timer.o
+obj-y += io.o dma.o memory.o
+ifndef CONFIG_ARM_ARCH_TIMER
+obj-y += timer.o
+endif
obj-y += clock.o clock-voter.o clock-dummy.o
obj-y += modem_notifier.o subsystem_map.o
obj-$(CONFIG_CPU_FREQ_MSM) += cpufreq.o
@@ -68,6 +71,7 @@
obj-$(CONFIG_ARCH_MSM8X60) += peripheral-reset.o
obj-$(CONFIG_ARCH_MSM8960) += peripheral-reset-8960.o
endif
+obj-$(CONFIG_MSM_PIL_QDSP6V4) += pil-q6v4.o
obj-$(CONFIG_ARCH_QSD8X50) += sirc.o
obj-$(CONFIG_ARCH_FSM9XXX) += sirc-fsm9xxx.o
obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o
@@ -99,7 +103,7 @@
endif
endif
endif
-obj-$(CONFIG_MSM_SDIO_TTY) += sdio_tty.o sdio_tty_ciq.o
+obj-$(CONFIG_MSM_SDIO_TTY) += sdio_tty.o
obj-$(CONFIG_MSM_SMD_TTY) += smd_tty.o
obj-$(CONFIG_MSM_SMD_QMI) += smd_qmi.o
obj-$(CONFIG_MSM_SMD_PKT) += smd_pkt.o
@@ -149,7 +153,7 @@
obj-$(CONFIG_ARCH_MSM7X01A) += pm.o
obj-y += pm-boot.o
else
- obj-y += no-pm.o
+ obj-y += no-pm.o hotplug.o
endif
obj-$(CONFIG_MSM_SPM_V1) += spm.o
@@ -223,16 +227,22 @@
obj-$(CONFIG_ARCH_MSM8960) += acpuclock-8960.o
obj-$(CONFIG_ARCH_MSM8960) += memory_topology.o
obj-$(CONFIG_ARCH_MSM8960) += saw-regulator.o rpm-regulator.o rpm-regulator-8960.o
-obj-$(CONFIG_MACH_MSM8960_SIM) += board-msm8960.o devices-8960.o board-msm8960-regulator.o
-obj-$(CONFIG_MACH_MSM8960_RUMI3) += board-msm8960.o devices-8960.o board-msm8960-regulator.o
-obj-$(CONFIG_MACH_MSM8960_CDP) += board-msm8960.o devices-8960.o board-msm8960-regulator.o
-obj-$(CONFIG_MACH_MSM8960_MTP) += board-msm8960.o devices-8960.o board-msm8960-regulator.o
-obj-$(CONFIG_MACH_MSM8960_FLUID) += board-msm8960.o devices-8960.o board-msm8960-regulator.o
-obj-$(CONFIG_MACH_MSM8930_CDP) += board-msm8960.o devices-8960.o board-msm8960-regulator.o
-obj-$(CONFIG_MACH_MSM8930_MTP) += board-msm8960.o devices-8960.o board-msm8960-regulator.o
-obj-$(CONFIG_MACH_MSM8930_FLUID) += board-msm8960.o devices-8960.o board-msm8960-regulator.o
+obj-$(CONFIG_ARCH_MSM8960) += devices-8960.o
+obj-$(CONFIG_ARCH_APQ8064) += devices-8960.o devices-8064.o
+board-8960-all-objs += board-8960.o board-8960-camera.o board-8960-display.o board-8960-pmic.o board-8960-storage.o board-8960-gpiomux.o
+board-8930-all-objs += board-8930.o board-8930-camera.o board-8930-display.o board-8930-pmic.o board-8930-storage.o board-8930-gpiomux.o
+board-8064-all-objs += board-8064.o board-8064-storage.o
+obj-$(CONFIG_MACH_MSM8960_SIM) += board-8960-all.o board-8960-regulator.o
+obj-$(CONFIG_MACH_MSM8960_RUMI3) += board-8960-all.o board-8960-regulator.o
+obj-$(CONFIG_MACH_MSM8960_CDP) += board-8960-all.o board-8960-regulator.o
+obj-$(CONFIG_MACH_MSM8960_MTP) += board-8960-all.o board-8960-regulator.o
+obj-$(CONFIG_MACH_MSM8960_FLUID) += board-8960-all.o board-8960-regulator.o
+obj-$(CONFIG_MACH_MSM8930_CDP) += board-8930-all.o board-8960-regulator.o
+obj-$(CONFIG_MACH_MSM8930_MTP) += board-8930-all.o board-8960-regulator.o
+obj-$(CONFIG_MACH_MSM8930_FLUID) += board-8930-all.o board-8960-regulator.o
obj-$(CONFIG_ARCH_MSM8960) += bms-batterydata.o
-obj-$(CONFIG_ARCH_APQ8064) += board-apq8064.o devices-8064.o board-apq8064-regulator.o
+obj-$(CONFIG_MACH_APQ8064_SIM) += board-8064-all.o board-8064-regulator.o
+obj-$(CONFIG_MACH_APQ8064_RUMI3) += board-8064-all.o board-8064-regulator.o
obj-$(CONFIG_ARCH_MSM9615) += board-9615.o devices-9615.o board-9615-regulator.o
obj-$(CONFIG_ARCH_MSM9615) += clock-local.o clock-9615.o acpuclock-9615.o clock-rpm.o
obj-$(CONFIG_ARCH_MSM9615) += rpm-regulator.o rpm-regulator-9615.o
@@ -253,11 +263,11 @@
obj-$(CONFIG_HTC_HEADSET) += htc_headset.o
obj-$(CONFIG_MSM_RMT_STORAGE_CLIENT) += rmt_storage_client.o
obj-$(CONFIG_MSM_SDIO_SMEM) += sdio_smem.o
-obj-$(CONFIG_PMIC8058) += pmic8058-gpio.o pmic8058-mpp.o
obj-$(CONFIG_MSM_RPM) += rpm.o rpm_resources.o
obj-$(CONFIG_MSM_MPM) += mpm.o
obj-$(CONFIG_MSM_RPM_STATS_LOG) += rpm_stats.o
obj-$(CONFIG_MSM_RPM_LOG) += rpm_log.o
+obj-$(CONFIG_MSM_TZ_LOG) += tz_log.o
obj-$(CONFIG_MSM_XO) += msm_xo.o
obj-$(CONFIG_MSM_BUS_SCALING) += msm_bus/
obj-$(CONFIG_MSM_BUSPM_DEV) += msm-buspm-dev.o
@@ -301,3 +311,5 @@
obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30-regulator.o
obj-$(CONFIG_ARCH_MSM7X27A) += board-msm7x27a-regulator.o
endif
+
+obj-$(CONFIG_ARCH_MSM8960) += mdm2.o mdm_common.o
diff --git a/arch/arm/mach-msm/acpuclock-7201.c b/arch/arm/mach-msm/acpuclock-7201.c
index 4702e51..0338d53 100644
--- a/arch/arm/mach-msm/acpuclock-7201.c
+++ b/arch/arm/mach-msm/acpuclock-7201.c
@@ -341,10 +341,86 @@
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
+/* 7x27a pll2 at 1200mhz with GSM capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_737_pll2_1200_pll4_800[] = {
+ { 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
+ { 0, 61440, ACPU_PLL_1, 1, 11, 7680, 3, 1, 61440 },
+ { 1, 122880, ACPU_PLL_1, 1, 5, 15360, 3, 2, 61440 },
+ { 1, 245760, ACPU_PLL_1, 1, 2, 30720, 3, 3, 61440 },
+ { 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+ { 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
+ { 0, 400000, ACPU_PLL_4, 6, 1, 50000, 3, 4, 122880 },
+ { 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
+ { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
+ { 1, 800000, ACPU_PLL_4, 6, 0, 100000, 3, 7, 200000 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+/* 7x27a pll2 at 1200mhz with CDMA only modem */
+static struct clkctl_acpu_speed pll0_960_pll1_589_pll2_1200_pll4_800[] = {
+ { 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 24576 },
+ { 0, 65536, ACPU_PLL_1, 1, 8, 8192, 3, 1, 49152 },
+ { 1, 98304, ACPU_PLL_1, 1, 5, 12288, 3, 2, 49152 },
+ { 1, 196608, ACPU_PLL_1, 1, 2, 24576, 3, 3, 98304 },
+ { 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 120000 },
+ { 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 120000 },
+ { 0, 400000, ACPU_PLL_4, 6, 1, 50000, 3, 4, 120000 },
+ { 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 120000 },
+ { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
+ { 1, 800000, ACPU_PLL_4, 6, 0, 100000, 3, 7, 200000 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+/* 7x27aa pll4 at 1008mhz with GSM capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_737_pll2_1200_pll4_1008[] = {
+ { 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
+ { 0, 61440, ACPU_PLL_1, 1, 11, 7680, 3, 1, 61440 },
+ { 1, 122880, ACPU_PLL_1, 1, 5, 15360, 3, 2, 61440 },
+ { 1, 245760, ACPU_PLL_1, 1, 2, 30720, 3, 3, 61440 },
+ { 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+ { 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
+ { 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
+ { 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
+ { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
+ { 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 7, 200000},
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+/* 7x27aa pll4 at 1008mhz with CDMA capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_589_pll2_1200_pll4_1008[] = {
+ { 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 24576 },
+ { 0, 65536, ACPU_PLL_1, 1, 8, 8192, 3, 1, 49152 },
+ { 1, 98304, ACPU_PLL_1, 1, 5, 12288, 3, 2, 49152 },
+ { 1, 196608, ACPU_PLL_1, 1, 2, 24576, 3, 3, 98304 },
+ { 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+ { 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
+ { 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
+ { 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
+ { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
+ { 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 7, 200000},
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+/* 7x25a pll2 at 1200mhz with GSM capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_737_pll2_1200_pll4_800_25a[] = {
+ { 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
+ { 0, 61440, ACPU_PLL_1, 1, 11, 7680, 3, 1, 61440 },
+ { 1, 122880, ACPU_PLL_1, 1, 5, 15360, 3, 2, 61440 },
+ { 1, 245760, ACPU_PLL_1, 1, 2, 30720, 3, 3, 61440 },
+ { 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+ { 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
+ { 0, 400000, ACPU_PLL_4, 6, 1, 50000, 3, 4, 122880 },
+ { 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
+ { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
#define PLL_0_MHZ 0
#define PLL_196_MHZ 10
#define PLL_245_MHZ 12
#define PLL_491_MHZ 25
+#define PLL_589_MHZ 30
+#define PLL_737_MHZ 38
#define PLL_768_MHZ 40
#define PLL_800_MHZ 41
#define PLL_960_MHZ 50
@@ -380,6 +456,10 @@
PLL_CONFIG(960, 196, 1200, 800),
PLL_CONFIG(960, 245, 1200, 1008),
PLL_CONFIG(960, 196, 1200, 1008),
+ PLL_CONFIG(960, 737, 1200, 800),
+ PLL_CONFIG(960, 589, 1200, 800),
+ PLL_CONFIG(960, 737, 1200, 1008),
+ PLL_CONFIG(960, 589, 1200, 1008),
{ 0, 0, 0, 0, 0 }
};
@@ -868,6 +948,9 @@
if (pll1_l == PLL_245_MHZ) {
acpu_freq_tbl =
pll0_960_pll1_245_pll2_1200_pll4_800_25a;
+ } else if (pll1_l == PLL_737_MHZ) {
+ acpu_freq_tbl =
+ pll0_960_pll1_737_pll2_1200_pll4_800_25a;
}
} else {
/* Select the right table to use. */
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index 659c292..be8c31c 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -140,7 +140,7 @@
.hfpll_base = MSM_HFPLL_BASE + 0x200,
.aux_clk_sel = MSM_ACC0_BASE + 0x014,
.l2cpmr_iaddr = L2CPUCPMR_IADDR,
- .vreg[VREG_CORE] = { "krait0", 1150000 },
+ .vreg[VREG_CORE] = { "krait0", 1300000 },
.vreg[VREG_MEM] = { "krait0_mem", 1150000,
RPM_VREG_VOTER1,
RPM_VREG_ID_PM8921_L24 },
@@ -158,7 +158,7 @@
.hfpll_base = MSM_HFPLL_BASE + 0x300,
.aux_clk_sel = MSM_ACC1_BASE + 0x014,
.l2cpmr_iaddr = L2CPUCPMR_IADDR,
- .vreg[VREG_CORE] = { "krait1", 1150000 },
+ .vreg[VREG_CORE] = { "krait1", 1300000 },
.vreg[VREG_MEM] = { "krait0_mem", 1150000,
RPM_VREG_VOTER2,
RPM_VREG_ID_PM8921_L24 },
@@ -287,8 +287,8 @@
static uint32_t bus_perf_client;
/* TODO: Update vdd_dig and vdd_mem when voltage data is available. */
-#define L2(x) (&l2_freq_tbl_8960[(x)])
-static struct l2_level l2_freq_tbl_8960[] = {
+#define L2(x) (&l2_freq_tbl_8960_kraitv1[(x)])
+static struct l2_level l2_freq_tbl_8960_kraitv1[] = {
[0] = { {STBY_KHZ, QSB, 0, 0, 0x00 }, 1050000, 1050000, 0 },
[1] = { { 384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
[2] = { { 432000, HFPLL, 2, 0, 0x20 }, 1050000, 1050000, 1 },
@@ -303,7 +303,7 @@
[11] = { { 918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 3 },
};
-static struct acpu_level acpu_freq_tbl_8960[] = {
+static struct acpu_level acpu_freq_tbl_8960_kraitv1[] = {
{ 0, {STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 950000 },
{ 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 950000 },
{ 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 950000 },
@@ -319,6 +319,55 @@
{ 0, { 0 } }
};
+#undef L2
+#define L2(x) (&l2_freq_tbl_8960_kraitv2[(x)])
+static struct l2_level l2_freq_tbl_8960_kraitv2[] = {
+ [0] = { {STBY_KHZ, QSB, 0, 0, 0x00 }, 1050000, 1050000, 0 },
+ [1] = { { 384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
+ [2] = { { 432000, HFPLL, 2, 0, 0x20 }, 1050000, 1050000, 1 },
+ [3] = { { 486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 1 },
+ [4] = { { 540000, HFPLL, 2, 0, 0x28 }, 1050000, 1050000, 1 },
+ [5] = { { 594000, HFPLL, 1, 0, 0x16 }, 1050000, 1050000, 2 },
+ [6] = { { 648000, HFPLL, 1, 0, 0x18 }, 1050000, 1050000, 2 },
+ [7] = { { 702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 2 },
+ [8] = { { 756000, HFPLL, 1, 0, 0x1C }, 1150000, 1150000, 2 },
+ [9] = { { 810000, HFPLL, 1, 0, 0x1E }, 1150000, 1150000, 3 },
+ [10] = { { 864000, HFPLL, 1, 0, 0x20 }, 1150000, 1150000, 3 },
+ [11] = { { 918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 3 },
+ [12] = { { 972000, HFPLL, 1, 0, 0x24 }, 1150000, 1150000, 4 },
+ [13] = { { 1026000, HFPLL, 1, 0, 0x26 }, 1150000, 1150000, 4 },
+ [14] = { { 1080000, HFPLL, 1, 0, 0x28 }, 1150000, 1150000, 4 },
+ [15] = { { 1134000, HFPLL, 1, 0, 0x2A }, 1150000, 1150000, 4 },
+ [16] = { { 1188000, HFPLL, 1, 0, 0x2C }, 1150000, 1150000, 4 },
+};
+
+static struct acpu_level acpu_freq_tbl_8960_kraitv2[] = {
+ { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 950000 },
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 950000 },
+ { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 950000 },
+ { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 962500 },
+ { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 962500 },
+ { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(6), 987500 },
+ { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(6), 1000000 },
+ { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(6), 1025000 },
+ { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(11), 1050000 },
+ { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(11), 1087500 },
+ { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(11), 1125000 },
+ { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(11), 1137500 },
+ { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(16), 1300000 },
+ { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(16), 1300000 },
+ { 1, { 1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1300000 },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1300000 },
+ { 1, { 1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1300000 },
+ { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(16), 1300000 },
+ { 1, { 1296000, HFPLL, 1, 0, 0x30 }, L2(16), 1300000 },
+ { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(16), 1300000 },
+ { 1, { 1404000, HFPLL, 1, 0, 0x34 }, L2(16), 1300000 },
+ { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(16), 1300000 },
+ { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(16), 1300000 },
+ { 0, { 0 } }
+};
+
/* TODO: Update vdd_dig and vdd_mem when voltage data is available. */
#undef L2
#define L2(x) (&l2_freq_tbl_8064[(x)])
@@ -715,7 +764,9 @@
{
unsigned int pll_vdd_dig;
- if (tgt->l2_level->speed.pll_l_val > HFPLL_LOW_VDD_PLL_L_MAX)
+ if (tgt->l2_level->speed.src != HFPLL)
+ pll_vdd_dig = 0;
+ else if (tgt->l2_level->speed.pll_l_val > HFPLL_LOW_VDD_PLL_L_MAX)
pll_vdd_dig = HFPLL_NOMINAL_VDD;
else
pll_vdd_dig = HFPLL_LOW_VDD;
@@ -727,7 +778,9 @@
{
unsigned int pll_vdd_core;
- if (tgt->speed.pll_l_val > HFPLL_LOW_VDD_PLL_L_MAX)
+ if (tgt->speed.src != HFPLL)
+ pll_vdd_core = 0;
+ else if (tgt->speed.pll_l_val > HFPLL_LOW_VDD_PLL_L_MAX)
pll_vdd_core = HFPLL_NOMINAL_VDD;
else
pll_vdd_core = HFPLL_LOW_VDD;
@@ -1051,9 +1104,15 @@
/* TODO: Select tables based on PVS data. */
scalable = scalable_8960;
- acpu_freq_tbl = acpu_freq_tbl_8960;
- l2_freq_tbl = l2_freq_tbl_8960;
- l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8960);
+ if (cpu_is_krait_v1()) {
+ acpu_freq_tbl = acpu_freq_tbl_8960_kraitv1;
+ l2_freq_tbl = l2_freq_tbl_8960_kraitv1;
+ l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8960_kraitv1);
+ } else {
+ acpu_freq_tbl = acpu_freq_tbl_8960_kraitv2;
+ l2_freq_tbl = l2_freq_tbl_8960_kraitv2;
+ l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8960_kraitv2);
+ }
} else if (cpu_is_apq8064()) {
scalable = scalable_8064;
acpu_freq_tbl = acpu_freq_tbl_8064;
diff --git a/arch/arm/mach-msm/acpuclock-9615.c b/arch/arm/mach-msm/acpuclock-9615.c
index ebc7f1b..1f112f6 100644
--- a/arch/arm/mach-msm/acpuclock-9615.c
+++ b/arch/arm/mach-msm/acpuclock-9615.c
@@ -27,6 +27,8 @@
#include <mach/board.h>
#include <mach/msm_iomap.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
#include <mach/rpm-regulator.h>
#include "acpuclock.h"
@@ -54,7 +56,6 @@
};
static struct src_clock clocks[NUM_SRC] = {
- [SRC_CXO].name = "cxo",
[SRC_PLL0].name = "pll0",
[SRC_PLL8].name = "pll8",
[SRC_PLL9].name = "pll9",
@@ -68,6 +69,7 @@
unsigned int src_div;
unsigned int vdd_cpu;
unsigned int vdd_mem;
+ unsigned int bw_level;
};
struct acpuclk_state {
@@ -79,12 +81,40 @@
.current_speed = &(struct clkctl_acpu_speed){ 0 },
};
+/* Instantaneous bandwidth requests in MB/s. */
+#define BW_MBPS(_bw) \
+ { \
+ .vectors = &(struct msm_bus_vectors){ \
+ .src = MSM_BUS_MASTER_AMPSS_M0, \
+ .dst = MSM_BUS_SLAVE_EBI_CH0, \
+ .ib = (_bw) * 1000000UL, \
+ .ab = 0, \
+ }, \
+ .num_paths = 1, \
+ }
+static struct msm_bus_paths bw_level_tbl[] = {
+ [0] = BW_MBPS(152), /* At least 19 MHz on bus. */
+ [1] = BW_MBPS(368), /* At least 46 MHz on bus. */
+ [2] = BW_MBPS(552), /* At least 69 MHz on bus. */
+ [3] = BW_MBPS(736), /* At least 92 MHz on bus. */
+ [4] = BW_MBPS(1064), /* At least 133 MHz on bus. */
+};
+
+static struct msm_bus_scale_pdata bus_client_pdata = {
+ .usecase = bw_level_tbl,
+ .num_usecases = ARRAY_SIZE(bw_level_tbl),
+ .active_only = 1,
+ .name = "acpuclock",
+};
+
+static uint32_t bus_perf_client;
+
static struct clkctl_acpu_speed acpu_freq_tbl[] = {
- { 0, 19200, SRC_CXO, 0, 0, 950000, 1050000 },
- { 1, 138000, SRC_PLL0, 6, 1, 950000, 1050000 },
- { 1, 276000, SRC_PLL0, 6, 0, 1050000, 1050000 },
- { 1, 384000, SRC_PLL8, 3, 0, 1150000, 1150000 },
- { 1, 440000, SRC_PLL9, 2, 0, 1150000, 1150000 },
+ { 0, 19200, SRC_CXO, 0, 0, 950000, 1050000, 0 },
+ { 1, 138000, SRC_PLL0, 6, 1, 950000, 1050000, 2 },
+ { 1, 276000, SRC_PLL0, 6, 0, 1050000, 1050000, 2 },
+ { 1, 384000, SRC_PLL8, 3, 0, 1150000, 1150000, 4 },
+ { 1, 440000, SRC_PLL9, 2, 0, 1150000, 1150000, 4 },
{ 0 }
};
@@ -104,6 +134,25 @@
udelay(1);
}
+/* Update the bus bandwidth request. */
+static void set_bus_bw(unsigned int bw)
+{
+ int ret;
+
+ /* Bounds check. */
+ if (bw >= ARRAY_SIZE(bw_level_tbl)) {
+ pr_err("invalid bandwidth request (%d)\n", bw);
+ return;
+ }
+
+ /* Update bandwidth if request has changed. This may sleep. */
+ ret = msm_bus_scale_client_update_request(bus_perf_client, bw);
+ if (ret)
+ pr_err("bandwidth request failed (%d)\n", ret);
+
+ return;
+}
+
/* Apply any per-cpu voltage increases. */
static int increase_vdd(unsigned int vdd_cpu, unsigned int vdd_mem)
{
@@ -198,6 +247,9 @@
if (reason == SETRATE_SWFI || reason == SETRATE_PC)
goto out;
+ /* Update bus bandwith request. */
+ set_bus_bw(tgt_s->bw_level);
+
/* Drop VDD levels if we can. */
if (tgt_s->khz < strt_s->khz)
decrease_vdd(tgt_s->vdd_cpu, tgt_s->vdd_mem);
@@ -258,9 +310,16 @@
int i;
mutex_init(&drv_state.lock);
+
+ bus_perf_client = msm_bus_scale_register_client(&bus_client_pdata);
+ if (!bus_perf_client) {
+ pr_err("Unable to register bus client\n");
+ BUG();
+ }
+
for (i = 0; i < NUM_SRC; i++) {
if (clocks[i].name) {
- clocks[i].clk = clk_get_sys(NULL, clocks[i].name);
+ clocks[i].clk = clk_get_sys("acpu", clocks[i].name);
BUG_ON(IS_ERR(clocks[i].clk));
}
}
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index cb0406f..644a666 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -25,11 +25,13 @@
#include <linux/skbuff.h>
#include <linux/debugfs.h>
#include <linux/clk.h>
+#include <linux/wakelock.h>
#include <mach/sps.h>
#include <mach/bam_dmux.h>
#include <mach/msm_smsm.h>
#include <mach/subsystem_notif.h>
+#include <mach/socinfo.h>
#define BAM_CH_LOCAL_OPEN 0x1
#define BAM_CH_REMOTE_OPEN 0x2
@@ -45,6 +47,8 @@
#define POLLING_MAX_SLEEP 1050 /* 1.05 ms */
#define POLLING_INACTIVITY 40 /* cycles before switch to intr mode */
+#define LOW_WATERMARK 2
+#define HIGH_WATERMARK 4
static int msm_bam_dmux_debug_enable;
module_param_named(debug_enable, msm_bam_dmux_debug_enable,
@@ -55,6 +59,7 @@
static uint32_t bam_dmux_write_cnt;
static uint32_t bam_dmux_write_cpy_cnt;
static uint32_t bam_dmux_write_cpy_bytes;
+static uint32_t bam_dmux_tx_sps_failure_cnt;
#define DBG(x...) do { \
if (msm_bam_dmux_debug_enable) \
@@ -83,11 +88,17 @@
__func__, bam_dmux_write_cpy_cnt, \
bam_dmux_write_cpy_bytes); \
} while (0)
+
+#define DBG_INC_TX_SPS_FAILURE_CNT() do { \
+ bam_dmux_tx_sps_failure_cnt++; \
+} while (0)
+
#else
#define DBG(x...) do { } while (0)
#define DBG_INC_READ_CNT(x...) do { } while (0)
#define DBG_INC_WRITE_CNT(x...) do { } while (0)
#define DBG_INC_WRITE_CPY(x...) do { } while (0)
+#define DBG_INC_TX_SPS_FAILURE_CNT() do { } while (0)
#endif
struct bam_ch_info {
@@ -97,6 +108,8 @@
spinlock_t lock;
struct platform_device *pdev;
char name[BAM_DMUX_CH_NAME_MAX_LEN];
+ int num_tx_pkts;
+ int use_wm;
};
struct tx_pkt_info {
@@ -183,6 +196,8 @@
static DEFINE_RWLOCK(ul_wakeup_lock);
static DECLARE_WORK(kickoff_ul_wakeup, kickoff_ul_wakeup_func);
static int bam_connection_is_active;
+static int wait_for_ack;
+static struct wake_lock bam_wakelock;
/* End A2 power collaspe */
/* subsystem restart */
@@ -217,12 +232,19 @@
return;
info = kmalloc(sizeof(struct rx_pkt_info), GFP_KERNEL);
- if (!info)
- return; /*need better way to handle this */
+ if (!info) {
+ pr_err("%s: unable to alloc rx_pkt_info\n", __func__);
+ return;
+ }
INIT_WORK(&info->work, handle_bam_mux_cmd);
info->skb = __dev_alloc_skb(BUFFER_SIZE, GFP_KERNEL);
+ if (info->skb == NULL) {
+ pr_err("%s: unable to alloc skb\n", __func__);
+ kfree(info);
+ return;
+ }
ptr = skb_put(info->skb, BUFFER_SIZE);
mutex_lock(&bam_rx_pool_mutexlock);
@@ -292,6 +314,17 @@
queue_rx();
return;
}
+
+ if (rx_hdr->ch_id >= BAM_DMUX_NUM_CHANNELS) {
+ pr_err("%s: dropping invalid LCID %d reserved %d cmd %d"
+ " pad %d ch %d len %d\n", __func__,
+ rx_hdr->ch_id, rx_hdr->reserved, rx_hdr->cmd,
+ rx_hdr->pad_len, rx_hdr->ch_id, rx_hdr->pkt_len);
+ dev_kfree_skb_any(rx_skb);
+ queue_rx();
+ return;
+ }
+
switch (rx_hdr->cmd) {
case BAM_MUX_HDR_CMD_DATA:
DBG_INC_READ_CNT(rx_hdr->pkt_len);
@@ -300,6 +333,7 @@
case BAM_MUX_HDR_CMD_OPEN:
spin_lock_irqsave(&bam_ch[rx_hdr->ch_id].lock, flags);
bam_ch[rx_hdr->ch_id].status |= BAM_CH_REMOTE_OPEN;
+ bam_ch[rx_hdr->ch_id].num_tx_pkts = 0;
spin_unlock_irqrestore(&bam_ch[rx_hdr->ch_id].lock, flags);
queue_rx();
ret = platform_device_add(bam_ch[rx_hdr->ch_id].pdev);
@@ -337,6 +371,7 @@
int rc;
struct tx_pkt_info *pkt;
dma_addr_t dma_address;
+ unsigned long flags;
pkt = kmalloc(sizeof(struct tx_pkt_info), GFP_ATOMIC);
if (pkt == NULL) {
@@ -349,6 +384,7 @@
DMA_TO_DEVICE);
if (!dma_address) {
pr_err("%s: dma_map_single() failed\n", __func__);
+ kfree(pkt);
rc = -ENOMEM;
return rc;
}
@@ -357,16 +393,17 @@
pkt->dma_address = dma_address;
pkt->is_cmd = 1;
INIT_WORK(&pkt->work, bam_mux_write_done);
- spin_lock(&bam_tx_pool_spinlock);
+ spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
list_add_tail(&pkt->list_node, &bam_tx_pool);
- spin_unlock(&bam_tx_pool_spinlock);
+ spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
rc = sps_transfer_one(bam_tx_pipe, dma_address, len,
pkt, SPS_IOVEC_FLAG_INT | SPS_IOVEC_FLAG_EOT);
if (rc) {
DBG("%s sps_transfer_one failed rc=%d\n", __func__, rc);
- spin_lock(&bam_tx_pool_spinlock);
+ spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
list_del(&pkt->list_node);
- spin_unlock(&bam_tx_pool_spinlock);
+ DBG_INC_TX_SPS_FAILURE_CNT();
+ spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
kfree(pkt);
}
@@ -381,13 +418,14 @@
struct tx_pkt_info *info;
unsigned long event_data;
struct list_head *node;
+ unsigned long flags;
if (in_global_reset)
return;
- spin_lock(&bam_tx_pool_spinlock);
+ spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
node = bam_tx_pool.next;
list_del(node);
- spin_unlock(&bam_tx_pool_spinlock);
+ spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
info = container_of(work, struct tx_pkt_info, work);
if (info->is_cmd) {
kfree(info->skb);
@@ -399,6 +437,9 @@
hdr = (struct bam_mux_hdr *)skb->data;
DBG_INC_WRITE_CNT(skb->data_len);
event_data = (unsigned long)(skb);
+ spin_lock_irqsave(&bam_ch[hdr->ch_id].lock, flags);
+ bam_ch[hdr->ch_id].num_tx_pkts--;
+ spin_unlock_irqrestore(&bam_ch[hdr->ch_id].lock, flags);
if (bam_ch[hdr->ch_id].notify)
bam_ch[hdr->ch_id].notify(
bam_ch[hdr->ch_id].priv, BAM_DMUX_WRITE_DONE,
@@ -430,6 +471,13 @@
pr_err("%s: port not open: %d\n", __func__, bam_ch[id].status);
return -ENODEV;
}
+
+ if (bam_ch[id].use_wm &&
+ (bam_ch[id].num_tx_pkts >= HIGH_WATERMARK)) {
+ spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+ pr_err("%s: watermark exceeded: %d\n", __func__, id);
+ return -EAGAIN;
+ }
spin_unlock_irqrestore(&bam_ch[id].lock, flags);
read_lock(&ul_wakeup_lock);
@@ -489,17 +537,24 @@
pkt->dma_address = dma_address;
pkt->is_cmd = 0;
INIT_WORK(&pkt->work, bam_mux_write_done);
- spin_lock(&bam_tx_pool_spinlock);
+ spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
list_add_tail(&pkt->list_node, &bam_tx_pool);
- spin_unlock(&bam_tx_pool_spinlock);
+ spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
rc = sps_transfer_one(bam_tx_pipe, dma_address, skb->len,
pkt, SPS_IOVEC_FLAG_INT | SPS_IOVEC_FLAG_EOT);
if (rc) {
DBG("%s sps_transfer_one failed rc=%d\n", __func__, rc);
- spin_lock(&bam_tx_pool_spinlock);
+ spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
list_del(&pkt->list_node);
- spin_unlock(&bam_tx_pool_spinlock);
+ DBG_INC_TX_SPS_FAILURE_CNT();
+ spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
kfree(pkt);
+ if (new_skb)
+ dev_kfree_skb_any(new_skb);
+ } else {
+ spin_lock_irqsave(&bam_ch[id].lock, flags);
+ bam_ch[id].num_tx_pkts++;
+ spin_unlock_irqrestore(&bam_ch[id].lock, flags);
}
ul_packet_written = 1;
read_unlock(&ul_wakeup_lock);
@@ -558,6 +613,8 @@
bam_ch[id].notify = notify;
bam_ch[id].priv = priv;
bam_ch[id].status |= BAM_CH_LOCAL_OPEN;
+ bam_ch[id].num_tx_pkts = 0;
+ bam_ch[id].use_wm = 0;
spin_unlock_irqrestore(&bam_ch[id].lock, flags);
read_lock(&ul_wakeup_lock);
@@ -635,6 +692,47 @@
return rc;
}
+int msm_bam_dmux_is_ch_full(uint32_t id)
+{
+ unsigned long flags;
+ int ret;
+
+ if (id >= BAM_DMUX_NUM_CHANNELS)
+ return -EINVAL;
+
+ spin_lock_irqsave(&bam_ch[id].lock, flags);
+ bam_ch[id].use_wm = 1;
+ ret = bam_ch[id].num_tx_pkts >= HIGH_WATERMARK;
+ DBG("%s: ch %d num tx pkts=%d, HWM=%d\n", __func__,
+ id, bam_ch[id].num_tx_pkts, ret);
+ if (!bam_ch_is_local_open(id)) {
+ ret = -ENODEV;
+ pr_err("%s: port not open: %d\n", __func__, bam_ch[id].status);
+ }
+ spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+
+ return ret;
+}
+
+int msm_bam_dmux_is_ch_low(uint32_t id)
+{
+ int ret;
+
+ if (id >= BAM_DMUX_NUM_CHANNELS)
+ return -EINVAL;
+
+ bam_ch[id].use_wm = 1;
+ ret = bam_ch[id].num_tx_pkts <= LOW_WATERMARK;
+ DBG("%s: ch %d num tx pkts=%d, LWM=%d\n", __func__,
+ id, bam_ch[id].num_tx_pkts, ret);
+ if (!bam_ch_is_local_open(id)) {
+ ret = -ENODEV;
+ pr_err("%s: port not open: %d\n", __func__, bam_ch[id].status);
+ }
+
+ return ret;
+}
+
static void rx_timer_work_func(struct work_struct *work)
{
struct sps_iovec iov;
@@ -761,15 +859,7 @@
" not disabled\n", __func__);
break;
}
- rx_register_event.options = 0;
- ret = sps_register_event(bam_rx_pipe,
- &rx_register_event);
- if (ret) {
- pr_err("%s: sps_register_event ret = %d\n",
- __func__, ret);
- break;
- }
- cur_rx_conn.options = SPS_O_AUTO_ENABLE | SPS_O_EOT |
+ cur_rx_conn.options = SPS_O_AUTO_ENABLE |
SPS_O_ACK_TRANSFERS | SPS_O_POLL;
ret = sps_set_config(bam_rx_pipe, &cur_rx_conn);
if (ret) {
@@ -804,6 +894,37 @@
return i;
}
+static int debug_ul_pkt_cnt(char *buf, int max)
+{
+ struct list_head *p;
+ unsigned long flags;
+ int n = 0;
+
+ spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
+ __list_for_each(p, &bam_tx_pool) {
+ ++n;
+ }
+ spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+
+ return scnprintf(buf, max, "Number of UL packets in flight: %d\n", n);
+}
+
+static int debug_stats(char *buf, int max)
+{
+ int i = 0;
+
+ i += scnprintf(buf + i, max - i,
+ "skb copy cnt: %u\n"
+ "skb copy bytes: %u\n"
+ "sps tx failures: %u\n",
+ bam_dmux_write_cpy_cnt,
+ bam_dmux_write_cpy_bytes,
+ bam_dmux_tx_sps_failure_cnt
+ );
+
+ return i;
+}
+
#define DEBUG_BUFMAX 4096
static char debug_buffer[DEBUG_BUFMAX];
@@ -866,33 +987,57 @@
static void ul_timeout(struct work_struct *work)
{
+ unsigned long flags;
+ int ret;
+
if (in_global_reset)
return;
- write_lock(&ul_wakeup_lock);
+ ret = write_trylock_irqsave(&ul_wakeup_lock, flags);
+ if (!ret) { /* failed to grab lock, reschedule and bail */
+ schedule_delayed_work(&ul_timeout_work,
+ msecs_to_jiffies(UL_TIMEOUT_DELAY));
+ return;
+ }
if (ul_packet_written) {
ul_packet_written = 0;
schedule_delayed_work(&ul_timeout_work,
msecs_to_jiffies(UL_TIMEOUT_DELAY));
} else {
+ wait_for_ack = 1;
+ INIT_COMPLETION(ul_wakeup_ack_completion);
smsm_change_state(SMSM_APPS_STATE, SMSM_A2_POWER_CONTROL, 0);
bam_is_connected = 0;
notify_all(BAM_DMUX_UL_DISCONNECTED, (unsigned long)(NULL));
}
- write_unlock(&ul_wakeup_lock);
+ write_unlock_irqrestore(&ul_wakeup_lock, flags);
}
static void ul_wakeup(void)
{
+ int ret;
+
mutex_lock(&wakeup_lock);
if (bam_is_connected) { /* bam got connected before lock grabbed */
mutex_unlock(&wakeup_lock);
return;
}
+ /*
+ * must wait for the previous power down request to have been acked
+ * chances are it already came in and this will just fall through
+ * instead of waiting
+ */
+ if (wait_for_ack) {
+ ret = wait_for_completion_interruptible_timeout(
+ &ul_wakeup_ack_completion, HZ);
+ BUG_ON(ret == 0);
+ }
INIT_COMPLETION(ul_wakeup_ack_completion);
smsm_change_state(SMSM_APPS_STATE, 0, SMSM_A2_POWER_CONTROL);
- wait_for_completion_interruptible_timeout(&ul_wakeup_ack_completion,
- HZ);
- wait_for_completion_interruptible_timeout(&bam_connection_completion,
- HZ);
+ ret = wait_for_completion_interruptible_timeout(
+ &ul_wakeup_ack_completion, HZ);
+ BUG_ON(ret == 0);
+ ret = wait_for_completion_interruptible_timeout(
+ &bam_connection_completion, HZ);
+ BUG_ON(ret == 0);
bam_is_connected = 1;
schedule_delayed_work(&ul_timeout_work,
@@ -953,10 +1098,16 @@
static void vote_dfab(void)
{
+ int rc;
+
+ rc = clk_enable(dfab_clk);
+ if (rc)
+ pr_err("bam_dmux vote for dfab failed rc = %d\n", rc);
}
static void unvote_dfab(void)
{
+ clk_disable(dfab_clk);
}
static int restart_notifier_cb(struct notifier_block *this,
@@ -967,6 +1118,7 @@
struct list_head *node;
struct tx_pkt_info *info;
int temp_remote_status;
+ unsigned long flags;
if (code != SUBSYS_AFTER_SHUTDOWN)
return NOTIFY_DONE;
@@ -975,6 +1127,7 @@
for (i = 0; i < BAM_DMUX_NUM_CHANNELS; ++i) {
temp_remote_status = bam_ch_is_remote_open(i);
bam_ch[i].status &= ~BAM_CH_REMOTE_OPEN;
+ bam_ch[i].num_tx_pkts = 0;
if (bam_ch_is_local_open(i))
bam_ch[i].status |= BAM_CH_IN_RESET;
if (temp_remote_status) {
@@ -984,7 +1137,7 @@
}
}
/*cleanup UL*/
- spin_lock(&bam_tx_pool_spinlock);
+ spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
while (!list_empty(&bam_tx_pool)) {
node = bam_tx_pool.next;
list_del(node);
@@ -1003,7 +1156,7 @@
}
kfree(info);
}
- spin_unlock(&bam_tx_pool_spinlock);
+ spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
smsm_change_state(SMSM_APPS_STATE, SMSM_A2_POWER_CONTROL, 0);
return NOTIFY_DONE;
@@ -1029,8 +1182,11 @@
a2_props.virt_addr = a2_virt_addr;
a2_props.virt_size = A2_PHYS_SIZE;
a2_props.irq = A2_BAM_IRQ;
+ a2_props.options = SPS_BAM_OPT_IRQ_WAKEUP;
a2_props.num_pipes = A2_NUM_PIPES;
a2_props.summing_threshold = A2_SUMMING_THRESHOLD;
+ if (cpu_is_msm9615())
+ a2_props.manage = SPS_BAM_MGR_DEVICE_REMOTE;
/* need to free on tear down */
ret = sps_register_bam_device(&a2_props, &h);
if (ret < 0) {
@@ -1178,14 +1334,19 @@
static void bam_dmux_smsm_cb(void *priv, uint32_t old_state, uint32_t new_state)
{
DBG("%s: smsm activity\n", __func__);
- if (bam_mux_initialized && new_state & SMSM_A2_POWER_CONTROL)
+ if (bam_mux_initialized && new_state & SMSM_A2_POWER_CONTROL) {
+ wake_lock(&bam_wakelock);
reconnect_to_bam();
- else if (bam_mux_initialized && !(new_state & SMSM_A2_POWER_CONTROL))
+ } else if (bam_mux_initialized &&
+ !(new_state & SMSM_A2_POWER_CONTROL)) {
disconnect_to_bam();
- else if (new_state & SMSM_A2_POWER_CONTROL)
+ wake_unlock(&bam_wakelock);
+ } else if (new_state & SMSM_A2_POWER_CONTROL) {
+ wake_lock(&bam_wakelock);
bam_init();
- else
+ } else {
pr_err("%s: unsupported state change\n", __func__);
+ }
}
@@ -1240,6 +1401,7 @@
init_completion(&ul_wakeup_ack_completion);
init_completion(&bam_connection_completion);
INIT_DELAYED_WORK(&ul_timeout_work, ul_timeout);
+ wake_lock_init(&bam_wakelock, WAKE_LOCK_SUSPEND, "bam_dmux_wakelock");
rc = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_A2_POWER_CONTROL,
bam_dmux_smsm_cb, NULL);
@@ -1267,6 +1429,9 @@
return -ENOMEM;
}
+ if (smsm_get_state(SMSM_MODEM_STATE) & SMSM_A2_POWER_CONTROL)
+ bam_dmux_smsm_cb(NULL, 0, smsm_get_state(SMSM_MODEM_STATE));
+
return 0;
}
@@ -1284,8 +1449,11 @@
struct dentry *dent;
dent = debugfs_create_dir("bam_dmux", 0);
- if (!IS_ERR(dent))
+ if (!IS_ERR(dent)) {
debug_create("tbl", 0444, dent, debug_tbl);
+ debug_create("ul_pkt_cnt", 0444, dent, debug_ul_pkt_cnt);
+ debug_create("stats", 0444, dent, debug_stats);
+ }
#endif
subsys_notif_register_notifier("modem", &restart_notifier);
return platform_driver_register(&bam_dmux_driver);
diff --git a/arch/arm/mach-msm/board-apq8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
similarity index 97%
rename from arch/arm/mach-msm/board-apq8064-regulator.c
rename to arch/arm/mach-msm/board-8064-regulator.c
index 8448600..4873258 100644
--- a/arch/arm/mach-msm/board-apq8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -13,7 +13,7 @@
#include <linux/regulator/pm8921-regulator.h>
-#include "board-apq8064.h"
+#include "board-8064.h"
#define VREG_CONSUMERS(_id) \
static struct regulator_consumer_supply vreg_consumers_##_id[]
@@ -93,6 +93,8 @@
};
VREG_CONSUMERS(L25) = {
REGULATOR_SUPPLY("8921_l25", NULL),
+ REGULATOR_SUPPLY("VDDD_CDC_D", "tabla-slim"),
+ REGULATOR_SUPPLY("CDC_VDDA_A_1P2V", "tabla-slim"),
};
VREG_CONSUMERS(L26) = {
REGULATOR_SUPPLY("8921_l26", NULL),
@@ -118,6 +120,10 @@
VREG_CONSUMERS(S4) = {
REGULATOR_SUPPLY("8921_s4", NULL),
REGULATOR_SUPPLY("sdc_vccq", "msm_sdcc.1"),
+ REGULATOR_SUPPLY("VDDIO_CDC", "tabla-slim"),
+ REGULATOR_SUPPLY("CDC_VDD_CP", "tabla-slim"),
+ REGULATOR_SUPPLY("CDC_VDDA_TX", "tabla-slim"),
+ REGULATOR_SUPPLY("CDC_VDDA_RX", "tabla-slim"),
};
VREG_CONSUMERS(S5) = {
REGULATOR_SUPPLY("8921_s5", NULL),
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
new file mode 100644
index 0000000..8a3b958
--- /dev/null
+++ b/arch/arm/mach-msm/board-8064-storage.c
@@ -0,0 +1,257 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/bootmem.h>
+#include <asm/mach-types.h>
+#include <asm/mach/mmc.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+#include "devices.h"
+#include "board-8064.h"
+
+
+/* APQ8064 has 4 SDCC controllers */
+enum sdcc_controllers {
+ SDCC1,
+ SDCC2,
+ SDCC3,
+ SDCC4,
+ MAX_SDCC_CONTROLLER
+};
+
+/* All SDCC controllers require VDD/VCC voltage */
+static struct msm_mmc_reg_data mmc_vdd_reg_data[MAX_SDCC_CONTROLLER] = {
+ /* SDCC1 : eMMC card connected */
+ [SDCC1] = {
+ .name = "sdc_vdd",
+ .high_vol_level = 2950000,
+ .low_vol_level = 2950000,
+ .always_on = 1,
+ .lpm_sup = 1,
+ .lpm_uA = 9000,
+ .hpm_uA = 200000, /* 200mA */
+ },
+ /* SDCC3 : External card slot connected */
+ [SDCC3] = {
+ .name = "sdc_vdd",
+ .high_vol_level = 2950000,
+ .low_vol_level = 2950000,
+ .hpm_uA = 600000, /* 600mA */
+ }
+};
+
+/* Only slots having eMMC card will require VCCQ voltage */
+static struct msm_mmc_reg_data mmc_vccq_reg_data[1] = {
+ /* SDCC1 : eMMC card connected */
+ [SDCC1] = {
+ .name = "sdc_vccq",
+ .always_on = 1,
+ .high_vol_level = 1800000,
+ .low_vol_level = 1800000,
+ .hpm_uA = 200000, /* 200mA */
+ }
+};
+
+/* All SDCC controllers may require voting for VDD PAD voltage */
+static struct msm_mmc_reg_data mmc_vddp_reg_data[MAX_SDCC_CONTROLLER] = {
+ /* SDCC3 : External card slot connected */
+ [SDCC3] = {
+ .name = "sdc_vddp",
+ .high_vol_level = 2950000,
+ .low_vol_level = 1850000,
+ .always_on = 1,
+ .lpm_sup = 1,
+ /* Max. Active current required is 16 mA */
+ .hpm_uA = 16000,
+ /*
+ * Sleep current required is ~300 uA. But min. vote can be
+ * in terms of mA (min. 1 mA). So let's vote for 2 mA
+ * during sleep.
+ */
+ .lpm_uA = 2000,
+ }
+};
+
+static struct msm_mmc_slot_reg_data mmc_slot_vreg_data[MAX_SDCC_CONTROLLER] = {
+ /* SDCC1 : eMMC card connected */
+ [SDCC1] = {
+ .vdd_data = &mmc_vdd_reg_data[SDCC1],
+ .vccq_data = &mmc_vccq_reg_data[SDCC1],
+ },
+ /* SDCC3 : External card slot connected */
+ [SDCC3] = {
+ .vdd_data = &mmc_vdd_reg_data[SDCC3],
+ .vddp_data = &mmc_vddp_reg_data[SDCC3],
+ }
+};
+
+/* SDC1 pad data */
+static struct msm_mmc_pad_drv sdc1_pad_drv_on_cfg[] = {
+ {TLMM_HDRV_SDC1_CLK, GPIO_CFG_16MA},
+ {TLMM_HDRV_SDC1_CMD, GPIO_CFG_10MA},
+ {TLMM_HDRV_SDC1_DATA, GPIO_CFG_10MA}
+};
+
+static struct msm_mmc_pad_drv sdc1_pad_drv_off_cfg[] = {
+ {TLMM_HDRV_SDC1_CLK, GPIO_CFG_2MA},
+ {TLMM_HDRV_SDC1_CMD, GPIO_CFG_2MA},
+ {TLMM_HDRV_SDC1_DATA, GPIO_CFG_2MA}
+};
+
+static struct msm_mmc_pad_pull sdc1_pad_pull_on_cfg[] = {
+ {TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
+ {TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_UP},
+ {TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_UP}
+};
+
+static struct msm_mmc_pad_pull sdc1_pad_pull_off_cfg[] = {
+ {TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
+ {TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_DOWN},
+ {TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_DOWN}
+};
+
+/* SDC3 pad data */
+static struct msm_mmc_pad_drv sdc3_pad_drv_on_cfg[] = {
+ {TLMM_HDRV_SDC3_CLK, GPIO_CFG_8MA},
+ {TLMM_HDRV_SDC3_CMD, GPIO_CFG_8MA},
+ {TLMM_HDRV_SDC3_DATA, GPIO_CFG_8MA}
+};
+
+static struct msm_mmc_pad_drv sdc3_pad_drv_off_cfg[] = {
+ {TLMM_HDRV_SDC3_CLK, GPIO_CFG_2MA},
+ {TLMM_HDRV_SDC3_CMD, GPIO_CFG_2MA},
+ {TLMM_HDRV_SDC3_DATA, GPIO_CFG_2MA}
+};
+
+static struct msm_mmc_pad_pull sdc3_pad_pull_on_cfg[] = {
+ {TLMM_PULL_SDC3_CLK, GPIO_CFG_NO_PULL},
+ {TLMM_PULL_SDC3_CMD, GPIO_CFG_PULL_UP},
+ {TLMM_PULL_SDC3_DATA, GPIO_CFG_PULL_UP}
+};
+
+static struct msm_mmc_pad_pull sdc3_pad_pull_off_cfg[] = {
+ {TLMM_PULL_SDC3_CLK, GPIO_CFG_NO_PULL},
+ {TLMM_PULL_SDC3_CMD, GPIO_CFG_PULL_DOWN},
+ {TLMM_PULL_SDC3_DATA, GPIO_CFG_PULL_DOWN}
+};
+
+static struct msm_mmc_pad_pull_data mmc_pad_pull_data[MAX_SDCC_CONTROLLER] = {
+ [SDCC1] = {
+ .on = sdc1_pad_pull_on_cfg,
+ .off = sdc1_pad_pull_off_cfg,
+ .size = ARRAY_SIZE(sdc1_pad_pull_on_cfg)
+ },
+ [SDCC3] = {
+ .on = sdc3_pad_pull_on_cfg,
+ .off = sdc3_pad_pull_off_cfg,
+ .size = ARRAY_SIZE(sdc3_pad_pull_on_cfg)
+ },
+};
+
+static struct msm_mmc_pad_drv_data mmc_pad_drv_data[MAX_SDCC_CONTROLLER] = {
+ [SDCC1] = {
+ .on = sdc1_pad_drv_on_cfg,
+ .off = sdc1_pad_drv_off_cfg,
+ .size = ARRAY_SIZE(sdc1_pad_drv_on_cfg)
+ },
+ [SDCC3] = {
+ .on = sdc3_pad_drv_on_cfg,
+ .off = sdc3_pad_drv_off_cfg,
+ .size = ARRAY_SIZE(sdc3_pad_drv_on_cfg)
+ },
+};
+
+static struct msm_mmc_pad_data mmc_pad_data[MAX_SDCC_CONTROLLER] = {
+ [SDCC1] = {
+ .pull = &mmc_pad_pull_data[SDCC1],
+ .drv = &mmc_pad_drv_data[SDCC1]
+ },
+ [SDCC3] = {
+ .pull = &mmc_pad_pull_data[SDCC3],
+ .drv = &mmc_pad_drv_data[SDCC3]
+ },
+};
+
+static struct msm_mmc_pin_data mmc_slot_pin_data[MAX_SDCC_CONTROLLER] = {
+ [SDCC1] = {
+ .pad_data = &mmc_pad_data[SDCC1],
+ },
+ [SDCC3] = {
+ .pad_data = &mmc_pad_data[SDCC3],
+ },
+};
+
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+static unsigned int sdc1_sup_clk_rates[] = {
+ 400000, 24000000, 48000000, 96000000
+};
+
+static struct mmc_platform_data sdc1_data = {
+ .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
+#ifdef CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT
+ .mmc_bus_width = MMC_CAP_8_BIT_DATA,
+#else
+ .mmc_bus_width = MMC_CAP_4_BIT_DATA,
+#endif
+ .sup_clk_table = sdc1_sup_clk_rates,
+ .sup_clk_cnt = ARRAY_SIZE(sdc1_sup_clk_rates),
+ .pin_data = &mmc_slot_pin_data[SDCC1],
+ .vreg_data = &mmc_slot_vreg_data[SDCC1],
+};
+static struct mmc_platform_data *apq8064_sdc1_pdata = &sdc1_data;
+#else
+static struct mmc_platform_data *apq8064_sdc1_pdata;
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+static unsigned int sdc3_sup_clk_rates[] = {
+ 400000, 24000000, 48000000, 96000000
+};
+
+static struct mmc_platform_data sdc3_data = {
+ .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
+ .mmc_bus_width = MMC_CAP_4_BIT_DATA,
+ .sup_clk_table = sdc3_sup_clk_rates,
+ .sup_clk_cnt = ARRAY_SIZE(sdc3_sup_clk_rates),
+ .pin_data = &mmc_slot_pin_data[SDCC3],
+ .vreg_data = &mmc_slot_vreg_data[SDCC3],
+};
+static struct mmc_platform_data *apq8064_sdc3_pdata = &sdc3_data;
+#else
+static struct mmc_platform_data *apq8064_sdc3_pdata;
+#endif
+
+void __init apq8064_init_mmc(void)
+{
+ if ((machine_is_apq8064_rumi3()) || machine_is_apq8064_sim()) {
+ if (apq8064_sdc1_pdata) {
+ if (machine_is_apq8064_sim())
+ apq8064_sdc1_pdata->disable_bam = true;
+ apq8064_sdc1_pdata->disable_runtime_pm = true;
+ apq8064_sdc1_pdata->disable_cmd23 = true;
+ }
+ if (apq8064_sdc3_pdata) {
+ if (machine_is_apq8064_sim())
+ apq8064_sdc3_pdata->disable_bam = true;
+ apq8064_sdc3_pdata->disable_runtime_pm = true;
+ apq8064_sdc3_pdata->disable_cmd23 = true;
+ }
+ }
+ apq8064_add_sdcc(1, apq8064_sdc1_pdata);
+ apq8064_add_sdcc(3, apq8064_sdc3_pdata);
+}
diff --git a/arch/arm/mach-msm/board-apq8064.c b/arch/arm/mach-msm/board-8064.c
similarity index 70%
rename from arch/arm/mach-msm/board-apq8064.c
rename to arch/arm/mach-msm/board-8064.c
index b131989..6e2c044 100644
--- a/arch/arm/mach-msm/board-apq8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -16,8 +16,12 @@
#include <linux/irq.h>
#include <linux/i2c.h>
#include <linux/slimbus/slimbus.h>
+#include <linux/mfd/wcd9310/core.h>
+#include <linux/mfd/wcd9310/pdata.h>
#include <linux/msm_ssbi.h>
#include <linux/spi/spi.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_data/qcom_crypto_device.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/hardware/gic.h>
@@ -37,9 +41,10 @@
#include <mach/msm_memtypes.h>
#include <linux/bootmem.h>
#include <asm/setup.h>
+#include <mach/dma.h>
#include "msm_watchdog.h"
-#include "board-apq8064.h"
+#include "board-8064.h"
#define MSM_PMEM_KERNEL_EBI1_SIZE 0x600000
#define MSM_PMEM_ADSP_SIZE 0x3800000
@@ -214,234 +219,157 @@
.pclk_src_name = "dfab_usb_hs_clk",
};
-/* APQ8064 has 4 SDCC controllers */
-enum sdcc_controllers {
- SDCC1,
- SDCC2,
- SDCC3,
- SDCC4,
- MAX_SDCC_CONTROLLER
-};
+#define TABLA_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS + NR_PM8921_IRQS)
-/* All SDCC controllers require VDD/VCC voltage */
-static struct msm_mmc_reg_data mmc_vdd_reg_data[MAX_SDCC_CONTROLLER] = {
- /* SDCC1 : eMMC card connected */
- [SDCC1] = {
- .name = "sdc_vdd",
- .high_vol_level = 2950000,
- .low_vol_level = 2950000,
- .always_on = 1,
- .lpm_sup = 1,
- .lpm_uA = 9000,
- .hpm_uA = 200000, /* 200mA */
+/* Micbias setting is based on 8660 CDP/MTP/FLUID requirement
+ * 4 micbiases are used to power various analog and digital
+ * microphones operating at 1800 mV. Technically, all micbiases
+ * can source from single cfilter since all microphones operate
+ * at the same voltage level. The arrangement below is to make
+ * sure all cfilters are exercised. LDO_H regulator ouput level
+ * does not need to be as high as 2.85V. It is choosen for
+ * microphone sensitivity purpose.
+ */
+static struct tabla_pdata apq8064_tabla_platform_data = {
+ .slimbus_slave_device = {
+ .name = "tabla-slave",
+ .e_addr = {0, 0, 0x10, 0, 0x17, 2},
},
- /* SDCC3 : External card slot connected */
- [SDCC3] = {
- .name = "sdc_vdd",
- .high_vol_level = 2950000,
- .low_vol_level = 2950000,
- .hpm_uA = 600000, /* 600mA */
+ .irq = MSM_GPIO_TO_INT(62),
+ .irq_base = TABLA_INTERRUPT_BASE,
+ .num_irqs = NR_TABLA_IRQS,
+ .reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
+ .micbias = {
+ .ldoh_v = TABLA_LDOH_2P85_V,
+ .cfilt1_mv = 1800,
+ .cfilt2_mv = 1800,
+ .cfilt3_mv = 1800,
+ .bias1_cfilt_sel = TABLA_CFILT1_SEL,
+ .bias2_cfilt_sel = TABLA_CFILT2_SEL,
+ .bias3_cfilt_sel = TABLA_CFILT3_SEL,
+ .bias4_cfilt_sel = TABLA_CFILT3_SEL,
}
};
-/* Only slots having eMMC card will require VCCQ voltage */
-static struct msm_mmc_reg_data mmc_vccq_reg_data[1] = {
- /* SDCC1 : eMMC card connected */
- [SDCC1] = {
- .name = "sdc_vccq",
- .always_on = 1,
- .high_vol_level = 1800000,
- .low_vol_level = 1800000,
- .hpm_uA = 200000, /* 200mA */
- }
-};
-
-/* All SDCC controllers may require voting for VDD PAD voltage */
-static struct msm_mmc_reg_data mmc_vddp_reg_data[MAX_SDCC_CONTROLLER] = {
- /* SDCC3 : External card slot connected */
- [SDCC3] = {
- .name = "sdc_vddp",
- .high_vol_level = 2950000,
- .low_vol_level = 1850000,
- .always_on = 1,
- .lpm_sup = 1,
- /* Max. Active current required is 16 mA */
- .hpm_uA = 16000,
- /*
- * Sleep current required is ~300 uA. But min. vote can be
- * in terms of mA (min. 1 mA). So let's vote for 2 mA
- * during sleep.
- */
- .lpm_uA = 2000,
- }
-};
-
-static struct msm_mmc_slot_reg_data mmc_slot_vreg_data[MAX_SDCC_CONTROLLER] = {
- /* SDCC1 : eMMC card connected */
- [SDCC1] = {
- .vdd_data = &mmc_vdd_reg_data[SDCC1],
- .vccq_data = &mmc_vccq_reg_data[SDCC1],
- },
- /* SDCC3 : External card slot connected */
- [SDCC3] = {
- .vdd_data = &mmc_vdd_reg_data[SDCC3],
- .vddp_data = &mmc_vddp_reg_data[SDCC3],
- }
-};
-
-/* SDC1 pad data */
-static struct msm_mmc_pad_drv sdc1_pad_drv_on_cfg[] = {
- {TLMM_HDRV_SDC1_CLK, GPIO_CFG_16MA},
- {TLMM_HDRV_SDC1_CMD, GPIO_CFG_10MA},
- {TLMM_HDRV_SDC1_DATA, GPIO_CFG_10MA}
-};
-
-static struct msm_mmc_pad_drv sdc1_pad_drv_off_cfg[] = {
- {TLMM_HDRV_SDC1_CLK, GPIO_CFG_2MA},
- {TLMM_HDRV_SDC1_CMD, GPIO_CFG_2MA},
- {TLMM_HDRV_SDC1_DATA, GPIO_CFG_2MA}
-};
-
-static struct msm_mmc_pad_pull sdc1_pad_pull_on_cfg[] = {
- {TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
- {TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_UP},
- {TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_UP}
-};
-
-static struct msm_mmc_pad_pull sdc1_pad_pull_off_cfg[] = {
- {TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
- {TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_DOWN},
- {TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_DOWN}
-};
-
-/* SDC3 pad data */
-static struct msm_mmc_pad_drv sdc3_pad_drv_on_cfg[] = {
- {TLMM_HDRV_SDC3_CLK, GPIO_CFG_8MA},
- {TLMM_HDRV_SDC3_CMD, GPIO_CFG_8MA},
- {TLMM_HDRV_SDC3_DATA, GPIO_CFG_8MA}
-};
-
-static struct msm_mmc_pad_drv sdc3_pad_drv_off_cfg[] = {
- {TLMM_HDRV_SDC3_CLK, GPIO_CFG_2MA},
- {TLMM_HDRV_SDC3_CMD, GPIO_CFG_2MA},
- {TLMM_HDRV_SDC3_DATA, GPIO_CFG_2MA}
-};
-
-static struct msm_mmc_pad_pull sdc3_pad_pull_on_cfg[] = {
- {TLMM_PULL_SDC3_CLK, GPIO_CFG_NO_PULL},
- {TLMM_PULL_SDC3_CMD, GPIO_CFG_PULL_UP},
- {TLMM_PULL_SDC3_DATA, GPIO_CFG_PULL_UP}
-};
-
-static struct msm_mmc_pad_pull sdc3_pad_pull_off_cfg[] = {
- {TLMM_PULL_SDC3_CLK, GPIO_CFG_NO_PULL},
- {TLMM_PULL_SDC3_CMD, GPIO_CFG_PULL_DOWN},
- {TLMM_PULL_SDC3_DATA, GPIO_CFG_PULL_DOWN}
-};
-
-static struct msm_mmc_pad_pull_data mmc_pad_pull_data[MAX_SDCC_CONTROLLER] = {
- [SDCC1] = {
- .on = sdc1_pad_pull_on_cfg,
- .off = sdc1_pad_pull_off_cfg,
- .size = ARRAY_SIZE(sdc1_pad_pull_on_cfg)
- },
- [SDCC3] = {
- .on = sdc3_pad_pull_on_cfg,
- .off = sdc3_pad_pull_off_cfg,
- .size = ARRAY_SIZE(sdc3_pad_pull_on_cfg)
+static struct slim_device apq8064_slim_tabla = {
+ .name = "tabla-slim",
+ .e_addr = {0, 1, 0x10, 0, 0x17, 2},
+ .dev = {
+ .platform_data = &apq8064_tabla_platform_data,
},
};
-static struct msm_mmc_pad_drv_data mmc_pad_drv_data[MAX_SDCC_CONTROLLER] = {
- [SDCC1] = {
- .on = sdc1_pad_drv_on_cfg,
- .off = sdc1_pad_drv_off_cfg,
- .size = ARRAY_SIZE(sdc1_pad_drv_on_cfg)
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+ defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE) || \
+ defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+ defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+#define QCE_SIZE 0x10000
+#define QCE_0_BASE 0x11000000
+
+#define QCE_HW_KEY_SUPPORT 0
+#define QCE_SHA_HMAC_SUPPORT 1
+#define QCE_SHARE_CE_RESOURCE 3
+#define QCE_CE_SHARED 0
+
+static struct resource qcrypto_resources[] = {
+ [0] = {
+ .start = QCE_0_BASE,
+ .end = QCE_0_BASE + QCE_SIZE - 1,
+ .flags = IORESOURCE_MEM,
},
- [SDCC3] = {
- .on = sdc3_pad_drv_on_cfg,
- .off = sdc3_pad_drv_off_cfg,
- .size = ARRAY_SIZE(sdc3_pad_drv_on_cfg)
+ [1] = {
+ .name = "crypto_channels",
+ .start = DMOV8064_CE_IN_CHAN,
+ .end = DMOV8064_CE_OUT_CHAN,
+ .flags = IORESOURCE_DMA,
+ },
+ [2] = {
+ .name = "crypto_crci_in",
+ .start = DMOV8064_CE_IN_CRCI,
+ .end = DMOV8064_CE_IN_CRCI,
+ .flags = IORESOURCE_DMA,
+ },
+ [3] = {
+ .name = "crypto_crci_out",
+ .start = DMOV8064_CE_OUT_CRCI,
+ .end = DMOV8064_CE_OUT_CRCI,
+ .flags = IORESOURCE_DMA,
},
};
-static struct msm_mmc_pad_data mmc_pad_data[MAX_SDCC_CONTROLLER] = {
- [SDCC1] = {
- .pull = &mmc_pad_pull_data[SDCC1],
- .drv = &mmc_pad_drv_data[SDCC1]
+static struct resource qcedev_resources[] = {
+ [0] = {
+ .start = QCE_0_BASE,
+ .end = QCE_0_BASE + QCE_SIZE - 1,
+ .flags = IORESOURCE_MEM,
},
- [SDCC3] = {
- .pull = &mmc_pad_pull_data[SDCC3],
- .drv = &mmc_pad_drv_data[SDCC3]
+ [1] = {
+ .name = "crypto_channels",
+ .start = DMOV8064_CE_IN_CHAN,
+ .end = DMOV8064_CE_OUT_CHAN,
+ .flags = IORESOURCE_DMA,
+ },
+ [2] = {
+ .name = "crypto_crci_in",
+ .start = DMOV8064_CE_IN_CRCI,
+ .end = DMOV8064_CE_IN_CRCI,
+ .flags = IORESOURCE_DMA,
+ },
+ [3] = {
+ .name = "crypto_crci_out",
+ .start = DMOV8064_CE_OUT_CRCI,
+ .end = DMOV8064_CE_OUT_CRCI,
+ .flags = IORESOURCE_DMA,
},
};
-static struct msm_mmc_pin_data mmc_slot_pin_data[MAX_SDCC_CONTROLLER] = {
- [SDCC1] = {
- .pad_data = &mmc_pad_data[SDCC1],
- },
- [SDCC3] = {
- .pad_data = &mmc_pad_data[SDCC3],
- },
-};
-
-#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
-static unsigned int sdc1_sup_clk_rates[] = {
- 400000, 24000000, 48000000, 96000000
-};
-
-static struct mmc_platform_data sdc1_data = {
- .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
-#ifdef CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT
- .mmc_bus_width = MMC_CAP_8_BIT_DATA,
-#else
- .mmc_bus_width = MMC_CAP_4_BIT_DATA,
-#endif
- .sup_clk_table = sdc1_sup_clk_rates,
- .sup_clk_cnt = ARRAY_SIZE(sdc1_sup_clk_rates),
- .pin_data = &mmc_slot_pin_data[SDCC1],
- .vreg_data = &mmc_slot_vreg_data[SDCC1],
-};
-static struct mmc_platform_data *apq8064_sdc1_pdata = &sdc1_data;
-#else
-static struct mmc_platform_data *apq8064_sdc1_pdata;
#endif
-#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
-static unsigned int sdc3_sup_clk_rates[] = {
- 400000, 24000000, 48000000, 96000000
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+ defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+
+static struct msm_ce_hw_support qcrypto_ce_hw_suppport = {
+ .ce_shared = QCE_CE_SHARED,
+ .shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+ .hw_key_support = QCE_HW_KEY_SUPPORT,
+ .sha_hmac = QCE_SHA_HMAC_SUPPORT,
};
-static struct mmc_platform_data sdc3_data = {
- .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
- .mmc_bus_width = MMC_CAP_4_BIT_DATA,
- .sup_clk_table = sdc3_sup_clk_rates,
- .sup_clk_cnt = ARRAY_SIZE(sdc3_sup_clk_rates),
- .pin_data = &mmc_slot_pin_data[SDCC3],
- .vreg_data = &mmc_slot_vreg_data[SDCC3],
+static struct platform_device qcrypto_device = {
+ .name = "qcrypto",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(qcrypto_resources),
+ .resource = qcrypto_resources,
+ .dev = {
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &qcrypto_ce_hw_suppport,
+ },
};
-static struct mmc_platform_data *apq8064_sdc3_pdata = &sdc3_data;
-#else
-static struct mmc_platform_data *apq8064_sdc3_pdata;
#endif
-static void __init apq8064_init_mmc(void)
-{
- if ((machine_is_apq8064_rumi3()) || machine_is_apq8064_sim()) {
- if (apq8064_sdc1_pdata) {
- apq8064_sdc1_pdata->disable_bam = true;
- apq8064_sdc1_pdata->disable_runtime_pm = true;
- apq8064_sdc1_pdata->disable_cmd23 = true;
- }
- if (apq8064_sdc3_pdata) {
- apq8064_sdc3_pdata->disable_bam = true;
- apq8064_sdc3_pdata->disable_runtime_pm = true;
- apq8064_sdc3_pdata->disable_cmd23 = true;
- }
- }
- apq8064_add_sdcc(1, apq8064_sdc1_pdata);
- apq8064_add_sdcc(3, apq8064_sdc3_pdata);
-}
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+ defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+static struct msm_ce_hw_support qcedev_ce_hw_suppport = {
+ .ce_shared = QCE_CE_SHARED,
+ .shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+ .hw_key_support = QCE_HW_KEY_SUPPORT,
+ .sha_hmac = QCE_SHA_HMAC_SUPPORT,
+};
+
+static struct platform_device qcedev_device = {
+ .name = "qce",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(qcedev_resources),
+ .resource = qcedev_resources,
+ .dev = {
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &qcedev_ce_hw_suppport,
+ },
+};
+#endif
+
#define MSM_SHARED_RAM_PHYS 0x80000000
static void __init apq8064_map_io(void)
@@ -526,6 +454,40 @@
&msm8064_device_saw_regulator_core1,
&msm8064_device_saw_regulator_core2,
&msm8064_device_saw_regulator_core3,
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+ defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+ &qcrypto_device,
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+ defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+ &qcedev_device,
+#endif
+
+#ifdef CONFIG_HW_RANDOM_MSM
+ &apq8064_device_rng,
+#endif
+ &msm_pcm,
+ &msm_pcm_routing,
+ &msm_cpudai0,
+ &msm_cpudai1,
+ &msm_cpudai_hdmi_rx,
+ &msm_cpudai_bt_rx,
+ &msm_cpudai_bt_tx,
+ &msm_cpudai_fm_rx,
+ &msm_cpudai_fm_tx,
+ &msm_cpu_fe,
+ &msm_stub_codec,
+ &msm_voice,
+ &msm_voip,
+ &msm_lpa_pcm,
+ &msm_cpudai_afe_01_rx,
+ &msm_cpudai_afe_01_tx,
+ &msm_cpudai_afe_02_rx,
+ &msm_cpudai_afe_02_tx,
+ &msm_pcm_afe,
+ &msm_cpudai_auxpcm_rx,
+ &msm_cpudai_auxpcm_tx,
};
static struct platform_device *sim_devices[] __initdata = {
@@ -535,6 +497,11 @@
static struct platform_device *rumi3_devices[] __initdata = {
&apq8064_device_uart_gsbi1,
+ &msm_device_sps_apq8064,
+ &msm_cpudai_bt_rx,
+ &msm_cpudai_bt_tx,
+ &msm_cpudai_fm_rx,
+ &msm_cpudai_fm_tx,
};
static struct msm_spi_platform_data apq8064_qup_spi_gsbi5_pdata = {
@@ -679,7 +646,11 @@
};
static struct slim_boardinfo apq8064_slim_devices[] = {
- /* Add slimbus slaves as needed */
+ {
+ .bus_num = 1,
+ .slim_slave = &apq8064_slim_tabla,
+ },
+ /* add more slimbus slaves as needed */
};
static struct msm_i2c_platform_data apq8064_i2c_qup_gsbi4_pdata = {
@@ -687,6 +658,52 @@
.src_clk_rate = 24000000,
};
+
+static struct gpiomux_setting audio_auxpcm[] = {
+ /* Suspended state */
+ {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ },
+ /* Active state */
+ {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ },
+};
+static struct msm_gpiomux_config apq8064_audio_auxpcm_configs[] __initdata = {
+ {
+ .gpio = 43,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+ [GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+ },
+ },
+ {
+ .gpio = 44,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+ [GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+ },
+ },
+ {
+ .gpio = 45,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+ [GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+ },
+ },
+ {
+ .gpio = 46,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+ [GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+ },
+ },
+};
+
static void __init apq8064_i2c_init(void)
{
apq8064_device_qup_i2c_gsbi4.dev.platform_data =
@@ -707,6 +724,8 @@
msm_gpiomux_install(apq8064_gsbi_configs,
ARRAY_SIZE(apq8064_gsbi_configs));
+ msm_gpiomux_install(apq8064_audio_auxpcm_configs,
+ ARRAY_SIZE(apq8064_audio_auxpcm_configs));
return 0;
}
diff --git a/arch/arm/mach-msm/board-apq8064.h b/arch/arm/mach-msm/board-8064.h
similarity index 98%
rename from arch/arm/mach-msm/board-apq8064.h
rename to arch/arm/mach-msm/board-8064.h
index 0928a58..d9da00a 100644
--- a/arch/arm/mach-msm/board-apq8064.h
+++ b/arch/arm/mach-msm/board-8064.h
@@ -41,4 +41,5 @@
int __init apq8064_add_sdcc(unsigned int controller,
struct mmc_platform_data *plat);
+void apq8064_init_mmc(void);
#endif
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
new file mode 100644
index 0000000..9161fbf
--- /dev/null
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -0,0 +1,470 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/i2c.h>
+#include <linux/i2c/sx150x.h>
+#include <asm/mach-types.h>
+#include <mach/board.h>
+#include <mach/msm_bus_board.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+#include "devices.h"
+#include "board-8930.h"
+
+#if (defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)) && \
+ defined(CONFIG_I2C)
+
+static struct i2c_board_info cam_expander_i2c_info[] = {
+ {
+ I2C_BOARD_INFO("sx1508q", 0x22),
+ .platform_data = &msm8930_sx150x_data[SX150X_CAM]
+ },
+};
+
+static struct msm_cam_expander_info cam_expander_info[] = {
+ {
+ cam_expander_i2c_info,
+ MSM_8930_GSBI4_QUP_I2C_BUS_ID,
+ },
+};
+#endif
+
+static struct gpiomux_setting cam_settings[] = {
+ {
+ .func = GPIOMUX_FUNC_GPIO, /*suspend*/
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_1, /*active 1*/
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_GPIO, /*active 2*/
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_1, /*active 3*/
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_5, /*active 4*/
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_6, /*active 5*/
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_2, /*active 6*/
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_3, /*active 7*/
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_GPIO, /*i2c suspend*/
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_KEEPER,
+ },
+
+};
+
+
+static struct msm_gpiomux_config msm8960_cam_common_configs[] = {
+ {
+ .gpio = 2,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[2],
+ [GPIOMUX_SUSPENDED] = &cam_settings[0],
+ },
+ },
+ {
+ .gpio = 3,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[1],
+ [GPIOMUX_SUSPENDED] = &cam_settings[0],
+ },
+ },
+ {
+ .gpio = 4,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[1],
+ [GPIOMUX_SUSPENDED] = &cam_settings[0],
+ },
+ },
+ {
+ .gpio = 5,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[1],
+ [GPIOMUX_SUSPENDED] = &cam_settings[0],
+ },
+ },
+ {
+ .gpio = 76,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[2],
+ [GPIOMUX_SUSPENDED] = &cam_settings[0],
+ },
+ },
+ {
+ .gpio = 107,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[2],
+ [GPIOMUX_SUSPENDED] = &cam_settings[0],
+ },
+ },
+};
+
+static struct msm_gpiomux_config msm8960_cam_2d_configs[] = {
+ {
+ .gpio = 18,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &cam_settings[8],
+ },
+ },
+ {
+ .gpio = 19,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &cam_settings[8],
+ },
+ },
+ {
+ .gpio = 20,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &cam_settings[8],
+ },
+ },
+ {
+ .gpio = 21,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &cam_settings[8],
+ },
+ },
+};
+
+#ifdef CONFIG_MSM_CAMERA
+
+static uint16_t msm_cam_gpio_2d_tbl[] = {
+ 5, /*CAMIF_MCLK*/
+ 20, /*CAMIF_I2C_DATA*/
+ 21, /*CAMIF_I2C_CLK*/
+};
+
+static struct msm_camera_gpio_conf gpio_conf = {
+ .cam_gpiomux_conf_tbl = msm8960_cam_2d_configs,
+ .cam_gpiomux_conf_tbl_size = ARRAY_SIZE(msm8960_cam_2d_configs),
+ .cam_gpio_tbl = msm_cam_gpio_2d_tbl,
+ .cam_gpio_tbl_size = ARRAY_SIZE(msm_cam_gpio_2d_tbl),
+};
+
+#define VFE_CAMIF_TIMER1_GPIO 2
+#define VFE_CAMIF_TIMER2_GPIO 3
+#define VFE_CAMIF_TIMER3_GPIO_INT 4
+static struct msm_camera_sensor_strobe_flash_data strobe_flash_xenon = {
+ .flash_trigger = VFE_CAMIF_TIMER2_GPIO,
+ .flash_charge = VFE_CAMIF_TIMER1_GPIO,
+ .flash_charge_done = VFE_CAMIF_TIMER3_GPIO_INT,
+ .flash_recharge_duration = 50000,
+ .irq = MSM_GPIO_TO_INT(VFE_CAMIF_TIMER3_GPIO_INT),
+};
+
+#ifdef CONFIG_MSM_CAMERA_FLASH
+static struct msm_camera_sensor_flash_src msm_flash_src = {
+ .flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
+ ._fsrc.ext_driver_src.led_en = GPIO_CAM_GP_LED_EN1,
+ ._fsrc.ext_driver_src.led_flash_en = GPIO_CAM_GP_LED_EN2,
+#if defined(CONFIG_I2C) && (defined(CONFIG_GPIO_SX150X) || \
+ defined(CONFIG_GPIO_SX150X_MODULE))
+ ._fsrc.ext_driver_src.expander_info = cam_expander_info,
+#endif
+};
+#endif
+
+static struct msm_bus_vectors cam_init_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+static struct msm_bus_vectors cam_preview_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 27648000,
+ .ib = 110592000,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+static struct msm_bus_vectors cam_video_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 140451840,
+ .ib = 561807360,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 206807040,
+ .ib = 488816640,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+static struct msm_bus_vectors cam_snapshot_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 274423680,
+ .ib = 1097694720,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 540000000,
+ .ib = 1350000000,
+ },
+};
+
+static struct msm_bus_vectors cam_zsl_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 302071680,
+ .ib = 1208286720,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 540000000,
+ .ib = 1350000000,
+ },
+};
+
+static struct msm_bus_paths cam_bus_client_config[] = {
+ {
+ ARRAY_SIZE(cam_init_vectors),
+ cam_init_vectors,
+ },
+ {
+ ARRAY_SIZE(cam_preview_vectors),
+ cam_preview_vectors,
+ },
+ {
+ ARRAY_SIZE(cam_video_vectors),
+ cam_video_vectors,
+ },
+ {
+ ARRAY_SIZE(cam_snapshot_vectors),
+ cam_snapshot_vectors,
+ },
+ {
+ ARRAY_SIZE(cam_zsl_vectors),
+ cam_zsl_vectors,
+ },
+};
+
+static struct msm_bus_scale_pdata cam_bus_client_pdata = {
+ cam_bus_client_config,
+ ARRAY_SIZE(cam_bus_client_config),
+ .name = "msm_camera",
+};
+
+static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
+ {
+ .ioclk.mclk_clk_rate = 24000000,
+ .ioclk.vfe_clk_rate = 228570000,
+ .csid_core = 0,
+ .cam_bus_scale_table = &cam_bus_client_pdata,
+ },
+ {
+ .ioclk.mclk_clk_rate = 24000000,
+ .ioclk.vfe_clk_rate = 228570000,
+ .csid_core = 1,
+ .cam_bus_scale_table = &cam_bus_client_pdata,
+ },
+};
+
+#ifdef CONFIG_IMX074_ACT
+static struct i2c_board_info imx074_actuator_i2c_info = {
+ I2C_BOARD_INFO("imx074_act", 0x11),
+};
+
+static struct msm_actuator_info imx074_actuator_info = {
+ .board_info = &imx074_actuator_i2c_info,
+ .bus_id = MSM_8930_GSBI4_QUP_I2C_BUS_ID,
+ .vcm_pwd = 0,
+ .vcm_enable = 1,
+};
+#endif
+
+#ifdef CONFIG_IMX074
+static struct msm_camera_sensor_flash_data flash_imx074 = {
+ .flash_type = MSM_CAMERA_FLASH_LED,
+#ifdef CONFIG_MSM_CAMERA_FLASH
+ .flash_src = &msm_flash_src
+#endif
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_imx074 = {
+ .mount_angle = 90,
+ .sensor_reset = 107,
+ .sensor_pwd = 85,
+ .vcm_pwd = 0,
+ .vcm_enable = 1,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_imx074_data = {
+ .sensor_name = "imx074",
+ .pdata = &msm_camera_csi_device_data[0],
+ .flash_data = &flash_imx074,
+ .strobe_flash_data = &strobe_flash_xenon,
+ .sensor_platform_info = &sensor_board_info_imx074,
+ .gpio_conf = &gpio_conf,
+ .csi_if = 1,
+ .camera_type = BACK_CAMERA_2D,
+#ifdef CONFIG_IMX074_ACT
+ .actuator_info = &imx074_actuator_info
+#endif
+};
+
+static struct platform_device msm8960_camera_sensor_imx074 = {
+ .name = "msm_camera_imx074",
+ .dev = {
+ .platform_data = &msm_camera_sensor_imx074_data,
+ },
+};
+#endif
+#ifdef CONFIG_OV2720
+static struct msm_camera_sensor_flash_data flash_ov2720 = {
+ .flash_type = MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_ov2720 = {
+ .mount_angle = 0,
+ .sensor_reset = 76,
+ .sensor_pwd = 85,
+ .vcm_pwd = 0,
+ .vcm_enable = 1,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov2720_data = {
+ .sensor_name = "ov2720",
+ .pdata = &msm_camera_csi_device_data[1],
+ .flash_data = &flash_ov2720,
+ .sensor_platform_info = &sensor_board_info_ov2720,
+ .gpio_conf = &gpio_conf,
+ .csi_if = 1,
+ .camera_type = FRONT_CAMERA_2D,
+};
+
+static struct platform_device msm8960_camera_sensor_ov2720 = {
+ .name = "msm_camera_ov2720",
+ .dev = {
+ .platform_data = &msm_camera_sensor_ov2720_data,
+ },
+};
+#endif
+
+void __init msm8930_init_cam(void)
+{
+ int i;
+ struct platform_device *cam_dev[] = {
+ &msm8960_camera_sensor_imx074,
+ &msm8960_camera_sensor_ov2720,
+ };
+
+ msm_gpiomux_install(msm8960_cam_common_configs,
+ ARRAY_SIZE(msm8960_cam_common_configs));
+
+ for (i = 0; i < ARRAY_SIZE(cam_dev); i++) {
+ struct msm_camera_sensor_info *s_info;
+ s_info = cam_dev[i]->dev.platform_data;
+ msm_get_cam_resources(s_info);
+ platform_device_register(cam_dev[i]);
+ }
+
+ platform_device_register(&msm8960_device_csiphy0);
+ platform_device_register(&msm8960_device_csiphy1);
+ platform_device_register(&msm8960_device_csid0);
+ platform_device_register(&msm8960_device_csid1);
+ platform_device_register(&msm8960_device_ispif);
+ platform_device_register(&msm8960_device_vfe);
+ platform_device_register(&msm8960_device_vpe);
+}
+#endif
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
new file mode 100644
index 0000000..ca21fac
--- /dev/null
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -0,0 +1,793 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/bootmem.h>
+#include <asm/mach-types.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+#include <mach/socinfo.h>
+#include "devices.h"
+#include "board-8930.h"
+
+#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
+#define MSM_FB_PRIM_BUF_SIZE (1376 * 768 * 4 * 3) /* 4 bpp x 3 pages */
+#else
+#define MSM_FB_PRIM_BUF_SIZE (1376 * 768 * 4 * 2) /* 4 bpp x 2 pages */
+#endif
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+#define MSM_FB_EXT_BUF_SIZE (1920 * 1088 * 2 * 1) /* 2 bpp x 1 page */
+#elif defined(CONFIG_FB_MSM_TVOUT)
+#define MSM_FB_EXT_BUF_SIZE (720 * 576 * 2 * 2) /* 2 bpp x 2 pages */
+#else
+#define MSM_FB_EXT_BUF_SIZE 0
+#endif
+
+#ifdef CONFIG_FB_MSM_OVERLAY_WRITEBACK
+/* width x height x 3 bpp x 2 frame buffer */
+#define MSM_FB_WRITEBACK_SIZE (1376 * 768 * 3 * 2)
+#define MSM_FB_WRITEBACK_OFFSET \
+ (MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE)
+#else
+#define MSM_FB_WRITEBACK_SIZE 0
+#define MSM_FB_WRITEBACK_OFFSET 0
+#endif
+
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+/* 4 bpp x 2 page HDMI case */
+#define MSM_FB_SIZE roundup((1920 * 1088 * 4 * 2), 4096)
+#else
+/* Note: must be multiple of 4096 */
+#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE + \
+ MSM_FB_WRITEBACK_SIZE, 4096)
+#endif
+
+#define MDP_VSYNC_GPIO 0
+
+#define PANEL_NAME_MAX_LEN 30
+#define MIPI_CMD_NOVATEK_QHD_PANEL_NAME "mipi_cmd_novatek_qhd"
+#define MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME "mipi_video_novatek_qhd"
+#define MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME "mipi_video_toshiba_wsvga"
+#define MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME "mipi_video_chimei_wxga"
+#define MIPI_VIDEO_SIMULATOR_VGA_PANEL_NAME "mipi_video_simulator_vga"
+#define MIPI_CMD_RENESAS_FWVGA_PANEL_NAME "mipi_cmd_renesas_fwvga"
+#define HDMI_PANEL_NAME "hdmi_msm"
+#define TVOUT_PANEL_NAME "tvout_msm"
+
+static int writeback_offset(void)
+{
+ return MSM_FB_WRITEBACK_OFFSET;
+}
+
+static struct resource msm_fb_resources[] = {
+ {
+ .flags = IORESOURCE_DMA,
+ }
+};
+
+static int msm_fb_detect_panel(const char *name)
+{
+ if (!strncmp(name, MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME,
+ strnlen(MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME,
+ PANEL_NAME_MAX_LEN)))
+ return 0;
+
+#ifndef CONFIG_FB_MSM_MIPI_PANEL_DETECT
+ if (!strncmp(name, MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME,
+ strnlen(MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME,
+ PANEL_NAME_MAX_LEN)))
+ return 0;
+
+ if (!strncmp(name, MIPI_CMD_NOVATEK_QHD_PANEL_NAME,
+ strnlen(MIPI_CMD_NOVATEK_QHD_PANEL_NAME,
+ PANEL_NAME_MAX_LEN)))
+ return 0;
+
+ if (!strncmp(name, MIPI_VIDEO_SIMULATOR_VGA_PANEL_NAME,
+ strnlen(MIPI_VIDEO_SIMULATOR_VGA_PANEL_NAME,
+ PANEL_NAME_MAX_LEN)))
+ return 0;
+
+ if (!strncmp(name, MIPI_CMD_RENESAS_FWVGA_PANEL_NAME,
+ strnlen(MIPI_CMD_RENESAS_FWVGA_PANEL_NAME,
+ PANEL_NAME_MAX_LEN)))
+ return 0;
+#endif
+
+ if (!strncmp(name, HDMI_PANEL_NAME,
+ strnlen(HDMI_PANEL_NAME,
+ PANEL_NAME_MAX_LEN)))
+ return 0;
+
+ if (!strncmp(name, TVOUT_PANEL_NAME,
+ strnlen(TVOUT_PANEL_NAME,
+ PANEL_NAME_MAX_LEN)))
+ return 0;
+
+ pr_warning("%s: not supported '%s'", __func__, name);
+ return -ENODEV;
+}
+
+static struct msm_fb_platform_data msm_fb_pdata = {
+ .detect_client = msm_fb_detect_panel,
+};
+
+static struct platform_device msm_fb_device = {
+ .name = "msm_fb",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(msm_fb_resources),
+ .resource = msm_fb_resources,
+ .dev.platform_data = &msm_fb_pdata,
+};
+
+static bool dsi_power_on;
+
+static int mipi_dsi_cdp_panel_power(int on)
+{
+ static struct regulator *reg_l8, *reg_l23, *reg_l2;
+ static int gpio43;
+ int rc;
+
+ pr_info("%s: state : %d\n", __func__, on);
+
+ if (!dsi_power_on) {
+
+ reg_l8 = regulator_get(&msm_mipi_dsi1_device.dev,
+ "dsi_vdc");
+ if (IS_ERR(reg_l8)) {
+ pr_err("could not get 8921_l8, rc = %ld\n",
+ PTR_ERR(reg_l8));
+ return -ENODEV;
+ }
+ reg_l23 = regulator_get(&msm_mipi_dsi1_device.dev,
+ "dsi_vddio");
+ if (IS_ERR(reg_l23)) {
+ pr_err("could not get 8921_l23, rc = %ld\n",
+ PTR_ERR(reg_l23));
+ return -ENODEV;
+ }
+ reg_l2 = regulator_get(&msm_mipi_dsi1_device.dev,
+ "dsi_vdda");
+ if (IS_ERR(reg_l2)) {
+ pr_err("could not get 8921_l2, rc = %ld\n",
+ PTR_ERR(reg_l2));
+ return -ENODEV;
+ }
+ rc = regulator_set_voltage(reg_l8, 2800000, 3000000);
+ if (rc) {
+ pr_err("set_voltage l8 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ rc = regulator_set_voltage(reg_l23, 1800000, 1800000);
+ if (rc) {
+ pr_err("set_voltage l23 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ rc = regulator_set_voltage(reg_l2, 1200000, 1200000);
+ if (rc) {
+ pr_err("set_voltage l2 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ gpio43 = PM8921_GPIO_PM_TO_SYS(43);
+ rc = gpio_request(gpio43, "disp_rst_n");
+ if (rc) {
+ pr_err("request gpio 43 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ dsi_power_on = true;
+ }
+ if (on) {
+ rc = regulator_set_optimum_mode(reg_l8, 100000);
+ if (rc < 0) {
+ pr_err("set_optimum_mode l8 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ rc = regulator_set_optimum_mode(reg_l23, 100000);
+ if (rc < 0) {
+ pr_err("set_optimum_mode l23 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ rc = regulator_set_optimum_mode(reg_l2, 100000);
+ if (rc < 0) {
+ pr_err("set_optimum_mode l2 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ rc = regulator_enable(reg_l8);
+ if (rc) {
+ pr_err("enable l8 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ rc = regulator_enable(reg_l23);
+ if (rc) {
+ pr_err("enable l8 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ rc = regulator_enable(reg_l2);
+ if (rc) {
+ pr_err("enable l2 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ gpio_set_value_cansleep(gpio43, 1);
+ } else {
+ rc = regulator_disable(reg_l2);
+ if (rc) {
+ pr_err("disable reg_l2 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ rc = regulator_disable(reg_l8);
+ if (rc) {
+ pr_err("disable reg_l8 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ rc = regulator_disable(reg_l23);
+ if (rc) {
+ pr_err("disable reg_l23 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ rc = regulator_set_optimum_mode(reg_l8, 100);
+ if (rc < 0) {
+ pr_err("set_optimum_mode l8 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ rc = regulator_set_optimum_mode(reg_l23, 100);
+ if (rc < 0) {
+ pr_err("set_optimum_mode l23 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ rc = regulator_set_optimum_mode(reg_l2, 100);
+ if (rc < 0) {
+ pr_err("set_optimum_mode l2 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ gpio_set_value_cansleep(gpio43, 0);
+ }
+ return 0;
+}
+
+static int mipi_dsi_panel_power(int on)
+{
+ pr_info("%s: on=%d\n", __func__, on);
+
+ return mipi_dsi_cdp_panel_power(on);
+}
+
+static struct mipi_dsi_platform_data mipi_dsi_pdata = {
+ .vsync_gpio = MDP_VSYNC_GPIO,
+ .dsi_power_save = mipi_dsi_panel_power,
+};
+
+#ifdef CONFIG_MSM_BUS_SCALING
+
+static struct msm_bus_vectors mdp_init_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_MDP_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+static struct msm_bus_vectors hdmi_as_primary_vectors[] = {
+ /* If HDMI is used as primary */
+ {
+ .src = MSM_BUS_MASTER_MDP_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2000000000,
+ .ib = 2000000000,
+ },
+};
+static struct msm_bus_paths mdp_bus_scale_usecases[] = {
+ {
+ ARRAY_SIZE(mdp_init_vectors),
+ mdp_init_vectors,
+ },
+ {
+ ARRAY_SIZE(hdmi_as_primary_vectors),
+ hdmi_as_primary_vectors,
+ },
+ {
+ ARRAY_SIZE(hdmi_as_primary_vectors),
+ hdmi_as_primary_vectors,
+ },
+ {
+ ARRAY_SIZE(hdmi_as_primary_vectors),
+ hdmi_as_primary_vectors,
+ },
+ {
+ ARRAY_SIZE(hdmi_as_primary_vectors),
+ hdmi_as_primary_vectors,
+ },
+ {
+ ARRAY_SIZE(hdmi_as_primary_vectors),
+ hdmi_as_primary_vectors,
+ },
+};
+#else
+static struct msm_bus_vectors mdp_ui_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_MDP_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 216000000 * 2,
+ .ib = 270000000 * 2,
+ },
+};
+
+static struct msm_bus_vectors mdp_vga_vectors[] = {
+ /* VGA and less video */
+ {
+ .src = MSM_BUS_MASTER_MDP_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 216000000 * 2,
+ .ib = 270000000 * 2,
+ },
+};
+
+static struct msm_bus_vectors mdp_720p_vectors[] = {
+ /* 720p and less video */
+ {
+ .src = MSM_BUS_MASTER_MDP_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 230400000 * 2,
+ .ib = 288000000 * 2,
+ },
+};
+
+static struct msm_bus_vectors mdp_1080p_vectors[] = {
+ /* 1080p and less video */
+ {
+ .src = MSM_BUS_MASTER_MDP_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 334080000 * 2,
+ .ib = 417600000 * 2,
+ },
+};
+
+static struct msm_bus_paths mdp_bus_scale_usecases[] = {
+ {
+ ARRAY_SIZE(mdp_init_vectors),
+ mdp_init_vectors,
+ },
+ {
+ ARRAY_SIZE(mdp_ui_vectors),
+ mdp_ui_vectors,
+ },
+ {
+ ARRAY_SIZE(mdp_ui_vectors),
+ mdp_ui_vectors,
+ },
+ {
+ ARRAY_SIZE(mdp_vga_vectors),
+ mdp_vga_vectors,
+ },
+ {
+ ARRAY_SIZE(mdp_720p_vectors),
+ mdp_720p_vectors,
+ },
+ {
+ ARRAY_SIZE(mdp_1080p_vectors),
+ mdp_1080p_vectors,
+ },
+};
+#endif
+
+static struct msm_bus_scale_pdata mdp_bus_scale_pdata = {
+ mdp_bus_scale_usecases,
+ ARRAY_SIZE(mdp_bus_scale_usecases),
+ .name = "mdp",
+};
+
+#endif
+
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+static int mdp_core_clk_rate_table[] = {
+ 200000000,
+ 200000000,
+ 200000000,
+ 200000000,
+};
+#else
+static int mdp_core_clk_rate_table[] = {
+ 85330000,
+ 85330000,
+ 160000000,
+ 200000000,
+};
+#endif
+
+static struct msm_panel_common_pdata mdp_pdata = {
+ .gpio = MDP_VSYNC_GPIO,
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+ .mdp_core_clk_rate = 200000000,
+#else
+ .mdp_core_clk_rate = 85330000,
+#endif
+ .mdp_core_clk_table = mdp_core_clk_rate_table,
+ .num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+#ifdef CONFIG_MSM_BUS_SCALING
+ .mdp_bus_scale_table = &mdp_bus_scale_pdata,
+#endif
+ .mdp_rev = MDP_REV_42,
+ .writeback_offset = writeback_offset,
+};
+
+#define LPM_CHANNEL0 0
+static int toshiba_gpio[] = {LPM_CHANNEL0};
+
+static struct mipi_dsi_panel_platform_data toshiba_pdata = {
+ .gpio = toshiba_gpio,
+};
+
+static struct platform_device mipi_dsi_toshiba_panel_device = {
+ .name = "mipi_toshiba",
+ .id = 0,
+ .dev = {
+ .platform_data = &toshiba_pdata,
+ }
+};
+
+#define FPGA_3D_GPIO_CONFIG_ADDR 0xB5
+
+static struct mipi_dsi_phy_ctrl dsi_novatek_cmd_mode_phy_db = {
+
+/* DSI_BIT_CLK at 500MHz, 2 lane, RGB888 */
+ {0x0F, 0x0a, 0x04, 0x00, 0x20}, /* regulator */
+ /* timing */
+ {0xab, 0x8a, 0x18, 0x00, 0x92, 0x97, 0x1b, 0x8c,
+ 0x0c, 0x03, 0x04, 0xa0},
+ {0x5f, 0x00, 0x00, 0x10}, /* phy ctrl */
+ {0xff, 0x00, 0x06, 0x00}, /* strength */
+ /* pll control */
+ {0x40, 0xf9, 0x30, 0xda, 0x00, 0x40, 0x03, 0x62,
+ 0x40, 0x07, 0x03,
+ 0x00, 0x1a, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0x01},
+};
+
+static struct mipi_dsi_panel_platform_data novatek_pdata = {
+ .fpga_3d_config_addr = FPGA_3D_GPIO_CONFIG_ADDR,
+ .fpga_ctrl_mode = FPGA_SPI_INTF,
+ .phy_ctrl_settings = &dsi_novatek_cmd_mode_phy_db,
+};
+
+static struct platform_device mipi_dsi_novatek_panel_device = {
+ .name = "mipi_novatek",
+ .id = 0,
+ .dev = {
+ .platform_data = &novatek_pdata,
+ }
+};
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+static struct resource hdmi_msm_resources[] = {
+ {
+ .name = "hdmi_msm_qfprom_addr",
+ .start = 0x00700000,
+ .end = 0x007060FF,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "hdmi_msm_hdmi_addr",
+ .start = 0x04A00000,
+ .end = 0x04A00FFF,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "hdmi_msm_irq",
+ .start = HDMI_IRQ,
+ .end = HDMI_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static int hdmi_enable_5v(int on);
+static int hdmi_core_power(int on, int show);
+static int hdmi_cec_power(int on);
+
+static struct msm_hdmi_platform_data hdmi_msm_data = {
+ .irq = HDMI_IRQ,
+ .enable_5v = hdmi_enable_5v,
+ .core_power = hdmi_core_power,
+ .cec_power = hdmi_cec_power,
+};
+
+static struct platform_device hdmi_msm_device = {
+ .name = "hdmi_msm",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(hdmi_msm_resources),
+ .resource = hdmi_msm_resources,
+ .dev.platform_data = &hdmi_msm_data,
+};
+#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL */
+
+#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+static struct platform_device wfd_panel_device = {
+ .name = "wfd_panel",
+ .id = 0,
+ .dev.platform_data = NULL,
+};
+
+static struct platform_device wfd_device = {
+ .name = "msm_wfd",
+ .id = -1,
+};
+#endif
+
+#ifdef CONFIG_MSM_BUS_SCALING
+static struct msm_bus_vectors dtv_bus_init_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_MDP_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+static struct msm_bus_vectors dtv_bus_def_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_MDP_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2000000000,
+ .ib = 2000000000,
+ },
+};
+#else
+static struct msm_bus_vectors dtv_bus_def_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_MDP_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 566092800 * 2,
+ .ib = 707616000 * 2,
+ },
+};
+#endif
+
+static struct msm_bus_paths dtv_bus_scale_usecases[] = {
+ {
+ ARRAY_SIZE(dtv_bus_init_vectors),
+ dtv_bus_init_vectors,
+ },
+ {
+ ARRAY_SIZE(dtv_bus_def_vectors),
+ dtv_bus_def_vectors,
+ },
+};
+static struct msm_bus_scale_pdata dtv_bus_scale_pdata = {
+ dtv_bus_scale_usecases,
+ ARRAY_SIZE(dtv_bus_scale_usecases),
+ .name = "dtv",
+};
+
+static struct lcdc_platform_data dtv_pdata = {
+ .bus_scale_table = &dtv_bus_scale_pdata,
+};
+#endif
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+static int hdmi_enable_5v(int on)
+{
+ /* TBD: PM8921 regulator instead of 8901 */
+ static struct regulator *reg_8921_hdmi_mvs; /* HDMI_5V */
+ static int prev_on;
+ int rc;
+
+ if (on == prev_on)
+ return 0;
+
+ if (!reg_8921_hdmi_mvs)
+ reg_8921_hdmi_mvs = regulator_get(&hdmi_msm_device.dev,
+ "hdmi_mvs");
+
+ if (on) {
+ rc = regulator_enable(reg_8921_hdmi_mvs);
+ if (rc) {
+ pr_err("'%s' regulator enable failed, rc=%d\n",
+ "8921_hdmi_mvs", rc);
+ return rc;
+ }
+ pr_debug("%s(on): success\n", __func__);
+ } else {
+ rc = regulator_disable(reg_8921_hdmi_mvs);
+ if (rc)
+ pr_warning("'%s' regulator disable failed, rc=%d\n",
+ "8921_hdmi_mvs", rc);
+ pr_debug("%s(off): success\n", __func__);
+ }
+
+ prev_on = on;
+
+ return 0;
+}
+
+static int hdmi_core_power(int on, int show)
+{
+ static struct regulator *reg_8921_l23, *reg_8921_s4;
+ static int prev_on;
+ int rc;
+
+ if (on == prev_on)
+ return 0;
+
+ /* TBD: PM8921 regulator instead of 8901 */
+ if (!reg_8921_l23) {
+ reg_8921_l23 = regulator_get(&hdmi_msm_device.dev, "hdmi_avdd");
+ if (IS_ERR(reg_8921_l23)) {
+ pr_err("could not get reg_8921_l23, rc = %ld\n",
+ PTR_ERR(reg_8921_l23));
+ return -ENODEV;
+ }
+ rc = regulator_set_voltage(reg_8921_l23, 1800000, 1800000);
+ if (rc) {
+ pr_err("set_voltage failed for 8921_l23, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ }
+ if (!reg_8921_s4) {
+ reg_8921_s4 = regulator_get(&hdmi_msm_device.dev, "hdmi_vcc");
+ if (IS_ERR(reg_8921_s4)) {
+ pr_err("could not get reg_8921_s4, rc = %ld\n",
+ PTR_ERR(reg_8921_s4));
+ return -ENODEV;
+ }
+ rc = regulator_set_voltage(reg_8921_s4, 1800000, 1800000);
+ if (rc) {
+ pr_err("set_voltage failed for 8921_s4, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ }
+
+ if (on) {
+ rc = regulator_set_optimum_mode(reg_8921_l23, 100000);
+ if (rc < 0) {
+ pr_err("set_optimum_mode l23 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ rc = regulator_enable(reg_8921_l23);
+ if (rc) {
+ pr_err("'%s' regulator enable failed, rc=%d\n",
+ "hdmi_avdd", rc);
+ return rc;
+ }
+ rc = regulator_enable(reg_8921_s4);
+ if (rc) {
+ pr_err("'%s' regulator enable failed, rc=%d\n",
+ "hdmi_vcc", rc);
+ return rc;
+ }
+ rc = gpio_request(100, "HDMI_DDC_CLK");
+ if (rc) {
+ pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+ "HDMI_DDC_CLK", 100, rc);
+ goto error1;
+ }
+ rc = gpio_request(101, "HDMI_DDC_DATA");
+ if (rc) {
+ pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+ "HDMI_DDC_DATA", 101, rc);
+ goto error2;
+ }
+ rc = gpio_request(102, "HDMI_HPD");
+ if (rc) {
+ pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+ "HDMI_HPD", 102, rc);
+ goto error3;
+ }
+ pr_debug("%s(on): success\n", __func__);
+ } else {
+ gpio_free(100);
+ gpio_free(101);
+ gpio_free(102);
+
+ rc = regulator_disable(reg_8921_l23);
+ if (rc) {
+ pr_err("disable reg_8921_l23 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ rc = regulator_disable(reg_8921_s4);
+ if (rc) {
+ pr_err("disable reg_8921_s4 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ rc = regulator_set_optimum_mode(reg_8921_l23, 100);
+ if (rc < 0) {
+ pr_err("set_optimum_mode l23 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ pr_debug("%s(off): success\n", __func__);
+ }
+
+ prev_on = on;
+
+ return 0;
+
+error3:
+ gpio_free(101);
+error2:
+ gpio_free(100);
+error1:
+ regulator_disable(reg_8921_l23);
+ regulator_disable(reg_8921_s4);
+ return rc;
+}
+
+static int hdmi_cec_power(int on)
+{
+ static int prev_on;
+ int rc;
+
+ if (on == prev_on)
+ return 0;
+
+ if (on) {
+ rc = gpio_request(99, "HDMI_CEC_VAR");
+ if (rc) {
+ pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+ "HDMI_CEC_VAR", 99, rc);
+ goto error;
+ }
+ pr_debug("%s(on): success\n", __func__);
+ } else {
+ gpio_free(99);
+ pr_debug("%s(off): success\n", __func__);
+ }
+
+ prev_on = on;
+
+ return 0;
+error:
+ return rc;
+}
+#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL */
+
+void __init msm8930_init_fb(void)
+{
+ platform_device_register(&msm_fb_device);
+
+#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+ platform_device_register(&wfd_panel_device);
+ platform_device_register(&wfd_device);
+#endif
+
+ platform_device_register(&mipi_dsi_novatek_panel_device);
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+ if (!cpu_is_msm8627())
+ platform_device_register(&hdmi_msm_device);
+#endif
+
+ platform_device_register(&mipi_dsi_toshiba_panel_device);
+
+ msm_fb_register_device("mdp", &mdp_pdata);
+ msm_fb_register_device("mipi_dsi", &mipi_dsi_pdata);
+#ifdef CONFIG_MSM_BUS_SCALING
+ msm_fb_register_device("dtv", &dtv_pdata);
+#endif
+}
+
+void __init msm8930_allocate_fb_region(void)
+{
+ void *addr;
+ unsigned long size;
+
+ size = MSM_FB_SIZE;
+ addr = alloc_bootmem_align(size, 0x1000);
+ msm_fb_resources[0].start = __pa(addr);
+ msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1;
+ pr_info("allocating %lu bytes at %p (%lx physical) for fb\n",
+ size, addr, __pa(addr));
+}
diff --git a/arch/arm/mach-msm/board-8930-gpiomux.c b/arch/arm/mach-msm/board-8930-gpiomux.c
new file mode 100644
index 0000000..e872d64
--- /dev/null
+++ b/arch/arm/mach-msm/board-8930-gpiomux.c
@@ -0,0 +1,662 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 <asm/mach-types.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+#include <mach/socinfo.h>
+#include "devices.h"
+#include "board-8930.h"
+
+/* The SPI configurations apply to GSBI 1*/
+static struct gpiomux_setting spi_active = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_12MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting spi_suspended_config = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting spi_active_config2 = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting spi_suspended_config2 = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting gsbi3_suspended_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_KEEPER,
+};
+
+static struct gpiomux_setting gsbi3_active_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi5 = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi10 = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi12 = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cdc_mclk = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting audio_auxpcm[] = {
+ /* Suspended state */
+ {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ },
+ /* Active state */
+ {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ },
+};
+
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+static struct gpiomux_setting gpio_eth_config = {
+ .pull = GPIOMUX_PULL_NONE,
+ .drv = GPIOMUX_DRV_8MA,
+ .func = GPIOMUX_FUNC_GPIO,
+};
+#endif
+
+static struct gpiomux_setting slimbus = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_KEEPER,
+};
+
+static struct gpiomux_setting wcnss_5wire_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting wcnss_5wire_active_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting cyts_resout_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting cyts_resout_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting cyts_sleep_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting cyts_sleep_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting cyts_int_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting cyts_int_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+static struct gpiomux_setting hsic_act_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_12MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting hsic_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+ .dir = GPIOMUX_OUT_LOW,
+};
+
+static struct gpiomux_setting hsic_hub_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+#endif
+
+static struct gpiomux_setting hap_lvl_shft_suspended_config = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting hap_lvl_shft_active_config = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting ap2mdm_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting mdm2ap_status_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting mdm2ap_errfatal_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_16MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting ap2mdm_kpdpwr_n_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting mdp_vsync_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting mdp_vsync_active_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+static struct gpiomux_setting hdmi_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting hdmi_active_1_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting hdmi_active_2_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+#endif
+
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+static struct msm_gpiomux_config msm8960_ethernet_configs[] = {
+ {
+ .gpio = 90,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_eth_config,
+ }
+ },
+ {
+ .gpio = 89,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_eth_config,
+ }
+ },
+};
+#endif
+
+static struct msm_gpiomux_config msm8960_gsbi_configs[] __initdata = {
+ {
+ .gpio = 6, /* GSBI1 QUP SPI_DATA_MOSI */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &spi_suspended_config,
+ [GPIOMUX_ACTIVE] = &spi_active,
+ },
+ },
+ {
+ .gpio = 7, /* GSBI1 QUP SPI_DATA_MISO */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &spi_suspended_config,
+ [GPIOMUX_ACTIVE] = &spi_active,
+ },
+ },
+ {
+ .gpio = 8, /* GSBI1 QUP SPI_CS_N */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &spi_suspended_config,
+ [GPIOMUX_ACTIVE] = &spi_active,
+ },
+ },
+ {
+ .gpio = 9, /* GSBI1 QUP SPI_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &spi_suspended_config,
+ [GPIOMUX_ACTIVE] = &spi_active,
+ },
+ },
+ {
+ .gpio = 14, /* GSBI1 SPI_CS_1 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &spi_suspended_config2,
+ [GPIOMUX_ACTIVE] = &spi_active_config2,
+ },
+ },
+ {
+ .gpio = 16, /* GSBI3 I2C QUP SDA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi3_suspended_cfg,
+ [GPIOMUX_ACTIVE] = &gsbi3_active_cfg,
+ },
+ },
+ {
+ .gpio = 17, /* GSBI3 I2C QUP SCL */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi3_suspended_cfg,
+ [GPIOMUX_ACTIVE] = &gsbi3_active_cfg,
+ },
+ },
+ {
+ .gpio = 22, /* GSBI5 UART2 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi5,
+ },
+ },
+ {
+ .gpio = 23, /* GSBI5 UART2 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi5,
+ },
+ },
+ {
+ .gpio = 24, /* GSBI5 UART2 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi5,
+ },
+ },
+ {
+ .gpio = 25, /* GSBI5 UART2 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi5,
+ },
+ },
+ {
+ .gpio = 44, /* GSBI12 I2C QUP SDA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi12,
+ },
+ },
+ {
+ .gpio = 45, /* GSBI12 I2C QUP SCL */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi12,
+ },
+ },
+ {
+ .gpio = 73, /* GSBI10 I2C QUP SDA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi10,
+ },
+ },
+ {
+ .gpio = 74, /* GSBI10 I2C QUP SCL */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi10,
+ },
+ },
+};
+
+static struct msm_gpiomux_config msm8960_slimbus_config[] __initdata = {
+ {
+ .gpio = 60, /* slimbus data */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &slimbus,
+ },
+ },
+ {
+ .gpio = 61, /* slimbus clk */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &slimbus,
+ },
+ },
+};
+
+static struct msm_gpiomux_config msm8960_audio_codec_configs[] __initdata = {
+ {
+ .gpio = 59,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &cdc_mclk,
+ },
+ },
+};
+
+static struct msm_gpiomux_config msm8960_audio_auxpcm_configs[] __initdata = {
+ {
+ .gpio = 63,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+ [GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+ },
+ },
+ {
+ .gpio = 64,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+ [GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+ },
+ },
+ {
+ .gpio = 65,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+ [GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+ },
+ },
+ {
+ .gpio = 66,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+ [GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+ },
+ },
+};
+
+static struct msm_gpiomux_config wcnss_5wire_interface[] = {
+ {
+ .gpio = 84,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 85,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 86,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 87,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 88,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+};
+
+static struct msm_gpiomux_config msm8960_cyts_configs[] __initdata = {
+ { /* TS INTERRUPT */
+ .gpio = 11,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cyts_int_act_cfg,
+ [GPIOMUX_SUSPENDED] = &cyts_int_sus_cfg,
+ },
+ },
+ { /* TS SLEEP */
+ .gpio = 50,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cyts_sleep_act_cfg,
+ [GPIOMUX_SUSPENDED] = &cyts_sleep_sus_cfg,
+ },
+ },
+ { /* TS RESOUT */
+ .gpio = 52,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cyts_resout_act_cfg,
+ [GPIOMUX_SUSPENDED] = &cyts_resout_sus_cfg,
+ },
+ },
+};
+
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+static struct msm_gpiomux_config msm8960_hsic_configs[] = {
+ {
+ .gpio = 150, /*HSIC_STROBE */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hsic_act_cfg,
+ [GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
+ },
+ },
+ {
+ .gpio = 151, /* HSIC_DATA */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hsic_act_cfg,
+ [GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
+ },
+ },
+ {
+ .gpio = 91, /* HSIC_HUB_RESET */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hsic_hub_act_cfg,
+ [GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
+ },
+ },
+};
+#endif
+
+static struct msm_gpiomux_config hap_lvl_shft_config[] __initdata = {
+ {
+ .gpio = 47,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &hap_lvl_shft_suspended_config,
+ [GPIOMUX_ACTIVE] = &hap_lvl_shft_active_config,
+ },
+ },
+};
+
+static struct msm_gpiomux_config mdm_configs[] __initdata = {
+ /* AP2MDM_STATUS */
+ {
+ .gpio = 94,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+ }
+ },
+ /* MDM2AP_STATUS */
+ {
+ .gpio = 69,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &mdm2ap_status_cfg,
+ }
+ },
+ /* MDM2AP_ERRFATAL */
+ {
+ .gpio = 70,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &mdm2ap_errfatal_cfg,
+ }
+ },
+ /* AP2MDM_ERRFATAL */
+ {
+ .gpio = 95,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+ }
+ },
+ /* AP2MDM_KPDPWR_N */
+ {
+ .gpio = 81,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &ap2mdm_kpdpwr_n_cfg,
+ }
+ },
+ /* AP2MDM_PMIC_RESET_N */
+ {
+ .gpio = 80,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &ap2mdm_kpdpwr_n_cfg,
+ }
+ }
+};
+
+static struct msm_gpiomux_config msm8960_mdp_vsync_configs[] __initdata = {
+ {
+ .gpio = 0,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &mdp_vsync_active_cfg,
+ [GPIOMUX_SUSPENDED] = &mdp_vsync_suspend_cfg,
+ },
+ }
+};
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+static struct msm_gpiomux_config msm8960_hdmi_configs[] __initdata = {
+ {
+ .gpio = 99,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hdmi_active_1_cfg,
+ [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 100,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hdmi_active_1_cfg,
+ [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 101,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hdmi_active_1_cfg,
+ [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 102,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hdmi_active_2_cfg,
+ [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+ },
+ },
+};
+#endif
+
+int __init msm8930_init_gpiomux(void)
+{
+ int rc = msm_gpiomux_init(NR_GPIO_IRQS);
+ if (rc) {
+ pr_err(KERN_ERR "msm_gpiomux_init failed %d\n", rc);
+ return rc;
+ }
+
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+ msm_gpiomux_install(msm8960_ethernet_configs,
+ ARRAY_SIZE(msm8960_ethernet_configs));
+#endif
+
+ msm_gpiomux_install(msm8960_gsbi_configs,
+ ARRAY_SIZE(msm8960_gsbi_configs));
+
+ msm_gpiomux_install(msm8960_cyts_configs,
+ ARRAY_SIZE(msm8960_cyts_configs));
+
+ msm_gpiomux_install(msm8960_slimbus_config,
+ ARRAY_SIZE(msm8960_slimbus_config));
+
+ msm_gpiomux_install(msm8960_audio_codec_configs,
+ ARRAY_SIZE(msm8960_audio_codec_configs));
+
+ msm_gpiomux_install(msm8960_audio_auxpcm_configs,
+ ARRAY_SIZE(msm8960_audio_auxpcm_configs));
+
+ msm_gpiomux_install(wcnss_5wire_interface,
+ ARRAY_SIZE(wcnss_5wire_interface));
+
+ if (machine_is_msm8930_mtp() || machine_is_msm8930_fluid() ||
+ machine_is_msm8930_cdp())
+ msm_gpiomux_install(hap_lvl_shft_config,
+ ARRAY_SIZE(hap_lvl_shft_config));
+
+ if (PLATFORM_IS_CHARM25())
+ msm_gpiomux_install(mdm_configs,
+ ARRAY_SIZE(mdm_configs));
+
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+ if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) != 1) &&
+ !machine_is_msm8930_mtp() &&
+ !machine_is_msm8930_fluid())
+ msm_gpiomux_install(msm8960_hsic_configs,
+ ARRAY_SIZE(msm8960_hsic_configs));
+#endif
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+ msm_gpiomux_install(msm8960_hdmi_configs,
+ ARRAY_SIZE(msm8960_hdmi_configs));
+#endif
+
+ msm_gpiomux_install(msm8960_mdp_vsync_configs,
+ ARRAY_SIZE(msm8960_mdp_vsync_configs));
+ return 0;
+}
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
new file mode 100644
index 0000000..cfb2347
--- /dev/null
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -0,0 +1,499 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/interrupt.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
+#include <linux/leds.h>
+#include <linux/leds-pm8xxx.h>
+#include <linux/msm_ssbi.h>
+#include <asm/mach-types.h>
+#include <mach/msm_bus_board.h>
+#include <mach/restart.h>
+#include "devices.h"
+#include "board-8930.h"
+
+struct pm8xxx_gpio_init {
+ unsigned gpio;
+ struct pm_gpio config;
+};
+
+struct pm8xxx_mpp_init {
+ unsigned mpp;
+ struct pm8xxx_mpp_config_data config;
+};
+
+#define PM8XXX_GPIO_INIT(_gpio, _dir, _buf, _val, _pull, _vin, _out_strength, \
+ _func, _inv, _disable) \
+{ \
+ .gpio = PM8921_GPIO_PM_TO_SYS(_gpio), \
+ .config = { \
+ .direction = _dir, \
+ .output_buffer = _buf, \
+ .output_value = _val, \
+ .pull = _pull, \
+ .vin_sel = _vin, \
+ .out_strength = _out_strength, \
+ .function = _func, \
+ .inv_int_pol = _inv, \
+ .disable_pin = _disable, \
+ } \
+}
+
+#define PM8XXX_MPP_INIT(_mpp, _type, _level, _control) \
+{ \
+ .mpp = PM8921_MPP_PM_TO_SYS(_mpp), \
+ .config = { \
+ .type = PM8XXX_MPP_TYPE_##_type, \
+ .level = _level, \
+ .control = PM8XXX_MPP_##_control, \
+ } \
+}
+
+#define PM8XXX_GPIO_DISABLE(_gpio) \
+ PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, 0, 0, 0, PM_GPIO_VIN_S4, \
+ 0, 0, 0, 1)
+
+#define PM8XXX_GPIO_OUTPUT(_gpio, _val) \
+ PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+ PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \
+ PM_GPIO_STRENGTH_HIGH, \
+ PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8XXX_GPIO_INPUT(_gpio, _pull) \
+ PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, PM_GPIO_OUT_BUF_CMOS, 0, \
+ _pull, PM_GPIO_VIN_S4, \
+ PM_GPIO_STRENGTH_NO, \
+ PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8XXX_GPIO_OUTPUT_FUNC(_gpio, _val, _func) \
+ PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+ PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \
+ PM_GPIO_STRENGTH_HIGH, \
+ _func, 0, 0)
+
+#define PM8XXX_GPIO_OUTPUT_VIN(_gpio, _val, _vin) \
+ PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+ PM_GPIO_PULL_NO, _vin, \
+ PM_GPIO_STRENGTH_HIGH, \
+ PM_GPIO_FUNC_NORMAL, 0, 0)
+
+/* Initial PM8921 GPIO configurations */
+static struct pm8xxx_gpio_init pm8921_gpios[] __initdata = {
+ PM8XXX_GPIO_DISABLE(6), /* Disable unused */
+ PM8XXX_GPIO_DISABLE(7), /* Disable NFC */
+ PM8XXX_GPIO_INPUT(16, PM_GPIO_PULL_UP_30), /* SD_CARD_WP */
+ /* External regulator shared by display and touchscreen on LiQUID */
+ PM8XXX_GPIO_OUTPUT(17, 0), /* DISP 3.3 V Boost */
+ PM8XXX_GPIO_OUTPUT_VIN(21, 1, PM_GPIO_VIN_VPH), /* Backlight Enable */
+ PM8XXX_GPIO_DISABLE(22), /* Disable NFC */
+ PM8XXX_GPIO_OUTPUT_FUNC(24, 0, PM_GPIO_FUNC_2), /* Bl: Off, PWM mode */
+ PM8XXX_GPIO_INPUT(26, PM_GPIO_PULL_UP_30), /* SD_CARD_DET_N */
+ PM8XXX_GPIO_OUTPUT(43, PM_GPIO_PULL_UP_30), /* DISP_RESET_N */
+ PM8XXX_GPIO_OUTPUT(42, 0), /* USB 5V reg enable */
+};
+
+/* Initial PM8921 MPP configurations */
+static struct pm8xxx_mpp_init pm8921_mpps[] __initdata = {
+ /* External 5V regulator enable; shared by HDMI and USB_OTG switches. */
+ PM8XXX_MPP_INIT(7, D_INPUT, PM8921_MPP_DIG_LEVEL_VPH, DIN_TO_INT),
+ PM8XXX_MPP_INIT(PM8XXX_AMUX_MPP_8, A_INPUT, PM8XXX_MPP_AIN_AMUX_CH8,
+ DOUT_CTRL_LOW),
+};
+
+void __init msm8930_pm8921_gpio_mpp_init(void)
+{
+ int i, rc;
+
+ for (i = 0; i < ARRAY_SIZE(pm8921_gpios); i++) {
+ rc = pm8xxx_gpio_config(pm8921_gpios[i].gpio,
+ &pm8921_gpios[i].config);
+ if (rc) {
+ pr_err("%s: pm8xxx_gpio_config: rc=%d\n", __func__, rc);
+ break;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(pm8921_mpps); i++) {
+ rc = pm8xxx_mpp_config(pm8921_mpps[i].mpp,
+ &pm8921_mpps[i].config);
+ if (rc) {
+ pr_err("%s: pm8xxx_mpp_config: rc=%d\n", __func__, rc);
+ break;
+ }
+ }
+}
+
+static struct pm8xxx_adc_amux pm8xxx_adc_channels_data[] = {
+ {"vcoin", CHANNEL_VCOIN, CHAN_PATH_SCALING2, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"vbat", CHANNEL_VBAT, CHAN_PATH_SCALING2, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"dcin", CHANNEL_DCIN, CHAN_PATH_SCALING4, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"ichg", CHANNEL_ICHG, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"vph_pwr", CHANNEL_VPH_PWR, CHAN_PATH_SCALING2, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"ibat", CHANNEL_IBAT, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"batt_therm", CHANNEL_BATT_THERM, CHAN_PATH_SCALING1, AMUX_RSV2,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_BATT_THERM},
+ {"batt_id", CHANNEL_BATT_ID, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"usbin", CHANNEL_USBIN, CHAN_PATH_SCALING3, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"pmic_therm", CHANNEL_DIE_TEMP, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_PMIC_THERM},
+ {"625mv", CHANNEL_625MV, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"125v", CHANNEL_125V, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"chg_temp", CHANNEL_CHG_TEMP, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"pa_therm1", ADC_MPP_1_AMUX8, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_PA_THERM},
+ {"xo_therm", CHANNEL_MUXOFF, CHAN_PATH_SCALING1, AMUX_RSV0,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_XOTHERM},
+ {"pa_therm0", ADC_MPP_1_AMUX3, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_PA_THERM},
+};
+
+static struct pm8xxx_adc_properties pm8xxx_adc_data = {
+ .adc_vdd_reference = 1800, /* milli-voltage for this adc */
+ .bitresolution = 15,
+ .bipolar = 0,
+};
+
+static struct pm8xxx_adc_platform_data pm8xxx_adc_pdata = {
+ .adc_channel = pm8xxx_adc_channels_data,
+ .adc_num_board_channel = ARRAY_SIZE(pm8xxx_adc_channels_data),
+ .adc_prop = &pm8xxx_adc_data,
+ .adc_mpp_base = PM8921_MPP_PM_TO_SYS(1),
+};
+
+
+static struct pm8xxx_irq_platform_data pm8xxx_irq_pdata __devinitdata = {
+ .irq_base = PM8921_IRQ_BASE,
+ .devirq = MSM_GPIO_TO_INT(104),
+ .irq_trigger_flag = IRQF_TRIGGER_LOW,
+};
+
+static struct pm8xxx_gpio_platform_data pm8xxx_gpio_pdata __devinitdata = {
+ .gpio_base = PM8921_GPIO_PM_TO_SYS(1),
+};
+
+static struct pm8xxx_mpp_platform_data pm8xxx_mpp_pdata __devinitdata = {
+ .mpp_base = PM8921_MPP_PM_TO_SYS(1),
+};
+
+static struct pm8xxx_rtc_platform_data pm8xxx_rtc_pdata __devinitdata = {
+ .rtc_write_enable = false,
+ .rtc_alarm_powerup = false,
+};
+
+static struct pm8xxx_pwrkey_platform_data pm8xxx_pwrkey_pdata = {
+ .pull_up = 1,
+ .kpd_trigger_delay_us = 970,
+ .wakeup = 1,
+};
+
+/* Rotate lock key is not available so use F1 */
+#define KEY_ROTATE_LOCK KEY_F1
+
+static const unsigned int keymap_liquid[] = {
+ KEY(0, 0, KEY_VOLUMEUP),
+ KEY(0, 1, KEY_VOLUMEDOWN),
+ KEY(1, 3, KEY_ROTATE_LOCK),
+ KEY(1, 4, KEY_HOME),
+};
+
+static const unsigned int keymap[] = {
+ KEY(0, 0, KEY_VOLUMEUP),
+ KEY(0, 1, KEY_VOLUMEDOWN),
+ KEY(0, 2, KEY_CAMERA_SNAPSHOT),
+ KEY(0, 3, KEY_CAMERA_FOCUS),
+};
+
+static struct matrix_keymap_data keymap_data = {
+ .keymap_size = ARRAY_SIZE(keymap),
+ .keymap = keymap,
+};
+
+static struct pm8xxx_keypad_platform_data keypad_data = {
+ .input_name = "keypad_8960",
+ .input_phys_device = "keypad_8960/input0",
+ .num_rows = 1,
+ .num_cols = 5,
+ .rows_gpio_start = PM8921_GPIO_PM_TO_SYS(9),
+ .cols_gpio_start = PM8921_GPIO_PM_TO_SYS(1),
+ .debounce_ms = 15,
+ .scan_delay_ms = 32,
+ .row_hold_ns = 91500,
+ .wakeup = 1,
+ .keymap_data = &keymap_data,
+};
+
+static const unsigned int keymap_sim[] = {
+ KEY(0, 0, KEY_7),
+ KEY(0, 1, KEY_DOWN),
+ KEY(0, 2, KEY_UP),
+ KEY(0, 3, KEY_RIGHT),
+ KEY(0, 4, KEY_ENTER),
+ KEY(0, 5, KEY_L),
+ KEY(0, 6, KEY_BACK),
+ KEY(0, 7, KEY_M),
+
+ KEY(1, 0, KEY_LEFT),
+ KEY(1, 1, KEY_SEND),
+ KEY(1, 2, KEY_1),
+ KEY(1, 3, KEY_4),
+ KEY(1, 4, KEY_CLEAR),
+ KEY(1, 5, KEY_MSDOS),
+ KEY(1, 6, KEY_SPACE),
+ KEY(1, 7, KEY_COMMA),
+
+ KEY(2, 0, KEY_6),
+ KEY(2, 1, KEY_5),
+ KEY(2, 2, KEY_8),
+ KEY(2, 3, KEY_3),
+ KEY(2, 4, KEY_NUMERIC_STAR),
+ KEY(2, 5, KEY_UP),
+ KEY(2, 6, KEY_DOWN),
+ KEY(2, 7, KEY_LEFTSHIFT),
+
+ KEY(3, 0, KEY_9),
+ KEY(3, 1, KEY_NUMERIC_POUND),
+ KEY(3, 2, KEY_0),
+ KEY(3, 3, KEY_2),
+ KEY(3, 4, KEY_SLEEP),
+ KEY(3, 5, KEY_F1),
+ KEY(3, 6, KEY_F2),
+ KEY(3, 7, KEY_F3),
+
+ KEY(4, 0, KEY_BACK),
+ KEY(4, 1, KEY_HOME),
+ KEY(4, 2, KEY_MENU),
+ KEY(4, 3, KEY_VOLUMEUP),
+ KEY(4, 4, KEY_VOLUMEDOWN),
+ KEY(4, 5, KEY_F4),
+ KEY(4, 6, KEY_F5),
+ KEY(4, 7, KEY_F6),
+
+ KEY(5, 0, KEY_R),
+ KEY(5, 1, KEY_T),
+ KEY(5, 2, KEY_Y),
+ KEY(5, 3, KEY_LEFTALT),
+ KEY(5, 4, KEY_KPENTER),
+ KEY(5, 5, KEY_Q),
+ KEY(5, 6, KEY_W),
+ KEY(5, 7, KEY_E),
+
+ KEY(6, 0, KEY_F),
+ KEY(6, 1, KEY_G),
+ KEY(6, 2, KEY_H),
+ KEY(6, 3, KEY_CAPSLOCK),
+ KEY(6, 4, KEY_PAGEUP),
+ KEY(6, 5, KEY_A),
+ KEY(6, 6, KEY_S),
+ KEY(6, 7, KEY_D),
+
+ KEY(7, 0, KEY_V),
+ KEY(7, 1, KEY_B),
+ KEY(7, 2, KEY_N),
+ KEY(7, 3, KEY_MENU),
+ KEY(7, 4, KEY_PAGEDOWN),
+ KEY(7, 5, KEY_Z),
+ KEY(7, 6, KEY_X),
+ KEY(7, 7, KEY_C),
+
+ KEY(8, 0, KEY_P),
+ KEY(8, 1, KEY_J),
+ KEY(8, 2, KEY_K),
+ KEY(8, 3, KEY_INSERT),
+ KEY(8, 4, KEY_LINEFEED),
+ KEY(8, 5, KEY_U),
+ KEY(8, 6, KEY_I),
+ KEY(8, 7, KEY_O),
+
+ KEY(9, 0, KEY_4),
+ KEY(9, 1, KEY_5),
+ KEY(9, 2, KEY_6),
+ KEY(9, 3, KEY_7),
+ KEY(9, 4, KEY_8),
+ KEY(9, 5, KEY_1),
+ KEY(9, 6, KEY_2),
+ KEY(9, 7, KEY_3),
+
+ KEY(10, 0, KEY_F7),
+ KEY(10, 1, KEY_F8),
+ KEY(10, 2, KEY_F9),
+ KEY(10, 3, KEY_F10),
+ KEY(10, 4, KEY_FN),
+ KEY(10, 5, KEY_9),
+ KEY(10, 6, KEY_0),
+ KEY(10, 7, KEY_DOT),
+
+ KEY(11, 0, KEY_LEFTCTRL),
+ KEY(11, 1, KEY_F11),
+ KEY(11, 2, KEY_ENTER),
+ KEY(11, 3, KEY_SEARCH),
+ KEY(11, 4, KEY_DELETE),
+ KEY(11, 5, KEY_RIGHT),
+ KEY(11, 6, KEY_LEFT),
+ KEY(11, 7, KEY_RIGHTSHIFT),
+ KEY(0, 0, KEY_VOLUMEUP),
+ KEY(0, 1, KEY_VOLUMEDOWN),
+ KEY(0, 2, KEY_CAMERA_SNAPSHOT),
+ KEY(0, 3, KEY_CAMERA_FOCUS),
+};
+
+static int pm8921_therm_mitigation[] = {
+ 1100,
+ 700,
+ 600,
+ 325,
+};
+
+static struct pm8921_charger_platform_data pm8921_chg_pdata __devinitdata = {
+ .safety_time = 180,
+ .update_time = 60000,
+ .max_voltage = 4200,
+ .min_voltage = 3200,
+ .resume_voltage_delta = 100,
+ .term_current = 100,
+ .cool_temp = 10,
+ .warm_temp = 40,
+ .temp_check_period = 1,
+ .max_bat_chg_current = 1100,
+ .cool_bat_chg_current = 350,
+ .warm_bat_chg_current = 350,
+ .cool_bat_voltage = 4100,
+ .warm_bat_voltage = 4100,
+ .thermal_mitigation = pm8921_therm_mitigation,
+ .thermal_levels = ARRAY_SIZE(pm8921_therm_mitigation),
+};
+
+static struct pm8xxx_misc_platform_data pm8xxx_misc_pdata = {
+ .priority = 0,
+};
+
+static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
+ .r_sense = 10,
+ .i_test = 2500,
+ .v_failure = 3000,
+ .calib_delay_ms = 600000,
+};
+
+#define PM8921_LC_LED_MAX_CURRENT 4 /* I = 4mA */
+#define PM8XXX_LED_PWM_PERIOD 1000
+#define PM8XXX_LED_PWM_DUTY_MS 20
+/**
+ * PM8XXX_PWM_CHANNEL_NONE shall be used when LED shall not be
+ * driven using PWM feature.
+ */
+#define PM8XXX_PWM_CHANNEL_NONE -1
+
+static struct led_info pm8921_led_info[] = {
+ [0] = {
+ .name = "led:battery_charging",
+ .default_trigger = "battery-charging",
+ },
+ [1] = {
+ .name = "led:battery_full",
+ .default_trigger = "battery-full",
+ },
+};
+
+static struct led_platform_data pm8921_led_core_pdata = {
+ .num_leds = ARRAY_SIZE(pm8921_led_info),
+ .leds = pm8921_led_info,
+};
+
+static int pm8921_led0_pwm_duty_pcts[56] = {
+ 1, 4, 8, 12, 16, 20, 24, 28, 32, 36,
+ 40, 44, 46, 52, 56, 60, 64, 68, 72, 76,
+ 80, 84, 88, 92, 96, 100, 100, 100, 98, 95,
+ 92, 88, 84, 82, 78, 74, 70, 66, 62, 58,
+ 58, 54, 50, 48, 42, 38, 34, 30, 26, 22,
+ 14, 10, 6, 4, 1
+};
+
+static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_duty_cycles = {
+ .duty_pcts = (int *)&pm8921_led0_pwm_duty_pcts,
+ .num_duty_pcts = ARRAY_SIZE(pm8921_led0_pwm_duty_pcts),
+ .duty_ms = PM8XXX_LED_PWM_DUTY_MS,
+ .start_idx = 0,
+};
+
+static struct pm8xxx_led_config pm8921_led_configs[] = {
+ [0] = {
+ .id = PM8XXX_ID_LED_0,
+ .mode = PM8XXX_LED_MODE_PWM2,
+ .max_current = PM8921_LC_LED_MAX_CURRENT,
+ .pwm_channel = 5,
+ .pwm_period_us = PM8XXX_LED_PWM_PERIOD,
+ .pwm_duty_cycles = &pm8921_led0_pwm_duty_cycles,
+ },
+ [1] = {
+ .id = PM8XXX_ID_LED_1,
+ .mode = PM8XXX_LED_MODE_PWM1,
+ .max_current = PM8921_LC_LED_MAX_CURRENT,
+ .pwm_channel = 4,
+ .pwm_period_us = PM8XXX_LED_PWM_PERIOD,
+ },
+};
+
+static struct pm8xxx_led_platform_data pm8xxx_leds_pdata = {
+ .led_core = &pm8921_led_core_pdata,
+ .configs = pm8921_led_configs,
+ .num_configs = ARRAY_SIZE(pm8921_led_configs),
+};
+
+static struct pm8xxx_ccadc_platform_data pm8xxx_ccadc_pdata = {
+ .r_sense = 10,
+};
+
+static struct pm8921_platform_data pm8921_platform_data __devinitdata = {
+ .irq_pdata = &pm8xxx_irq_pdata,
+ .gpio_pdata = &pm8xxx_gpio_pdata,
+ .mpp_pdata = &pm8xxx_mpp_pdata,
+ .rtc_pdata = &pm8xxx_rtc_pdata,
+ .pwrkey_pdata = &pm8xxx_pwrkey_pdata,
+ .keypad_pdata = &keypad_data,
+ .misc_pdata = &pm8xxx_misc_pdata,
+ .regulator_pdatas = msm_pm8921_regulator_pdata,
+ .charger_pdata = &pm8921_chg_pdata,
+ .bms_pdata = &pm8921_bms_pdata,
+ .adc_pdata = &pm8xxx_adc_pdata,
+ .leds_pdata = &pm8xxx_leds_pdata,
+ .ccadc_pdata = &pm8xxx_ccadc_pdata,
+};
+
+static struct msm_ssbi_platform_data msm8960_ssbi_pm8921_pdata __devinitdata = {
+ .controller_type = MSM_SBI_CTRL_PMIC_ARBITER,
+ .slave = {
+ .name = "pm8921-core",
+ .platform_data = &pm8921_platform_data,
+ },
+};
+
+void __init msm8930_init_pmic(void)
+{
+ pmic_reset_irq = PM8921_IRQ_BASE + PM8921_RESOUT_IRQ;
+ msm8960_device_ssbi_pm8921.dev.platform_data =
+ &msm8960_ssbi_pm8921_pdata;
+ pm8921_platform_data.num_regulators = msm_pm8921_regulator_pdata_len;
+
+ /* Simulator supports a QWERTY keypad */
+}
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
new file mode 100644
index 0000000..032d3d0
--- /dev/null
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -0,0 +1,268 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/bootmem.h>
+#include <asm/mach-types.h>
+#include <asm/mach/mmc.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+#include "devices.h"
+#include "board-8930.h"
+
+/* MSM8960 has 5 SDCC controllers */
+enum sdcc_controllers {
+ SDCC1,
+ SDCC2,
+ SDCC3,
+ SDCC4,
+ SDCC5,
+ MAX_SDCC_CONTROLLER
+};
+
+/* All SDCC controllers require VDD/VCC voltage */
+static struct msm_mmc_reg_data mmc_vdd_reg_data[MAX_SDCC_CONTROLLER] = {
+ /* SDCC1 : eMMC card connected */
+ [SDCC1] = {
+ .name = "sdc_vdd",
+ .high_vol_level = 2950000,
+ .low_vol_level = 2950000,
+ .always_on = 1,
+ .lpm_sup = 1,
+ .lpm_uA = 9000,
+ .hpm_uA = 200000, /* 200mA */
+ },
+ /* SDCC3 : External card slot connected */
+ [SDCC3] = {
+ .name = "sdc_vdd",
+ .high_vol_level = 2950000,
+ .low_vol_level = 2950000,
+ .hpm_uA = 600000, /* 600mA */
+ }
+};
+
+/* Only slots having eMMC card will require VCCQ voltage */
+static struct msm_mmc_reg_data mmc_vccq_reg_data[1] = {
+ /* SDCC1 : eMMC card connected */
+ [SDCC1] = {
+ .name = "sdc_vccq",
+ .always_on = 1,
+ .high_vol_level = 1800000,
+ .low_vol_level = 1800000,
+ .hpm_uA = 200000, /* 200mA */
+ }
+};
+
+/* All SDCC controllers may require voting for VDD PAD voltage */
+static struct msm_mmc_reg_data mmc_vddp_reg_data[MAX_SDCC_CONTROLLER] = {
+ /* SDCC3 : External card slot connected */
+ [SDCC3] = {
+ .name = "sdc_vddp",
+ .high_vol_level = 2950000,
+ .low_vol_level = 1850000,
+ .always_on = 1,
+ .lpm_sup = 1,
+ /* Max. Active current required is 16 mA */
+ .hpm_uA = 16000,
+ /*
+ * Sleep current required is ~300 uA. But min. vote can be
+ * in terms of mA (min. 1 mA). So let's vote for 2 mA
+ * during sleep.
+ */
+ .lpm_uA = 2000,
+ }
+};
+
+static struct msm_mmc_slot_reg_data mmc_slot_vreg_data[MAX_SDCC_CONTROLLER] = {
+ /* SDCC1 : eMMC card connected */
+ [SDCC1] = {
+ .vdd_data = &mmc_vdd_reg_data[SDCC1],
+ .vccq_data = &mmc_vccq_reg_data[SDCC1],
+ },
+ /* SDCC3 : External card slot connected */
+ [SDCC3] = {
+ .vdd_data = &mmc_vdd_reg_data[SDCC3],
+ .vddp_data = &mmc_vddp_reg_data[SDCC3],
+ }
+};
+
+/* SDC1 pad data */
+static struct msm_mmc_pad_drv sdc1_pad_drv_on_cfg[] = {
+ {TLMM_HDRV_SDC1_CLK, GPIO_CFG_16MA},
+ {TLMM_HDRV_SDC1_CMD, GPIO_CFG_10MA},
+ {TLMM_HDRV_SDC1_DATA, GPIO_CFG_10MA}
+};
+
+static struct msm_mmc_pad_drv sdc1_pad_drv_off_cfg[] = {
+ {TLMM_HDRV_SDC1_CLK, GPIO_CFG_2MA},
+ {TLMM_HDRV_SDC1_CMD, GPIO_CFG_2MA},
+ {TLMM_HDRV_SDC1_DATA, GPIO_CFG_2MA}
+};
+
+static struct msm_mmc_pad_pull sdc1_pad_pull_on_cfg[] = {
+ {TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
+ {TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_UP},
+ {TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_UP}
+};
+
+static struct msm_mmc_pad_pull sdc1_pad_pull_off_cfg[] = {
+ {TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
+ {TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_DOWN},
+ {TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_DOWN}
+};
+
+/* SDC3 pad data */
+static struct msm_mmc_pad_drv sdc3_pad_drv_on_cfg[] = {
+ {TLMM_HDRV_SDC3_CLK, GPIO_CFG_8MA},
+ {TLMM_HDRV_SDC3_CMD, GPIO_CFG_8MA},
+ {TLMM_HDRV_SDC3_DATA, GPIO_CFG_8MA}
+};
+
+static struct msm_mmc_pad_drv sdc3_pad_drv_off_cfg[] = {
+ {TLMM_HDRV_SDC3_CLK, GPIO_CFG_2MA},
+ {TLMM_HDRV_SDC3_CMD, GPIO_CFG_2MA},
+ {TLMM_HDRV_SDC3_DATA, GPIO_CFG_2MA}
+};
+
+static struct msm_mmc_pad_pull sdc3_pad_pull_on_cfg[] = {
+ {TLMM_PULL_SDC3_CLK, GPIO_CFG_NO_PULL},
+ {TLMM_PULL_SDC3_CMD, GPIO_CFG_PULL_UP},
+ {TLMM_PULL_SDC3_DATA, GPIO_CFG_PULL_UP}
+};
+
+static struct msm_mmc_pad_pull sdc3_pad_pull_off_cfg[] = {
+ {TLMM_PULL_SDC3_CLK, GPIO_CFG_NO_PULL},
+ /*
+ * SDC3 CMD line should be PULLed UP otherwise fluid platform will
+ * see transitions (1 -> 0 and 0 -> 1) on card detection line,
+ * which would result in false card detection interrupts.
+ */
+ {TLMM_PULL_SDC3_CMD, GPIO_CFG_PULL_UP},
+ /*
+ * Keeping DATA lines status to PULL UP will make sure that
+ * there is no current leak during sleep if external pull up
+ * is connected to DATA lines.
+ */
+ {TLMM_PULL_SDC3_DATA, GPIO_CFG_PULL_UP}
+};
+
+static struct msm_mmc_pad_pull_data mmc_pad_pull_data[MAX_SDCC_CONTROLLER] = {
+ [SDCC1] = {
+ .on = sdc1_pad_pull_on_cfg,
+ .off = sdc1_pad_pull_off_cfg,
+ .size = ARRAY_SIZE(sdc1_pad_pull_on_cfg)
+ },
+ [SDCC3] = {
+ .on = sdc3_pad_pull_on_cfg,
+ .off = sdc3_pad_pull_off_cfg,
+ .size = ARRAY_SIZE(sdc3_pad_pull_on_cfg)
+ },
+};
+
+static struct msm_mmc_pad_drv_data mmc_pad_drv_data[MAX_SDCC_CONTROLLER] = {
+ [SDCC1] = {
+ .on = sdc1_pad_drv_on_cfg,
+ .off = sdc1_pad_drv_off_cfg,
+ .size = ARRAY_SIZE(sdc1_pad_drv_on_cfg)
+ },
+ [SDCC3] = {
+ .on = sdc3_pad_drv_on_cfg,
+ .off = sdc3_pad_drv_off_cfg,
+ .size = ARRAY_SIZE(sdc3_pad_drv_on_cfg)
+ },
+};
+
+static struct msm_mmc_pad_data mmc_pad_data[MAX_SDCC_CONTROLLER] = {
+ [SDCC1] = {
+ .pull = &mmc_pad_pull_data[SDCC1],
+ .drv = &mmc_pad_drv_data[SDCC1]
+ },
+ [SDCC3] = {
+ .pull = &mmc_pad_pull_data[SDCC3],
+ .drv = &mmc_pad_drv_data[SDCC3]
+ },
+};
+
+static struct msm_mmc_pin_data mmc_slot_pin_data[MAX_SDCC_CONTROLLER] = {
+ [SDCC1] = {
+ .pad_data = &mmc_pad_data[SDCC1],
+ },
+ [SDCC3] = {
+ .pad_data = &mmc_pad_data[SDCC3],
+ },
+};
+
+static unsigned int sdc1_sup_clk_rates[] = {
+ 400000, 24000000, 48000000
+};
+
+static unsigned int sdc3_sup_clk_rates[] = {
+ 400000, 24000000, 48000000, 96000000
+};
+
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+static struct mmc_platform_data msm8960_sdc1_data = {
+ .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
+#ifdef CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT
+ .mmc_bus_width = MMC_CAP_8_BIT_DATA,
+#else
+ .mmc_bus_width = MMC_CAP_4_BIT_DATA,
+#endif
+ .sup_clk_table = sdc1_sup_clk_rates,
+ .sup_clk_cnt = ARRAY_SIZE(sdc1_sup_clk_rates),
+ .pclk_src_dfab = 1,
+ .nonremovable = 1,
+ .vreg_data = &mmc_slot_vreg_data[SDCC1],
+ .pin_data = &mmc_slot_pin_data[SDCC1]
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+static struct mmc_platform_data msm8960_sdc3_data = {
+ .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
+ .mmc_bus_width = MMC_CAP_4_BIT_DATA,
+ .sup_clk_table = sdc3_sup_clk_rates,
+ .sup_clk_cnt = ARRAY_SIZE(sdc3_sup_clk_rates),
+ .pclk_src_dfab = 1,
+#ifdef CONFIG_MMC_MSM_SDC3_WP_SUPPORT
+ .wpswitch_gpio = PM8921_GPIO_PM_TO_SYS(16),
+#endif
+ .vreg_data = &mmc_slot_vreg_data[SDCC3],
+ .pin_data = &mmc_slot_pin_data[SDCC3],
+#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
+ .status_gpio = PM8921_GPIO_PM_TO_SYS(26),
+ .status_irq = PM8921_GPIO_IRQ(PM8921_IRQ_BASE, 26),
+ .irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+#endif
+ .xpc_cap = 1,
+ .uhs_caps = (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 |
+ MMC_CAP_MAX_CURRENT_600)
+};
+#endif
+
+void __init msm8930_init_mmc(void)
+{
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+ /* SDC1 : eMMC card connected */
+ msm_add_sdcc(1, &msm8960_sdc1_data);
+#endif
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+ /* SDC3: External card slot */
+ msm_add_sdcc(3, &msm8960_sdc3_data);
+#endif
+}
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
new file mode 100644
index 0000000..cc020b5
--- /dev/null
+++ b/arch/arm/mach-msm/board-8930.c
@@ -0,0 +1,1985 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/i2c.h>
+#include <linux/i2c/sx150x.h>
+#include <linux/i2c/isl9519.h>
+#include <linux/gpio.h>
+#include <linux/msm_ssbi.h>
+#include <linux/regulator/gpio-regulator.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/slimbus/slimbus.h>
+#include <linux/bootmem.h>
+#include <linux/msm_kgsl.h>
+#ifdef CONFIG_ANDROID_PMEM
+#include <linux/android_pmem.h>
+#endif
+#include <linux/cyttsp.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_data/qcom_crypto_device.h>
+#include <linux/platform_data/qcom_wcnss_device.h>
+#include <linux/leds.h>
+#include <linux/leds-pm8xxx.h>
+#include <linux/i2c/atmel_mxt_ts.h>
+#include <linux/msm_tsens.h>
+#include <linux/ks8851.h>
+#include <linux/i2c/isa1200.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/setup.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/mmc.h>
+
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_spi.h>
+#ifdef CONFIG_USB_MSM_OTG_72K
+#include <mach/msm_hsusb.h>
+#else
+#include <linux/usb/msm_hsusb.h>
+#endif
+#include <linux/usb/android.h>
+#include <mach/usbdiag.h>
+#include <mach/socinfo.h>
+#include <mach/rpm.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_memtypes.h>
+#include <mach/dma.h>
+#include <mach/msm_xo.h>
+#include <mach/restart.h>
+
+#ifdef CONFIG_WCD9310_CODEC
+#include <linux/slimbus/slimbus.h>
+#include <linux/mfd/wcd9310/core.h>
+#include <linux/mfd/wcd9310/pdata.h>
+#endif
+
+#include <linux/ion.h>
+#include <mach/ion.h>
+#include <mach/mdm2.h>
+
+#include "timer.h"
+#include "devices.h"
+#include "devices-msm8x60.h"
+#include "spm.h"
+#include "board-8930.h"
+#include "pm.h"
+#include "cpuidle.h"
+#include "rpm_resources.h"
+#include "mpm.h"
+#include "acpuclock.h"
+#include "rpm_log.h"
+#include "smd_private.h"
+#include "pm-boot.h"
+#include "msm_watchdog.h"
+
+static struct platform_device msm_fm_platform_init = {
+ .name = "iris_fm",
+ .id = -1,
+};
+
+#define KS8851_RST_GPIO 89
+#define KS8851_IRQ_GPIO 90
+#define HAP_SHIFT_LVL_OE_GPIO 47
+
+#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
+
+struct sx150x_platform_data msm8930_sx150x_data[] = {
+ [SX150X_CAM] = {
+ .gpio_base = GPIO_CAM_EXPANDER_BASE,
+ .oscio_is_gpo = false,
+ .io_pullup_ena = 0x0,
+ .io_pulldn_ena = 0xc0,
+ .io_open_drain_ena = 0x0,
+ .irq_summary = -1,
+ },
+};
+
+#endif
+
+#define MSM_PMEM_ADSP_SIZE 0x3800000
+#define MSM_PMEM_AUDIO_SIZE 0x28B000
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+#define MSM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
+#else
+#define MSM_PMEM_SIZE 0x1C00000 /* 28 Mbytes */
+#endif
+
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+#define MSM_PMEM_KERNEL_EBI1_SIZE 0xB0C000
+#define MSM_ION_EBI_SIZE (MSM_PMEM_SIZE + 0x600000)
+#define MSM_ION_ADSP_SIZE MSM_PMEM_ADSP_SIZE
+#define MSM_ION_HEAP_NUM 4
+#else
+#define MSM_PMEM_KERNEL_EBI1_SIZE 0x110C000
+#define MSM_ION_HEAP_NUM 2
+#endif
+
+#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
+static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
+static int __init pmem_kernel_ebi1_size_setup(char *p)
+{
+ pmem_kernel_ebi1_size = memparse(p, NULL);
+ return 0;
+}
+early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+#endif
+
+#ifdef CONFIG_ANDROID_PMEM
+static unsigned pmem_size = MSM_PMEM_SIZE;
+static int __init pmem_size_setup(char *p)
+{
+ pmem_size = memparse(p, NULL);
+ return 0;
+}
+early_param("pmem_size", pmem_size_setup);
+
+static unsigned pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
+
+static int __init pmem_adsp_size_setup(char *p)
+{
+ pmem_adsp_size = memparse(p, NULL);
+ return 0;
+}
+early_param("pmem_adsp_size", pmem_adsp_size_setup);
+
+static unsigned pmem_audio_size = MSM_PMEM_AUDIO_SIZE;
+
+static int __init pmem_audio_size_setup(char *p)
+{
+ pmem_audio_size = memparse(p, NULL);
+ return 0;
+}
+early_param("pmem_audio_size", pmem_audio_size_setup);
+#endif
+
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+static struct android_pmem_platform_data android_pmem_pdata = {
+ .name = "pmem",
+ .allocator_type = PMEM_ALLOCATORTYPE_ALLORNOTHING,
+ .cached = 1,
+ .memory_type = MEMTYPE_EBI1,
+};
+
+static struct platform_device android_pmem_device = {
+ .name = "android_pmem",
+ .id = 0,
+ .dev = {.platform_data = &android_pmem_pdata},
+};
+
+static struct android_pmem_platform_data android_pmem_adsp_pdata = {
+ .name = "pmem_adsp",
+ .allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+ .cached = 0,
+ .memory_type = MEMTYPE_EBI1,
+};
+static struct platform_device android_pmem_adsp_device = {
+ .name = "android_pmem",
+ .id = 2,
+ .dev = { .platform_data = &android_pmem_adsp_pdata },
+};
+#endif
+
+static struct android_pmem_platform_data android_pmem_audio_pdata = {
+ .name = "pmem_audio",
+ .allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+ .cached = 0,
+ .memory_type = MEMTYPE_EBI1,
+};
+
+static struct platform_device android_pmem_audio_device = {
+ .name = "android_pmem",
+ .id = 4,
+ .dev = { .platform_data = &android_pmem_audio_pdata },
+};
+#endif
+
+#define DSP_RAM_BASE_8960 0x8da00000
+#define DSP_RAM_SIZE_8960 0x1800000
+static int dspcrashd_pdata_8960 = 0xDEADDEAD;
+
+static struct resource resources_dspcrashd_8960[] = {
+ {
+ .name = "msm_dspcrashd",
+ .start = DSP_RAM_BASE_8960,
+ .end = DSP_RAM_BASE_8960 + DSP_RAM_SIZE_8960,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+static struct platform_device msm_device_dspcrashd_8960 = {
+ .name = "msm_dspcrashd",
+ .num_resources = ARRAY_SIZE(resources_dspcrashd_8960),
+ .resource = resources_dspcrashd_8960,
+ .dev = { .platform_data = &dspcrashd_pdata_8960 },
+};
+
+static struct memtype_reserve msm8930_reserve_table[] __initdata = {
+ [MEMTYPE_SMI] = {
+ },
+ [MEMTYPE_EBI0] = {
+ .flags = MEMTYPE_FLAGS_1M_ALIGN,
+ },
+ [MEMTYPE_EBI1] = {
+ .flags = MEMTYPE_FLAGS_1M_ALIGN,
+ },
+};
+
+static void __init size_pmem_devices(void)
+{
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+ android_pmem_adsp_pdata.size = pmem_adsp_size;
+ android_pmem_pdata.size = pmem_size;
+#endif
+ android_pmem_audio_pdata.size = MSM_PMEM_AUDIO_SIZE;
+#endif
+}
+
+static void __init reserve_memory_for(struct android_pmem_platform_data *p)
+{
+ msm8930_reserve_table[p->memory_type].size += p->size;
+}
+
+static void __init reserve_pmem_memory(void)
+{
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+ reserve_memory_for(&android_pmem_adsp_pdata);
+ reserve_memory_for(&android_pmem_pdata);
+#endif
+ reserve_memory_for(&android_pmem_audio_pdata);
+ msm8930_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
+#endif
+}
+
+static int msm8930_paddr_to_memtype(unsigned int paddr)
+{
+ return MEMTYPE_EBI1;
+}
+
+#ifdef CONFIG_ION_MSM
+static struct ion_platform_data ion_pdata = {
+ .nr = MSM_ION_HEAP_NUM,
+ .heaps = {
+ {
+ .id = ION_HEAP_SYSTEM_ID,
+ .type = ION_HEAP_TYPE_SYSTEM,
+ .name = ION_KMALLOC_HEAP_NAME,
+ },
+ {
+ .id = ION_HEAP_SYSTEM_CONTIG_ID,
+ .type = ION_HEAP_TYPE_SYSTEM_CONTIG,
+ .name = ION_VMALLOC_HEAP_NAME,
+ },
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ {
+ .id = ION_HEAP_EBI_ID,
+ .type = ION_HEAP_TYPE_CARVEOUT,
+ .name = ION_EBI1_HEAP_NAME,
+ .size = MSM_ION_EBI_SIZE,
+ .memory_type = ION_EBI_TYPE,
+ },
+ {
+ .id = ION_HEAP_ADSP_ID,
+ .type = ION_HEAP_TYPE_CARVEOUT,
+ .name = ION_ADSP_HEAP_NAME,
+ .size = MSM_ION_ADSP_SIZE,
+ .memory_type = ION_EBI_TYPE,
+ },
+#endif
+ }
+};
+
+static struct platform_device ion_dev = {
+ .name = "ion-msm",
+ .id = 1,
+ .dev = { .platform_data = &ion_pdata },
+};
+#endif
+
+static void reserve_ion_memory(void)
+{
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+ msm8930_reserve_table[MEMTYPE_EBI1].size += MSM_ION_EBI_SIZE;
+ msm8930_reserve_table[MEMTYPE_EBI1].size += MSM_ION_ADSP_SIZE;
+#endif
+}
+static void __init msm8930_calculate_reserve_sizes(void)
+{
+ size_pmem_devices();
+ reserve_pmem_memory();
+ reserve_ion_memory();
+}
+
+static struct reserve_info msm8930_reserve_info __initdata = {
+ .memtype_reserve_table = msm8930_reserve_table,
+ .calculate_reserve_sizes = msm8930_calculate_reserve_sizes,
+ .paddr_to_memtype = msm8930_paddr_to_memtype,
+};
+
+static int msm8930_memory_bank_size(void)
+{
+ return 1<<29;
+}
+
+static void __init locate_unstable_memory(void)
+{
+ struct membank *mb = &meminfo.bank[meminfo.nr_banks - 1];
+ unsigned long bank_size;
+ unsigned long low, high;
+
+ bank_size = msm8930_memory_bank_size();
+ low = meminfo.bank[0].start;
+ high = mb->start + mb->size;
+
+ /* Check if 32 bit overflow occured */
+ if (high < mb->start)
+ high = ~0UL;
+
+ low &= ~(bank_size - 1);
+
+ if (high - low <= bank_size)
+ return;
+ msm8930_reserve_info.low_unstable_address = low + bank_size;
+ /* To avoid overflow of u32 compute max_unstable_size
+ * by first subtracting low from mb->start)
+ * */
+ msm8930_reserve_info.max_unstable_size = (mb->start - low) +
+ mb->size - bank_size;
+
+ msm8930_reserve_info.bank_size = bank_size;
+ pr_info("low unstable address %lx max size %lx bank size %lx\n",
+ msm8930_reserve_info.low_unstable_address,
+ msm8930_reserve_info.max_unstable_size,
+ msm8930_reserve_info.bank_size);
+}
+
+static void __init place_movable_zone(void)
+{
+ movable_reserved_start = msm8930_reserve_info.low_unstable_address;
+ movable_reserved_size = msm8930_reserve_info.max_unstable_size;
+ pr_info("movable zone start %lx size %lx\n",
+ movable_reserved_start, movable_reserved_size);
+}
+
+static void __init msm8930_early_memory(void)
+{
+ reserve_info = &msm8930_reserve_info;
+ locate_unstable_memory();
+ place_movable_zone();
+}
+
+static void __init msm8930_reserve(void)
+{
+ msm_reserve();
+}
+
+static int msm8930_change_memory_power(u64 start, u64 size,
+ int change_type)
+{
+ return soc_change_memory_power(start, size, change_type);
+}
+
+static void __init msm8930_allocate_memory_regions(void)
+{
+ msm8930_allocate_fb_region();
+}
+
+#ifdef CONFIG_WCD9310_CODEC
+
+#define TABLA_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS + NR_PM8921_IRQS)
+
+/* Micbias setting is based on 8660 CDP/MTP/FLUID requirement
+ * 4 micbiases are used to power various analog and digital
+ * microphones operating at 1800 mV. Technically, all micbiases
+ * can source from single cfilter since all microphones operate
+ * at the same voltage level. The arrangement below is to make
+ * sure all cfilters are exercised. LDO_H regulator ouput level
+ * does not need to be as high as 2.85V. It is choosen for
+ * microphone sensitivity purpose.
+ */
+static struct tabla_pdata tabla_platform_data = {
+ .slimbus_slave_device = {
+ .name = "tabla-slave",
+ .e_addr = {0, 0, 0x10, 0, 0x17, 2},
+ },
+ .irq = MSM_GPIO_TO_INT(62),
+ .irq_base = TABLA_INTERRUPT_BASE,
+ .num_irqs = NR_TABLA_IRQS,
+ .reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
+ .micbias = {
+ .ldoh_v = TABLA_LDOH_2P85_V,
+ .cfilt1_mv = 1800,
+ .cfilt2_mv = 1800,
+ .cfilt3_mv = 1800,
+ .bias1_cfilt_sel = TABLA_CFILT1_SEL,
+ .bias2_cfilt_sel = TABLA_CFILT2_SEL,
+ .bias3_cfilt_sel = TABLA_CFILT3_SEL,
+ .bias4_cfilt_sel = TABLA_CFILT3_SEL,
+ }
+};
+
+static struct slim_device msm_slim_tabla = {
+ .name = "tabla-slim",
+ .e_addr = {0, 1, 0x10, 0, 0x17, 2},
+ .dev = {
+ .platform_data = &tabla_platform_data,
+ },
+};
+
+static struct tabla_pdata tabla20_platform_data = {
+ .slimbus_slave_device = {
+ .name = "tabla-slave",
+ .e_addr = {0, 0, 0x60, 0, 0x17, 2},
+ },
+ .irq = MSM_GPIO_TO_INT(62),
+ .irq_base = TABLA_INTERRUPT_BASE,
+ .num_irqs = NR_TABLA_IRQS,
+ .reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
+ .micbias = {
+ .ldoh_v = TABLA_LDOH_2P85_V,
+ .cfilt1_mv = 1800,
+ .cfilt2_mv = 1800,
+ .cfilt3_mv = 1800,
+ .bias1_cfilt_sel = TABLA_CFILT1_SEL,
+ .bias2_cfilt_sel = TABLA_CFILT2_SEL,
+ .bias3_cfilt_sel = TABLA_CFILT3_SEL,
+ .bias4_cfilt_sel = TABLA_CFILT3_SEL,
+ }
+};
+
+static struct slim_device msm_slim_tabla20 = {
+ .name = "tabla2x-slim",
+ .e_addr = {0, 1, 0x60, 0, 0x17, 2},
+ .dev = {
+ .platform_data = &tabla20_platform_data,
+ },
+};
+#endif
+
+static struct slim_boardinfo msm_slim_devices[] = {
+#ifdef CONFIG_WCD9310_CODEC
+ {
+ .bus_num = 1,
+ .slim_slave = &msm_slim_tabla,
+ },
+ {
+ .bus_num = 1,
+ .slim_slave = &msm_slim_tabla20,
+ },
+#endif
+ /* add more slimbus slaves as needed */
+};
+
+#define MSM_WCNSS_PHYS 0x03000000
+#define MSM_WCNSS_SIZE 0x280000
+
+static struct resource resources_wcnss_wlan[] = {
+ {
+ .start = RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ,
+ .end = RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ,
+ .name = "wcnss_wlanrx_irq",
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ,
+ .end = RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ,
+ .name = "wcnss_wlantx_irq",
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = MSM_WCNSS_PHYS,
+ .end = MSM_WCNSS_PHYS + MSM_WCNSS_SIZE - 1,
+ .name = "wcnss_mmio",
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = 84,
+ .end = 88,
+ .name = "wcnss_gpios_5wire",
+ .flags = IORESOURCE_IO,
+ },
+};
+
+static struct qcom_wcnss_opts qcom_wcnss_pdata = {
+ .has_48mhz_xo = 1,
+};
+
+static struct platform_device msm_device_wcnss_wlan = {
+ .name = "wcnss_wlan",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(resources_wcnss_wlan),
+ .resource = resources_wcnss_wlan,
+ .dev = {.platform_data = &qcom_wcnss_pdata},
+};
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+ defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE) || \
+ defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+ defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+#define QCE_SIZE 0x10000
+#define QCE_0_BASE 0x18500000
+
+#define QCE_HW_KEY_SUPPORT 0
+#define QCE_SHA_HMAC_SUPPORT 1
+#define QCE_SHARE_CE_RESOURCE 1
+#define QCE_CE_SHARED 0
+
+static struct resource qcrypto_resources[] = {
+ [0] = {
+ .start = QCE_0_BASE,
+ .end = QCE_0_BASE + QCE_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "crypto_channels",
+ .start = DMOV_CE_IN_CHAN,
+ .end = DMOV_CE_OUT_CHAN,
+ .flags = IORESOURCE_DMA,
+ },
+ [2] = {
+ .name = "crypto_crci_in",
+ .start = DMOV_CE_IN_CRCI,
+ .end = DMOV_CE_IN_CRCI,
+ .flags = IORESOURCE_DMA,
+ },
+ [3] = {
+ .name = "crypto_crci_out",
+ .start = DMOV_CE_OUT_CRCI,
+ .end = DMOV_CE_OUT_CRCI,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+static struct resource qcedev_resources[] = {
+ [0] = {
+ .start = QCE_0_BASE,
+ .end = QCE_0_BASE + QCE_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "crypto_channels",
+ .start = DMOV_CE_IN_CHAN,
+ .end = DMOV_CE_OUT_CHAN,
+ .flags = IORESOURCE_DMA,
+ },
+ [2] = {
+ .name = "crypto_crci_in",
+ .start = DMOV_CE_IN_CRCI,
+ .end = DMOV_CE_IN_CRCI,
+ .flags = IORESOURCE_DMA,
+ },
+ [3] = {
+ .name = "crypto_crci_out",
+ .start = DMOV_CE_OUT_CRCI,
+ .end = DMOV_CE_OUT_CRCI,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+ defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+
+static struct msm_ce_hw_support qcrypto_ce_hw_suppport = {
+ .ce_shared = QCE_CE_SHARED,
+ .shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+ .hw_key_support = QCE_HW_KEY_SUPPORT,
+ .sha_hmac = QCE_SHA_HMAC_SUPPORT,
+};
+
+static struct platform_device qcrypto_device = {
+ .name = "qcrypto",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(qcrypto_resources),
+ .resource = qcrypto_resources,
+ .dev = {
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &qcrypto_ce_hw_suppport,
+ },
+};
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+ defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+static struct msm_ce_hw_support qcedev_ce_hw_suppport = {
+ .ce_shared = QCE_CE_SHARED,
+ .shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+ .hw_key_support = QCE_HW_KEY_SUPPORT,
+ .sha_hmac = QCE_SHA_HMAC_SUPPORT,
+};
+
+static struct platform_device qcedev_device = {
+ .name = "qce",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(qcedev_resources),
+ .resource = qcedev_resources,
+ .dev = {
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &qcedev_ce_hw_suppport,
+ },
+};
+#endif
+
+#define MDM2AP_ERRFATAL 70
+#define AP2MDM_ERRFATAL 95
+#define MDM2AP_STATUS 69
+#define AP2MDM_STATUS 94
+#define AP2MDM_PMIC_RESET_N 80
+#define AP2MDM_KPDPWR_N 81
+
+static struct resource mdm_resources[] = {
+ {
+ .start = MDM2AP_ERRFATAL,
+ .end = MDM2AP_ERRFATAL,
+ .name = "MDM2AP_ERRFATAL",
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .start = AP2MDM_ERRFATAL,
+ .end = AP2MDM_ERRFATAL,
+ .name = "AP2MDM_ERRFATAL",
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .start = MDM2AP_STATUS,
+ .end = MDM2AP_STATUS,
+ .name = "MDM2AP_STATUS",
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .start = AP2MDM_STATUS,
+ .end = AP2MDM_STATUS,
+ .name = "AP2MDM_STATUS",
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .start = AP2MDM_PMIC_RESET_N,
+ .end = AP2MDM_PMIC_RESET_N,
+ .name = "AP2MDM_PMIC_RESET_N",
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .start = AP2MDM_KPDPWR_N,
+ .end = AP2MDM_KPDPWR_N,
+ .name = "AP2MDM_KPDPWR_N",
+ .flags = IORESOURCE_IO,
+ },
+};
+
+static struct mdm_platform_data mdm_platform_data = {
+ .mdm_version = "2.5",
+};
+
+static struct platform_device mdm_device = {
+ .name = "mdm2_modem",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(mdm_resources),
+ .resource = mdm_resources,
+ .dev = {
+ .platform_data = &mdm_platform_data,
+ },
+};
+
+static struct platform_device *mdm_devices[] __initdata = {
+ &mdm_device,
+};
+
+#define MSM_SHARED_RAM_PHYS 0x80000000
+
+static void __init msm8930_map_io(void)
+{
+ msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
+ msm_map_msm8930_io();
+
+ if (socinfo_init() < 0)
+ pr_err("socinfo_init() failed!\n");
+}
+
+static void __init msm8930_init_irq(void)
+{
+ unsigned int i;
+
+ msm_mpm_irq_extn_init();
+ gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
+ (void *)MSM_QGIC_CPU_BASE);
+
+ /* Edge trigger PPIs except AVS_SVICINT and AVS_SVICINTSWDONE */
+ writel_relaxed(0xFFFFD7FF, MSM_QGIC_DIST_BASE + GIC_DIST_CONFIG + 4);
+
+ writel_relaxed(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
+ mb();
+
+ /* FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
+ * as they are configured as level, which does not play nice with
+ * handle_percpu_irq.
+ */
+ for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
+ if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
+ irq_set_handler(i, handle_percpu_irq);
+ }
+}
+
+static void __init msm8930_init_buses(void)
+{
+#ifdef CONFIG_MSM_BUS_SCALING
+ msm_bus_rpm_set_mt_mask();
+ msm_bus_8960_apps_fabric_pdata.rpm_enabled = 1;
+ msm_bus_8960_sys_fabric_pdata.rpm_enabled = 1;
+ msm_bus_8960_mm_fabric_pdata.rpm_enabled = 1;
+ msm_bus_apps_fabric.dev.platform_data =
+ &msm_bus_8960_apps_fabric_pdata;
+ msm_bus_sys_fabric.dev.platform_data = &msm_bus_8960_sys_fabric_pdata;
+ msm_bus_mm_fabric.dev.platform_data = &msm_bus_8960_mm_fabric_pdata;
+ msm_bus_sys_fpb.dev.platform_data = &msm_bus_8960_sys_fpb_pdata;
+ msm_bus_cpss_fpb.dev.platform_data = &msm_bus_8960_cpss_fpb_pdata;
+#endif
+}
+
+static struct msm_spi_platform_data msm8960_qup_spi_gsbi1_pdata = {
+ .max_clock_speed = 15060000,
+};
+
+#ifdef CONFIG_USB_MSM_OTG_72K
+static struct msm_otg_platform_data msm_otg_pdata;
+#else
+#define USB_5V_EN 42
+static void msm_hsusb_vbus_power(bool on)
+{
+ int rc;
+ static bool vbus_is_on;
+ static struct regulator *mvs_otg_switch;
+
+ if (vbus_is_on == on)
+ return;
+
+ if (on) {
+ mvs_otg_switch = regulator_get(&msm8960_device_otg.dev,
+ "vbus_otg");
+ if (IS_ERR(mvs_otg_switch)) {
+ pr_err("Unable to get mvs_otg_switch\n");
+ return;
+ }
+
+ rc = gpio_request(PM8921_GPIO_PM_TO_SYS(USB_5V_EN),
+ "usb_5v_en");
+ if (rc < 0) {
+ pr_err("failed to request usb_5v_en gpio\n");
+ goto put_mvs_otg;
+ }
+
+ rc = gpio_direction_output(PM8921_GPIO_PM_TO_SYS(USB_5V_EN), 1);
+ if (rc) {
+ pr_err("%s: unable to set_direction for gpio [%d]\n",
+ __func__, PM8921_GPIO_PM_TO_SYS(USB_5V_EN));
+ goto free_usb_5v_en;
+ }
+
+ if (regulator_enable(mvs_otg_switch)) {
+ pr_err("unable to enable mvs_otg_switch\n");
+ goto err_ldo_gpio_set_dir;
+ }
+
+ vbus_is_on = true;
+ return;
+ }
+ regulator_disable(mvs_otg_switch);
+err_ldo_gpio_set_dir:
+ gpio_set_value(PM8921_GPIO_PM_TO_SYS(USB_5V_EN), 0);
+free_usb_5v_en:
+ gpio_free(PM8921_GPIO_PM_TO_SYS(USB_5V_EN));
+put_mvs_otg:
+ regulator_put(mvs_otg_switch);
+ vbus_is_on = false;
+}
+
+static struct msm_otg_platform_data msm_otg_pdata = {
+ .mode = USB_OTG,
+ .otg_control = OTG_PMIC_CONTROL,
+ .phy_type = SNPS_28NM_INTEGRATED_PHY,
+ .pclk_src_name = "dfab_usb_hs_clk",
+ .pmic_id_irq = PM8921_USB_ID_IN_IRQ(PM8921_IRQ_BASE),
+ .vbus_power = msm_hsusb_vbus_power,
+ .power_budget = 750,
+};
+#endif
+
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+#define HSIC_HUB_RESET_GPIO 91
+static struct msm_hsic_host_platform_data msm_hsic_pdata = {
+ .strobe = 150,
+ .data = 151,
+};
+#else
+static struct msm_hsic_host_platform_data msm_hsic_pdata;
+#endif
+
+#define PID_MAGIC_ID 0x71432909
+#define SERIAL_NUM_MAGIC_ID 0x61945374
+#define SERIAL_NUMBER_LENGTH 127
+#define DLOAD_USB_BASE_ADD 0x2A03F0C8
+
+struct magic_num_struct {
+ uint32_t pid;
+ uint32_t serial_num;
+};
+
+struct dload_struct {
+ uint32_t reserved1;
+ uint32_t reserved2;
+ uint32_t reserved3;
+ uint16_t reserved4;
+ uint16_t pid;
+ char serial_number[SERIAL_NUMBER_LENGTH];
+ uint16_t reserved5;
+ struct magic_num_struct magic_struct;
+};
+
+static int usb_diag_update_pid_and_serial_num(uint32_t pid, const char *snum)
+{
+ struct dload_struct __iomem *dload = 0;
+
+ dload = ioremap(DLOAD_USB_BASE_ADD, sizeof(*dload));
+ if (!dload) {
+ pr_err("%s: cannot remap I/O memory region: %08x\n",
+ __func__, DLOAD_USB_BASE_ADD);
+ return -ENXIO;
+ }
+
+ pr_debug("%s: dload:%p pid:%x serial_num:%s\n",
+ __func__, dload, pid, snum);
+ /* update pid */
+ dload->magic_struct.pid = PID_MAGIC_ID;
+ dload->pid = pid;
+
+ /* update serial number */
+ dload->magic_struct.serial_num = 0;
+ if (!snum) {
+ memset(dload->serial_number, 0, SERIAL_NUMBER_LENGTH);
+ goto out;
+ }
+
+ dload->magic_struct.serial_num = SERIAL_NUM_MAGIC_ID;
+ strlcpy(dload->serial_number, snum, SERIAL_NUMBER_LENGTH);
+out:
+ iounmap(dload);
+ return 0;
+}
+
+static struct android_usb_platform_data android_usb_pdata = {
+ .update_pid_and_serial_num = usb_diag_update_pid_and_serial_num,
+};
+
+static struct platform_device android_usb_device = {
+ .name = "android_usb",
+ .id = -1,
+ .dev = {
+ .platform_data = &android_usb_pdata,
+ },
+};
+
+static uint8_t spm_wfi_cmd_sequence[] __initdata = {
+ 0x03, 0x0f,
+};
+
+static uint8_t spm_power_collapse_without_rpm[] __initdata = {
+ 0x00, 0x24, 0x54, 0x10,
+ 0x09, 0x03, 0x01,
+ 0x10, 0x54, 0x30, 0x0C,
+ 0x24, 0x30, 0x0f,
+};
+
+static uint8_t spm_power_collapse_with_rpm[] __initdata = {
+ 0x00, 0x24, 0x54, 0x10,
+ 0x09, 0x07, 0x01, 0x0B,
+ 0x10, 0x54, 0x30, 0x0C,
+ 0x24, 0x30, 0x0f,
+};
+
+static struct msm_spm_seq_entry msm_spm_seq_list[] __initdata = {
+ [0] = {
+ .mode = MSM_SPM_MODE_CLOCK_GATING,
+ .notify_rpm = false,
+ .cmd = spm_wfi_cmd_sequence,
+ },
+ [1] = {
+ .mode = MSM_SPM_MODE_POWER_COLLAPSE,
+ .notify_rpm = false,
+ .cmd = spm_power_collapse_without_rpm,
+ },
+ [2] = {
+ .mode = MSM_SPM_MODE_POWER_COLLAPSE,
+ .notify_rpm = true,
+ .cmd = spm_power_collapse_with_rpm,
+ },
+};
+
+static struct msm_spm_platform_data msm_spm_data[] __initdata = {
+ [0] = {
+ .reg_base_addr = MSM_SAW0_BASE,
+ .reg_init_values[MSM_SPM_REG_SAW2_SECURE] = 0x00,
+ .reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
+ .reg_init_values[MSM_SPM_REG_SAW2_VCTL] = 0x9C,
+#if defined(CONFIG_MSM_AVS_HW)
+ .reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x00,
+ .reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
+#endif
+ .reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020202,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
+ .vctl_timeout_us = 50,
+ .num_modes = ARRAY_SIZE(msm_spm_seq_list),
+ .modes = msm_spm_seq_list,
+ },
+ [1] = {
+ .reg_base_addr = MSM_SAW1_BASE,
+ .reg_init_values[MSM_SPM_REG_SAW2_SECURE] = 0x00,
+ .reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
+ .reg_init_values[MSM_SPM_REG_SAW2_VCTL] = 0x9C,
+#if defined(CONFIG_MSM_AVS_HW)
+ .reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x00,
+ .reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
+#endif
+ .reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020202,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
+ .vctl_timeout_us = 50,
+ .num_modes = ARRAY_SIZE(msm_spm_seq_list),
+ .modes = msm_spm_seq_list,
+ },
+};
+
+static uint8_t l2_spm_wfi_cmd_sequence[] __initdata = {
+ 0x00, 0x20, 0x03, 0x20,
+ 0x00, 0x0f,
+};
+
+static uint8_t l2_spm_gdhs_cmd_sequence[] __initdata = {
+ 0x00, 0x20, 0x34, 0x64,
+ 0x48, 0x07, 0x48, 0x20,
+ 0x50, 0x64, 0x04, 0x34,
+ 0x50, 0x0f,
+};
+static uint8_t l2_spm_power_off_cmd_sequence[] __initdata = {
+ 0x00, 0x10, 0x34, 0x64,
+ 0x48, 0x07, 0x48, 0x10,
+ 0x50, 0x64, 0x04, 0x34,
+ 0x50, 0x0F,
+};
+
+static struct msm_spm_seq_entry msm_spm_l2_seq_list[] __initdata = {
+ [0] = {
+ .mode = MSM_SPM_L2_MODE_RETENTION,
+ .notify_rpm = false,
+ .cmd = l2_spm_wfi_cmd_sequence,
+ },
+ [1] = {
+ .mode = MSM_SPM_L2_MODE_GDHS,
+ .notify_rpm = true,
+ .cmd = l2_spm_gdhs_cmd_sequence,
+ },
+ [2] = {
+ .mode = MSM_SPM_L2_MODE_POWER_COLLAPSE,
+ .notify_rpm = true,
+ .cmd = l2_spm_power_off_cmd_sequence,
+ },
+};
+
+static struct msm_spm_platform_data msm_spm_l2_data[] __initdata = {
+ [0] = {
+ .reg_base_addr = MSM_SAW_L2_BASE,
+ .reg_init_values[MSM_SPM_REG_SAW2_SECURE] = 0x00,
+ .reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x00,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020202,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x00A000AE,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x00A00020,
+ .modes = msm_spm_l2_seq_list,
+ .num_modes = ARRAY_SIZE(msm_spm_l2_seq_list),
+ },
+};
+
+#define PM_HAP_EN_GPIO PM8921_GPIO_PM_TO_SYS(33)
+#define PM_HAP_LEN_GPIO PM8921_GPIO_PM_TO_SYS(20)
+
+static struct msm_xo_voter *xo_handle_d1;
+
+static int isa1200_power(int on)
+{
+ int rc = 0;
+
+ gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !!on);
+
+ rc = on ? msm_xo_mode_vote(xo_handle_d1, MSM_XO_MODE_ON) :
+ msm_xo_mode_vote(xo_handle_d1, MSM_XO_MODE_OFF);
+ if (rc < 0) {
+ pr_err("%s: failed to %svote for TCXO D1 buffer%d\n",
+ __func__, on ? "" : "de-", rc);
+ goto err_xo_vote;
+ }
+
+ return 0;
+
+err_xo_vote:
+ gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !on);
+ return rc;
+}
+
+static int isa1200_dev_setup(bool enable)
+{
+ int rc = 0;
+
+ struct pm_gpio hap_gpio_config = {
+ .direction = PM_GPIO_DIR_OUT,
+ .pull = PM_GPIO_PULL_NO,
+ .out_strength = PM_GPIO_STRENGTH_HIGH,
+ .function = PM_GPIO_FUNC_NORMAL,
+ .inv_int_pol = 0,
+ .vin_sel = 2,
+ .output_buffer = PM_GPIO_OUT_BUF_CMOS,
+ .output_value = 0,
+ };
+
+ if (enable == true) {
+ rc = pm8xxx_gpio_config(PM_HAP_EN_GPIO, &hap_gpio_config);
+ if (rc) {
+ pr_err("%s: pm8921 gpio %d config failed(%d)\n",
+ __func__, PM_HAP_EN_GPIO, rc);
+ return rc;
+ }
+
+ rc = pm8xxx_gpio_config(PM_HAP_LEN_GPIO, &hap_gpio_config);
+ if (rc) {
+ pr_err("%s: pm8921 gpio %d config failed(%d)\n",
+ __func__, PM_HAP_LEN_GPIO, rc);
+ return rc;
+ }
+
+ rc = gpio_request(HAP_SHIFT_LVL_OE_GPIO, "hap_shft_lvl_oe");
+ if (rc) {
+ pr_err("%s: unable to request gpio %d (%d)\n",
+ __func__, HAP_SHIFT_LVL_OE_GPIO, rc);
+ return rc;
+ }
+
+ rc = gpio_direction_output(HAP_SHIFT_LVL_OE_GPIO, 0);
+ if (rc) {
+ pr_err("%s: Unable to set direction\n", __func__);
+ goto free_gpio;
+ }
+
+ xo_handle_d1 = msm_xo_get(MSM_XO_TCXO_D1, "isa1200");
+ if (IS_ERR(xo_handle_d1)) {
+ rc = PTR_ERR(xo_handle_d1);
+ pr_err("%s: failed to get the handle for D1(%d)\n",
+ __func__, rc);
+ goto gpio_set_dir;
+ }
+ } else {
+ gpio_free(HAP_SHIFT_LVL_OE_GPIO);
+
+ msm_xo_put(xo_handle_d1);
+ }
+
+ return 0;
+
+gpio_set_dir:
+ gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, 0);
+free_gpio:
+ gpio_free(HAP_SHIFT_LVL_OE_GPIO);
+ return rc;
+}
+
+static struct isa1200_regulator isa1200_reg_data[] = {
+ {
+ .name = "vcc_i2c",
+ .min_uV = ISA_I2C_VTG_MIN_UV,
+ .max_uV = ISA_I2C_VTG_MAX_UV,
+ .load_uA = ISA_I2C_CURR_UA,
+ },
+};
+
+static struct isa1200_platform_data isa1200_1_pdata = {
+ .name = "vibrator",
+ .dev_setup = isa1200_dev_setup,
+ .power_on = isa1200_power,
+ .hap_en_gpio = PM_HAP_EN_GPIO,
+ .hap_len_gpio = PM_HAP_LEN_GPIO,
+ .max_timeout = 15000,
+ .mode_ctrl = PWM_GEN_MODE,
+ .pwm_fd = {
+ .pwm_div = 256,
+ },
+ .is_erm = false,
+ .smart_en = true,
+ .ext_clk_en = true,
+ .chip_en = 1,
+ .regulator_info = isa1200_reg_data,
+ .num_regulators = ARRAY_SIZE(isa1200_reg_data),
+};
+
+static struct i2c_board_info msm_isa1200_board_info[] __initdata = {
+ {
+ I2C_BOARD_INFO("isa1200_1", 0x90>>1),
+ .platform_data = &isa1200_1_pdata,
+ },
+};
+
+#define CYTTSP_TS_GPIO_IRQ 11
+#define CYTTSP_TS_SLEEP_GPIO 50
+#define CYTTSP_TS_RESOUT_N_GPIO 52
+
+/*virtual key support */
+static ssize_t tma340_vkeys_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return snprintf(buf, 200,
+ __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":73:1120:97:97"
+ ":" __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":230:1120:97:97"
+ ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":389:1120:97:97"
+ ":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":544:1120:97:97"
+ "\n");
+}
+
+static struct kobj_attribute tma340_vkeys_attr = {
+ .attr = {
+ .mode = S_IRUGO,
+ },
+ .show = &tma340_vkeys_show,
+};
+
+static struct attribute *tma340_properties_attrs[] = {
+ &tma340_vkeys_attr.attr,
+ NULL
+};
+
+static struct attribute_group tma340_properties_attr_group = {
+ .attrs = tma340_properties_attrs,
+};
+
+
+static int cyttsp_platform_init(struct i2c_client *client)
+{
+ int rc = 0;
+ static struct kobject *tma340_properties_kobj;
+
+ tma340_vkeys_attr.attr.name = "virtualkeys.cyttsp-i2c";
+ tma340_properties_kobj = kobject_create_and_add("board_properties",
+ NULL);
+ if (tma340_properties_kobj)
+ rc = sysfs_create_group(tma340_properties_kobj,
+ &tma340_properties_attr_group);
+ if (!tma340_properties_kobj || rc)
+ pr_err("%s: failed to create board_properties\n",
+ __func__);
+
+ return 0;
+}
+
+static struct cyttsp_regulator regulator_data[] = {
+ {
+ .name = "vdd",
+ .min_uV = CY_TMA300_VTG_MIN_UV,
+ .max_uV = CY_TMA300_VTG_MAX_UV,
+ .hpm_load_uA = CY_TMA300_CURR_24HZ_UA,
+ .lpm_load_uA = CY_TMA300_SLEEP_CURR_UA,
+ },
+ /* TODO: Remove after runtime PM is enabled in I2C driver */
+ {
+ .name = "vcc_i2c",
+ .min_uV = CY_I2C_VTG_MIN_UV,
+ .max_uV = CY_I2C_VTG_MAX_UV,
+ .hpm_load_uA = CY_I2C_CURR_UA,
+ .lpm_load_uA = CY_I2C_SLEEP_CURR_UA,
+ },
+};
+
+static struct cyttsp_platform_data cyttsp_pdata = {
+ .panel_maxx = 634,
+ .panel_maxy = 1166,
+ .disp_maxx = 616,
+ .disp_maxy = 1023,
+ .disp_minx = 0,
+ .disp_miny = 16,
+ .flags = 0x01,
+ .gen = CY_GEN3, /* or */
+ .use_st = CY_USE_ST,
+ .use_mt = CY_USE_MT,
+ .use_hndshk = CY_SEND_HNDSHK,
+ .use_trk_id = CY_USE_TRACKING_ID,
+ .use_sleep = CY_USE_DEEP_SLEEP_SEL | CY_USE_LOW_POWER_SEL,
+ .use_gestures = CY_USE_GESTURES,
+ .fw_fname = "cyttsp_8960_cdp.hex",
+ /* activate up to 4 groups
+ * and set active distance
+ */
+ .gest_set = CY_GEST_GRP1 | CY_GEST_GRP2 |
+ CY_GEST_GRP3 | CY_GEST_GRP4 |
+ CY_ACT_DIST,
+ /* change act_intrvl to customize the Active power state
+ * scanning/processing refresh interval for Operating mode
+ */
+ .act_intrvl = CY_ACT_INTRVL_DFLT,
+ /* change tch_tmout to customize the touch timeout for the
+ * Active power state for Operating mode
+ */
+ .tch_tmout = CY_TCH_TMOUT_DFLT,
+ /* change lp_intrvl to customize the Low Power power state
+ * scanning/processing refresh interval for Operating mode
+ */
+ .lp_intrvl = CY_LP_INTRVL_DFLT,
+ .sleep_gpio = CYTTSP_TS_SLEEP_GPIO,
+ .resout_gpio = CYTTSP_TS_RESOUT_N_GPIO,
+ .irq_gpio = CYTTSP_TS_GPIO_IRQ,
+ .regulator_info = regulator_data,
+ .num_regulators = ARRAY_SIZE(regulator_data),
+ .init = cyttsp_platform_init,
+ .correct_fw_ver = 9,
+};
+
+static struct i2c_board_info cyttsp_info[] __initdata = {
+ {
+ I2C_BOARD_INFO(CY_I2C_NAME, 0x24),
+ .platform_data = &cyttsp_pdata,
+#ifndef CY_USE_TIMER
+ .irq = MSM_GPIO_TO_INT(CYTTSP_TS_GPIO_IRQ),
+#endif /* CY_USE_TIMER */
+ },
+};
+
+/* configuration data */
+static const u8 mxt_config_data[] = {
+ /* T6 Object */
+ 0, 0, 0, 0, 0, 0,
+ /* T38 Object */
+ 11, 2, 0, 11, 11, 11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ /* T7 Object */
+ 100, 16, 50,
+ /* T8 Object */
+ 8, 0, 0, 0, 0, 0, 8, 14, 50, 215,
+ /* T9 Object */
+ 131, 0, 0, 26, 42, 0, 32, 63, 3, 5,
+ 0, 2, 1, 113, 10, 10, 8, 10, 255, 2,
+ 85, 5, 0, 0, 20, 20, 75, 25, 202, 29,
+ 10, 10, 45, 46,
+ /* T15 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+ /* T22 Object */
+ 5, 0, 0, 0, 0, 0, 0, 0, 30, 0,
+ 0, 0, 5, 8, 10, 13, 0,
+ /* T24 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* T25 Object */
+ 3, 0, 188, 52, 52, 33, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ /* T27 Object */
+ 0, 0, 0, 0, 0, 0, 0,
+ /* T28 Object */
+ 0, 0, 0, 8, 12, 60,
+ /* T40 Object */
+ 0, 0, 0, 0, 0,
+ /* T41 Object */
+ 0, 0, 0, 0, 0, 0,
+ /* T43 Object */
+ 0, 0, 0, 0, 0, 0,
+};
+
+#define MXT_TS_GPIO_IRQ 11
+#define MXT_TS_LDO_EN_GPIO 50
+#define MXT_TS_RESET_GPIO 52
+
+static struct mxt_platform_data mxt_platform_data = {
+ .config = mxt_config_data,
+ .config_length = ARRAY_SIZE(mxt_config_data),
+ .x_size = 1365,
+ .y_size = 767,
+ .irqflags = IRQF_TRIGGER_FALLING,
+ .i2c_pull_up = true,
+};
+
+static struct i2c_board_info mxt_device_info[] __initdata = {
+ {
+ I2C_BOARD_INFO("atmel_mxt_ts", 0x5b),
+ .platform_data = &mxt_platform_data,
+ .irq = MSM_GPIO_TO_INT(MXT_TS_GPIO_IRQ),
+ },
+};
+
+static void gsbi_qup_i2c_gpio_config(int adap_id, int config_type)
+{
+}
+
+static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi4_pdata = {
+ .clk_freq = 100000,
+ .src_clk_rate = 24000000,
+ .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
+};
+
+static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi3_pdata = {
+ .clk_freq = 100000,
+ .src_clk_rate = 24000000,
+ .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
+};
+
+static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi10_pdata = {
+ .clk_freq = 100000,
+ .src_clk_rate = 24000000,
+ .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
+};
+
+static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi12_pdata = {
+ .clk_freq = 100000,
+ .src_clk_rate = 24000000,
+ .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
+};
+
+static struct msm_rpm_platform_data msm_rpm_data = {
+ .reg_base_addrs = {
+ [MSM_RPM_PAGE_STATUS] = MSM_RPM_BASE,
+ [MSM_RPM_PAGE_CTRL] = MSM_RPM_BASE + 0x400,
+ [MSM_RPM_PAGE_REQ] = MSM_RPM_BASE + 0x600,
+ [MSM_RPM_PAGE_ACK] = MSM_RPM_BASE + 0xa00,
+ },
+
+ .irq_ack = RPM_APCC_CPU0_GP_HIGH_IRQ,
+ .irq_err = RPM_APCC_CPU0_GP_LOW_IRQ,
+ .irq_vmpm = RPM_APCC_CPU0_GP_MEDIUM_IRQ,
+ .msm_apps_ipc_rpm_reg = MSM_APCS_GCC_BASE + 0x008,
+ .msm_apps_ipc_rpm_val = 4,
+};
+
+static struct ks8851_pdata spi_eth_pdata = {
+ .irq_gpio = KS8851_IRQ_GPIO,
+ .rst_gpio = KS8851_RST_GPIO,
+};
+
+static struct spi_board_info spi_board_info[] __initdata = {
+ {
+ .modalias = "ks8851",
+ .irq = MSM_GPIO_TO_INT(KS8851_IRQ_GPIO),
+ .max_speed_hz = 19200000,
+ .bus_num = 0,
+ .chip_select = 0,
+ .mode = SPI_MODE_0,
+ .platform_data = &spi_eth_pdata
+ },
+ {
+ .modalias = "dsi_novatek_3d_panel_spi",
+ .max_speed_hz = 10800000,
+ .bus_num = 0,
+ .chip_select = 1,
+ .mode = SPI_MODE_0,
+ },
+};
+
+static struct platform_device msm_device_saw_core0 = {
+ .name = "saw-regulator",
+ .id = 0,
+ .dev = {
+ .platform_data = &msm_saw_regulator_pdata_s5,
+ },
+};
+
+static struct platform_device msm_device_saw_core1 = {
+ .name = "saw-regulator",
+ .id = 1,
+ .dev = {
+ .platform_data = &msm_saw_regulator_pdata_s6,
+ },
+};
+
+static struct tsens_platform_data msm_tsens_pdata = {
+ .slope = 910,
+ .tsens_factor = 1000,
+ .hw_type = MSM_8960,
+ .tsens_num_sensor = 5,
+};
+
+static struct platform_device msm_tsens_device = {
+ .name = "tsens8960-tm",
+ .id = -1,
+ .dev = {
+ .platform_data = &msm_tsens_pdata,
+ },
+};
+
+#ifdef CONFIG_MSM_FAKE_BATTERY
+static struct platform_device fish_battery_device = {
+ .name = "fish_battery",
+};
+#endif
+
+static struct platform_device msm8960_device_ext_5v_vreg __devinitdata = {
+ .name = GPIO_REGULATOR_DEV_NAME,
+ .id = PM8921_MPP_PM_TO_SYS(7),
+ .dev = {
+ .platform_data = &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_5V],
+ },
+};
+
+static struct platform_device msm8960_device_ext_l2_vreg __devinitdata = {
+ .name = GPIO_REGULATOR_DEV_NAME,
+ .id = 91,
+ .dev = {
+ .platform_data = &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_L2],
+ },
+};
+
+static struct platform_device msm8960_device_rpm_regulator __devinitdata = {
+ .name = "rpm-regulator",
+ .id = -1,
+ .dev = {
+ .platform_data = &msm_rpm_regulator_pdata,
+ },
+};
+
+static struct msm_rpm_log_platform_data msm_rpm_log_pdata = {
+ .phys_addr_base = 0x0010C000,
+ .reg_offsets = {
+ [MSM_RPM_LOG_PAGE_INDICES] = 0x00000080,
+ [MSM_RPM_LOG_PAGE_BUFFER] = 0x000000A0,
+ },
+ .phys_size = SZ_8K,
+ .log_len = 4096, /* log's buffer length in bytes */
+ .log_len_mask = (4096 >> 2) - 1, /* length mask in units of u32 */
+};
+
+static struct platform_device msm_rpm_log_device = {
+ .name = "msm_rpm_log",
+ .id = -1,
+ .dev = {
+ .platform_data = &msm_rpm_log_pdata,
+ },
+};
+
+static struct platform_device *common_devices[] __initdata = {
+ &msm8960_device_dmov,
+ &msm_device_smd,
+ &msm8960_device_uart_gsbi5,
+ &msm_device_uart_dm6,
+ &msm_device_saw_core0,
+ &msm_device_saw_core1,
+ &msm8960_device_ext_5v_vreg,
+ &msm8960_device_ext_l2_vreg,
+ &msm8960_device_ssbi_pm8921,
+ &msm8960_device_qup_spi_gsbi1,
+ &msm8960_device_qup_i2c_gsbi3,
+ &msm8960_device_qup_i2c_gsbi4,
+ &msm8960_device_qup_i2c_gsbi10,
+ &msm8960_device_qup_i2c_gsbi12,
+ &msm_slim_ctrl,
+ &msm_device_wcnss_wlan,
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+ defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+ &qcrypto_device,
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+ defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+ &qcedev_device,
+#endif
+#ifdef CONFIG_MSM_ROTATOR
+ &msm_rotator_device,
+#endif
+ &msm_device_sps,
+#ifdef CONFIG_MSM_FAKE_BATTERY
+ &fish_battery_device,
+#endif
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+ &android_pmem_device,
+ &android_pmem_adsp_device,
+#endif
+ &android_pmem_audio_device,
+#endif
+ &msm_device_vidc,
+ &msm_device_bam_dmux,
+ &msm_fm_platform_init,
+
+#ifdef CONFIG_HW_RANDOM_MSM
+ &msm_device_rng,
+#endif
+ &msm_rpm_device,
+#ifdef CONFIG_ION_MSM
+ &ion_dev,
+#endif
+ &msm_rpm_log_device,
+ &msm_rpm_stat_device,
+ &msm_device_tz_log,
+
+#ifdef CONFIG_MSM_QDSS
+ &msm_etb_device,
+ &msm_tpiu_device,
+ &msm_funnel_device,
+ &msm_debug_device,
+ &msm_ptm_device,
+#endif
+ &msm_device_dspcrashd_8960,
+ &msm8960_device_watchdog,
+};
+
+static struct platform_device *cdp_devices[] __initdata = {
+ &msm8960_device_otg,
+ &msm8960_device_gadget_peripheral,
+ &msm_device_hsusb_host,
+ &android_usb_device,
+ &msm_pcm,
+ &msm_pcm_routing,
+ &msm_cpudai0,
+ &msm_cpudai1,
+ &msm_cpudai_hdmi_rx,
+ &msm_cpudai_bt_rx,
+ &msm_cpudai_bt_tx,
+ &msm_cpudai_fm_rx,
+ &msm_cpudai_fm_tx,
+ &msm_cpudai_auxpcm_rx,
+ &msm_cpudai_auxpcm_tx,
+ &msm_cpu_fe,
+ &msm_stub_codec,
+ &msm_kgsl_3d0,
+#ifdef CONFIG_MSM_KGSL_2D
+ &msm_kgsl_2d0,
+ &msm_kgsl_2d1,
+#endif
+#ifdef CONFIG_MSM_GEMINI
+ &msm8960_gemini_device,
+#endif
+ &msm_voice,
+ &msm_voip,
+ &msm_lpa_pcm,
+ &msm_cpudai_afe_01_rx,
+ &msm_cpudai_afe_01_tx,
+ &msm_cpudai_afe_02_rx,
+ &msm_cpudai_afe_02_tx,
+ &msm_pcm_afe,
+ &msm_pcm_hostless,
+ &msm_bus_apps_fabric,
+ &msm_bus_sys_fabric,
+ &msm_bus_mm_fabric,
+ &msm_bus_sys_fpb,
+ &msm_bus_cpss_fpb,
+ &msm_tsens_device,
+};
+
+static void __init msm8930_i2c_init(void)
+{
+ msm8960_device_qup_i2c_gsbi4.dev.platform_data =
+ &msm8960_i2c_qup_gsbi4_pdata;
+
+ msm8960_device_qup_i2c_gsbi3.dev.platform_data =
+ &msm8960_i2c_qup_gsbi3_pdata;
+
+ msm8960_device_qup_i2c_gsbi10.dev.platform_data =
+ &msm8960_i2c_qup_gsbi10_pdata;
+
+ msm8960_device_qup_i2c_gsbi12.dev.platform_data =
+ &msm8960_i2c_qup_gsbi12_pdata;
+}
+
+static void __init msm8930_gfx_init(void)
+{
+ uint32_t soc_platform_version = socinfo_get_version();
+ if (SOCINFO_VERSION_MAJOR(soc_platform_version) == 1) {
+ struct kgsl_device_platform_data *kgsl_3d0_pdata =
+ msm_kgsl_3d0.dev.platform_data;
+ kgsl_3d0_pdata->pwrlevel[0].gpu_freq = 320000000;
+ kgsl_3d0_pdata->pwrlevel[1].gpu_freq = 266667000;
+ }
+}
+
+static struct msm_cpuidle_state msm_cstates[] __initdata = {
+ {0, 0, "C0", "WFI",
+ MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
+
+ {0, 1, "C1", "STANDALONE_POWER_COLLAPSE",
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
+
+ {0, 2, "C2", "POWER_COLLAPSE",
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE},
+
+ {1, 0, "C0", "WFI",
+ MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
+
+ {1, 1, "C1", "STANDALONE_POWER_COLLAPSE",
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
+};
+
+static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR * 2] = {
+ [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
+ .idle_supported = 1,
+ .suspend_supported = 1,
+ .idle_enabled = 0,
+ .suspend_enabled = 0,
+ },
+
+ [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
+ .idle_supported = 1,
+ .suspend_supported = 1,
+ .idle_enabled = 0,
+ .suspend_enabled = 0,
+ },
+
+ [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+ .idle_supported = 1,
+ .suspend_supported = 1,
+ .idle_enabled = 1,
+ .suspend_enabled = 1,
+ },
+
+ [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
+ .idle_supported = 0,
+ .suspend_supported = 1,
+ .idle_enabled = 0,
+ .suspend_enabled = 0,
+ },
+
+ [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
+ .idle_supported = 1,
+ .suspend_supported = 1,
+ .idle_enabled = 0,
+ .suspend_enabled = 0,
+ },
+
+ [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+ .idle_supported = 1,
+ .suspend_supported = 0,
+ .idle_enabled = 1,
+ .suspend_enabled = 0,
+ },
+};
+
+static struct msm_rpmrs_level msm_rpmrs_levels[] __initdata = {
+ {
+ MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
+ MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
+ true,
+ 100, 8000, 100000, 1,
+ },
+
+ {
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
+ MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
+ true,
+ 2000, 6000, 60100000, 3000,
+ },
+
+ {
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+ MSM_RPMRS_LIMITS(ON, GDHS, MAX, ACTIVE),
+ false,
+ 4200, 5000, 60350000, 3500,
+ },
+
+ {
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+ MSM_RPMRS_LIMITS(ON, HSFS_OPEN, MAX, ACTIVE),
+ false,
+ 6300, 4500, 65350000, 4800,
+ },
+ {
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+ MSM_RPMRS_LIMITS(ON, HSFS_OPEN, ACTIVE, RET_HIGH),
+ false,
+ 7000, 3500, 66600000, 5150,
+ },
+
+ {
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+ MSM_RPMRS_LIMITS(OFF, GDHS, MAX, ACTIVE),
+ false,
+ 11700, 2500, 67850000, 5500,
+ },
+
+ {
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+ MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, MAX, ACTIVE),
+ false,
+ 13800, 2000, 71850000, 6800,
+ },
+
+ {
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+ MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, ACTIVE, RET_HIGH),
+ false,
+ 29700, 500, 75850000, 8800,
+ },
+
+ {
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+ MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, RET_HIGH, RET_LOW),
+ false,
+ 29700, 0, 76350000, 9800,
+ },
+};
+
+#ifdef CONFIG_I2C
+#define I2C_SURF 1
+#define I2C_FFA (1 << 1)
+#define I2C_RUMI (1 << 2)
+#define I2C_SIM (1 << 3)
+#define I2C_FLUID (1 << 4)
+#define I2C_LIQUID (1 << 5)
+
+struct i2c_registry {
+ u8 machs;
+ int bus;
+ struct i2c_board_info *info;
+ int len;
+};
+
+#ifdef CONFIG_MSM_CAMERA
+static struct i2c_board_info msm_camera_boardinfo[] __initdata = {
+#ifdef CONFIG_IMX074
+ {
+ I2C_BOARD_INFO("imx074", 0x1A),
+ },
+#endif
+#ifdef CONFIG_OV2720
+ {
+ I2C_BOARD_INFO("ov2720", 0x6C),
+ },
+#endif
+#ifdef CONFIG_MSM_CAMERA_FLASH_SC628A
+ {
+ I2C_BOARD_INFO("sc628a", 0x6E),
+ },
+#endif
+};
+#endif
+
+static void __init msm8930_init_hsic(void)
+{
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+ uint32_t version = socinfo_get_version();
+
+ pr_info("%s: version:%d mtp:%d\n", __func__,
+ SOCINFO_VERSION_MAJOR(version),
+ machine_is_msm8930_mtp());
+
+ if ((SOCINFO_VERSION_MAJOR(version) == 1) ||
+ machine_is_msm8930_mtp() ||
+ machine_is_msm8930_fluid())
+ return;
+
+ platform_device_register(&msm_device_hsic_host);
+#endif
+}
+
+#ifdef CONFIG_ISL9519_CHARGER
+static struct isl_platform_data isl_data __initdata = {
+ .valid_n_gpio = 0, /* Not required when notify-by-pmic */
+ .chg_detection_config = NULL, /* Not required when notify-by-pmic */
+ .max_system_voltage = 4200,
+ .min_system_voltage = 3200,
+ .chgcurrent = 1000, /* 1900, */
+ .term_current = 400, /* Need fine tuning */
+ .input_current = 2048,
+};
+
+static struct i2c_board_info isl_charger_i2c_info[] __initdata = {
+ {
+ I2C_BOARD_INFO("isl9519q", 0x9),
+ .irq = 0, /* Not required when notify-by-pmic */
+ .platform_data = &isl_data,
+ },
+};
+#endif /* CONFIG_ISL9519_CHARGER */
+
+static struct i2c_registry msm8960_i2c_devices[] __initdata = {
+#ifdef CONFIG_MSM_CAMERA
+ {
+ I2C_SURF | I2C_FFA | I2C_FLUID | I2C_LIQUID | I2C_RUMI,
+ MSM_8930_GSBI4_QUP_I2C_BUS_ID,
+ msm_camera_boardinfo,
+ ARRAY_SIZE(msm_camera_boardinfo),
+ },
+#endif
+#ifdef CONFIG_ISL9519_CHARGER
+ {
+ I2C_LIQUID,
+ MSM_8930_GSBI10_QUP_I2C_BUS_ID,
+ isl_charger_i2c_info,
+ ARRAY_SIZE(isl_charger_i2c_info),
+ },
+#endif /* CONFIG_ISL9519_CHARGER */
+ {
+ I2C_SURF | I2C_FFA | I2C_FLUID,
+ MSM_8930_GSBI3_QUP_I2C_BUS_ID,
+ cyttsp_info,
+ ARRAY_SIZE(cyttsp_info),
+ },
+ {
+ I2C_LIQUID,
+ MSM_8930_GSBI3_QUP_I2C_BUS_ID,
+ mxt_device_info,
+ ARRAY_SIZE(mxt_device_info),
+ },
+ {
+ I2C_LIQUID,
+ MSM_8930_GSBI10_QUP_I2C_BUS_ID,
+ msm_isa1200_board_info,
+ ARRAY_SIZE(msm_isa1200_board_info),
+ },
+};
+#endif /* CONFIG_I2C */
+
+static void __init register_i2c_devices(void)
+{
+#ifdef CONFIG_I2C
+ u8 mach_mask = 0;
+ int i;
+
+ /* Build the matching 'supported_machs' bitmask */
+ if (machine_is_msm8930_cdp() || machine_is_msm8627_cdp())
+ mach_mask = I2C_SURF;
+ else if (machine_is_msm8930_fluid())
+ mach_mask = I2C_FLUID;
+ else if (machine_is_msm8930_mtp() || machine_is_msm8627_mtp())
+ mach_mask = I2C_FFA;
+ else
+ pr_err("unmatched machine ID in register_i2c_devices\n");
+
+ /* Run the array and install devices as appropriate */
+ for (i = 0; i < ARRAY_SIZE(msm8960_i2c_devices); ++i) {
+ if (msm8960_i2c_devices[i].machs & mach_mask)
+ i2c_register_board_info(msm8960_i2c_devices[i].bus,
+ msm8960_i2c_devices[i].info,
+ msm8960_i2c_devices[i].len);
+ }
+#endif
+}
+
+static void __init msm8930_cdp_init(void)
+{
+ if (meminfo_init(SYS_MEMORY, SZ_256M) < 0)
+ pr_err("meminfo_init() failed!\n");
+
+ BUG_ON(msm_rpm_init(&msm_rpm_data));
+ BUG_ON(msm_rpmrs_levels_init(msm_rpmrs_levels,
+ ARRAY_SIZE(msm_rpmrs_levels)));
+
+ regulator_suppress_info_printing();
+ if (msm_xo_init())
+ pr_err("Failed to initialize XO votes\n");
+ platform_device_register(&msm8960_device_rpm_regulator);
+ msm_clock_init(&msm8960_clock_init_data);
+ msm8960_device_otg.dev.platform_data = &msm_otg_pdata;
+ msm_device_hsic_host.dev.platform_data = &msm_hsic_pdata;
+ msm8930_init_gpiomux();
+ msm8960_device_qup_spi_gsbi1.dev.platform_data =
+ &msm8960_qup_spi_gsbi1_pdata;
+ spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+
+ msm8930_init_pmic();
+ msm8930_i2c_init();
+ msm8930_gfx_init();
+ msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
+ msm_spm_l2_init(msm_spm_l2_data);
+ msm8930_init_buses();
+ platform_add_devices(msm_footswitch_devices,
+ msm_num_footswitch_devices);
+ platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
+ msm8930_pm8921_gpio_mpp_init();
+ platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
+ msm8930_init_hsic();
+ msm8930_init_cam();
+ msm8930_init_mmc();
+ acpuclk_init(&acpuclk_8960_soc_data);
+ register_i2c_devices();
+ msm8930_init_fb();
+ slim_register_board_info(msm_slim_devices,
+ ARRAY_SIZE(msm_slim_devices));
+ msm_pm_set_platform_data(msm_pm_data, ARRAY_SIZE(msm_pm_data));
+ msm_pm_set_rpm_wakeup_irq(RPM_APCC_CPU0_WAKE_UP_IRQ);
+ msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
+ msm_pm_data);
+ change_memory_power = &msm8930_change_memory_power;
+ BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_TZ, NULL));
+
+ if (PLATFORM_IS_CHARM25())
+ platform_add_devices(mdm_devices, ARRAY_SIZE(mdm_devices));
+}
+
+MACHINE_START(MSM8930_CDP, "QCT MSM8930 CDP")
+ .map_io = msm8930_map_io,
+ .reserve = msm8930_reserve,
+ .init_irq = msm8930_init_irq,
+ .timer = &msm_timer,
+ .init_machine = msm8930_cdp_init,
+ .init_early = msm8930_allocate_memory_regions,
+ .init_very_early = msm8930_early_memory,
+MACHINE_END
+
+MACHINE_START(MSM8930_MTP, "QCT MSM8930 MTP")
+ .map_io = msm8930_map_io,
+ .reserve = msm8930_reserve,
+ .init_irq = msm8930_init_irq,
+ .timer = &msm_timer,
+ .init_machine = msm8930_cdp_init,
+ .init_early = msm8930_allocate_memory_regions,
+ .init_very_early = msm8930_early_memory,
+MACHINE_END
+
+MACHINE_START(MSM8930_FLUID, "QCT MSM8930 FLUID")
+ .map_io = msm8930_map_io,
+ .reserve = msm8930_reserve,
+ .init_irq = msm8930_init_irq,
+ .timer = &msm_timer,
+ .init_machine = msm8930_cdp_init,
+ .init_early = msm8930_allocate_memory_regions,
+ .init_very_early = msm8930_early_memory,
+MACHINE_END
+
+MACHINE_START(MSM8627_CDP, "QCT MSM8627 CDP")
+ .map_io = msm8930_map_io,
+ .reserve = msm8930_reserve,
+ .init_irq = msm8930_init_irq,
+ .timer = &msm_timer,
+ .init_machine = msm8930_cdp_init,
+ .init_early = msm8930_allocate_memory_regions,
+ .init_very_early = msm8930_early_memory,
+MACHINE_END
+
+MACHINE_START(MSM8627_MTP, "QCT MSM8627 MTP")
+ .map_io = msm8930_map_io,
+ .reserve = msm8930_reserve,
+ .init_irq = msm8930_init_irq,
+ .timer = &msm_timer,
+ .init_machine = msm8930_cdp_init,
+ .init_early = msm8930_allocate_memory_regions,
+ .init_very_early = msm8930_early_memory,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-8930.h b/arch/arm/mach-msm/board-8930.h
new file mode 100644
index 0000000..c413061
--- /dev/null
+++ b/arch/arm/mach-msm/board-8930.h
@@ -0,0 +1,86 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_BOARD_MSM8930_H
+#define __ARCH_ARM_MACH_MSM_BOARD_MSM8930_H
+
+#include <linux/regulator/gpio-regulator.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/i2c/sx150x.h>
+#include <mach/irqs.h>
+#include <mach/rpm-regulator.h>
+
+/* Macros assume PMIC GPIOs and MPPs start at 1 */
+#define PM8921_GPIO_BASE NR_GPIO_IRQS
+#define PM8921_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8921_GPIO_BASE)
+#define PM8921_MPP_BASE (PM8921_GPIO_BASE + PM8921_NR_GPIOS)
+#define PM8921_MPP_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8921_MPP_BASE)
+#define PM8921_IRQ_BASE (NR_MSM_IRQS + NR_GPIO_IRQS)
+
+extern struct pm8921_regulator_platform_data
+ msm_pm8921_regulator_pdata[] __devinitdata;
+
+extern int msm_pm8921_regulator_pdata_len __devinitdata;
+
+#define GPIO_VREG_ID_EXT_5V 0
+#define GPIO_VREG_ID_EXT_L2 1
+#define GPIO_VREG_ID_EXT_3P3V 2
+
+extern struct gpio_regulator_platform_data
+ msm_gpio_regulator_pdata[] __devinitdata;
+
+extern struct regulator_init_data msm_saw_regulator_pdata_s5;
+extern struct regulator_init_data msm_saw_regulator_pdata_s6;
+
+extern struct rpm_regulator_platform_data msm_rpm_regulator_pdata __devinitdata;
+
+#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
+enum {
+ GPIO_EXPANDER_IRQ_BASE = (PM8921_IRQ_BASE + PM8921_NR_IRQS),
+ GPIO_EXPANDER_GPIO_BASE = (PM8921_MPP_BASE + PM8921_NR_MPPS),
+ /* CAM Expander */
+ GPIO_CAM_EXPANDER_BASE = GPIO_EXPANDER_GPIO_BASE,
+ GPIO_CAM_GP_STROBE_READY = GPIO_CAM_EXPANDER_BASE,
+ GPIO_CAM_GP_AFBUSY,
+ GPIO_CAM_GP_STROBE_CE,
+ GPIO_CAM_GP_CAM1MP_XCLR,
+ GPIO_CAM_GP_CAMIF_RESET_N,
+ GPIO_CAM_GP_XMT_FLASH_INT,
+ GPIO_CAM_GP_LED_EN1,
+ GPIO_CAM_GP_LED_EN2,
+
+};
+#endif
+
+enum {
+ SX150X_CAM,
+};
+
+#endif
+
+extern struct sx150x_platform_data msm8930_sx150x_data[];
+void msm8930_init_cam(void);
+void msm8930_init_fb(void);
+void msm8930_init_pmic(void);
+void msm8930_init_mmc(void);
+int msm8930_init_gpiomux(void);
+void msm8930_allocate_fb_region(void);
+void msm8930_pm8921_gpio_mpp_init(void);
+
+#define PLATFORM_IS_CHARM25() \
+ (machine_is_msm8930_cdp() && \
+ (socinfo_get_platform_subtype() == 1) \
+ )
+
+#define MSM_8930_GSBI4_QUP_I2C_BUS_ID 4
+#define MSM_8930_GSBI3_QUP_I2C_BUS_ID 3
+#define MSM_8930_GSBI10_QUP_I2C_BUS_ID 10
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
new file mode 100644
index 0000000..e827b2b
--- /dev/null
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -0,0 +1,503 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/i2c.h>
+#include <linux/i2c/sx150x.h>
+#include <asm/mach-types.h>
+#include <mach/board.h>
+#include <mach/msm_bus_board.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+#include "devices.h"
+#include "board-8960.h"
+
+#if (defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)) && \
+ defined(CONFIG_I2C)
+
+static struct i2c_board_info cam_expander_i2c_info[] = {
+ {
+ I2C_BOARD_INFO("sx1508q", 0x22),
+ .platform_data = &msm8960_sx150x_data[SX150X_CAM]
+ },
+};
+
+static struct msm_cam_expander_info cam_expander_info[] = {
+ {
+ cam_expander_i2c_info,
+ MSM_8960_GSBI4_QUP_I2C_BUS_ID,
+ },
+};
+#endif
+
+static struct gpiomux_setting cam_settings[] = {
+ {
+ .func = GPIOMUX_FUNC_GPIO, /*suspend*/
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_1, /*active 1*/
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_GPIO, /*active 2*/
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_1, /*active 3*/
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_5, /*active 4*/
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_6, /*active 5*/
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_2, /*active 6*/
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_3, /*active 7*/
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_GPIO, /*i2c suspend*/
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_KEEPER,
+ },
+
+};
+
+static struct msm_gpiomux_config msm8960_cdp_flash_configs[] = {
+ {
+ .gpio = 3,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[1],
+ [GPIOMUX_SUSPENDED] = &cam_settings[0],
+ },
+ },
+};
+
+static struct msm_gpiomux_config msm8960_cam_common_configs[] = {
+ {
+ .gpio = 2,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[2],
+ [GPIOMUX_SUSPENDED] = &cam_settings[0],
+ },
+ },
+ {
+ .gpio = 3,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[2],
+ [GPIOMUX_SUSPENDED] = &cam_settings[0],
+ },
+ },
+ {
+ .gpio = 4,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[1],
+ [GPIOMUX_SUSPENDED] = &cam_settings[0],
+ },
+ },
+ {
+ .gpio = 5,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[1],
+ [GPIOMUX_SUSPENDED] = &cam_settings[0],
+ },
+ },
+ {
+ .gpio = 76,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[2],
+ [GPIOMUX_SUSPENDED] = &cam_settings[0],
+ },
+ },
+ {
+ .gpio = 107,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[2],
+ [GPIOMUX_SUSPENDED] = &cam_settings[0],
+ },
+ },
+};
+
+static struct msm_gpiomux_config msm8960_cam_2d_configs[] = {
+ {
+ .gpio = 18,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &cam_settings[8],
+ },
+ },
+ {
+ .gpio = 19,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &cam_settings[8],
+ },
+ },
+ {
+ .gpio = 20,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &cam_settings[8],
+ },
+ },
+ {
+ .gpio = 21,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &cam_settings[8],
+ },
+ },
+};
+
+#ifdef CONFIG_MSM_CAMERA
+
+static uint16_t msm_cam_gpio_2d_tbl[] = {
+ 5, /*CAMIF_MCLK*/
+ 20, /*CAMIF_I2C_DATA*/
+ 21, /*CAMIF_I2C_CLK*/
+};
+
+static struct msm_camera_gpio_conf gpio_conf = {
+ .cam_gpiomux_conf_tbl = msm8960_cam_2d_configs,
+ .cam_gpiomux_conf_tbl_size = ARRAY_SIZE(msm8960_cam_2d_configs),
+ .cam_gpio_tbl = msm_cam_gpio_2d_tbl,
+ .cam_gpio_tbl_size = ARRAY_SIZE(msm_cam_gpio_2d_tbl),
+};
+
+#define VFE_CAMIF_TIMER1_GPIO 2
+#define VFE_CAMIF_TIMER2_GPIO 3
+#define VFE_CAMIF_TIMER3_GPIO_INT 4
+static struct msm_camera_sensor_strobe_flash_data strobe_flash_xenon = {
+ .flash_trigger = VFE_CAMIF_TIMER2_GPIO,
+ .flash_charge = VFE_CAMIF_TIMER1_GPIO,
+ .flash_charge_done = VFE_CAMIF_TIMER3_GPIO_INT,
+ .flash_recharge_duration = 50000,
+ .irq = MSM_GPIO_TO_INT(VFE_CAMIF_TIMER3_GPIO_INT),
+};
+
+#ifdef CONFIG_MSM_CAMERA_FLASH
+static struct msm_camera_sensor_flash_src msm_flash_src = {
+ .flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
+ ._fsrc.ext_driver_src.led_en = VFE_CAMIF_TIMER1_GPIO,
+ ._fsrc.ext_driver_src.led_flash_en = VFE_CAMIF_TIMER2_GPIO,
+};
+#endif
+
+static struct msm_bus_vectors cam_init_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+static struct msm_bus_vectors cam_preview_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 27648000,
+ .ib = 110592000,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+static struct msm_bus_vectors cam_video_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 140451840,
+ .ib = 561807360,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 206807040,
+ .ib = 488816640,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+static struct msm_bus_vectors cam_snapshot_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 274423680,
+ .ib = 1097694720,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 540000000,
+ .ib = 1350000000,
+ },
+};
+
+static struct msm_bus_vectors cam_zsl_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 302071680,
+ .ib = 1208286720,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 540000000,
+ .ib = 1350000000,
+ },
+};
+
+static struct msm_bus_paths cam_bus_client_config[] = {
+ {
+ ARRAY_SIZE(cam_init_vectors),
+ cam_init_vectors,
+ },
+ {
+ ARRAY_SIZE(cam_preview_vectors),
+ cam_preview_vectors,
+ },
+ {
+ ARRAY_SIZE(cam_video_vectors),
+ cam_video_vectors,
+ },
+ {
+ ARRAY_SIZE(cam_snapshot_vectors),
+ cam_snapshot_vectors,
+ },
+ {
+ ARRAY_SIZE(cam_zsl_vectors),
+ cam_zsl_vectors,
+ },
+};
+
+static struct msm_bus_scale_pdata cam_bus_client_pdata = {
+ cam_bus_client_config,
+ ARRAY_SIZE(cam_bus_client_config),
+ .name = "msm_camera",
+};
+
+static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
+ {
+ .ioclk.mclk_clk_rate = 24000000,
+ .ioclk.vfe_clk_rate = 228570000,
+ .csid_core = 0,
+ .cam_bus_scale_table = &cam_bus_client_pdata,
+ },
+ {
+ .ioclk.mclk_clk_rate = 24000000,
+ .ioclk.vfe_clk_rate = 228570000,
+ .csid_core = 1,
+ .cam_bus_scale_table = &cam_bus_client_pdata,
+ },
+};
+
+#ifdef CONFIG_IMX074_ACT
+static struct i2c_board_info imx074_actuator_i2c_info = {
+ I2C_BOARD_INFO("imx074_act", 0x11),
+};
+
+static struct msm_actuator_info imx074_actuator_info = {
+ .board_info = &imx074_actuator_i2c_info,
+ .bus_id = MSM_8960_GSBI4_QUP_I2C_BUS_ID,
+ .vcm_pwd = 0,
+ .vcm_enable = 1,
+};
+#endif
+
+#ifdef CONFIG_IMX074
+static struct msm_camera_sensor_flash_data flash_imx074 = {
+ .flash_type = MSM_CAMERA_FLASH_LED,
+#ifdef CONFIG_MSM_CAMERA_FLASH
+ .flash_src = &msm_flash_src
+#endif
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_imx074 = {
+ .mount_angle = 90,
+ .sensor_reset = 107,
+ .sensor_pwd = 85,
+ .vcm_pwd = 0,
+ .vcm_enable = 1,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_imx074_data = {
+ .sensor_name = "imx074",
+ .pdata = &msm_camera_csi_device_data[0],
+ .flash_data = &flash_imx074,
+ .strobe_flash_data = &strobe_flash_xenon,
+ .sensor_platform_info = &sensor_board_info_imx074,
+ .gpio_conf = &gpio_conf,
+ .csi_if = 1,
+ .camera_type = BACK_CAMERA_2D,
+#ifdef CONFIG_IMX074_ACT
+ .actuator_info = &imx074_actuator_info
+#endif
+};
+
+static struct platform_device msm8960_camera_sensor_imx074 = {
+ .name = "msm_camera_imx074",
+ .dev = {
+ .platform_data = &msm_camera_sensor_imx074_data,
+ },
+};
+#endif
+#ifdef CONFIG_OV2720
+static struct msm_camera_sensor_flash_data flash_ov2720 = {
+ .flash_type = MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_ov2720 = {
+ .mount_angle = 0,
+ .sensor_reset = 76,
+ .sensor_pwd = 85,
+ .vcm_pwd = 0,
+ .vcm_enable = 1,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov2720_data = {
+ .sensor_name = "ov2720",
+ .pdata = &msm_camera_csi_device_data[1],
+ .flash_data = &flash_ov2720,
+ .sensor_platform_info = &sensor_board_info_ov2720,
+ .gpio_conf = &gpio_conf,
+ .csi_if = 1,
+ .camera_type = FRONT_CAMERA_2D,
+};
+
+static struct platform_device msm8960_camera_sensor_ov2720 = {
+ .name = "msm_camera_ov2720",
+ .dev = {
+ .platform_data = &msm_camera_sensor_ov2720_data,
+ },
+};
+#endif
+
+static struct msm8960_privacy_light_cfg privacy_light_info = {
+ .mpp = PM8921_MPP_PM_TO_SYS(12),
+};
+
+void __init msm8960_init_cam(void)
+{
+ int i;
+ struct platform_device *cam_dev[] = {
+ &msm8960_camera_sensor_imx074,
+ &msm8960_camera_sensor_ov2720,
+ };
+
+ msm_gpiomux_install(msm8960_cam_common_configs,
+ ARRAY_SIZE(msm8960_cam_common_configs));
+
+ if (machine_is_msm8960_cdp()) {
+ msm_gpiomux_install(msm8960_cdp_flash_configs,
+ ARRAY_SIZE(msm8960_cdp_flash_configs));
+ msm_flash_src._fsrc.ext_driver_src.led_en =
+ GPIO_CAM_GP_LED_EN1;
+ msm_flash_src._fsrc.ext_driver_src.led_flash_en =
+ GPIO_CAM_GP_LED_EN2;
+ #if defined(CONFIG_I2C) && (defined(CONFIG_GPIO_SX150X) || \
+ defined(CONFIG_GPIO_SX150X_MODULE))
+ msm_flash_src._fsrc.ext_driver_src.expander_info =
+ cam_expander_info;
+ #endif
+ }
+
+ if (machine_is_msm8960_liquid()) {
+ struct msm_camera_sensor_info *s_info;
+ s_info = msm8960_camera_sensor_imx074.dev.platform_data;
+ s_info->sensor_platform_info->mount_angle = 180;
+ s_info = msm8960_camera_sensor_ov2720.dev.platform_data;
+ s_info->sensor_platform_info->privacy_light = 1;
+ s_info->sensor_platform_info->privacy_light_info =
+ &privacy_light_info;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(cam_dev); i++) {
+ struct msm_camera_sensor_info *s_info;
+ s_info = cam_dev[i]->dev.platform_data;
+ msm_get_cam_resources(s_info);
+ platform_device_register(cam_dev[i]);
+ }
+
+ platform_device_register(&msm8960_device_csiphy0);
+ platform_device_register(&msm8960_device_csiphy1);
+ platform_device_register(&msm8960_device_csid0);
+ platform_device_register(&msm8960_device_csid1);
+ platform_device_register(&msm8960_device_ispif);
+ platform_device_register(&msm8960_device_vfe);
+ platform_device_register(&msm8960_device_vpe);
+}
+#endif
diff --git a/arch/arm/mach-msm/board-8960-display.c b/arch/arm/mach-msm/board-8960-display.c
new file mode 100644
index 0000000..63c51ea
--- /dev/null
+++ b/arch/arm/mach-msm/board-8960-display.c
@@ -0,0 +1,961 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/bootmem.h>
+#include <asm/mach-types.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+#include "devices.h"
+#include "board-8960.h"
+
+#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
+#define MSM_FB_PRIM_BUF_SIZE (1376 * 768 * 4 * 3) /* 4 bpp x 3 pages */
+#else
+#define MSM_FB_PRIM_BUF_SIZE (1376 * 768 * 4 * 2) /* 4 bpp x 2 pages */
+#endif
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+#define MSM_FB_EXT_BUF_SIZE (1920 * 1088 * 2 * 1) /* 2 bpp x 1 page */
+#elif defined(CONFIG_FB_MSM_TVOUT)
+#define MSM_FB_EXT_BUF_SIZE (720 * 576 * 2 * 2) /* 2 bpp x 2 pages */
+#else
+#define MSM_FB_EXT_BUF_SIZE 0
+#endif
+
+#ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
+/* width x height x 3 bpp x 2 frame buffer */
+#define MSM_FB_WRITEBACK_SIZE (1376 * 768 * 3 * 2)
+#define MSM_FB_WRITEBACK_OFFSET \
+ (MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE)
+#else
+#define MSM_FB_WRITEBACK_SIZE 0
+#define MSM_FB_WRITEBACK_OFFSET 0
+#endif
+
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+/* 4 bpp x 2 page HDMI case */
+#define MSM_FB_SIZE roundup((1920 * 1088 * 4 * 2), 4096)
+#else
+/* Note: must be multiple of 4096 */
+#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE + \
+ MSM_FB_WRITEBACK_SIZE, 4096)
+#endif
+
+#define MDP_VSYNC_GPIO 0
+
+#define PANEL_NAME_MAX_LEN 30
+#define MIPI_CMD_NOVATEK_QHD_PANEL_NAME "mipi_cmd_novatek_qhd"
+#define MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME "mipi_video_novatek_qhd"
+#define MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME "mipi_video_toshiba_wsvga"
+#define MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME "mipi_video_chimei_wxga"
+#define MIPI_VIDEO_SIMULATOR_VGA_PANEL_NAME "mipi_video_simulator_vga"
+#define MIPI_CMD_RENESAS_FWVGA_PANEL_NAME "mipi_cmd_renesas_fwvga"
+#define HDMI_PANEL_NAME "hdmi_msm"
+#define TVOUT_PANEL_NAME "tvout_msm"
+
+static int writeback_offset(void)
+{
+ return MSM_FB_WRITEBACK_OFFSET;
+}
+
+static struct resource msm_fb_resources[] = {
+ {
+ .flags = IORESOURCE_DMA,
+ }
+};
+
+static int msm_fb_detect_panel(const char *name)
+{
+ if (machine_is_msm8960_liquid()) {
+ if (!strncmp(name, MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME,
+ strnlen(MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME,
+ PANEL_NAME_MAX_LEN)))
+ return 0;
+ } else {
+ if (!strncmp(name, MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME,
+ strnlen(MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME,
+ PANEL_NAME_MAX_LEN)))
+ return 0;
+
+#ifndef CONFIG_FB_MSM_MIPI_PANEL_DETECT
+ if (!strncmp(name, MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME,
+ strnlen(MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME,
+ PANEL_NAME_MAX_LEN)))
+ return 0;
+
+ if (!strncmp(name, MIPI_CMD_NOVATEK_QHD_PANEL_NAME,
+ strnlen(MIPI_CMD_NOVATEK_QHD_PANEL_NAME,
+ PANEL_NAME_MAX_LEN)))
+ return 0;
+
+ if (!strncmp(name, MIPI_VIDEO_SIMULATOR_VGA_PANEL_NAME,
+ strnlen(MIPI_VIDEO_SIMULATOR_VGA_PANEL_NAME,
+ PANEL_NAME_MAX_LEN)))
+ return 0;
+
+ if (!strncmp(name, MIPI_CMD_RENESAS_FWVGA_PANEL_NAME,
+ strnlen(MIPI_CMD_RENESAS_FWVGA_PANEL_NAME,
+ PANEL_NAME_MAX_LEN)))
+ return 0;
+#endif
+ }
+
+ if (!strncmp(name, HDMI_PANEL_NAME,
+ strnlen(HDMI_PANEL_NAME,
+ PANEL_NAME_MAX_LEN)))
+ return 0;
+
+ if (!strncmp(name, TVOUT_PANEL_NAME,
+ strnlen(TVOUT_PANEL_NAME,
+ PANEL_NAME_MAX_LEN)))
+ return 0;
+
+ pr_warning("%s: not supported '%s'", __func__, name);
+ return -ENODEV;
+}
+
+static struct msm_fb_platform_data msm_fb_pdata = {
+ .detect_client = msm_fb_detect_panel,
+};
+
+static struct platform_device msm_fb_device = {
+ .name = "msm_fb",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(msm_fb_resources),
+ .resource = msm_fb_resources,
+ .dev.platform_data = &msm_fb_pdata,
+};
+
+static bool dsi_power_on;
+
+/**
+ * LiQUID panel on/off
+ *
+ * @param on
+ *
+ * @return int
+ */
+static int mipi_dsi_liquid_panel_power(int on)
+{
+ static struct regulator *reg_l2, *reg_ext_3p3v;
+ static int gpio21, gpio24, gpio43;
+ int rc;
+
+ pr_info("%s: on=%d\n", __func__, on);
+
+ gpio21 = PM8921_GPIO_PM_TO_SYS(21); /* disp power enable_n */
+ gpio43 = PM8921_GPIO_PM_TO_SYS(43); /* Displays Enable (rst_n)*/
+ gpio24 = PM8921_GPIO_PM_TO_SYS(24); /* Backlight PWM */
+
+ if (!dsi_power_on) {
+
+ reg_l2 = regulator_get(&msm_mipi_dsi1_device.dev,
+ "dsi_vdda");
+ if (IS_ERR(reg_l2)) {
+ pr_err("could not get 8921_l2, rc = %ld\n",
+ PTR_ERR(reg_l2));
+ return -ENODEV;
+ }
+
+ rc = regulator_set_voltage(reg_l2, 1200000, 1200000);
+ if (rc) {
+ pr_err("set_voltage l2 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+
+ reg_ext_3p3v = regulator_get(&msm_mipi_dsi1_device.dev,
+ "vdd_lvds_3p3v");
+ if (IS_ERR(reg_ext_3p3v)) {
+ pr_err("could not get reg_ext_3p3v, rc = %ld\n",
+ PTR_ERR(reg_ext_3p3v));
+ return -ENODEV;
+ }
+
+ rc = gpio_request(gpio21, "disp_pwr_en_n");
+ if (rc) {
+ pr_err("request gpio 21 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+
+ rc = gpio_request(gpio43, "disp_rst_n");
+ if (rc) {
+ pr_err("request gpio 43 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+
+ rc = gpio_request(gpio24, "disp_backlight_pwm");
+ if (rc) {
+ pr_err("request gpio 24 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+
+ dsi_power_on = true;
+ }
+
+ if (on) {
+ rc = regulator_set_optimum_mode(reg_l2, 100000);
+ if (rc < 0) {
+ pr_err("set_optimum_mode l2 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ rc = regulator_enable(reg_l2);
+ if (rc) {
+ pr_err("enable l2 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+
+ rc = regulator_enable(reg_ext_3p3v);
+ if (rc) {
+ pr_err("enable reg_ext_3p3v failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+
+ /* set reset pin before power enable */
+ gpio_set_value_cansleep(gpio43, 0); /* disp disable (resx=0) */
+
+ gpio_set_value_cansleep(gpio21, 0); /* disp power enable_n */
+ msleep(20);
+ gpio_set_value_cansleep(gpio43, 1); /* disp enable */
+ msleep(20);
+ gpio_set_value_cansleep(gpio43, 0); /* disp enable */
+ msleep(20);
+ gpio_set_value_cansleep(gpio43, 1); /* disp enable */
+ msleep(20);
+ } else {
+ gpio_set_value_cansleep(gpio43, 0);
+ gpio_set_value_cansleep(gpio21, 1);
+
+ rc = regulator_disable(reg_l2);
+ if (rc) {
+ pr_err("disable reg_l2 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ rc = regulator_disable(reg_ext_3p3v);
+ if (rc) {
+ pr_err("disable reg_ext_3p3v failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ rc = regulator_set_optimum_mode(reg_l2, 100);
+ if (rc < 0) {
+ pr_err("set_optimum_mode l2 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int mipi_dsi_cdp_panel_power(int on)
+{
+ static struct regulator *reg_l8, *reg_l23, *reg_l2;
+ static int gpio43;
+ int rc;
+
+ pr_info("%s: state : %d\n", __func__, on);
+
+ if (!dsi_power_on) {
+
+ reg_l8 = regulator_get(&msm_mipi_dsi1_device.dev,
+ "dsi_vdc");
+ if (IS_ERR(reg_l8)) {
+ pr_err("could not get 8921_l8, rc = %ld\n",
+ PTR_ERR(reg_l8));
+ return -ENODEV;
+ }
+ reg_l23 = regulator_get(&msm_mipi_dsi1_device.dev,
+ "dsi_vddio");
+ if (IS_ERR(reg_l23)) {
+ pr_err("could not get 8921_l23, rc = %ld\n",
+ PTR_ERR(reg_l23));
+ return -ENODEV;
+ }
+ reg_l2 = regulator_get(&msm_mipi_dsi1_device.dev,
+ "dsi_vdda");
+ if (IS_ERR(reg_l2)) {
+ pr_err("could not get 8921_l2, rc = %ld\n",
+ PTR_ERR(reg_l2));
+ return -ENODEV;
+ }
+ rc = regulator_set_voltage(reg_l8, 2800000, 3000000);
+ if (rc) {
+ pr_err("set_voltage l8 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ rc = regulator_set_voltage(reg_l23, 1800000, 1800000);
+ if (rc) {
+ pr_err("set_voltage l23 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ rc = regulator_set_voltage(reg_l2, 1200000, 1200000);
+ if (rc) {
+ pr_err("set_voltage l2 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ gpio43 = PM8921_GPIO_PM_TO_SYS(43);
+ rc = gpio_request(gpio43, "disp_rst_n");
+ if (rc) {
+ pr_err("request gpio 43 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ dsi_power_on = true;
+ }
+ if (on) {
+ rc = regulator_set_optimum_mode(reg_l8, 100000);
+ if (rc < 0) {
+ pr_err("set_optimum_mode l8 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ rc = regulator_set_optimum_mode(reg_l23, 100000);
+ if (rc < 0) {
+ pr_err("set_optimum_mode l23 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ rc = regulator_set_optimum_mode(reg_l2, 100000);
+ if (rc < 0) {
+ pr_err("set_optimum_mode l2 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ rc = regulator_enable(reg_l8);
+ if (rc) {
+ pr_err("enable l8 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ rc = regulator_enable(reg_l23);
+ if (rc) {
+ pr_err("enable l8 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ rc = regulator_enable(reg_l2);
+ if (rc) {
+ pr_err("enable l2 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ gpio_set_value_cansleep(gpio43, 1);
+ } else {
+ rc = regulator_disable(reg_l2);
+ if (rc) {
+ pr_err("disable reg_l2 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ rc = regulator_disable(reg_l8);
+ if (rc) {
+ pr_err("disable reg_l8 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ rc = regulator_disable(reg_l23);
+ if (rc) {
+ pr_err("disable reg_l23 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ rc = regulator_set_optimum_mode(reg_l8, 100);
+ if (rc < 0) {
+ pr_err("set_optimum_mode l8 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ rc = regulator_set_optimum_mode(reg_l23, 100);
+ if (rc < 0) {
+ pr_err("set_optimum_mode l23 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ rc = regulator_set_optimum_mode(reg_l2, 100);
+ if (rc < 0) {
+ pr_err("set_optimum_mode l2 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ gpio_set_value_cansleep(gpio43, 0);
+ }
+ return 0;
+}
+
+static int mipi_dsi_panel_power(int on)
+{
+ int ret;
+
+ pr_info("%s: on=%d\n", __func__, on);
+
+ if (machine_is_msm8960_liquid())
+ ret = mipi_dsi_liquid_panel_power(on);
+ else
+ ret = mipi_dsi_cdp_panel_power(on);
+
+ return ret;
+}
+
+static struct mipi_dsi_platform_data mipi_dsi_pdata = {
+ .vsync_gpio = MDP_VSYNC_GPIO,
+ .dsi_power_save = mipi_dsi_panel_power,
+};
+
+#ifdef CONFIG_MSM_BUS_SCALING
+
+static struct msm_bus_vectors mdp_init_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_MDP_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+static struct msm_bus_vectors hdmi_as_primary_vectors[] = {
+ /* If HDMI is used as primary */
+ {
+ .src = MSM_BUS_MASTER_MDP_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2000000000,
+ .ib = 2000000000,
+ },
+};
+static struct msm_bus_paths mdp_bus_scale_usecases[] = {
+ {
+ ARRAY_SIZE(mdp_init_vectors),
+ mdp_init_vectors,
+ },
+ {
+ ARRAY_SIZE(hdmi_as_primary_vectors),
+ hdmi_as_primary_vectors,
+ },
+ {
+ ARRAY_SIZE(hdmi_as_primary_vectors),
+ hdmi_as_primary_vectors,
+ },
+ {
+ ARRAY_SIZE(hdmi_as_primary_vectors),
+ hdmi_as_primary_vectors,
+ },
+ {
+ ARRAY_SIZE(hdmi_as_primary_vectors),
+ hdmi_as_primary_vectors,
+ },
+ {
+ ARRAY_SIZE(hdmi_as_primary_vectors),
+ hdmi_as_primary_vectors,
+ },
+};
+#else
+static struct msm_bus_vectors mdp_ui_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_MDP_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 216000000 * 2,
+ .ib = 270000000 * 2,
+ },
+};
+
+static struct msm_bus_vectors mdp_vga_vectors[] = {
+ /* VGA and less video */
+ {
+ .src = MSM_BUS_MASTER_MDP_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 216000000 * 2,
+ .ib = 270000000 * 2,
+ },
+};
+
+static struct msm_bus_vectors mdp_720p_vectors[] = {
+ /* 720p and less video */
+ {
+ .src = MSM_BUS_MASTER_MDP_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 230400000 * 2,
+ .ib = 288000000 * 2,
+ },
+};
+
+static struct msm_bus_vectors mdp_1080p_vectors[] = {
+ /* 1080p and less video */
+ {
+ .src = MSM_BUS_MASTER_MDP_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 334080000 * 2,
+ .ib = 417600000 * 2,
+ },
+};
+
+static struct msm_bus_paths mdp_bus_scale_usecases[] = {
+ {
+ ARRAY_SIZE(mdp_init_vectors),
+ mdp_init_vectors,
+ },
+ {
+ ARRAY_SIZE(mdp_ui_vectors),
+ mdp_ui_vectors,
+ },
+ {
+ ARRAY_SIZE(mdp_ui_vectors),
+ mdp_ui_vectors,
+ },
+ {
+ ARRAY_SIZE(mdp_vga_vectors),
+ mdp_vga_vectors,
+ },
+ {
+ ARRAY_SIZE(mdp_720p_vectors),
+ mdp_720p_vectors,
+ },
+ {
+ ARRAY_SIZE(mdp_1080p_vectors),
+ mdp_1080p_vectors,
+ },
+};
+#endif
+
+static struct msm_bus_scale_pdata mdp_bus_scale_pdata = {
+ mdp_bus_scale_usecases,
+ ARRAY_SIZE(mdp_bus_scale_usecases),
+ .name = "mdp",
+};
+
+#endif
+
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+static int mdp_core_clk_rate_table[] = {
+ 200000000,
+ 200000000,
+ 200000000,
+ 200000000,
+};
+#else
+static int mdp_core_clk_rate_table[] = {
+ 85330000,
+ 85330000,
+ 160000000,
+ 200000000,
+};
+#endif
+
+static struct msm_panel_common_pdata mdp_pdata = {
+ .gpio = MDP_VSYNC_GPIO,
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+ .mdp_core_clk_rate = 200000000,
+#else
+ .mdp_core_clk_rate = 85330000,
+#endif
+ .mdp_core_clk_table = mdp_core_clk_rate_table,
+ .num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+#ifdef CONFIG_MSM_BUS_SCALING
+ .mdp_bus_scale_table = &mdp_bus_scale_pdata,
+#endif
+ .mdp_rev = MDP_REV_42,
+ .writeback_offset = writeback_offset,
+};
+
+static struct platform_device mipi_dsi_renesas_panel_device = {
+ .name = "mipi_renesas",
+ .id = 0,
+};
+
+static struct platform_device mipi_dsi_simulator_panel_device = {
+ .name = "mipi_simulator",
+ .id = 0,
+};
+
+#define LPM_CHANNEL0 0
+static int toshiba_gpio[] = {LPM_CHANNEL0};
+
+static struct mipi_dsi_panel_platform_data toshiba_pdata = {
+ .gpio = toshiba_gpio,
+};
+
+static struct platform_device mipi_dsi_toshiba_panel_device = {
+ .name = "mipi_toshiba",
+ .id = 0,
+ .dev = {
+ .platform_data = &toshiba_pdata,
+ }
+};
+
+#define FPGA_3D_GPIO_CONFIG_ADDR 0xB5
+static int dsi2lvds_gpio[2] = {
+ 0,/* Backlight PWM-ID=0 for PMIC-GPIO#24 */
+ 0x1F08 /* DSI2LVDS Bridge GPIO Output, mask=0x1f, out=0x08 */
+ };
+
+static struct msm_panel_common_pdata mipi_dsi2lvds_pdata = {
+ .gpio_num = dsi2lvds_gpio,
+};
+
+static struct mipi_dsi_phy_ctrl dsi_novatek_cmd_mode_phy_db = {
+
+/* DSI_BIT_CLK at 500MHz, 2 lane, RGB888 */
+ {0x0F, 0x0a, 0x04, 0x00, 0x20}, /* regulator */
+ /* timing */
+ {0xab, 0x8a, 0x18, 0x00, 0x92, 0x97, 0x1b, 0x8c,
+ 0x0c, 0x03, 0x04, 0xa0},
+ {0x5f, 0x00, 0x00, 0x10}, /* phy ctrl */
+ {0xff, 0x00, 0x06, 0x00}, /* strength */
+ /* pll control */
+ {0x40, 0xf9, 0x30, 0xda, 0x00, 0x40, 0x03, 0x62,
+ 0x40, 0x07, 0x03,
+ 0x00, 0x1a, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0x01},
+};
+
+static struct mipi_dsi_panel_platform_data novatek_pdata = {
+ .fpga_3d_config_addr = FPGA_3D_GPIO_CONFIG_ADDR,
+ .fpga_ctrl_mode = FPGA_SPI_INTF,
+ .phy_ctrl_settings = &dsi_novatek_cmd_mode_phy_db,
+};
+
+static struct platform_device mipi_dsi_novatek_panel_device = {
+ .name = "mipi_novatek",
+ .id = 0,
+ .dev = {
+ .platform_data = &novatek_pdata,
+ }
+};
+
+static struct platform_device mipi_dsi2lvds_bridge_device = {
+ .name = "mipi_tc358764",
+ .id = 0,
+ .dev.platform_data = &mipi_dsi2lvds_pdata,
+};
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+static struct resource hdmi_msm_resources[] = {
+ {
+ .name = "hdmi_msm_qfprom_addr",
+ .start = 0x00700000,
+ .end = 0x007060FF,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "hdmi_msm_hdmi_addr",
+ .start = 0x04A00000,
+ .end = 0x04A00FFF,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "hdmi_msm_irq",
+ .start = HDMI_IRQ,
+ .end = HDMI_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static int hdmi_enable_5v(int on);
+static int hdmi_core_power(int on, int show);
+static int hdmi_cec_power(int on);
+
+static struct msm_hdmi_platform_data hdmi_msm_data = {
+ .irq = HDMI_IRQ,
+ .enable_5v = hdmi_enable_5v,
+ .core_power = hdmi_core_power,
+ .cec_power = hdmi_cec_power,
+};
+
+static struct platform_device hdmi_msm_device = {
+ .name = "hdmi_msm",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(hdmi_msm_resources),
+ .resource = hdmi_msm_resources,
+ .dev.platform_data = &hdmi_msm_data,
+};
+#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL */
+
+#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+static struct platform_device wfd_panel_device = {
+ .name = "wfd_panel",
+ .id = 0,
+ .dev.platform_data = NULL,
+};
+
+static struct platform_device wfd_device = {
+ .name = "msm_wfd",
+ .id = -1,
+};
+#endif
+
+#ifdef CONFIG_MSM_BUS_SCALING
+static struct msm_bus_vectors dtv_bus_init_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_MDP_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+static struct msm_bus_vectors dtv_bus_def_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_MDP_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2000000000,
+ .ib = 2000000000,
+ },
+};
+#else
+static struct msm_bus_vectors dtv_bus_def_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_MDP_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 566092800 * 2,
+ .ib = 707616000 * 2,
+ },
+};
+#endif
+
+static struct msm_bus_paths dtv_bus_scale_usecases[] = {
+ {
+ ARRAY_SIZE(dtv_bus_init_vectors),
+ dtv_bus_init_vectors,
+ },
+ {
+ ARRAY_SIZE(dtv_bus_def_vectors),
+ dtv_bus_def_vectors,
+ },
+};
+static struct msm_bus_scale_pdata dtv_bus_scale_pdata = {
+ dtv_bus_scale_usecases,
+ ARRAY_SIZE(dtv_bus_scale_usecases),
+ .name = "dtv",
+};
+
+static struct lcdc_platform_data dtv_pdata = {
+ .bus_scale_table = &dtv_bus_scale_pdata,
+};
+#endif
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+static int hdmi_enable_5v(int on)
+{
+ /* TBD: PM8921 regulator instead of 8901 */
+ static struct regulator *reg_8921_hdmi_mvs; /* HDMI_5V */
+ static int prev_on;
+ int rc;
+
+ if (on == prev_on)
+ return 0;
+
+ if (!reg_8921_hdmi_mvs)
+ reg_8921_hdmi_mvs = regulator_get(&hdmi_msm_device.dev,
+ "hdmi_mvs");
+
+ if (on) {
+ rc = regulator_enable(reg_8921_hdmi_mvs);
+ if (rc) {
+ pr_err("'%s' regulator enable failed, rc=%d\n",
+ "8921_hdmi_mvs", rc);
+ return rc;
+ }
+ pr_debug("%s(on): success\n", __func__);
+ } else {
+ rc = regulator_disable(reg_8921_hdmi_mvs);
+ if (rc)
+ pr_warning("'%s' regulator disable failed, rc=%d\n",
+ "8921_hdmi_mvs", rc);
+ pr_debug("%s(off): success\n", __func__);
+ }
+
+ prev_on = on;
+
+ return 0;
+}
+
+static int hdmi_core_power(int on, int show)
+{
+ static struct regulator *reg_8921_l23, *reg_8921_s4;
+ static int prev_on;
+ int rc;
+
+ if (on == prev_on)
+ return 0;
+
+ /* TBD: PM8921 regulator instead of 8901 */
+ if (!reg_8921_l23) {
+ reg_8921_l23 = regulator_get(&hdmi_msm_device.dev, "hdmi_avdd");
+ if (IS_ERR(reg_8921_l23)) {
+ pr_err("could not get reg_8921_l23, rc = %ld\n",
+ PTR_ERR(reg_8921_l23));
+ return -ENODEV;
+ }
+ rc = regulator_set_voltage(reg_8921_l23, 1800000, 1800000);
+ if (rc) {
+ pr_err("set_voltage failed for 8921_l23, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ }
+ if (!reg_8921_s4) {
+ reg_8921_s4 = regulator_get(&hdmi_msm_device.dev, "hdmi_vcc");
+ if (IS_ERR(reg_8921_s4)) {
+ pr_err("could not get reg_8921_s4, rc = %ld\n",
+ PTR_ERR(reg_8921_s4));
+ return -ENODEV;
+ }
+ rc = regulator_set_voltage(reg_8921_s4, 1800000, 1800000);
+ if (rc) {
+ pr_err("set_voltage failed for 8921_s4, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ }
+
+ if (on) {
+ rc = regulator_set_optimum_mode(reg_8921_l23, 100000);
+ if (rc < 0) {
+ pr_err("set_optimum_mode l23 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ rc = regulator_enable(reg_8921_l23);
+ if (rc) {
+ pr_err("'%s' regulator enable failed, rc=%d\n",
+ "hdmi_avdd", rc);
+ return rc;
+ }
+ rc = regulator_enable(reg_8921_s4);
+ if (rc) {
+ pr_err("'%s' regulator enable failed, rc=%d\n",
+ "hdmi_vcc", rc);
+ return rc;
+ }
+ rc = gpio_request(100, "HDMI_DDC_CLK");
+ if (rc) {
+ pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+ "HDMI_DDC_CLK", 100, rc);
+ goto error1;
+ }
+ rc = gpio_request(101, "HDMI_DDC_DATA");
+ if (rc) {
+ pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+ "HDMI_DDC_DATA", 101, rc);
+ goto error2;
+ }
+ rc = gpio_request(102, "HDMI_HPD");
+ if (rc) {
+ pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+ "HDMI_HPD", 102, rc);
+ goto error3;
+ }
+ pr_debug("%s(on): success\n", __func__);
+ } else {
+ gpio_free(100);
+ gpio_free(101);
+ gpio_free(102);
+
+ rc = regulator_disable(reg_8921_l23);
+ if (rc) {
+ pr_err("disable reg_8921_l23 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ rc = regulator_disable(reg_8921_s4);
+ if (rc) {
+ pr_err("disable reg_8921_s4 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ rc = regulator_set_optimum_mode(reg_8921_l23, 100);
+ if (rc < 0) {
+ pr_err("set_optimum_mode l23 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ pr_debug("%s(off): success\n", __func__);
+ }
+
+ prev_on = on;
+
+ return 0;
+
+error3:
+ gpio_free(101);
+error2:
+ gpio_free(100);
+error1:
+ regulator_disable(reg_8921_l23);
+ regulator_disable(reg_8921_s4);
+ return rc;
+}
+
+static int hdmi_cec_power(int on)
+{
+ static int prev_on;
+ int rc;
+
+ if (on == prev_on)
+ return 0;
+
+ if (on) {
+ rc = gpio_request(99, "HDMI_CEC_VAR");
+ if (rc) {
+ pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+ "HDMI_CEC_VAR", 99, rc);
+ goto error;
+ }
+ pr_debug("%s(on): success\n", __func__);
+ } else {
+ gpio_free(99);
+ pr_debug("%s(off): success\n", __func__);
+ }
+
+ prev_on = on;
+
+ return 0;
+error:
+ return rc;
+}
+#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL */
+
+void __init msm8960_init_fb(void)
+{
+ platform_device_register(&msm_fb_device);
+
+#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+ platform_device_register(&wfd_panel_device);
+ platform_device_register(&wfd_device);
+#endif
+
+ if (machine_is_msm8960_sim())
+ platform_device_register(&mipi_dsi_simulator_panel_device);
+
+ if (machine_is_msm8960_rumi3())
+ platform_device_register(&mipi_dsi_renesas_panel_device);
+
+ if (!machine_is_msm8960_sim() && !machine_is_msm8960_rumi3()) {
+ platform_device_register(&mipi_dsi_novatek_panel_device);
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+ platform_device_register(&hdmi_msm_device);
+#endif
+ }
+
+ if (machine_is_msm8960_liquid())
+ platform_device_register(&mipi_dsi2lvds_bridge_device);
+ else
+ platform_device_register(&mipi_dsi_toshiba_panel_device);
+
+ if (machine_is_msm8x60_rumi3()) {
+ msm_fb_register_device("mdp", NULL);
+ mipi_dsi_pdata.target_type = 1;
+ } else
+ msm_fb_register_device("mdp", &mdp_pdata);
+ msm_fb_register_device("mipi_dsi", &mipi_dsi_pdata);
+#ifdef CONFIG_MSM_BUS_SCALING
+ msm_fb_register_device("dtv", &dtv_pdata);
+#endif
+}
+
+void __init msm8960_allocate_fb_region(void)
+{
+ void *addr;
+ unsigned long size;
+
+ size = MSM_FB_SIZE;
+ addr = alloc_bootmem_align(size, 0x1000);
+ msm_fb_resources[0].start = __pa(addr);
+ msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1;
+ pr_info("allocating %lu bytes at %p (%lx physical) for fb\n",
+ size, addr, __pa(addr));
+}
diff --git a/arch/arm/mach-msm/board-8960-gpiomux.c b/arch/arm/mach-msm/board-8960-gpiomux.c
new file mode 100644
index 0000000..ce260e1
--- /dev/null
+++ b/arch/arm/mach-msm/board-8960-gpiomux.c
@@ -0,0 +1,690 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 <asm/mach-types.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+#include <mach/socinfo.h>
+#include "devices.h"
+#include "board-8960.h"
+
+/* The SPI configurations apply to GSBI 1*/
+static struct gpiomux_setting spi_active = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_12MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting spi_suspended_config = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting spi_active_config2 = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting spi_suspended_config2 = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting gsbi3_suspended_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_KEEPER,
+};
+
+static struct gpiomux_setting gsbi3_active_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi5 = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi10 = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi12 = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cdc_mclk = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting audio_auxpcm[] = {
+ /* Suspended state */
+ {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ },
+ /* Active state */
+ {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ },
+};
+
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+static struct gpiomux_setting gpio_eth_config = {
+ .pull = GPIOMUX_PULL_NONE,
+ .drv = GPIOMUX_DRV_8MA,
+ .func = GPIOMUX_FUNC_GPIO,
+};
+#endif
+
+static struct gpiomux_setting slimbus = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_KEEPER,
+};
+
+static struct gpiomux_setting wcnss_5wire_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting wcnss_5wire_active_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting cyts_resout_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting cyts_resout_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting cyts_sleep_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting cyts_sleep_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting cyts_int_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting cyts_int_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+static struct gpiomux_setting hsic_act_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_12MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting hsic_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+ .dir = GPIOMUX_OUT_LOW,
+};
+
+static struct gpiomux_setting hsic_hub_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+#endif
+
+static struct gpiomux_setting hap_lvl_shft_suspended_config = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting hap_lvl_shft_active_config = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting ap2mdm_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting mdm2ap_status_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting mdm2ap_errfatal_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_16MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting ap2mdm_kpdpwr_n_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting mdp_vsync_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting mdp_vsync_active_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+static struct gpiomux_setting hdmi_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting hdmi_active_1_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting hdmi_active_2_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting hdmi_active_3_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+ .dir = GPIOMUX_IN,
+};
+
+static struct gpiomux_setting hdmi_active_4_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+ .dir = GPIOMUX_OUT_HIGH,
+};
+#endif
+
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+static struct msm_gpiomux_config msm8960_ethernet_configs[] = {
+ {
+ .gpio = 90,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_eth_config,
+ }
+ },
+ {
+ .gpio = 89,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_eth_config,
+ }
+ },
+};
+#endif
+
+static struct msm_gpiomux_config msm8960_gsbi_configs[] __initdata = {
+ {
+ .gpio = 6, /* GSBI1 QUP SPI_DATA_MOSI */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &spi_suspended_config,
+ [GPIOMUX_ACTIVE] = &spi_active,
+ },
+ },
+ {
+ .gpio = 7, /* GSBI1 QUP SPI_DATA_MISO */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &spi_suspended_config,
+ [GPIOMUX_ACTIVE] = &spi_active,
+ },
+ },
+ {
+ .gpio = 8, /* GSBI1 QUP SPI_CS_N */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &spi_suspended_config,
+ [GPIOMUX_ACTIVE] = &spi_active,
+ },
+ },
+ {
+ .gpio = 9, /* GSBI1 QUP SPI_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &spi_suspended_config,
+ [GPIOMUX_ACTIVE] = &spi_active,
+ },
+ },
+ {
+ .gpio = 14, /* GSBI1 SPI_CS_1 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &spi_suspended_config2,
+ [GPIOMUX_ACTIVE] = &spi_active_config2,
+ },
+ },
+ {
+ .gpio = 16, /* GSBI3 I2C QUP SDA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi3_suspended_cfg,
+ [GPIOMUX_ACTIVE] = &gsbi3_active_cfg,
+ },
+ },
+ {
+ .gpio = 17, /* GSBI3 I2C QUP SCL */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi3_suspended_cfg,
+ [GPIOMUX_ACTIVE] = &gsbi3_active_cfg,
+ },
+ },
+ {
+ .gpio = 22, /* GSBI5 UART2 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi5,
+ },
+ },
+ {
+ .gpio = 23, /* GSBI5 UART2 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi5,
+ },
+ },
+ {
+ .gpio = 24, /* GSBI5 UART2 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi5,
+ },
+ },
+ {
+ .gpio = 25, /* GSBI5 UART2 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi5,
+ },
+ },
+ {
+ .gpio = 44, /* GSBI12 I2C QUP SDA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi12,
+ },
+ },
+ {
+ .gpio = 45, /* GSBI12 I2C QUP SCL */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi12,
+ },
+ },
+ {
+ .gpio = 73, /* GSBI10 I2C QUP SDA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi10,
+ },
+ },
+ {
+ .gpio = 74, /* GSBI10 I2C QUP SCL */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi10,
+ },
+ },
+};
+
+static struct msm_gpiomux_config msm8960_slimbus_config[] __initdata = {
+ {
+ .gpio = 60, /* slimbus data */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &slimbus,
+ },
+ },
+ {
+ .gpio = 61, /* slimbus clk */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &slimbus,
+ },
+ },
+};
+
+static struct msm_gpiomux_config msm8960_audio_codec_configs[] __initdata = {
+ {
+ .gpio = 59,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &cdc_mclk,
+ },
+ },
+};
+
+static struct msm_gpiomux_config msm8960_audio_auxpcm_configs[] __initdata = {
+ {
+ .gpio = 63,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+ [GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+ },
+ },
+ {
+ .gpio = 64,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+ [GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+ },
+ },
+ {
+ .gpio = 65,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+ [GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+ },
+ },
+ {
+ .gpio = 66,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+ [GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+ },
+ },
+};
+
+static struct msm_gpiomux_config wcnss_5wire_interface[] = {
+ {
+ .gpio = 84,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 85,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 86,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 87,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 88,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+};
+
+static struct msm_gpiomux_config msm8960_cyts_configs[] __initdata = {
+ { /* TS INTERRUPT */
+ .gpio = 11,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cyts_int_act_cfg,
+ [GPIOMUX_SUSPENDED] = &cyts_int_sus_cfg,
+ },
+ },
+ { /* TS SLEEP */
+ .gpio = 50,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cyts_sleep_act_cfg,
+ [GPIOMUX_SUSPENDED] = &cyts_sleep_sus_cfg,
+ },
+ },
+ { /* TS RESOUT */
+ .gpio = 52,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cyts_resout_act_cfg,
+ [GPIOMUX_SUSPENDED] = &cyts_resout_sus_cfg,
+ },
+ },
+};
+
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+static struct msm_gpiomux_config msm8960_hsic_configs[] = {
+ {
+ .gpio = 150, /*HSIC_STROBE */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hsic_act_cfg,
+ [GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
+ },
+ },
+ {
+ .gpio = 151, /* HSIC_DATA */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hsic_act_cfg,
+ [GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
+ },
+ },
+ {
+ .gpio = 91, /* HSIC_HUB_RESET */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hsic_hub_act_cfg,
+ [GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
+ },
+ },
+};
+#endif
+
+static struct msm_gpiomux_config hap_lvl_shft_config[] __initdata = {
+ {
+ .gpio = 47,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &hap_lvl_shft_suspended_config,
+ [GPIOMUX_ACTIVE] = &hap_lvl_shft_active_config,
+ },
+ },
+};
+
+static struct msm_gpiomux_config mdm_configs[] __initdata = {
+ /* AP2MDM_STATUS */
+ {
+ .gpio = 94,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+ }
+ },
+ /* MDM2AP_STATUS */
+ {
+ .gpio = 69,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &mdm2ap_status_cfg,
+ }
+ },
+ /* MDM2AP_ERRFATAL */
+ {
+ .gpio = 70,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &mdm2ap_errfatal_cfg,
+ }
+ },
+ /* AP2MDM_ERRFATAL */
+ {
+ .gpio = 95,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+ }
+ },
+ /* AP2MDM_KPDPWR_N */
+ {
+ .gpio = 81,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &ap2mdm_kpdpwr_n_cfg,
+ }
+ },
+ /* AP2MDM_PMIC_RESET_N */
+ {
+ .gpio = 80,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &ap2mdm_kpdpwr_n_cfg,
+ }
+ }
+};
+
+static struct msm_gpiomux_config msm8960_mdp_vsync_configs[] __initdata = {
+ {
+ .gpio = 0,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &mdp_vsync_active_cfg,
+ [GPIOMUX_SUSPENDED] = &mdp_vsync_suspend_cfg,
+ },
+ }
+};
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+static struct msm_gpiomux_config msm8960_hdmi_configs[] __initdata = {
+ {
+ .gpio = 99,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hdmi_active_1_cfg,
+ [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 100,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hdmi_active_1_cfg,
+ [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 101,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hdmi_active_1_cfg,
+ [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 102,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hdmi_active_2_cfg,
+ [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 15,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hdmi_active_3_cfg,
+ [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 66,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hdmi_active_4_cfg,
+ [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+ },
+ },
+};
+#endif
+
+int __init msm8960_init_gpiomux(void)
+{
+ int rc = msm_gpiomux_init(NR_GPIO_IRQS);
+ if (rc) {
+ pr_err(KERN_ERR "msm_gpiomux_init failed %d\n", rc);
+ return rc;
+ }
+
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+ msm_gpiomux_install(msm8960_ethernet_configs,
+ ARRAY_SIZE(msm8960_ethernet_configs));
+#endif
+
+ msm_gpiomux_install(msm8960_gsbi_configs,
+ ARRAY_SIZE(msm8960_gsbi_configs));
+
+ msm_gpiomux_install(msm8960_cyts_configs,
+ ARRAY_SIZE(msm8960_cyts_configs));
+
+ msm_gpiomux_install(msm8960_slimbus_config,
+ ARRAY_SIZE(msm8960_slimbus_config));
+
+ msm_gpiomux_install(msm8960_audio_codec_configs,
+ ARRAY_SIZE(msm8960_audio_codec_configs));
+
+ msm_gpiomux_install(msm8960_audio_auxpcm_configs,
+ ARRAY_SIZE(msm8960_audio_auxpcm_configs));
+
+ msm_gpiomux_install(wcnss_5wire_interface,
+ ARRAY_SIZE(wcnss_5wire_interface));
+
+ if (machine_is_msm8960_mtp() || machine_is_msm8960_fluid() ||
+ machine_is_msm8960_liquid() || machine_is_msm8960_cdp())
+ msm_gpiomux_install(hap_lvl_shft_config,
+ ARRAY_SIZE(hap_lvl_shft_config));
+
+ if (PLATFORM_IS_CHARM25())
+ msm_gpiomux_install(mdm_configs,
+ ARRAY_SIZE(mdm_configs));
+
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+ if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) != 1) &&
+ (PLATFORM_IS_CHARM25() || machine_is_msm8960_liquid()))
+ msm_gpiomux_install(msm8960_hsic_configs,
+ ARRAY_SIZE(msm8960_hsic_configs));
+#endif
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+ msm_gpiomux_install(msm8960_hdmi_configs,
+ ARRAY_SIZE(msm8960_hdmi_configs));
+#endif
+
+ msm_gpiomux_install(msm8960_mdp_vsync_configs,
+ ARRAY_SIZE(msm8960_mdp_vsync_configs));
+
+ return 0;
+}
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
new file mode 100644
index 0000000..44f7be6
--- /dev/null
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -0,0 +1,542 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/interrupt.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
+#include <linux/leds.h>
+#include <linux/leds-pm8xxx.h>
+#include <linux/msm_ssbi.h>
+#include <asm/mach-types.h>
+#include <mach/msm_bus_board.h>
+#include <mach/restart.h>
+#include "devices.h"
+#include "board-8960.h"
+
+struct pm8xxx_gpio_init {
+ unsigned gpio;
+ struct pm_gpio config;
+};
+
+struct pm8xxx_mpp_init {
+ unsigned mpp;
+ struct pm8xxx_mpp_config_data config;
+};
+
+#define PM8XXX_GPIO_INIT(_gpio, _dir, _buf, _val, _pull, _vin, _out_strength, \
+ _func, _inv, _disable) \
+{ \
+ .gpio = PM8921_GPIO_PM_TO_SYS(_gpio), \
+ .config = { \
+ .direction = _dir, \
+ .output_buffer = _buf, \
+ .output_value = _val, \
+ .pull = _pull, \
+ .vin_sel = _vin, \
+ .out_strength = _out_strength, \
+ .function = _func, \
+ .inv_int_pol = _inv, \
+ .disable_pin = _disable, \
+ } \
+}
+
+#define PM8XXX_MPP_INIT(_mpp, _type, _level, _control) \
+{ \
+ .mpp = PM8921_MPP_PM_TO_SYS(_mpp), \
+ .config = { \
+ .type = PM8XXX_MPP_TYPE_##_type, \
+ .level = _level, \
+ .control = PM8XXX_MPP_##_control, \
+ } \
+}
+
+#define PM8XXX_GPIO_DISABLE(_gpio) \
+ PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, 0, 0, 0, PM_GPIO_VIN_S4, \
+ 0, 0, 0, 1)
+
+#define PM8XXX_GPIO_OUTPUT(_gpio, _val) \
+ PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+ PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \
+ PM_GPIO_STRENGTH_HIGH, \
+ PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8XXX_GPIO_INPUT(_gpio, _pull) \
+ PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, PM_GPIO_OUT_BUF_CMOS, 0, \
+ _pull, PM_GPIO_VIN_S4, \
+ PM_GPIO_STRENGTH_NO, \
+ PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8XXX_GPIO_OUTPUT_FUNC(_gpio, _val, _func) \
+ PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+ PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \
+ PM_GPIO_STRENGTH_HIGH, \
+ _func, 0, 0)
+
+#define PM8XXX_GPIO_OUTPUT_VIN(_gpio, _val, _vin) \
+ PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+ PM_GPIO_PULL_NO, _vin, \
+ PM_GPIO_STRENGTH_HIGH, \
+ PM_GPIO_FUNC_NORMAL, 0, 0)
+
+/* Initial PM8921 GPIO configurations */
+static struct pm8xxx_gpio_init pm8921_gpios[] __initdata = {
+ PM8XXX_GPIO_DISABLE(6), /* Disable unused */
+ PM8XXX_GPIO_DISABLE(7), /* Disable NFC */
+ PM8XXX_GPIO_INPUT(16, PM_GPIO_PULL_UP_30), /* SD_CARD_WP */
+ /* External regulator shared by display and touchscreen on LiQUID */
+ PM8XXX_GPIO_OUTPUT(17, 0), /* DISP 3.3 V Boost */
+ PM8XXX_GPIO_OUTPUT_VIN(21, 1, PM_GPIO_VIN_VPH), /* Backlight Enable */
+ PM8XXX_GPIO_DISABLE(22), /* Disable NFC */
+ PM8XXX_GPIO_OUTPUT_FUNC(24, 0, PM_GPIO_FUNC_2), /* Bl: Off, PWM mode */
+ PM8XXX_GPIO_INPUT(26, PM_GPIO_PULL_UP_30), /* SD_CARD_DET_N */
+ PM8XXX_GPIO_OUTPUT(43, PM_GPIO_PULL_UP_30), /* DISP_RESET_N */
+ PM8XXX_GPIO_OUTPUT(42, 0), /* USB 5V reg enable */
+};
+
+/* Initial PM8921 MPP configurations */
+static struct pm8xxx_mpp_init pm8921_mpps[] __initdata = {
+ /* External 5V regulator enable; shared by HDMI and USB_OTG switches. */
+ PM8XXX_MPP_INIT(7, D_INPUT, PM8921_MPP_DIG_LEVEL_VPH, DIN_TO_INT),
+ PM8XXX_MPP_INIT(PM8XXX_AMUX_MPP_8, A_INPUT, PM8XXX_MPP_AIN_AMUX_CH8,
+ DOUT_CTRL_LOW),
+};
+
+void __init msm8960_pm8921_gpio_mpp_init(void)
+{
+ int i, rc;
+
+ for (i = 0; i < ARRAY_SIZE(pm8921_gpios); i++) {
+ rc = pm8xxx_gpio_config(pm8921_gpios[i].gpio,
+ &pm8921_gpios[i].config);
+ if (rc) {
+ pr_err("%s: pm8xxx_gpio_config: rc=%d\n", __func__, rc);
+ break;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(pm8921_mpps); i++) {
+ rc = pm8xxx_mpp_config(pm8921_mpps[i].mpp,
+ &pm8921_mpps[i].config);
+ if (rc) {
+ pr_err("%s: pm8xxx_mpp_config: rc=%d\n", __func__, rc);
+ break;
+ }
+ }
+}
+
+static struct pm8xxx_adc_amux pm8xxx_adc_channels_data[] = {
+ {"vcoin", CHANNEL_VCOIN, CHAN_PATH_SCALING2, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"vbat", CHANNEL_VBAT, CHAN_PATH_SCALING2, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"dcin", CHANNEL_DCIN, CHAN_PATH_SCALING4, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"ichg", CHANNEL_ICHG, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"vph_pwr", CHANNEL_VPH_PWR, CHAN_PATH_SCALING2, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"ibat", CHANNEL_IBAT, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"batt_therm", CHANNEL_BATT_THERM, CHAN_PATH_SCALING1, AMUX_RSV2,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_BATT_THERM},
+ {"batt_id", CHANNEL_BATT_ID, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"usbin", CHANNEL_USBIN, CHAN_PATH_SCALING3, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"pmic_therm", CHANNEL_DIE_TEMP, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_PMIC_THERM},
+ {"625mv", CHANNEL_625MV, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"125v", CHANNEL_125V, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"chg_temp", CHANNEL_CHG_TEMP, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"pa_therm1", ADC_MPP_1_AMUX8, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_PA_THERM},
+ {"xo_therm", CHANNEL_MUXOFF, CHAN_PATH_SCALING1, AMUX_RSV0,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_XOTHERM},
+ {"pa_therm0", ADC_MPP_1_AMUX3, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_PA_THERM},
+};
+
+static struct pm8xxx_adc_properties pm8xxx_adc_data = {
+ .adc_vdd_reference = 1800, /* milli-voltage for this adc */
+ .bitresolution = 15,
+ .bipolar = 0,
+};
+
+static struct pm8xxx_adc_platform_data pm8xxx_adc_pdata = {
+ .adc_channel = pm8xxx_adc_channels_data,
+ .adc_num_board_channel = ARRAY_SIZE(pm8xxx_adc_channels_data),
+ .adc_prop = &pm8xxx_adc_data,
+ .adc_mpp_base = PM8921_MPP_PM_TO_SYS(1),
+};
+
+static struct pm8xxx_irq_platform_data pm8xxx_irq_pdata __devinitdata = {
+ .irq_base = PM8921_IRQ_BASE,
+ .devirq = MSM_GPIO_TO_INT(104),
+ .irq_trigger_flag = IRQF_TRIGGER_LOW,
+};
+
+static struct pm8xxx_gpio_platform_data pm8xxx_gpio_pdata __devinitdata = {
+ .gpio_base = PM8921_GPIO_PM_TO_SYS(1),
+};
+
+static struct pm8xxx_mpp_platform_data pm8xxx_mpp_pdata __devinitdata = {
+ .mpp_base = PM8921_MPP_PM_TO_SYS(1),
+};
+
+static struct pm8xxx_rtc_platform_data pm8xxx_rtc_pdata __devinitdata = {
+ .rtc_write_enable = false,
+ .rtc_alarm_powerup = false,
+};
+
+static struct pm8xxx_pwrkey_platform_data pm8xxx_pwrkey_pdata = {
+ .pull_up = 1,
+ .kpd_trigger_delay_us = 15625,
+ .wakeup = 1,
+};
+
+/* Rotate lock key is not available so use F1 */
+#define KEY_ROTATE_LOCK KEY_F1
+
+static const unsigned int keymap_liquid[] = {
+ KEY(0, 0, KEY_VOLUMEUP),
+ KEY(0, 1, KEY_VOLUMEDOWN),
+ KEY(1, 3, KEY_ROTATE_LOCK),
+ KEY(1, 4, KEY_HOME),
+};
+
+static struct matrix_keymap_data keymap_data_liquid = {
+ .keymap_size = ARRAY_SIZE(keymap_liquid),
+ .keymap = keymap_liquid,
+};
+
+static struct pm8xxx_keypad_platform_data keypad_data_liquid = {
+ .input_name = "keypad_8960_liquid",
+ .input_phys_device = "keypad_8960/input0",
+ .num_rows = 2,
+ .num_cols = 5,
+ .rows_gpio_start = PM8921_GPIO_PM_TO_SYS(9),
+ .cols_gpio_start = PM8921_GPIO_PM_TO_SYS(1),
+ .debounce_ms = 15,
+ .scan_delay_ms = 32,
+ .row_hold_ns = 91500,
+ .wakeup = 1,
+ .keymap_data = &keymap_data_liquid,
+};
+
+
+static const unsigned int keymap[] = {
+ KEY(0, 0, KEY_VOLUMEUP),
+ KEY(0, 1, KEY_VOLUMEDOWN),
+ KEY(0, 2, KEY_CAMERA_SNAPSHOT),
+ KEY(0, 3, KEY_CAMERA_FOCUS),
+};
+
+static struct matrix_keymap_data keymap_data = {
+ .keymap_size = ARRAY_SIZE(keymap),
+ .keymap = keymap,
+};
+
+static struct pm8xxx_keypad_platform_data keypad_data = {
+ .input_name = "keypad_8960",
+ .input_phys_device = "keypad_8960/input0",
+ .num_rows = 1,
+ .num_cols = 5,
+ .rows_gpio_start = PM8921_GPIO_PM_TO_SYS(9),
+ .cols_gpio_start = PM8921_GPIO_PM_TO_SYS(1),
+ .debounce_ms = 15,
+ .scan_delay_ms = 32,
+ .row_hold_ns = 91500,
+ .wakeup = 1,
+ .keymap_data = &keymap_data,
+};
+
+static const unsigned int keymap_sim[] = {
+ KEY(0, 0, KEY_7),
+ KEY(0, 1, KEY_DOWN),
+ KEY(0, 2, KEY_UP),
+ KEY(0, 3, KEY_RIGHT),
+ KEY(0, 4, KEY_ENTER),
+ KEY(0, 5, KEY_L),
+ KEY(0, 6, KEY_BACK),
+ KEY(0, 7, KEY_M),
+
+ KEY(1, 0, KEY_LEFT),
+ KEY(1, 1, KEY_SEND),
+ KEY(1, 2, KEY_1),
+ KEY(1, 3, KEY_4),
+ KEY(1, 4, KEY_CLEAR),
+ KEY(1, 5, KEY_MSDOS),
+ KEY(1, 6, KEY_SPACE),
+ KEY(1, 7, KEY_COMMA),
+
+ KEY(2, 0, KEY_6),
+ KEY(2, 1, KEY_5),
+ KEY(2, 2, KEY_8),
+ KEY(2, 3, KEY_3),
+ KEY(2, 4, KEY_NUMERIC_STAR),
+ KEY(2, 5, KEY_UP),
+ KEY(2, 6, KEY_DOWN),
+ KEY(2, 7, KEY_LEFTSHIFT),
+
+ KEY(3, 0, KEY_9),
+ KEY(3, 1, KEY_NUMERIC_POUND),
+ KEY(3, 2, KEY_0),
+ KEY(3, 3, KEY_2),
+ KEY(3, 4, KEY_SLEEP),
+ KEY(3, 5, KEY_F1),
+ KEY(3, 6, KEY_F2),
+ KEY(3, 7, KEY_F3),
+
+ KEY(4, 0, KEY_BACK),
+ KEY(4, 1, KEY_HOME),
+ KEY(4, 2, KEY_MENU),
+ KEY(4, 3, KEY_VOLUMEUP),
+ KEY(4, 4, KEY_VOLUMEDOWN),
+ KEY(4, 5, KEY_F4),
+ KEY(4, 6, KEY_F5),
+ KEY(4, 7, KEY_F6),
+
+ KEY(5, 0, KEY_R),
+ KEY(5, 1, KEY_T),
+ KEY(5, 2, KEY_Y),
+ KEY(5, 3, KEY_LEFTALT),
+ KEY(5, 4, KEY_KPENTER),
+ KEY(5, 5, KEY_Q),
+ KEY(5, 6, KEY_W),
+ KEY(5, 7, KEY_E),
+
+ KEY(6, 0, KEY_F),
+ KEY(6, 1, KEY_G),
+ KEY(6, 2, KEY_H),
+ KEY(6, 3, KEY_CAPSLOCK),
+ KEY(6, 4, KEY_PAGEUP),
+ KEY(6, 5, KEY_A),
+ KEY(6, 6, KEY_S),
+ KEY(6, 7, KEY_D),
+
+ KEY(7, 0, KEY_V),
+ KEY(7, 1, KEY_B),
+ KEY(7, 2, KEY_N),
+ KEY(7, 3, KEY_MENU),
+ KEY(7, 4, KEY_PAGEDOWN),
+ KEY(7, 5, KEY_Z),
+ KEY(7, 6, KEY_X),
+ KEY(7, 7, KEY_C),
+
+ KEY(8, 0, KEY_P),
+ KEY(8, 1, KEY_J),
+ KEY(8, 2, KEY_K),
+ KEY(8, 3, KEY_INSERT),
+ KEY(8, 4, KEY_LINEFEED),
+ KEY(8, 5, KEY_U),
+ KEY(8, 6, KEY_I),
+ KEY(8, 7, KEY_O),
+
+ KEY(9, 0, KEY_4),
+ KEY(9, 1, KEY_5),
+ KEY(9, 2, KEY_6),
+ KEY(9, 3, KEY_7),
+ KEY(9, 4, KEY_8),
+ KEY(9, 5, KEY_1),
+ KEY(9, 6, KEY_2),
+ KEY(9, 7, KEY_3),
+
+ KEY(10, 0, KEY_F7),
+ KEY(10, 1, KEY_F8),
+ KEY(10, 2, KEY_F9),
+ KEY(10, 3, KEY_F10),
+ KEY(10, 4, KEY_FN),
+ KEY(10, 5, KEY_9),
+ KEY(10, 6, KEY_0),
+ KEY(10, 7, KEY_DOT),
+
+ KEY(11, 0, KEY_LEFTCTRL),
+ KEY(11, 1, KEY_F11),
+ KEY(11, 2, KEY_ENTER),
+ KEY(11, 3, KEY_SEARCH),
+ KEY(11, 4, KEY_DELETE),
+ KEY(11, 5, KEY_RIGHT),
+ KEY(11, 6, KEY_LEFT),
+ KEY(11, 7, KEY_RIGHTSHIFT),
+ KEY(0, 0, KEY_VOLUMEUP),
+ KEY(0, 1, KEY_VOLUMEDOWN),
+ KEY(0, 2, KEY_CAMERA_SNAPSHOT),
+ KEY(0, 3, KEY_CAMERA_FOCUS),
+};
+
+static struct matrix_keymap_data keymap_data_sim = {
+ .keymap_size = ARRAY_SIZE(keymap_sim),
+ .keymap = keymap_sim,
+};
+
+static struct pm8xxx_keypad_platform_data keypad_data_sim = {
+ .input_name = "keypad_8960",
+ .input_phys_device = "keypad_8960/input0",
+ .num_rows = 12,
+ .num_cols = 8,
+ .rows_gpio_start = PM8921_GPIO_PM_TO_SYS(9),
+ .cols_gpio_start = PM8921_GPIO_PM_TO_SYS(1),
+ .debounce_ms = 15,
+ .scan_delay_ms = 32,
+ .row_hold_ns = 91500,
+ .wakeup = 1,
+ .keymap_data = &keymap_data_sim,
+};
+
+static int pm8921_therm_mitigation[] = {
+ 1100,
+ 700,
+ 600,
+ 325,
+};
+
+static struct pm8921_charger_platform_data pm8921_chg_pdata __devinitdata = {
+ .safety_time = 180,
+ .update_time = 60000,
+ .max_voltage = 4200,
+ .min_voltage = 3200,
+ .resume_voltage_delta = 100,
+ .term_current = 100,
+ .cool_temp = 10,
+ .warm_temp = 40,
+ .temp_check_period = 1,
+ .max_bat_chg_current = 1100,
+ .cool_bat_chg_current = 350,
+ .warm_bat_chg_current = 350,
+ .cool_bat_voltage = 4100,
+ .warm_bat_voltage = 4100,
+ .thermal_mitigation = pm8921_therm_mitigation,
+ .thermal_levels = ARRAY_SIZE(pm8921_therm_mitigation),
+};
+
+static struct pm8xxx_misc_platform_data pm8xxx_misc_pdata = {
+ .priority = 0,
+};
+
+static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
+ .r_sense = 10,
+ .i_test = 2500,
+ .v_failure = 3000,
+ .calib_delay_ms = 600000,
+};
+
+#define PM8921_LC_LED_MAX_CURRENT 4 /* I = 4mA */
+#define PM8XXX_LED_PWM_PERIOD 1000
+#define PM8XXX_LED_PWM_DUTY_MS 20
+/**
+ * PM8XXX_PWM_CHANNEL_NONE shall be used when LED shall not be
+ * driven using PWM feature.
+ */
+#define PM8XXX_PWM_CHANNEL_NONE -1
+
+static struct led_info pm8921_led_info[] = {
+ [0] = {
+ .name = "led:battery_charging",
+ .default_trigger = "battery-charging",
+ },
+ [1] = {
+ .name = "led:battery_full",
+ .default_trigger = "battery-full",
+ },
+};
+
+static struct led_platform_data pm8921_led_core_pdata = {
+ .num_leds = ARRAY_SIZE(pm8921_led_info),
+ .leds = pm8921_led_info,
+};
+
+static int pm8921_led0_pwm_duty_pcts[56] = {
+ 1, 4, 8, 12, 16, 20, 24, 28, 32, 36,
+ 40, 44, 46, 52, 56, 60, 64, 68, 72, 76,
+ 80, 84, 88, 92, 96, 100, 100, 100, 98, 95,
+ 92, 88, 84, 82, 78, 74, 70, 66, 62, 58,
+ 58, 54, 50, 48, 42, 38, 34, 30, 26, 22,
+ 14, 10, 6, 4, 1
+};
+
+static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_duty_cycles = {
+ .duty_pcts = (int *)&pm8921_led0_pwm_duty_pcts,
+ .num_duty_pcts = ARRAY_SIZE(pm8921_led0_pwm_duty_pcts),
+ .duty_ms = PM8XXX_LED_PWM_DUTY_MS,
+ .start_idx = 0,
+};
+
+static struct pm8xxx_led_config pm8921_led_configs[] = {
+ [0] = {
+ .id = PM8XXX_ID_LED_0,
+ .mode = PM8XXX_LED_MODE_PWM2,
+ .max_current = PM8921_LC_LED_MAX_CURRENT,
+ .pwm_channel = 5,
+ .pwm_period_us = PM8XXX_LED_PWM_PERIOD,
+ .pwm_duty_cycles = &pm8921_led0_pwm_duty_cycles,
+ },
+ [1] = {
+ .id = PM8XXX_ID_LED_1,
+ .mode = PM8XXX_LED_MODE_PWM1,
+ .max_current = PM8921_LC_LED_MAX_CURRENT,
+ .pwm_channel = 4,
+ .pwm_period_us = PM8XXX_LED_PWM_PERIOD,
+ },
+};
+
+static struct pm8xxx_led_platform_data pm8xxx_leds_pdata = {
+ .led_core = &pm8921_led_core_pdata,
+ .configs = pm8921_led_configs,
+ .num_configs = ARRAY_SIZE(pm8921_led_configs),
+};
+
+static struct pm8xxx_ccadc_platform_data pm8xxx_ccadc_pdata = {
+ .r_sense = 10,
+};
+
+static struct pm8921_platform_data pm8921_platform_data __devinitdata = {
+ .irq_pdata = &pm8xxx_irq_pdata,
+ .gpio_pdata = &pm8xxx_gpio_pdata,
+ .mpp_pdata = &pm8xxx_mpp_pdata,
+ .rtc_pdata = &pm8xxx_rtc_pdata,
+ .pwrkey_pdata = &pm8xxx_pwrkey_pdata,
+ .keypad_pdata = &keypad_data,
+ .misc_pdata = &pm8xxx_misc_pdata,
+ .regulator_pdatas = msm_pm8921_regulator_pdata,
+ .charger_pdata = &pm8921_chg_pdata,
+ .bms_pdata = &pm8921_bms_pdata,
+ .adc_pdata = &pm8xxx_adc_pdata,
+ .leds_pdata = &pm8xxx_leds_pdata,
+ .ccadc_pdata = &pm8xxx_ccadc_pdata,
+};
+
+static struct msm_ssbi_platform_data msm8960_ssbi_pm8921_pdata __devinitdata = {
+ .controller_type = MSM_SBI_CTRL_PMIC_ARBITER,
+ .slave = {
+ .name = "pm8921-core",
+ .platform_data = &pm8921_platform_data,
+ },
+};
+
+void __init msm8960_init_pmic(void)
+{
+ pmic_reset_irq = PM8921_IRQ_BASE + PM8921_RESOUT_IRQ;
+ msm8960_device_ssbi_pm8921.dev.platform_data =
+ &msm8960_ssbi_pm8921_pdata;
+ pm8921_platform_data.num_regulators = msm_pm8921_regulator_pdata_len;
+
+ /* Simulator supports a QWERTY keypad */
+ if (machine_is_msm8960_sim())
+ pm8921_platform_data.keypad_pdata = &keypad_data_sim;
+
+ if (machine_is_msm8960_liquid())
+ pm8921_platform_data.keypad_pdata = &keypad_data_liquid;
+}
diff --git a/arch/arm/mach-msm/board-msm8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
similarity index 96%
rename from arch/arm/mach-msm/board-msm8960-regulator.c
rename to arch/arm/mach-msm/board-8960-regulator.c
index c67e100..7bc3ca5 100644
--- a/arch/arm/mach-msm/board-msm8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -15,7 +15,7 @@
#include <linux/regulator/gpio-regulator.h>
#include <mach/rpm-regulator.h>
-#include "board-msm8960.h"
+#include "board-8960.h"
#define VREG_CONSUMERS(_id) \
static struct regulator_consumer_supply vreg_consumers_##_id[]
@@ -32,7 +32,6 @@
REGULATOR_SUPPLY("dsi_vdda", "mipi_dsi.1"),
REGULATOR_SUPPLY("mipi_csi_vdd", "msm_camera_imx074.0"),
REGULATOR_SUPPLY("mipi_csi_vdd", "msm_camera_ov2720.0"),
- REGULATOR_SUPPLY("mipi_csi_vdd", "msm_camera_qs_mt9p017.0"),
};
VREG_CONSUMERS(L3) = {
REGULATOR_SUPPLY("8921_l3", NULL),
@@ -72,17 +71,15 @@
REGULATOR_SUPPLY("8921_l11", NULL),
REGULATOR_SUPPLY("cam_vana", "msm_camera_imx074.0"),
REGULATOR_SUPPLY("cam_vana", "msm_camera_ov2720.0"),
- REGULATOR_SUPPLY("cam_vana", "msm_camera_qs_mt9p017.0"),
};
VREG_CONSUMERS(L12) = {
REGULATOR_SUPPLY("8921_l12", NULL),
REGULATOR_SUPPLY("cam_vdig", "msm_camera_imx074.0"),
REGULATOR_SUPPLY("cam_vdig", "msm_camera_ov2720.0"),
- REGULATOR_SUPPLY("cam_vdig", "msm_camera_qs_mt9p017.0"),
};
VREG_CONSUMERS(L14) = {
REGULATOR_SUPPLY("8921_l14", NULL),
- REGULATOR_SUPPLY("pa_therm", "pm8921-adc"),
+ REGULATOR_SUPPLY("pa_therm", "pm8xxx-adc"),
};
VREG_CONSUMERS(L15) = {
REGULATOR_SUPPLY("8921_l15", NULL),
@@ -91,7 +88,6 @@
REGULATOR_SUPPLY("8921_l16", NULL),
REGULATOR_SUPPLY("cam_vaf", "msm_camera_imx074.0"),
REGULATOR_SUPPLY("cam_vaf", "msm_camera_ov2720.0"),
- REGULATOR_SUPPLY("cam_vaf", "msm_camera_qs_mt9p017.0"),
};
VREG_CONSUMERS(L17) = {
REGULATOR_SUPPLY("8921_l17", NULL),
@@ -123,15 +119,15 @@
};
VREG_CONSUMERS(L26) = {
REGULATOR_SUPPLY("8921_l26", NULL),
- REGULATOR_SUPPLY("q6_lpass", NULL),
+ REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.0"),
};
VREG_CONSUMERS(L27) = {
REGULATOR_SUPPLY("8921_l27", NULL),
- REGULATOR_SUPPLY("q6_modem_sw", NULL),
+ REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.2"),
};
VREG_CONSUMERS(L28) = {
REGULATOR_SUPPLY("8921_l28", NULL),
- REGULATOR_SUPPLY("q6_modem_fw", NULL),
+ REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.1"),
};
VREG_CONSUMERS(L29) = {
REGULATOR_SUPPLY("8921_l29", NULL),
@@ -201,7 +197,6 @@
REGULATOR_SUPPLY("8921_lvs5", NULL),
REGULATOR_SUPPLY("cam_vio", "msm_camera_imx074.0"),
REGULATOR_SUPPLY("cam_vio", "msm_camera_ov2720.0"),
- REGULATOR_SUPPLY("cam_vio", "msm_camera_qs_mt9p017.0"),
};
VREG_CONSUMERS(LVS6) = {
REGULATOR_SUPPLY("8921_lvs6", NULL),
@@ -454,9 +449,9 @@
/* SAW regulator constraints */
struct regulator_init_data msm_saw_regulator_pdata_s5 =
/* ID vreg_name min_uV max_uV */
- SAW_VREG_INIT(S5, "8921_s5", 950000, 1150000);
+ SAW_VREG_INIT(S5, "8921_s5", 950000, 1300000);
struct regulator_init_data msm_saw_regulator_pdata_s6 =
- SAW_VREG_INIT(S6, "8921_s6", 950000, 1150000);
+ SAW_VREG_INIT(S6, "8921_s6", 950000, 1300000);
/* PM8921 regulator constraints */
struct pm8921_regulator_platform_data
diff --git a/arch/arm/mach-msm/board-8960-storage.c b/arch/arm/mach-msm/board-8960-storage.c
new file mode 100644
index 0000000..dfcafd4
--- /dev/null
+++ b/arch/arm/mach-msm/board-8960-storage.c
@@ -0,0 +1,268 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/bootmem.h>
+#include <asm/mach-types.h>
+#include <asm/mach/mmc.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+#include "devices.h"
+#include "board-8960.h"
+
+/* MSM8960 has 5 SDCC controllers */
+enum sdcc_controllers {
+ SDCC1,
+ SDCC2,
+ SDCC3,
+ SDCC4,
+ SDCC5,
+ MAX_SDCC_CONTROLLER
+};
+
+/* All SDCC controllers require VDD/VCC voltage */
+static struct msm_mmc_reg_data mmc_vdd_reg_data[MAX_SDCC_CONTROLLER] = {
+ /* SDCC1 : eMMC card connected */
+ [SDCC1] = {
+ .name = "sdc_vdd",
+ .high_vol_level = 2950000,
+ .low_vol_level = 2950000,
+ .always_on = 1,
+ .lpm_sup = 1,
+ .lpm_uA = 9000,
+ .hpm_uA = 200000, /* 200mA */
+ },
+ /* SDCC3 : External card slot connected */
+ [SDCC3] = {
+ .name = "sdc_vdd",
+ .high_vol_level = 2950000,
+ .low_vol_level = 2950000,
+ .hpm_uA = 600000, /* 600mA */
+ }
+};
+
+/* Only slots having eMMC card will require VCCQ voltage */
+static struct msm_mmc_reg_data mmc_vccq_reg_data[1] = {
+ /* SDCC1 : eMMC card connected */
+ [SDCC1] = {
+ .name = "sdc_vccq",
+ .always_on = 1,
+ .high_vol_level = 1800000,
+ .low_vol_level = 1800000,
+ .hpm_uA = 200000, /* 200mA */
+ }
+};
+
+/* All SDCC controllers may require voting for VDD PAD voltage */
+static struct msm_mmc_reg_data mmc_vddp_reg_data[MAX_SDCC_CONTROLLER] = {
+ /* SDCC3 : External card slot connected */
+ [SDCC3] = {
+ .name = "sdc_vddp",
+ .high_vol_level = 2950000,
+ .low_vol_level = 1850000,
+ .always_on = 1,
+ .lpm_sup = 1,
+ /* Max. Active current required is 16 mA */
+ .hpm_uA = 16000,
+ /*
+ * Sleep current required is ~300 uA. But min. vote can be
+ * in terms of mA (min. 1 mA). So let's vote for 2 mA
+ * during sleep.
+ */
+ .lpm_uA = 2000,
+ }
+};
+
+static struct msm_mmc_slot_reg_data mmc_slot_vreg_data[MAX_SDCC_CONTROLLER] = {
+ /* SDCC1 : eMMC card connected */
+ [SDCC1] = {
+ .vdd_data = &mmc_vdd_reg_data[SDCC1],
+ .vccq_data = &mmc_vccq_reg_data[SDCC1],
+ },
+ /* SDCC3 : External card slot connected */
+ [SDCC3] = {
+ .vdd_data = &mmc_vdd_reg_data[SDCC3],
+ .vddp_data = &mmc_vddp_reg_data[SDCC3],
+ }
+};
+
+/* SDC1 pad data */
+static struct msm_mmc_pad_drv sdc1_pad_drv_on_cfg[] = {
+ {TLMM_HDRV_SDC1_CLK, GPIO_CFG_16MA},
+ {TLMM_HDRV_SDC1_CMD, GPIO_CFG_10MA},
+ {TLMM_HDRV_SDC1_DATA, GPIO_CFG_10MA}
+};
+
+static struct msm_mmc_pad_drv sdc1_pad_drv_off_cfg[] = {
+ {TLMM_HDRV_SDC1_CLK, GPIO_CFG_2MA},
+ {TLMM_HDRV_SDC1_CMD, GPIO_CFG_2MA},
+ {TLMM_HDRV_SDC1_DATA, GPIO_CFG_2MA}
+};
+
+static struct msm_mmc_pad_pull sdc1_pad_pull_on_cfg[] = {
+ {TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
+ {TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_UP},
+ {TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_UP}
+};
+
+static struct msm_mmc_pad_pull sdc1_pad_pull_off_cfg[] = {
+ {TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
+ {TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_DOWN},
+ {TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_DOWN}
+};
+
+/* SDC3 pad data */
+static struct msm_mmc_pad_drv sdc3_pad_drv_on_cfg[] = {
+ {TLMM_HDRV_SDC3_CLK, GPIO_CFG_8MA},
+ {TLMM_HDRV_SDC3_CMD, GPIO_CFG_8MA},
+ {TLMM_HDRV_SDC3_DATA, GPIO_CFG_8MA}
+};
+
+static struct msm_mmc_pad_drv sdc3_pad_drv_off_cfg[] = {
+ {TLMM_HDRV_SDC3_CLK, GPIO_CFG_2MA},
+ {TLMM_HDRV_SDC3_CMD, GPIO_CFG_2MA},
+ {TLMM_HDRV_SDC3_DATA, GPIO_CFG_2MA}
+};
+
+static struct msm_mmc_pad_pull sdc3_pad_pull_on_cfg[] = {
+ {TLMM_PULL_SDC3_CLK, GPIO_CFG_NO_PULL},
+ {TLMM_PULL_SDC3_CMD, GPIO_CFG_PULL_UP},
+ {TLMM_PULL_SDC3_DATA, GPIO_CFG_PULL_UP}
+};
+
+static struct msm_mmc_pad_pull sdc3_pad_pull_off_cfg[] = {
+ {TLMM_PULL_SDC3_CLK, GPIO_CFG_NO_PULL},
+ /*
+ * SDC3 CMD line should be PULLed UP otherwise fluid platform will
+ * see transitions (1 -> 0 and 0 -> 1) on card detection line,
+ * which would result in false card detection interrupts.
+ */
+ {TLMM_PULL_SDC3_CMD, GPIO_CFG_PULL_UP},
+ /*
+ * Keeping DATA lines status to PULL UP will make sure that
+ * there is no current leak during sleep if external pull up
+ * is connected to DATA lines.
+ */
+ {TLMM_PULL_SDC3_DATA, GPIO_CFG_PULL_UP}
+};
+
+static struct msm_mmc_pad_pull_data mmc_pad_pull_data[MAX_SDCC_CONTROLLER] = {
+ [SDCC1] = {
+ .on = sdc1_pad_pull_on_cfg,
+ .off = sdc1_pad_pull_off_cfg,
+ .size = ARRAY_SIZE(sdc1_pad_pull_on_cfg)
+ },
+ [SDCC3] = {
+ .on = sdc3_pad_pull_on_cfg,
+ .off = sdc3_pad_pull_off_cfg,
+ .size = ARRAY_SIZE(sdc3_pad_pull_on_cfg)
+ },
+};
+
+static struct msm_mmc_pad_drv_data mmc_pad_drv_data[MAX_SDCC_CONTROLLER] = {
+ [SDCC1] = {
+ .on = sdc1_pad_drv_on_cfg,
+ .off = sdc1_pad_drv_off_cfg,
+ .size = ARRAY_SIZE(sdc1_pad_drv_on_cfg)
+ },
+ [SDCC3] = {
+ .on = sdc3_pad_drv_on_cfg,
+ .off = sdc3_pad_drv_off_cfg,
+ .size = ARRAY_SIZE(sdc3_pad_drv_on_cfg)
+ },
+};
+
+static struct msm_mmc_pad_data mmc_pad_data[MAX_SDCC_CONTROLLER] = {
+ [SDCC1] = {
+ .pull = &mmc_pad_pull_data[SDCC1],
+ .drv = &mmc_pad_drv_data[SDCC1]
+ },
+ [SDCC3] = {
+ .pull = &mmc_pad_pull_data[SDCC3],
+ .drv = &mmc_pad_drv_data[SDCC3]
+ },
+};
+
+static struct msm_mmc_pin_data mmc_slot_pin_data[MAX_SDCC_CONTROLLER] = {
+ [SDCC1] = {
+ .pad_data = &mmc_pad_data[SDCC1],
+ },
+ [SDCC3] = {
+ .pad_data = &mmc_pad_data[SDCC3],
+ },
+};
+
+static unsigned int sdc1_sup_clk_rates[] = {
+ 400000, 24000000, 48000000
+};
+
+static unsigned int sdc3_sup_clk_rates[] = {
+ 400000, 24000000, 48000000, 96000000
+};
+
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+static struct mmc_platform_data msm8960_sdc1_data = {
+ .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
+#ifdef CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT
+ .mmc_bus_width = MMC_CAP_8_BIT_DATA,
+#else
+ .mmc_bus_width = MMC_CAP_4_BIT_DATA,
+#endif
+ .sup_clk_table = sdc1_sup_clk_rates,
+ .sup_clk_cnt = ARRAY_SIZE(sdc1_sup_clk_rates),
+ .pclk_src_dfab = 1,
+ .nonremovable = 1,
+ .vreg_data = &mmc_slot_vreg_data[SDCC1],
+ .pin_data = &mmc_slot_pin_data[SDCC1]
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+static struct mmc_platform_data msm8960_sdc3_data = {
+ .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
+ .mmc_bus_width = MMC_CAP_4_BIT_DATA,
+ .sup_clk_table = sdc3_sup_clk_rates,
+ .sup_clk_cnt = ARRAY_SIZE(sdc3_sup_clk_rates),
+ .pclk_src_dfab = 1,
+#ifdef CONFIG_MMC_MSM_SDC3_WP_SUPPORT
+ .wpswitch_gpio = PM8921_GPIO_PM_TO_SYS(16),
+#endif
+ .vreg_data = &mmc_slot_vreg_data[SDCC3],
+ .pin_data = &mmc_slot_pin_data[SDCC3],
+#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
+ .status_gpio = PM8921_GPIO_PM_TO_SYS(26),
+ .status_irq = PM8921_GPIO_IRQ(PM8921_IRQ_BASE, 26),
+ .irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+#endif
+ .xpc_cap = 1,
+ .uhs_caps = (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 |
+ MMC_CAP_MAX_CURRENT_600)
+};
+#endif
+
+void __init msm8960_init_mmc(void)
+{
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+ /* SDC1 : eMMC card connected */
+ msm_add_sdcc(1, &msm8960_sdc1_data);
+#endif
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+ /* SDC3: External card slot */
+ msm_add_sdcc(3, &msm8960_sdc3_data);
+#endif
+}
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
new file mode 100644
index 0000000..06d63d9
--- /dev/null
+++ b/arch/arm/mach-msm/board-8960.c
@@ -0,0 +1,2262 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/i2c.h>
+#include <linux/i2c/sx150x.h>
+#include <linux/i2c/isl9519.h>
+#include <linux/gpio.h>
+#include <linux/msm_ssbi.h>
+#include <linux/regulator/gpio-regulator.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/slimbus/slimbus.h>
+#include <linux/bootmem.h>
+#include <linux/msm_kgsl.h>
+#ifdef CONFIG_ANDROID_PMEM
+#include <linux/android_pmem.h>
+#endif
+#include <linux/cyttsp.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_data/qcom_crypto_device.h>
+#include <linux/platform_data/qcom_wcnss_device.h>
+#include <linux/leds.h>
+#include <linux/leds-pm8xxx.h>
+#include <linux/i2c/atmel_mxt_ts.h>
+#include <linux/msm_tsens.h>
+#include <linux/ks8851.h>
+#include <linux/i2c/isa1200.h>
+#include <linux/memory.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/setup.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/mmc.h>
+
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_spi.h>
+#ifdef CONFIG_USB_MSM_OTG_72K
+#include <mach/msm_hsusb.h>
+#else
+#include <linux/usb/msm_hsusb.h>
+#endif
+#include <linux/usb/android.h>
+#include <mach/usbdiag.h>
+#include <mach/socinfo.h>
+#include <mach/rpm.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_memtypes.h>
+#include <mach/dma.h>
+#include <mach/msm_dsps.h>
+#include <mach/msm_xo.h>
+#include <mach/restart.h>
+
+#ifdef CONFIG_WCD9310_CODEC
+#include <linux/slimbus/slimbus.h>
+#include <linux/mfd/wcd9310/core.h>
+#include <linux/mfd/wcd9310/pdata.h>
+#endif
+
+#include <linux/ion.h>
+#include <mach/ion.h>
+#include <mach/mdm2.h>
+
+#include "timer.h"
+#include "devices.h"
+#include "devices-msm8x60.h"
+#include "spm.h"
+#include "board-8960.h"
+#include "pm.h"
+#include "cpuidle.h"
+#include "rpm_resources.h"
+#include "mpm.h"
+#include "acpuclock.h"
+#include "rpm_log.h"
+#include "smd_private.h"
+#include "pm-boot.h"
+#include "msm_watchdog.h"
+
+static struct platform_device msm_fm_platform_init = {
+ .name = "iris_fm",
+ .id = -1,
+};
+
+#define KS8851_RST_GPIO 89
+#define KS8851_IRQ_GPIO 90
+#define HAP_SHIFT_LVL_OE_GPIO 47
+
+#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
+
+struct sx150x_platform_data msm8960_sx150x_data[] = {
+ [SX150X_CAM] = {
+ .gpio_base = GPIO_CAM_EXPANDER_BASE,
+ .oscio_is_gpo = false,
+ .io_pullup_ena = 0x0,
+ .io_pulldn_ena = 0xc0,
+ .io_open_drain_ena = 0x0,
+ .irq_summary = -1,
+ },
+};
+
+#endif
+
+#define MSM_PMEM_ADSP_SIZE 0x3800000
+#define MSM_PMEM_AUDIO_SIZE 0x28B000
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+#define MSM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
+#else
+#define MSM_PMEM_SIZE 0x1C00000 /* 28 Mbytes */
+#endif
+
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+#define MSM_PMEM_KERNEL_EBI1_SIZE 0xB0C000
+#define MSM_ION_EBI_SIZE (MSM_PMEM_SIZE + 0x600000)
+#define MSM_ION_ADSP_SIZE MSM_PMEM_ADSP_SIZE
+#define MSM_ION_HEAP_NUM 5
+#else
+#define MSM_PMEM_KERNEL_EBI1_SIZE 0x110C000
+#define MSM_ION_HEAP_NUM 2
+#endif
+
+#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
+static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
+static int __init pmem_kernel_ebi1_size_setup(char *p)
+{
+ pmem_kernel_ebi1_size = memparse(p, NULL);
+ return 0;
+}
+early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+#endif
+
+#ifdef CONFIG_ANDROID_PMEM
+static unsigned pmem_size = MSM_PMEM_SIZE;
+static int __init pmem_size_setup(char *p)
+{
+ pmem_size = memparse(p, NULL);
+ return 0;
+}
+early_param("pmem_size", pmem_size_setup);
+
+static unsigned pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
+
+static int __init pmem_adsp_size_setup(char *p)
+{
+ pmem_adsp_size = memparse(p, NULL);
+ return 0;
+}
+early_param("pmem_adsp_size", pmem_adsp_size_setup);
+
+static unsigned pmem_audio_size = MSM_PMEM_AUDIO_SIZE;
+
+static int __init pmem_audio_size_setup(char *p)
+{
+ pmem_audio_size = memparse(p, NULL);
+ return 0;
+}
+early_param("pmem_audio_size", pmem_audio_size_setup);
+#endif
+
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+static struct android_pmem_platform_data android_pmem_pdata = {
+ .name = "pmem",
+ .allocator_type = PMEM_ALLOCATORTYPE_ALLORNOTHING,
+ .cached = 1,
+ .memory_type = MEMTYPE_EBI1,
+};
+
+static struct platform_device android_pmem_device = {
+ .name = "android_pmem",
+ .id = 0,
+ .dev = {.platform_data = &android_pmem_pdata},
+};
+
+static struct android_pmem_platform_data android_pmem_adsp_pdata = {
+ .name = "pmem_adsp",
+ .allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+ .cached = 0,
+ .memory_type = MEMTYPE_EBI1,
+};
+static struct platform_device android_pmem_adsp_device = {
+ .name = "android_pmem",
+ .id = 2,
+ .dev = { .platform_data = &android_pmem_adsp_pdata },
+};
+#endif
+
+static struct android_pmem_platform_data android_pmem_audio_pdata = {
+ .name = "pmem_audio",
+ .allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+ .cached = 0,
+ .memory_type = MEMTYPE_EBI1,
+};
+
+static struct platform_device android_pmem_audio_device = {
+ .name = "android_pmem",
+ .id = 4,
+ .dev = { .platform_data = &android_pmem_audio_pdata },
+};
+#endif
+
+#define DSP_RAM_BASE_8960 0x8da00000
+#define DSP_RAM_SIZE_8960 0x1800000
+static int dspcrashd_pdata_8960 = 0xDEADDEAD;
+
+static struct resource resources_dspcrashd_8960[] = {
+ {
+ .name = "msm_dspcrashd",
+ .start = DSP_RAM_BASE_8960,
+ .end = DSP_RAM_BASE_8960 + DSP_RAM_SIZE_8960,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+static struct platform_device msm_device_dspcrashd_8960 = {
+ .name = "msm_dspcrashd",
+ .num_resources = ARRAY_SIZE(resources_dspcrashd_8960),
+ .resource = resources_dspcrashd_8960,
+ .dev = { .platform_data = &dspcrashd_pdata_8960 },
+};
+
+static struct memtype_reserve msm8960_reserve_table[] __initdata = {
+ [MEMTYPE_SMI] = {
+ },
+ [MEMTYPE_EBI0] = {
+ .flags = MEMTYPE_FLAGS_1M_ALIGN,
+ },
+ [MEMTYPE_EBI1] = {
+ .flags = MEMTYPE_FLAGS_1M_ALIGN,
+ },
+};
+
+static void __init size_pmem_devices(void)
+{
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+ android_pmem_adsp_pdata.size = pmem_adsp_size;
+ android_pmem_pdata.size = pmem_size;
+#endif
+ android_pmem_audio_pdata.size = MSM_PMEM_AUDIO_SIZE;
+#endif
+}
+
+static void __init reserve_memory_for(struct android_pmem_platform_data *p)
+{
+ msm8960_reserve_table[p->memory_type].size += p->size;
+}
+
+static void __init reserve_pmem_memory(void)
+{
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+ reserve_memory_for(&android_pmem_adsp_pdata);
+ reserve_memory_for(&android_pmem_pdata);
+#endif
+ reserve_memory_for(&android_pmem_audio_pdata);
+ msm8960_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
+#endif
+}
+
+static int msm8960_paddr_to_memtype(unsigned int paddr)
+{
+ return MEMTYPE_EBI1;
+}
+
+#ifdef CONFIG_ION_MSM
+static struct ion_platform_data ion_pdata = {
+ .nr = MSM_ION_HEAP_NUM,
+ .heaps = {
+ {
+ .id = ION_HEAP_SYSTEM_ID,
+ .type = ION_HEAP_TYPE_SYSTEM,
+ .name = ION_KMALLOC_HEAP_NAME,
+ },
+ {
+ .id = ION_HEAP_SYSTEM_CONTIG_ID,
+ .type = ION_HEAP_TYPE_SYSTEM_CONTIG,
+ .name = ION_VMALLOC_HEAP_NAME,
+ },
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ {
+ .id = ION_HEAP_EBI_ID,
+ .type = ION_HEAP_TYPE_CARVEOUT,
+ .name = ION_EBI1_HEAP_NAME,
+ .size = MSM_ION_EBI_SIZE,
+ .memory_type = ION_EBI_TYPE,
+ },
+ {
+ .id = ION_HEAP_ADSP_ID,
+ .type = ION_HEAP_TYPE_CARVEOUT,
+ .name = ION_ADSP_HEAP_NAME,
+ .size = MSM_ION_ADSP_SIZE,
+ .memory_type = ION_EBI_TYPE,
+ },
+ {
+ .id = ION_HEAP_IOMMU_ID,
+ .type = ION_HEAP_TYPE_IOMMU,
+ .name = ION_IOMMU_HEAP_NAME,
+ },
+#endif
+ }
+};
+
+static struct platform_device ion_dev = {
+ .name = "ion-msm",
+ .id = 1,
+ .dev = { .platform_data = &ion_pdata },
+};
+#endif
+
+static void reserve_ion_memory(void)
+{
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+ msm8960_reserve_table[MEMTYPE_EBI1].size += MSM_ION_EBI_SIZE;
+ msm8960_reserve_table[MEMTYPE_EBI1].size += MSM_ION_ADSP_SIZE;
+#endif
+}
+static void __init msm8960_calculate_reserve_sizes(void)
+{
+ size_pmem_devices();
+ reserve_pmem_memory();
+ reserve_ion_memory();
+}
+
+static struct reserve_info msm8960_reserve_info __initdata = {
+ .memtype_reserve_table = msm8960_reserve_table,
+ .calculate_reserve_sizes = msm8960_calculate_reserve_sizes,
+ .paddr_to_memtype = msm8960_paddr_to_memtype,
+};
+
+static int msm8960_memory_bank_size(void)
+{
+ return 1<<29;
+}
+
+static void __init locate_unstable_memory(void)
+{
+ struct membank *mb = &meminfo.bank[meminfo.nr_banks - 1];
+ unsigned long bank_size;
+ unsigned long low, high;
+
+ bank_size = msm8960_memory_bank_size();
+ low = meminfo.bank[0].start;
+ high = mb->start + mb->size;
+
+ /* Check if 32 bit overflow occured */
+ if (high < mb->start)
+ high = ~0UL;
+
+ low &= ~(bank_size - 1);
+
+ if (high - low <= bank_size)
+ return;
+ msm8960_reserve_info.low_unstable_address = high -
+ MIN_MEMORY_BLOCK_SIZE;
+ msm8960_reserve_info.max_unstable_size = MIN_MEMORY_BLOCK_SIZE;
+
+ msm8960_reserve_info.bank_size = bank_size;
+ pr_info("low unstable address %lx max size %lx bank size %lx\n",
+ msm8960_reserve_info.low_unstable_address,
+ msm8960_reserve_info.max_unstable_size,
+ msm8960_reserve_info.bank_size);
+}
+
+static void __init place_movable_zone(void)
+{
+ movable_reserved_start = msm8960_reserve_info.low_unstable_address;
+ movable_reserved_size = msm8960_reserve_info.max_unstable_size;
+ pr_info("movable zone start %lx size %lx\n",
+ movable_reserved_start, movable_reserved_size);
+}
+
+static void __init msm8960_early_memory(void)
+{
+ reserve_info = &msm8960_reserve_info;
+ locate_unstable_memory();
+ place_movable_zone();
+}
+
+static void __init msm8960_reserve(void)
+{
+ msm_reserve();
+}
+
+static int msm8960_change_memory_power(u64 start, u64 size,
+ int change_type)
+{
+ return soc_change_memory_power(start, size, change_type);
+}
+
+static void __init msm8960_allocate_memory_regions(void)
+{
+ msm8960_allocate_fb_region();
+}
+
+#ifdef CONFIG_WCD9310_CODEC
+
+#define TABLA_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS + NR_PM8921_IRQS)
+
+/* Micbias setting is based on 8660 CDP/MTP/FLUID requirement
+ * 4 micbiases are used to power various analog and digital
+ * microphones operating at 1800 mV. Technically, all micbiases
+ * can source from single cfilter since all microphones operate
+ * at the same voltage level. The arrangement below is to make
+ * sure all cfilters are exercised. LDO_H regulator ouput level
+ * does not need to be as high as 2.85V. It is choosen for
+ * microphone sensitivity purpose.
+ */
+static struct tabla_pdata tabla_platform_data = {
+ .slimbus_slave_device = {
+ .name = "tabla-slave",
+ .e_addr = {0, 0, 0x10, 0, 0x17, 2},
+ },
+ .irq = MSM_GPIO_TO_INT(62),
+ .irq_base = TABLA_INTERRUPT_BASE,
+ .num_irqs = NR_TABLA_IRQS,
+ .reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
+ .micbias = {
+ .ldoh_v = TABLA_LDOH_2P85_V,
+ .cfilt1_mv = 1800,
+ .cfilt2_mv = 1800,
+ .cfilt3_mv = 1800,
+ .bias1_cfilt_sel = TABLA_CFILT1_SEL,
+ .bias2_cfilt_sel = TABLA_CFILT2_SEL,
+ .bias3_cfilt_sel = TABLA_CFILT3_SEL,
+ .bias4_cfilt_sel = TABLA_CFILT3_SEL,
+ }
+};
+
+static struct slim_device msm_slim_tabla = {
+ .name = "tabla-slim",
+ .e_addr = {0, 1, 0x10, 0, 0x17, 2},
+ .dev = {
+ .platform_data = &tabla_platform_data,
+ },
+};
+
+static struct tabla_pdata tabla20_platform_data = {
+ .slimbus_slave_device = {
+ .name = "tabla-slave",
+ .e_addr = {0, 0, 0x60, 0, 0x17, 2},
+ },
+ .irq = MSM_GPIO_TO_INT(62),
+ .irq_base = TABLA_INTERRUPT_BASE,
+ .num_irqs = NR_TABLA_IRQS,
+ .reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
+ .micbias = {
+ .ldoh_v = TABLA_LDOH_2P85_V,
+ .cfilt1_mv = 1800,
+ .cfilt2_mv = 1800,
+ .cfilt3_mv = 1800,
+ .bias1_cfilt_sel = TABLA_CFILT1_SEL,
+ .bias2_cfilt_sel = TABLA_CFILT2_SEL,
+ .bias3_cfilt_sel = TABLA_CFILT3_SEL,
+ .bias4_cfilt_sel = TABLA_CFILT3_SEL,
+ }
+};
+
+static struct slim_device msm_slim_tabla20 = {
+ .name = "tabla2x-slim",
+ .e_addr = {0, 1, 0x60, 0, 0x17, 2},
+ .dev = {
+ .platform_data = &tabla20_platform_data,
+ },
+};
+#endif
+
+static struct slim_boardinfo msm_slim_devices[] = {
+#ifdef CONFIG_WCD9310_CODEC
+ {
+ .bus_num = 1,
+ .slim_slave = &msm_slim_tabla,
+ },
+ {
+ .bus_num = 1,
+ .slim_slave = &msm_slim_tabla20,
+ },
+#endif
+ /* add more slimbus slaves as needed */
+};
+
+#define MSM_WCNSS_PHYS 0x03000000
+#define MSM_WCNSS_SIZE 0x280000
+
+static struct resource resources_wcnss_wlan[] = {
+ {
+ .start = RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ,
+ .end = RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ,
+ .name = "wcnss_wlanrx_irq",
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ,
+ .end = RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ,
+ .name = "wcnss_wlantx_irq",
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = MSM_WCNSS_PHYS,
+ .end = MSM_WCNSS_PHYS + MSM_WCNSS_SIZE - 1,
+ .name = "wcnss_mmio",
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = 84,
+ .end = 88,
+ .name = "wcnss_gpios_5wire",
+ .flags = IORESOURCE_IO,
+ },
+};
+
+static struct qcom_wcnss_opts qcom_wcnss_pdata = {
+ .has_48mhz_xo = 1,
+};
+
+static struct platform_device msm_device_wcnss_wlan = {
+ .name = "wcnss_wlan",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(resources_wcnss_wlan),
+ .resource = resources_wcnss_wlan,
+ .dev = {.platform_data = &qcom_wcnss_pdata},
+};
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+ defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE) || \
+ defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+ defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+#define QCE_SIZE 0x10000
+#define QCE_0_BASE 0x18500000
+
+#define QCE_HW_KEY_SUPPORT 0
+#define QCE_SHA_HMAC_SUPPORT 1
+#define QCE_SHARE_CE_RESOURCE 1
+#define QCE_CE_SHARED 0
+
+static struct resource qcrypto_resources[] = {
+ [0] = {
+ .start = QCE_0_BASE,
+ .end = QCE_0_BASE + QCE_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "crypto_channels",
+ .start = DMOV_CE_IN_CHAN,
+ .end = DMOV_CE_OUT_CHAN,
+ .flags = IORESOURCE_DMA,
+ },
+ [2] = {
+ .name = "crypto_crci_in",
+ .start = DMOV_CE_IN_CRCI,
+ .end = DMOV_CE_IN_CRCI,
+ .flags = IORESOURCE_DMA,
+ },
+ [3] = {
+ .name = "crypto_crci_out",
+ .start = DMOV_CE_OUT_CRCI,
+ .end = DMOV_CE_OUT_CRCI,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+static struct resource qcedev_resources[] = {
+ [0] = {
+ .start = QCE_0_BASE,
+ .end = QCE_0_BASE + QCE_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "crypto_channels",
+ .start = DMOV_CE_IN_CHAN,
+ .end = DMOV_CE_OUT_CHAN,
+ .flags = IORESOURCE_DMA,
+ },
+ [2] = {
+ .name = "crypto_crci_in",
+ .start = DMOV_CE_IN_CRCI,
+ .end = DMOV_CE_IN_CRCI,
+ .flags = IORESOURCE_DMA,
+ },
+ [3] = {
+ .name = "crypto_crci_out",
+ .start = DMOV_CE_OUT_CRCI,
+ .end = DMOV_CE_OUT_CRCI,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+ defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+
+static struct msm_ce_hw_support qcrypto_ce_hw_suppport = {
+ .ce_shared = QCE_CE_SHARED,
+ .shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+ .hw_key_support = QCE_HW_KEY_SUPPORT,
+ .sha_hmac = QCE_SHA_HMAC_SUPPORT,
+};
+
+static struct platform_device qcrypto_device = {
+ .name = "qcrypto",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(qcrypto_resources),
+ .resource = qcrypto_resources,
+ .dev = {
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &qcrypto_ce_hw_suppport,
+ },
+};
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+ defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+static struct msm_ce_hw_support qcedev_ce_hw_suppport = {
+ .ce_shared = QCE_CE_SHARED,
+ .shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+ .hw_key_support = QCE_HW_KEY_SUPPORT,
+ .sha_hmac = QCE_SHA_HMAC_SUPPORT,
+};
+
+static struct platform_device qcedev_device = {
+ .name = "qce",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(qcedev_resources),
+ .resource = qcedev_resources,
+ .dev = {
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &qcedev_ce_hw_suppport,
+ },
+};
+#endif
+
+#define MDM2AP_ERRFATAL 70
+#define AP2MDM_ERRFATAL 95
+#define MDM2AP_STATUS 69
+#define AP2MDM_STATUS 94
+#define AP2MDM_PMIC_RESET_N 80
+#define AP2MDM_KPDPWR_N 81
+
+static struct resource mdm_resources[] = {
+ {
+ .start = MDM2AP_ERRFATAL,
+ .end = MDM2AP_ERRFATAL,
+ .name = "MDM2AP_ERRFATAL",
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .start = AP2MDM_ERRFATAL,
+ .end = AP2MDM_ERRFATAL,
+ .name = "AP2MDM_ERRFATAL",
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .start = MDM2AP_STATUS,
+ .end = MDM2AP_STATUS,
+ .name = "MDM2AP_STATUS",
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .start = AP2MDM_STATUS,
+ .end = AP2MDM_STATUS,
+ .name = "AP2MDM_STATUS",
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .start = AP2MDM_PMIC_RESET_N,
+ .end = AP2MDM_PMIC_RESET_N,
+ .name = "AP2MDM_PMIC_RESET_N",
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .start = AP2MDM_KPDPWR_N,
+ .end = AP2MDM_KPDPWR_N,
+ .name = "AP2MDM_KPDPWR_N",
+ .flags = IORESOURCE_IO,
+ },
+};
+
+static struct mdm_platform_data mdm_platform_data = {
+ .mdm_version = "2.5",
+};
+
+static struct platform_device mdm_device = {
+ .name = "mdm2_modem",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(mdm_resources),
+ .resource = mdm_resources,
+ .dev = {
+ .platform_data = &mdm_platform_data,
+ },
+};
+
+static struct platform_device *mdm_devices[] __initdata = {
+ &mdm_device,
+};
+
+#define MSM_SHARED_RAM_PHYS 0x80000000
+
+static void __init msm8960_map_io(void)
+{
+ msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
+ msm_map_msm8960_io();
+
+ if (socinfo_init() < 0)
+ pr_err("socinfo_init() failed!\n");
+}
+
+static void __init msm8960_init_irq(void)
+{
+ unsigned int i;
+
+ msm_mpm_irq_extn_init();
+ gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
+ (void *)MSM_QGIC_CPU_BASE);
+
+ /* Edge trigger PPIs except AVS_SVICINT and AVS_SVICINTSWDONE */
+ writel_relaxed(0xFFFFD7FF, MSM_QGIC_DIST_BASE + GIC_DIST_CONFIG + 4);
+
+ writel_relaxed(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
+ mb();
+
+ /* FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
+ * as they are configured as level, which does not play nice with
+ * handle_percpu_irq.
+ */
+ for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
+ if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
+ irq_set_handler(i, handle_percpu_irq);
+ }
+}
+
+static void __init msm8960_init_buses(void)
+{
+#ifdef CONFIG_MSM_BUS_SCALING
+ msm_bus_rpm_set_mt_mask();
+ msm_bus_8960_apps_fabric_pdata.rpm_enabled = 1;
+ msm_bus_8960_sys_fabric_pdata.rpm_enabled = 1;
+ msm_bus_8960_mm_fabric_pdata.rpm_enabled = 1;
+ msm_bus_apps_fabric.dev.platform_data =
+ &msm_bus_8960_apps_fabric_pdata;
+ msm_bus_sys_fabric.dev.platform_data = &msm_bus_8960_sys_fabric_pdata;
+ msm_bus_mm_fabric.dev.platform_data = &msm_bus_8960_mm_fabric_pdata;
+ msm_bus_sys_fpb.dev.platform_data = &msm_bus_8960_sys_fpb_pdata;
+ msm_bus_cpss_fpb.dev.platform_data = &msm_bus_8960_cpss_fpb_pdata;
+#endif
+}
+
+static struct msm_spi_platform_data msm8960_qup_spi_gsbi1_pdata = {
+ .max_clock_speed = 15060000,
+};
+
+#ifdef CONFIG_USB_MSM_OTG_72K
+static struct msm_otg_platform_data msm_otg_pdata;
+#else
+#define USB_5V_EN 42
+static void msm_hsusb_vbus_power(bool on)
+{
+ int rc;
+ static bool vbus_is_on;
+ static struct regulator *mvs_otg_switch;
+
+ if (vbus_is_on == on)
+ return;
+
+ if (on) {
+ mvs_otg_switch = regulator_get(&msm8960_device_otg.dev,
+ "vbus_otg");
+ if (IS_ERR(mvs_otg_switch)) {
+ pr_err("Unable to get mvs_otg_switch\n");
+ return;
+ }
+
+ rc = gpio_request(PM8921_GPIO_PM_TO_SYS(USB_5V_EN),
+ "usb_5v_en");
+ if (rc < 0) {
+ pr_err("failed to request usb_5v_en gpio\n");
+ goto put_mvs_otg;
+ }
+
+ rc = gpio_direction_output(PM8921_GPIO_PM_TO_SYS(USB_5V_EN), 1);
+ if (rc) {
+ pr_err("%s: unable to set_direction for gpio [%d]\n",
+ __func__, PM8921_GPIO_PM_TO_SYS(USB_5V_EN));
+ goto free_usb_5v_en;
+ }
+
+ if (regulator_enable(mvs_otg_switch)) {
+ pr_err("unable to enable mvs_otg_switch\n");
+ goto err_ldo_gpio_set_dir;
+ }
+
+ vbus_is_on = true;
+ return;
+ }
+ regulator_disable(mvs_otg_switch);
+err_ldo_gpio_set_dir:
+ gpio_set_value_cansleep(PM8921_GPIO_PM_TO_SYS(USB_5V_EN), 0);
+free_usb_5v_en:
+ gpio_free(PM8921_GPIO_PM_TO_SYS(USB_5V_EN));
+put_mvs_otg:
+ regulator_put(mvs_otg_switch);
+ vbus_is_on = false;
+}
+
+static int wr_phy_init_seq[] = {
+ 0x44, 0x80, /* set VBUS valid threshold
+ and disconnect valid threshold */
+ 0x38, 0x81, /* update DC voltage level */
+ 0x14, 0x82, /* set preemphasis and rise/fall time */
+ 0x13, 0x83, /* set source impedance adjusment */
+ -1};
+
+static int liquid_v1_phy_init_seq[] = {
+ 0x44, 0x80,/* set VBUS valid threshold
+ and disconnect valid threshold */
+ 0x3C, 0x81,/* update DC voltage level */
+ 0x18, 0x82,/* set preemphasis and rise/fall time */
+ 0x23, 0x83,/* set source impedance sdjusment */
+ -1};
+
+static struct msm_otg_platform_data msm_otg_pdata = {
+ .mode = USB_OTG,
+ .otg_control = OTG_PMIC_CONTROL,
+ .phy_type = SNPS_28NM_INTEGRATED_PHY,
+ .pclk_src_name = "dfab_usb_hs_clk",
+ .pmic_id_irq = PM8921_USB_ID_IN_IRQ(PM8921_IRQ_BASE),
+ .vbus_power = msm_hsusb_vbus_power,
+ .power_budget = 750,
+};
+#endif
+
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+#define HSIC_HUB_RESET_GPIO 91
+static struct msm_hsic_host_platform_data msm_hsic_pdata = {
+ .strobe = 150,
+ .data = 151,
+};
+#else
+static struct msm_hsic_host_platform_data msm_hsic_pdata;
+#endif
+
+#define PID_MAGIC_ID 0x71432909
+#define SERIAL_NUM_MAGIC_ID 0x61945374
+#define SERIAL_NUMBER_LENGTH 127
+#define DLOAD_USB_BASE_ADD 0x2A03F0C8
+
+struct magic_num_struct {
+ uint32_t pid;
+ uint32_t serial_num;
+};
+
+struct dload_struct {
+ uint32_t reserved1;
+ uint32_t reserved2;
+ uint32_t reserved3;
+ uint16_t reserved4;
+ uint16_t pid;
+ char serial_number[SERIAL_NUMBER_LENGTH];
+ uint16_t reserved5;
+ struct magic_num_struct magic_struct;
+};
+
+static int usb_diag_update_pid_and_serial_num(uint32_t pid, const char *snum)
+{
+ struct dload_struct __iomem *dload = 0;
+
+ dload = ioremap(DLOAD_USB_BASE_ADD, sizeof(*dload));
+ if (!dload) {
+ pr_err("%s: cannot remap I/O memory region: %08x\n",
+ __func__, DLOAD_USB_BASE_ADD);
+ return -ENXIO;
+ }
+
+ pr_debug("%s: dload:%p pid:%x serial_num:%s\n",
+ __func__, dload, pid, snum);
+ /* update pid */
+ dload->magic_struct.pid = PID_MAGIC_ID;
+ dload->pid = pid;
+
+ /* update serial number */
+ dload->magic_struct.serial_num = 0;
+ if (!snum) {
+ memset(dload->serial_number, 0, SERIAL_NUMBER_LENGTH);
+ goto out;
+ }
+
+ dload->magic_struct.serial_num = SERIAL_NUM_MAGIC_ID;
+ strlcpy(dload->serial_number, snum, SERIAL_NUMBER_LENGTH);
+out:
+ iounmap(dload);
+ return 0;
+}
+
+static struct android_usb_platform_data android_usb_pdata = {
+ .update_pid_and_serial_num = usb_diag_update_pid_and_serial_num,
+};
+
+static struct platform_device android_usb_device = {
+ .name = "android_usb",
+ .id = -1,
+ .dev = {
+ .platform_data = &android_usb_pdata,
+ },
+};
+
+static uint8_t spm_wfi_cmd_sequence[] __initdata = {
+ 0x03, 0x0f,
+};
+
+static uint8_t spm_power_collapse_without_rpm[] __initdata = {
+ 0x00, 0x24, 0x54, 0x10,
+ 0x09, 0x03, 0x01,
+ 0x10, 0x54, 0x30, 0x0C,
+ 0x24, 0x30, 0x0f,
+};
+
+static uint8_t spm_power_collapse_with_rpm[] __initdata = {
+ 0x00, 0x24, 0x54, 0x10,
+ 0x09, 0x07, 0x01, 0x0B,
+ 0x10, 0x54, 0x30, 0x0C,
+ 0x24, 0x30, 0x0f,
+};
+
+static struct msm_spm_seq_entry msm_spm_seq_list[] __initdata = {
+ [0] = {
+ .mode = MSM_SPM_MODE_CLOCK_GATING,
+ .notify_rpm = false,
+ .cmd = spm_wfi_cmd_sequence,
+ },
+ [1] = {
+ .mode = MSM_SPM_MODE_POWER_COLLAPSE,
+ .notify_rpm = false,
+ .cmd = spm_power_collapse_without_rpm,
+ },
+ [2] = {
+ .mode = MSM_SPM_MODE_POWER_COLLAPSE,
+ .notify_rpm = true,
+ .cmd = spm_power_collapse_with_rpm,
+ },
+};
+
+static struct msm_spm_platform_data msm_spm_data[] __initdata = {
+ [0] = {
+ .reg_base_addr = MSM_SAW0_BASE,
+ .reg_init_values[MSM_SPM_REG_SAW2_SECURE] = 0x00,
+ .reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
+ .reg_init_values[MSM_SPM_REG_SAW2_VCTL] = 0xB0,
+#if defined(CONFIG_MSM_AVS_HW)
+ .reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x00,
+ .reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
+#endif
+ .reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020202,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
+ .vctl_timeout_us = 50,
+ .num_modes = ARRAY_SIZE(msm_spm_seq_list),
+ .modes = msm_spm_seq_list,
+ },
+ [1] = {
+ .reg_base_addr = MSM_SAW1_BASE,
+ .reg_init_values[MSM_SPM_REG_SAW2_SECURE] = 0x00,
+ .reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
+ .reg_init_values[MSM_SPM_REG_SAW2_VCTL] = 0xB0,
+#if defined(CONFIG_MSM_AVS_HW)
+ .reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x00,
+ .reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
+#endif
+ .reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020202,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
+ .vctl_timeout_us = 50,
+ .num_modes = ARRAY_SIZE(msm_spm_seq_list),
+ .modes = msm_spm_seq_list,
+ },
+};
+
+static uint8_t l2_spm_wfi_cmd_sequence[] __initdata = {
+ 0x00, 0x20, 0x03, 0x20,
+ 0x00, 0x0f,
+};
+
+static uint8_t l2_spm_gdhs_cmd_sequence[] __initdata = {
+ 0x00, 0x20, 0x34, 0x64,
+ 0x48, 0x07, 0x48, 0x20,
+ 0x50, 0x64, 0x04, 0x34,
+ 0x50, 0x0f,
+};
+static uint8_t l2_spm_power_off_cmd_sequence[] __initdata = {
+ 0x00, 0x10, 0x34, 0x64,
+ 0x48, 0x07, 0x48, 0x10,
+ 0x50, 0x64, 0x04, 0x34,
+ 0x50, 0x0F,
+};
+
+static struct msm_spm_seq_entry msm_spm_l2_seq_list[] __initdata = {
+ [0] = {
+ .mode = MSM_SPM_L2_MODE_RETENTION,
+ .notify_rpm = false,
+ .cmd = l2_spm_wfi_cmd_sequence,
+ },
+ [1] = {
+ .mode = MSM_SPM_L2_MODE_GDHS,
+ .notify_rpm = true,
+ .cmd = l2_spm_gdhs_cmd_sequence,
+ },
+ [2] = {
+ .mode = MSM_SPM_L2_MODE_POWER_COLLAPSE,
+ .notify_rpm = true,
+ .cmd = l2_spm_power_off_cmd_sequence,
+ },
+};
+
+static struct msm_spm_platform_data msm_spm_l2_data[] __initdata = {
+ [0] = {
+ .reg_base_addr = MSM_SAW_L2_BASE,
+ .reg_init_values[MSM_SPM_REG_SAW2_SECURE] = 0x00,
+ .reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x00,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020202,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x00A000AE,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x00A00020,
+ .modes = msm_spm_l2_seq_list,
+ .num_modes = ARRAY_SIZE(msm_spm_l2_seq_list),
+ },
+};
+
+#define PM_HAP_EN_GPIO PM8921_GPIO_PM_TO_SYS(33)
+#define PM_HAP_LEN_GPIO PM8921_GPIO_PM_TO_SYS(20)
+
+static struct msm_xo_voter *xo_handle_d1;
+
+static int isa1200_power(int on)
+{
+ int rc = 0;
+
+ gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !!on);
+
+ rc = on ? msm_xo_mode_vote(xo_handle_d1, MSM_XO_MODE_ON) :
+ msm_xo_mode_vote(xo_handle_d1, MSM_XO_MODE_OFF);
+ if (rc < 0) {
+ pr_err("%s: failed to %svote for TCXO D1 buffer%d\n",
+ __func__, on ? "" : "de-", rc);
+ goto err_xo_vote;
+ }
+
+ return 0;
+
+err_xo_vote:
+ gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !on);
+ return rc;
+}
+
+static int isa1200_dev_setup(bool enable)
+{
+ int rc = 0;
+
+ struct pm_gpio hap_gpio_config = {
+ .direction = PM_GPIO_DIR_OUT,
+ .pull = PM_GPIO_PULL_NO,
+ .out_strength = PM_GPIO_STRENGTH_HIGH,
+ .function = PM_GPIO_FUNC_NORMAL,
+ .inv_int_pol = 0,
+ .vin_sel = 2,
+ .output_buffer = PM_GPIO_OUT_BUF_CMOS,
+ .output_value = 0,
+ };
+
+ if (enable == true) {
+ rc = pm8xxx_gpio_config(PM_HAP_EN_GPIO, &hap_gpio_config);
+ if (rc) {
+ pr_err("%s: pm8921 gpio %d config failed(%d)\n",
+ __func__, PM_HAP_EN_GPIO, rc);
+ return rc;
+ }
+
+ rc = pm8xxx_gpio_config(PM_HAP_LEN_GPIO, &hap_gpio_config);
+ if (rc) {
+ pr_err("%s: pm8921 gpio %d config failed(%d)\n",
+ __func__, PM_HAP_LEN_GPIO, rc);
+ return rc;
+ }
+
+ rc = gpio_request(HAP_SHIFT_LVL_OE_GPIO, "hap_shft_lvl_oe");
+ if (rc) {
+ pr_err("%s: unable to request gpio %d (%d)\n",
+ __func__, HAP_SHIFT_LVL_OE_GPIO, rc);
+ return rc;
+ }
+
+ rc = gpio_direction_output(HAP_SHIFT_LVL_OE_GPIO, 0);
+ if (rc) {
+ pr_err("%s: Unable to set direction\n", __func__);
+ goto free_gpio;
+ }
+
+ xo_handle_d1 = msm_xo_get(MSM_XO_TCXO_D1, "isa1200");
+ if (IS_ERR(xo_handle_d1)) {
+ rc = PTR_ERR(xo_handle_d1);
+ pr_err("%s: failed to get the handle for D1(%d)\n",
+ __func__, rc);
+ goto gpio_set_dir;
+ }
+ } else {
+ gpio_free(HAP_SHIFT_LVL_OE_GPIO);
+
+ msm_xo_put(xo_handle_d1);
+ }
+
+ return 0;
+
+gpio_set_dir:
+ gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, 0);
+free_gpio:
+ gpio_free(HAP_SHIFT_LVL_OE_GPIO);
+ return rc;
+}
+
+static struct isa1200_regulator isa1200_reg_data[] = {
+ {
+ .name = "vcc_i2c",
+ .min_uV = ISA_I2C_VTG_MIN_UV,
+ .max_uV = ISA_I2C_VTG_MAX_UV,
+ .load_uA = ISA_I2C_CURR_UA,
+ },
+};
+
+static struct isa1200_platform_data isa1200_1_pdata = {
+ .name = "vibrator",
+ .dev_setup = isa1200_dev_setup,
+ .power_on = isa1200_power,
+ .hap_en_gpio = PM_HAP_EN_GPIO,
+ .hap_len_gpio = PM_HAP_LEN_GPIO,
+ .max_timeout = 15000,
+ .mode_ctrl = PWM_GEN_MODE,
+ .pwm_fd = {
+ .pwm_div = 256,
+ },
+ .is_erm = false,
+ .smart_en = true,
+ .ext_clk_en = true,
+ .chip_en = 1,
+ .regulator_info = isa1200_reg_data,
+ .num_regulators = ARRAY_SIZE(isa1200_reg_data),
+};
+
+static struct i2c_board_info msm_isa1200_board_info[] __initdata = {
+ {
+ I2C_BOARD_INFO("isa1200_1", 0x90>>1),
+ .platform_data = &isa1200_1_pdata,
+ },
+};
+
+#define CYTTSP_TS_GPIO_IRQ 11
+#define CYTTSP_TS_SLEEP_GPIO 50
+#define CYTTSP_TS_RESOUT_N_GPIO 52
+
+/*virtual key support */
+static ssize_t tma340_vkeys_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return snprintf(buf, 200,
+ __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":73:1120:97:97"
+ ":" __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":230:1120:97:97"
+ ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":389:1120:97:97"
+ ":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":544:1120:97:97"
+ "\n");
+}
+
+static struct kobj_attribute tma340_vkeys_attr = {
+ .attr = {
+ .mode = S_IRUGO,
+ },
+ .show = &tma340_vkeys_show,
+};
+
+static struct attribute *tma340_properties_attrs[] = {
+ &tma340_vkeys_attr.attr,
+ NULL
+};
+
+static struct attribute_group tma340_properties_attr_group = {
+ .attrs = tma340_properties_attrs,
+};
+
+
+static int cyttsp_platform_init(struct i2c_client *client)
+{
+ int rc = 0;
+ static struct kobject *tma340_properties_kobj;
+
+ tma340_vkeys_attr.attr.name = "virtualkeys.cyttsp-i2c";
+ tma340_properties_kobj = kobject_create_and_add("board_properties",
+ NULL);
+ if (tma340_properties_kobj)
+ rc = sysfs_create_group(tma340_properties_kobj,
+ &tma340_properties_attr_group);
+ if (!tma340_properties_kobj || rc)
+ pr_err("%s: failed to create board_properties\n",
+ __func__);
+
+ return 0;
+}
+
+static struct cyttsp_regulator regulator_data[] = {
+ {
+ .name = "vdd",
+ .min_uV = CY_TMA300_VTG_MIN_UV,
+ .max_uV = CY_TMA300_VTG_MAX_UV,
+ .hpm_load_uA = CY_TMA300_CURR_24HZ_UA,
+ .lpm_load_uA = CY_TMA300_SLEEP_CURR_UA,
+ },
+ /* TODO: Remove after runtime PM is enabled in I2C driver */
+ {
+ .name = "vcc_i2c",
+ .min_uV = CY_I2C_VTG_MIN_UV,
+ .max_uV = CY_I2C_VTG_MAX_UV,
+ .hpm_load_uA = CY_I2C_CURR_UA,
+ .lpm_load_uA = CY_I2C_SLEEP_CURR_UA,
+ },
+};
+
+static struct cyttsp_platform_data cyttsp_pdata = {
+ .panel_maxx = 634,
+ .panel_maxy = 1166,
+ .disp_maxx = 616,
+ .disp_maxy = 1023,
+ .disp_minx = 0,
+ .disp_miny = 16,
+ .flags = 0x01,
+ .gen = CY_GEN3, /* or */
+ .use_st = CY_USE_ST,
+ .use_mt = CY_USE_MT,
+ .use_hndshk = CY_SEND_HNDSHK,
+ .use_trk_id = CY_USE_TRACKING_ID,
+ .use_sleep = CY_USE_DEEP_SLEEP_SEL | CY_USE_LOW_POWER_SEL,
+ .use_gestures = CY_USE_GESTURES,
+ .fw_fname = "cyttsp_8960_cdp.hex",
+ /* activate up to 4 groups
+ * and set active distance
+ */
+ .gest_set = CY_GEST_GRP1 | CY_GEST_GRP2 |
+ CY_GEST_GRP3 | CY_GEST_GRP4 |
+ CY_ACT_DIST,
+ /* change act_intrvl to customize the Active power state
+ * scanning/processing refresh interval for Operating mode
+ */
+ .act_intrvl = CY_ACT_INTRVL_DFLT,
+ /* change tch_tmout to customize the touch timeout for the
+ * Active power state for Operating mode
+ */
+ .tch_tmout = CY_TCH_TMOUT_DFLT,
+ /* change lp_intrvl to customize the Low Power power state
+ * scanning/processing refresh interval for Operating mode
+ */
+ .lp_intrvl = CY_LP_INTRVL_DFLT,
+ .sleep_gpio = CYTTSP_TS_SLEEP_GPIO,
+ .resout_gpio = CYTTSP_TS_RESOUT_N_GPIO,
+ .irq_gpio = CYTTSP_TS_GPIO_IRQ,
+ .regulator_info = regulator_data,
+ .num_regulators = ARRAY_SIZE(regulator_data),
+ .init = cyttsp_platform_init,
+ .correct_fw_ver = 9,
+};
+
+static struct i2c_board_info cyttsp_info[] __initdata = {
+ {
+ I2C_BOARD_INFO(CY_I2C_NAME, 0x24),
+ .platform_data = &cyttsp_pdata,
+#ifndef CY_USE_TIMER
+ .irq = MSM_GPIO_TO_INT(CYTTSP_TS_GPIO_IRQ),
+#endif /* CY_USE_TIMER */
+ },
+};
+
+/* configuration data */
+static const u8 mxt_config_data[] = {
+ /* T6 Object */
+ 0, 0, 0, 0, 0, 0,
+ /* T38 Object */
+ 11, 2, 0, 11, 11, 11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ /* T7 Object */
+ 100, 16, 50,
+ /* T8 Object */
+ 8, 0, 0, 0, 0, 0, 8, 14, 50, 215,
+ /* T9 Object */
+ 131, 0, 0, 26, 42, 0, 32, 63, 3, 5,
+ 0, 2, 1, 113, 10, 10, 8, 10, 255, 2,
+ 85, 5, 0, 0, 20, 20, 75, 25, 202, 29,
+ 10, 10, 45, 46,
+ /* T15 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+ /* T22 Object */
+ 5, 0, 0, 0, 0, 0, 0, 0, 30, 0,
+ 0, 0, 5, 8, 10, 13, 0,
+ /* T24 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* T25 Object */
+ 3, 0, 188, 52, 52, 33, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ /* T27 Object */
+ 0, 0, 0, 0, 0, 0, 0,
+ /* T28 Object */
+ 0, 0, 0, 8, 12, 60,
+ /* T40 Object */
+ 0, 0, 0, 0, 0,
+ /* T41 Object */
+ 0, 0, 0, 0, 0, 0,
+ /* T43 Object */
+ 0, 0, 0, 0, 0, 0,
+};
+
+#define MXT_TS_GPIO_IRQ 11
+#define MXT_TS_LDO_EN_GPIO 50
+#define MXT_TS_RESET_GPIO 52
+
+static void mxt_init_hw_liquid(void)
+{
+ int rc;
+
+ rc = gpio_request(MXT_TS_GPIO_IRQ, "mxt_ts_irq_gpio");
+ if (rc) {
+ pr_err("%s: unable to request mxt_ts_irq gpio [%d]\n",
+ __func__, MXT_TS_GPIO_IRQ);
+ return;
+ }
+
+ rc = gpio_direction_input(MXT_TS_GPIO_IRQ);
+ if (rc) {
+ pr_err("%s: unable to set_direction for mxt_ts_irq gpio [%d]\n",
+ __func__, MXT_TS_GPIO_IRQ);
+ goto err_irq_gpio_req;
+ }
+
+ rc = gpio_request(MXT_TS_LDO_EN_GPIO, "mxt_ldo_en_gpio");
+ if (rc) {
+ pr_err("%s: unable to request mxt_ldo_en gpio [%d]\n",
+ __func__, MXT_TS_LDO_EN_GPIO);
+ goto err_irq_gpio_req;
+ }
+
+ rc = gpio_direction_output(MXT_TS_LDO_EN_GPIO, 1);
+ if (rc) {
+ pr_err("%s: unable to set_direction for mxt_ldo_en gpio [%d]\n",
+ __func__, MXT_TS_LDO_EN_GPIO);
+ goto err_ldo_gpio_req;
+ }
+
+ rc = gpio_request(MXT_TS_RESET_GPIO, "mxt_reset_gpio");
+ if (rc) {
+ pr_err("%s: unable to request mxt_reset gpio [%d]\n",
+ __func__, MXT_TS_RESET_GPIO);
+ goto err_ldo_gpio_set_dir;
+ }
+
+ rc = gpio_direction_output(MXT_TS_RESET_GPIO, 1);
+ if (rc) {
+ pr_err("%s: unable to set_direction for mxt_reset gpio [%d]\n",
+ __func__, MXT_TS_RESET_GPIO);
+ goto err_reset_gpio_req;
+ }
+
+ return;
+
+err_reset_gpio_req:
+ gpio_free(MXT_TS_RESET_GPIO);
+err_ldo_gpio_set_dir:
+ gpio_set_value(MXT_TS_LDO_EN_GPIO, 0);
+err_ldo_gpio_req:
+ gpio_free(MXT_TS_LDO_EN_GPIO);
+err_irq_gpio_req:
+ gpio_free(MXT_TS_GPIO_IRQ);
+}
+
+static struct mxt_platform_data mxt_platform_data = {
+ .config = mxt_config_data,
+ .config_length = ARRAY_SIZE(mxt_config_data),
+ .x_size = 1365,
+ .y_size = 767,
+ .irqflags = IRQF_TRIGGER_FALLING,
+ .i2c_pull_up = true,
+};
+
+static struct i2c_board_info mxt_device_info[] __initdata = {
+ {
+ I2C_BOARD_INFO("atmel_mxt_ts", 0x5b),
+ .platform_data = &mxt_platform_data,
+ .irq = MSM_GPIO_TO_INT(MXT_TS_GPIO_IRQ),
+ },
+};
+
+static struct i2c_board_info sii_device_info[] __initdata = {
+ {
+ I2C_BOARD_INFO("Sil-9244", 0x39),
+ .flags = I2C_CLIENT_WAKE,
+ .irq = MSM_GPIO_TO_INT(15),
+ },
+};
+
+static void gsbi_qup_i2c_gpio_config(int adap_id, int config_type)
+{
+}
+
+static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi4_pdata = {
+ .clk_freq = 100000,
+ .src_clk_rate = 24000000,
+ .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
+};
+
+static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi3_pdata = {
+ .clk_freq = 100000,
+ .src_clk_rate = 24000000,
+ .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
+};
+
+static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi10_pdata = {
+ .clk_freq = 100000,
+ .src_clk_rate = 24000000,
+ .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
+};
+
+static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi12_pdata = {
+ .clk_freq = 100000,
+ .src_clk_rate = 24000000,
+ .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
+};
+
+static struct msm_rpm_platform_data msm_rpm_data = {
+ .reg_base_addrs = {
+ [MSM_RPM_PAGE_STATUS] = MSM_RPM_BASE,
+ [MSM_RPM_PAGE_CTRL] = MSM_RPM_BASE + 0x400,
+ [MSM_RPM_PAGE_REQ] = MSM_RPM_BASE + 0x600,
+ [MSM_RPM_PAGE_ACK] = MSM_RPM_BASE + 0xa00,
+ },
+
+ .irq_ack = RPM_APCC_CPU0_GP_HIGH_IRQ,
+ .irq_err = RPM_APCC_CPU0_GP_LOW_IRQ,
+ .irq_vmpm = RPM_APCC_CPU0_GP_MEDIUM_IRQ,
+ .msm_apps_ipc_rpm_reg = MSM_APCS_GCC_BASE + 0x008,
+ .msm_apps_ipc_rpm_val = 4,
+};
+
+static struct ks8851_pdata spi_eth_pdata = {
+ .irq_gpio = KS8851_IRQ_GPIO,
+ .rst_gpio = KS8851_RST_GPIO,
+};
+
+static struct spi_board_info spi_board_info[] __initdata = {
+ {
+ .modalias = "ks8851",
+ .irq = MSM_GPIO_TO_INT(KS8851_IRQ_GPIO),
+ .max_speed_hz = 19200000,
+ .bus_num = 0,
+ .chip_select = 0,
+ .mode = SPI_MODE_0,
+ .platform_data = &spi_eth_pdata
+ },
+ {
+ .modalias = "dsi_novatek_3d_panel_spi",
+ .max_speed_hz = 10800000,
+ .bus_num = 0,
+ .chip_select = 1,
+ .mode = SPI_MODE_0,
+ },
+};
+
+static struct platform_device msm_device_saw_core0 = {
+ .name = "saw-regulator",
+ .id = 0,
+ .dev = {
+ .platform_data = &msm_saw_regulator_pdata_s5,
+ },
+};
+
+static struct platform_device msm_device_saw_core1 = {
+ .name = "saw-regulator",
+ .id = 1,
+ .dev = {
+ .platform_data = &msm_saw_regulator_pdata_s6,
+ },
+};
+
+static struct tsens_platform_data msm_tsens_pdata = {
+ .slope = 910,
+ .tsens_factor = 1000,
+ .hw_type = MSM_8960,
+ .tsens_num_sensor = 5,
+};
+
+static struct platform_device msm_tsens_device = {
+ .name = "tsens8960-tm",
+ .id = -1,
+ .dev = {
+ .platform_data = &msm_tsens_pdata,
+ },
+};
+
+#ifdef CONFIG_MSM_FAKE_BATTERY
+static struct platform_device fish_battery_device = {
+ .name = "fish_battery",
+};
+#endif
+
+static struct platform_device msm8960_device_ext_5v_vreg __devinitdata = {
+ .name = GPIO_REGULATOR_DEV_NAME,
+ .id = PM8921_MPP_PM_TO_SYS(7),
+ .dev = {
+ .platform_data = &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_5V],
+ },
+};
+
+static struct platform_device msm8960_device_ext_l2_vreg __devinitdata = {
+ .name = GPIO_REGULATOR_DEV_NAME,
+ .id = 91,
+ .dev = {
+ .platform_data = &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_L2],
+ },
+};
+
+static struct platform_device msm8960_device_ext_3p3v_vreg __devinitdata = {
+ .name = GPIO_REGULATOR_DEV_NAME,
+ .id = PM8921_GPIO_PM_TO_SYS(17),
+ .dev = {
+ .platform_data =
+ &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_3P3V],
+ },
+};
+
+static struct platform_device msm8960_device_rpm_regulator __devinitdata = {
+ .name = "rpm-regulator",
+ .id = -1,
+ .dev = {
+ .platform_data = &msm_rpm_regulator_pdata,
+ },
+};
+
+static struct msm_rpm_log_platform_data msm_rpm_log_pdata = {
+ .phys_addr_base = 0x0010C000,
+ .reg_offsets = {
+ [MSM_RPM_LOG_PAGE_INDICES] = 0x00000080,
+ [MSM_RPM_LOG_PAGE_BUFFER] = 0x000000A0,
+ },
+ .phys_size = SZ_8K,
+ .log_len = 4096, /* log's buffer length in bytes */
+ .log_len_mask = (4096 >> 2) - 1, /* length mask in units of u32 */
+};
+
+static struct platform_device msm_rpm_log_device = {
+ .name = "msm_rpm_log",
+ .id = -1,
+ .dev = {
+ .platform_data = &msm_rpm_log_pdata,
+ },
+};
+
+static struct platform_device *common_devices[] __initdata = {
+ &msm8960_device_dmov,
+ &msm_device_smd,
+ &msm8960_device_uart_gsbi5,
+ &msm_device_uart_dm6,
+ &msm_device_saw_core0,
+ &msm_device_saw_core1,
+ &msm8960_device_ext_5v_vreg,
+ &msm8960_device_ext_l2_vreg,
+ &msm8960_device_ssbi_pm8921,
+ &msm8960_device_qup_spi_gsbi1,
+ &msm8960_device_qup_i2c_gsbi3,
+ &msm8960_device_qup_i2c_gsbi4,
+ &msm8960_device_qup_i2c_gsbi10,
+#ifndef CONFIG_MSM_DSPS
+ &msm8960_device_qup_i2c_gsbi12,
+#endif
+ &msm_slim_ctrl,
+ &msm_device_wcnss_wlan,
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+ defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+ &qcrypto_device,
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+ defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+ &qcedev_device,
+#endif
+#ifdef CONFIG_MSM_ROTATOR
+ &msm_rotator_device,
+#endif
+ &msm_device_sps,
+#ifdef CONFIG_MSM_FAKE_BATTERY
+ &fish_battery_device,
+#endif
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+ &android_pmem_device,
+ &android_pmem_adsp_device,
+#endif
+ &android_pmem_audio_device,
+#endif
+ &msm_device_vidc,
+ &msm_device_bam_dmux,
+ &msm_fm_platform_init,
+
+#ifdef CONFIG_HW_RANDOM_MSM
+ &msm_device_rng,
+#endif
+ &msm_rpm_device,
+#ifdef CONFIG_ION_MSM
+ &ion_dev,
+#endif
+ &msm_rpm_log_device,
+ &msm_rpm_stat_device,
+ &msm_device_tz_log,
+
+#ifdef CONFIG_MSM_QDSS
+ &msm_etb_device,
+ &msm_tpiu_device,
+ &msm_funnel_device,
+ &msm_debug_device,
+ &msm_ptm_device,
+#endif
+ &msm_device_dspcrashd_8960,
+ &msm8960_device_watchdog,
+};
+
+static struct platform_device *sim_devices[] __initdata = {
+ &msm8960_device_otg,
+ &msm8960_device_gadget_peripheral,
+ &msm_device_hsusb_host,
+ &msm_device_hsic_host,
+ &android_usb_device,
+ &msm_device_vidc,
+ &msm_bus_apps_fabric,
+ &msm_bus_sys_fabric,
+ &msm_bus_mm_fabric,
+ &msm_bus_sys_fpb,
+ &msm_bus_cpss_fpb,
+ &msm_pcm,
+ &msm_pcm_routing,
+ &msm_cpudai0,
+ &msm_cpudai1,
+ &msm_cpudai_hdmi_rx,
+ &msm_cpudai_bt_rx,
+ &msm_cpudai_bt_tx,
+ &msm_cpudai_fm_rx,
+ &msm_cpudai_fm_tx,
+ &msm_cpudai_auxpcm_rx,
+ &msm_cpudai_auxpcm_tx,
+ &msm_cpu_fe,
+ &msm_stub_codec,
+ &msm_voice,
+ &msm_voip,
+ &msm_lpa_pcm,
+ &msm_compr_dsp,
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+ defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+ &qcrypto_device,
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+ defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+ &qcedev_device,
+#endif
+};
+
+static struct platform_device *rumi3_devices[] __initdata = {
+ &msm_kgsl_3d0,
+ &msm_kgsl_2d0,
+ &msm_kgsl_2d1,
+#ifdef CONFIG_MSM_GEMINI
+ &msm8960_gemini_device,
+#endif
+};
+
+static struct platform_device *cdp_devices[] __initdata = {
+ &msm_8960_q6_lpass,
+ &msm_8960_q6_mss_fw,
+ &msm_8960_q6_mss_sw,
+ &msm8960_device_otg,
+ &msm8960_device_gadget_peripheral,
+ &msm_device_hsusb_host,
+ &android_usb_device,
+ &msm_pcm,
+ &msm_pcm_routing,
+ &msm_cpudai0,
+ &msm_cpudai1,
+ &msm_cpudai_hdmi_rx,
+ &msm_cpudai_bt_rx,
+ &msm_cpudai_bt_tx,
+ &msm_cpudai_fm_rx,
+ &msm_cpudai_fm_tx,
+ &msm_cpudai_auxpcm_rx,
+ &msm_cpudai_auxpcm_tx,
+ &msm_cpu_fe,
+ &msm_stub_codec,
+ &msm_kgsl_3d0,
+#ifdef CONFIG_MSM_KGSL_2D
+ &msm_kgsl_2d0,
+ &msm_kgsl_2d1,
+#endif
+#ifdef CONFIG_MSM_GEMINI
+ &msm8960_gemini_device,
+#endif
+ &msm_voice,
+ &msm_voip,
+ &msm_lpa_pcm,
+ &msm_cpudai_afe_01_rx,
+ &msm_cpudai_afe_01_tx,
+ &msm_cpudai_afe_02_rx,
+ &msm_cpudai_afe_02_tx,
+ &msm_pcm_afe,
+ &msm_compr_dsp,
+ &msm_pcm_hostless,
+ &msm_bus_apps_fabric,
+ &msm_bus_sys_fabric,
+ &msm_bus_mm_fabric,
+ &msm_bus_sys_fpb,
+ &msm_bus_cpss_fpb,
+ &msm_tsens_device,
+};
+
+static void __init msm8960_i2c_init(void)
+{
+ msm8960_device_qup_i2c_gsbi4.dev.platform_data =
+ &msm8960_i2c_qup_gsbi4_pdata;
+
+ msm8960_device_qup_i2c_gsbi3.dev.platform_data =
+ &msm8960_i2c_qup_gsbi3_pdata;
+
+ msm8960_device_qup_i2c_gsbi10.dev.platform_data =
+ &msm8960_i2c_qup_gsbi10_pdata;
+
+ msm8960_device_qup_i2c_gsbi12.dev.platform_data =
+ &msm8960_i2c_qup_gsbi12_pdata;
+}
+
+static void __init msm8960_gfx_init(void)
+{
+ uint32_t soc_platform_version = socinfo_get_version();
+ if (SOCINFO_VERSION_MAJOR(soc_platform_version) == 1) {
+ struct kgsl_device_platform_data *kgsl_3d0_pdata =
+ msm_kgsl_3d0.dev.platform_data;
+ kgsl_3d0_pdata->pwrlevel[0].gpu_freq = 320000000;
+ kgsl_3d0_pdata->pwrlevel[1].gpu_freq = 266667000;
+ }
+}
+
+static struct msm_cpuidle_state msm_cstates[] __initdata = {
+ {0, 0, "C0", "WFI",
+ MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
+
+ {0, 1, "C1", "STANDALONE_POWER_COLLAPSE",
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
+
+ {0, 2, "C2", "POWER_COLLAPSE",
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE},
+
+ {1, 0, "C0", "WFI",
+ MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
+
+ {1, 1, "C1", "STANDALONE_POWER_COLLAPSE",
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
+};
+
+static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR * 2] = {
+ [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
+ .idle_supported = 1,
+ .suspend_supported = 1,
+ .idle_enabled = 0,
+ .suspend_enabled = 0,
+ },
+
+ [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
+ .idle_supported = 1,
+ .suspend_supported = 1,
+ .idle_enabled = 0,
+ .suspend_enabled = 0,
+ },
+
+ [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+ .idle_supported = 1,
+ .suspend_supported = 1,
+ .idle_enabled = 1,
+ .suspend_enabled = 1,
+ },
+
+ [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
+ .idle_supported = 0,
+ .suspend_supported = 1,
+ .idle_enabled = 0,
+ .suspend_enabled = 0,
+ },
+
+ [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
+ .idle_supported = 1,
+ .suspend_supported = 1,
+ .idle_enabled = 0,
+ .suspend_enabled = 0,
+ },
+
+ [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+ .idle_supported = 1,
+ .suspend_supported = 0,
+ .idle_enabled = 1,
+ .suspend_enabled = 0,
+ },
+};
+
+static struct msm_rpmrs_level msm_rpmrs_levels[] __initdata = {
+ {
+ MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
+ MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
+ true,
+ 100, 8000, 100000, 1,
+ },
+
+ {
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
+ MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
+ true,
+ 2000, 6000, 60100000, 3000,
+ },
+
+ {
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+ MSM_RPMRS_LIMITS(ON, GDHS, MAX, ACTIVE),
+ false,
+ 4200, 5000, 60350000, 3500,
+ },
+
+ {
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+ MSM_RPMRS_LIMITS(ON, HSFS_OPEN, MAX, ACTIVE),
+ false,
+ 6300, 4500, 65350000, 4800,
+ },
+ {
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+ MSM_RPMRS_LIMITS(ON, HSFS_OPEN, ACTIVE, RET_HIGH),
+ false,
+ 7000, 3500, 66600000, 5150,
+ },
+
+ {
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+ MSM_RPMRS_LIMITS(OFF, GDHS, MAX, ACTIVE),
+ false,
+ 11700, 2500, 67850000, 5500,
+ },
+
+ {
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+ MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, MAX, ACTIVE),
+ false,
+ 13800, 2000, 71850000, 6800,
+ },
+
+ {
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+ MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, ACTIVE, RET_HIGH),
+ false,
+ 29700, 500, 75850000, 8800,
+ },
+
+ {
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+ MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, RET_HIGH, RET_LOW),
+ false,
+ 29700, 0, 76350000, 9800,
+ },
+};
+
+#ifdef CONFIG_I2C
+#define I2C_SURF 1
+#define I2C_FFA (1 << 1)
+#define I2C_RUMI (1 << 2)
+#define I2C_SIM (1 << 3)
+#define I2C_FLUID (1 << 4)
+#define I2C_LIQUID (1 << 5)
+
+struct i2c_registry {
+ u8 machs;
+ int bus;
+ struct i2c_board_info *info;
+ int len;
+};
+
+#ifdef CONFIG_MSM_CAMERA
+static struct i2c_board_info msm_camera_boardinfo[] __initdata = {
+#ifdef CONFIG_IMX074
+ {
+ I2C_BOARD_INFO("imx074", 0x1A),
+ },
+#endif
+#ifdef CONFIG_OV2720
+ {
+ I2C_BOARD_INFO("ov2720", 0x6C),
+ },
+#endif
+#ifdef CONFIG_MSM_CAMERA_FLASH_SC628A
+ {
+ I2C_BOARD_INFO("sc628a", 0x6E),
+ },
+#endif
+};
+#endif
+
+/* Sensors DSPS platform data */
+#ifdef CONFIG_MSM_DSPS
+#define DSPS_PIL_GENERIC_NAME "dsps"
+#endif /* CONFIG_MSM_DSPS */
+
+static void __init msm8960_init_dsps(void)
+{
+#ifdef CONFIG_MSM_DSPS
+ struct msm_dsps_platform_data *pdata =
+ msm_dsps_device.dev.platform_data;
+ pdata->pil_name = DSPS_PIL_GENERIC_NAME;
+ pdata->gpios = NULL;
+ pdata->gpios_num = 0;
+
+ platform_device_register(&msm_dsps_device);
+#endif /* CONFIG_MSM_DSPS */
+}
+
+static void __init msm8960_init_hsic(void)
+{
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+ uint32_t version = socinfo_get_version();
+
+ if (SOCINFO_VERSION_MAJOR(version) == 1)
+ return;
+
+ if (PLATFORM_IS_CHARM25() || machine_is_msm8960_liquid())
+ platform_device_register(&msm_device_hsic_host);
+#endif
+}
+
+#ifdef CONFIG_ISL9519_CHARGER
+static struct isl_platform_data isl_data __initdata = {
+ .valid_n_gpio = 0, /* Not required when notify-by-pmic */
+ .chg_detection_config = NULL, /* Not required when notify-by-pmic */
+ .max_system_voltage = 4200,
+ .min_system_voltage = 3200,
+ .chgcurrent = 1000, /* 1900, */
+ .term_current = 400, /* Need fine tuning */
+ .input_current = 2048,
+};
+
+static struct i2c_board_info isl_charger_i2c_info[] __initdata = {
+ {
+ I2C_BOARD_INFO("isl9519q", 0x9),
+ .irq = 0, /* Not required when notify-by-pmic */
+ .platform_data = &isl_data,
+ },
+};
+#endif /* CONFIG_ISL9519_CHARGER */
+
+static struct i2c_registry msm8960_i2c_devices[] __initdata = {
+#ifdef CONFIG_MSM_CAMERA
+ {
+ I2C_SURF | I2C_FFA | I2C_FLUID | I2C_LIQUID | I2C_RUMI,
+ MSM_8960_GSBI4_QUP_I2C_BUS_ID,
+ msm_camera_boardinfo,
+ ARRAY_SIZE(msm_camera_boardinfo),
+ },
+#endif
+#ifdef CONFIG_ISL9519_CHARGER
+ {
+ I2C_LIQUID,
+ MSM_8960_GSBI10_QUP_I2C_BUS_ID,
+ isl_charger_i2c_info,
+ ARRAY_SIZE(isl_charger_i2c_info),
+ },
+#endif /* CONFIG_ISL9519_CHARGER */
+ {
+ I2C_SURF | I2C_FFA | I2C_FLUID,
+ MSM_8960_GSBI3_QUP_I2C_BUS_ID,
+ cyttsp_info,
+ ARRAY_SIZE(cyttsp_info),
+ },
+ {
+ I2C_LIQUID,
+ MSM_8960_GSBI3_QUP_I2C_BUS_ID,
+ mxt_device_info,
+ ARRAY_SIZE(mxt_device_info),
+ },
+ {
+ I2C_LIQUID,
+ MSM_8960_GSBI10_QUP_I2C_BUS_ID,
+ sii_device_info,
+ ARRAY_SIZE(sii_device_info),
+ },
+ {
+ I2C_LIQUID,
+ MSM_8960_GSBI10_QUP_I2C_BUS_ID,
+ msm_isa1200_board_info,
+ ARRAY_SIZE(msm_isa1200_board_info),
+ },
+};
+#endif /* CONFIG_I2C */
+
+static void __init register_i2c_devices(void)
+{
+#ifdef CONFIG_I2C
+ u8 mach_mask = 0;
+ int i;
+
+ /* Build the matching 'supported_machs' bitmask */
+ if (machine_is_msm8960_cdp())
+ mach_mask = I2C_SURF;
+ else if (machine_is_msm8960_rumi3())
+ mach_mask = I2C_RUMI;
+ else if (machine_is_msm8960_sim())
+ mach_mask = I2C_SIM;
+ else if (machine_is_msm8960_fluid())
+ mach_mask = I2C_FLUID;
+ else if (machine_is_msm8960_liquid())
+ mach_mask = I2C_LIQUID;
+ else if (machine_is_msm8960_mtp())
+ mach_mask = I2C_FFA;
+ else
+ pr_err("unmatched machine ID in register_i2c_devices\n");
+
+ /* Run the array and install devices as appropriate */
+ for (i = 0; i < ARRAY_SIZE(msm8960_i2c_devices); ++i) {
+ if (msm8960_i2c_devices[i].machs & mach_mask)
+ i2c_register_board_info(msm8960_i2c_devices[i].bus,
+ msm8960_i2c_devices[i].info,
+ msm8960_i2c_devices[i].len);
+ }
+#endif
+}
+
+static void __init msm8960_sim_init(void)
+{
+ struct msm_watchdog_pdata *wdog_pdata = (struct msm_watchdog_pdata *)
+ &msm8960_device_watchdog.dev.platform_data;
+
+ wdog_pdata->bark_time = 15000;
+ BUG_ON(msm_rpm_init(&msm_rpm_data));
+ BUG_ON(msm_rpmrs_levels_init(msm_rpmrs_levels,
+ ARRAY_SIZE(msm_rpmrs_levels)));
+ regulator_suppress_info_printing();
+ platform_device_register(&msm8960_device_rpm_regulator);
+ msm_clock_init(&msm8960_clock_init_data);
+ msm8960_init_pmic();
+
+ msm8960_device_otg.dev.platform_data = &msm_otg_pdata;
+ msm8960_init_gpiomux();
+ msm8960_i2c_init();
+ msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
+ msm_spm_l2_init(msm_spm_l2_data);
+ msm8960_init_buses();
+ platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
+ msm8960_pm8921_gpio_mpp_init();
+ platform_add_devices(sim_devices, ARRAY_SIZE(sim_devices));
+ acpuclk_init(&acpuclk_8960_soc_data);
+
+ msm8960_device_qup_spi_gsbi1.dev.platform_data =
+ &msm8960_qup_spi_gsbi1_pdata;
+ spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+
+ msm8960_init_mmc();
+ msm8960_init_fb();
+ slim_register_board_info(msm_slim_devices,
+ ARRAY_SIZE(msm_slim_devices));
+ msm_pm_set_platform_data(msm_pm_data, ARRAY_SIZE(msm_pm_data));
+ msm_pm_set_rpm_wakeup_irq(RPM_APCC_CPU0_WAKE_UP_IRQ);
+ msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
+ msm_pm_data);
+ BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_TZ, NULL));
+}
+
+static void __init msm8960_rumi3_init(void)
+{
+ BUG_ON(msm_rpm_init(&msm_rpm_data));
+ BUG_ON(msm_rpmrs_levels_init(msm_rpmrs_levels,
+ ARRAY_SIZE(msm_rpmrs_levels)));
+ regulator_suppress_info_printing();
+ platform_device_register(&msm8960_device_rpm_regulator);
+ msm_clock_init(&msm8960_dummy_clock_init_data);
+ msm8960_init_gpiomux();
+ msm8960_init_pmic();
+ msm8960_device_qup_spi_gsbi1.dev.platform_data =
+ &msm8960_qup_spi_gsbi1_pdata;
+ spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+ msm8960_i2c_init();
+ msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
+ msm_spm_l2_init(msm_spm_l2_data);
+ platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
+ msm8960_pm8921_gpio_mpp_init();
+ platform_add_devices(rumi3_devices, ARRAY_SIZE(rumi3_devices));
+ msm8960_init_mmc();
+ register_i2c_devices();
+ msm8960_init_fb();
+ slim_register_board_info(msm_slim_devices,
+ ARRAY_SIZE(msm_slim_devices));
+ msm_pm_set_platform_data(msm_pm_data, ARRAY_SIZE(msm_pm_data));
+ msm_pm_set_rpm_wakeup_irq(RPM_APCC_CPU0_WAKE_UP_IRQ);
+ msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
+ msm_pm_data);
+ BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_TZ, NULL));
+}
+
+static void __init msm8960_cdp_init(void)
+{
+ if (meminfo_init(SYS_MEMORY, SZ_256M) < 0)
+ pr_err("meminfo_init() failed!\n");
+
+ BUG_ON(msm_rpm_init(&msm_rpm_data));
+ BUG_ON(msm_rpmrs_levels_init(msm_rpmrs_levels,
+ ARRAY_SIZE(msm_rpmrs_levels)));
+
+ regulator_suppress_info_printing();
+ if (msm_xo_init())
+ pr_err("Failed to initialize XO votes\n");
+ platform_device_register(&msm8960_device_rpm_regulator);
+ msm_clock_init(&msm8960_clock_init_data);
+ if (machine_is_msm8960_liquid())
+ msm_otg_pdata.mhl_enable = true;
+ msm8960_device_otg.dev.platform_data = &msm_otg_pdata;
+ if (machine_is_msm8960_mtp() || machine_is_msm8960_fluid() ||
+ machine_is_msm8960_cdp()) {
+ msm_otg_pdata.phy_init_seq = wr_phy_init_seq;
+ } else if (machine_is_msm8960_liquid()) {
+ msm_otg_pdata.phy_init_seq =
+ liquid_v1_phy_init_seq;
+ }
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+ if (machine_is_msm8960_liquid()) {
+ if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2)
+ msm_hsic_pdata.hub_reset = HSIC_HUB_RESET_GPIO;
+ }
+#endif
+ msm_device_hsic_host.dev.platform_data = &msm_hsic_pdata;
+ msm8960_init_gpiomux();
+ msm8960_device_qup_spi_gsbi1.dev.platform_data =
+ &msm8960_qup_spi_gsbi1_pdata;
+ spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+
+ msm8960_init_pmic();
+ msm8960_i2c_init();
+ msm8960_gfx_init();
+ msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
+ msm_spm_l2_init(msm_spm_l2_data);
+ msm8960_init_buses();
+ platform_add_devices(msm_footswitch_devices,
+ msm_num_footswitch_devices);
+ if (machine_is_msm8960_liquid())
+ platform_device_register(&msm8960_device_ext_3p3v_vreg);
+ platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
+ msm8960_pm8921_gpio_mpp_init();
+ platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
+ msm8960_init_hsic();
+ msm8960_init_cam();
+ msm8960_init_mmc();
+ acpuclk_init(&acpuclk_8960_soc_data);
+ if (machine_is_msm8960_liquid())
+ mxt_init_hw_liquid();
+ register_i2c_devices();
+ msm8960_init_fb();
+ slim_register_board_info(msm_slim_devices,
+ ARRAY_SIZE(msm_slim_devices));
+ msm8960_init_dsps();
+ msm_pm_set_platform_data(msm_pm_data, ARRAY_SIZE(msm_pm_data));
+ msm_pm_set_rpm_wakeup_irq(RPM_APCC_CPU0_WAKE_UP_IRQ);
+ msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
+ msm_pm_data);
+ change_memory_power = &msm8960_change_memory_power;
+ BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_TZ, NULL));
+
+ if (PLATFORM_IS_CHARM25())
+ platform_add_devices(mdm_devices, ARRAY_SIZE(mdm_devices));
+}
+
+MACHINE_START(MSM8960_SIM, "QCT MSM8960 SIMULATOR")
+ .map_io = msm8960_map_io,
+ .reserve = msm8960_reserve,
+ .init_irq = msm8960_init_irq,
+ .timer = &msm_timer,
+ .init_machine = msm8960_sim_init,
+ .init_early = msm8960_allocate_memory_regions,
+ .init_very_early = msm8960_early_memory,
+MACHINE_END
+
+MACHINE_START(MSM8960_RUMI3, "QCT MSM8960 RUMI3")
+ .map_io = msm8960_map_io,
+ .reserve = msm8960_reserve,
+ .init_irq = msm8960_init_irq,
+ .timer = &msm_timer,
+ .init_machine = msm8960_rumi3_init,
+ .init_early = msm8960_allocate_memory_regions,
+ .init_very_early = msm8960_early_memory,
+MACHINE_END
+
+MACHINE_START(MSM8960_CDP, "QCT MSM8960 CDP")
+ .map_io = msm8960_map_io,
+ .reserve = msm8960_reserve,
+ .init_irq = msm8960_init_irq,
+ .timer = &msm_timer,
+ .init_machine = msm8960_cdp_init,
+ .init_early = msm8960_allocate_memory_regions,
+ .init_very_early = msm8960_early_memory,
+MACHINE_END
+
+MACHINE_START(MSM8960_MTP, "QCT MSM8960 MTP")
+ .map_io = msm8960_map_io,
+ .reserve = msm8960_reserve,
+ .init_irq = msm8960_init_irq,
+ .timer = &msm_timer,
+ .init_machine = msm8960_cdp_init,
+ .init_early = msm8960_allocate_memory_regions,
+ .init_very_early = msm8960_early_memory,
+MACHINE_END
+
+MACHINE_START(MSM8960_FLUID, "QCT MSM8960 FLUID")
+ .map_io = msm8960_map_io,
+ .reserve = msm8960_reserve,
+ .init_irq = msm8960_init_irq,
+ .timer = &msm_timer,
+ .init_machine = msm8960_cdp_init,
+ .init_early = msm8960_allocate_memory_regions,
+ .init_very_early = msm8960_early_memory,
+MACHINE_END
+
+MACHINE_START(MSM8960_LIQUID, "QCT MSM8960 LIQUID")
+ .map_io = msm8960_map_io,
+ .reserve = msm8960_reserve,
+ .init_irq = msm8960_init_irq,
+ .timer = &msm_timer,
+ .init_machine = msm8960_cdp_init,
+ .init_early = msm8960_allocate_memory_regions,
+ .init_very_early = msm8960_early_memory,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-8960.h b/arch/arm/mach-msm/board-8960.h
new file mode 100644
index 0000000..56fa3ca
--- /dev/null
+++ b/arch/arm/mach-msm/board-8960.h
@@ -0,0 +1,86 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_BOARD_MSM8960_H
+#define __ARCH_ARM_MACH_MSM_BOARD_MSM8960_H
+
+#include <linux/regulator/gpio-regulator.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/i2c/sx150x.h>
+#include <mach/irqs.h>
+#include <mach/rpm-regulator.h>
+
+/* Macros assume PMIC GPIOs and MPPs start at 1 */
+#define PM8921_GPIO_BASE NR_GPIO_IRQS
+#define PM8921_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8921_GPIO_BASE)
+#define PM8921_MPP_BASE (PM8921_GPIO_BASE + PM8921_NR_GPIOS)
+#define PM8921_MPP_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8921_MPP_BASE)
+#define PM8921_IRQ_BASE (NR_MSM_IRQS + NR_GPIO_IRQS)
+
+extern struct pm8921_regulator_platform_data
+ msm_pm8921_regulator_pdata[] __devinitdata;
+
+extern int msm_pm8921_regulator_pdata_len __devinitdata;
+
+#define GPIO_VREG_ID_EXT_5V 0
+#define GPIO_VREG_ID_EXT_L2 1
+#define GPIO_VREG_ID_EXT_3P3V 2
+
+extern struct gpio_regulator_platform_data
+ msm_gpio_regulator_pdata[] __devinitdata;
+
+extern struct regulator_init_data msm_saw_regulator_pdata_s5;
+extern struct regulator_init_data msm_saw_regulator_pdata_s6;
+
+extern struct rpm_regulator_platform_data msm_rpm_regulator_pdata __devinitdata;
+
+#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
+enum {
+ GPIO_EXPANDER_IRQ_BASE = (PM8921_IRQ_BASE + PM8921_NR_IRQS),
+ GPIO_EXPANDER_GPIO_BASE = (PM8921_MPP_BASE + PM8921_NR_MPPS),
+ /* CAM Expander */
+ GPIO_CAM_EXPANDER_BASE = GPIO_EXPANDER_GPIO_BASE,
+ GPIO_CAM_GP_STROBE_READY = GPIO_CAM_EXPANDER_BASE,
+ GPIO_CAM_GP_AFBUSY,
+ GPIO_CAM_GP_STROBE_CE,
+ GPIO_CAM_GP_CAM1MP_XCLR,
+ GPIO_CAM_GP_CAMIF_RESET_N,
+ GPIO_CAM_GP_XMT_FLASH_INT,
+ GPIO_CAM_GP_LED_EN1,
+ GPIO_CAM_GP_LED_EN2,
+
+};
+#endif
+
+enum {
+ SX150X_CAM,
+};
+
+#endif
+
+extern struct sx150x_platform_data msm8960_sx150x_data[];
+void msm8960_init_cam(void);
+void msm8960_init_fb(void);
+void msm8960_init_pmic(void);
+void msm8960_init_mmc(void);
+int msm8960_init_gpiomux(void);
+void msm8960_allocate_fb_region(void);
+void msm8960_pm8921_gpio_mpp_init(void);
+
+#define PLATFORM_IS_CHARM25() \
+ (machine_is_msm8960_cdp() && \
+ (socinfo_get_platform_subtype() == 1) \
+ )
+
+#define MSM_8960_GSBI4_QUP_I2C_BUS_ID 4
+#define MSM_8960_GSBI3_QUP_I2C_BUS_ID 3
+#define MSM_8960_GSBI10_QUP_I2C_BUS_ID 10
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index d863b5d..5efafae 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -27,12 +27,14 @@
#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
#include <linux/leds.h>
#include <linux/leds-pm8xxx.h>
+#include <mach/msm_bus_board.h>
#include "timer.h"
#include "devices.h"
#include "board-9615.h"
#include "cpuidle.h"
#include "pm.h"
#include "acpuclock.h"
+#include <linux/power/ltc4088-charger.h>
static struct pm8xxx_adc_amux pm8018_adc_channels_data[] = {
{"vcoin", CHANNEL_VCOIN, CHAN_PATH_SCALING2, AMUX_RSV1,
@@ -88,7 +90,7 @@
static struct pm8xxx_pwrkey_platform_data pm8xxx_pwrkey_pdata = {
.pull_up = 1,
- .kpd_trigger_delay_us = 970,
+ .kpd_trigger_delay_us = 15625,
.wakeup = 1,
};
@@ -132,6 +134,14 @@
.num_configs = ARRAY_SIZE(pm8018_led_configs),
};
+#ifdef CONFIG_LTC4088_CHARGER
+static struct ltc4088_charger_platform_data ltc4088_chg_pdata = {
+ .gpio_mode_select_d0 = 7,
+ .gpio_mode_select_d1 = 6,
+ .gpio_mode_select_d2 = 4,
+};
+#endif
+
static struct pm8018_platform_data pm8018_platform_data __devinitdata = {
.irq_pdata = &pm8xxx_irq_pdata,
.gpio_pdata = &pm8xxx_gpio_pdata,
@@ -199,6 +209,14 @@
.pull = GPIOMUX_PULL_NONE,
};
+#ifdef CONFIG_LTC4088_CHARGER
+static struct gpiomux_setting ltc4088_chg_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+#endif
+
struct msm_gpiomux_config msm9615_ps_hold_config[] __initdata = {
{
.gpio = 83,
@@ -208,6 +226,30 @@
},
};
+#ifdef CONFIG_LTC4088_CHARGER
+static struct msm_gpiomux_config
+ msm9615_ltc4088_charger_config[] __initdata = {
+ {
+ .gpio = 4,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = <c4088_chg_cfg,
+ },
+ },
+ {
+ .gpio = 6,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = <c4088_chg_cfg,
+ },
+ },
+ {
+ .gpio = 7,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = <c4088_chg_cfg,
+ },
+ },
+};
+#endif
+
struct msm_gpiomux_config msm9615_gsbi_configs[] __initdata = {
{
.gpio = 8, /* GSBI3 QUP SPI_CLK */
@@ -599,9 +641,24 @@
msm_gpiomux_install(msm9615_ps_hold_config,
ARRAY_SIZE(msm9615_ps_hold_config));
+#ifdef CONFIG_LTC4088_CHARGER
+ msm_gpiomux_install(msm9615_ltc4088_charger_config,
+ ARRAY_SIZE(msm9615_ltc4088_charger_config));
+#endif
return 0;
}
+static void __init msm9615_init_buses(void)
+{
+#ifdef CONFIG_MSM_BUS_SCALING
+ msm_bus_rpm_set_mt_mask();
+ msm_bus_9615_sys_fabric_pdata.rpm_enabled = 1;
+ msm_bus_9615_sys_fabric.dev.platform_data =
+ &msm_bus_9615_sys_fabric_pdata;
+ msm_bus_def_fab.dev.platform_data = &msm_bus_9615_def_fab_pdata;
+#endif
+}
+
static struct msm_spi_platform_data msm9615_qup_spi_gsbi3_pdata = {
.max_clock_speed = 24000000,
};
@@ -611,11 +668,71 @@
.src_clk_rate = 24000000,
};
+#define USB_5V_EN 3
+#define PM_USB_5V_EN PM8018_GPIO_PM_TO_SYS(USB_5V_EN)
+
+static void msm_hsusb_vbus_power(bool on)
+{
+ int rc;
+ static bool vbus_is_on;
+ struct pm_gpio usb_vbus = {
+ .direction = PM_GPIO_DIR_OUT,
+ .pull = PM_GPIO_PULL_NO,
+ .output_buffer = PM_GPIO_OUT_BUF_CMOS,
+ .output_value = 0,
+ .vin_sel = 2,
+ .out_strength = PM_GPIO_STRENGTH_HIGH,
+ .function = PM_GPIO_FUNC_NORMAL,
+ .inv_int_pol = 0,
+ };
+
+ if (vbus_is_on == on)
+ return;
+
+ if (on) {
+ rc = pm8xxx_gpio_config(PM_USB_5V_EN, &usb_vbus);
+ if (rc) {
+ pr_err("failed to config usb_5v_en gpio\n");
+ return;
+ }
+
+ rc = gpio_request(PM_USB_5V_EN,
+ "usb_5v_en");
+ if (rc < 0) {
+ pr_err("failed to request usb_5v_en gpio\n");
+ return;
+ }
+
+ rc = gpio_direction_output(PM_USB_5V_EN, 1);
+ if (rc) {
+ pr_err("%s: unable to set_direction for gpio [%d]\n",
+ __func__, PM_USB_5V_EN);
+ goto free_usb_5v_en;
+ }
+
+ vbus_is_on = true;
+ return;
+ }
+ gpio_set_value(PM_USB_5V_EN, 0);
+free_usb_5v_en:
+ gpio_free(PM_USB_5V_EN);
+ vbus_is_on = false;
+}
+
+static int shelby_phy_init_seq[] = {
+ 0x44, 0x80,/* set VBUS valid threshold and
+ disconnect valid threshold */
+ 0x38, 0x81, /* update DC voltage level */
+ 0x14, 0x82,/* set preemphasis and rise/fall time */
+ 0x13, 0x83,/* set source impedance adjustment */
+ -1};
+
static struct msm_otg_platform_data msm_otg_pdata = {
- .mode = USB_PERIPHERAL,
- .otg_control = OTG_NO_CONTROL,
+ .mode = USB_OTG,
+ .otg_control = OTG_PHY_CONTROL,
.phy_type = SNPS_28NM_INTEGRATED_PHY,
- .pclk_src_name = "dfab_usb_hs_clk",
+ .pclk_src_name = "dfab_usb_hs_clk",
+ .vbus_power = msm_hsusb_vbus_power,
};
static int usb_diag_update_pid_and_serial_num(uint32_t pid, const char *snum)
@@ -645,11 +762,25 @@
return platform_device_register(&msm_wlan_ar6000_pm_device);
}
+#ifdef CONFIG_LTC4088_CHARGER
+static struct platform_device msm_device_charger = {
+ .name = LTC4088_CHARGER_DEV_NAME,
+ .id = -1,
+ .dev = {
+ .platform_data = <c4088_chg_pdata,
+ },
+};
+#endif
+
static struct platform_device *common_devices[] = {
&msm9615_device_dmov,
&msm_device_smd,
+#ifdef CONFIG_LTC4088_CHARGER
+ &msm_device_charger,
+#endif
&msm_device_otg,
&msm_device_gadget_peripheral,
+ &msm_device_hsusb_host,
&android_usb_device,
&msm9615_device_uart_gsbi4,
&msm9615_device_ext_2p95v_vreg,
@@ -675,6 +806,8 @@
&msm9615_qcedev_device,
#endif
&msm9615_device_watchdog,
+ &msm_bus_9615_sys_fabric,
+ &msm_bus_def_fab,
};
static void __init msm9615_i2c_init(void)
@@ -690,6 +823,8 @@
msm9615_i2c_init();
regulator_suppress_info_printing();
platform_device_register(&msm9615_device_rpm_regulator);
+ msm_clock_init(&msm9615_clock_init_data);
+ msm9615_init_buses();
msm9615_device_qup_spi_gsbi3.dev.platform_data =
&msm9615_qup_spi_gsbi3_pdata;
msm9615_device_ssbi_pmic1.dev.platform_data =
@@ -697,9 +832,9 @@
pm8018_platform_data.num_regulators = msm_pm8018_regulator_pdata_len;
msm_device_otg.dev.platform_data = &msm_otg_pdata;
+ msm_otg_pdata.phy_init_seq = shelby_phy_init_seq;
platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
- msm_clock_init(&msm9615_clock_init_data);
acpuclk_init(&acpuclk_9615_soc_data);
/* Ensure ar6000pm device is registered before MMC/SDC */
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index 9ddcc78..13d63d3 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -80,6 +80,12 @@
CLK_DUMMY("iface_clk", SDC1_P_CLK, NULL, OFF),
CLK_DUMMY("core_clk", SDC3_CLK, NULL, OFF),
CLK_DUMMY("iface_clk", SDC3_P_CLK, NULL, OFF),
+ CLK_DUMMY("usb_phy_clk", NULL, NULL, OFF),
+ CLK_DUMMY("usb_hs_clk", NULL, NULL, OFF),
+ CLK_DUMMY("usb_hs_pclk", NULL, NULL, OFF),
+ CLK_DUMMY("dfab_clk", DFAB_CLK, NULL, 0),
+ CLK_DUMMY("dma_bam_pclk", DMA_BAM_P_CLK, NULL, 0),
+ CLK_DUMMY("mem_clk", NULL, NULL, 0),
};
struct clock_init_data msm_dummy_clock_init_data __initdata = {
@@ -88,7 +94,7 @@
};
static struct of_dev_auxdata msm_copper_auxdata_lookup[] __initdata = {
- OF_DEV_AUXDATA("qcom,msm-lsuart-v14", 0xF9684000, \
+ OF_DEV_AUXDATA("qcom,msm-lsuart-v14", 0xF991F000, \
"msm_serial_hsl.0", NULL),
{}
};
diff --git a/arch/arm/mach-msm/board-dt.c b/arch/arm/mach-msm/board-dt.c
index 1a085de..ebe884de 100644
--- a/arch/arm/mach-msm/board-dt.c
+++ b/arch/arm/mach-msm/board-dt.c
@@ -16,10 +16,48 @@
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <asm/arch_timer.h>
#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
#include <mach/socinfo.h>
#include <mach/board.h>
-#include "timer.h"
+
+static void __init msm_dt_timer_init(void)
+{
+ struct device_node *node;
+ struct resource res;
+ struct of_irq oirq;
+
+ node = of_find_compatible_node(NULL, NULL, "qcom,msm-qtimer");
+ if (!node) {
+ pr_err("no matching timer node found\n");
+ return;
+ }
+
+ if (of_irq_map_one(node, 0, &oirq)) {
+ pr_err("interrupt not specified in timer node\n");
+ } else {
+ res.start = res.end = oirq.specifier[0];
+ res.flags = IORESOURCE_IRQ;
+ arch_timer_register(&res, 1);
+ }
+ of_node_put(node);
+}
+
+static struct sys_timer msm_dt_timer = {
+ .init = msm_dt_timer_init
+};
+
+int __cpuinit local_timer_setup(struct clock_event_device *evt)
+{
+ return 0;
+}
+
+int local_timer_ack(void)
+{
+ return 1;
+}
static void __init msm_dt_init_irq(void)
{
@@ -56,6 +94,6 @@
.map_io = msm_dt_map_io,
.init_irq = msm_dt_init_irq,
.init_machine = msm_dt_init,
- .timer = &msm_timer,
+ .timer = &msm_dt_timer,
.dt_compat = msm_dt_match,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index eb936e4..333d366 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -28,15 +28,12 @@
#include <asm/mach/arch.h>
#include <asm/setup.h>
-#include <mach/mpp.h>
#include <mach/board.h>
#include <mach/memory.h>
#include <mach/msm_iomap.h>
#include <mach/dma.h>
#include <mach/sirc.h>
-#include <mach/pmic.h>
-#include <mach/vreg.h>
#include <mach/socinfo.h>
#include "devices.h"
#include "timer.h"
@@ -46,7 +43,6 @@
#include <linux/regulator/consumer.h>
#include <linux/regulator/machine.h>
#include <linux/msm_adc.h>
-#include <linux/pmic8058-xoadc.h>
#include <linux/m_adcproc.h>
#include <linux/platform_data/qcom_crypto_device.h>
@@ -89,8 +85,11 @@
#define FPGA_SDCC_STATUS 0x8E0001A8
/* Macros assume PMIC GPIOs start at 0 */
-#define PM8058_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio + NR_MSM_GPIOS)
-#define PM8058_GPIO_SYS_TO_PM(sys_gpio) (sys_gpio - NR_MSM_GPIOS)
+#define PM8058_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio + NR_MSM_GPIOS)
+#define PM8058_GPIO_SYS_TO_PM(sys_gpio) (sys_gpio - NR_MSM_GPIOS)
+#define PM8058_MPP_BASE (NR_MSM_GPIOS + PM8058_GPIOS)
+#define PM8058_MPP_PM_TO_SYS(pm_gpio) (pm_gpio + PM8058_MPP_BASE)
+#define PM8058_MPP_SYS_TO_PM(sys_gpio) (sys_gpio - PM8058_MPP_BASE)
#define PMIC_GPIO_5V_PA_PWR 21 /* PMIC GPIO Number 22 */
#define PMIC_GPIO_4_2V_PA_PWR 22 /* PMIC GPIO Number 23 */
@@ -102,19 +101,33 @@
/*
* PM8058
*/
+struct pm8xxx_mpp_init_info {
+ unsigned mpp;
+ struct pm8xxx_mpp_config_data config;
+};
+
+#define PM8XXX_MPP_INIT(_mpp, _type, _level, _control) \
+{ \
+ .mpp = PM8058_MPP_PM_TO_SYS(_mpp), \
+ .config = { \
+ .type = PM8XXX_MPP_TYPE_##_type, \
+ .level = _level, \
+ .control = PM8XXX_MPP_##_control, \
+ } \
+}
static int pm8058_gpios_init(void)
{
int i;
int rc;
struct pm8058_gpio_cfg {
- int gpio;
- struct pm8058_gpio cfg;
+ int gpio;
+ struct pm_gpio cfg;
};
struct pm8058_gpio_cfg gpio_cfgs[] = {
{ /* 5V PA Power */
- PMIC_GPIO_5V_PA_PWR,
+ PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_5V_PA_PWR),
{
.vin_sel = 0,
.direction = PM_GPIO_DIR_BOTH,
@@ -127,7 +140,7 @@
},
},
{ /* 4.2V PA Power */
- PMIC_GPIO_4_2V_PA_PWR,
+ PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_4_2V_PA_PWR),
{
.vin_sel = 0,
.direction = PM_GPIO_DIR_BOTH,
@@ -142,7 +155,7 @@
};
for (i = 0; i < ARRAY_SIZE(gpio_cfgs); ++i) {
- rc = pm8058_gpio_config(gpio_cfgs[i].gpio, &gpio_cfgs[i].cfg);
+ rc = pm8xxx_gpio_config(gpio_cfgs[i].gpio, &gpio_cfgs[i].cfg);
if (rc < 0) {
pr_err("%s pmic gpio config failed\n", __func__);
return rc;
@@ -154,37 +167,28 @@
static int pm8058_mpps_init(void)
{
- int rc;
+ int rc, i;
- /* Set up MPP 3 and 6 as analog outputs at 1.25V */
- rc = pm8058_mpp_config_analog_output(PMIC_MPP_3,
- PM_MPP_AOUT_LVL_1V25_2, PM_MPP_AOUT_CTL_ENABLE);
- if (rc) {
- pr_err("%s: Config mpp3 on pmic 8058 failed\n", __func__);
- return rc;
+ struct pm8xxx_mpp_init_info pm8058_mpps[] = {
+ PM8XXX_MPP_INIT(PMIC_MPP_3, A_OUTPUT,
+ PM8XXX_MPP_AOUT_LVL_1V25_2, AOUT_CTRL_ENABLE),
+ PM8XXX_MPP_INIT(PMIC_MPP_6, A_OUTPUT,
+ PM8XXX_MPP_AOUT_LVL_1V25_2, AOUT_CTRL_ENABLE),
+ };
+
+ for (i = 0; i < ARRAY_SIZE(pm8058_mpps); i++) {
+ rc = pm8xxx_mpp_config(pm8058_mpps[i].mpp,
+ &pm8058_mpps[i].config);
+ if (rc) {
+ pr_err("%s: Config %d mpp pm 8058 failed\n",
+ __func__, pm8058_mpps[i].mpp);
+ return rc;
+ }
}
- rc = pm8058_mpp_config_analog_output(PMIC_MPP_6,
- PM_MPP_AOUT_LVL_1V25_2, PM_MPP_AOUT_CTL_ENABLE);
- if (rc) {
- pr_err("%s: Config mpp5 on pmic 8058 failed\n", __func__);
- return rc;
- }
return 0;
}
-static struct pm8058_gpio_platform_data pm8058_gpio_data = {
- .gpio_base = PM8058_GPIO_PM_TO_SYS(0),
- .irq_base = PM8058_GPIO_IRQ(PMIC8058_IRQ_BASE, 0),
- .init = pm8058_gpios_init,
-};
-
-static struct pm8058_gpio_platform_data pm8058_mpp_data = {
- .gpio_base = PM8058_GPIO_PM_TO_SYS(PM8058_GPIOS),
- .irq_base = PM8058_MPP_IRQ(PMIC8058_IRQ_BASE, 0),
- .init = pm8058_mpps_init,
-};
-
static struct regulator_consumer_supply pm8058_vreg_supply[PM8058_VREG_MAX] = {
[PM8058_VREG_ID_L3] = REGULATOR_SUPPLY("8058_l3", NULL),
[PM8058_VREG_ID_L8] = REGULATOR_SUPPLY("8058_l8", NULL),
@@ -199,7 +203,7 @@
#define PM8058_VREG_INIT(_id, _min_uV, _max_uV, _modes, _ops, _apply_uV, \
_always_on, _pull_down) \
- [_id] = { \
+ { \
.init_data = { \
.constraints = { \
.valid_modes_mask = _modes, \
@@ -212,6 +216,7 @@
.num_consumer_supplies = 1, \
.consumer_supplies = &pm8058_vreg_supply[_id], \
}, \
+ .id = _id, \
.pull_down_enable = _pull_down, \
.pin_ctrl = 0, \
.pin_fn = PM8058_VREG_PIN_FN_ENABLE, \
@@ -233,7 +238,7 @@
PM8058_VREG_INIT(_id, _min_uV, _min_uV, REGULATOR_MODE_NORMAL, \
REGULATOR_CHANGE_STATUS, 0, 0, 1)
-static struct pm8058_vreg_pdata pm8058_vreg_init[PM8058_VREG_MAX] = {
+static struct pm8058_vreg_pdata pm8058_vreg_init[] = {
PM8058_VREG_INIT_LDO(PM8058_VREG_ID_L3, 1800000, 1800000),
PM8058_VREG_INIT_LDO(PM8058_VREG_ID_L8, 2200000, 2200000),
PM8058_VREG_INIT_LDO(PM8058_VREG_ID_L9, 2050000, 2050000),
@@ -244,22 +249,7 @@
PM8058_VREG_INIT_SMPS(PM8058_VREG_ID_S4, 1300000, 1300000),
};
-#define PM8058_VREG(_id) { \
- .name = "pm8058-regulator", \
- .id = _id, \
- .platform_data = &pm8058_vreg_init[_id], \
- .pdata_size = sizeof(pm8058_vreg_init[_id]), \
-}
-
#ifdef CONFIG_SENSORS_MSM_ADC
-static struct resource resources_adc[] = {
- {
- .start = PM8058_ADC_IRQ(PMIC8058_IRQ_BASE),
- .end = PM8058_ADC_IRQ(PMIC8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
-};
-
static struct adc_access_fn xoadc_fn = {
pm8058_xoadc_select_chan_and_start_conv,
pm8058_xoadc_read_adc_code,
@@ -298,17 +288,21 @@
static void pmic8058_xoadc_mpp_config(void)
{
- int rc;
-
- rc = pm8058_mpp_config_analog_input(XOADC_MPP_7,
- PM_MPP_AIN_AMUX_CH5, PM_MPP_AOUT_CTL_DISABLE);
- if (rc)
- pr_err("%s: Config mpp7 on pmic 8058 failed\n", __func__);
-
- rc = pm8058_mpp_config_analog_input(XOADC_MPP_10,
- PM_MPP_AIN_AMUX_CH6, PM_MPP_AOUT_CTL_DISABLE);
- if (rc)
- pr_err("%s: Config mpp10 on pmic 8058 failed\n", __func__);
+ int rc, i;
+ struct pm8xxx_mpp_init_info xoadc_mpps[] = {
+ PM8XXX_MPP_INIT(PMIC_MPP_7, A_INPUT, PM8XXX_MPP_AIN_AMUX_CH5,
+ AOUT_CTRL_DISABLE),
+ PM8XXX_MPP_INIT(PMIC_MPP_10, A_INPUT, PM8XXX_MPP_AIN_AMUX_CH6,
+ AOUT_CTRL_DISABLE),
+ };
+ for (i = 0; i < ARRAY_SIZE(xoadc_mpps); i++) {
+ rc = pm8xxx_mpp_config(xoadc_mpps[i].mpp,
+ &xoadc_mpps[i].config);
+ if (rc) {
+ pr_err("%s: Config MPP %d of PM8058 failed\n",
+ __func__, xoadc_mpps[i].mpp);
+ }
+ }
}
static struct regulator *vreg_ldo18_adc;
@@ -373,7 +367,7 @@
.conversiontime = 54,
};
-static struct xoadc_platform_data xoadc_pdata = {
+static struct xoadc_platform_data pm8058_xoadc_pdata = {
.xoadc_prop = &pm8058_xoadc_data,
.xoadc_mpp_config = pmic8058_xoadc_mpp_config,
.xoadc_vreg_set = pmic8058_xoadc_vreg_config,
@@ -400,7 +394,7 @@
};
#define PM8058_XO_INIT(_id, _modes, _ops, _always_on) \
- [PM8058_XO_ID_##_id] = { \
+ { \
.init_data = { \
.constraints = { \
.valid_modes_mask = _modes, \
@@ -412,63 +406,44 @@
ARRAY_SIZE(xo_consumers_##_id),\
.consumer_supplies = xo_consumers_##_id, \
}, \
+ .id = PM8058_XO_ID_##_id, \
}
#define PM8058_XO_INIT_AX(_id) \
PM8058_XO_INIT(_id, REGULATOR_MODE_NORMAL, REGULATOR_CHANGE_STATUS, 0)
-static struct pm8058_xo_pdata pm8058_xo_init_pdata[PM8058_XO_ID_MAX] = {
+static struct pm8058_xo_pdata pm8058_xo_init_pdata[] = {
PM8058_XO_INIT_AX(A0),
PM8058_XO_INIT_AX(A1),
};
-#define PM8058_XO(_id) { \
- .name = PM8058_XO_BUFFER_DEV_NAME, \
- .id = _id, \
- .platform_data = &pm8058_xo_init_pdata[_id], \
- .pdata_size = sizeof(pm8058_xo_init_pdata[_id]), \
-}
+#define PM8058_GPIO_INT 47
-/* Put sub devices with fixed location first in sub_devices array */
-static struct mfd_cell pm8058_subdevs[] = {
- { .name = "pm8058-mpp",
- .platform_data = &pm8058_mpp_data,
- .pdata_size = sizeof(pm8058_mpp_data),
- },
- {
- .name = "pm8058-gpio",
- .id = -1,
- .platform_data = &pm8058_gpio_data,
- .pdata_size = sizeof(pm8058_gpio_data),
- },
-#ifdef CONFIG_SENSORS_MSM_ADC
- {
- .name = "pm8058-xoadc",
- .id = -1,
- .num_resources = ARRAY_SIZE(resources_adc),
- .resources = resources_adc,
- .platform_data = &xoadc_pdata,
- .pdata_size =sizeof(xoadc_pdata),
- },
-#endif
- PM8058_VREG(PM8058_VREG_ID_L3),
- PM8058_VREG(PM8058_VREG_ID_L8),
- PM8058_VREG(PM8058_VREG_ID_L9),
- PM8058_VREG(PM8058_VREG_ID_L14),
- PM8058_VREG(PM8058_VREG_ID_L15),
- PM8058_VREG(PM8058_VREG_ID_L18),
- PM8058_VREG(PM8058_VREG_ID_S4),
- PM8058_VREG(PM8058_VREG_ID_LVS0),
- PM8058_XO(PM8058_XO_ID_A0),
- PM8058_XO(PM8058_XO_ID_A1),
+static struct pm8xxx_irq_platform_data pm8xxx_irq_pdata = {
+ .irq_base = PMIC8058_IRQ_BASE,
+ .devirq = MSM_GPIO_TO_INT(PM8058_GPIO_INT),
+ .irq_trigger_flag = IRQF_TRIGGER_LOW,
+};
+
+static struct pm8xxx_gpio_platform_data pm8xxx_gpio_pdata = {
+ .gpio_base = PM8058_GPIO_PM_TO_SYS(0),
+};
+
+static struct pm8xxx_mpp_platform_data pm8xxx_mpp_pdata = {
+ .mpp_base = PM8058_MPP_PM_TO_SYS(0),
};
static struct pm8058_platform_data pm8058_fsm9xxx_data = {
- .irq_base = PMIC8058_IRQ_BASE,
- .irq = MSM_GPIO_TO_INT(47),
-
- .num_subdevs = ARRAY_SIZE(pm8058_subdevs),
- .sub_devices = pm8058_subdevs,
+ .irq_pdata = &pm8xxx_irq_pdata,
+ .gpio_pdata = &pm8xxx_gpio_pdata,
+ .mpp_pdata = &pm8xxx_mpp_pdata,
+ .regulator_pdatas = pm8058_vreg_init,
+ .num_regulators = ARRAY_SIZE(pm8058_vreg_init),
+ .xo_buffer_pdata = pm8058_xo_init_pdata,
+ .num_xo_buffers = ARRAY_SIZE(pm8058_xo_init_pdata),
+#ifdef CONFIG_SENSORS_MSM_ADC
+ .xoadc_pdata = &pm8058_xoadc_pdata,
+#endif
};
#ifdef CONFIG_MSM_SSBI
@@ -882,13 +857,15 @@
msm_device_ssbi_pmic1.dev.platform_data =
&fsm9xxx_ssbi_pm8058_pdata;
#endif
+ buses_init();
platform_add_devices(devices, ARRAY_SIZE(devices));
#ifdef CONFIG_MSM_SPM
msm_spm_init(&msm_spm_data, 1);
#endif
- buses_init();
+ pm8058_gpios_init();
+ pm8058_mpps_init();
phy_init();
grfc_init();
user_gpios_init();
diff --git a/arch/arm/mach-msm/board-mahimahi-smb329.c b/arch/arm/mach-msm/board-mahimahi-smb329.c
old mode 100755
new mode 100644
diff --git a/arch/arm/mach-msm/board-msm7627-regulator.c b/arch/arm/mach-msm/board-msm7627-regulator.c
index 2ecda72c..7437911 100644
--- a/arch/arm/mach-msm/board-msm7627-regulator.c
+++ b/arch/arm/mach-msm/board-msm7627-regulator.c
@@ -207,10 +207,10 @@
PCOM_VREG_LDO(ldo10, 7, NULL, 2600000, 2600000, 0, -1, 0, 0, 0, 0),
PCOM_VREG_LDO(ldo11, 21, NULL, 1800000, 1800000, 0, -1, 0, 0, 0, 0),
PCOM_VREG_LDO(ldo12, 11, NULL, 1800000, 1800000, 0, -1, 0, 0, 0, 0),
- PCOM_VREG_LDO(ldo13, 15, NULL, 2850000, 2850000, 0, -1, 0, 0, 0, 0),
+ PCOM_VREG_LDO(ldo13, 15, NULL, 1800000, 2850000, 0, -1, 0, 0, 0, 0),
PCOM_VREG_LDO(ldo14, 24, NULL, 2700000, 2700000, 0, -1, 0, 0, 0, 0),
PCOM_VREG_LDO(ldo15, 23, NULL, 2600000, 2600000, 0, -1, 0, 0, 0, 0),
- PCOM_VREG_LDO(ldo16, 22, NULL, 3000000, 3000000, 0, -1, 0, 0, 0, 0),
+ PCOM_VREG_LDO(ldo16, 22, NULL, 2850000, 3000000, 0, -1, 0, 0, 0, 0),
PCOM_VREG_LDO(ldo17, 6, NULL, 1300000, 1300000, 0, -1, 0, 0, 0, 0),
};
diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c
index 3114e42..15705ec 100644
--- a/arch/arm/mach-msm/board-msm7x27.c
+++ b/arch/arm/mach-msm/board-msm7x27.c
@@ -160,10 +160,33 @@
#endif
#ifdef CONFIG_USB_MSM_OTG_72K
-struct vreg *vreg_3p3;
static int msm_hsusb_ldo_init(int init)
{
+ static struct regulator *reg_hsusb;
+ int rc;
if (init) {
+ reg_hsusb = regulator_get(NULL, "usb");
+ if (IS_ERR(reg_hsusb)) {
+ rc = PTR_ERR(reg_hsusb);
+ pr_err("%s: could not get regulator: %d\n",
+ __func__, rc);
+ goto out;
+ }
+
+ rc = regulator_set_voltage(reg_hsusb, 3300000, 3300000);
+ if (rc < 0) {
+ pr_err("%s: could not set voltage: %d\n",
+ __func__, rc);
+ goto usb_reg_fail;
+ }
+
+ rc = regulator_enable(reg_hsusb);
+ if (rc < 0) {
+ pr_err("%s: could not enable regulator: %d\n",
+ __func__, rc);
+ goto usb_reg_fail;
+ }
+
/*
* PHY 3.3V analog domain(VDDA33) is powered up by
* an always enabled power supply (LP5900TL-3.3).
@@ -172,15 +195,22 @@
* current. Hence USB VREG is explicitly turned
* off here.
*/
- vreg_3p3 = vreg_get(NULL, "usb");
- if (IS_ERR(vreg_3p3))
- return PTR_ERR(vreg_3p3);
- vreg_enable(vreg_3p3);
- vreg_disable(vreg_3p3);
- vreg_put(vreg_3p3);
+
+ rc = regulator_disable(reg_hsusb);
+ if (rc < 0) {
+ pr_err("%s: could not disable regulator: %d\n",
+ __func__, rc);
+ goto usb_reg_fail;
+ }
+
+ regulator_put(reg_hsusb);
}
return 0;
+usb_reg_fail:
+ regulator_put(reg_hsusb);
+out:
+ return rc;
}
static int msm_hsusb_pmic_notif_init(void (*callback)(int online), int init)
@@ -548,38 +578,56 @@
static int msm_fb_lcdc_power_save(int on)
{
- struct vreg *vreg[ARRAY_SIZE(msm_fb_lcdc_vreg)];
int i, rc = 0;
+ static struct regulator *vreg[ARRAY_SIZE(msm_fb_lcdc_vreg)];
+
+ if (on) {
+ for (i = 0; i < ARRAY_SIZE(msm_fb_lcdc_vreg); i++) {
+ vreg[i] = regulator_get(NULL, msm_fb_lcdc_vreg[i]);
+ if (IS_ERR(vreg[i])) {
+ rc = PTR_ERR(vreg[i]);
+ pr_err("%s: could get not regulator: %d\n",
+ __func__, rc);
+ goto reg_get_fail;
+ }
+
+ rc = regulator_set_voltage(vreg[i], 2850000, 3000000);
+ if (rc < 0) {
+ pr_err("%s: could not set voltage: %d\n",
+ __func__, rc);
+ goto reg_get_fail;
+ }
+ }
+ }
for (i = 0; i < ARRAY_SIZE(msm_fb_lcdc_vreg); i++) {
if (on) {
- vreg[i] = vreg_get(0, msm_fb_lcdc_vreg[i]);
- rc = vreg_enable(vreg[i]);
+ rc = regulator_enable(vreg[i]);
if (rc) {
- printk(KERN_ERR "vreg_enable: %s vreg"
- "operation failed \n",
- msm_fb_lcdc_vreg[i]);
- goto bail;
+ pr_err("%s: could not enable regulator %s:"
+ "%d\n", __func__,
+ msm_fb_lcdc_vreg[i], rc);
+ goto vreg_lcdc_fail;
}
} else {
- int tmp;
- vreg[i] = vreg_get(0, msm_fb_lcdc_vreg[i]);
- tmp = vreg_disable(vreg[i]);
- if (tmp) {
- printk(KERN_ERR "vreg_disable: %s vreg "
- "operation failed \n",
- msm_fb_lcdc_vreg[i]);
- if (!rc)
- rc = tmp;
+ rc = regulator_disable(vreg[i]);
+ if (rc) {
+ pr_err("%s: could not disable regulator %s:"
+ "%d\n", __func__,
+ msm_fb_lcdc_vreg[i], rc);
+
+ regulator_put(vreg[i]);
+ goto vreg_lcdc_fail;
+
}
- tmp = gpio_tlmm_config(GPIO_CFG(GPIO_OUT_88, 0,
+
+ regulator_put(vreg[i]);
+ rc = gpio_tlmm_config(GPIO_CFG(GPIO_OUT_88, 0,
GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
GPIO_CFG_2MA), GPIO_CFG_ENABLE);
- if (tmp) {
+ if (rc)
printk(KERN_ERR "gpio_tlmm_config failed\n");
- if (!rc)
- rc = tmp;
- }
+
gpio_set_value(88, 0);
mdelay(15);
gpio_set_value(88, 1);
@@ -589,14 +637,23 @@
return rc;
-bail:
+reg_get_fail:
+ for (; i > 0; i--)
+ regulator_put(vreg[i - 1]);
+ return rc;
+
+vreg_lcdc_fail:
if (on) {
for (; i > 0; i--)
- vreg_disable(vreg[i - 1]);
+ regulator_disable(vreg[i - 1]);
+ } else {
+ for (; i > 0; i--)
+ regulator_enable(vreg[i - 1]);
}
return rc;
}
+
static struct lcdc_platform_data lcdc_pdata = {
.lcdc_gpio_config = msm_fb_lcdc_config,
.lcdc_power_save = msm_fb_lcdc_power_save,
@@ -695,20 +752,13 @@
static int bluetooth_power(int on)
{
- struct vreg *vreg_bt;
int pin, rc;
+ static struct regulator *vreg_bt;
printk(KERN_DEBUG "%s\n", __func__);
/* do not have vreg bt defined, gp6 is the same */
/* vreg_get parameter 1 (struct device *) is ignored */
- vreg_bt = vreg_get(NULL, "gp6");
-
- if (IS_ERR(vreg_bt)) {
- printk(KERN_ERR "%s: vreg get failed (%ld)\n",
- __func__, PTR_ERR(vreg_bt));
- return PTR_ERR(vreg_bt);
- }
if (on) {
for (pin = 0; pin < ARRAY_SIZE(bt_config_power_on); pin++) {
@@ -721,27 +771,35 @@
return -EIO;
}
}
+ vreg_bt = regulator_get(NULL, "gp6");
+
+ if (IS_ERR(vreg_bt)) {
+ rc = PTR_ERR(vreg_bt);
+ pr_err("%s: could get not regulator: %d\n",
+ __func__, rc);
+ goto out;
+ }
/* units of mV, steps of 50 mV */
- rc = vreg_set_level(vreg_bt, 2600);
- if (rc) {
- printk(KERN_ERR "%s: vreg set level failed (%d)\n",
- __func__, rc);
- return -EIO;
+ rc = regulator_set_voltage(vreg_bt, 2600000, 2600000);
+ if (rc < 0) {
+ pr_err("%s: could not set voltage: %d\n", __func__, rc);
+ goto bt_vreg_fail;
}
- rc = vreg_enable(vreg_bt);
- if (rc) {
- printk(KERN_ERR "%s: vreg enable failed (%d)\n",
- __func__, rc);
- return -EIO;
+ rc = regulator_enable(vreg_bt);
+ if (rc < 0) {
+ pr_err("%s: could not enable regulator: %d\n",
+ __func__, rc);
+ goto bt_vreg_fail;
}
} else {
- rc = vreg_disable(vreg_bt);
- if (rc) {
- printk(KERN_ERR "%s: vreg disable failed (%d)\n",
- __func__, rc);
- return -EIO;
+ rc = regulator_disable(vreg_bt);
+ if (rc < 0) {
+ pr_err("%s: could not disable regulator: %d\n",
+ __func__, rc);
+ goto bt_vreg_fail;
}
+ regulator_put(vreg_bt);
for (pin = 0; pin < ARRAY_SIZE(bt_config_power_off); pin++) {
rc = gpio_tlmm_config(bt_config_power_off[pin],
GPIO_CFG_ENABLE);
@@ -754,6 +812,11 @@
}
}
return 0;
+
+bt_vreg_fail:
+ regulator_put(vreg_bt);
+out:
+ return rc;
}
static void __init bt_power_init(void)
@@ -884,68 +947,93 @@
}
}
-static struct vreg *vreg_gp2;
-static struct vreg *vreg_gp3;
-
static void msm_camera_vreg_config(int vreg_en)
{
int rc;
+ static struct regulator *vreg_gp2;
+ static struct regulator *vreg_gp3;
- if (vreg_gp2 == NULL) {
- vreg_gp2 = vreg_get(NULL, "gp2");
+ if (vreg_gp2 == NULL && vreg_gp3 == NULL) {
+ vreg_gp2 = regulator_get(NULL, "gp2");
if (IS_ERR(vreg_gp2)) {
- printk(KERN_ERR "%s: vreg_get(%s) failed (%ld)\n",
- __func__, "gp2", PTR_ERR(vreg_gp2));
+ rc = PTR_ERR(vreg_gp2);
+ pr_err("%s: could not get regulator: %d\n",
+ __func__, rc);
return;
}
- rc = vreg_set_level(vreg_gp2, 1800);
- if (rc) {
- printk(KERN_ERR "%s: GP2 set_level failed (%d)\n",
- __func__, rc);
+ rc = regulator_set_voltage(vreg_gp2, 1800000, 1800000);
+ if (rc < 0) {
+ pr_err("%s: could not set voltage: %d\n",
+ __func__, rc);
+ goto cam_vreg_fail;
}
+
+ vreg_gp3 = regulator_get(NULL, "gp3");
+ if (IS_ERR(vreg_gp3)) {
+ rc = PTR_ERR(vreg_gp3);
+ pr_err("%s: could not get regulator: %d\n",
+ __func__, rc);
+ goto cam_vreg_fail;
+ }
+
+ rc = regulator_set_voltage(vreg_gp3, 2850000, 2850000);
+ if (rc < 0) {
+ pr_err("%s: could not set voltage: %d\n", __func__, rc);
+ goto cam_vreg2_fail;
+ }
+
+ return;
+
}
- if (vreg_gp3 == NULL) {
- vreg_gp3 = vreg_get(NULL, "gp3");
- if (IS_ERR(vreg_gp3)) {
- printk(KERN_ERR "%s: vreg_get(%s) failed (%ld)\n",
- __func__, "gp3", PTR_ERR(vreg_gp3));
- return;
- }
-
- rc = vreg_set_level(vreg_gp3, 2850);
- if (rc) {
- printk(KERN_ERR "%s: GP3 set level failed (%d)\n",
- __func__, rc);
- }
+ if (vreg_gp2 == NULL || vreg_gp3 == NULL) {
+ pr_err("Camera Regulators are not initialized\n");
+ return;
}
if (vreg_en) {
- rc = vreg_enable(vreg_gp2);
+ rc = regulator_enable(vreg_gp2);
if (rc) {
- printk(KERN_ERR "%s: GP2 enable failed (%d)\n",
- __func__, rc);
+ pr_err("%s: could not enable regulator: %d\n",
+ __func__, rc);
+ goto cam_vreg2_fail;
}
- rc = vreg_enable(vreg_gp3);
+ rc = regulator_enable(vreg_gp3);
if (rc) {
- printk(KERN_ERR "%s: GP3 enable failed (%d)\n",
- __func__, rc);
+ pr_err("%s: could not enable regulator: %d\n",
+ __func__, rc);
+ goto vreg_gp3_fail;
}
} else {
- rc = vreg_disable(vreg_gp2);
+ rc = regulator_disable(vreg_gp2);
if (rc) {
- printk(KERN_ERR "%s: GP2 disable failed (%d)\n",
- __func__, rc);
+ pr_err("%s: could not disable regulator: %d\n",
+ __func__, rc);
+ return;
}
- rc = vreg_disable(vreg_gp3);
+ rc = regulator_disable(vreg_gp3);
if (rc) {
- printk(KERN_ERR "%s: GP3 disable failed (%d)\n",
- __func__, rc);
+ pr_err("%s: could not disable regulator: %d\n",
+ __func__, rc);
+ goto cam_vreg2_fail;
}
}
+
+ return;
+
+vreg_gp3_fail:
+ if (vreg_en)
+ regulator_disable(vreg_gp2);
+
+cam_vreg2_fail:
+ regulator_put(vreg_gp3);
+cam_vreg_fail:
+ regulator_put(vreg_gp2);
+ vreg_gp3 = NULL;
+ vreg_gp2 = NULL;
}
static int config_camera_on_gpios(void)
@@ -1262,7 +1350,7 @@
|| defined(CONFIG_MMC_MSM_SDC4_SUPPORT))
static unsigned long vreg_sts, gpio_sts;
-static struct vreg *vreg_mmc;
+static struct regulator *vreg_mmc;
static unsigned mpp_mmc = 2;
struct sdcc_gpio {
@@ -1385,10 +1473,11 @@
MPP_CFG(MPP_DLOGIC_LVL_MSMP,
MPP_DLOGIC_OUT_CTRL_LOW));
} else
- rc = vreg_disable(vreg_mmc);
- if (rc)
- printk(KERN_ERR "%s: return val: %d \n",
+ rc = regulator_disable(vreg_mmc);
+ if (rc) {
+ pr_err("%s: return val: %d\n",
__func__, rc);
+ }
}
return 0;
}
@@ -1399,13 +1488,14 @@
MPP_CFG(MPP_DLOGIC_LVL_MSMP,
MPP_DLOGIC_OUT_CTRL_HIGH));
} else {
- rc = vreg_set_level(vreg_mmc, 2850);
+ rc = regulator_set_voltage(vreg_mmc, 2850000, 2850000);
if (!rc)
- rc = vreg_enable(vreg_mmc);
+ rc = regulator_enable(vreg_mmc);
}
- if (rc)
- printk(KERN_ERR "%s: return val: %d \n",
+ if (rc) {
+ pr_err("%s: return val: %d\n",
__func__, rc);
+ }
}
set_bit(pdev->id, &vreg_sts);
return 0;
@@ -1465,11 +1555,10 @@
static void __init msm7x2x_init_mmc(void)
{
if (!machine_is_msm7x25_ffa() && !machine_is_msm7x27_ffa()) {
- vreg_mmc = vreg_get(NULL, "mmc");
+ vreg_mmc = regulator_get(NULL, "mmc");
if (IS_ERR(vreg_mmc)) {
- printk(KERN_ERR "%s: vreg get failed (%ld)\n",
- __func__, PTR_ERR(vreg_mmc));
- return;
+ pr_err("%s: could not get regulator: %ld\n",
+ __func__, PTR_ERR(vreg_mmc));
}
}
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 1435774..5de5ea3 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -3023,7 +3023,6 @@
gpio_tlmm_config(GPIO_CFG(ATMEL_TS_GPIO_IRQ, 0,
GPIO_CFG_INPUT, GPIO_CFG_NO_PULL,
GPIO_CFG_2MA), GPIO_CFG_DISABLE);
- regulator_bulk_disable(ARRAY_SIZE(regs_atmel), regs_atmel);
regulator_bulk_free(ARRAY_SIZE(regs_atmel), regs_atmel);
return 0;
}
@@ -3041,7 +3040,7 @@
#define ATMEL_X_OFFSET 13
#define ATMEL_Y_OFFSET 0
-static struct mxt_platform_data atmel_ts_pdata = {
+static struct maxtouch_platform_data atmel_ts_pdata = {
.numtouch = 4,
.init_platform_hw = atmel_ts_platform_init,
.exit_platform_hw = atmel_ts_platform_exit,
diff --git a/arch/arm/mach-msm/board-msm7x30-regulator.c b/arch/arm/mach-msm/board-msm7x30-regulator.c
index 0ca7f16..a3f5ee1 100644
--- a/arch/arm/mach-msm/board-msm7x30-regulator.c
+++ b/arch/arm/mach-msm/board-msm7x30-regulator.c
@@ -274,7 +274,7 @@
* name id supp min uV max uV R P A B V S */
PCOM_VREG_SMP(smps0, 3, NULL, 500000, 1500000, 0, -1, 0, 0, 0, 0),
PCOM_VREG_SMP(smps1, 4, NULL, 500000, 1500000, 0, -1, 0, 0, 0, 0),
- PCOM_VREG_SMP(smps2, 28, NULL, 1225000, 1225000, 0, -1, 0, 0, 0, 0),
+ PCOM_VREG_SMP(smps2, 28, NULL, 1300000, 1300000, 0, -1, 0, 0, 0, 0),
PCOM_VREG_SMP(smps3, 29, NULL, 1800000, 1800000, 0, -1, 0, 0, 0, 0),
PCOM_VREG_SMP(smps4, 43, NULL, 2200000, 2200000, 0, -1, 0, 0, 0, 0),
PCOM_VREG_LDO(ldo00, 5, NULL, 1200000, 1200000, 0, -1, 0, 0, 0, 0),
@@ -282,25 +282,25 @@
PCOM_VREG_LDO(ldo03, 19, NULL, 1800000, 3000000, 0, -1, 0, 0, 0, 0),
PCOM_VREG_LDO(ldo04, 9, NULL, 2850000, 2850000, 0, -1, 0, 0, 0, 0),
PCOM_VREG_LDO(ldo05, 18, NULL, 2850000, 2850000, 0, -1, 0, 0, 0, 0),
- PCOM_VREG_LDO(ldo06, 16, NULL, 3075000, 3075000, 0, -1, 0, 0, 0, 0),
+ PCOM_VREG_LDO(ldo06, 16, NULL, 3075000, 3400000, 0, -1, 0, 0, 0, 0),
PCOM_VREG_LDO(ldo07, 44, NULL, 1800000, 1800000, 0, -1, 0, 0, 0, 0),
PCOM_VREG_LDO(ldo08, 32, NULL, 1800000, 1800000, 0, -1, 0, 0, 0, 0),
PCOM_VREG_LDO(ldo09, 8, NULL, 2050000, 2050000, 0, -1, 0, 0, 0, 0),
PCOM_VREG_LDO(ldo10, 7, NULL, 2600000, 2600000, 0, -1, 0, 0, 0, 0),
PCOM_VREG_LDO(ldo11, 21, NULL, 2600000, 2600000, 0, -1, 0, 0, 0, 0),
PCOM_VREG_LDO(ldo12, 34, NULL, 1800000, 1800000, 0, -1, 0, 0, 0, 0),
- PCOM_VREG_LDO(ldo13, 15, NULL, 2900000, 2900000, 0, -1, 0, 0, 0, 0),
+ PCOM_VREG_LDO(ldo13, 15, NULL, 2900000, 3050000, 0, -1, 0, 0, 0, 0),
PCOM_VREG_LDO(ldo14, 24, NULL, 2850000, 2850000, 0, -1, 0, 0, 0, 0),
- PCOM_VREG_LDO(ldo15, 23, NULL, 3100000, 3100000, 0, -1, 0, 0, 0, 0),
+ PCOM_VREG_LDO(ldo15, 23, NULL, 3050000, 3100000, 0, -1, 0, 0, 0, 0),
PCOM_VREG_LDO(ldo16, 35, NULL, 2600000, 2600000, 0, -1, 0, 0, 0, 0),
PCOM_VREG_LDO(ldo17, 36, NULL, 2600000, 2600000, 0, -1, 0, 0, 0, 0),
PCOM_VREG_LDO(ldo18, 37, NULL, 2200000, 2200000, 0, -1, 0, 0, 0, 0),
- PCOM_VREG_LDO(ldo19, 45, NULL, 2500000, 2500000, 0, -1, 0, 0, 0, 0),
- PCOM_VREG_LDO(ldo20, 38, NULL, 1500000, 1500000, 0, -1, 0, 0, 0, 0),
+ PCOM_VREG_LDO(ldo19, 45, NULL, 2400000, 2500000, 0, -1, 0, 0, 0, 0),
+ PCOM_VREG_LDO(ldo20, 38, NULL, 1500000, 1800000, 0, -1, 0, 0, 0, 0),
PCOM_VREG_LDO(ldo21, 39, NULL, 1100000, 1100000, 0, -1, 0, 0, 0, 0),
- PCOM_VREG_LDO(ldo22, 40, NULL, 1300000, 1300000, 0, -1, 0, 0, 0, 0),
+ PCOM_VREG_LDO(ldo22, 40, NULL, 1200000, 1300000, 0, -1, 0, 0, 0, 0),
PCOM_VREG_LDO(ldo23, 22, NULL, 1350000, 1350000, 0, -1, 0, 0, 0, 0),
- PCOM_VREG_LDO(ldo24, 41, NULL, 1225000, 1225000, 0, -1, 0, 0, 0, 0),
+ PCOM_VREG_LDO(ldo24, 41, NULL, 1200000, 1200000, 0, -1, 0, 0, 0, 0),
PCOM_VREG_LDO(ldo25, 42, NULL, 1200000, 1200000, 0, -1, 0, 0, 0, 0),
/* Low-voltage switches */
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 9155e0c..9ba92ed 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -23,22 +23,21 @@
#endif
#include <linux/msm_ssbi.h>
#include <linux/mfd/pmic8058.h>
+#include <linux/leds.h>
#include <linux/mfd/marimba.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/smsc911x.h>
#include <linux/ofn_atlab.h>
#include <linux/power_supply.h>
-#include <linux/input/pmic8058-keypad.h>
#include <linux/i2c/isa1200.h>
-#include <linux/pwm.h>
-#include <linux/pmic8058-pwm.h>
#include <linux/i2c/tsc2007.h>
#include <linux/input/kp_flip_switch.h>
#include <linux/leds-pmic8058.h>
#include <linux/input/cy8c_ts.h>
#include <linux/msm_adc.h>
#include <linux/dma-mapping.h>
+#include <linux/regulator/consumer.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -123,6 +122,8 @@
/* Macros assume PMIC GPIOs start at 0 */
#define PM8058_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio + NR_GPIO_IRQS)
#define PM8058_GPIO_SYS_TO_PM(sys_gpio) (sys_gpio - NR_GPIO_IRQS)
+#define PM8058_MPP_BASE PM8058_GPIO_PM_TO_SYS(PM8058_GPIOS)
+#define PM8058_MPP_PM_TO_SYS(pm_gpio) (pm_gpio + PM8058_MPP_BASE)
#define PMIC_GPIO_FLASH_BOOST_ENABLE 15 /* PMIC GPIO Number 16 */
#define PMIC_GPIO_HAP_ENABLE 16 /* PMIC GPIO Number 17 */
@@ -136,61 +137,71 @@
#define PMIC_GPIO_QUICKVX_CLK 37 /* PMIC GPIO 38 */
#define PM_FLIP_MPP 5 /* PMIC MPP 06 */
+
+struct pm8xxx_gpio_init_info {
+ unsigned gpio;
+ struct pm_gpio config;
+};
+
static int pm8058_gpios_init(void)
{
int rc;
- int pmic_gpio_hdmi_5v_en;
-#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
- struct pm8058_gpio sdcc_det = {
- .direction = PM_GPIO_DIR_IN,
- .pull = PM_GPIO_PULL_UP_1P5,
- .vin_sel = 2,
- .function = PM_GPIO_FUNC_NORMAL,
- .inv_int_pol = 0,
- };
-#endif
- struct pm8058_gpio sdc4_en = {
- .direction = PM_GPIO_DIR_OUT,
- .pull = PM_GPIO_PULL_NO,
- .vin_sel = PM_GPIO_VIN_L5,
- .function = PM_GPIO_FUNC_NORMAL,
- .inv_int_pol = 0,
- .out_strength = PM_GPIO_STRENGTH_LOW,
- .output_value = 0,
+ struct pm8xxx_gpio_init_info sdc4_en = {
+ PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_SDC4_EN_N),
+ {
+ .direction = PM_GPIO_DIR_OUT,
+ .pull = PM_GPIO_PULL_NO,
+ .vin_sel = PM8058_GPIO_VIN_L5,
+ .function = PM_GPIO_FUNC_NORMAL,
+ .inv_int_pol = 0,
+ .out_strength = PM_GPIO_STRENGTH_LOW,
+ .output_value = 0,
+ },
};
- struct pm8058_gpio haptics_enable = {
- .direction = PM_GPIO_DIR_OUT,
- .pull = PM_GPIO_PULL_NO,
- .out_strength = PM_GPIO_STRENGTH_HIGH,
- .function = PM_GPIO_FUNC_NORMAL,
- .inv_int_pol = 0,
- .vin_sel = 2,
- .output_buffer = PM_GPIO_OUT_BUF_CMOS,
- .output_value = 0,
+ struct pm8xxx_gpio_init_info haptics_enable = {
+ PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_HAP_ENABLE),
+ {
+ .direction = PM_GPIO_DIR_OUT,
+ .pull = PM_GPIO_PULL_NO,
+ .out_strength = PM_GPIO_STRENGTH_HIGH,
+ .function = PM_GPIO_FUNC_NORMAL,
+ .inv_int_pol = 0,
+ .vin_sel = 2,
+ .output_buffer = PM_GPIO_OUT_BUF_CMOS,
+ .output_value = 0,
+ },
};
- struct pm8058_gpio hdmi_5V_en = {
- .direction = PM_GPIO_DIR_OUT,
- .pull = PM_GPIO_PULL_NO,
- .vin_sel = PM_GPIO_VIN_VPH,
- .function = PM_GPIO_FUNC_NORMAL,
- .out_strength = PM_GPIO_STRENGTH_LOW,
- .output_value = 0,
+ struct pm8xxx_gpio_init_info hdmi_5V_en = {
+ PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_HDMI_5V_EN_V3),
+ {
+ .direction = PM_GPIO_DIR_OUT,
+ .pull = PM_GPIO_PULL_NO,
+ .vin_sel = PM8058_GPIO_VIN_VPH,
+ .function = PM_GPIO_FUNC_NORMAL,
+ .out_strength = PM_GPIO_STRENGTH_LOW,
+ .output_value = 0,
+ },
};
- struct pm8058_gpio flash_boost_enable = {
- .direction = PM_GPIO_DIR_OUT,
- .output_buffer = PM_GPIO_OUT_BUF_CMOS,
- .output_value = 0,
- .pull = PM_GPIO_PULL_NO,
- .vin_sel = PM_GPIO_VIN_S3,
- .out_strength = PM_GPIO_STRENGTH_HIGH,
- .function = PM_GPIO_FUNC_2,
+ struct pm8xxx_gpio_init_info flash_boost_enable = {
+ PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_FLASH_BOOST_ENABLE),
+ {
+ .direction = PM_GPIO_DIR_OUT,
+ .output_buffer = PM_GPIO_OUT_BUF_CMOS,
+ .output_value = 0,
+ .pull = PM_GPIO_PULL_NO,
+ .vin_sel = PM8058_GPIO_VIN_S3,
+ .out_strength = PM_GPIO_STRENGTH_HIGH,
+ .function = PM_GPIO_FUNC_2,
+ },
};
- struct pm8058_gpio gpio23 = {
+ struct pm8xxx_gpio_init_info gpio23 = {
+ PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_WLAN_EXT_POR),
+ {
.direction = PM_GPIO_DIR_OUT,
.output_buffer = PM_GPIO_OUT_BUF_CMOS,
.output_value = 0,
@@ -198,71 +209,83 @@
.vin_sel = 2,
.out_strength = PM_GPIO_STRENGTH_LOW,
.function = PM_GPIO_FUNC_NORMAL,
+ }
};
-
- if (machine_is_msm8x55_svlte_surf() || machine_is_msm8x55_svlte_ffa() ||
- machine_is_msm7x30_fluid())
- pmic_gpio_hdmi_5v_en = PMIC_GPIO_HDMI_5V_EN_V2 ;
- else
- pmic_gpio_hdmi_5v_en = PMIC_GPIO_HDMI_5V_EN_V3 ;
-
- if (machine_is_msm7x30_fluid()) {
- rc = pm8058_gpio_config(PMIC_GPIO_HAP_ENABLE, &haptics_enable);
- if (rc) {
- pr_err("%s: PMIC GPIO %d write failed\n", __func__,
- (PMIC_GPIO_HAP_ENABLE + 1));
- return rc;
- }
- rc = pm8058_gpio_config(PMIC_GPIO_FLASH_BOOST_ENABLE,
- &flash_boost_enable);
- if (rc) {
- pr_err("%s: PMIC GPIO %d write failed\n", __func__,
- (PMIC_GPIO_FLASH_BOOST_ENABLE + 1));
- return rc;
- }
- }
-
#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
- if (machine_is_msm7x30_fluid())
- sdcc_det.inv_int_pol = 1;
+ struct pm8xxx_gpio_init_info sdcc_det = {
+ PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_SD_DET - 1),
+ {
+ .direction = PM_GPIO_DIR_IN,
+ .pull = PM_GPIO_PULL_UP_1P5,
+ .vin_sel = 2,
+ .function = PM_GPIO_FUNC_NORMAL,
+ .inv_int_pol = 0,
+ },
+ };
- rc = pm8058_gpio_config(PMIC_GPIO_SD_DET - 1, &sdcc_det);
+ if (machine_is_msm7x30_fluid())
+ sdcc_det.config.inv_int_pol = 1;
+
+ rc = pm8xxx_gpio_config(sdcc_det.gpio, &sdcc_det.config);
if (rc) {
pr_err("%s PMIC_GPIO_SD_DET config failed\n", __func__);
return rc;
}
#endif
- rc = pm8058_gpio_config(pmic_gpio_hdmi_5v_en, &hdmi_5V_en);
+ if (machine_is_msm8x55_svlte_surf() || machine_is_msm8x55_svlte_ffa() ||
+ machine_is_msm7x30_fluid())
+ hdmi_5V_en.gpio = PMIC_GPIO_HDMI_5V_EN_V2;
+ else
+ hdmi_5V_en.gpio = PMIC_GPIO_HDMI_5V_EN_V3;
+
+ hdmi_5V_en.gpio = PM8058_GPIO_PM_TO_SYS(hdmi_5V_en.gpio);
+
+ rc = pm8xxx_gpio_config(hdmi_5V_en.gpio, &hdmi_5V_en.config);
if (rc) {
pr_err("%s PMIC_GPIO_HDMI_5V_EN config failed\n", __func__);
return rc;
}
/* Deassert GPIO#23 (source for Ext_POR on WLAN-Volans) */
- rc = pm8058_gpio_config(PMIC_GPIO_WLAN_EXT_POR, &gpio23);
+ rc = pm8xxx_gpio_config(gpio23.gpio, &gpio23.config);
if (rc) {
pr_err("%s PMIC_GPIO_WLAN_EXT_POR config failed\n", __func__);
return rc;
}
if (machine_is_msm7x30_fluid()) {
- rc = pm8058_gpio_config(PMIC_GPIO_SDC4_EN_N, &sdc4_en);
+ /* Haptics gpio */
+ rc = pm8xxx_gpio_config(haptics_enable.gpio,
+ &haptics_enable.config);
+ if (rc) {
+ pr_err("%s: PMIC GPIO %d write failed\n", __func__,
+ haptics_enable.gpio);
+ return rc;
+ }
+ /* Flash boost gpio */
+ rc = pm8xxx_gpio_config(flash_boost_enable.gpio,
+ &flash_boost_enable.config);
+ if (rc) {
+ pr_err("%s: PMIC GPIO %d write failed\n", __func__,
+ flash_boost_enable.gpio);
+ return rc;
+ }
+ /* SCD4 gpio */
+ rc = pm8xxx_gpio_config(sdc4_en.gpio, &sdc4_en.config);
if (rc) {
pr_err("%s PMIC_GPIO_SDC4_EN_N config failed\n",
__func__);
return rc;
}
- rc = gpio_request(PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_SDC4_EN_N),
- "sdc4_en");
+ rc = gpio_request(sdc4_en.gpio, "sdc4_en");
if (rc) {
pr_err("%s PMIC_GPIO_SDC4_EN_N gpio_request failed\n",
__func__);
return rc;
}
- gpio_set_value_cansleep(
- PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_SDC4_EN_N), 0);
+ gpio_set_value_cansleep(sdc4_en.gpio, 0);
}
return 0;
@@ -309,56 +332,43 @@
};
static struct kobject *properties_kobj;
+static struct regulator_bulk_data cyttsp_regs[] = {
+ { .supply = "ldo8", .min_uV = 1800000, .max_uV = 1800000 },
+ { .supply = "ldo15", .min_uV = 3050000, .max_uV = 3100000 },
+};
#define CYTTSP_TS_GPIO_IRQ 150
static int cyttsp_platform_init(struct i2c_client *client)
{
int rc = -EINVAL;
- struct vreg *vreg_ldo8, *vreg_ldo15;
- vreg_ldo8 = vreg_get(NULL, "gp7");
+ rc = regulator_bulk_get(NULL, ARRAY_SIZE(cyttsp_regs), cyttsp_regs);
- if (!vreg_ldo8) {
- pr_err("%s: VREG L8 get failed\n", __func__);
- return rc;
- }
-
- rc = vreg_set_level(vreg_ldo8, 1800);
if (rc) {
- pr_err("%s: VREG L8 set failed\n", __func__);
- goto l8_put;
+ pr_err("%s: could not get regulators: %d\n", __func__, rc);
+ goto out;
}
- rc = vreg_enable(vreg_ldo8);
+ rc = regulator_bulk_set_voltage(ARRAY_SIZE(cyttsp_regs), cyttsp_regs);
+
if (rc) {
- pr_err("%s: VREG L8 enable failed\n", __func__);
- goto l8_put;
+ pr_err("%s: could not set regulator voltages: %d\n", __func__,
+ rc);
+ goto regs_free;
}
- vreg_ldo15 = vreg_get(NULL, "gp6");
+ rc = regulator_bulk_enable(ARRAY_SIZE(cyttsp_regs), cyttsp_regs);
- if (!vreg_ldo15) {
- pr_err("%s: VREG L15 get failed\n", __func__);
- goto l8_disable;
- }
-
- rc = vreg_set_level(vreg_ldo15, 3050);
if (rc) {
- pr_err("%s: VREG L15 set failed\n", __func__);
- goto l8_disable;
- }
-
- rc = vreg_enable(vreg_ldo15);
- if (rc) {
- pr_err("%s: VREG L15 enable failed\n", __func__);
- goto l8_disable;
+ pr_err("%s: could not enable regulators: %d\n", __func__, rc);
+ goto regs_free;
}
/* check this device active by reading first byte/register */
rc = i2c_smbus_read_byte_data(client, 0x01);
if (rc < 0) {
pr_err("%s: i2c sanity check failed\n", __func__);
- goto l8_disable;
+ goto regs_disable;
}
rc = gpio_tlmm_config(GPIO_CFG(CYTTSP_TS_GPIO_IRQ, 0, GPIO_CFG_INPUT,
@@ -366,7 +376,7 @@
if (rc) {
pr_err("%s: Could not configure gpio %d\n",
__func__, CYTTSP_TS_GPIO_IRQ);
- goto l8_disable;
+ goto regs_disable;
}
/* virtual keys */
@@ -382,10 +392,11 @@
return CY_OK;
-l8_disable:
- vreg_disable(vreg_ldo8);
-l8_put:
- vreg_put(vreg_ldo8);
+regs_disable:
+ regulator_bulk_disable(ARRAY_SIZE(cyttsp_regs), cyttsp_regs);
+regs_free:
+ regulator_bulk_free(ARRAY_SIZE(cyttsp_regs), cyttsp_regs);
+out:
return rc;
}
@@ -450,12 +461,12 @@
static int pm8058_pwm_config(struct pwm_device *pwm, int ch, int on)
{
- struct pm8058_gpio pwm_gpio_config = {
+ struct pm_gpio pwm_gpio_config = {
.direction = PM_GPIO_DIR_OUT,
.output_buffer = PM_GPIO_OUT_BUF_CMOS,
.output_value = 0,
.pull = PM_GPIO_PULL_NO,
- .vin_sel = PM_GPIO_VIN_S3,
+ .vin_sel = PM8058_GPIO_VIN_S3,
.out_strength = PM_GPIO_STRENGTH_HIGH,
.function = PM_GPIO_FUNC_2,
};
@@ -469,9 +480,10 @@
case 2:
if (on) {
id = 24 + ch;
- rc = pm8058_gpio_config(id - 1, &pwm_gpio_config);
+ rc = pm8xxx_gpio_config(PM8058_GPIO_PM_TO_SYS(id - 1),
+ &pwm_gpio_config);
if (rc)
- pr_err("%s: pm8058_gpio_config(%d): rc=%d\n",
+ pr_err("%s: pm8xxx_gpio_config(%d): rc=%d\n",
__func__, id, rc);
}
break;
@@ -660,78 +672,47 @@
KEY(11, 7, KEY_RIGHTSHIFT),
};
-static struct resource resources_keypad[] = {
- {
- .start = PM8058_KEYPAD_IRQ(PMIC8058_IRQ_BASE),
- .end = PM8058_KEYPAD_IRQ(PMIC8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .start = PM8058_KEYSTUCK_IRQ(PMIC8058_IRQ_BASE),
- .end = PM8058_KEYSTUCK_IRQ(PMIC8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
-};
-
static struct matrix_keymap_data surf_keymap_data = {
- .keymap_size = ARRAY_SIZE(surf_keymap),
- .keymap = surf_keymap,
+ .keymap_size = ARRAY_SIZE(surf_keymap),
+ .keymap = surf_keymap,
};
-
-static struct pmic8058_keypad_data surf_keypad_data = {
+static struct pm8xxx_keypad_platform_data surf_keypad_data = {
.input_name = "surf_keypad",
.input_phys_device = "surf_keypad/input0",
.num_rows = 12,
.num_cols = 8,
- .rows_gpio_start = 8,
- .cols_gpio_start = 0,
- .debounce_ms = {8, 10},
+ .rows_gpio_start = PM8058_GPIO_PM_TO_SYS(8),
+ .cols_gpio_start = PM8058_GPIO_PM_TO_SYS(0),
+ .debounce_ms = 15,
.scan_delay_ms = 32,
.row_hold_ns = 91500,
.wakeup = 1,
- .keymap_data = &surf_keymap_data,
+ .keymap_data = &surf_keymap_data,
};
static struct matrix_keymap_data fluid_keymap_data = {
- .keymap_size = ARRAY_SIZE(fluid_keymap),
- .keymap = fluid_keymap,
+ .keymap_size = ARRAY_SIZE(fluid_keymap),
+ .keymap = fluid_keymap,
};
-
-
-static struct pmic8058_keypad_data fluid_keypad_data = {
+static struct pm8xxx_keypad_platform_data fluid_keypad_data = {
.input_name = "fluid-keypad",
.input_phys_device = "fluid-keypad/input0",
.num_rows = 5,
.num_cols = 5,
- .rows_gpio_start = 8,
- .cols_gpio_start = 0,
- .debounce_ms = {8, 10},
+ .rows_gpio_start = PM8058_GPIO_PM_TO_SYS(8),
+ .cols_gpio_start = PM8058_GPIO_PM_TO_SYS(0),
+ .debounce_ms = 15,
.scan_delay_ms = 32,
.row_hold_ns = 91500,
.wakeup = 1,
- .keymap_data = &fluid_keymap_data,
+ .keymap_data = &fluid_keymap_data,
};
static struct pm8058_pwm_pdata pm8058_pwm_data = {
- .config = pm8058_pwm_config,
- .enable = pm8058_pwm_enable,
-};
-
-/* Put sub devices with fixed location first in sub_devices array */
-#define PM8058_SUBDEV_KPD 0
-#define PM8058_SUBDEV_LED 1
-
-static struct pm8058_gpio_platform_data pm8058_gpio_data = {
- .gpio_base = PM8058_GPIO_PM_TO_SYS(0),
- .irq_base = PM8058_GPIO_IRQ(PMIC8058_IRQ_BASE, 0),
- .init = pm8058_gpios_init,
-};
-
-static struct pm8058_gpio_platform_data pm8058_mpp_data = {
- .gpio_base = PM8058_GPIO_PM_TO_SYS(PM8058_GPIOS),
- .irq_base = PM8058_MPP_IRQ(PMIC8058_IRQ_BASE, 0),
+ .config = pm8058_pwm_config,
+ .enable = pm8058_pwm_enable,
};
static struct pmic8058_led pmic8058_ffa_leds[] = {
@@ -765,38 +746,6 @@
},
};
-static struct mfd_cell pm8058_subdevs[] = {
- { .name = "pm8058-keypad",
- .id = -1,
- .num_resources = ARRAY_SIZE(resources_keypad),
- .resources = resources_keypad,
- },
- { .name = "pm8058-led",
- .id = -1,
- },
- { .name = "pm8058-gpio",
- .id = -1,
- .platform_data = &pm8058_gpio_data,
- .pdata_size = sizeof(pm8058_gpio_data),
- },
- { .name = "pm8058-mpp",
- .id = -1,
- .platform_data = &pm8058_mpp_data,
- .pdata_size = sizeof(pm8058_mpp_data),
- },
- { .name = "pm8058-pwm",
- .id = -1,
- .platform_data = &pm8058_pwm_data,
- .pdata_size = sizeof(pm8058_pwm_data),
- },
- { .name = "pm8058-nfc",
- .id = -1,
- },
- { .name = "pm8058-upl",
- .id = -1,
- },
-};
-
static struct pmic8058_leds_platform_data pm8058_surf_leds_data = {
.num_leds = ARRAY_SIZE(pmic8058_surf_leds),
.leds = pmic8058_surf_leds,
@@ -825,13 +774,25 @@
.leds = pmic8058_fluid_leds,
};
-static struct pm8058_platform_data pm8058_7x30_data = {
- .irq_base = PMIC8058_IRQ_BASE,
- .irq = MSM_GPIO_TO_INT(PMIC_GPIO_INT),
+static struct pm8xxx_irq_platform_data pm8xxx_irq_pdata = {
+ .irq_base = PMIC8058_IRQ_BASE,
+ .devirq = MSM_GPIO_TO_INT(PMIC_GPIO_INT),
+ .irq_trigger_flag = IRQF_TRIGGER_LOW,
+};
- .num_subdevs = ARRAY_SIZE(pm8058_subdevs),
- .sub_devices = pm8058_subdevs,
- .irq_trigger_flags = IRQF_TRIGGER_LOW,
+static struct pm8xxx_gpio_platform_data pm8xxx_gpio_pdata = {
+ .gpio_base = PM8058_GPIO_PM_TO_SYS(0),
+};
+
+static struct pm8xxx_mpp_platform_data pm8xxx_mpp_pdata = {
+ .mpp_base = PM8058_MPP_PM_TO_SYS(0),
+};
+
+static struct pm8058_platform_data pm8058_7x30_data = {
+ .irq_pdata = &pm8xxx_irq_pdata,
+ .gpio_pdata = &pm8xxx_gpio_pdata,
+ .mpp_pdata = &pm8xxx_mpp_pdata,
+ .pwm_pdata = &pm8058_pwm_data,
};
#ifdef CONFIG_MSM_SSBI
@@ -1399,58 +1360,54 @@
pr_info("%s: power off amplifier\n", __func__);
}
-static struct vreg *snddev_vreg_ncp, *snddev_vreg_gp4;
+static struct regulator_bulk_data snddev_regs[] = {
+ { .supply = "gp4", .min_uV = 2600000, .max_uV = 2600000 },
+ { .supply = "ncp", .min_uV = 1800000, .max_uV = 1800000 },
+};
-void msm_snddev_hsed_voltage_on(void)
+static int __init snddev_hsed_voltage_init(void)
{
int rc;
- snddev_vreg_gp4 = vreg_get(NULL, "gp4");
- if (IS_ERR(snddev_vreg_gp4)) {
- pr_err("%s: vreg_get(%s) failed (%ld)\n",
- __func__, "gp4", PTR_ERR(snddev_vreg_gp4));
- return;
- }
- rc = vreg_enable(snddev_vreg_gp4);
- if (rc)
- pr_err("%s: vreg_enable(gp4) failed (%d)\n", __func__, rc);
+ rc = regulator_bulk_get(NULL, ARRAY_SIZE(snddev_regs), snddev_regs);
- snddev_vreg_ncp = vreg_get(NULL, "ncp");
- if (IS_ERR(snddev_vreg_ncp)) {
- pr_err("%s: vreg_get(%s) failed (%ld)\n",
- __func__, "ncp", PTR_ERR(snddev_vreg_ncp));
- return;
+ if (rc) {
+ pr_err("%s: could not get regulators: %d\n", __func__, rc);
+ goto out;
}
- rc = vreg_enable(snddev_vreg_ncp);
+
+ rc = regulator_bulk_set_voltage(ARRAY_SIZE(snddev_regs), snddev_regs);
+
+ if (rc) {
+ pr_err("%s: could not set regulator voltages: %d\n",
+ __func__, rc);
+ goto regs_free;
+ }
+
+ return 0;
+
+regs_free:
+ regulator_bulk_free(ARRAY_SIZE(snddev_regs), snddev_regs);
+out:
+ return rc;
+}
+
+
+void msm_snddev_hsed_voltage_on(void)
+{
+ int rc = regulator_bulk_enable(ARRAY_SIZE(snddev_regs), snddev_regs);
+
if (rc)
- pr_err("%s: vreg_enable(ncp) failed (%d)\n", __func__, rc);
+ pr_err("%s: could not enable regulators: %d\n", __func__, rc);
}
void msm_snddev_hsed_voltage_off(void)
{
- int rc;
+ int rc = regulator_bulk_disable(ARRAY_SIZE(snddev_regs), snddev_regs);
- if (IS_ERR(snddev_vreg_ncp)) {
- pr_err("%s: vreg_get(%s) failed (%ld)\n",
- __func__, "ncp", PTR_ERR(snddev_vreg_ncp));
- return;
+ if (rc) {
+ pr_err("%s: could not disable regulators: %d\n", __func__, rc);
}
- rc = vreg_disable(snddev_vreg_ncp);
- if (rc)
- pr_err("%s: vreg_disable(ncp) failed (%d)\n", __func__, rc);
- vreg_put(snddev_vreg_ncp);
-
- if (IS_ERR(snddev_vreg_gp4)) {
- pr_err("%s: vreg_get(%s) failed (%ld)\n",
- __func__, "gp4", PTR_ERR(snddev_vreg_gp4));
- return;
- }
- rc = vreg_disable(snddev_vreg_gp4);
- if (rc)
- pr_err("%s: vreg_disable(gp4) failed (%d)\n", __func__, rc);
-
- vreg_put(snddev_vreg_gp4);
-
}
static unsigned aux_pcm_gpio_on[] = {
@@ -1611,15 +1568,10 @@
pr_err("%s: gpio_tlmm_config (gpio=%d) failed\n",
__func__, PMIC_GPIO_INT);
- if (machine_is_msm7x30_fluid()) {
- pm8058_7x30_data.sub_devices[PM8058_SUBDEV_KPD].platform_data
- = &fluid_keypad_data;
- } else {
- pm8058_7x30_data.sub_devices[PM8058_SUBDEV_KPD].platform_data
- = &surf_keypad_data;
- pm8058_7x30_data.sub_devices[PM8058_SUBDEV_KPD].pdata_size
- = sizeof(surf_keypad_data);
- }
+ if (machine_is_msm8x60_fluid())
+ pm8058_7x30_data.keypad_pdata = &fluid_keypad_data;
+ else
+ pm8058_7x30_data.keypad_pdata = &surf_keypad_data;
return 0;
}
@@ -1638,10 +1590,9 @@
VER_UNSUPPORTED = 0xFF
};
-
-static struct vreg *vreg_marimba_1;
-static struct vreg *vreg_marimba_2;
-static struct vreg *vreg_marimba_3;
+static struct regulator *vreg_marimba_1;
+static struct regulator *vreg_marimba_2;
+static struct regulator *vreg_bahama;
static struct msm_gpio timpani_reset_gpio_cfg[] = {
{ GPIO_CFG(TIMPANI_RESET_GPIO, 0, GPIO_CFG_OUTPUT,
@@ -1699,34 +1650,33 @@
if (rc < 0)
goto out;
- rc = vreg_enable(vreg_marimba_1);
+ rc = regulator_enable(vreg_marimba_1);
if (rc) {
- printk(KERN_ERR "%s: vreg_enable() = %d\n",
- __func__, rc);
+ pr_err("%s: regulator_enable failed (%d)\n", __func__, rc);
goto out;
}
- rc = vreg_enable(vreg_marimba_2);
+
+ rc = regulator_enable(vreg_marimba_2);
if (rc) {
- printk(KERN_ERR "%s: vreg_enable() = %d\n",
- __func__, rc);
- goto fail_disable_vreg_marimba_1;
+ pr_err("%s: regulator_enable failed (%d)\n", __func__, rc);
+ goto disable_marimba_1;
}
rc = gpio_direction_output(TIMPANI_RESET_GPIO, 1);
if (rc < 0) {
- printk(KERN_ERR
- "%s: gpio_direction_output failed (%d)\n",
+ pr_err("%s: gpio_direction_output failed (%d)\n",
__func__, rc);
msm_gpios_free(timpani_reset_gpio_cfg,
ARRAY_SIZE(timpani_reset_gpio_cfg));
- vreg_disable(vreg_marimba_2);
- } else
- goto out;
+ goto disable_marimba_2;
+ }
+ return 0;
-fail_disable_vreg_marimba_1:
- vreg_disable(vreg_marimba_1);
-
+disable_marimba_2:
+ regulator_disable(vreg_marimba_2);
+disable_marimba_1:
+ regulator_disable(vreg_marimba_1);
out:
return rc;
};
@@ -1735,23 +1685,18 @@
{
int rc;
- rc = vreg_disable(vreg_marimba_1);
- if (rc) {
- printk(KERN_ERR "%s: return val: %d\n",
- __func__, rc);
- }
- rc = vreg_disable(vreg_marimba_2);
- if (rc) {
- printk(KERN_ERR "%s: return val: %d\n",
- __func__, rc);
- }
+ rc = regulator_disable(vreg_marimba_2);
+ if (rc)
+ pr_err("%s: regulator_disable failed (%d)\n", __func__, rc);
+
+ rc = regulator_disable(vreg_marimba_1);
+ if (rc)
+ pr_err("%s: regulator_disable failed (%d)\n", __func__, rc);
rc = gpio_direction_output(TIMPANI_RESET_GPIO, 0);
- if (rc < 0) {
- printk(KERN_ERR
- "%s: gpio_direction_output failed (%d)\n",
+ if (rc < 0)
+ pr_err("%s: gpio_direction_output failed (%d)\n",
__func__, rc);
- }
msm_gpios_free(timpani_reset_gpio_cfg,
ARRAY_SIZE(timpani_reset_gpio_cfg));
@@ -1800,13 +1745,10 @@
static unsigned int msm_bahama_setup_power(void)
{
- int rc;
+ int rc = regulator_enable(vreg_bahama);
- rc = vreg_enable(vreg_marimba_3);
- if (rc) {
- printk(KERN_ERR "%s: vreg_enable() = %d\n",
- __func__, rc);
- }
+ if (rc)
+ pr_err("%s: regulator_enable failed (%d)\n", __func__, rc);
return rc;
};
@@ -1816,11 +1758,11 @@
int rc = 0;
if (value != BAHAMA_ID) {
- rc = vreg_disable(vreg_marimba_3);
- if (rc) {
- printk(KERN_ERR "%s: return val: %d\n",
+ rc = regulator_disable(vreg_bahama);
+
+ if (rc)
+ pr_err("%s: regulator_disable failed (%d)\n",
__func__, rc);
- }
}
return rc;
@@ -1850,39 +1792,42 @@
{
int rc;
- rc = vreg_enable(vreg_marimba_1);
+ rc = regulator_enable(vreg_marimba_1);
if (rc) {
- printk(KERN_ERR "%s: vreg_enable() = %d \n",
- __func__, rc);
+ pr_err("%s: regulator_enable failed (%d)\n", __func__, rc);
goto out;
}
- rc = vreg_enable(vreg_marimba_2);
+
+ rc = regulator_enable(vreg_marimba_2);
if (rc) {
- printk(KERN_ERR "%s: vreg_enable() = %d \n",
- __func__, rc);
- goto out;
+ pr_err("%s: regulator_enable failed (%d)\n", __func__, rc);
+ goto disable_marimba_1;
}
if (machine_is_msm8x55_svlte_surf() || machine_is_msm8x55_svlte_ffa()) {
rc = msm_gpios_request_enable(marimba_svlte_config_clock,
ARRAY_SIZE(marimba_svlte_config_clock));
if (rc < 0) {
- printk(KERN_ERR
- "%s: msm_gpios_request_enable failed (%d)\n",
+ pr_err("%s: msm_gpios_request_enable failed (%d)\n",
__func__, rc);
- return rc;
+ goto disable_marimba_2;
}
rc = gpio_direction_output(GPIO_PIN
(marimba_svlte_config_clock->gpio_cfg), 0);
if (rc < 0) {
- printk(KERN_ERR
- "%s: gpio_direction_output failed (%d)\n",
+ pr_err("%s: gpio_direction_output failed (%d)\n",
__func__, rc);
- return rc;
+ goto disable_marimba_2;
}
}
+ return 0;
+
+disable_marimba_2:
+ regulator_disable(vreg_marimba_2);
+disable_marimba_1:
+ regulator_disable(vreg_marimba_1);
out:
return rc;
};
@@ -1891,16 +1836,13 @@
{
int rc;
- rc = vreg_disable(vreg_marimba_1);
- if (rc) {
- printk(KERN_ERR "%s: return val: %d\n",
- __func__, rc);
- }
- rc = vreg_disable(vreg_marimba_2);
- if (rc) {
- printk(KERN_ERR "%s: return val: %d \n",
- __func__, rc);
- }
+ rc = regulator_disable(vreg_marimba_2);
+ if (rc)
+ pr_err("%s: regulator_disable failed (%d)\n", __func__, rc);
+
+ rc = regulator_disable(vreg_marimba_1);
+ if (rc)
+ pr_err("%s: regulator_disable failed (%d)\n", __func__, rc);
};
static int bahama_present(void)
@@ -1921,81 +1863,89 @@
}
}
-struct vreg *fm_regulator;
+struct regulator *fm_regulator;
static int fm_radio_setup(struct marimba_fm_platform_data *pdata)
{
- int rc;
+ int rc, voltage;
uint32_t irqcfg;
const char *id = "FMPW";
int bahama_not_marimba = bahama_present();
- if (bahama_not_marimba == -1) {
- printk(KERN_WARNING "%s: bahama_present: %d\n",
+ if (bahama_not_marimba < 0) {
+ pr_warn("%s: bahama_present: %d\n",
__func__, bahama_not_marimba);
- return -ENODEV;
+ rc = -ENODEV;
+ goto out;
}
- if (bahama_not_marimba)
- fm_regulator = vreg_get(NULL, "s3");
- else
- fm_regulator = vreg_get(NULL, "s2");
+ if (bahama_not_marimba) {
+ fm_regulator = regulator_get(NULL, "s3");
+ voltage = 1800000;
+ } else {
+ fm_regulator = regulator_get(NULL, "s2");
+ voltage = 1300000;
+ }
if (IS_ERR(fm_regulator)) {
- printk(KERN_ERR "%s: vreg get failed (%ld)\n",
- __func__, PTR_ERR(fm_regulator));
- return -1;
+ rc = PTR_ERR(fm_regulator);
+ pr_err("%s: regulator_get failed (%d)\n", __func__, rc);
+ goto out;
}
- if (!bahama_not_marimba) {
- rc = pmapp_vreg_level_vote(id, PMAPP_VREG_S2, 1300);
+ rc = regulator_set_voltage(fm_regulator, voltage, voltage);
- if (rc < 0) {
- printk(KERN_ERR "%s: voltage level vote failed (%d)\n",
- __func__, rc);
- return rc;
- }
- }
- rc = vreg_enable(fm_regulator);
if (rc) {
- printk(KERN_ERR "%s: vreg_enable() = %d\n",
- __func__, rc);
- return rc;
+ pr_err("%s: regulator_set_voltage failed (%d)\n", __func__, rc);
+ goto regulator_free;
}
- rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_DO,
- PMAPP_CLOCK_VOTE_ON);
- if (rc < 0) {
- printk(KERN_ERR "%s: clock vote failed (%d)\n",
- __func__, rc);
- goto fm_clock_vote_fail;
+ rc = regulator_enable(fm_regulator);
+
+ if (rc) {
+ pr_err("%s: regulator_enable failed (%d)\n", __func__, rc);
+ goto regulator_free;
}
+
+ rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_DO, PMAPP_CLOCK_VOTE_ON);
+
+ if (rc < 0) {
+ pr_err("%s: clock vote failed (%d)\n", __func__, rc);
+ goto regulator_disable;
+ }
+
/*Request the Clock Using GPIO34/AP2MDM_MRMBCK_EN in case
of svlte*/
- if (machine_is_msm8x55_svlte_surf() ||
- machine_is_msm8x55_svlte_ffa()) {
+ if (machine_is_msm8x55_svlte_surf() || machine_is_msm8x55_svlte_ffa()) {
rc = marimba_gpio_config(1);
- if (rc < 0)
- printk(KERN_ERR "%s: clock enable for svlte : %d\n",
- __func__, rc);
+ if (rc < 0) {
+ pr_err("%s: clock enable for svlte : %d\n",
+ __func__, rc);
+ goto clock_devote;
+ }
}
irqcfg = GPIO_CFG(147, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL,
GPIO_CFG_2MA);
rc = gpio_tlmm_config(irqcfg, GPIO_CFG_ENABLE);
if (rc) {
- printk(KERN_ERR "%s: gpio_tlmm_config(%#x)=%d\n",
- __func__, irqcfg, rc);
+ pr_err("%s: gpio_tlmm_config(%#x)=%d\n", __func__, irqcfg, rc);
rc = -EIO;
- goto fm_gpio_config_fail;
+ goto gpio_deconfig;
}
return 0;
-fm_gpio_config_fail:
- pmapp_clock_vote(id, PMAPP_CLOCK_ID_DO,
- PMAPP_CLOCK_VOTE_OFF);
-fm_clock_vote_fail:
- vreg_disable(fm_regulator);
- return rc;
+gpio_deconfig:
+ if (machine_is_msm8x55_svlte_surf() || machine_is_msm8x55_svlte_ffa())
+ marimba_gpio_config(0);
+clock_devote:
+ pmapp_clock_vote(id, PMAPP_CLOCK_ID_DO, PMAPP_CLOCK_VOTE_OFF);
+regulator_disable:
+ regulator_disable(fm_regulator);
+regulator_free:
+ regulator_put(fm_regulator);
+ fm_regulator = NULL;
+out:
+ return rc;
};
static void fm_radio_shutdown(struct marimba_fm_platform_data *pdata)
@@ -2007,48 +1957,36 @@
int bahama_not_marimba = bahama_present();
if (bahama_not_marimba == -1) {
- printk(KERN_WARNING "%s: bahama_present: %d\n",
- __func__, bahama_not_marimba);
+ pr_warn("%s: bahama_present: %d\n",
+ __func__, bahama_not_marimba);
return;
}
rc = gpio_tlmm_config(irqcfg, GPIO_CFG_ENABLE);
if (rc) {
- printk(KERN_ERR "%s: gpio_tlmm_config(%#x)=%d\n",
- __func__, irqcfg, rc);
+ pr_err("%s: gpio_tlmm_config(%#x)=%d\n", __func__, irqcfg, rc);
}
- if (fm_regulator != NULL) {
- rc = vreg_disable(fm_regulator);
+ if (!IS_ERR_OR_NULL(fm_regulator)) {
+ rc = regulator_disable(fm_regulator);
- if (rc) {
- printk(KERN_ERR "%s: return val: %d\n",
- __func__, rc);
- }
+ if (rc)
+ pr_err("%s: return val: %d\n", __func__, rc);
+
+ regulator_put(fm_regulator);
fm_regulator = NULL;
}
rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_DO,
PMAPP_CLOCK_VOTE_OFF);
if (rc < 0)
- printk(KERN_ERR "%s: clock_vote return val: %d\n",
- __func__, rc);
+ pr_err("%s: clock_vote return val: %d\n", __func__, rc);
/*Disable the Clock Using GPIO34/AP2MDM_MRMBCK_EN in case
of svlte*/
- if (machine_is_msm8x55_svlte_surf() ||
- machine_is_msm8x55_svlte_ffa()) {
+ if (machine_is_msm8x55_svlte_surf() || machine_is_msm8x55_svlte_ffa()) {
rc = marimba_gpio_config(0);
if (rc < 0)
- printk(KERN_ERR "%s: clock disable for svlte : %d\n",
- __func__, rc);
- }
-
-
- if (!bahama_not_marimba) {
- rc = pmapp_vreg_level_vote(id, PMAPP_VREG_S2, 0);
-
- if (rc < 0)
- printk(KERN_ERR "%s: vreg level vote return val: %d\n",
- __func__, rc);
+ pr_err("%s: clock disable for svlte : %d\n",
+ __func__, rc);
}
}
@@ -2075,82 +2013,60 @@
#define BAHAMA_SLAVE_ID_QMEMBIST_ADDR 0x7B
static const char *tsadc_id = "MADC";
-static const char *vregs_tsadc_name[] = {
- "gp12",
- "s2",
-};
-static struct vreg *vregs_tsadc[ARRAY_SIZE(vregs_tsadc_name)];
-static const char *vregs_timpani_tsadc_name[] = {
- "s3",
- "gp12",
- "gp16"
+static struct regulator_bulk_data regs_tsadc_marimba[] = {
+ { .supply = "gp12", .min_uV = 2200000, .max_uV = 2200000 },
+ { .supply = "s2", .min_uV = 1300000, .max_uV = 1300000 },
};
-static struct vreg *vregs_timpani_tsadc[ARRAY_SIZE(vregs_timpani_tsadc_name)];
+
+static struct regulator_bulk_data regs_tsadc_timpani[] = {
+ { .supply = "s3", .min_uV = 1800000, .max_uV = 1800000 },
+ { .supply = "gp12", .min_uV = 2200000, .max_uV = 2200000 },
+ { .supply = "gp16", .min_uV = 1200000, .max_uV = 1200000 },
+};
+
+static struct regulator_bulk_data *regs_tsadc;
+static int regs_tsadc_count;
static int marimba_tsadc_power(int vreg_on)
{
- int i, rc = 0;
+ int rc = 0;
int tsadc_adie_type = adie_get_detected_codec_type();
- if (tsadc_adie_type == TIMPANI_ID) {
- for (i = 0; i < ARRAY_SIZE(vregs_timpani_tsadc_name); i++) {
- if (!vregs_timpani_tsadc[i]) {
- pr_err("%s: vreg_get %s failed(%d)\n",
- __func__, vregs_timpani_tsadc_name[i], rc);
- goto vreg_fail;
- }
-
- rc = vreg_on ? vreg_enable(vregs_timpani_tsadc[i]) :
- vreg_disable(vregs_timpani_tsadc[i]);
- if (rc < 0) {
- pr_err("%s: vreg %s %s failed(%d)\n",
- __func__, vregs_timpani_tsadc_name[i],
- vreg_on ? "enable" : "disable", rc);
- goto vreg_fail;
- }
- }
- /* Vote for D0 and D1 buffer */
+ switch (tsadc_adie_type) {
+ case TIMPANI_ID:
rc = pmapp_clock_vote(tsadc_id, PMAPP_CLOCK_ID_D1,
vreg_on ? PMAPP_CLOCK_VOTE_ON : PMAPP_CLOCK_VOTE_OFF);
if (rc) {
pr_err("%s: unable to %svote for d1 clk\n",
__func__, vreg_on ? "" : "de-");
- goto do_vote_fail;
+ goto D1_vote_fail;
}
+
+ /* fall through */
+ case MARIMBA_ID:
rc = pmapp_clock_vote(tsadc_id, PMAPP_CLOCK_ID_DO,
vreg_on ? PMAPP_CLOCK_VOTE_ON : PMAPP_CLOCK_VOTE_OFF);
if (rc) {
pr_err("%s: unable to %svote for d1 clk\n",
__func__, vreg_on ? "" : "de-");
- goto do_vote_fail;
+ goto D0_vote_fail;
}
- } else if (tsadc_adie_type == MARIMBA_ID) {
- for (i = 0; i < ARRAY_SIZE(vregs_tsadc_name); i++) {
- if (!vregs_tsadc[i]) {
- pr_err("%s: vreg_get %s failed (%d)\n",
- __func__, vregs_tsadc_name[i], rc);
- goto vreg_fail;
- }
- rc = vreg_on ? vreg_enable(vregs_tsadc[i]) :
- vreg_disable(vregs_tsadc[i]);
- if (rc < 0) {
- pr_err("%s: vreg %s %s failed (%d)\n",
- __func__, vregs_tsadc_name[i],
- vreg_on ? "enable" : "disable", rc);
- goto vreg_fail;
- }
+ WARN_ON(regs_tsadc_count == 0);
+
+ rc = vreg_on ?
+ regulator_bulk_enable(regs_tsadc_count, regs_tsadc) :
+ regulator_bulk_disable(regs_tsadc_count, regs_tsadc);
+
+ if (rc) {
+ pr_err("%s: regulator %sable failed: %d\n",
+ __func__, vreg_on ? "en" : "dis", rc);
+ goto regulator_switch_fail;
}
- /* If marimba vote for DO buffer */
- rc = pmapp_clock_vote(tsadc_id, PMAPP_CLOCK_ID_DO,
- vreg_on ? PMAPP_CLOCK_VOTE_ON : PMAPP_CLOCK_VOTE_OFF);
- if (rc) {
- pr_err("%s: unable to %svote for d0 clk\n",
- __func__, vreg_on ? "" : "de-");
- goto do_vote_fail;
- }
- } else {
+
+ break;
+ default:
pr_err("%s:Adie %d not supported\n",
__func__, tsadc_adie_type);
return -ENODEV;
@@ -2160,112 +2076,69 @@
return 0;
-do_vote_fail:
-vreg_fail:
- while (i) {
- if (vreg_on) {
- if (tsadc_adie_type == TIMPANI_ID)
- vreg_disable(vregs_timpani_tsadc[--i]);
- else if (tsadc_adie_type == MARIMBA_ID)
- vreg_disable(vregs_tsadc[--i]);
- } else {
- if (tsadc_adie_type == TIMPANI_ID)
- vreg_enable(vregs_timpani_tsadc[--i]);
- else if (tsadc_adie_type == MARIMBA_ID)
- vreg_enable(vregs_tsadc[--i]);
- }
- }
-
- return rc;
-}
-
-static int marimba_tsadc_vote(int vote_on)
-{
- int rc = 0;
-
- if (adie_get_detected_codec_type() == MARIMBA_ID) {
- int level = vote_on ? 1300 : 0;
- rc = pmapp_vreg_level_vote(tsadc_id, PMAPP_VREG_S2, level);
- if (rc < 0)
- pr_err("%s: vreg level %s failed (%d)\n",
- __func__, vote_on ? "on" : "off", rc);
- }
-
+regulator_switch_fail:
+ pmapp_clock_vote(tsadc_id, PMAPP_CLOCK_ID_DO,
+ vreg_on ? PMAPP_CLOCK_VOTE_OFF : PMAPP_CLOCK_VOTE_ON);
+D0_vote_fail:
+ if (tsadc_adie_type == TIMPANI_ID)
+ pmapp_clock_vote(tsadc_id, PMAPP_CLOCK_ID_D1,
+ vreg_on ? PMAPP_CLOCK_VOTE_OFF : PMAPP_CLOCK_VOTE_ON);
+D1_vote_fail:
return rc;
}
static int marimba_tsadc_init(void)
{
- int i, rc = 0;
+ int rc = 0;
int tsadc_adie_type = adie_get_detected_codec_type();
- if (tsadc_adie_type == TIMPANI_ID) {
- for (i = 0; i < ARRAY_SIZE(vregs_timpani_tsadc_name); i++) {
- vregs_timpani_tsadc[i] = vreg_get(NULL,
- vregs_timpani_tsadc_name[i]);
- if (IS_ERR(vregs_timpani_tsadc[i])) {
- pr_err("%s: vreg get %s failed (%ld)\n",
- __func__, vregs_timpani_tsadc_name[i],
- PTR_ERR(vregs_timpani_tsadc[i]));
- rc = PTR_ERR(vregs_timpani_tsadc[i]);
- goto vreg_get_fail;
- }
- }
- } else if (tsadc_adie_type == MARIMBA_ID) {
- for (i = 0; i < ARRAY_SIZE(vregs_tsadc_name); i++) {
- vregs_tsadc[i] = vreg_get(NULL, vregs_tsadc_name[i]);
- if (IS_ERR(vregs_tsadc[i])) {
- pr_err("%s: vreg get %s failed (%ld)\n",
- __func__, vregs_tsadc_name[i],
- PTR_ERR(vregs_tsadc[i]));
- rc = PTR_ERR(vregs_tsadc[i]);
- goto vreg_get_fail;
- }
- }
- } else {
+ switch (tsadc_adie_type) {
+ case MARIMBA_ID:
+ regs_tsadc = regs_tsadc_marimba;
+ regs_tsadc_count = ARRAY_SIZE(regs_tsadc_marimba);
+ break;
+ case TIMPANI_ID:
+ regs_tsadc = regs_tsadc_timpani;
+ regs_tsadc_count = ARRAY_SIZE(regs_tsadc_timpani);
+ break;
+ default:
pr_err("%s:Adie %d not supported\n",
__func__, tsadc_adie_type);
- return -ENODEV;
+ rc = -ENODEV;
+ goto out;
+ }
+
+ rc = regulator_bulk_get(NULL, regs_tsadc_count, regs_tsadc);
+ if (rc) {
+ pr_err("%s: could not get regulators: %d\n",
+ __func__, rc);
+ goto out;
+ }
+
+ rc = regulator_bulk_set_voltage(regs_tsadc_count, regs_tsadc);
+ if (rc) {
+ pr_err("%s: could not set regulator voltages: %d\n",
+ __func__, rc);
+ goto vreg_free;
}
return 0;
-vreg_get_fail:
- while (i) {
- if (tsadc_adie_type == TIMPANI_ID)
- vreg_put(vregs_timpani_tsadc[--i]);
- else if (tsadc_adie_type == MARIMBA_ID)
- vreg_put(vregs_tsadc[--i]);
- }
+vreg_free:
+ regulator_bulk_free(regs_tsadc_count, regs_tsadc);
+out:
+ regs_tsadc = NULL;
+ regs_tsadc_count = 0;
return rc;
}
static int marimba_tsadc_exit(void)
{
- int i, rc = 0;
- int tsadc_adie_type = adie_get_detected_codec_type();
+ regulator_bulk_free(regs_tsadc_count, regs_tsadc);
+ regs_tsadc_count = 0;
+ regs_tsadc = NULL;
- if (tsadc_adie_type == TIMPANI_ID) {
- for (i = 0; i < ARRAY_SIZE(vregs_timpani_tsadc_name); i++) {
- if (vregs_tsadc[i])
- vreg_put(vregs_timpani_tsadc[i]);
- }
- } else if (tsadc_adie_type == MARIMBA_ID) {
- for (i = 0; i < ARRAY_SIZE(vregs_tsadc_name); i++) {
- if (vregs_tsadc[i])
- vreg_put(vregs_tsadc[i]);
- }
- rc = pmapp_vreg_level_vote(tsadc_id, PMAPP_VREG_S2, 0);
- if (rc < 0)
- pr_err("%s: vreg level off failed (%d)\n",
- __func__, rc);
- } else {
- pr_err("%s:Adie %d not supported\n",
- __func__, tsadc_adie_type);
- rc = -ENODEV;
- }
-
- return rc;
+ return 0;
}
@@ -2285,7 +2158,6 @@
.marimba_tsadc_power = marimba_tsadc_power,
.init = marimba_tsadc_init,
.exit = marimba_tsadc_exit,
- .level_vote = marimba_tsadc_vote,
.tsadc_prechg_en = true,
.can_wakeup = false,
.setup = {
@@ -2304,39 +2176,47 @@
.tssc_data = &msm_ts_data,
};
-static struct vreg *vreg_codec_s4;
+static struct regulator_bulk_data codec_regs[] = {
+ { .supply = "s4", .min_uV = 2200000, .max_uV = 2200000 },
+};
+
+static int __init msm_marimba_codec_init(void)
+{
+ int rc = regulator_bulk_get(NULL, ARRAY_SIZE(codec_regs), codec_regs);
+
+ if (rc) {
+ pr_err("%s: could not get regulators: %d\n", __func__, rc);
+ goto out;
+ }
+
+ rc = regulator_bulk_set_voltage(ARRAY_SIZE(codec_regs), codec_regs);
+ if (rc) {
+ pr_err("%s: could not set regulator voltages: %d\n",
+ __func__, rc);
+ goto reg_free;
+ }
+
+ return rc;
+
+reg_free:
+ regulator_bulk_free(ARRAY_SIZE(codec_regs), codec_regs);
+out:
+ return rc;
+}
+
static int msm_marimba_codec_power(int vreg_on)
{
- int rc = 0;
+ int rc = vreg_on ?
+ regulator_bulk_enable(ARRAY_SIZE(codec_regs), codec_regs) :
+ regulator_bulk_disable(ARRAY_SIZE(codec_regs), codec_regs);
- if (!vreg_codec_s4) {
-
- vreg_codec_s4 = vreg_get(NULL, "s4");
-
- if (IS_ERR(vreg_codec_s4)) {
- printk(KERN_ERR "%s: vreg_get() failed (%ld)\n",
- __func__, PTR_ERR(vreg_codec_s4));
- rc = PTR_ERR(vreg_codec_s4);
- goto vreg_codec_s4_fail;
- }
+ if (rc) {
+ pr_err("%s: could not %sable regulators: %d",
+ __func__, vreg_on ? "en" : "dis", rc);
+ return rc;
}
- if (vreg_on) {
- rc = vreg_enable(vreg_codec_s4);
- if (rc)
- printk(KERN_ERR "%s: vreg_enable() = %d \n",
- __func__, rc);
- goto vreg_codec_s4_fail;
- } else {
- rc = vreg_disable(vreg_codec_s4);
- if (rc)
- printk(KERN_ERR "%s: vreg_disable() = %d \n",
- __func__, rc);
- goto vreg_codec_s4_fail;
- }
-
-vreg_codec_s4_fail:
- return rc;
+ return 0;
}
static struct marimba_codec_platform_data mariba_codec_pdata = {
@@ -2367,29 +2247,38 @@
{
int rc;
- vreg_marimba_1 = vreg_get(NULL, "s3");
- if (IS_ERR(vreg_marimba_1)) {
- printk(KERN_ERR "%s: vreg get failed (%ld)\n",
- __func__, PTR_ERR(vreg_marimba_1));
- return;
- }
- rc = vreg_set_level(vreg_marimba_1, 1800);
+ struct regulator_bulk_data regs[] = {
+ { .supply = "s3", .min_uV = 1800000, .max_uV = 1800000 },
+ { .supply = "gp16", .min_uV = 1200000, .max_uV = 1200000 },
+ { .supply = "usb2", .min_uV = 1800000, .max_uV = 1800000 },
+ };
- vreg_marimba_2 = vreg_get(NULL, "gp16");
- if (IS_ERR(vreg_marimba_1)) {
- printk(KERN_ERR "%s: vreg get failed (%ld)\n",
- __func__, PTR_ERR(vreg_marimba_1));
- return;
- }
- rc = vreg_set_level(vreg_marimba_2, 1200);
+ rc = msm_marimba_codec_init();
- vreg_marimba_3 = vreg_get(NULL, "usb2");
- if (IS_ERR(vreg_marimba_3)) {
- printk(KERN_ERR "%s: vreg get failed (%ld)\n",
- __func__, PTR_ERR(vreg_marimba_3));
+ if (rc) {
+ pr_err("%s: msm_marimba_codec_init failed (%d)\n",
+ __func__, rc);
return;
}
- rc = vreg_set_level(vreg_marimba_3, 1800);
+
+ rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs), regs);
+
+ if (rc) {
+ pr_err("%s: could not get regulators: %d\n", __func__, rc);
+ return;
+ }
+
+ rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs), regs);
+
+ if (rc) {
+ pr_err("%s: could not set voltages: %d\n", __func__, rc);
+ regulator_bulk_free(ARRAY_SIZE(regs), regs);
+ return;
+ }
+
+ vreg_marimba_1 = regs[0].consumer;
+ vreg_marimba_2 = regs[1].consumer;
+ vreg_bahama = regs[2].consumer;
}
static struct marimba_codec_platform_data timpani_codec_pdata = {
@@ -2781,6 +2670,13 @@
"optnav_chip_select" },
};
+static struct regulator_bulk_data optnav_regulators[] = {
+ { .supply = "gp7", .min_uV = 1800000, .max_uV = 1800000 },
+ { .supply = "gp4", .min_uV = 2600000, .max_uV = 2600000 },
+ { .supply = "gp9", .min_uV = 1800000, .max_uV = 1800000 },
+ { .supply = "usb", .min_uV = 3300000, .max_uV = 3300000 },
+};
+
static void __iomem *virtual_optnav;
static int optnav_gpio_setup(void)
@@ -2789,6 +2685,9 @@
rc = msm_gpios_request_enable(optnav_config_data,
ARRAY_SIZE(optnav_config_data));
+ if (rc)
+ return rc;
+
/* Configure the FPGA for GPIOs */
virtual_optnav = ioremap(FPGA_OPTNAV_GPIO_ADDR, 0x4);
if (!virtual_optnav) {
@@ -2800,6 +2699,22 @@
* normal, active(enabled), output(MSM to SURF)
*/
writew(0x311E, virtual_optnav);
+
+ rc = regulator_bulk_get(NULL, ARRAY_SIZE(optnav_regulators),
+ optnav_regulators);
+ if (rc)
+ return rc;
+
+ rc = regulator_bulk_set_voltage(ARRAY_SIZE(optnav_regulators),
+ optnav_regulators);
+
+ if (rc)
+ goto regulator_put;
+
+ return rc;
+
+regulator_put:
+ regulator_bulk_free(ARRAY_SIZE(optnav_regulators), optnav_regulators);
return rc;
}
@@ -2808,13 +2723,9 @@
msm_gpios_disable_free(optnav_config_data,
ARRAY_SIZE(optnav_config_data));
iounmap(virtual_optnav);
+ regulator_bulk_free(ARRAY_SIZE(optnav_regulators), optnav_regulators);
}
-static struct vreg *vreg_gp7;
-static struct vreg *vreg_gp4;
-static struct vreg *vreg_gp9;
-static struct vreg *vreg_usb3_3;
-
static int optnav_enable(void)
{
int rc;
@@ -2822,80 +2733,24 @@
* Enable the VREGs L8(gp7), L10(gp4), L12(gp9), L6(usb)
* for I2C communication with keyboard.
*/
- vreg_gp7 = vreg_get(NULL, "gp7");
- rc = vreg_set_level(vreg_gp7, 1800);
- if (rc) {
- pr_err("%s: vreg_set_level failed \n", __func__);
- goto fail_vreg_gp7;
- }
- rc = vreg_enable(vreg_gp7);
- if (rc) {
- pr_err("%s: vreg_enable failed \n", __func__);
- goto fail_vreg_gp7;
- }
+ rc = regulator_bulk_enable(ARRAY_SIZE(optnav_regulators),
+ optnav_regulators);
- vreg_gp4 = vreg_get(NULL, "gp4");
- rc = vreg_set_level(vreg_gp4, 2600);
- if (rc) {
- pr_err("%s: vreg_set_level failed \n", __func__);
- goto fail_vreg_gp4;
- }
-
- rc = vreg_enable(vreg_gp4);
- if (rc) {
- pr_err("%s: vreg_enable failed \n", __func__);
- goto fail_vreg_gp4;
- }
-
- vreg_gp9 = vreg_get(NULL, "gp9");
- rc = vreg_set_level(vreg_gp9, 1800);
- if (rc) {
- pr_err("%s: vreg_set_level failed \n", __func__);
- goto fail_vreg_gp9;
- }
-
- rc = vreg_enable(vreg_gp9);
- if (rc) {
- pr_err("%s: vreg_enable failed \n", __func__);
- goto fail_vreg_gp9;
- }
-
- vreg_usb3_3 = vreg_get(NULL, "usb");
- rc = vreg_set_level(vreg_usb3_3, 3300);
- if (rc) {
- pr_err("%s: vreg_set_level failed \n", __func__);
- goto fail_vreg_3_3;
- }
-
- rc = vreg_enable(vreg_usb3_3);
- if (rc) {
- pr_err("%s: vreg_enable failed \n", __func__);
- goto fail_vreg_3_3;
- }
+ if (rc)
+ return rc;
/* Enable the chip select GPIO */
gpio_set_value(OPTNAV_CHIP_SELECT, 1);
gpio_set_value(OPTNAV_CHIP_SELECT, 0);
return 0;
-
-fail_vreg_3_3:
- vreg_disable(vreg_gp9);
-fail_vreg_gp9:
- vreg_disable(vreg_gp4);
-fail_vreg_gp4:
- vreg_disable(vreg_gp7);
-fail_vreg_gp7:
- return rc;
}
static void optnav_disable(void)
{
- vreg_disable(vreg_usb3_3);
- vreg_disable(vreg_gp9);
- vreg_disable(vreg_gp4);
- vreg_disable(vreg_gp7);
+ regulator_bulk_disable(ARRAY_SIZE(optnav_regulators),
+ optnav_regulators);
gpio_set_value(OPTNAV_CHIP_SELECT, 1);
}
@@ -2940,74 +2795,61 @@
};
#ifdef CONFIG_BOSCH_BMA150
-static struct vreg *vreg_gp6;
-static int sensors_ldo_enable(void)
+
+static struct regulator_bulk_data sensors_ldo[] = {
+ { .supply = "gp7", .min_uV = 1800000, .max_uV = 1800000 },
+ { .supply = "gp6", .min_uV = 3050000, .max_uV = 3100000 },
+};
+
+static int __init sensors_ldo_init(void)
{
int rc;
- /*
- * Enable the VREGs L8(gp7), L15(gp6)
- * for I2C communication with sensors.
- */
- pr_info("sensors_ldo_enable called!!\n");
- vreg_gp7 = vreg_get(NULL, "gp7");
- if (IS_ERR(vreg_gp7)) {
- pr_err("%s: vreg_get gp7 failed\n", __func__);
- rc = PTR_ERR(vreg_gp7);
- goto fail_gp7_get;
- }
+ rc = regulator_bulk_get(NULL, ARRAY_SIZE(sensors_ldo), sensors_ldo);
- rc = vreg_set_level(vreg_gp7, 1800);
if (rc) {
- pr_err("%s: vreg_set_level gp7 failed\n", __func__);
- goto fail_gp7_level;
+ pr_err("%s: could not get regulators: %d\n", __func__, rc);
+ goto out;
}
- rc = vreg_enable(vreg_gp7);
+ rc = regulator_bulk_set_voltage(ARRAY_SIZE(sensors_ldo), sensors_ldo);
+
if (rc) {
- pr_err("%s: vreg_enable gp7 failed\n", __func__);
- goto fail_gp7_level;
- }
-
- vreg_gp6 = vreg_get(NULL, "gp6");
- if (IS_ERR(vreg_gp6)) {
- pr_err("%s: vreg_get gp6 failed\n", __func__);
- rc = PTR_ERR(vreg_gp6);
- goto fail_gp6_get;
- }
-
- rc = vreg_set_level(vreg_gp6, 3050);
- if (rc) {
- pr_err("%s: vreg_set_level gp6 failed\n", __func__);
- goto fail_gp6_level;
- }
-
- rc = vreg_enable(vreg_gp6);
- if (rc) {
- pr_err("%s: vreg_enable gp6 failed\n", __func__);
- goto fail_gp6_level;
+ pr_err("%s: could not set voltages: %d\n", __func__, rc);
+ goto reg_free;
}
return 0;
-fail_gp6_level:
- vreg_put(vreg_gp6);
-fail_gp6_get:
- vreg_disable(vreg_gp7);
-fail_gp7_level:
- vreg_put(vreg_gp7);
-fail_gp7_get:
+reg_free:
+ regulator_bulk_free(ARRAY_SIZE(sensors_ldo), sensors_ldo);
+out:
return rc;
}
+static int sensors_ldo_set(int on)
+{
+ int rc = on ?
+ regulator_bulk_enable(ARRAY_SIZE(sensors_ldo), sensors_ldo) :
+ regulator_bulk_disable(ARRAY_SIZE(sensors_ldo), sensors_ldo);
+
+ if (rc)
+ pr_err("%s: could not %sable regulators: %d\n",
+ __func__, on ? "en" : "dis", rc);
+
+ return rc;
+}
+
+static int sensors_ldo_enable(void)
+{
+ return sensors_ldo_set(1);
+}
+
static void sensors_ldo_disable(void)
{
- pr_info("sensors_ldo_disable called!!\n");
- vreg_disable(vreg_gp6);
- vreg_put(vreg_gp6);
- vreg_disable(vreg_gp7);
- vreg_put(vreg_gp7);
+ sensors_ldo_set(0);
}
+
static struct bma150_platform_data bma150_data = {
.power_on = sensors_ldo_enable,
.power_off = sensors_ldo_disable,
@@ -3246,24 +3088,27 @@
{
int rc;
static int vbus_is_on;
- struct pm8058_gpio usb_vbus = {
- .direction = PM_GPIO_DIR_OUT,
- .pull = PM_GPIO_PULL_NO,
- .output_buffer = PM_GPIO_OUT_BUF_CMOS,
- .output_value = 1,
- .vin_sel = 2,
- .out_strength = PM_GPIO_STRENGTH_MED,
- .function = PM_GPIO_FUNC_NORMAL,
- .inv_int_pol = 0,
- };
+ struct pm8xxx_gpio_init_info usb_vbus = {
+ PM8058_GPIO_PM_TO_SYS(36),
+ {
+ .direction = PM_GPIO_DIR_OUT,
+ .pull = PM_GPIO_PULL_NO,
+ .output_buffer = PM_GPIO_OUT_BUF_CMOS,
+ .output_value = 1,
+ .vin_sel = 2,
+ .out_strength = PM_GPIO_STRENGTH_MED,
+ .function = PM_GPIO_FUNC_NORMAL,
+ .inv_int_pol = 0,
+ },
+ };
/* If VBUS is already on (or off), do nothing. */
if (unlikely(on == vbus_is_on))
return;
if (on) {
- rc = pm8058_gpio_config(36, &usb_vbus);
- if (rc) {
+ rc = pm8xxx_gpio_config(usb_vbus.gpio, &usb_vbus.config);
+ if (rc) {
pr_err("%s PMIC GPIO 36 write failed\n", __func__);
return;
}
@@ -3292,27 +3137,27 @@
#endif
#ifdef CONFIG_USB_MSM_OTG_72K
-static struct vreg *vreg_3p3;
+static struct regulator *vreg_3p3;
static int msm_hsusb_ldo_init(int init)
{
uint32_t version = 0;
- int def_vol = 3400;
+ int def_vol = 3400000;
version = socinfo_get_version();
if (SOCINFO_VERSION_MAJOR(version) >= 2 &&
SOCINFO_VERSION_MINOR(version) >= 1) {
- def_vol = 3075;
+ def_vol = 3075000;
pr_debug("%s: default voltage:%d\n", __func__, def_vol);
}
if (init) {
- vreg_3p3 = vreg_get(NULL, "usb");
+ vreg_3p3 = regulator_get(NULL, "usb");
if (IS_ERR(vreg_3p3))
return PTR_ERR(vreg_3p3);
- vreg_set_level(vreg_3p3, def_vol);
+ regulator_set_voltage(vreg_3p3, def_vol, def_vol);
} else
- vreg_put(vreg_3p3);
+ regulator_put(vreg_3p3);
return 0;
}
@@ -3330,14 +3175,14 @@
ldo_status = enable;
if (enable)
- return vreg_enable(vreg_3p3);
-
- return vreg_disable(vreg_3p3);
+ return regulator_enable(vreg_3p3);
+ else
+ return regulator_disable(vreg_3p3);
}
static int msm_hsusb_ldo_set_voltage(int mV)
{
- static int cur_voltage = 3400;
+ static int cur_voltage;
if (!vreg_3p3 || IS_ERR(vreg_3p3))
return -ENODEV;
@@ -3349,7 +3194,7 @@
pr_debug("%s: (%d)\n", __func__, mV);
- return vreg_set_level(vreg_3p3, mV);
+ return regulator_set_voltage(vreg_3p3, mV*1000, mV*1000);
}
#endif
@@ -3530,35 +3375,163 @@
GPIO_CFG(37, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA);
#endif
-static int gpio_set(const char *label, const char *name, int level, int on)
+static struct regulator_bulk_data hdmi_core_regs[] = {
+ { .supply = "ldo8", .min_uV = 1800000, .max_uV = 1800000 },
+};
+
+static struct regulator_bulk_data hdmi_comm_regs[] = {
+ { .supply = "ldo8", .min_uV = 1800000, .max_uV = 1800000 },
+ { .supply = "ldo10", .min_uV = 2600000, .max_uV = 2600000 },
+};
+
+static struct regulator_bulk_data hdmi_cec_regs[] = {
+ { .supply = "ldo17", .min_uV = 2600000, .max_uV = 2600000 },
+};
+
+static int __init hdmi_init_regs(void)
{
- struct vreg *vreg = vreg_get(NULL, label);
int rc;
- if (IS_ERR(vreg)) {
- rc = PTR_ERR(vreg);
- pr_err("%s: vreg %s get failed (%d)\n",
- __func__, name, rc);
- return rc;
- }
+ rc = regulator_bulk_get(NULL, ARRAY_SIZE(hdmi_core_regs),
+ hdmi_core_regs);
- rc = vreg_set_level(vreg, level);
if (rc) {
- pr_err("%s: vreg %s set level failed (%d)\n",
- __func__, name, rc);
- return rc;
+ pr_err("%s: could not get %s regulators: %d\n",
+ __func__, "core", rc);
+ goto out;
}
- if (on)
- rc = vreg_enable(vreg);
- else
- rc = vreg_disable(vreg);
- if (rc)
- pr_err("%s: vreg %s enable failed (%d)\n",
- __func__, name, rc);
+ rc = regulator_bulk_set_voltage(ARRAY_SIZE(hdmi_core_regs),
+ hdmi_core_regs);
+
+ if (rc) {
+ pr_err("%s: could not set %s voltages: %d\n",
+ __func__, "core", rc);
+ goto free_core;
+ }
+
+ rc = regulator_bulk_get(NULL, ARRAY_SIZE(hdmi_comm_regs),
+ hdmi_comm_regs);
+
+ if (rc) {
+ pr_err("%s: could not get %s regulators: %d\n",
+ __func__, "comm", rc);
+ goto free_core;
+ }
+
+ rc = regulator_bulk_set_voltage(ARRAY_SIZE(hdmi_comm_regs),
+ hdmi_comm_regs);
+
+ if (rc) {
+ pr_err("%s: could not set %s voltages: %d\n",
+ __func__, "comm", rc);
+ goto free_comm;
+ }
+
+ rc = regulator_bulk_get(NULL, ARRAY_SIZE(hdmi_cec_regs),
+ hdmi_cec_regs);
+
+ if (rc) {
+ pr_err("%s: could not get %s regulators: %d\n",
+ __func__, "cec", rc);
+ goto free_comm;
+ }
+
+ rc = regulator_bulk_set_voltage(ARRAY_SIZE(hdmi_cec_regs),
+ hdmi_cec_regs);
+
+ if (rc) {
+ pr_err("%s: could not set %s voltages: %d\n",
+ __func__, "cec", rc);
+ goto free_cec;
+ }
+
+ return 0;
+
+free_cec:
+ regulator_bulk_free(ARRAY_SIZE(hdmi_cec_regs), hdmi_cec_regs);
+free_comm:
+ regulator_bulk_free(ARRAY_SIZE(hdmi_comm_regs), hdmi_comm_regs);
+free_core:
+ regulator_bulk_free(ARRAY_SIZE(hdmi_core_regs), hdmi_core_regs);
+out:
return rc;
}
+static int hdmi_init_irq(void)
+{
+ int rc = msm_gpios_enable(dtv_panel_irq_gpios,
+ ARRAY_SIZE(dtv_panel_irq_gpios));
+ if (rc < 0) {
+ pr_err("%s: gpio enable failed: %d\n", __func__, rc);
+ return rc;
+ }
+ pr_info("%s\n", __func__);
+
+ return 0;
+}
+
+static int hdmi_enable_5v(int on)
+{
+ int pmic_gpio_hdmi_5v_en ;
+
+ if (machine_is_msm8x55_svlte_surf() || machine_is_msm8x55_svlte_ffa() ||
+ machine_is_msm7x30_fluid())
+ pmic_gpio_hdmi_5v_en = PMIC_GPIO_HDMI_5V_EN_V2 ;
+ else
+ pmic_gpio_hdmi_5v_en = PMIC_GPIO_HDMI_5V_EN_V3 ;
+
+ pr_info("%s: %d\n", __func__, on);
+ if (on) {
+ int rc;
+ rc = gpio_request(PM8058_GPIO_PM_TO_SYS(pmic_gpio_hdmi_5v_en),
+ "hdmi_5V_en");
+ if (rc) {
+ pr_err("%s PMIC_GPIO_HDMI_5V_EN gpio_request failed\n",
+ __func__);
+ return rc;
+ }
+ gpio_set_value_cansleep(
+ PM8058_GPIO_PM_TO_SYS(pmic_gpio_hdmi_5v_en), 1);
+ } else {
+ gpio_set_value_cansleep(
+ PM8058_GPIO_PM_TO_SYS(pmic_gpio_hdmi_5v_en), 0);
+ gpio_free(PM8058_GPIO_PM_TO_SYS(pmic_gpio_hdmi_5v_en));
+ }
+ return 0;
+}
+
+static int hdmi_comm_power(int on, int show)
+{
+ if (show)
+ pr_info("%s: i2c comm: %d <LDO8+LDO10>\n", __func__, on);
+ return on ?
+ regulator_bulk_enable(ARRAY_SIZE(hdmi_comm_regs),
+ hdmi_comm_regs) :
+ regulator_bulk_disable(ARRAY_SIZE(hdmi_comm_regs),
+ hdmi_comm_regs);
+}
+
+static int hdmi_core_power(int on, int show)
+{
+ if (show)
+ pr_info("%s: %d <LDO8>\n", __func__, on);
+ return on ?
+ regulator_bulk_enable(ARRAY_SIZE(hdmi_core_regs),
+ hdmi_core_regs) :
+ regulator_bulk_disable(ARRAY_SIZE(hdmi_core_regs),
+ hdmi_core_regs);
+}
+
+static int hdmi_cec_power(int on)
+{
+ pr_info("%s: %d <LDO17>\n", __func__, on);
+ return on ? regulator_bulk_enable(ARRAY_SIZE(hdmi_cec_regs),
+ hdmi_cec_regs) :
+ regulator_bulk_disable(ARRAY_SIZE(hdmi_cec_regs),
+ hdmi_cec_regs);
+}
+
#if defined(CONFIG_FB_MSM_HDMI_ADV7520_PANEL) || defined(CONFIG_BOSCH_BMA150)
/* there is an i2c address conflict between adv7520 and bma150 sensor after
* power up on fluid. As a solution, the default address of adv7520's packet
@@ -3571,7 +3544,6 @@
struct i2c_msg msgs[3];
int res;
int rc = -EINVAL;
- struct vreg *vreg_ldo8;
struct i2c_adapter *adapter;
if (machine_is_msm7x30_fluid()) {
@@ -3582,24 +3554,13 @@
}
/* turn on LDO8 */
- vreg_ldo8 = vreg_get(NULL, "gp7");
- if (!vreg_ldo8) {
- pr_err("%s: VREG L8 get failed\n", __func__);
+ rc = hdmi_core_power(1, 0);
+ if (rc) {
+ pr_err("%s: could not enable hdmi core regs: %d",
+ __func__, rc);
goto adapter_put;
}
- rc = vreg_set_level(vreg_ldo8, 1800);
- if (rc) {
- pr_err("%s: VREG L8 set failed\n", __func__);
- goto ldo8_put;
- }
-
- rc = vreg_enable(vreg_ldo8);
- if (rc) {
- pr_err("%s: VREG L8 enable failed\n", __func__);
- goto ldo8_put;
- }
-
/* change packet memory address to 0x74 */
wBuff[0] = 0x45;
wBuff[1] = 0x74;
@@ -3657,9 +3618,7 @@
return 0;
ldo8_disable:
- vreg_disable(vreg_ldo8);
-ldo8_put:
- vreg_put(vreg_ldo8);
+ hdmi_core_power(0, 0);
adapter_put:
i2c_put_adapter(adapter);
return rc;
@@ -3667,77 +3626,6 @@
fs_initcall_sync(fluid_i2c_address_fixup);
#endif
-static int hdmi_comm_power(int on, int show)
-{
- int rc = gpio_set("gp7", "LDO8", 1800, on);
- if (rc) {
- pr_warning("hdmi_comm_power: LDO8 gpio failed: rc=%d\n", rc);
- return rc;
- }
- rc = gpio_set("gp4", "LDO10", 2600, on);
- if (rc)
- pr_warning("hdmi_comm_power: LDO10 gpio failed: rc=%d\n", rc);
- if (show)
- pr_info("%s: i2c comm: %d <LDO8+LDO10>\n", __func__, on);
- return rc;
-}
-
-static int hdmi_init_irq(void)
-{
- int rc = msm_gpios_enable(dtv_panel_irq_gpios,
- ARRAY_SIZE(dtv_panel_irq_gpios));
- if (rc < 0) {
- pr_err("%s: gpio enable failed: %d\n", __func__, rc);
- return rc;
- }
- pr_info("%s\n", __func__);
-
- return 0;
-}
-
-static int hdmi_enable_5v(int on)
-{
- int pmic_gpio_hdmi_5v_en ;
-
- if (machine_is_msm8x55_svlte_surf() || machine_is_msm8x55_svlte_ffa() ||
- machine_is_msm7x30_fluid())
- pmic_gpio_hdmi_5v_en = PMIC_GPIO_HDMI_5V_EN_V2 ;
- else
- pmic_gpio_hdmi_5v_en = PMIC_GPIO_HDMI_5V_EN_V3 ;
-
- pr_info("%s: %d\n", __func__, on);
- if (on) {
- int rc;
- rc = gpio_request(PM8058_GPIO_PM_TO_SYS(pmic_gpio_hdmi_5v_en),
- "hdmi_5V_en");
- if (rc) {
- pr_err("%s PMIC_GPIO_HDMI_5V_EN gpio_request failed\n",
- __func__);
- return rc;
- }
- gpio_set_value_cansleep(
- PM8058_GPIO_PM_TO_SYS(pmic_gpio_hdmi_5v_en), 1);
- } else {
- gpio_set_value_cansleep(
- PM8058_GPIO_PM_TO_SYS(pmic_gpio_hdmi_5v_en), 0);
- gpio_free(PM8058_GPIO_PM_TO_SYS(pmic_gpio_hdmi_5v_en));
- }
- return 0;
-}
-
-static int hdmi_core_power(int on, int show)
-{
- if (show)
- pr_info("%s: %d <LDO8>\n", __func__, on);
- return gpio_set("gp7", "LDO8", 1800, on);
-}
-
-static int hdmi_cec_power(int on)
-{
- pr_info("%s: %d <LDO17>\n", __func__, on);
- return gpio_set("gp11", "LDO17", 2600, on);
-}
-
static bool hdmi_check_hdcp_hw_support(void)
{
if (machine_is_msm7x30_fluid())
@@ -4041,28 +3929,99 @@
static unsigned quickvx_vlp_gpio =
GPIO_CFG(97, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA);
-static struct pm8058_gpio pmic_quickvx_clk_gpio = {
- .direction = PM_GPIO_DIR_OUT,
- .output_buffer = PM_GPIO_OUT_BUF_CMOS,
- .output_value = 1,
- .pull = PM_GPIO_PULL_NO,
- .vin_sel = PM_GPIO_VIN_S3,
- .out_strength = PM_GPIO_STRENGTH_HIGH,
- .function = PM_GPIO_FUNC_2,
+static struct pm8xxx_gpio_init_info pmic_quickvx_clk_gpio = {
+ PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_QUICKVX_CLK),
+ {
+ .direction = PM_GPIO_DIR_OUT,
+ .output_buffer = PM_GPIO_OUT_BUF_CMOS,
+ .output_value = 1,
+ .pull = PM_GPIO_PULL_NO,
+ .vin_sel = PM8058_GPIO_VIN_S3,
+ .out_strength = PM_GPIO_STRENGTH_HIGH,
+ .function = PM_GPIO_FUNC_2,
+ },
};
+static struct regulator *mddi_ldo20;
+static struct regulator *mddi_ldo12;
+static struct regulator *mddi_ldo16;
+static struct regulator *mddi_ldo6;
+static struct regulator *mddi_lcd;
+
+static int display_common_init(void)
+{
+ struct regulator_bulk_data regs[5] = {
+ { .supply = "ldo20", /* voltage set in display_common_power */},
+ { .supply = "ldo12", .min_uV = 1800000, .max_uV = 1800000 },
+ { .supply = "ldo6", .min_uV = 3075000, .max_uV = 3400000 },
+ { .supply = "ldo16", .min_uV = 2600000, .max_uV = 2600000 },
+ { .supply = NULL, /* mddi_lcd, initialized below */ },
+ };
+
+ int rc = 0;
+
+ if (machine_is_msm7x30_fluid()) {
+ /* lcd: LDO8 @1.8V */
+ regs[4].supply = "ldo8";
+ regs[4].min_uV = 1800000;
+ regs[4].max_uV = 1800000;
+ } else {
+ /* lcd: LDO15 @3.1V */
+ regs[4].supply = "ldo15";
+ regs[4].min_uV = 3100000;
+ regs[4].max_uV = 3100000;
+ }
+
+ rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs), regs);
+ if (rc) {
+ pr_err("%s: regulator_bulk_get failed: %d\n",
+ __func__, rc);
+ goto bail;
+ }
+
+ rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs), regs);
+ if (rc) {
+ pr_err("%s: regulator_bulk_set_voltage failed: %d\n",
+ __func__, rc);
+ goto put_regs;
+ }
+
+ mddi_ldo20 = regs[0].consumer;
+ mddi_ldo12 = regs[1].consumer;
+ mddi_ldo6 = regs[2].consumer;
+ mddi_ldo16 = regs[3].consumer;
+ mddi_lcd = regs[4].consumer;
+
+ return rc;
+
+put_regs:
+ regulator_bulk_free(ARRAY_SIZE(regs), regs);
+bail:
+ return rc;
+}
+
static int display_common_power(int on)
{
int rc = 0, flag_on = !!on;
static int display_common_power_save_on;
- struct vreg *vreg_ldo12, *vreg_ldo15 = NULL, *vreg_ldo6;
- struct vreg *vreg_ldo20, *vreg_ldo16, *vreg_ldo8 = NULL;
+ static bool display_regs_initialized;
if (display_common_power_save_on == flag_on)
return 0;
display_common_power_save_on = flag_on;
+ if (unlikely(!display_regs_initialized)) {
+ rc = display_common_init();
+ if (rc) {
+ pr_err("%s: regulator init failed: %d\n",
+ __func__, rc);
+ return rc;
+ }
+ display_regs_initialized = true;
+ }
+
+
if (on) {
/* reset Toshiba WeGA chip -- toggle reset pin -- gpio_180 */
rc = gpio_tlmm_config(wega_reset_gpio, GPIO_CFG_ENABLE);
@@ -4088,11 +4047,11 @@
/* bring QuickVX VLP line low */
gpio_set_value(97, 0);
- rc = pm8058_gpio_config(PMIC_GPIO_QUICKVX_CLK,
- &pmic_quickvx_clk_gpio);
+ rc = pm8xxx_gpio_config(pmic_quickvx_clk_gpio.gpio,
+ &pmic_quickvx_clk_gpio.config);
if (rc) {
- pr_err("%s: pm8058_gpio_config(%#x)=%d\n",
- __func__, PMIC_GPIO_QUICKVX_CLK + 1,
+ pr_err("%s: pm8xxx_gpio_config(%#x)=%d\n",
+ __func__, pmic_quickvx_clk_gpio.gpio,
rc);
return rc;
}
@@ -4102,172 +4061,57 @@
}
}
- /* Toshiba WeGA power -- has 3 power source */
- /* 1.5V -- LDO20*/
- vreg_ldo20 = vreg_get(NULL, "gp13");
-
- if (IS_ERR(vreg_ldo20)) {
- rc = PTR_ERR(vreg_ldo20);
- pr_err("%s: gp13 vreg get failed (%d)\n",
- __func__, rc);
- return rc;
- }
-
- /* 1.8V -- LDO12 */
- vreg_ldo12 = vreg_get(NULL, "gp9");
-
- if (IS_ERR(vreg_ldo12)) {
- rc = PTR_ERR(vreg_ldo12);
- pr_err("%s: gp9 vreg get failed (%d)\n",
- __func__, rc);
- return rc;
- }
-
- /* 2.6V -- LDO16 */
- vreg_ldo16 = vreg_get(NULL, "gp10");
-
- if (IS_ERR(vreg_ldo16)) {
- rc = PTR_ERR(vreg_ldo16);
- pr_err("%s: gp10 vreg get failed (%d)\n",
- __func__, rc);
- return rc;
- }
-
- /* 3.075V -- LDO6 */
- vreg_ldo6 = vreg_get(NULL, "usb");
-
- if (IS_ERR(vreg_ldo6)) {
- rc = PTR_ERR(vreg_ldo6);
- pr_err("%s: usb vreg get failed (%d)\n",
- __func__, rc);
- return rc;
- }
-
- if (machine_is_msm7x30_fluid()) {
- /* 1.8V -- LDO8 */
- vreg_ldo8 = vreg_get(NULL, "gp7");
-
- if (IS_ERR(vreg_ldo8)) {
- rc = PTR_ERR(vreg_ldo8);
- pr_err("%s: gp7 vreg get failed (%d)\n",
- __func__, rc);
- return rc;
- }
- } else {
- /* lcd panel power */
- /* 3.1V -- LDO15 */
- vreg_ldo15 = vreg_get(NULL, "gp6");
-
- if (IS_ERR(vreg_ldo15)) {
- rc = PTR_ERR(vreg_ldo15);
- pr_err("%s: gp6 vreg get failed (%d)\n",
- __func__, rc);
- return rc;
- }
- }
-
- /* For QuickLogic chip, LDO20 requires 1.8V */
- /* Toshiba chip requires 1.5V, but can tolerate 1.8V since max is 3V */
if (quickvx_mddi_client)
- rc = vreg_set_level(vreg_ldo20, 1800);
+ rc = regulator_set_voltage(mddi_ldo20, 1800000, 1800000);
else
- rc = vreg_set_level(vreg_ldo20, 1500);
+ rc = regulator_set_voltage(mddi_ldo20, 1500000, 1500000);
+
if (rc) {
- pr_err("%s: vreg LDO20 set level failed (%d)\n",
- __func__, rc);
- return rc;
- }
-
- rc = vreg_set_level(vreg_ldo12, 1800);
- if (rc) {
- pr_err("%s: vreg LDO12 set level failed (%d)\n",
- __func__, rc);
- return rc;
- }
-
- if (other_mddi_client) {
- rc = vreg_set_level(vreg_ldo16, 2600);
- if (rc) {
- pr_err("%s: vreg LDO16 set level failed (%d)\n",
- __func__, rc);
- return rc;
- }
- }
-
- if (quickvx_mddi_client) {
- rc = vreg_set_level(vreg_ldo6, 3075);
- if (rc) {
- pr_err("%s: vreg LDO6 set level failed (%d)\n",
- __func__, rc);
- return rc;
- }
- }
-
- if (machine_is_msm7x30_fluid()) {
- rc = vreg_set_level(vreg_ldo8, 1800);
- if (rc) {
- pr_err("%s: vreg LDO8 set level failed (%d)\n",
+ pr_err("%s: could not set voltage for ldo20: %d\n",
__func__, rc);
- return rc;
- }
- } else {
- rc = vreg_set_level(vreg_ldo15, 3100);
- if (rc) {
- pr_err("%s: vreg LDO15 set level failed (%d)\n",
- __func__, rc);
- return rc;
- }
+ return rc;
}
if (on) {
- rc = vreg_enable(vreg_ldo20);
+ rc = regulator_enable(mddi_ldo20);
if (rc) {
- pr_err("%s: LDO20 vreg enable failed (%d)\n",
+ pr_err("%s: LDO20 regulator enable failed (%d)\n",
__func__, rc);
return rc;
}
- rc = vreg_enable(vreg_ldo12);
+ rc = regulator_enable(mddi_ldo12);
if (rc) {
- pr_err("%s: LDO12 vreg enable failed (%d)\n",
+ pr_err("%s: LDO12 regulator enable failed (%d)\n",
__func__, rc);
return rc;
}
if (other_mddi_client) {
- rc = vreg_enable(vreg_ldo16);
+ rc = regulator_enable(mddi_ldo16);
if (rc) {
- pr_err("%s: LDO16 vreg enable failed (%d)\n",
+ pr_err("%s: LDO16 regulator enable failed (%d)\n",
__func__, rc);
return rc;
}
}
- if (quickvx_mddi_client && quickvx_ldo_enabled) {
+ if (quickvx_ldo_enabled) {
/* Disable LDO6 during display ON */
- rc = vreg_disable(vreg_ldo6);
+ rc = regulator_disable(mddi_ldo6);
if (rc) {
- pr_err("%s: LDO6 vreg disable failed (%d)\n",
+ pr_err("%s: LDO6 regulator disable failed (%d)\n",
__func__, rc);
return rc;
}
quickvx_ldo_enabled = 0;
}
- if (machine_is_msm7x30_fluid()) {
- rc = vreg_enable(vreg_ldo8);
- if (rc) {
- pr_err("%s: LDO8 vreg enable failed (%d)\n",
- __func__, rc);
- return rc;
- }
- } else {
- rc = vreg_enable(vreg_ldo15);
- if (rc) {
- pr_err("%s: LDO15 vreg enable failed (%d)\n",
- __func__, rc);
- return rc;
- }
+ rc = regulator_enable(mddi_lcd);
+ if (rc) {
+ pr_err("%s: LCD regulator enable failed (%d)\n",
+ __func__, rc);
+ return rc;
}
mdelay(5); /* ensure power is stable */
@@ -4306,18 +4150,18 @@
}
} else {
- rc = vreg_disable(vreg_ldo20);
+ rc = regulator_disable(mddi_ldo20);
if (rc) {
- pr_err("%s: LDO20 vreg disable failed (%d)\n",
+ pr_err("%s: LDO20 regulator disable failed (%d)\n",
__func__, rc);
return rc;
}
if (other_mddi_client) {
- rc = vreg_disable(vreg_ldo16);
+ rc = regulator_disable(mddi_ldo16);
if (rc) {
- pr_err("%s: LDO16 vreg disable failed (%d)\n",
+ pr_err("%s: LDO16 regulator disable failed (%d)\n",
__func__, rc);
return rc;
}
@@ -4326,9 +4170,9 @@
if (quickvx_mddi_client && !quickvx_ldo_enabled) {
/* Enable LDO6 during display OFF for
Quicklogic chip to sleep with data retention */
- rc = vreg_enable(vreg_ldo6);
+ rc = regulator_enable(mddi_ldo6);
if (rc) {
- pr_err("%s: LDO6 vreg enable failed (%d)\n",
+ pr_err("%s: LDO6 regulator enable failed (%d)\n",
__func__, rc);
return rc;
}
@@ -4343,27 +4187,18 @@
PMIC_GPIO_QUICKVX_CLK), 0);
}
- if (machine_is_msm7x30_fluid()) {
- rc = vreg_disable(vreg_ldo8);
- if (rc) {
- pr_err("%s: LDO8 vreg disable failed (%d)\n",
- __func__, rc);
- return rc;
- }
- } else {
- rc = vreg_disable(vreg_ldo15);
- if (rc) {
- pr_err("%s: LDO15 vreg disable failed (%d)\n",
- __func__, rc);
- return rc;
- }
+ rc = regulator_disable(mddi_lcd);
+ if (rc) {
+ pr_err("%s: LCD regulator disable failed (%d)\n",
+ __func__, rc);
+ return rc;
}
mdelay(5); /* ensure power is stable */
- rc = vreg_disable(vreg_ldo12);
+ rc = regulator_disable(mddi_ldo12);
if (rc) {
- pr_err("%s: LDO12 vreg disable failed (%d)\n",
+ pr_err("%s: LDO12 regulator disable failed (%d)\n",
__func__, rc);
return rc;
}
@@ -4392,51 +4227,19 @@
static int msm_fb_mddi_client_power(u32 client_id)
{
- struct vreg *vreg_ldo20, *vreg_ldo16;
- int rc;
-
printk(KERN_NOTICE "\n client_id = 0x%x", client_id);
/* Check if it is Quicklogic client */
if (client_id == 0xc5835800) {
printk(KERN_NOTICE "\n Quicklogic MDDI client");
other_mddi_client = 0;
- vreg_ldo16 = vreg_get(NULL, "gp10");
-
- if (IS_ERR(vreg_ldo16)) {
- rc = PTR_ERR(vreg_ldo16);
- pr_err("%s: gp10 vreg get failed (%d)\n",
- __func__, rc);
- return rc;
- }
-
- rc = vreg_disable(vreg_ldo16);
- if (rc) {
- pr_err("%s: LDO16 vreg enable failed (%d)\n",
- __func__, rc);
- return rc;
- }
} else {
printk(KERN_NOTICE "\n Non-Quicklogic MDDI client");
quickvx_mddi_client = 0;
gpio_set_value(97, 0);
gpio_set_value_cansleep(PM8058_GPIO_PM_TO_SYS(
PMIC_GPIO_QUICKVX_CLK), 0);
-
- vreg_ldo20 = vreg_get(NULL, "gp13");
-
- if (IS_ERR(vreg_ldo20)) {
- rc = PTR_ERR(vreg_ldo20);
- pr_err("%s: gp13 vreg get failed (%d)\n",
- __func__, rc);
- return rc;
- }
- rc = vreg_set_level(vreg_ldo20, 1500);
- if (rc) {
- pr_err("%s: vreg LDO20 set level failed (%d)\n",
- __func__, rc);
- return rc;
- }
}
+
return 0;
}
@@ -4601,13 +4404,18 @@
static int lcdc_panel_power(int on)
{
int flag_on = !!on;
- static int lcdc_power_save_on;
+ static int lcdc_power_save_on, lcdc_power_initialized;
if (lcdc_power_save_on == flag_on)
return 0;
lcdc_power_save_on = flag_on;
- quickvx_mddi_client = 0;
+
+ if (unlikely(!lcdc_power_initialized)) {
+ quickvx_mddi_client = 0;
+ display_common_init();
+ lcdc_power_initialized = 1;
+ }
if (machine_is_msm7x30_fluid())
return lcdc_sharp_panel_power(on);
@@ -4619,47 +4427,64 @@
.lcdc_power_save = lcdc_panel_power,
};
+static struct regulator *atv_s4, *atv_ldo9;
+
+static int __init atv_dac_power_init(void)
+{
+ int rc;
+ struct regulator_bulk_data regs[] = {
+ { .supply = "smps4", .min_uV = 2200000, .max_uV = 2200000 },
+ { .supply = "ldo9", .min_uV = 2050000, .max_uV = 2050000 },
+ };
+
+ rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs), regs);
+
+ if (rc) {
+ pr_err("%s: could not get regulators: %d\n", __func__, rc);
+ goto bail;
+ }
+
+ rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs), regs);
+
+ if (rc) {
+ pr_err("%s: could not set voltages: %d\n", __func__, rc);
+ goto reg_free;
+ }
+
+ atv_s4 = regs[0].consumer;
+ atv_ldo9 = regs[1].consumer;
+
+reg_free:
+ regulator_bulk_free(ARRAY_SIZE(regs), regs);
+bail:
+ return rc;
+}
+
static int atv_dac_power(int on)
{
int rc = 0;
- struct vreg *vreg_s4, *vreg_ldo9;
-
- vreg_s4 = vreg_get(NULL, "s4");
- if (IS_ERR(vreg_s4)) {
- rc = PTR_ERR(vreg_s4);
- pr_err("%s: s4 vreg get failed (%d)\n",
- __func__, rc);
- return -1;
- }
- vreg_ldo9 = vreg_get(NULL, "gp1");
- if (IS_ERR(vreg_ldo9)) {
- rc = PTR_ERR(vreg_ldo9);
- pr_err("%s: ldo9 vreg get failed (%d)\n",
- __func__, rc);
- return rc;
- }
if (on) {
- rc = vreg_enable(vreg_s4);
+ rc = regulator_enable(atv_s4);
if (rc) {
pr_err("%s: s4 vreg enable failed (%d)\n",
__func__, rc);
return rc;
}
- rc = vreg_enable(vreg_ldo9);
+ rc = regulator_enable(atv_ldo9);
if (rc) {
pr_err("%s: ldo9 vreg enable failed (%d)\n",
__func__, rc);
return rc;
}
} else {
- rc = vreg_disable(vreg_ldo9);
+ rc = regulator_disable(atv_ldo9);
if (rc) {
pr_err("%s: ldo9 vreg disable failed (%d)\n",
__func__, rc);
return rc;
}
- rc = vreg_disable(vreg_s4);
+ rc = regulator_disable(atv_s4);
if (rc) {
pr_err("%s: s4 vreg disable failed (%d)\n",
__func__, rc);
@@ -4734,24 +4559,31 @@
"UART1DM_Tx" }
};
-static const char *vregs_bt_marimba_name[] = {
- "s3",
- "s2",
- "gp16",
- "wlan"
-};
-static struct vreg *vregs_bt_marimba[ARRAY_SIZE(vregs_bt_marimba_name)];
-
-static const char *vregs_bt_bahama_name[] = {
- "s3",
- "usb2",
- "s2",
- "wlan"
-};
-static struct vreg *vregs_bt_bahama[ARRAY_SIZE(vregs_bt_bahama_name)];
-
static u8 bahama_version;
+static struct regulator_bulk_data regs_bt_marimba[] = {
+ { .supply = "smps3", .min_uV = 1800000, .max_uV = 1800000 },
+ { .supply = "smps2", .min_uV = 1300000, .max_uV = 1300000 },
+ { .supply = "ldo24", .min_uV = 1200000, .max_uV = 1200000 },
+ { .supply = "ldo13", .min_uV = 2900000, .max_uV = 3050000 },
+};
+
+static struct regulator_bulk_data regs_bt_bahama_v1[] = {
+ { .supply = "smps3", .min_uV = 1800000, .max_uV = 1800000 },
+ { .supply = "ldo7", .min_uV = 1800000, .max_uV = 1800000 },
+ { .supply = "smps2", .min_uV = 1300000, .max_uV = 1300000 },
+ { .supply = "ldo13", .min_uV = 2900000, .max_uV = 3050000 },
+};
+
+static struct regulator_bulk_data regs_bt_bahama_v2[] = {
+ { .supply = "smps3", .min_uV = 1800000, .max_uV = 1800000 },
+ { .supply = "ldo7", .min_uV = 1800000, .max_uV = 1800000 },
+ { .supply = "ldo13", .min_uV = 2900000, .max_uV = 3050000 },
+};
+
+static struct regulator_bulk_data *regs_bt;
+static int regs_bt_count;
+
static int marimba_bt(int on)
{
int rc;
@@ -4973,15 +4805,6 @@
on = on ? 1 : 0;
- bahama_version = read_bahama_ver();
-
- if (((int)bahama_version) < 0 ||
- bahama_version == VER_UNSUPPORTED) {
- dev_err(&msm_bt_power_device.dev,
- "%s: i2c failure or unsupported version: %d\n",
- __func__, bahama_version);
- return -EIO;
- }
if (bahama_version == VER_2_0) {
if (marimba_get_fm_status(&config))
@@ -5017,69 +4840,62 @@
else
marimba_set_bt_status(&config, false);
- if (bahama_version == VER_2_0 && on) { /* variant of bahama v2 */
- /* Disable s2 as bahama v2 uses internal LDO regulator */
- for (i = 0; i < ARRAY_SIZE(vregs_bt_bahama_name); i++) {
- if (!strcmp(vregs_bt_bahama_name[i], "s2")) {
- rc = vreg_disable(vregs_bt_bahama[i]);
- if (rc < 0) {
- printk(KERN_ERR
- "%s: vreg %s disable "
- "failed (%d)\n",
- __func__,
- vregs_bt_bahama_name[i], rc);
- return -EIO;
- }
- rc = pmapp_vreg_level_vote("BTPW",
- PMAPP_VREG_S2,
- 0);
- if (rc < 0) {
- printk(KERN_ERR "%s: vreg "
- "level off failed (%d)\n",
- __func__, rc);
- return -EIO;
- }
- printk(KERN_INFO "%s: vreg disable & "
- "level off successful (%d)\n",
- __func__, rc);
- }
- }
- }
-
return 0;
}
-static int bluetooth_power_regulators(int on, int bahama_not_marimba)
+static int bluetooth_regs_init(int bahama_not_marimba)
{
- int i, rc;
- const char **vregs_name;
- struct vreg **vregs;
- int vregs_size;
+ int rc = 0;
+ struct device *const dev = &msm_bt_power_device.dev;
if (bahama_not_marimba) {
- vregs_name = vregs_bt_bahama_name;
- vregs = vregs_bt_bahama;
- vregs_size = ARRAY_SIZE(vregs_bt_bahama_name);
+ bahama_version = read_bahama_ver();
+
+ switch (bahama_version) {
+ case VER_1_0:
+ regs_bt = regs_bt_bahama_v1;
+ regs_bt_count = ARRAY_SIZE(regs_bt_bahama_v1);
+ break;
+ case VER_2_0:
+ regs_bt = regs_bt_bahama_v2;
+ regs_bt_count = ARRAY_SIZE(regs_bt_bahama_v2);
+ break;
+ case VER_UNSUPPORTED:
+ default:
+ dev_err(dev,
+ "%s: i2c failure or unsupported version: %d\n",
+ __func__, bahama_version);
+ rc = -EIO;
+ goto out;
+ }
} else {
- vregs_name = vregs_bt_marimba_name;
- vregs = vregs_bt_marimba;
- vregs_size = ARRAY_SIZE(vregs_bt_marimba_name);
+ regs_bt = regs_bt_marimba;
+ regs_bt_count = ARRAY_SIZE(regs_bt_marimba);
}
- for (i = 0; i < vregs_size; i++) {
- if (bahama_not_marimba && (bahama_version == VER_2_0) &&
- !on && !strcmp(vregs_bt_bahama_name[i], "s2"))
- continue;
- rc = on ? vreg_enable(vregs[i]) :
- vreg_disable(vregs[i]);
- if (rc < 0) {
- printk(KERN_ERR "%s: vreg %s %s failed (%d)\n",
- __func__, vregs_name[i],
- on ? "enable" : "disable", rc);
- return -EIO;
- }
+ rc = regulator_bulk_get(&msm_bt_power_device.dev,
+ regs_bt_count, regs_bt);
+ if (rc) {
+ dev_err(dev, "%s: could not get regulators: %d\n",
+ __func__, rc);
+ goto out;
}
+
+ rc = regulator_bulk_set_voltage(regs_bt_count, regs_bt);
+ if (rc) {
+ dev_err(dev, "%s: could not set voltages: %d\n",
+ __func__, rc);
+ goto reg_free;
+ }
+
return 0;
+
+reg_free:
+ regulator_bulk_free(regs_bt_count, regs_bt);
+out:
+ regs_bt_count = 0;
+ regs_bt = NULL;
+ return rc;
}
static int bluetooth_power(int on)
@@ -5095,17 +4911,16 @@
return -ENODEV;
}
- if (on) {
- rc = pmapp_vreg_level_vote(id, PMAPP_VREG_S2, 1300);
- if (rc < 0) {
- printk(KERN_ERR "%s: vreg level on failed (%d)\n",
- __func__, rc);
+ if (unlikely(regs_bt_count == 0)) {
+ rc = bluetooth_regs_init(bahama_not_marimba);
+ if (rc)
return rc;
- }
+ }
- rc = bluetooth_power_regulators(on, bahama_not_marimba);
- if (rc < 0)
- return -EIO;
+ if (on) {
+ rc = regulator_bulk_enable(regs_bt_count, regs_bt);
+ if (rc)
+ return rc;
rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_DO,
PMAPP_CLOCK_VOTE_ON);
@@ -5162,18 +4977,10 @@
if (rc < 0)
return -EIO;
- rc = bluetooth_power_regulators(on, bahama_not_marimba);
- if (rc < 0)
- return -EIO;
+ rc = regulator_bulk_disable(regs_bt_count, regs_bt);
+ if (rc)
+ return rc;
- if (bahama_version == VER_1_0) {
- rc = pmapp_vreg_level_vote(id, PMAPP_VREG_S2, 0);
- if (rc < 0) {
- printk(KERN_ERR "%s: vreg level off failed "
- "(%d)\n", __func__, rc);
- return -EIO;
- }
- }
}
out:
@@ -5184,29 +4991,7 @@
static void __init bt_power_init(void)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(vregs_bt_marimba_name); i++) {
- vregs_bt_marimba[i] = vreg_get(NULL, vregs_bt_marimba_name[i]);
- if (IS_ERR(vregs_bt_marimba[i])) {
- printk(KERN_ERR "%s: vreg get %s failed (%ld)\n",
- __func__, vregs_bt_marimba_name[i],
- PTR_ERR(vregs_bt_marimba[i]));
- return;
- }
- }
-
- for (i = 0; i < ARRAY_SIZE(vregs_bt_bahama_name); i++) {
- vregs_bt_bahama[i] = vreg_get(NULL, vregs_bt_bahama_name[i]);
- if (IS_ERR(vregs_bt_bahama[i])) {
- printk(KERN_ERR "%s: vreg get %s failed (%ld)\n",
- __func__, vregs_bt_bahama_name[i],
- PTR_ERR(vregs_bt_bahama[i]));
- return;
- }
- }
-
- msm_bt_power_device.dev.platform_data = &bluetooth_power;
+ msm_bt_power_device.dev.platform_data = &bluetooth_power;
}
#else
#define bt_power_init(x) do {} while (0)
@@ -5442,7 +5227,7 @@
}
/*This needs to be enabled only for OEMS*/
#ifndef CONFIG_QUP_EXCLUSIVE_TO_CAMERA
-static struct vreg *qup_vreg;
+static struct regulator *qup_vreg;
#endif
static void
qup_i2c_gpio_config(int adap_id, int config_type)
@@ -5461,15 +5246,10 @@
printk(KERN_ERR "QUP GPIO enable failed: %d\n", rc);
/*This needs to be enabled only for OEMS*/
#ifndef CONFIG_QUP_EXCLUSIVE_TO_CAMERA
- if (qup_vreg) {
- int rc = vreg_set_level(qup_vreg, 1800);
+ if (!IS_ERR_OR_NULL(qup_vreg)) {
+ rc = regulator_enable(qup_vreg);
if (rc) {
- pr_err("%s: vreg LVS1 set level failed (%d)\n",
- __func__, rc);
- }
- rc = vreg_enable(qup_vreg);
- if (rc) {
- pr_err("%s: vreg_enable() = %d \n",
+ pr_err("%s: regulator_enable failed: %d\n",
__func__, rc);
}
}
@@ -5518,9 +5298,10 @@
qup_device_i2c.dev.platform_data = &qup_i2c_pdata;
/*This needs to be enabled only for OEMS*/
#ifndef CONFIG_QUP_EXCLUSIVE_TO_CAMERA
- qup_vreg = vreg_get(NULL, "lvsw1");
+ qup_vreg = regulator_get(&qup_device_i2c.dev, "lvsw1");
if (IS_ERR(qup_vreg)) {
- printk(KERN_ERR "%s: vreg get failed (%ld)\n",
+ dev_err(&qup_device_i2c.dev,
+ "%s: regulator_get failed: %ld\n",
__func__, PTR_ERR(qup_vreg));
}
#endif
@@ -5543,9 +5324,6 @@
{GPIO_CFG(115, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "ebi2_busy1"},
};
-struct vreg *vreg_s3;
-struct vreg *vreg_mmc;
-
#if (defined(CONFIG_MMC_MSM_SDC1_SUPPORT)\
|| defined(CONFIG_MMC_MSM_SDC2_SUPPORT)\
|| defined(CONFIG_MMC_MSM_SDC3_SUPPORT)\
@@ -5642,12 +5420,7 @@
},
};
-struct sdcc_vreg {
- struct vreg *vreg_data;
- unsigned level;
-};
-
-static struct sdcc_vreg sdcc_vreg_data[4];
+static struct regulator *sdcc_vreg_data[ARRAY_SIZE(sdcc_cfg_data)];
static unsigned long vreg_sts, gpio_sts;
@@ -5683,37 +5456,36 @@
static uint32_t msm_sdcc_setup_vreg(int dev_id, unsigned int enable)
{
int rc = 0;
- struct sdcc_vreg *curr;
+ struct regulator *curr = sdcc_vreg_data[dev_id - 1];
static int enabled_once[] = {0, 0, 0, 0};
- curr = &sdcc_vreg_data[dev_id - 1];
-
- if (!(test_bit(dev_id, &vreg_sts)^enable))
+ if (test_bit(dev_id, &vreg_sts) == enable)
return rc;
if (!enable || enabled_once[dev_id - 1])
return 0;
+ if (!curr)
+ return -ENODEV;
+
+ if (IS_ERR(curr))
+ return PTR_ERR(curr);
+
if (enable) {
set_bit(dev_id, &vreg_sts);
- rc = vreg_set_level(curr->vreg_data, curr->level);
- if (rc) {
- printk(KERN_ERR "%s: vreg_set_level() = %d \n",
+
+ rc = regulator_enable(curr);
+ if (rc)
+ pr_err("%s: could not enable regulator: %d\n",
__func__, rc);
- }
- rc = vreg_enable(curr->vreg_data);
- if (rc) {
- printk(KERN_ERR "%s: vreg_enable() = %d \n",
- __func__, rc);
- }
enabled_once[dev_id - 1] = 1;
} else {
clear_bit(dev_id, &vreg_sts);
- rc = vreg_disable(curr->vreg_data);
- if (rc) {
- printk(KERN_ERR "%s: vreg_disable() = %d \n",
+
+ rc = regulator_disable(curr);
+ if (rc)
+ pr_err("%s: could not disable regulator: %d\n",
__func__, rc);
- }
}
return rc;
}
@@ -5784,109 +5556,76 @@
return rc;
}
-static int mbp_setup_rf_vregs(int state)
+static struct regulator_bulk_data mbp_regs_io[2];
+static struct regulator_bulk_data mbp_regs_rf[2];
+static struct regulator_bulk_data mbp_regs_adc[1];
+static struct regulator_bulk_data mbp_regs_core[1];
+
+static int mbp_init_regs(struct device *dev)
{
- struct vreg *vreg_rf = NULL;
- struct vreg *vreg_rf_switch = NULL;
+ struct regulator_bulk_data regs[] = {
+ /* Analog and I/O regs */
+ { .supply = "gp4", .min_uV = 2600000, .max_uV = 2600000 },
+ { .supply = "s3", .min_uV = 1800000, .max_uV = 1800000 },
+ /* RF regs */
+ { .supply = "s2", .min_uV = 1300000, .max_uV = 1300000 },
+ { .supply = "rf", .min_uV = 2600000, .max_uV = 2600000 },
+ /* ADC regs */
+ { .supply = "s4", .min_uV = 2200000, .max_uV = 2200000 },
+ /* Core regs */
+ { .supply = "gp16", .min_uV = 1200000, .max_uV = 1200000 },
+ };
+
+ struct regulator_bulk_data *regptr = regs;
int rc;
- vreg_rf = vreg_get(NULL, "s2");
- if (IS_ERR(vreg_rf)) {
- pr_err("%s: s2 vreg get failed (%ld)",
- __func__, PTR_ERR(vreg_rf));
- return -EFAULT;
- }
- vreg_rf_switch = vreg_get(NULL, "rf");
- if (IS_ERR(vreg_rf_switch)) {
- pr_err("%s: rf vreg get failed (%ld)",
- __func__, PTR_ERR(vreg_rf_switch));
- return -EFAULT;
+ rc = regulator_bulk_get(dev, ARRAY_SIZE(regs), regs);
+
+ if (rc) {
+ dev_err(dev, "%s: could not get regulators: %d\n",
+ __func__, rc);
+ goto out;
}
- if (state) {
- rc = vreg_set_level(vreg_rf, 1300);
- if (rc) {
- pr_err("%s: vreg s2 set level failed (%d)\n",
- __func__, rc);
- return rc;
- }
+ rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs), regs);
- rc = vreg_enable(vreg_rf);
- if (rc) {
- printk(KERN_ERR "%s: vreg_enable(s2) = %d\n",
- __func__, rc);
- }
-
- rc = vreg_set_level(vreg_rf_switch, 2600);
- if (rc) {
- pr_err("%s: vreg rf switch set level failed (%d)\n",
- __func__, rc);
- return rc;
- }
- rc = vreg_enable(vreg_rf_switch);
- if (rc) {
- printk(KERN_ERR "%s: vreg_enable(rf) = %d\n",
- __func__, rc);
- }
- } else {
- (void) vreg_disable(vreg_rf);
- (void) vreg_disable(vreg_rf_switch);
+ if (rc) {
+ dev_err(dev, "%s: could not set voltages: %d\n",
+ __func__, rc);
+ goto reg_free;
}
+
+ memcpy(mbp_regs_io, regptr, sizeof(mbp_regs_io));
+ regptr += ARRAY_SIZE(mbp_regs_io);
+
+ memcpy(mbp_regs_rf, regptr, sizeof(mbp_regs_rf));
+ regptr += ARRAY_SIZE(mbp_regs_rf);
+
+ memcpy(mbp_regs_adc, regptr, sizeof(mbp_regs_adc));
+ regptr += ARRAY_SIZE(mbp_regs_adc);
+
+ memcpy(mbp_regs_core, regptr, sizeof(mbp_regs_core));
+
return 0;
+
+reg_free:
+ regulator_bulk_free(ARRAY_SIZE(regs), regs);
+out:
+ return rc;
+}
+
+static int mbp_setup_rf_vregs(int state)
+{
+ return state ?
+ regulator_bulk_enable(ARRAY_SIZE(mbp_regs_rf), mbp_regs_rf) :
+ regulator_bulk_disable(ARRAY_SIZE(mbp_regs_rf), mbp_regs_rf);
}
static int mbp_setup_vregs(int state)
{
- struct vreg *vreg_analog = NULL;
- struct vreg *vreg_io = NULL;
- int rc;
-
- vreg_analog = vreg_get(NULL, "gp4");
- if (IS_ERR(vreg_analog)) {
- pr_err("%s: gp4 vreg get failed (%ld)",
- __func__, PTR_ERR(vreg_analog));
- return -EFAULT;
- }
- vreg_io = vreg_get(NULL, "s3");
- if (IS_ERR(vreg_io)) {
- pr_err("%s: s3 vreg get failed (%ld)",
- __func__, PTR_ERR(vreg_io));
- return -EFAULT;
- }
- if (state) {
- rc = vreg_set_level(vreg_analog, 2600);
- if (rc) {
- pr_err("%s: vreg_set_level failed (%d)",
- __func__, rc);
- }
- rc = vreg_enable(vreg_analog);
- if (rc) {
- pr_err("%s: analog vreg enable failed (%d)",
- __func__, rc);
- }
- rc = vreg_set_level(vreg_io, 1800);
- if (rc) {
- pr_err("%s: vreg_set_level failed (%d)",
- __func__, rc);
- }
- rc = vreg_enable(vreg_io);
- if (rc) {
- pr_err("%s: io vreg enable failed (%d)",
- __func__, rc);
- }
- } else {
- rc = vreg_disable(vreg_analog);
- if (rc) {
- pr_err("%s: analog vreg disable failed (%d)",
- __func__, rc);
- }
- rc = vreg_disable(vreg_io);
- if (rc) {
- pr_err("%s: io vreg disable failed (%d)",
- __func__, rc);
- }
- }
- return rc;
+ return state ?
+ regulator_bulk_enable(ARRAY_SIZE(mbp_regs_io), mbp_regs_io) :
+ regulator_bulk_disable(ARRAY_SIZE(mbp_regs_io), mbp_regs_io);
}
static int mbp_set_tcxo_en(int enable)
@@ -5902,16 +5641,6 @@
__func__, enable ? "" : "de-");
return -EIO;
}
- if (!enable) {
- vreg_analog = vreg_get(NULL, "gp4");
- if (IS_ERR(vreg_analog)) {
- pr_err("%s: gp4 vreg get failed (%ld)",
- __func__, PTR_ERR(vreg_analog));
- return -EFAULT;
- }
-
- (void) vreg_disable(vreg_analog);
- }
return rc;
}
@@ -5925,28 +5654,20 @@
static int mbp_set_core_voltage_en(int enable)
{
- int rc;
- struct vreg *vreg_core1p2 = NULL;
+ static bool is_enabled;
+ int rc = 0;
- vreg_core1p2 = vreg_get(NULL, "gp16");
- if (IS_ERR(vreg_core1p2)) {
- pr_err("%s: gp16 vreg get failed (%ld)",
- __func__, PTR_ERR(vreg_core1p2));
- return -EFAULT;
- }
- if (enable) {
- rc = vreg_set_level(vreg_core1p2, 1200);
+ if (enable && !is_enabled) {
+ rc = regulator_bulk_enable(ARRAY_SIZE(mbp_regs_core),
+ mbp_regs_core);
if (rc) {
- pr_err("%s: vreg_set_level failed (%d)",
+ pr_err("%s: could not enable regulators: %d\n",
__func__, rc);
+ } else {
+ is_enabled = true;
}
- (void) vreg_enable(vreg_core1p2);
-
- return 80;
- } else {
- gpio_set_value(85, 1);
- return 0;
}
+
return rc;
}
@@ -5977,34 +5698,9 @@
static int mbp_setup_adc_vregs(int state)
{
- struct vreg *vreg_adc = NULL;
- int rc;
-
- vreg_adc = vreg_get(NULL, "s4");
- if (IS_ERR(vreg_adc)) {
- pr_err("%s: s4 vreg get failed (%ld)",
- __func__, PTR_ERR(vreg_adc));
- return -EFAULT;
- }
- if (state) {
- rc = vreg_set_level(vreg_adc, 2200);
- if (rc) {
- pr_err("%s: vreg_set_level failed (%d)",
- __func__, rc);
- }
- rc = vreg_enable(vreg_adc);
- if (rc) {
- pr_err("%s: enable vreg adc failed (%d)",
- __func__, rc);
- }
- } else {
- rc = vreg_disable(vreg_adc);
- if (rc) {
- pr_err("%s: disable vreg adc failed (%d)",
- __func__, rc);
- }
- }
- return rc;
+ return state ?
+ regulator_bulk_enable(ARRAY_SIZE(mbp_regs_adc), mbp_regs_adc) :
+ regulator_bulk_disable(ARRAY_SIZE(mbp_regs_adc), mbp_regs_adc);
}
static int mbp_power_up(void)
@@ -6069,14 +5765,6 @@
static int mbp_power_down(void)
{
int rc;
- struct vreg *vreg_adc = NULL;
-
- vreg_adc = vreg_get(NULL, "s4");
- if (IS_ERR(vreg_adc)) {
- pr_err("%s: s4 vreg get failed (%ld)",
- __func__, PTR_ERR(vreg_adc));
- return -EFAULT;
- }
mbp_set_reset(MBP_ON);
pr_debug("%s: mbp_set_reset(MBP_ON) done\n", __func__);
@@ -6106,13 +5794,16 @@
goto exit;
pr_debug("%s: mbp_set_core_voltage_en(MBP_OFF) done\n", __func__);
- gpio_set_value(85, 1);
-
rc = mbp_set_tcxo_en(MBP_OFF);
if (rc)
goto exit;
pr_debug("%s: mbp_set_tcxo_en(MBP_OFF) done\n", __func__);
+ rc = mbp_setup_vregs(MBP_OFF);
+ if (rc)
+ goto exit;
+ pr_debug("%s: mbp_setup_vregs(MBP_OFF) done\n", __func__);
+
rc = mbp_config_gpios_pre_init(MBP_OFF);
if (rc)
goto exit;
@@ -6174,6 +5865,12 @@
goto out;
}
if (!mbp_power_init_done) {
+ rc = mbp_init_regs(dv);
+ if (rc) {
+ dev_err(dv, "%s: regulator init failed: %d\n",
+ __func__, rc);
+ goto out;
+ }
mbp_setup_power(dv, 1);
mbp_setup_power(dv, 0);
mbp_power_init_done = 1;
@@ -6312,18 +6009,32 @@
#endif
#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
-static void msm_sdc1_lvlshft_enable(void)
+static int msm_sdc1_lvlshft_enable(void)
{
+ static struct regulator *ldo5;
int rc;
/* Enable LDO5, an input to the FET that powers slot 1 */
- rc = vreg_set_level(vreg_mmc, 2850);
- if (rc)
- printk(KERN_ERR "%s: vreg_set_level() = %d \n", __func__, rc);
- rc = vreg_enable(vreg_mmc);
- if (rc)
- printk(KERN_ERR "%s: vreg_enable() = %d \n", __func__, rc);
+ ldo5 = regulator_get(NULL, "ldo5");
+
+ if (IS_ERR(ldo5)) {
+ rc = PTR_ERR(ldo5);
+ pr_err("%s: could not get ldo5: %d\n", __func__, rc);
+ goto out;
+ }
+
+ rc = regulator_set_voltage(ldo5, 2850000, 2850000);
+ if (rc) {
+ pr_err("%s: could not set ldo5 voltage: %d\n", __func__, rc);
+ goto ldo5_free;
+ }
+
+ rc = regulator_enable(ldo5);
+ if (rc) {
+ pr_err("%s: could not enable ldo5: %d\n", __func__, rc);
+ goto ldo5_free;
+ }
/* Enable GPIO 35, to turn on the FET that powers slot 1 */
rc = msm_gpios_request_enable(sdc1_lvlshft_cfg_data,
@@ -6335,35 +6046,72 @@
1);
if (rc)
printk(KERN_ERR "%s: Failed to turn on GPIO 35\n", __func__);
+
+ return 0;
+
+ldo5_free:
+ regulator_put(ldo5);
+out:
+ ldo5 = NULL;
+ return rc;
}
#endif
+static int mmc_regulator_init(int sdcc_no, const char *supply, int uV)
+{
+ int rc;
+
+ BUG_ON(sdcc_no < 1 || sdcc_no > 4);
+
+ sdcc_no--;
+
+ sdcc_vreg_data[sdcc_no] = regulator_get(NULL, supply);
+
+ if (IS_ERR(sdcc_vreg_data[sdcc_no])) {
+ rc = PTR_ERR(sdcc_vreg_data[sdcc_no]);
+ pr_err("%s: could not get regulator \"%s\": %d\n",
+ __func__, supply, rc);
+ goto out;
+ }
+
+ rc = regulator_set_voltage(sdcc_vreg_data[sdcc_no], uV, uV);
+
+ if (rc) {
+ pr_err("%s: could not set voltage for \"%s\" to %d uV: %d\n",
+ __func__, supply, uV, rc);
+ goto reg_free;
+ }
+
+ return rc;
+
+reg_free:
+ regulator_put(sdcc_vreg_data[sdcc_no]);
+out:
+ sdcc_vreg_data[sdcc_no] = NULL;
+ return rc;
+}
+
static void __init msm7x30_init_mmc(void)
{
- vreg_s3 = vreg_get(NULL, "s3");
- if (IS_ERR(vreg_s3)) {
- printk(KERN_ERR "%s: vreg get failed (%ld)\n",
- __func__, PTR_ERR(vreg_s3));
- return;
- }
-
- vreg_mmc = vreg_get(NULL, "mmc");
- if (IS_ERR(vreg_mmc)) {
- printk(KERN_ERR "%s: vreg get failed (%ld)\n",
- __func__, PTR_ERR(vreg_mmc));
- return;
- }
-
#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+ if (mmc_regulator_init(1, "s3", 1800000))
+ goto out1;
+
if (machine_is_msm7x30_fluid()) {
msm7x30_sdc1_data.ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29;
- msm_sdc1_lvlshft_enable();
+ if (msm_sdc1_lvlshft_enable()) {
+ pr_err("%s: could not enable level shift\n");
+ goto out1;
+ }
}
- sdcc_vreg_data[0].vreg_data = vreg_s3;
- sdcc_vreg_data[0].level = 1800;
+
msm_add_sdcc(1, &msm7x30_sdc1_data);
+out1:
#endif
#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+ if (mmc_regulator_init(2, "s3", 1800000))
+ goto out2;
+
if (machine_is_msm8x55_svlte_surf())
msm7x30_sdc2_data.msmsdcc_fmax = 24576000;
if (machine_is_msm8x55_svlte_surf() ||
@@ -6371,19 +6119,22 @@
msm7x30_sdc2_data.sdiowakeup_irq = MSM_GPIO_TO_INT(68);
msm7x30_sdc2_data.is_sdio_al_client = 1;
}
- sdcc_vreg_data[1].vreg_data = vreg_s3;
- sdcc_vreg_data[1].level = 1800;
+
msm_add_sdcc(2, &msm7x30_sdc2_data);
+out2:
#endif
#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
- sdcc_vreg_data[2].vreg_data = vreg_s3;
- sdcc_vreg_data[2].level = 1800;
+ if (mmc_regulator_init(3, "s3", 1800000))
+ goto out3;
+
msm_sdcc_setup_gpio(3, 1);
msm_add_sdcc(3, &msm7x30_sdc3_data);
+out3:
#endif
#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
- sdcc_vreg_data[3].vreg_data = vreg_mmc;
- sdcc_vreg_data[3].level = 2850;
+ if (mmc_regulator_init(4, "mmc", 2850000))
+ return;
+
msm_add_sdcc(4, &msm7x30_sdc4_data);
#endif
@@ -6452,16 +6203,12 @@
static void __init pmic8058_leds_init(void)
{
- if (machine_is_msm7x30_surf()) {
- pm8058_7x30_data.sub_devices[PM8058_SUBDEV_LED].platform_data
- = &pm8058_surf_leds_data;
- } else if (!machine_is_msm7x30_fluid()) {
- pm8058_7x30_data.sub_devices[PM8058_SUBDEV_LED].platform_data
- = &pm8058_ffa_leds_data;
- } else if (machine_is_msm7x30_fluid()) {
- pm8058_7x30_data.sub_devices[PM8058_SUBDEV_LED].platform_data
- = &pm8058_fluid_leds_data;
- }
+ if (machine_is_msm7x30_surf())
+ pm8058_7x30_data.leds_pdata = &pm8058_surf_leds_data;
+ else if (!machine_is_msm7x30_fluid())
+ pm8058_7x30_data.leds_pdata = &pm8058_ffa_leds_data;
+ else if (machine_is_msm7x30_fluid())
+ pm8058_7x30_data.leds_pdata = &pm8058_fluid_leds_data;
}
static struct msm_spm_platform_data msm_spm_data __initdata = {
@@ -6499,68 +6246,50 @@
"tsc2007_irq" },
};
-static struct vreg *vreg_tsc_s3;
-static struct vreg *vreg_tsc_s2;
+static struct regulator_bulk_data tsc2007_regs[] = {
+ { .supply = "s3", .min_uV = 1800000, .max_uV = 1800000 },
+ { .supply = "s2", .min_uV = 1300000, .max_uV = 1300000 },
+};
static int tsc2007_init(void)
{
int rc;
- vreg_tsc_s3 = vreg_get(NULL, "s3");
- if (IS_ERR(vreg_tsc_s3)) {
- printk(KERN_ERR "%s: vreg get failed (%ld)\n",
- __func__, PTR_ERR(vreg_tsc_s3));
- return -ENODEV;
- }
+ rc = regulator_bulk_get(NULL, ARRAY_SIZE(tsc2007_regs), tsc2007_regs);
- rc = vreg_set_level(vreg_tsc_s3, 1800);
if (rc) {
- pr_err("%s: vreg_set_level failed \n", __func__);
- goto fail_vreg_set_level;
+ pr_err("%s: could not get regulators: %d\n", __func__, rc);
+ goto out;
}
- rc = vreg_enable(vreg_tsc_s3);
+ rc = regulator_bulk_set_voltage(ARRAY_SIZE(tsc2007_regs), tsc2007_regs);
+
if (rc) {
- pr_err("%s: vreg_enable failed \n", __func__);
- goto fail_vreg_set_level;
+ pr_err("%s: could not set voltages: %d\n", __func__, rc);
+ goto reg_free;
}
- vreg_tsc_s2 = vreg_get(NULL, "s2");
- if (IS_ERR(vreg_tsc_s2)) {
- printk(KERN_ERR "%s: vreg get failed (%ld)\n",
- __func__, PTR_ERR(vreg_tsc_s2));
- goto fail_vreg_get;
- }
+ rc = regulator_bulk_enable(ARRAY_SIZE(tsc2007_regs), tsc2007_regs);
- rc = vreg_set_level(vreg_tsc_s2, 1300);
if (rc) {
- pr_err("%s: vreg_set_level failed \n", __func__);
- goto fail_vreg_s2_level;
- }
-
- rc = vreg_enable(vreg_tsc_s2);
- if (rc) {
- pr_err("%s: vreg_enable failed \n", __func__);
- goto fail_vreg_s2_level;
+ pr_err("%s: could not enable regulators: %d\n", __func__, rc);
+ goto reg_free;
}
rc = msm_gpios_request_enable(tsc2007_config_data,
ARRAY_SIZE(tsc2007_config_data));
if (rc) {
pr_err("%s: Unable to request gpios\n", __func__);
- goto fail_gpio_req;
+ goto reg_disable;
}
return 0;
-fail_gpio_req:
- vreg_disable(vreg_tsc_s2);
-fail_vreg_s2_level:
- vreg_put(vreg_tsc_s2);
-fail_vreg_get:
- vreg_disable(vreg_tsc_s3);
-fail_vreg_set_level:
- vreg_put(vreg_tsc_s3);
+reg_disable:
+ regulator_bulk_disable(ARRAY_SIZE(tsc2007_regs), tsc2007_regs);
+reg_free:
+ regulator_bulk_free(ARRAY_SIZE(tsc2007_regs), tsc2007_regs);
+out:
return rc;
}
@@ -6580,10 +6309,9 @@
static void tsc2007_exit(void)
{
- vreg_disable(vreg_tsc_s3);
- vreg_put(vreg_tsc_s3);
- vreg_disable(vreg_tsc_s2);
- vreg_put(vreg_tsc_s2);
+
+ regulator_bulk_disable(ARRAY_SIZE(tsc2007_regs), tsc2007_regs);
+ regulator_bulk_free(ARRAY_SIZE(tsc2007_regs), tsc2007_regs);
msm_gpios_disable_free(tsc2007_config_data,
ARRAY_SIZE(tsc2007_config_data));
@@ -6593,35 +6321,20 @@
{
int rc;
- if (enable == false) {
- rc = vreg_enable(vreg_tsc_s2);
- if (rc) {
- pr_err("%s: vreg_enable failed\n", __func__);
- return rc;
- }
- rc = vreg_enable(vreg_tsc_s3);
- if (rc) {
- pr_err("%s: vreg_enable failed\n", __func__);
- vreg_disable(vreg_tsc_s2);
- return rc;
- }
- /* Voltage settling delay */
- msleep(20);
- } else {
- rc = vreg_disable(vreg_tsc_s2);
- if (rc) {
- pr_err("%s: vreg_disable failed\n", __func__);
- return rc;
- }
- rc = vreg_disable(vreg_tsc_s3);
- if (rc) {
- pr_err("%s: vreg_disable failed\n", __func__);
- vreg_enable(vreg_tsc_s2);
- return rc;
- }
+ rc = (enable == false) ?
+ regulator_bulk_enable(ARRAY_SIZE(tsc2007_regs), tsc2007_regs) :
+ regulator_bulk_disable(ARRAY_SIZE(tsc2007_regs), tsc2007_regs);
+
+ if (rc) {
+ pr_err("%s: could not %sable regulators: %d\n",
+ __func__, enable ? "dis" : "en", rc);
+ return rc;
}
- return rc;
+ if (enable == false)
+ msleep(20);
+
+ return 0;
}
static struct tsc2007_platform_data tsc2007_ts_data = {
@@ -6648,36 +6361,23 @@
};
#endif
-static const char *vregs_isa1200_name[] = {
- "gp7",
- "gp10",
+static struct regulator_bulk_data regs_isa1200[] = {
+ { .supply = "gp7", .min_uV = 1800000, .max_uV = 1800000 },
+ { .supply = "gp10", .min_uV = 2600000, .max_uV = 2600000 },
};
-static const int vregs_isa1200_val[] = {
- 1800,
- 2600,
-};
-static struct vreg *vregs_isa1200[ARRAY_SIZE(vregs_isa1200_name)];
-
static int isa1200_power(int vreg_on)
{
- int i, rc = 0;
+ int rc = 0;
- for (i = 0; i < ARRAY_SIZE(vregs_isa1200_name); i++) {
- if (!vregs_isa1200[i]) {
- pr_err("%s: vreg_get %s failed (%d)\n",
- __func__, vregs_isa1200_name[i], rc);
- goto vreg_fail;
- }
+ rc = vreg_on ?
+ regulator_bulk_enable(ARRAY_SIZE(regs_isa1200), regs_isa1200) :
+ regulator_bulk_disable(ARRAY_SIZE(regs_isa1200), regs_isa1200);
- rc = vreg_on ? vreg_enable(vregs_isa1200[i]) :
- vreg_disable(vregs_isa1200[i]);
- if (rc < 0) {
- pr_err("%s: vreg %s %s failed (%d)\n",
- __func__, vregs_isa1200_name[i],
- vreg_on ? "enable" : "disable", rc);
- goto vreg_fail;
- }
+ if (rc) {
+ pr_err("%s: could not %sable regulators: %d\n",
+ __func__, vreg_on ? "en" : "dis", rc);
+ goto out;
}
/* vote for DO buffer */
@@ -6692,33 +6392,34 @@
return 0;
vreg_fail:
- while (i)
- vreg_disable(vregs_isa1200[--i]);
+ if (vreg_on)
+ regulator_bulk_disable(ARRAY_SIZE(regs_isa1200), regs_isa1200);
+ else
+ regulator_bulk_enable(ARRAY_SIZE(regs_isa1200), regs_isa1200);
+out:
return rc;
}
static int isa1200_dev_setup(bool enable)
{
- int i, rc;
+ int rc;
if (enable == true) {
- for (i = 0; i < ARRAY_SIZE(vregs_isa1200_name); i++) {
- vregs_isa1200[i] = vreg_get(NULL,
- vregs_isa1200_name[i]);
- if (IS_ERR(vregs_isa1200[i])) {
- pr_err("%s: vreg get %s failed (%ld)\n",
- __func__, vregs_isa1200_name[i],
- PTR_ERR(vregs_isa1200[i]));
- rc = PTR_ERR(vregs_isa1200[i]);
- goto vreg_get_fail;
- }
- rc = vreg_set_level(vregs_isa1200[i],
- vregs_isa1200_val[i]);
- if (rc) {
- pr_err("%s: vreg_set_level() = %d\n",
+ rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs_isa1200),
+ regs_isa1200);
+
+ if (rc) {
+ pr_err("%s: could not get regulators: %d\n",
__func__, rc);
- goto vreg_get_fail;
- }
+ goto out;
+ }
+
+ rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs_isa1200),
+ regs_isa1200);
+ if (rc) {
+ pr_err("%s: could not set voltages: %d\n",
+ __func__, rc);
+ goto reg_free;
}
rc = gpio_tlmm_config(GPIO_CFG(HAP_LVL_SHFT_MSM_GPIO, 0,
@@ -6727,28 +6428,27 @@
if (rc) {
pr_err("%s: Could not configure gpio %d\n",
__func__, HAP_LVL_SHFT_MSM_GPIO);
- goto vreg_get_fail;
+ goto reg_free;
}
rc = gpio_request(HAP_LVL_SHFT_MSM_GPIO, "haptics_shft_lvl_oe");
if (rc) {
pr_err("%s: unable to request gpio %d (%d)\n",
__func__, HAP_LVL_SHFT_MSM_GPIO, rc);
- goto vreg_get_fail;
+ goto reg_free;
}
gpio_set_value(HAP_LVL_SHFT_MSM_GPIO, 1);
} else {
- for (i = 0; i < ARRAY_SIZE(vregs_isa1200_name); i++)
- vreg_put(vregs_isa1200[i]);
-
+ regulator_bulk_free(ARRAY_SIZE(regs_isa1200), regs_isa1200);
gpio_free(HAP_LVL_SHFT_MSM_GPIO);
}
return 0;
-vreg_get_fail:
- while (i)
- vreg_put(vregs_isa1200[--i]);
+
+reg_free:
+ regulator_bulk_free(ARRAY_SIZE(regs_isa1200), regs_isa1200);
+out:
return rc;
}
static struct isa1200_platform_data isa1200_1_pdata = {
@@ -6780,8 +6480,14 @@
static int kp_flip_mpp_config(void)
{
- return pm8058_mpp_config_digital_in(PM_FLIP_MPP,
- PM8058_MPP_DIG_LEVEL_S3, PM_MPP_DIN_TO_INT);
+ struct pm8xxx_mpp_config_data kp_flip_mpp = {
+ .type = PM8XXX_MPP_TYPE_D_INPUT,
+ .level = PM8018_MPP_DIG_LEVEL_S3,
+ .control = PM8XXX_MPP_DIN_TO_INT,
+ };
+
+ return pm8xxx_mpp_config(PM8058_MPP_PM_TO_SYS(PM_FLIP_MPP),
+ &kp_flip_mpp);
}
static struct flip_switch_pdata flip_switch_data = {
@@ -6802,69 +6508,48 @@
}
};
-static const char *vregs_tma300_name[] = {
- "gp6",
- "gp7",
+static struct regulator_bulk_data regs_tma300[] = {
+ { .supply = "gp6", .min_uV = 3050000, .max_uV = 3100000 },
+ { .supply = "gp7", .min_uV = 1800000, .max_uV = 1800000 },
};
-static const int vregs_tma300_val[] = {
- 3050,
- 1800,
-};
-static struct vreg *vregs_tma300[ARRAY_SIZE(vregs_tma300_name)];
-
static int tma300_power(int vreg_on)
{
- int i, rc = -EINVAL;
+ int rc;
- for (i = 0; i < ARRAY_SIZE(vregs_tma300_name); i++) {
- /* Never disable gp6 for fluid as lcd has a problem with it */
- if (!i && !vreg_on)
- continue;
- if (!vregs_tma300[i]) {
- printk(KERN_ERR "%s: vreg_get %s failed (%d)\n",
- __func__, vregs_tma300_name[i], rc);
- return rc;
- }
+ rc = vreg_on ?
+ regulator_bulk_enable(ARRAY_SIZE(regs_tma300), regs_tma300) :
+ regulator_bulk_disable(ARRAY_SIZE(regs_tma300), regs_tma300);
- rc = vreg_on ? vreg_enable(vregs_tma300[i]) :
- vreg_disable(vregs_tma300[i]);
- if (rc < 0) {
- printk(KERN_ERR "%s: vreg %s %s failed (%d)\n",
- __func__, vregs_tma300_name[i],
- vreg_on ? "enable" : "disable", rc);
- return rc;
- }
- }
-
- return 0;
+ if (rc)
+ pr_err("%s: could not %sable regulators: %d\n",
+ __func__, vreg_on ? "en" : "dis", rc);
+ return rc;
}
#define TS_GPIO_IRQ 150
static int tma300_dev_setup(bool enable)
{
- int i, rc;
+ int rc;
if (enable) {
- /* get voltage sources */
- for (i = 0; i < ARRAY_SIZE(vregs_tma300_name); i++) {
- vregs_tma300[i] = vreg_get(NULL, vregs_tma300_name[i]);
- if (IS_ERR(vregs_tma300[i])) {
- pr_err("%s: vreg get %s failed (%ld)\n",
- __func__, vregs_tma300_name[i],
- PTR_ERR(vregs_tma300[i]));
- rc = PTR_ERR(vregs_tma300[i]);
- goto vreg_get_fail;
- }
- rc = vreg_set_level(vregs_tma300[i],
- vregs_tma300_val[i]);
- if (rc) {
- pr_err("%s: vreg_set_level() = %d\n",
+ rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs_tma300),
+ regs_tma300);
+
+ if (rc) {
+ pr_err("%s: could not get regulators: %d\n",
__func__, rc);
- i++;
- goto vreg_get_fail;
- }
+ goto out;
+ }
+
+ rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs_tma300),
+ regs_tma300);
+
+ if (rc) {
+ pr_err("%s: could not set voltages: %d\n",
+ __func__, rc);
+ goto reg_free;
}
/* enable interrupt gpio */
@@ -6873,7 +6558,7 @@
if (rc) {
pr_err("%s: Could not configure gpio %d\n",
__func__, TS_GPIO_IRQ);
- goto vreg_get_fail;
+ goto reg_free;
}
/* virtual keys */
@@ -6881,23 +6566,20 @@
properties_kobj = kobject_create_and_add("board_properties",
NULL);
if (!properties_kobj) {
- pr_err("%s: failed to create a kobject"
- "for board_properites\n", __func__);
+ pr_err("%s: failed to create a kobject "
+ "for board_properties\n", __func__);
rc = -ENOMEM;
- goto vreg_get_fail;
+ goto reg_free;
}
rc = sysfs_create_group(properties_kobj,
&tma300_properties_attr_group);
if (rc) {
pr_err("%s: failed to create a sysfs entry %s\n",
__func__, tma300_vkeys_attr.attr.name);
- kobject_put(properties_kobj);
- goto vreg_get_fail;
+ goto kobj_free;
}
} else {
- /* put voltage sources */
- for (i = 0; i < ARRAY_SIZE(vregs_tma300_name); i++)
- vreg_put(vregs_tma300[i]);
+ regulator_bulk_free(ARRAY_SIZE(regs_tma300), regs_tma300);
/* destroy virtual keys */
if (properties_kobj) {
sysfs_remove_group(properties_kobj,
@@ -6907,9 +6589,12 @@
}
return 0;
-vreg_get_fail:
- while (i)
- vreg_put(vregs_tma300[--i]);
+kobj_free:
+ kobject_put(properties_kobj);
+ properties_kobj = NULL;
+reg_free:
+ regulator_bulk_free(ARRAY_SIZE(regs_tma300), regs_tma300);
+out:
return rc;
}
@@ -6992,6 +6677,10 @@
msm_adc_pdata.num_adc = ARRAY_SIZE(msm_adc_surf_device_names);
}
+ pmic8058_leds_init();
+
+ buses_init();
+
#ifdef CONFIG_MSM_SSBI
msm_device_ssbi_pmic1.dev.platform_data =
&msm7x30_ssbi_pm8058_pdata;
@@ -7016,6 +6705,9 @@
ARRAY_SIZE(lcdc_toshiba_spi_board_info));
#endif
+ atv_dac_power_init();
+ sensors_ldo_init();
+ hdmi_init_regs();
msm_fb_add_devices();
msm_pm_set_platform_data(msm_pm_data, ARRAY_SIZE(msm_pm_data));
BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_RESET_VECTOR,
@@ -7023,10 +6715,10 @@
msm_device_i2c_init();
msm_device_i2c_2_init();
qup_device_i2c_init();
- buses_init();
msm7x30_init_marimba();
#ifdef CONFIG_MSM7KV2_AUDIO
snddev_poweramp_gpio_init();
+ snddev_hsed_voltage_init();
aux_pcm_gpio_init();
#endif
@@ -7071,7 +6763,8 @@
if (machine_is_msm7x30_surf())
platform_device_register(&flip_switch_device);
- pmic8058_leds_init();
+
+ pm8058_gpios_init();
if (machine_is_msm7x30_fluid()) {
/* Initialize platform data for fluid v2 hardware */
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
deleted file mode 100644
index ab45aca..0000000
--- a/arch/arm/mach-msm/board-msm8960.c
+++ /dev/null
@@ -1,4949 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/i2c.h>
-#include <linux/i2c/sx150x.h>
-#include <linux/i2c/isl9519.h>
-#include <linux/gpio.h>
-#include <linux/msm_ssbi.h>
-#include <linux/regulator/gpio-regulator.h>
-#include <linux/mfd/pm8xxx/pm8921.h>
-#include <linux/mfd/pm8xxx/pm8921-adc.h>
-#include <linux/regulator/consumer.h>
-#include <linux/spi/spi.h>
-#include <linux/slimbus/slimbus.h>
-#include <linux/bootmem.h>
-#include <linux/msm_kgsl.h>
-#ifdef CONFIG_ANDROID_PMEM
-#include <linux/android_pmem.h>
-#endif
-#include <linux/cyttsp.h>
-#include <linux/dma-mapping.h>
-#include <linux/platform_data/qcom_crypto_device.h>
-#include <linux/platform_data/qcom_wcnss_device.h>
-#include <linux/leds.h>
-#include <linux/leds-pm8xxx.h>
-#include <linux/i2c/atmel_mxt_ts.h>
-#include <linux/msm_tsens.h>
-#include <linux/ks8851.h>
-#include <linux/i2c/isa1200.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/setup.h>
-#include <asm/hardware/gic.h>
-#include <asm/mach/mmc.h>
-
-#include <mach/board.h>
-#include <mach/msm_iomap.h>
-#include <mach/msm_spi.h>
-#ifdef CONFIG_USB_MSM_OTG_72K
-#include <mach/msm_hsusb.h>
-#else
-#include <linux/usb/msm_hsusb.h>
-#endif
-#include <linux/usb/android.h>
-#include <mach/usbdiag.h>
-#include <mach/socinfo.h>
-#include <mach/rpm.h>
-#include <mach/gpio.h>
-#include <mach/gpiomux.h>
-#include <mach/msm_bus_board.h>
-#include <mach/msm_memtypes.h>
-#include <mach/dma.h>
-#include <mach/msm_dsps.h>
-#include <mach/msm_xo.h>
-#include <mach/restart.h>
-
-#ifdef CONFIG_WCD9310_CODEC
-#include <linux/slimbus/slimbus.h>
-#include <linux/mfd/wcd9310/core.h>
-#include <linux/mfd/wcd9310/pdata.h>
-#endif
-
-#include <linux/ion.h>
-#include <mach/ion.h>
-
-#include "timer.h"
-#include "devices.h"
-#include "devices-msm8x60.h"
-#include "spm.h"
-#include "board-msm8960.h"
-#include "pm.h"
-#include "cpuidle.h"
-#include "rpm_resources.h"
-#include "mpm.h"
-#include "acpuclock.h"
-#include "rpm_log.h"
-#include "smd_private.h"
-#include "pm-boot.h"
-#include "msm_watchdog.h"
-
-static struct platform_device msm_fm_platform_init = {
- .name = "iris_fm",
- .id = -1,
-};
-
-struct pm8xxx_gpio_init {
- unsigned gpio;
- struct pm_gpio config;
-};
-
-struct pm8xxx_mpp_init {
- unsigned mpp;
- struct pm8xxx_mpp_config_data config;
-};
-
-#define PM8XXX_GPIO_INIT(_gpio, _dir, _buf, _val, _pull, _vin, _out_strength, \
- _func, _inv, _disable) \
-{ \
- .gpio = PM8921_GPIO_PM_TO_SYS(_gpio), \
- .config = { \
- .direction = _dir, \
- .output_buffer = _buf, \
- .output_value = _val, \
- .pull = _pull, \
- .vin_sel = _vin, \
- .out_strength = _out_strength, \
- .function = _func, \
- .inv_int_pol = _inv, \
- .disable_pin = _disable, \
- } \
-}
-
-#define PM8XXX_MPP_INIT(_mpp, _type, _level, _control) \
-{ \
- .mpp = PM8921_MPP_PM_TO_SYS(_mpp), \
- .config = { \
- .type = PM8XXX_MPP_TYPE_##_type, \
- .level = _level, \
- .control = PM8XXX_MPP_##_control, \
- } \
-}
-
-#define PM8XXX_GPIO_DISABLE(_gpio) \
- PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, 0, 0, 0, PM_GPIO_VIN_S4, \
- 0, 0, 0, 1)
-
-#define PM8XXX_GPIO_OUTPUT(_gpio, _val) \
- PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
- PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \
- PM_GPIO_STRENGTH_HIGH, \
- PM_GPIO_FUNC_NORMAL, 0, 0)
-
-#define PM8XXX_GPIO_INPUT(_gpio, _pull) \
- PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, PM_GPIO_OUT_BUF_CMOS, 0, \
- _pull, PM_GPIO_VIN_S4, \
- PM_GPIO_STRENGTH_NO, \
- PM_GPIO_FUNC_NORMAL, 0, 0)
-
-#define PM8XXX_GPIO_OUTPUT_FUNC(_gpio, _val, _func) \
- PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
- PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \
- PM_GPIO_STRENGTH_HIGH, \
- _func, 0, 0)
-
-#define PM8XXX_GPIO_OUTPUT_VIN(_gpio, _val, _vin) \
- PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
- PM_GPIO_PULL_NO, _vin, \
- PM_GPIO_STRENGTH_HIGH, \
- PM_GPIO_FUNC_NORMAL, 0, 0)
-
-/* Initial PM8921 GPIO configurations */
-static struct pm8xxx_gpio_init pm8921_gpios[] __initdata = {
- PM8XXX_GPIO_DISABLE(6), /* Disable unused */
- PM8XXX_GPIO_DISABLE(7), /* Disable NFC */
- PM8XXX_GPIO_INPUT(16, PM_GPIO_PULL_UP_30), /* SD_CARD_WP */
- /* External regulator shared by display and touchscreen on LiQUID */
- PM8XXX_GPIO_OUTPUT(17, 0), /* DISP 3.3 V Boost */
- PM8XXX_GPIO_OUTPUT_VIN(21, 1, PM_GPIO_VIN_VPH), /* Backlight Enable */
- PM8XXX_GPIO_DISABLE(22), /* Disable NFC */
- PM8XXX_GPIO_OUTPUT_FUNC(24, 0, PM_GPIO_FUNC_2), /* Bl: Off, PWM mode */
- PM8XXX_GPIO_INPUT(26, PM_GPIO_PULL_UP_30), /* SD_CARD_DET_N */
- PM8XXX_GPIO_OUTPUT(43, PM_GPIO_PULL_UP_30), /* DISP_RESET_N */
- PM8XXX_GPIO_OUTPUT(42, 0), /* USB 5V reg enable */
-};
-
-/* Initial PM8921 MPP configurations */
-static struct pm8xxx_mpp_init pm8921_mpps[] __initdata = {
- /* External 5V regulator enable; shared by HDMI and USB_OTG switches. */
- PM8XXX_MPP_INIT(7, D_INPUT, PM8921_MPP_DIG_LEVEL_VPH, DIN_TO_INT),
- PM8XXX_MPP_INIT(PM8921_AMUX_MPP_8, A_INPUT, PM8XXX_MPP_AIN_AMUX_CH8,
- DOUT_CTRL_LOW),
-};
-
-static void __init pm8921_gpio_mpp_init(void)
-{
- int i, rc;
-
- for (i = 0; i < ARRAY_SIZE(pm8921_gpios); i++) {
- rc = pm8xxx_gpio_config(pm8921_gpios[i].gpio,
- &pm8921_gpios[i].config);
- if (rc) {
- pr_err("%s: pm8xxx_gpio_config: rc=%d\n", __func__, rc);
- break;
- }
- }
-
- for (i = 0; i < ARRAY_SIZE(pm8921_mpps); i++) {
- rc = pm8xxx_mpp_config(pm8921_mpps[i].mpp,
- &pm8921_mpps[i].config);
- if (rc) {
- pr_err("%s: pm8xxx_mpp_config: rc=%d\n", __func__, rc);
- break;
- }
- }
-}
-
-#define KS8851_RST_GPIO 89
-#define KS8851_IRQ_GPIO 90
-
-#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
-enum {
- GPIO_EXPANDER_IRQ_BASE = (PM8921_IRQ_BASE + PM8921_NR_IRQS),
- GPIO_EXPANDER_GPIO_BASE = (PM8921_MPP_BASE + PM8921_NR_MPPS),
- /* CAM Expander */
- GPIO_CAM_EXPANDER_BASE = GPIO_EXPANDER_GPIO_BASE,
- GPIO_CAM_GP_STROBE_READY = GPIO_CAM_EXPANDER_BASE,
- GPIO_CAM_GP_AFBUSY,
- GPIO_CAM_GP_STROBE_CE,
- GPIO_CAM_GP_CAM1MP_XCLR,
- GPIO_CAM_GP_CAMIF_RESET_N,
- GPIO_CAM_GP_XMT_FLASH_INT,
- GPIO_CAM_GP_LED_EN1,
- GPIO_CAM_GP_LED_EN2,
-
-};
-#endif
-
-/* The SPI configurations apply to GSBI 1*/
-static struct gpiomux_setting spi_active = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_12MA,
- .pull = GPIOMUX_PULL_NONE,
-};
-
-static struct gpiomux_setting spi_suspended_config = {
- .func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_DOWN,
-};
-
-static struct gpiomux_setting spi_active_config2 = {
- .func = GPIOMUX_FUNC_2,
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_NONE,
-};
-
-static struct gpiomux_setting spi_suspended_config2 = {
- .func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_UP,
-};
-
-static struct gpiomux_setting gsbi3_suspended_cfg = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_KEEPER,
-};
-
-static struct gpiomux_setting gsbi3_active_cfg = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_NONE,
-};
-
-static struct gpiomux_setting gsbi5 = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_NONE,
-};
-
-static struct gpiomux_setting gsbi10 = {
- .func = GPIOMUX_FUNC_2,
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_NONE,
-};
-
-static struct gpiomux_setting gsbi12 = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_NONE,
-};
-
-static struct gpiomux_setting cdc_mclk = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_NONE,
-};
-
-static struct gpiomux_setting audio_auxpcm[] = {
- /* Suspended state */
- {
- .func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_NONE,
- },
- /* Active state */
- {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_NONE,
- },
-};
-
-#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
-static struct gpiomux_setting gpio_eth_config = {
- .pull = GPIOMUX_PULL_NONE,
- .drv = GPIOMUX_DRV_8MA,
- .func = GPIOMUX_FUNC_GPIO,
-};
-#endif
-
-static struct gpiomux_setting slimbus = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_KEEPER,
-};
-
-struct msm_gpiomux_config msm8960_gpiomux_configs[NR_GPIO_IRQS] = {
-#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
- {
- .gpio = KS8851_IRQ_GPIO,
- .settings = {
- [GPIOMUX_SUSPENDED] = &gpio_eth_config,
- }
- },
- {
- .gpio = KS8851_RST_GPIO,
- .settings = {
- [GPIOMUX_SUSPENDED] = &gpio_eth_config,
- }
- },
-#endif
-};
-
-static struct msm_gpiomux_config msm8960_gsbi_configs[] __initdata = {
- {
- .gpio = 6, /* GSBI1 QUP SPI_DATA_MOSI */
- .settings = {
- [GPIOMUX_SUSPENDED] = &spi_suspended_config,
- [GPIOMUX_ACTIVE] = &spi_active,
- },
- },
- {
- .gpio = 7, /* GSBI1 QUP SPI_DATA_MISO */
- .settings = {
- [GPIOMUX_SUSPENDED] = &spi_suspended_config,
- [GPIOMUX_ACTIVE] = &spi_active,
- },
- },
- {
- .gpio = 8, /* GSBI1 QUP SPI_CS_N */
- .settings = {
- [GPIOMUX_SUSPENDED] = &spi_suspended_config,
- [GPIOMUX_ACTIVE] = &spi_active,
- },
- },
- {
- .gpio = 9, /* GSBI1 QUP SPI_CLK */
- .settings = {
- [GPIOMUX_SUSPENDED] = &spi_suspended_config,
- [GPIOMUX_ACTIVE] = &spi_active,
- },
- },
- {
- .gpio = 14, /* GSBI1 SPI_CS_1 */
- .settings = {
- [GPIOMUX_SUSPENDED] = &spi_suspended_config2,
- [GPIOMUX_ACTIVE] = &spi_active_config2,
- },
- },
- {
- .gpio = 16, /* GSBI3 I2C QUP SDA */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi3_suspended_cfg,
- [GPIOMUX_ACTIVE] = &gsbi3_active_cfg,
- },
- },
- {
- .gpio = 17, /* GSBI3 I2C QUP SCL */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi3_suspended_cfg,
- [GPIOMUX_ACTIVE] = &gsbi3_active_cfg,
- },
- },
- {
- .gpio = 22, /* GSBI5 UART2 */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi5,
- },
- },
- {
- .gpio = 23, /* GSBI5 UART2 */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi5,
- },
- },
- {
- .gpio = 24, /* GSBI5 UART2 */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi5,
- },
- },
- {
- .gpio = 25, /* GSBI5 UART2 */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi5,
- },
- },
- {
- .gpio = 44, /* GSBI12 I2C QUP SDA */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi12,
- },
- },
- {
- .gpio = 45, /* GSBI12 I2C QUP SCL */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi12,
- },
- },
- {
- .gpio = 73, /* GSBI10 I2C QUP SDA */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi10,
- },
- },
- {
- .gpio = 74, /* GSBI10 I2C QUP SCL */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi10,
- },
- },
-};
-
-static struct msm_gpiomux_config msm8960_slimbus_config[] __initdata = {
- {
- .gpio = 60, /* slimbus data */
- .settings = {
- [GPIOMUX_SUSPENDED] = &slimbus,
- },
- },
- {
- .gpio = 61, /* slimbus clk */
- .settings = {
- [GPIOMUX_SUSPENDED] = &slimbus,
- },
- },
-};
-
-static struct msm_gpiomux_config msm8960_audio_codec_configs[] __initdata = {
- {
- .gpio = 59,
- .settings = {
- [GPIOMUX_SUSPENDED] = &cdc_mclk,
- },
- },
-};
-
-static struct msm_gpiomux_config msm8960_audio_auxpcm_configs[] __initdata = {
- {
- .gpio = 63,
- .settings = {
- [GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
- [GPIOMUX_ACTIVE] = &audio_auxpcm[1],
- },
- },
- {
- .gpio = 64,
- .settings = {
- [GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
- [GPIOMUX_ACTIVE] = &audio_auxpcm[1],
- },
- },
- {
- .gpio = 65,
- .settings = {
- [GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
- [GPIOMUX_ACTIVE] = &audio_auxpcm[1],
- },
- },
- {
- .gpio = 66,
- .settings = {
- [GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
- [GPIOMUX_ACTIVE] = &audio_auxpcm[1],
- },
- },
-};
-
-static struct gpiomux_setting wcnss_5wire_suspend_cfg = {
- .func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_UP,
-};
-
-static struct gpiomux_setting wcnss_5wire_active_cfg = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_6MA,
- .pull = GPIOMUX_PULL_DOWN,
-};
-
-static struct msm_gpiomux_config wcnss_5wire_interface[] = {
- {
- .gpio = 84,
- .settings = {
- [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
- [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
- },
- },
- {
- .gpio = 85,
- .settings = {
- [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
- [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
- },
- },
- {
- .gpio = 86,
- .settings = {
- [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
- [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
- },
- },
- {
- .gpio = 87,
- .settings = {
- [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
- [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
- },
- },
- {
- .gpio = 88,
- .settings = {
- [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
- [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
- },
- },
-};
-static struct gpiomux_setting cam_settings[] = {
- {
- .func = GPIOMUX_FUNC_GPIO, /*suspend*/
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_DOWN,
- },
-
- {
- .func = GPIOMUX_FUNC_1, /*active 1*/
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_NONE,
- },
-
- {
- .func = GPIOMUX_FUNC_GPIO, /*active 2*/
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_NONE,
- },
-
- {
- .func = GPIOMUX_FUNC_1, /*active 3*/
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_NONE,
- },
-
- {
- .func = GPIOMUX_FUNC_5, /*active 4*/
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_UP,
- },
-
- {
- .func = GPIOMUX_FUNC_6, /*active 5*/
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_UP,
- },
-
- {
- .func = GPIOMUX_FUNC_2, /*active 6*/
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_UP,
- },
-
- {
- .func = GPIOMUX_FUNC_3, /*active 7*/
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_UP,
- },
-
- {
- .func = GPIOMUX_FUNC_GPIO, /*i2c suspend*/
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_KEEPER,
- },
-
-};
-
-static struct msm_gpiomux_config msm8960_cam_common_configs[] = {
- {
- .gpio = 2,
- .settings = {
- [GPIOMUX_ACTIVE] = &cam_settings[2],
- [GPIOMUX_SUSPENDED] = &cam_settings[0],
- },
- },
- {
- .gpio = 3,
- .settings = {
- [GPIOMUX_ACTIVE] = &cam_settings[1],
- [GPIOMUX_SUSPENDED] = &cam_settings[0],
- },
- },
- {
- .gpio = 4,
- .settings = {
- [GPIOMUX_ACTIVE] = &cam_settings[1],
- [GPIOMUX_SUSPENDED] = &cam_settings[0],
- },
- },
- {
- .gpio = 5,
- .settings = {
- [GPIOMUX_ACTIVE] = &cam_settings[1],
- [GPIOMUX_SUSPENDED] = &cam_settings[0],
- },
- },
- {
- .gpio = 76,
- .settings = {
- [GPIOMUX_ACTIVE] = &cam_settings[2],
- [GPIOMUX_SUSPENDED] = &cam_settings[0],
- },
- },
- {
- .gpio = 107,
- .settings = {
- [GPIOMUX_ACTIVE] = &cam_settings[2],
- [GPIOMUX_SUSPENDED] = &cam_settings[0],
- },
- },
-};
-
-static struct msm_gpiomux_config msm8960_cam_2d_configs[] = {
- {
- .gpio = 18,
- .settings = {
- [GPIOMUX_ACTIVE] = &cam_settings[3],
- [GPIOMUX_SUSPENDED] = &cam_settings[8],
- },
- },
- {
- .gpio = 19,
- .settings = {
- [GPIOMUX_ACTIVE] = &cam_settings[3],
- [GPIOMUX_SUSPENDED] = &cam_settings[8],
- },
- },
- {
- .gpio = 20,
- .settings = {
- [GPIOMUX_ACTIVE] = &cam_settings[3],
- [GPIOMUX_SUSPENDED] = &cam_settings[8],
- },
- },
- {
- .gpio = 21,
- .settings = {
- [GPIOMUX_ACTIVE] = &cam_settings[3],
- [GPIOMUX_SUSPENDED] = &cam_settings[8],
- },
- },
-};
-
-static struct gpiomux_setting cyts_resout_sus_cfg = {
- .func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_6MA,
- .pull = GPIOMUX_PULL_UP,
-};
-
-static struct gpiomux_setting cyts_resout_act_cfg = {
- .func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_6MA,
- .pull = GPIOMUX_PULL_UP,
-};
-
-static struct gpiomux_setting cyts_sleep_sus_cfg = {
- .func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_6MA,
- .pull = GPIOMUX_PULL_DOWN,
-};
-
-static struct gpiomux_setting cyts_sleep_act_cfg = {
- .func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_6MA,
- .pull = GPIOMUX_PULL_DOWN,
-};
-
-static struct gpiomux_setting cyts_int_act_cfg = {
- .func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_UP,
-};
-
-static struct gpiomux_setting cyts_int_sus_cfg = {
- .func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_DOWN,
-};
-
-static struct msm_gpiomux_config msm8960_cyts_configs[] __initdata = {
- { /* TS INTERRUPT */
- .gpio = 11,
- .settings = {
- [GPIOMUX_ACTIVE] = &cyts_int_act_cfg,
- [GPIOMUX_SUSPENDED] = &cyts_int_sus_cfg,
- },
- },
- { /* TS SLEEP */
- .gpio = 50,
- .settings = {
- [GPIOMUX_ACTIVE] = &cyts_sleep_act_cfg,
- [GPIOMUX_SUSPENDED] = &cyts_sleep_sus_cfg,
- },
- },
- { /* TS RESOUT */
- .gpio = 52,
- .settings = {
- [GPIOMUX_ACTIVE] = &cyts_resout_act_cfg,
- [GPIOMUX_SUSPENDED] = &cyts_resout_sus_cfg,
- },
- },
-};
-
-#ifdef CONFIG_USB_EHCI_MSM_HSIC
-static struct gpiomux_setting hsic_act_cfg = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_12MA,
- .pull = GPIOMUX_PULL_NONE,
-};
-
-static struct gpiomux_setting hsic_sus_cfg = {
- .func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_DOWN,
-};
-
-static struct gpiomux_setting hsic_hub_act_cfg = {
- .func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_NONE,
-};
-
-static struct msm_gpiomux_config msm8960_hsic_configs[] = {
- {
- .gpio = 150, /*HSIC_STROBE */
- .settings = {
- [GPIOMUX_ACTIVE] = &hsic_act_cfg,
- [GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
- },
- },
- {
- .gpio = 151, /* HSIC_DATA */
- .settings = {
- [GPIOMUX_ACTIVE] = &hsic_act_cfg,
- [GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
- },
- },
- {
- .gpio = 91, /* HSIC_HUB_RESET */
- .settings = {
- [GPIOMUX_ACTIVE] = &hsic_hub_act_cfg,
- [GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
- },
- },
-};
-#endif
-
-#define HAP_SHIFT_LVL_OE_GPIO 47
-
-static struct gpiomux_setting hap_lvl_shft_suspended_config = {
- .func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_DOWN,
-};
-
-static struct gpiomux_setting hap_lvl_shft_active_config = {
- .func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_UP,
-};
-
-static struct msm_gpiomux_config hap_lvl_shft_config[] __initdata = {
- {
- .gpio = HAP_SHIFT_LVL_OE_GPIO,
- .settings = {
- [GPIOMUX_SUSPENDED] = &hap_lvl_shft_suspended_config,
- [GPIOMUX_ACTIVE] = &hap_lvl_shft_active_config,
- },
- },
-};
-
-#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
-enum {
- SX150X_CAM,
-};
-
-static struct sx150x_platform_data sx150x_data[] = {
- [SX150X_CAM] = {
- .gpio_base = GPIO_CAM_EXPANDER_BASE,
- .oscio_is_gpo = false,
- .io_pullup_ena = 0x0,
- .io_pulldn_ena = 0xc0,
- .io_open_drain_ena = 0x0,
- .irq_summary = -1,
- },
-};
-
-#endif
-
-#ifdef CONFIG_I2C
-
-#define MSM_8960_GSBI4_QUP_I2C_BUS_ID 4
-#define MSM_8960_GSBI3_QUP_I2C_BUS_ID 3
-#define MSM_8960_GSBI10_QUP_I2C_BUS_ID 10
-
-#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
-
-static struct i2c_board_info cam_expander_i2c_info[] = {
- {
- I2C_BOARD_INFO("sx1508q", 0x22),
- .platform_data = &sx150x_data[SX150X_CAM]
- },
-};
-
-static struct msm_cam_expander_info cam_expander_info[] = {
- {
- cam_expander_i2c_info,
- MSM_8960_GSBI4_QUP_I2C_BUS_ID,
- },
-};
-#endif
-#endif
-
-#define MSM_PMEM_KERNEL_EBI1_SIZE 0x110C000
-#define MSM_PMEM_ADSP_SIZE 0x3800000
-#define MSM_PMEM_AUDIO_SIZE 0x28B000
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-#define MSM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
-#else
-#define MSM_PMEM_SIZE 0x1800000 /* 24 Mbytes */
-#endif
-
-
-#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-#define MSM_ION_EBI_SIZE MSM_PMEM_SIZE
-#define MSM_ION_ADSP_SIZE MSM_PMEM_ADSP_SIZE
-#define MSM_ION_HEAP_NUM 4
-#else
-#define MSM_ION_HEAP_NUM 2
-#endif
-
-#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
-static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
-static int __init pmem_kernel_ebi1_size_setup(char *p)
-{
- pmem_kernel_ebi1_size = memparse(p, NULL);
- return 0;
-}
-early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
-#endif
-
-#ifdef CONFIG_ANDROID_PMEM
-static unsigned pmem_size = MSM_PMEM_SIZE;
-static int __init pmem_size_setup(char *p)
-{
- pmem_size = memparse(p, NULL);
- return 0;
-}
-early_param("pmem_size", pmem_size_setup);
-
-static unsigned pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
-
-static int __init pmem_adsp_size_setup(char *p)
-{
- pmem_adsp_size = memparse(p, NULL);
- return 0;
-}
-early_param("pmem_adsp_size", pmem_adsp_size_setup);
-
-static unsigned pmem_audio_size = MSM_PMEM_AUDIO_SIZE;
-
-static int __init pmem_audio_size_setup(char *p)
-{
- pmem_audio_size = memparse(p, NULL);
- return 0;
-}
-early_param("pmem_audio_size", pmem_audio_size_setup);
-#endif
-
-#ifdef CONFIG_ANDROID_PMEM
-#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
-static struct android_pmem_platform_data android_pmem_pdata = {
- .name = "pmem",
- .allocator_type = PMEM_ALLOCATORTYPE_ALLORNOTHING,
- .cached = 1,
- .memory_type = MEMTYPE_EBI1,
-};
-
-static struct platform_device android_pmem_device = {
- .name = "android_pmem",
- .id = 0,
- .dev = {.platform_data = &android_pmem_pdata},
-};
-
-static struct android_pmem_platform_data android_pmem_adsp_pdata = {
- .name = "pmem_adsp",
- .allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
- .cached = 0,
- .memory_type = MEMTYPE_EBI1,
-};
-static struct platform_device android_pmem_adsp_device = {
- .name = "android_pmem",
- .id = 2,
- .dev = { .platform_data = &android_pmem_adsp_pdata },
-};
-#endif
-
-static struct android_pmem_platform_data android_pmem_audio_pdata = {
- .name = "pmem_audio",
- .allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
- .cached = 0,
- .memory_type = MEMTYPE_EBI1,
-};
-
-static struct platform_device android_pmem_audio_device = {
- .name = "android_pmem",
- .id = 4,
- .dev = { .platform_data = &android_pmem_audio_pdata },
-};
-#endif
-
-#define DSP_RAM_BASE_8960 0x8da00000
-#define DSP_RAM_SIZE_8960 0x1800000
-static int dspcrashd_pdata_8960 = 0xDEADDEAD;
-
-static struct resource resources_dspcrashd_8960[] = {
- {
- .name = "msm_dspcrashd",
- .start = DSP_RAM_BASE_8960,
- .end = DSP_RAM_BASE_8960 + DSP_RAM_SIZE_8960,
- .flags = IORESOURCE_DMA,
- },
-};
-
-struct platform_device msm_device_dspcrashd_8960 = {
- .name = "msm_dspcrashd",
- .num_resources = ARRAY_SIZE(resources_dspcrashd_8960),
- .resource = resources_dspcrashd_8960,
- .dev = { .platform_data = &dspcrashd_pdata_8960 },
-};
-
-static struct memtype_reserve msm8960_reserve_table[] __initdata = {
- [MEMTYPE_SMI] = {
- },
- [MEMTYPE_EBI0] = {
- .flags = MEMTYPE_FLAGS_1M_ALIGN,
- },
- [MEMTYPE_EBI1] = {
- .flags = MEMTYPE_FLAGS_1M_ALIGN,
- },
-};
-
-static void __init size_pmem_devices(void)
-{
-#ifdef CONFIG_ANDROID_PMEM
-#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
- android_pmem_adsp_pdata.size = pmem_adsp_size;
- android_pmem_pdata.size = pmem_size;
-#endif
- android_pmem_audio_pdata.size = MSM_PMEM_AUDIO_SIZE;
-#endif
-}
-
-static void __init reserve_memory_for(struct android_pmem_platform_data *p)
-{
- msm8960_reserve_table[p->memory_type].size += p->size;
-}
-
-static void __init reserve_pmem_memory(void)
-{
-#ifdef CONFIG_ANDROID_PMEM
-#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
- reserve_memory_for(&android_pmem_adsp_pdata);
- reserve_memory_for(&android_pmem_pdata);
-#endif
- reserve_memory_for(&android_pmem_audio_pdata);
- msm8960_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
-#endif
-}
-
-static int msm8960_paddr_to_memtype(unsigned int paddr)
-{
- return MEMTYPE_EBI1;
-}
-
-#ifdef CONFIG_ION_MSM
-struct ion_platform_data ion_pdata = {
- .nr = MSM_ION_HEAP_NUM,
- .heaps = {
- {
- .id = ION_HEAP_SYSTEM_ID,
- .type = ION_HEAP_TYPE_SYSTEM,
- .name = ION_KMALLOC_HEAP_NAME,
- },
- {
- .id = ION_HEAP_SYSTEM_CONTIG_ID,
- .type = ION_HEAP_TYPE_SYSTEM_CONTIG,
- .name = ION_VMALLOC_HEAP_NAME,
- },
-#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
- {
- .id = ION_HEAP_EBI_ID,
- .type = ION_HEAP_TYPE_CARVEOUT,
- .name = ION_EBI1_HEAP_NAME,
- .size = MSM_ION_EBI_SIZE,
- .memory_type = ION_EBI_TYPE,
- },
- {
- .id = ION_HEAP_ADSP_ID,
- .type = ION_HEAP_TYPE_CARVEOUT,
- .name = ION_ADSP_HEAP_NAME,
- .size = MSM_ION_ADSP_SIZE,
- .memory_type = ION_EBI_TYPE,
- },
-#endif
- }
-};
-
-struct platform_device ion_dev = {
- .name = "ion-msm",
- .id = 1,
- .dev = { .platform_data = &ion_pdata },
-};
-#endif
-
-static void reserve_ion_memory(void)
-{
-#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
- msm8960_reserve_table[MEMTYPE_EBI1].size += MSM_ION_EBI_SIZE;
- msm8960_reserve_table[MEMTYPE_EBI1].size += MSM_ION_ADSP_SIZE;
-#endif
-}
-static void __init msm8960_calculate_reserve_sizes(void)
-{
- size_pmem_devices();
- reserve_pmem_memory();
- reserve_ion_memory();
-}
-
-static struct reserve_info msm8960_reserve_info __initdata = {
- .memtype_reserve_table = msm8960_reserve_table,
- .calculate_reserve_sizes = msm8960_calculate_reserve_sizes,
- .paddr_to_memtype = msm8960_paddr_to_memtype,
-};
-
-static int msm8960_memory_bank_size(void)
-{
- return 1<<29;
-}
-
-static void __init locate_unstable_memory(void)
-{
- struct membank *mb = &meminfo.bank[meminfo.nr_banks - 1];
- unsigned long bank_size;
- unsigned long low, high;
-
- bank_size = msm8960_memory_bank_size();
- low = meminfo.bank[0].start;
- high = mb->start + mb->size;
- low &= ~(bank_size - 1);
-
- if (high - low <= bank_size)
- return;
- msm8960_reserve_info.low_unstable_address = low + bank_size;
- msm8960_reserve_info.max_unstable_size = high - low - bank_size;
- msm8960_reserve_info.bank_size = bank_size;
- pr_info("low unstable address %lx max size %lx bank size %lx\n",
- msm8960_reserve_info.low_unstable_address,
- msm8960_reserve_info.max_unstable_size,
- msm8960_reserve_info.bank_size);
-}
-
-static void __init place_movable_zone(void)
-{
- movable_reserved_start = msm8960_reserve_info.low_unstable_address;
- movable_reserved_size = msm8960_reserve_info.max_unstable_size;
- pr_info("movable zone start %lx size %lx\n",
- movable_reserved_start, movable_reserved_size);
-}
-
-static void __init msm8960_early_memory(void)
-{
- reserve_info = &msm8960_reserve_info;
- locate_unstable_memory();
- place_movable_zone();
-}
-
-static void __init msm8960_reserve(void)
-{
- msm_reserve();
-}
-
-static int msm8960_change_memory_power(u64 start, u64 size,
- int change_type)
-{
- return soc_change_memory_power(start, size, change_type);
-}
-
-#ifdef CONFIG_MSM_CAMERA
-
-static uint16_t msm_cam_gpio_2d_tbl[] = {
- 5, /*CAMIF_MCLK*/
- 20, /*CAMIF_I2C_DATA*/
- 21, /*CAMIF_I2C_CLK*/
-};
-
-static struct msm_camera_gpio_conf gpio_conf = {
- .cam_gpiomux_conf_tbl = msm8960_cam_2d_configs,
- .cam_gpiomux_conf_tbl_size = ARRAY_SIZE(msm8960_cam_2d_configs),
- .cam_gpio_tbl = msm_cam_gpio_2d_tbl,
- .cam_gpio_tbl_size = ARRAY_SIZE(msm_cam_gpio_2d_tbl),
-};
-
-#define VFE_CAMIF_TIMER1_GPIO 2
-#define VFE_CAMIF_TIMER2_GPIO 3
-#define VFE_CAMIF_TIMER3_GPIO_INT 4
-struct msm_camera_sensor_strobe_flash_data strobe_flash_xenon = {
- .flash_trigger = VFE_CAMIF_TIMER2_GPIO,
- .flash_charge = VFE_CAMIF_TIMER1_GPIO,
- .flash_charge_done = VFE_CAMIF_TIMER3_GPIO_INT,
- .flash_recharge_duration = 50000,
- .irq = MSM_GPIO_TO_INT(VFE_CAMIF_TIMER3_GPIO_INT),
-};
-
-#ifdef CONFIG_MSM_CAMERA_FLASH
-static struct msm_camera_sensor_flash_src msm_flash_src = {
- .flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
- ._fsrc.ext_driver_src.led_en = GPIO_CAM_GP_LED_EN1,
- ._fsrc.ext_driver_src.led_flash_en = GPIO_CAM_GP_LED_EN2,
-#if defined(CONFIG_I2C) && (defined(CONFIG_GPIO_SX150X) || \
- defined(CONFIG_GPIO_SX150X_MODULE))
- ._fsrc.ext_driver_src.expander_info = cam_expander_info,
-#endif
-};
-#endif
-
-static struct msm_bus_vectors cam_init_vectors[] = {
- {
- .src = MSM_BUS_MASTER_VFE,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 0,
- .ib = 0,
- },
- {
- .src = MSM_BUS_MASTER_VPE,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 0,
- .ib = 0,
- },
- {
- .src = MSM_BUS_MASTER_JPEG_ENC,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 0,
- .ib = 0,
- },
-};
-
-static struct msm_bus_vectors cam_preview_vectors[] = {
- {
- .src = MSM_BUS_MASTER_VFE,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 27648000,
- .ib = 110592000,
- },
- {
- .src = MSM_BUS_MASTER_VPE,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 0,
- .ib = 0,
- },
- {
- .src = MSM_BUS_MASTER_JPEG_ENC,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 0,
- .ib = 0,
- },
-};
-
-static struct msm_bus_vectors cam_video_vectors[] = {
- {
- .src = MSM_BUS_MASTER_VFE,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 140451840,
- .ib = 561807360,
- },
- {
- .src = MSM_BUS_MASTER_VPE,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 206807040,
- .ib = 488816640,
- },
- {
- .src = MSM_BUS_MASTER_JPEG_ENC,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 0,
- .ib = 0,
- },
-};
-
-static struct msm_bus_vectors cam_snapshot_vectors[] = {
- {
- .src = MSM_BUS_MASTER_VFE,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 274423680,
- .ib = 1097694720,
- },
- {
- .src = MSM_BUS_MASTER_VPE,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 0,
- .ib = 0,
- },
- {
- .src = MSM_BUS_MASTER_JPEG_ENC,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 540000000,
- .ib = 1350000000,
- },
-};
-
-static struct msm_bus_vectors cam_zsl_vectors[] = {
- {
- .src = MSM_BUS_MASTER_VFE,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 302071680,
- .ib = 1208286720,
- },
- {
- .src = MSM_BUS_MASTER_VPE,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 0,
- .ib = 0,
- },
- {
- .src = MSM_BUS_MASTER_JPEG_ENC,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 540000000,
- .ib = 1350000000,
- },
-};
-
-static struct msm_bus_paths cam_bus_client_config[] = {
- {
- ARRAY_SIZE(cam_init_vectors),
- cam_init_vectors,
- },
- {
- ARRAY_SIZE(cam_preview_vectors),
- cam_preview_vectors,
- },
- {
- ARRAY_SIZE(cam_video_vectors),
- cam_video_vectors,
- },
- {
- ARRAY_SIZE(cam_snapshot_vectors),
- cam_snapshot_vectors,
- },
- {
- ARRAY_SIZE(cam_zsl_vectors),
- cam_zsl_vectors,
- },
-};
-
-static struct msm_bus_scale_pdata cam_bus_client_pdata = {
- cam_bus_client_config,
- ARRAY_SIZE(cam_bus_client_config),
- .name = "msm_camera",
-};
-
-struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
- {
- .ioclk.mclk_clk_rate = 24000000,
- .ioclk.vfe_clk_rate = 228570000,
- .csid_core = 0,
- .cam_bus_scale_table = &cam_bus_client_pdata,
- },
- {
- .ioclk.mclk_clk_rate = 24000000,
- .ioclk.vfe_clk_rate = 228570000,
- .csid_core = 1,
- .cam_bus_scale_table = &cam_bus_client_pdata,
- },
-};
-
-#ifdef CONFIG_IMX074_ACT
-static struct i2c_board_info imx074_actuator_i2c_info = {
- I2C_BOARD_INFO("imx074_act", 0x11),
-};
-
-static struct msm_actuator_info imx074_actuator_info = {
- .board_info = &imx074_actuator_i2c_info,
- .bus_id = MSM_8960_GSBI4_QUP_I2C_BUS_ID,
- .vcm_pwd = 0,
- .vcm_enable = 1,
-};
-#endif
-
-#ifdef CONFIG_IMX074
-static struct msm_camera_sensor_flash_data flash_imx074 = {
- .flash_type = MSM_CAMERA_FLASH_LED,
-#ifdef CONFIG_MSM_CAMERA_FLASH
- .flash_src = &msm_flash_src
-#endif
-};
-
-static struct msm_camera_sensor_platform_info sensor_board_info_imx074 = {
- .mount_angle = 90,
- .sensor_reset = 107,
- .sensor_pwd = 85,
- .vcm_pwd = 0,
- .vcm_enable = 1,
-};
-
-static struct msm_camera_sensor_info msm_camera_sensor_imx074_data = {
- .sensor_name = "imx074",
- .pdata = &msm_camera_csi_device_data[0],
- .flash_data = &flash_imx074,
- .strobe_flash_data = &strobe_flash_xenon,
- .sensor_platform_info = &sensor_board_info_imx074,
- .gpio_conf = &gpio_conf,
- .csi_if = 1,
- .camera_type = BACK_CAMERA_2D,
-#ifdef CONFIG_IMX074_ACT
- .actuator_info = &imx074_actuator_info
-#endif
-};
-
-struct platform_device msm8960_camera_sensor_imx074 = {
- .name = "msm_camera_imx074",
- .dev = {
- .platform_data = &msm_camera_sensor_imx074_data,
- },
-};
-#endif
-#ifdef CONFIG_OV2720
-static struct msm_camera_sensor_flash_data flash_ov2720 = {
- .flash_type = MSM_CAMERA_FLASH_NONE,
-};
-
-static struct msm_camera_sensor_platform_info sensor_board_info_ov2720 = {
- .mount_angle = 0,
- .sensor_reset = 76,
- .sensor_pwd = 85,
- .vcm_pwd = 0,
- .vcm_enable = 1,
-};
-
-static struct msm_camera_sensor_info msm_camera_sensor_ov2720_data = {
- .sensor_name = "ov2720",
- .pdata = &msm_camera_csi_device_data[1],
- .flash_data = &flash_ov2720,
- .sensor_platform_info = &sensor_board_info_ov2720,
- .gpio_conf = &gpio_conf,
- .csi_if = 1,
- .camera_type = FRONT_CAMERA_2D,
-};
-
-struct platform_device msm8960_camera_sensor_ov2720 = {
- .name = "msm_camera_ov2720",
- .dev = {
- .platform_data = &msm_camera_sensor_ov2720_data,
- },
-};
-#endif
-
-static struct msm_camera_sensor_flash_data flash_qs_mt9p017 = {
- .flash_type = MSM_CAMERA_FLASH_LED,
-};
-
-static struct msm_camera_sensor_platform_info sensor_board_info_qs_mt9p017 = {
- .mount_angle = 270,
- .sensor_reset = 107,
- .sensor_pwd = 85,
- .vcm_pwd = 0,
- .vcm_enable = 1,
-};
-
-static struct msm_camera_sensor_info msm_camera_sensor_qs_mt9p017_data = {
- .sensor_name = "qs_mt9p017",
- .pdata = &msm_camera_csi_device_data[0],
- .flash_data = &flash_qs_mt9p017,
- .sensor_platform_info = &sensor_board_info_qs_mt9p017,
- .gpio_conf = &gpio_conf,
- .csi_if = 1,
- .camera_type = BACK_CAMERA_3D,
-};
-
-struct platform_device msm8960_camera_sensor_qs_mt9p017 = {
- .name = "msm_camera_qs_mt9p017",
- .dev = {
- .platform_data = &msm_camera_sensor_qs_mt9p017_data,
- },
-};
-
-static struct msm8960_privacy_light_cfg privacy_light_info = {
- .mpp = PM8921_MPP_PM_TO_SYS(12),
-};
-
-static void __init msm8960_init_cam(void)
-{
- int i;
- struct platform_device *cam_dev[] = {
- &msm8960_camera_sensor_imx074,
- &msm8960_camera_sensor_ov2720,
- &msm8960_camera_sensor_qs_mt9p017,
- };
-
- if (machine_is_msm8960_liquid()) {
- struct msm_camera_sensor_info *s_info;
- s_info = msm8960_camera_sensor_imx074.dev.platform_data;
- s_info->sensor_platform_info->mount_angle = 180;
- s_info = msm8960_camera_sensor_ov2720.dev.platform_data;
- s_info->sensor_platform_info->privacy_light = 1;
- s_info->sensor_platform_info->privacy_light_info =
- &privacy_light_info;
- }
-
- for (i = 0; i < ARRAY_SIZE(cam_dev); i++) {
- struct msm_camera_sensor_info *s_info;
- s_info = cam_dev[i]->dev.platform_data;
- msm_get_cam_resources(s_info);
- platform_device_register(cam_dev[i]);
- }
-
- platform_device_register(&msm8960_device_csiphy0);
- platform_device_register(&msm8960_device_csiphy1);
- platform_device_register(&msm8960_device_csid0);
- platform_device_register(&msm8960_device_csid1);
- platform_device_register(&msm8960_device_ispif);
- platform_device_register(&msm8960_device_vfe);
- platform_device_register(&msm8960_device_vpe);
-}
-#endif
-
-#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
-#define MSM_FB_PRIM_BUF_SIZE (1376 * 768 * 4 * 3) /* 4 bpp x 3 pages */
-#else
-#define MSM_FB_PRIM_BUF_SIZE (1376 * 768 * 4 * 2) /* 4 bpp x 2 pages */
-#endif
-
-
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
-#define MSM_FB_EXT_BUF_SIZE (1920 * 1088 * 2 * 1) /* 2 bpp x 1 page */
-#elif defined(CONFIG_FB_MSM_TVOUT)
-#define MSM_FB_EXT_BUF_SIZE (720 * 576 * 2 * 2) /* 2 bpp x 2 pages */
-#else
-#define MSM_FB_EXT_BUF_SIZE 0
-#endif
-
-#ifdef CONFIG_FB_MSM_OVERLAY_WRITEBACK
-/* width x height x 3 bpp x 2 frame buffer */
-#define MSM_FB_WRITEBACK_SIZE (1376 * 768 * 3 * 2)
-#define MSM_FB_WRITEBACK_OFFSET \
- (MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE)
-#else
-#define MSM_FB_WRITEBACK_SIZE 0
-#define MSM_FB_WRITEBACK_OFFSET 0
-#endif
-
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-/* 4 bpp x 2 page HDMI case */
-#define MSM_FB_SIZE roundup((1920 * 1088 * 4 * 2), 4096)
-#else
-/* Note: must be multiple of 4096 */
-#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE + \
- MSM_FB_WRITEBACK_SIZE, 4096)
-#endif
-
-static int writeback_offset(void)
-{
- return MSM_FB_WRITEBACK_OFFSET;
-}
-
-
-#define MDP_VSYNC_GPIO 0
-
-#define PANEL_NAME_MAX_LEN 30
-#define MIPI_CMD_NOVATEK_QHD_PANEL_NAME "mipi_cmd_novatek_qhd"
-#define MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME "mipi_video_novatek_qhd"
-#define MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME "mipi_video_toshiba_wsvga"
-#define MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME "mipi_video_chimei_wxga"
-#define MIPI_VIDEO_SIMULATOR_VGA_PANEL_NAME "mipi_video_simulator_vga"
-#define MIPI_CMD_RENESAS_FWVGA_PANEL_NAME "mipi_cmd_renesas_fwvga"
-#define HDMI_PANEL_NAME "hdmi_msm"
-#define TVOUT_PANEL_NAME "tvout_msm"
-
-static struct resource msm_fb_resources[] = {
- {
- .flags = IORESOURCE_DMA,
- }
-};
-
-static int msm_fb_detect_panel(const char *name)
-{
- if (machine_is_msm8960_liquid()) {
- if (!strncmp(name, MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME,
- strnlen(MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME,
- PANEL_NAME_MAX_LEN)))
- return 0;
- } else {
- if (!strncmp(name, MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME,
- strnlen(MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME,
- PANEL_NAME_MAX_LEN)))
- return 0;
-
-#ifndef CONFIG_FB_MSM_MIPI_PANEL_DETECT
- if (!strncmp(name, MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME,
- strnlen(MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME,
- PANEL_NAME_MAX_LEN)))
- return 0;
-
- if (!strncmp(name, MIPI_CMD_NOVATEK_QHD_PANEL_NAME,
- strnlen(MIPI_CMD_NOVATEK_QHD_PANEL_NAME,
- PANEL_NAME_MAX_LEN)))
- return 0;
-
- if (!strncmp(name, MIPI_VIDEO_SIMULATOR_VGA_PANEL_NAME,
- strnlen(MIPI_VIDEO_SIMULATOR_VGA_PANEL_NAME,
- PANEL_NAME_MAX_LEN)))
- return 0;
-
- if (!strncmp(name, MIPI_CMD_RENESAS_FWVGA_PANEL_NAME,
- strnlen(MIPI_CMD_RENESAS_FWVGA_PANEL_NAME,
- PANEL_NAME_MAX_LEN)))
- return 0;
-#endif
- }
-
- if (!strncmp(name, HDMI_PANEL_NAME,
- strnlen(HDMI_PANEL_NAME,
- PANEL_NAME_MAX_LEN)))
- return 0;
-
- if (!strncmp(name, TVOUT_PANEL_NAME,
- strnlen(TVOUT_PANEL_NAME,
- PANEL_NAME_MAX_LEN)))
- return 0;
-
- pr_warning("%s: not supported '%s'", __func__, name);
- return -ENODEV;
-}
-
-static struct msm_fb_platform_data msm_fb_pdata = {
- .detect_client = msm_fb_detect_panel,
-};
-
-static struct platform_device msm_fb_device = {
- .name = "msm_fb",
- .id = 0,
- .num_resources = ARRAY_SIZE(msm_fb_resources),
- .resource = msm_fb_resources,
- .dev.platform_data = &msm_fb_pdata,
-};
-
-static bool dsi_power_on;
-
-/**
- * LiQUID panel on/off
- *
- * @param on
- *
- * @return int
- */
-static int mipi_dsi_liquid_panel_power(int on)
-{
- static struct regulator *reg_l2, *reg_ext_3p3v;
- static int gpio21, gpio24, gpio43;
- int rc;
-
- pr_info("%s: on=%d\n", __func__, on);
-
- gpio21 = PM8921_GPIO_PM_TO_SYS(21); /* disp power enable_n */
- gpio43 = PM8921_GPIO_PM_TO_SYS(43); /* Displays Enable (rst_n)*/
- gpio24 = PM8921_GPIO_PM_TO_SYS(24); /* Backlight PWM */
-
- if (!dsi_power_on) {
-
- reg_l2 = regulator_get(&msm_mipi_dsi1_device.dev,
- "dsi_vdda");
- if (IS_ERR(reg_l2)) {
- pr_err("could not get 8921_l2, rc = %ld\n",
- PTR_ERR(reg_l2));
- return -ENODEV;
- }
-
- rc = regulator_set_voltage(reg_l2, 1200000, 1200000);
- if (rc) {
- pr_err("set_voltage l2 failed, rc=%d\n", rc);
- return -EINVAL;
- }
-
- reg_ext_3p3v = regulator_get(&msm_mipi_dsi1_device.dev,
- "vdd_lvds_3p3v");
- if (IS_ERR(reg_ext_3p3v)) {
- pr_err("could not get reg_ext_3p3v, rc = %ld\n",
- PTR_ERR(reg_ext_3p3v));
- return -ENODEV;
- }
-
- rc = gpio_request(gpio21, "disp_pwr_en_n");
- if (rc) {
- pr_err("request gpio 21 failed, rc=%d\n", rc);
- return -ENODEV;
- }
-
- rc = gpio_request(gpio43, "disp_rst_n");
- if (rc) {
- pr_err("request gpio 43 failed, rc=%d\n", rc);
- return -ENODEV;
- }
-
- rc = gpio_request(gpio24, "disp_backlight_pwm");
- if (rc) {
- pr_err("request gpio 24 failed, rc=%d\n", rc);
- return -ENODEV;
- }
-
- dsi_power_on = true;
- }
-
- if (on) {
- rc = regulator_set_optimum_mode(reg_l2, 100000);
- if (rc < 0) {
- pr_err("set_optimum_mode l2 failed, rc=%d\n", rc);
- return -EINVAL;
- }
- rc = regulator_enable(reg_l2);
- if (rc) {
- pr_err("enable l2 failed, rc=%d\n", rc);
- return -ENODEV;
- }
-
- rc = regulator_enable(reg_ext_3p3v);
- if (rc) {
- pr_err("enable reg_ext_3p3v failed, rc=%d\n", rc);
- return -ENODEV;
- }
-
- /* set reset pin before power enable */
- gpio_set_value_cansleep(gpio43, 0); /* disp disable (resx=0) */
-
- gpio_set_value_cansleep(gpio21, 0); /* disp power enable_n */
- msleep(20);
- gpio_set_value_cansleep(gpio43, 1); /* disp enable */
- msleep(20);
- gpio_set_value_cansleep(gpio43, 0); /* disp enable */
- msleep(20);
- gpio_set_value_cansleep(gpio43, 1); /* disp enable */
- msleep(20);
- } else {
- gpio_set_value_cansleep(gpio43, 0);
- gpio_set_value_cansleep(gpio21, 1);
-
- rc = regulator_disable(reg_l2);
- if (rc) {
- pr_err("disable reg_l2 failed, rc=%d\n", rc);
- return -ENODEV;
- }
- rc = regulator_disable(reg_ext_3p3v);
- if (rc) {
- pr_err("disable reg_ext_3p3v failed, rc=%d\n", rc);
- return -ENODEV;
- }
- rc = regulator_set_optimum_mode(reg_l2, 100);
- if (rc < 0) {
- pr_err("set_optimum_mode l2 failed, rc=%d\n", rc);
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-static int mipi_dsi_cdp_panel_power(int on)
-{
- static struct regulator *reg_l8, *reg_l23, *reg_l2;
- static int gpio43;
- int rc;
-
- pr_info("%s: state : %d\n", __func__, on);
-
- if (!dsi_power_on) {
-
- reg_l8 = regulator_get(&msm_mipi_dsi1_device.dev,
- "dsi_vdc");
- if (IS_ERR(reg_l8)) {
- pr_err("could not get 8921_l8, rc = %ld\n",
- PTR_ERR(reg_l8));
- return -ENODEV;
- }
- reg_l23 = regulator_get(&msm_mipi_dsi1_device.dev,
- "dsi_vddio");
- if (IS_ERR(reg_l23)) {
- pr_err("could not get 8921_l23, rc = %ld\n",
- PTR_ERR(reg_l23));
- return -ENODEV;
- }
- reg_l2 = regulator_get(&msm_mipi_dsi1_device.dev,
- "dsi_vdda");
- if (IS_ERR(reg_l2)) {
- pr_err("could not get 8921_l2, rc = %ld\n",
- PTR_ERR(reg_l2));
- return -ENODEV;
- }
- rc = regulator_set_voltage(reg_l8, 2800000, 3000000);
- if (rc) {
- pr_err("set_voltage l8 failed, rc=%d\n", rc);
- return -EINVAL;
- }
- rc = regulator_set_voltage(reg_l23, 1800000, 1800000);
- if (rc) {
- pr_err("set_voltage l23 failed, rc=%d\n", rc);
- return -EINVAL;
- }
- rc = regulator_set_voltage(reg_l2, 1200000, 1200000);
- if (rc) {
- pr_err("set_voltage l2 failed, rc=%d\n", rc);
- return -EINVAL;
- }
- gpio43 = PM8921_GPIO_PM_TO_SYS(43);
- rc = gpio_request(gpio43, "disp_rst_n");
- if (rc) {
- pr_err("request gpio 43 failed, rc=%d\n", rc);
- return -ENODEV;
- }
- dsi_power_on = true;
- }
- if (on) {
- rc = regulator_set_optimum_mode(reg_l8, 100000);
- if (rc < 0) {
- pr_err("set_optimum_mode l8 failed, rc=%d\n", rc);
- return -EINVAL;
- }
- rc = regulator_set_optimum_mode(reg_l23, 100000);
- if (rc < 0) {
- pr_err("set_optimum_mode l23 failed, rc=%d\n", rc);
- return -EINVAL;
- }
- rc = regulator_set_optimum_mode(reg_l2, 100000);
- if (rc < 0) {
- pr_err("set_optimum_mode l2 failed, rc=%d\n", rc);
- return -EINVAL;
- }
- rc = regulator_enable(reg_l8);
- if (rc) {
- pr_err("enable l8 failed, rc=%d\n", rc);
- return -ENODEV;
- }
- rc = regulator_enable(reg_l23);
- if (rc) {
- pr_err("enable l8 failed, rc=%d\n", rc);
- return -ENODEV;
- }
- rc = regulator_enable(reg_l2);
- if (rc) {
- pr_err("enable l2 failed, rc=%d\n", rc);
- return -ENODEV;
- }
- gpio_set_value_cansleep(gpio43, 1);
- } else {
- rc = regulator_disable(reg_l2);
- if (rc) {
- pr_err("disable reg_l2 failed, rc=%d\n", rc);
- return -ENODEV;
- }
- rc = regulator_disable(reg_l8);
- if (rc) {
- pr_err("disable reg_l8 failed, rc=%d\n", rc);
- return -ENODEV;
- }
- rc = regulator_disable(reg_l23);
- if (rc) {
- pr_err("disable reg_l23 failed, rc=%d\n", rc);
- return -ENODEV;
- }
- rc = regulator_set_optimum_mode(reg_l8, 100);
- if (rc < 0) {
- pr_err("set_optimum_mode l8 failed, rc=%d\n", rc);
- return -EINVAL;
- }
- rc = regulator_set_optimum_mode(reg_l23, 100);
- if (rc < 0) {
- pr_err("set_optimum_mode l23 failed, rc=%d\n", rc);
- return -EINVAL;
- }
- rc = regulator_set_optimum_mode(reg_l2, 100);
- if (rc < 0) {
- pr_err("set_optimum_mode l2 failed, rc=%d\n", rc);
- return -EINVAL;
- }
- gpio_set_value_cansleep(gpio43, 0);
- }
- return 0;
-}
-
-static int mipi_dsi_panel_power(int on)
-{
- int ret;
-
- pr_info("%s: on=%d\n", __func__, on);
-
- if (machine_is_msm8960_liquid())
- ret = mipi_dsi_liquid_panel_power(on);
- else
- ret = mipi_dsi_cdp_panel_power(on);
-
- return ret;
-}
-
-static struct mipi_dsi_platform_data mipi_dsi_pdata = {
- .vsync_gpio = MDP_VSYNC_GPIO,
- .dsi_power_save = mipi_dsi_panel_power,
-};
-
-#ifdef CONFIG_MSM_BUS_SCALING
-
-static struct msm_bus_vectors mdp_init_vectors[] = {
- {
- .src = MSM_BUS_MASTER_MDP_PORT0,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 0,
- .ib = 0,
- },
-};
-
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-static struct msm_bus_vectors hdmi_as_primary_vectors[] = {
- /* If HDMI is used as primary */
- {
- .src = MSM_BUS_MASTER_MDP_PORT0,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 2000000000,
- .ib = 2000000000,
- },
-};
-static struct msm_bus_paths mdp_bus_scale_usecases[] = {
- {
- ARRAY_SIZE(mdp_init_vectors),
- mdp_init_vectors,
- },
- {
- ARRAY_SIZE(hdmi_as_primary_vectors),
- hdmi_as_primary_vectors,
- },
- {
- ARRAY_SIZE(hdmi_as_primary_vectors),
- hdmi_as_primary_vectors,
- },
- {
- ARRAY_SIZE(hdmi_as_primary_vectors),
- hdmi_as_primary_vectors,
- },
- {
- ARRAY_SIZE(hdmi_as_primary_vectors),
- hdmi_as_primary_vectors,
- },
- {
- ARRAY_SIZE(hdmi_as_primary_vectors),
- hdmi_as_primary_vectors,
- },
-};
-#else
-static struct msm_bus_vectors mdp_ui_vectors[] = {
- {
- .src = MSM_BUS_MASTER_MDP_PORT0,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 216000000 * 2,
- .ib = 270000000 * 2,
- },
-};
-
-static struct msm_bus_vectors mdp_vga_vectors[] = {
- /* VGA and less video */
- {
- .src = MSM_BUS_MASTER_MDP_PORT0,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 216000000 * 2,
- .ib = 270000000 * 2,
- },
-};
-
-static struct msm_bus_vectors mdp_720p_vectors[] = {
- /* 720p and less video */
- {
- .src = MSM_BUS_MASTER_MDP_PORT0,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 230400000 * 2,
- .ib = 288000000 * 2,
- },
-};
-
-static struct msm_bus_vectors mdp_1080p_vectors[] = {
- /* 1080p and less video */
- {
- .src = MSM_BUS_MASTER_MDP_PORT0,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 334080000 * 2,
- .ib = 417600000 * 2,
- },
-};
-
-static struct msm_bus_paths mdp_bus_scale_usecases[] = {
- {
- ARRAY_SIZE(mdp_init_vectors),
- mdp_init_vectors,
- },
- {
- ARRAY_SIZE(mdp_ui_vectors),
- mdp_ui_vectors,
- },
- {
- ARRAY_SIZE(mdp_ui_vectors),
- mdp_ui_vectors,
- },
- {
- ARRAY_SIZE(mdp_vga_vectors),
- mdp_vga_vectors,
- },
- {
- ARRAY_SIZE(mdp_720p_vectors),
- mdp_720p_vectors,
- },
- {
- ARRAY_SIZE(mdp_1080p_vectors),
- mdp_1080p_vectors,
- },
-};
-#endif
-
-static struct msm_bus_scale_pdata mdp_bus_scale_pdata = {
- mdp_bus_scale_usecases,
- ARRAY_SIZE(mdp_bus_scale_usecases),
- .name = "mdp",
-};
-
-#endif
-
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-int mdp_core_clk_rate_table[] = {
- 200000000,
- 200000000,
- 200000000,
- 200000000,
-};
-#else
-int mdp_core_clk_rate_table[] = {
- 85330000,
- 85330000,
- 160000000,
- 200000000,
-};
-#endif
-
-static struct msm_panel_common_pdata mdp_pdata = {
- .gpio = MDP_VSYNC_GPIO,
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
- .mdp_core_clk_rate = 200000000,
-#else
- .mdp_core_clk_rate = 85330000,
-#endif
- .mdp_core_clk_table = mdp_core_clk_rate_table,
- .num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
-#ifdef CONFIG_MSM_BUS_SCALING
- .mdp_bus_scale_table = &mdp_bus_scale_pdata,
-#endif
- .mdp_rev = MDP_REV_42,
- .writeback_offset = writeback_offset,
-};
-
-static struct platform_device mipi_dsi_renesas_panel_device = {
- .name = "mipi_renesas",
- .id = 0,
-};
-
-static struct platform_device mipi_dsi_simulator_panel_device = {
- .name = "mipi_simulator",
- .id = 0,
-};
-
-#define LPM_CHANNEL0 0
-static int toshiba_gpio[] = {LPM_CHANNEL0};
-
-static struct mipi_dsi_panel_platform_data toshiba_pdata = {
- .gpio = toshiba_gpio,
-};
-
-static struct platform_device mipi_dsi_toshiba_panel_device = {
- .name = "mipi_toshiba",
- .id = 0,
- .dev = {
- .platform_data = &toshiba_pdata,
- }
-};
-
-#define FPGA_3D_GPIO_CONFIG_ADDR 0xB5
-static int dsi2lvds_gpio[2] = {
- 0,/* Backlight PWM-ID=0 for PMIC-GPIO#24 */
- 0x1F08 /* DSI2LVDS Bridge GPIO Output, mask=0x1f, out=0x08 */
- };
-
-static struct msm_panel_common_pdata mipi_dsi2lvds_pdata = {
- .gpio_num = dsi2lvds_gpio,
-};
-
-static struct mipi_dsi_phy_ctrl dsi_novatek_cmd_mode_phy_db = {
-
-/* DSI_BIT_CLK at 500MHz, 2 lane, RGB888 */
- {0x0F, 0x0a, 0x04, 0x00, 0x20}, /* regulator */
- /* timing */
- {0xab, 0x8a, 0x18, 0x00, 0x92, 0x97, 0x1b, 0x8c,
- 0x0c, 0x03, 0x04, 0xa0},
- {0x5f, 0x00, 0x00, 0x10}, /* phy ctrl */
- {0xff, 0x00, 0x06, 0x00}, /* strength */
- /* pll control */
- {0x40, 0xf9, 0x30, 0xda, 0x00, 0x40, 0x03, 0x62,
- 0x40, 0x07, 0x03,
- 0x00, 0x1a, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0x01},
-};
-
-static struct mipi_dsi_panel_platform_data novatek_pdata = {
- .fpga_3d_config_addr = FPGA_3D_GPIO_CONFIG_ADDR,
- .fpga_ctrl_mode = FPGA_SPI_INTF,
- .phy_ctrl_settings = &dsi_novatek_cmd_mode_phy_db,
-};
-
-static struct platform_device mipi_dsi_novatek_panel_device = {
- .name = "mipi_novatek",
- .id = 0,
- .dev = {
- .platform_data = &novatek_pdata,
- }
-};
-
-static struct platform_device mipi_dsi2lvds_bridge_device = {
- .name = "mipi_tc358764",
- .id = 0,
- .dev.platform_data = &mipi_dsi2lvds_pdata,
-};
-
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
-static struct resource hdmi_msm_resources[] = {
- {
- .name = "hdmi_msm_qfprom_addr",
- .start = 0x00700000,
- .end = 0x007060FF,
- .flags = IORESOURCE_MEM,
- },
- {
- .name = "hdmi_msm_hdmi_addr",
- .start = 0x04A00000,
- .end = 0x04A00FFF,
- .flags = IORESOURCE_MEM,
- },
- {
- .name = "hdmi_msm_irq",
- .start = HDMI_IRQ,
- .end = HDMI_IRQ,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static int hdmi_enable_5v(int on);
-static int hdmi_core_power(int on, int show);
-static int hdmi_cec_power(int on);
-
-static struct msm_hdmi_platform_data hdmi_msm_data = {
- .irq = HDMI_IRQ,
- .enable_5v = hdmi_enable_5v,
- .core_power = hdmi_core_power,
- .cec_power = hdmi_cec_power,
-};
-
-static struct platform_device hdmi_msm_device = {
- .name = "hdmi_msm",
- .id = 0,
- .num_resources = ARRAY_SIZE(hdmi_msm_resources),
- .resource = hdmi_msm_resources,
- .dev.platform_data = &hdmi_msm_data,
-};
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL */
-
-#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
-static struct platform_device wfd_panel_device = {
- .name = "wfd_panel",
- .id = 0,
- .dev.platform_data = NULL,
-};
-#endif
-
-#ifdef CONFIG_MSM_BUS_SCALING
-static struct msm_bus_vectors dtv_bus_init_vectors[] = {
- {
- .src = MSM_BUS_MASTER_MDP_PORT0,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 0,
- .ib = 0,
- },
-};
-
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-static struct msm_bus_vectors dtv_bus_def_vectors[] = {
- {
- .src = MSM_BUS_MASTER_MDP_PORT0,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 2000000000,
- .ib = 2000000000,
- },
-};
-#else
-static struct msm_bus_vectors dtv_bus_def_vectors[] = {
- {
- .src = MSM_BUS_MASTER_MDP_PORT0,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 566092800 * 2,
- .ib = 707616000 * 2,
- },
-};
-#endif
-
-static struct msm_bus_paths dtv_bus_scale_usecases[] = {
- {
- ARRAY_SIZE(dtv_bus_init_vectors),
- dtv_bus_init_vectors,
- },
- {
- ARRAY_SIZE(dtv_bus_def_vectors),
- dtv_bus_def_vectors,
- },
-};
-static struct msm_bus_scale_pdata dtv_bus_scale_pdata = {
- dtv_bus_scale_usecases,
- ARRAY_SIZE(dtv_bus_scale_usecases),
- .name = "dtv",
-};
-
-static struct lcdc_platform_data dtv_pdata = {
- .bus_scale_table = &dtv_bus_scale_pdata,
-};
-#endif
-
-static void __init msm_fb_add_devices(void)
-{
- struct platform_device *ptr = NULL;
-
- if (machine_is_msm8960_liquid())
- ptr = &mipi_dsi2lvds_bridge_device;
- else
- ptr = &mipi_dsi_toshiba_panel_device;
- platform_add_devices(&ptr, 1);
-
- if (machine_is_msm8x60_rumi3()) {
- msm_fb_register_device("mdp", NULL);
- mipi_dsi_pdata.target_type = 1;
- } else
- msm_fb_register_device("mdp", &mdp_pdata);
- msm_fb_register_device("mipi_dsi", &mipi_dsi_pdata);
-#ifdef CONFIG_MSM_BUS_SCALING
- msm_fb_register_device("dtv", &dtv_pdata);
-#endif
-}
-
-static struct gpiomux_setting mdp_vsync_suspend_cfg = {
- .func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_DOWN,
-};
-
-static struct gpiomux_setting mdp_vsync_active_cfg = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_DOWN,
-};
-
-static struct msm_gpiomux_config msm8960_mdp_vsync_configs[] __initdata = {
- {
- .gpio = MDP_VSYNC_GPIO,
- .settings = {
- [GPIOMUX_ACTIVE] = &mdp_vsync_active_cfg,
- [GPIOMUX_SUSPENDED] = &mdp_vsync_suspend_cfg,
- },
- }
-};
-
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
-static struct gpiomux_setting hdmi_suspend_cfg = {
- .func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_DOWN,
-};
-
-static struct gpiomux_setting hdmi_active_1_cfg = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_UP,
-};
-
-static struct gpiomux_setting hdmi_active_2_cfg = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_DOWN,
-};
-
-static struct msm_gpiomux_config msm8960_hdmi_configs[] __initdata = {
- {
- .gpio = 99,
- .settings = {
- [GPIOMUX_ACTIVE] = &hdmi_active_1_cfg,
- [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
- },
- },
- {
- .gpio = 100,
- .settings = {
- [GPIOMUX_ACTIVE] = &hdmi_active_1_cfg,
- [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
- },
- },
- {
- .gpio = 101,
- .settings = {
- [GPIOMUX_ACTIVE] = &hdmi_active_1_cfg,
- [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
- },
- },
- {
- .gpio = 102,
- .settings = {
- [GPIOMUX_ACTIVE] = &hdmi_active_2_cfg,
- [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
- },
- },
-};
-
-static int hdmi_enable_5v(int on)
-{
- /* TBD: PM8921 regulator instead of 8901 */
- static struct regulator *reg_8921_hdmi_mvs; /* HDMI_5V */
- static int prev_on;
- int rc;
-
- if (on == prev_on)
- return 0;
-
- if (!reg_8921_hdmi_mvs)
- reg_8921_hdmi_mvs = regulator_get(&hdmi_msm_device.dev,
- "hdmi_mvs");
-
- if (on) {
- rc = regulator_enable(reg_8921_hdmi_mvs);
- if (rc) {
- pr_err("'%s' regulator enable failed, rc=%d\n",
- "8921_hdmi_mvs", rc);
- return rc;
- }
- pr_debug("%s(on): success\n", __func__);
- } else {
- rc = regulator_disable(reg_8921_hdmi_mvs);
- if (rc)
- pr_warning("'%s' regulator disable failed, rc=%d\n",
- "8921_hdmi_mvs", rc);
- pr_debug("%s(off): success\n", __func__);
- }
-
- prev_on = on;
-
- return 0;
-}
-
-static int hdmi_core_power(int on, int show)
-{
- static struct regulator *reg_8921_l23, *reg_8921_s4;
- static int prev_on;
- int rc;
-
- if (on == prev_on)
- return 0;
-
- /* TBD: PM8921 regulator instead of 8901 */
- if (!reg_8921_l23) {
- reg_8921_l23 = regulator_get(&hdmi_msm_device.dev, "hdmi_avdd");
- if (IS_ERR(reg_8921_l23)) {
- pr_err("could not get reg_8921_l23, rc = %ld\n",
- PTR_ERR(reg_8921_l23));
- return -ENODEV;
- }
- rc = regulator_set_voltage(reg_8921_l23, 1800000, 1800000);
- if (rc) {
- pr_err("set_voltage failed for 8921_l23, rc=%d\n", rc);
- return -EINVAL;
- }
- }
- if (!reg_8921_s4) {
- reg_8921_s4 = regulator_get(&hdmi_msm_device.dev, "hdmi_vcc");
- if (IS_ERR(reg_8921_s4)) {
- pr_err("could not get reg_8921_s4, rc = %ld\n",
- PTR_ERR(reg_8921_s4));
- return -ENODEV;
- }
- rc = regulator_set_voltage(reg_8921_s4, 1800000, 1800000);
- if (rc) {
- pr_err("set_voltage failed for 8921_s4, rc=%d\n", rc);
- return -EINVAL;
- }
- }
-
- if (on) {
- rc = regulator_set_optimum_mode(reg_8921_l23, 100000);
- if (rc < 0) {
- pr_err("set_optimum_mode l23 failed, rc=%d\n", rc);
- return -EINVAL;
- }
- rc = regulator_enable(reg_8921_l23);
- if (rc) {
- pr_err("'%s' regulator enable failed, rc=%d\n",
- "hdmi_avdd", rc);
- return rc;
- }
- rc = regulator_enable(reg_8921_s4);
- if (rc) {
- pr_err("'%s' regulator enable failed, rc=%d\n",
- "hdmi_vcc", rc);
- return rc;
- }
- rc = gpio_request(100, "HDMI_DDC_CLK");
- if (rc) {
- pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
- "HDMI_DDC_CLK", 100, rc);
- goto error1;
- }
- rc = gpio_request(101, "HDMI_DDC_DATA");
- if (rc) {
- pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
- "HDMI_DDC_DATA", 101, rc);
- goto error2;
- }
- rc = gpio_request(102, "HDMI_HPD");
- if (rc) {
- pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
- "HDMI_HPD", 102, rc);
- goto error3;
- }
- pr_debug("%s(on): success\n", __func__);
- } else {
- gpio_free(100);
- gpio_free(101);
- gpio_free(102);
-
- rc = regulator_disable(reg_8921_l23);
- if (rc) {
- pr_err("disable reg_8921_l23 failed, rc=%d\n", rc);
- return -ENODEV;
- }
- rc = regulator_disable(reg_8921_s4);
- if (rc) {
- pr_err("disable reg_8921_s4 failed, rc=%d\n", rc);
- return -ENODEV;
- }
- rc = regulator_set_optimum_mode(reg_8921_l23, 100);
- if (rc < 0) {
- pr_err("set_optimum_mode l23 failed, rc=%d\n", rc);
- return -EINVAL;
- }
- pr_debug("%s(off): success\n", __func__);
- }
-
- prev_on = on;
-
- return 0;
-
-error3:
- gpio_free(101);
-error2:
- gpio_free(100);
-error1:
- regulator_disable(reg_8921_l23);
- regulator_disable(reg_8921_s4);
- return rc;
-}
-
-static int hdmi_cec_power(int on)
-{
- static int prev_on;
- int rc;
-
- if (on == prev_on)
- return 0;
-
- if (on) {
- rc = gpio_request(99, "HDMI_CEC_VAR");
- if (rc) {
- pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
- "HDMI_CEC_VAR", 99, rc);
- goto error;
- }
- pr_debug("%s(on): success\n", __func__);
- } else {
- gpio_free(99);
- pr_debug("%s(off): success\n", __func__);
- }
-
- prev_on = on;
-
- return 0;
-error:
- return rc;
-}
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL */
-
-static void __init msm8960_allocate_memory_regions(void)
-{
- void *addr;
- unsigned long size;
-
- size = MSM_FB_SIZE;
- addr = alloc_bootmem_align(size, 0x1000);
- msm_fb_resources[0].start = __pa(addr);
- msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1;
- pr_info("allocating %lu bytes at %p (%lx physical) for fb\n",
- size, addr, __pa(addr));
-
-}
-#ifdef CONFIG_WCD9310_CODEC
-
-#define TABLA_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS + NR_PM8921_IRQS)
-
-/* Micbias setting is based on 8660 CDP/MTP/FLUID requirement
- * 4 micbiases are used to power various analog and digital
- * microphones operating at 1800 mV. Technically, all micbiases
- * can source from single cfilter since all microphones operate
- * at the same voltage level. The arrangement below is to make
- * sure all cfilters are exercised. LDO_H regulator ouput level
- * does not need to be as high as 2.85V. It is choosen for
- * microphone sensitivity purpose.
- */
-static struct tabla_pdata tabla_platform_data = {
- .slimbus_slave_device = {
- .name = "tabla-slave",
- .e_addr = {0, 0, 0x10, 0, 0x17, 2},
- },
- .irq = MSM_GPIO_TO_INT(62),
- .irq_base = TABLA_INTERRUPT_BASE,
- .num_irqs = NR_TABLA_IRQS,
- .reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
- .micbias = {
- .ldoh_v = TABLA_LDOH_2P85_V,
- .cfilt1_mv = 1800,
- .cfilt2_mv = 1800,
- .cfilt3_mv = 1800,
- .bias1_cfilt_sel = TABLA_CFILT1_SEL,
- .bias2_cfilt_sel = TABLA_CFILT2_SEL,
- .bias3_cfilt_sel = TABLA_CFILT3_SEL,
- .bias4_cfilt_sel = TABLA_CFILT3_SEL,
- }
-};
-
-static struct slim_device msm_slim_tabla = {
- .name = "tabla-slim",
- .e_addr = {0, 1, 0x10, 0, 0x17, 2},
- .dev = {
- .platform_data = &tabla_platform_data,
- },
-};
-
-static struct tabla_pdata tabla20_platform_data = {
- .slimbus_slave_device = {
- .name = "tabla-slave",
- .e_addr = {0, 0, 0x60, 0, 0x17, 2},
- },
- .irq = MSM_GPIO_TO_INT(62),
- .irq_base = TABLA_INTERRUPT_BASE,
- .num_irqs = NR_TABLA_IRQS,
- .reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
- .micbias = {
- .ldoh_v = TABLA_LDOH_2P85_V,
- .cfilt1_mv = 1800,
- .cfilt2_mv = 1800,
- .cfilt3_mv = 1800,
- .bias1_cfilt_sel = TABLA_CFILT1_SEL,
- .bias2_cfilt_sel = TABLA_CFILT2_SEL,
- .bias3_cfilt_sel = TABLA_CFILT3_SEL,
- .bias4_cfilt_sel = TABLA_CFILT3_SEL,
- }
-};
-
-static struct slim_device msm_slim_tabla20 = {
- .name = "tabla2x-slim",
- .e_addr = {0, 1, 0x60, 0, 0x17, 2},
- .dev = {
- .platform_data = &tabla20_platform_data,
- },
-};
-#endif
-
-static struct slim_boardinfo msm_slim_devices[] = {
-#ifdef CONFIG_WCD9310_CODEC
- {
- .bus_num = 1,
- .slim_slave = &msm_slim_tabla,
- },
- {
- .bus_num = 1,
- .slim_slave = &msm_slim_tabla20,
- },
-#endif
- /* add more slimbus slaves as needed */
-};
-
-#define MSM_WCNSS_PHYS 0x03000000
-#define MSM_WCNSS_SIZE 0x280000
-
-static struct resource resources_wcnss_wlan[] = {
- {
- .start = RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ,
- .end = RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ,
- .name = "wcnss_wlanrx_irq",
- .flags = IORESOURCE_IRQ,
- },
- {
- .start = RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ,
- .end = RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ,
- .name = "wcnss_wlantx_irq",
- .flags = IORESOURCE_IRQ,
- },
- {
- .start = MSM_WCNSS_PHYS,
- .end = MSM_WCNSS_PHYS + MSM_WCNSS_SIZE - 1,
- .name = "wcnss_mmio",
- .flags = IORESOURCE_MEM,
- },
- {
- .start = 84,
- .end = 88,
- .name = "wcnss_gpios_5wire",
- .flags = IORESOURCE_IO,
- },
-};
-
-static struct qcom_wcnss_opts qcom_wcnss_pdata = {
- .has_48mhz_xo = 1,
-};
-
-static struct platform_device msm_device_wcnss_wlan = {
- .name = "wcnss_wlan",
- .id = 0,
- .num_resources = ARRAY_SIZE(resources_wcnss_wlan),
- .resource = resources_wcnss_wlan,
- .dev = {.platform_data = &qcom_wcnss_pdata},
-};
-
-#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
- defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE) || \
- defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
- defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
-
-#define QCE_SIZE 0x10000
-#define QCE_0_BASE 0x18500000
-
-#define QCE_HW_KEY_SUPPORT 0
-#define QCE_SHA_HMAC_SUPPORT 1
-#define QCE_SHARE_CE_RESOURCE 1
-#define QCE_CE_SHARED 0
-
-static struct resource qcrypto_resources[] = {
- [0] = {
- .start = QCE_0_BASE,
- .end = QCE_0_BASE + QCE_SIZE - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .name = "crypto_channels",
- .start = DMOV_CE_IN_CHAN,
- .end = DMOV_CE_OUT_CHAN,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .name = "crypto_crci_in",
- .start = DMOV_CE_IN_CRCI,
- .end = DMOV_CE_IN_CRCI,
- .flags = IORESOURCE_DMA,
- },
- [3] = {
- .name = "crypto_crci_out",
- .start = DMOV_CE_OUT_CRCI,
- .end = DMOV_CE_OUT_CRCI,
- .flags = IORESOURCE_DMA,
- },
-};
-
-static struct resource qcedev_resources[] = {
- [0] = {
- .start = QCE_0_BASE,
- .end = QCE_0_BASE + QCE_SIZE - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .name = "crypto_channels",
- .start = DMOV_CE_IN_CHAN,
- .end = DMOV_CE_OUT_CHAN,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .name = "crypto_crci_in",
- .start = DMOV_CE_IN_CRCI,
- .end = DMOV_CE_IN_CRCI,
- .flags = IORESOURCE_DMA,
- },
- [3] = {
- .name = "crypto_crci_out",
- .start = DMOV_CE_OUT_CRCI,
- .end = DMOV_CE_OUT_CRCI,
- .flags = IORESOURCE_DMA,
- },
-};
-
-#endif
-
-#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
- defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
-
-static struct msm_ce_hw_support qcrypto_ce_hw_suppport = {
- .ce_shared = QCE_CE_SHARED,
- .shared_ce_resource = QCE_SHARE_CE_RESOURCE,
- .hw_key_support = QCE_HW_KEY_SUPPORT,
- .sha_hmac = QCE_SHA_HMAC_SUPPORT,
-};
-
-static struct platform_device qcrypto_device = {
- .name = "qcrypto",
- .id = 0,
- .num_resources = ARRAY_SIZE(qcrypto_resources),
- .resource = qcrypto_resources,
- .dev = {
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &qcrypto_ce_hw_suppport,
- },
-};
-#endif
-
-#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
- defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
-
-static struct msm_ce_hw_support qcedev_ce_hw_suppport = {
- .ce_shared = QCE_CE_SHARED,
- .shared_ce_resource = QCE_SHARE_CE_RESOURCE,
- .hw_key_support = QCE_HW_KEY_SUPPORT,
- .sha_hmac = QCE_SHA_HMAC_SUPPORT,
-};
-
-static struct platform_device qcedev_device = {
- .name = "qce",
- .id = 0,
- .num_resources = ARRAY_SIZE(qcedev_resources),
- .resource = qcedev_resources,
- .dev = {
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &qcedev_ce_hw_suppport,
- },
-};
-#endif
-
-
-static int __init gpiomux_init(void)
-{
- int rc;
-
- rc = msm_gpiomux_init(NR_GPIO_IRQS);
- if (rc) {
- pr_err(KERN_ERR "msm_gpiomux_init failed %d\n", rc);
- return rc;
- }
-
- msm_gpiomux_install(msm8960_cam_common_configs,
- ARRAY_SIZE(msm8960_cam_common_configs));
-
- msm_gpiomux_install(msm8960_gpiomux_configs,
- ARRAY_SIZE(msm8960_gpiomux_configs));
-
- msm_gpiomux_install(msm8960_gsbi_configs,
- ARRAY_SIZE(msm8960_gsbi_configs));
-
- msm_gpiomux_install(msm8960_cyts_configs,
- ARRAY_SIZE(msm8960_cyts_configs));
-
- msm_gpiomux_install(msm8960_slimbus_config,
- ARRAY_SIZE(msm8960_slimbus_config));
-
- msm_gpiomux_install(msm8960_audio_codec_configs,
- ARRAY_SIZE(msm8960_audio_codec_configs));
-
- msm_gpiomux_install(msm8960_audio_auxpcm_configs,
- ARRAY_SIZE(msm8960_audio_auxpcm_configs));
-
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
- msm_gpiomux_install(msm8960_hdmi_configs,
- ARRAY_SIZE(msm8960_hdmi_configs));
-#endif
-
- msm_gpiomux_install(msm8960_mdp_vsync_configs,
- ARRAY_SIZE(msm8960_mdp_vsync_configs));
-
- msm_gpiomux_install(wcnss_5wire_interface,
- ARRAY_SIZE(wcnss_5wire_interface));
-
- if (machine_is_msm8960_mtp() || machine_is_msm8960_fluid() ||
- machine_is_msm8960_liquid() || machine_is_msm8960_cdp())
- msm_gpiomux_install(hap_lvl_shft_config,
- ARRAY_SIZE(hap_lvl_shft_config));
- return 0;
-}
-
-#define MSM_SHARED_RAM_PHYS 0x80000000
-
-static struct pm8921_adc_amux pm8921_adc_channels_data[] = {
- {"vcoin", CHANNEL_VCOIN, CHAN_PATH_SCALING2, AMUX_RSV1,
- ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
- {"vbat", CHANNEL_VBAT, CHAN_PATH_SCALING2, AMUX_RSV1,
- ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
- {"dcin", CHANNEL_DCIN, CHAN_PATH_SCALING4, AMUX_RSV1,
- ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
- {"ichg", CHANNEL_ICHG, CHAN_PATH_SCALING1, AMUX_RSV1,
- ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
- {"vph_pwr", CHANNEL_VPH_PWR, CHAN_PATH_SCALING2, AMUX_RSV1,
- ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
- {"ibat", CHANNEL_IBAT, CHAN_PATH_SCALING1, AMUX_RSV1,
- ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
- {"batt_therm", CHANNEL_BATT_THERM, CHAN_PATH_SCALING1, AMUX_RSV2,
- ADC_DECIMATION_TYPE2, ADC_SCALE_BATT_THERM},
- {"batt_id", CHANNEL_BATT_ID, CHAN_PATH_SCALING1, AMUX_RSV1,
- ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
- {"usbin", CHANNEL_USBIN, CHAN_PATH_SCALING3, AMUX_RSV1,
- ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
- {"pmic_therm", CHANNEL_DIE_TEMP, CHAN_PATH_SCALING1, AMUX_RSV1,
- ADC_DECIMATION_TYPE2, ADC_SCALE_PMIC_THERM},
- {"625mv", CHANNEL_625MV, CHAN_PATH_SCALING1, AMUX_RSV1,
- ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
- {"125v", CHANNEL_125V, CHAN_PATH_SCALING1, AMUX_RSV1,
- ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
- {"chg_temp", CHANNEL_CHG_TEMP, CHAN_PATH_SCALING1, AMUX_RSV1,
- ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
- {"pa_therm1", ADC_MPP_1_AMUX8, CHAN_PATH_SCALING1, AMUX_RSV1,
- ADC_DECIMATION_TYPE2, ADC_SCALE_PA_THERM},
- {"xo_therm", CHANNEL_MUXOFF, CHAN_PATH_SCALING1, AMUX_RSV0,
- ADC_DECIMATION_TYPE2, ADC_SCALE_XOTHERM},
- {"pa_therm0", ADC_MPP_1_AMUX3, CHAN_PATH_SCALING1, AMUX_RSV1,
- ADC_DECIMATION_TYPE2, ADC_SCALE_PA_THERM},
-};
-
-static struct pm8921_adc_properties pm8921_adc_data = {
- .adc_vdd_reference = 1800, /* milli-voltage for this adc */
- .bitresolution = 15,
- .bipolar = 0,
-};
-
-static struct pm8921_adc_platform_data pm8921_adc_pdata = {
- .adc_channel = pm8921_adc_channels_data,
- .adc_num_board_channel = ARRAY_SIZE(pm8921_adc_channels_data),
- .adc_prop = &pm8921_adc_data,
- .adc_mpp_base = PM8921_MPP_PM_TO_SYS(1),
-};
-
-static void __init msm8960_map_io(void)
-{
- msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
- msm_map_msm8960_io();
-
- if (socinfo_init() < 0)
- pr_err("socinfo_init() failed!\n");
-}
-
-#ifdef CONFIG_ARCH_MSM8930
-static void __init msm8930_map_io(void)
-{
- msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
- msm_map_msm8930_io();
-
- if (socinfo_init() < 0)
- pr_err("socinfo_init() failed!\n");
-}
-#endif
-
-static void __init msm8960_init_irq(void)
-{
- unsigned int i;
-
- msm_mpm_irq_extn_init();
- gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
- (void *)MSM_QGIC_CPU_BASE);
-
- /* Edge trigger PPIs except AVS_SVICINT and AVS_SVICINTSWDONE */
- writel_relaxed(0xFFFFD7FF, MSM_QGIC_DIST_BASE + GIC_DIST_CONFIG + 4);
-
- writel_relaxed(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
- mb();
-
- /* FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
- * as they are configured as level, which does not play nice with
- * handle_percpu_irq.
- */
- for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
- if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
- irq_set_handler(i, handle_percpu_irq);
- }
-}
-
-/* MSM8960 has 5 SDCC controllers */
-enum sdcc_controllers {
- SDCC1,
- SDCC2,
- SDCC3,
- SDCC4,
- SDCC5,
- MAX_SDCC_CONTROLLER
-};
-
-/* All SDCC controllers require VDD/VCC voltage */
-static struct msm_mmc_reg_data mmc_vdd_reg_data[MAX_SDCC_CONTROLLER] = {
- /* SDCC1 : eMMC card connected */
- [SDCC1] = {
- .name = "sdc_vdd",
- .high_vol_level = 2950000,
- .low_vol_level = 2950000,
- .always_on = 1,
- .lpm_sup = 1,
- .lpm_uA = 9000,
- .hpm_uA = 200000, /* 200mA */
- },
- /* SDCC3 : External card slot connected */
- [SDCC3] = {
- .name = "sdc_vdd",
- .high_vol_level = 2950000,
- .low_vol_level = 2950000,
- .hpm_uA = 600000, /* 600mA */
- }
-};
-
-/* Only slots having eMMC card will require VCCQ voltage */
-static struct msm_mmc_reg_data mmc_vccq_reg_data[1] = {
- /* SDCC1 : eMMC card connected */
- [SDCC1] = {
- .name = "sdc_vccq",
- .always_on = 1,
- .high_vol_level = 1800000,
- .low_vol_level = 1800000,
- .hpm_uA = 200000, /* 200mA */
- }
-};
-
-/* All SDCC controllers may require voting for VDD PAD voltage */
-static struct msm_mmc_reg_data mmc_vddp_reg_data[MAX_SDCC_CONTROLLER] = {
- /* SDCC3 : External card slot connected */
- [SDCC3] = {
- .name = "sdc_vddp",
- .high_vol_level = 2950000,
- .low_vol_level = 1850000,
- .always_on = 1,
- .lpm_sup = 1,
- /* Max. Active current required is 16 mA */
- .hpm_uA = 16000,
- /*
- * Sleep current required is ~300 uA. But min. vote can be
- * in terms of mA (min. 1 mA). So let's vote for 2 mA
- * during sleep.
- */
- .lpm_uA = 2000,
- }
-};
-
-static struct msm_mmc_slot_reg_data mmc_slot_vreg_data[MAX_SDCC_CONTROLLER] = {
- /* SDCC1 : eMMC card connected */
- [SDCC1] = {
- .vdd_data = &mmc_vdd_reg_data[SDCC1],
- .vccq_data = &mmc_vccq_reg_data[SDCC1],
- },
- /* SDCC3 : External card slot connected */
- [SDCC3] = {
- .vdd_data = &mmc_vdd_reg_data[SDCC3],
- .vddp_data = &mmc_vddp_reg_data[SDCC3],
- }
-};
-
-/* SDC1 pad data */
-static struct msm_mmc_pad_drv sdc1_pad_drv_on_cfg[] = {
- {TLMM_HDRV_SDC1_CLK, GPIO_CFG_16MA},
- {TLMM_HDRV_SDC1_CMD, GPIO_CFG_10MA},
- {TLMM_HDRV_SDC1_DATA, GPIO_CFG_10MA}
-};
-
-static struct msm_mmc_pad_drv sdc1_pad_drv_off_cfg[] = {
- {TLMM_HDRV_SDC1_CLK, GPIO_CFG_2MA},
- {TLMM_HDRV_SDC1_CMD, GPIO_CFG_2MA},
- {TLMM_HDRV_SDC1_DATA, GPIO_CFG_2MA}
-};
-
-static struct msm_mmc_pad_pull sdc1_pad_pull_on_cfg[] = {
- {TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
- {TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_UP},
- {TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_UP}
-};
-
-static struct msm_mmc_pad_pull sdc1_pad_pull_off_cfg[] = {
- {TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
- {TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_DOWN},
- {TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_DOWN}
-};
-
-/* SDC3 pad data */
-static struct msm_mmc_pad_drv sdc3_pad_drv_on_cfg[] = {
- {TLMM_HDRV_SDC3_CLK, GPIO_CFG_8MA},
- {TLMM_HDRV_SDC3_CMD, GPIO_CFG_8MA},
- {TLMM_HDRV_SDC3_DATA, GPIO_CFG_8MA}
-};
-
-static struct msm_mmc_pad_drv sdc3_pad_drv_off_cfg[] = {
- {TLMM_HDRV_SDC3_CLK, GPIO_CFG_2MA},
- {TLMM_HDRV_SDC3_CMD, GPIO_CFG_2MA},
- {TLMM_HDRV_SDC3_DATA, GPIO_CFG_2MA}
-};
-
-static struct msm_mmc_pad_pull sdc3_pad_pull_on_cfg[] = {
- {TLMM_PULL_SDC3_CLK, GPIO_CFG_NO_PULL},
- {TLMM_PULL_SDC3_CMD, GPIO_CFG_PULL_UP},
- {TLMM_PULL_SDC3_DATA, GPIO_CFG_PULL_UP}
-};
-
-static struct msm_mmc_pad_pull sdc3_pad_pull_off_cfg[] = {
- {TLMM_PULL_SDC3_CLK, GPIO_CFG_NO_PULL},
- /*
- * SDC3 CMD line should be PULLed UP otherwise fluid platform will
- * see transitions (1 -> 0 and 0 -> 1) on card detection line,
- * which would result in false card detection interrupts.
- */
- {TLMM_PULL_SDC3_CMD, GPIO_CFG_PULL_UP},
- /*
- * Keeping DATA lines status to PULL UP will make sure that
- * there is no current leak during sleep if external pull up
- * is connected to DATA lines.
- */
- {TLMM_PULL_SDC3_DATA, GPIO_CFG_PULL_UP}
-};
-
-struct msm_mmc_pad_pull_data mmc_pad_pull_data[MAX_SDCC_CONTROLLER] = {
- [SDCC1] = {
- .on = sdc1_pad_pull_on_cfg,
- .off = sdc1_pad_pull_off_cfg,
- .size = ARRAY_SIZE(sdc1_pad_pull_on_cfg)
- },
- [SDCC3] = {
- .on = sdc3_pad_pull_on_cfg,
- .off = sdc3_pad_pull_off_cfg,
- .size = ARRAY_SIZE(sdc3_pad_pull_on_cfg)
- },
-};
-
-struct msm_mmc_pad_drv_data mmc_pad_drv_data[MAX_SDCC_CONTROLLER] = {
- [SDCC1] = {
- .on = sdc1_pad_drv_on_cfg,
- .off = sdc1_pad_drv_off_cfg,
- .size = ARRAY_SIZE(sdc1_pad_drv_on_cfg)
- },
- [SDCC3] = {
- .on = sdc3_pad_drv_on_cfg,
- .off = sdc3_pad_drv_off_cfg,
- .size = ARRAY_SIZE(sdc3_pad_drv_on_cfg)
- },
-};
-
-struct msm_mmc_pad_data mmc_pad_data[MAX_SDCC_CONTROLLER] = {
- [SDCC1] = {
- .pull = &mmc_pad_pull_data[SDCC1],
- .drv = &mmc_pad_drv_data[SDCC1]
- },
- [SDCC3] = {
- .pull = &mmc_pad_pull_data[SDCC3],
- .drv = &mmc_pad_drv_data[SDCC3]
- },
-};
-
-struct msm_mmc_pin_data mmc_slot_pin_data[MAX_SDCC_CONTROLLER] = {
- [SDCC1] = {
- .pad_data = &mmc_pad_data[SDCC1],
- },
- [SDCC3] = {
- .pad_data = &mmc_pad_data[SDCC3],
- },
-};
-
-static unsigned int sdc1_sup_clk_rates[] = {
- 400000, 24000000, 48000000
-};
-
-static unsigned int sdc3_sup_clk_rates[] = {
- 400000, 24000000, 48000000, 96000000
-};
-
-#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
-static struct mmc_platform_data msm8960_sdc1_data = {
- .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
-#ifdef CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT
- .mmc_bus_width = MMC_CAP_8_BIT_DATA,
-#else
- .mmc_bus_width = MMC_CAP_4_BIT_DATA,
-#endif
- .sup_clk_table = sdc1_sup_clk_rates,
- .sup_clk_cnt = ARRAY_SIZE(sdc1_sup_clk_rates),
- .pclk_src_dfab = 1,
- .nonremovable = 1,
- .vreg_data = &mmc_slot_vreg_data[SDCC1],
- .pin_data = &mmc_slot_pin_data[SDCC1]
-};
-#endif
-
-#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
-static struct mmc_platform_data msm8960_sdc3_data = {
- .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
- .mmc_bus_width = MMC_CAP_4_BIT_DATA,
- .sup_clk_table = sdc3_sup_clk_rates,
- .sup_clk_cnt = ARRAY_SIZE(sdc3_sup_clk_rates),
- .pclk_src_dfab = 1,
-#ifdef CONFIG_MMC_MSM_SDC3_WP_SUPPORT
- .wpswitch_gpio = PM8921_GPIO_PM_TO_SYS(16),
-#endif
- .vreg_data = &mmc_slot_vreg_data[SDCC3],
- .pin_data = &mmc_slot_pin_data[SDCC3],
-#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
- .status_gpio = PM8921_GPIO_PM_TO_SYS(26),
- .status_irq = PM8921_GPIO_IRQ(PM8921_IRQ_BASE, 26),
- .irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-#endif
- .xpc_cap = 1,
- .uhs_caps = (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 |
- MMC_CAP_MAX_CURRENT_600)
-};
-#endif
-
-static void __init msm8960_init_mmc(void)
-{
-#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
- /* SDC1 : eMMC card connected */
- msm_add_sdcc(1, &msm8960_sdc1_data);
-#endif
-#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
- /* SDC3: External card slot */
- msm_add_sdcc(3, &msm8960_sdc3_data);
-#endif
-}
-
-static void __init msm8960_init_buses(void)
-{
-#ifdef CONFIG_MSM_BUS_SCALING
- msm_bus_rpm_set_mt_mask();
- msm_bus_8960_apps_fabric_pdata.rpm_enabled = 1;
- msm_bus_8960_sys_fabric_pdata.rpm_enabled = 1;
- msm_bus_8960_mm_fabric_pdata.rpm_enabled = 1;
- msm_bus_apps_fabric.dev.platform_data =
- &msm_bus_8960_apps_fabric_pdata;
- msm_bus_sys_fabric.dev.platform_data = &msm_bus_8960_sys_fabric_pdata;
- msm_bus_mm_fabric.dev.platform_data = &msm_bus_8960_mm_fabric_pdata;
- msm_bus_sys_fpb.dev.platform_data = &msm_bus_8960_sys_fpb_pdata;
- msm_bus_cpss_fpb.dev.platform_data = &msm_bus_8960_cpss_fpb_pdata;
-#endif
-}
-
-static struct msm_spi_platform_data msm8960_qup_spi_gsbi1_pdata = {
- .max_clock_speed = 15060000,
-};
-
-#ifdef CONFIG_USB_MSM_OTG_72K
-static struct msm_otg_platform_data msm_otg_pdata;
-#else
-#define USB_5V_EN 42
-static void msm_hsusb_vbus_power(bool on)
-{
- int rc;
- static bool vbus_is_on;
- static struct regulator *mvs_otg_switch;
-
- if (vbus_is_on == on)
- return;
-
- if (on) {
- mvs_otg_switch = regulator_get(&msm8960_device_otg.dev,
- "vbus_otg");
- if (IS_ERR(mvs_otg_switch)) {
- pr_err("Unable to get mvs_otg_switch\n");
- return;
- }
-
- rc = gpio_request(PM8921_GPIO_PM_TO_SYS(USB_5V_EN),
- "usb_5v_en");
- if (rc < 0) {
- pr_err("failed to request usb_5v_en gpio\n");
- goto put_mvs_otg;
- }
-
- rc = gpio_direction_output(PM8921_GPIO_PM_TO_SYS(USB_5V_EN), 1);
- if (rc) {
- pr_err("%s: unable to set_direction for gpio [%d]\n",
- __func__, PM8921_GPIO_PM_TO_SYS(USB_5V_EN));
- goto free_usb_5v_en;
- }
-
- if (regulator_enable(mvs_otg_switch)) {
- pr_err("unable to enable mvs_otg_switch\n");
- goto err_ldo_gpio_set_dir;
- }
-
- vbus_is_on = true;
- return;
- }
- regulator_disable(mvs_otg_switch);
-err_ldo_gpio_set_dir:
- gpio_set_value(PM8921_GPIO_PM_TO_SYS(USB_5V_EN), 0);
-free_usb_5v_en:
- gpio_free(PM8921_GPIO_PM_TO_SYS(USB_5V_EN));
-put_mvs_otg:
- regulator_put(mvs_otg_switch);
- vbus_is_on = false;
-}
-
-static struct msm_otg_platform_data msm_otg_pdata = {
- .mode = USB_OTG,
- .otg_control = OTG_PMIC_CONTROL,
- .phy_type = SNPS_28NM_INTEGRATED_PHY,
- .pclk_src_name = "dfab_usb_hs_clk",
- .pmic_id_irq = PM8921_USB_ID_IN_IRQ(PM8921_IRQ_BASE),
- .vbus_power = msm_hsusb_vbus_power,
- .power_budget = 750,
-};
-#endif
-
-#ifdef CONFIG_USB_EHCI_MSM_HSIC
-#define HSIC_HUB_RESET_GPIO 91
-static struct msm_hsic_host_platform_data msm_hsic_pdata = {
- .strobe = 150,
- .data = 151,
-};
-#else
-static struct msm_hsic_host_platform_data msm_hsic_pdata;
-#endif
-
-#define PID_MAGIC_ID 0x71432909
-#define SERIAL_NUM_MAGIC_ID 0x61945374
-#define SERIAL_NUMBER_LENGTH 127
-#define DLOAD_USB_BASE_ADD 0x2A03F0C8
-
-struct magic_num_struct {
- uint32_t pid;
- uint32_t serial_num;
-};
-
-struct dload_struct {
- uint32_t reserved1;
- uint32_t reserved2;
- uint32_t reserved3;
- uint16_t reserved4;
- uint16_t pid;
- char serial_number[SERIAL_NUMBER_LENGTH];
- uint16_t reserved5;
- struct magic_num_struct magic_struct;
-};
-
-static int usb_diag_update_pid_and_serial_num(uint32_t pid, const char *snum)
-{
- struct dload_struct __iomem *dload = 0;
-
- dload = ioremap(DLOAD_USB_BASE_ADD, sizeof(*dload));
- if (!dload) {
- pr_err("%s: cannot remap I/O memory region: %08x\n",
- __func__, DLOAD_USB_BASE_ADD);
- return -ENXIO;
- }
-
- pr_debug("%s: dload:%p pid:%x serial_num:%s\n",
- __func__, dload, pid, snum);
- /* update pid */
- dload->magic_struct.pid = PID_MAGIC_ID;
- dload->pid = pid;
-
- /* update serial number */
- dload->magic_struct.serial_num = 0;
- if (!snum) {
- memset(dload->serial_number, 0, SERIAL_NUMBER_LENGTH);
- goto out;
- }
-
- dload->magic_struct.serial_num = SERIAL_NUM_MAGIC_ID;
- strlcpy(dload->serial_number, snum, SERIAL_NUMBER_LENGTH);
-out:
- iounmap(dload);
- return 0;
-}
-
-static struct android_usb_platform_data android_usb_pdata = {
- .update_pid_and_serial_num = usb_diag_update_pid_and_serial_num,
-};
-
-static struct platform_device android_usb_device = {
- .name = "android_usb",
- .id = -1,
- .dev = {
- .platform_data = &android_usb_pdata,
- },
-};
-
-static uint8_t spm_wfi_cmd_sequence[] __initdata = {
- 0x03, 0x0f,
-};
-
-static uint8_t spm_power_collapse_without_rpm[] __initdata = {
- 0x00, 0x24, 0x54, 0x10,
- 0x09, 0x03, 0x01,
- 0x10, 0x54, 0x30, 0x0C,
- 0x24, 0x30, 0x0f,
-};
-
-static uint8_t spm_power_collapse_with_rpm[] __initdata = {
- 0x00, 0x24, 0x54, 0x10,
- 0x09, 0x07, 0x01, 0x0B,
- 0x10, 0x54, 0x30, 0x0C,
- 0x24, 0x30, 0x0f,
-};
-
-static struct msm_spm_seq_entry msm_spm_seq_list[] __initdata = {
- [0] = {
- .mode = MSM_SPM_MODE_CLOCK_GATING,
- .notify_rpm = false,
- .cmd = spm_wfi_cmd_sequence,
- },
- [1] = {
- .mode = MSM_SPM_MODE_POWER_COLLAPSE,
- .notify_rpm = false,
- .cmd = spm_power_collapse_without_rpm,
- },
- [2] = {
- .mode = MSM_SPM_MODE_POWER_COLLAPSE,
- .notify_rpm = true,
- .cmd = spm_power_collapse_with_rpm,
- },
-};
-
-static struct msm_spm_platform_data msm_spm_data[] __initdata = {
- [0] = {
- .reg_base_addr = MSM_SAW0_BASE,
- .reg_init_values[MSM_SPM_REG_SAW2_SECURE] = 0x00,
- .reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
- .reg_init_values[MSM_SPM_REG_SAW2_VCTL] = 0x9C,
-#if defined(CONFIG_MSM_AVS_HW)
- .reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x00,
- .reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
-#endif
- .reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
- .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020202,
- .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
- .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
- .vctl_timeout_us = 50,
- .num_modes = ARRAY_SIZE(msm_spm_seq_list),
- .modes = msm_spm_seq_list,
- },
- [1] = {
- .reg_base_addr = MSM_SAW1_BASE,
- .reg_init_values[MSM_SPM_REG_SAW2_SECURE] = 0x00,
- .reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
- .reg_init_values[MSM_SPM_REG_SAW2_VCTL] = 0x9C,
-#if defined(CONFIG_MSM_AVS_HW)
- .reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x00,
- .reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
-#endif
- .reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
- .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020202,
- .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
- .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
- .vctl_timeout_us = 50,
- .num_modes = ARRAY_SIZE(msm_spm_seq_list),
- .modes = msm_spm_seq_list,
- },
-};
-
-static uint8_t l2_spm_wfi_cmd_sequence[] __initdata = {
- 0x00, 0x20, 0x03, 0x20,
- 0x00, 0x0f,
-};
-
-static uint8_t l2_spm_gdhs_cmd_sequence[] __initdata = {
- 0x00, 0x20, 0x34, 0x64,
- 0x48, 0x07, 0x48, 0x20,
- 0x50, 0x64, 0x04, 0x34,
- 0x50, 0x0f,
-};
-static uint8_t l2_spm_power_off_cmd_sequence[] __initdata = {
- 0x00, 0x10, 0x34, 0x64,
- 0x48, 0x07, 0x48, 0x10,
- 0x50, 0x64, 0x04, 0x34,
- 0x50, 0x0F,
-};
-
-static struct msm_spm_seq_entry msm_spm_l2_seq_list[] __initdata = {
- [0] = {
- .mode = MSM_SPM_L2_MODE_RETENTION,
- .notify_rpm = false,
- .cmd = l2_spm_wfi_cmd_sequence,
- },
- [1] = {
- .mode = MSM_SPM_L2_MODE_GDHS,
- .notify_rpm = true,
- .cmd = l2_spm_gdhs_cmd_sequence,
- },
- [2] = {
- .mode = MSM_SPM_L2_MODE_POWER_COLLAPSE,
- .notify_rpm = true,
- .cmd = l2_spm_power_off_cmd_sequence,
- },
-};
-
-
-static struct msm_spm_platform_data msm_spm_l2_data[] __initdata = {
- [0] = {
- .reg_base_addr = MSM_SAW_L2_BASE,
- .reg_init_values[MSM_SPM_REG_SAW2_SECURE] = 0x00,
- .reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x00,
- .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020202,
- .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x00A000AE,
- .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x00A00020,
- .modes = msm_spm_l2_seq_list,
- .num_modes = ARRAY_SIZE(msm_spm_l2_seq_list),
- },
-};
-
-#define PM_HAP_EN_GPIO PM8921_GPIO_PM_TO_SYS(33)
-#define PM_HAP_LEN_GPIO PM8921_GPIO_PM_TO_SYS(20)
-
-static struct msm_xo_voter *xo_handle_d1;
-
-static int isa1200_power(int on)
-{
- int rc = 0;
-
- gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !!on);
-
- rc = on ? msm_xo_mode_vote(xo_handle_d1, MSM_XO_MODE_ON) :
- msm_xo_mode_vote(xo_handle_d1, MSM_XO_MODE_OFF);
- if (rc < 0) {
- pr_err("%s: failed to %svote for TCXO D1 buffer%d\n",
- __func__, on ? "" : "de-", rc);
- goto err_xo_vote;
- }
-
- return 0;
-
-err_xo_vote:
- gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !on);
- return rc;
-}
-
-static int isa1200_dev_setup(bool enable)
-{
- int rc = 0;
-
- struct pm_gpio hap_gpio_config = {
- .direction = PM_GPIO_DIR_OUT,
- .pull = PM_GPIO_PULL_NO,
- .out_strength = PM_GPIO_STRENGTH_HIGH,
- .function = PM_GPIO_FUNC_NORMAL,
- .inv_int_pol = 0,
- .vin_sel = 2,
- .output_buffer = PM_GPIO_OUT_BUF_CMOS,
- .output_value = 0,
- };
-
- if (enable == true) {
- rc = pm8xxx_gpio_config(PM_HAP_EN_GPIO, &hap_gpio_config);
- if (rc) {
- pr_err("%s: pm8921 gpio %d config failed(%d)\n",
- __func__, PM_HAP_EN_GPIO, rc);
- return rc;
- }
-
- rc = pm8xxx_gpio_config(PM_HAP_LEN_GPIO, &hap_gpio_config);
- if (rc) {
- pr_err("%s: pm8921 gpio %d config failed(%d)\n",
- __func__, PM_HAP_LEN_GPIO, rc);
- return rc;
- }
-
- rc = gpio_request(HAP_SHIFT_LVL_OE_GPIO, "hap_shft_lvl_oe");
- if (rc) {
- pr_err("%s: unable to request gpio %d (%d)\n",
- __func__, HAP_SHIFT_LVL_OE_GPIO, rc);
- return rc;
- }
-
- rc = gpio_direction_output(HAP_SHIFT_LVL_OE_GPIO, 0);
- if (rc) {
- pr_err("%s: Unable to set direction\n", __func__);
- goto free_gpio;
- }
-
- xo_handle_d1 = msm_xo_get(MSM_XO_TCXO_D1, "isa1200");
- if (IS_ERR(xo_handle_d1)) {
- rc = PTR_ERR(xo_handle_d1);
- pr_err("%s: failed to get the handle for D1(%d)\n",
- __func__, rc);
- goto gpio_set_dir;
- }
- } else {
- gpio_free(HAP_SHIFT_LVL_OE_GPIO);
-
- msm_xo_put(xo_handle_d1);
- }
-
- return 0;
-
-gpio_set_dir:
- gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, 0);
-free_gpio:
- gpio_free(HAP_SHIFT_LVL_OE_GPIO);
- return rc;
-}
-
-static struct isa1200_regulator isa1200_reg_data[] = {
- {
- .name = "vcc_i2c",
- .min_uV = ISA_I2C_VTG_MIN_UV,
- .max_uV = ISA_I2C_VTG_MAX_UV,
- .load_uA = ISA_I2C_CURR_UA,
- },
-};
-
-static struct isa1200_platform_data isa1200_1_pdata = {
- .name = "vibrator",
- .dev_setup = isa1200_dev_setup,
- .power_on = isa1200_power,
- .hap_en_gpio = PM_HAP_EN_GPIO,
- .hap_len_gpio = PM_HAP_LEN_GPIO,
- .max_timeout = 15000,
- .mode_ctrl = PWM_GEN_MODE,
- .pwm_fd = {
- .pwm_div = 256,
- },
- .is_erm = false,
- .smart_en = true,
- .ext_clk_en = true,
- .chip_en = 1,
- .regulator_info = isa1200_reg_data,
- .num_regulators = ARRAY_SIZE(isa1200_reg_data),
-};
-
-static struct i2c_board_info msm_isa1200_board_info[] __initdata = {
- {
- I2C_BOARD_INFO("isa1200_1", 0x90>>1),
- .platform_data = &isa1200_1_pdata,
- },
-};
-
-#define CYTTSP_TS_GPIO_IRQ 11
-#define CYTTSP_TS_SLEEP_GPIO 50
-#define CYTTSP_TS_RESOUT_N_GPIO 52
-
-/*virtual key support */
-static ssize_t tma340_vkeys_show(struct kobject *kobj,
- struct kobj_attribute *attr, char *buf)
-{
- return snprintf(buf, 200,
- __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":73:1120:97:97"
- ":" __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":230:1120:97:97"
- ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":389:1120:97:97"
- ":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":544:1120:97:97"
- "\n");
-}
-
-static struct kobj_attribute tma340_vkeys_attr = {
- .attr = {
- .mode = S_IRUGO,
- },
- .show = &tma340_vkeys_show,
-};
-
-static struct attribute *tma340_properties_attrs[] = {
- &tma340_vkeys_attr.attr,
- NULL
-};
-
-static struct attribute_group tma340_properties_attr_group = {
- .attrs = tma340_properties_attrs,
-};
-
-
-static int cyttsp_platform_init(struct i2c_client *client)
-{
- int rc = 0;
- static struct kobject *tma340_properties_kobj;
-
- tma340_vkeys_attr.attr.name = "virtualkeys.cyttsp-i2c";
- tma340_properties_kobj = kobject_create_and_add("board_properties",
- NULL);
- if (tma340_properties_kobj)
- rc = sysfs_create_group(tma340_properties_kobj,
- &tma340_properties_attr_group);
- if (!tma340_properties_kobj || rc)
- pr_err("%s: failed to create board_properties\n",
- __func__);
-
- return 0;
-}
-
-static struct cyttsp_regulator regulator_data[] = {
- {
- .name = "vdd",
- .min_uV = CY_TMA300_VTG_MIN_UV,
- .max_uV = CY_TMA300_VTG_MAX_UV,
- .hpm_load_uA = CY_TMA300_CURR_24HZ_UA,
- .lpm_load_uA = CY_TMA300_SLEEP_CURR_UA,
- },
- /* TODO: Remove after runtime PM is enabled in I2C driver */
- {
- .name = "vcc_i2c",
- .min_uV = CY_I2C_VTG_MIN_UV,
- .max_uV = CY_I2C_VTG_MAX_UV,
- .hpm_load_uA = CY_I2C_CURR_UA,
- .lpm_load_uA = CY_I2C_SLEEP_CURR_UA,
- },
-};
-
-static struct cyttsp_platform_data cyttsp_pdata = {
- .panel_maxx = 634,
- .panel_maxy = 1166,
- .disp_maxx = 616,
- .disp_maxy = 1023,
- .disp_minx = 0,
- .disp_miny = 16,
- .flags = 0x01,
- .gen = CY_GEN3, /* or */
- .use_st = CY_USE_ST,
- .use_mt = CY_USE_MT,
- .use_hndshk = CY_SEND_HNDSHK,
- .use_trk_id = CY_USE_TRACKING_ID,
- .use_sleep = CY_USE_DEEP_SLEEP_SEL | CY_USE_LOW_POWER_SEL,
- .use_gestures = CY_USE_GESTURES,
- .fw_fname = "cyttsp_8960_cdp.hex",
- /* activate up to 4 groups
- * and set active distance
- */
- .gest_set = CY_GEST_GRP1 | CY_GEST_GRP2 |
- CY_GEST_GRP3 | CY_GEST_GRP4 |
- CY_ACT_DIST,
- /* change act_intrvl to customize the Active power state
- * scanning/processing refresh interval for Operating mode
- */
- .act_intrvl = CY_ACT_INTRVL_DFLT,
- /* change tch_tmout to customize the touch timeout for the
- * Active power state for Operating mode
- */
- .tch_tmout = CY_TCH_TMOUT_DFLT,
- /* change lp_intrvl to customize the Low Power power state
- * scanning/processing refresh interval for Operating mode
- */
- .lp_intrvl = CY_LP_INTRVL_DFLT,
- .sleep_gpio = CYTTSP_TS_SLEEP_GPIO,
- .resout_gpio = CYTTSP_TS_RESOUT_N_GPIO,
- .irq_gpio = CYTTSP_TS_GPIO_IRQ,
- .regulator_info = regulator_data,
- .num_regulators = ARRAY_SIZE(regulator_data),
- .init = cyttsp_platform_init,
- .correct_fw_ver = 9,
-};
-
-static struct i2c_board_info cyttsp_info[] __initdata = {
- {
- I2C_BOARD_INFO(CY_I2C_NAME, 0x24),
- .platform_data = &cyttsp_pdata,
-#ifndef CY_USE_TIMER
- .irq = MSM_GPIO_TO_INT(CYTTSP_TS_GPIO_IRQ),
-#endif /* CY_USE_TIMER */
- },
-};
-
-/* configuration data */
-static const u8 mxt_config_data[] = {
- /* T6 Object */
- 0, 0, 0, 0, 0, 0,
- /* T38 Object */
- 11, 1, 0, 20, 10, 11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- /* T7 Object */
- 100, 16, 50,
- /* T8 Object */
- 8, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* T9 Object */
- 131, 0, 0, 26, 42, 0, 32, 60, 2, 5,
- 0, 5, 5, 34, 10, 10, 10, 10, 255, 2,
- 85, 5, 18, 18, 18, 18, 0, 0, 5, 20,
- 0, 5, 45, 46,
- /* T15 Object */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,
- /* T22 Object */
- 0, 0, 0, 0, 0, 0, 0, 0, 30, 0,
- 0, 0, 255, 255, 255, 255, 0,
- /* T24 Object */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* T25 Object */
- 3, 0, 188, 52, 52, 33, 0, 0, 0, 0,
- 0, 0, 0, 0,
- /* T27 Object */
- 0, 0, 0, 0, 0, 0, 0,
- /* T28 Object */
- 0, 0, 0, 8, 8, 60,
- /* T40 Object */
- 0, 0, 0, 0, 0,
- /* T41 Object */
- 0, 0, 0, 0, 0, 0,
- /* T43 Object */
- 0, 0, 0, 0, 0, 0,
-};
-
-#define MXT_TS_GPIO_IRQ 11
-#define MXT_TS_LDO_EN_GPIO 50
-#define MXT_TS_RESET_GPIO 52
-
-static void mxt_init_hw_liquid(void)
-{
- int rc;
-
- rc = gpio_request(MXT_TS_GPIO_IRQ, "mxt_ts_irq_gpio");
- if (rc) {
- pr_err("%s: unable to request mxt_ts_irq gpio [%d]\n",
- __func__, MXT_TS_GPIO_IRQ);
- return;
- }
-
- rc = gpio_direction_input(MXT_TS_GPIO_IRQ);
- if (rc) {
- pr_err("%s: unable to set_direction for mxt_ts_irq gpio [%d]\n",
- __func__, MXT_TS_GPIO_IRQ);
- goto err_irq_gpio_req;
- }
-
- rc = gpio_request(MXT_TS_LDO_EN_GPIO, "mxt_ldo_en_gpio");
- if (rc) {
- pr_err("%s: unable to request mxt_ldo_en gpio [%d]\n",
- __func__, MXT_TS_LDO_EN_GPIO);
- goto err_irq_gpio_req;
- }
-
- rc = gpio_direction_output(MXT_TS_LDO_EN_GPIO, 1);
- if (rc) {
- pr_err("%s: unable to set_direction for mxt_ldo_en gpio [%d]\n",
- __func__, MXT_TS_LDO_EN_GPIO);
- goto err_ldo_gpio_req;
- }
-
- rc = gpio_request(MXT_TS_RESET_GPIO, "mxt_reset_gpio");
- if (rc) {
- pr_err("%s: unable to request mxt_reset gpio [%d]\n",
- __func__, MXT_TS_RESET_GPIO);
- goto err_ldo_gpio_set_dir;
- }
-
- rc = gpio_direction_output(MXT_TS_RESET_GPIO, 1);
- if (rc) {
- pr_err("%s: unable to set_direction for mxt_reset gpio [%d]\n",
- __func__, MXT_TS_RESET_GPIO);
- goto err_reset_gpio_req;
- }
-
- return;
-
-err_reset_gpio_req:
- gpio_free(MXT_TS_RESET_GPIO);
-err_ldo_gpio_set_dir:
- gpio_set_value(MXT_TS_LDO_EN_GPIO, 0);
-err_ldo_gpio_req:
- gpio_free(MXT_TS_LDO_EN_GPIO);
-err_irq_gpio_req:
- gpio_free(MXT_TS_GPIO_IRQ);
-}
-
-static struct mxt_platform_data mxt_platform_data = {
- .config = mxt_config_data,
- .config_length = ARRAY_SIZE(mxt_config_data),
- .x_size = 1365,
- .y_size = 767,
- .irqflags = IRQF_TRIGGER_FALLING,
- .i2c_pull_up = true,
-};
-
-static struct i2c_board_info mxt_device_info[] __initdata = {
- {
- I2C_BOARD_INFO("atmel_mxt_ts", 0x5b),
- .platform_data = &mxt_platform_data,
- .irq = MSM_GPIO_TO_INT(MXT_TS_GPIO_IRQ),
- },
-};
-
-static void gsbi_qup_i2c_gpio_config(int adap_id, int config_type)
-{
-}
-
-static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi4_pdata = {
- .clk_freq = 100000,
- .src_clk_rate = 24000000,
- .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
-};
-
-static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi3_pdata = {
- .clk_freq = 100000,
- .src_clk_rate = 24000000,
- .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
-};
-
-static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi10_pdata = {
- .clk_freq = 100000,
- .src_clk_rate = 24000000,
- .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
-};
-
-static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi12_pdata = {
- .clk_freq = 100000,
- .src_clk_rate = 24000000,
- .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
-};
-
-static struct msm_rpm_platform_data msm_rpm_data = {
- .reg_base_addrs = {
- [MSM_RPM_PAGE_STATUS] = MSM_RPM_BASE,
- [MSM_RPM_PAGE_CTRL] = MSM_RPM_BASE + 0x400,
- [MSM_RPM_PAGE_REQ] = MSM_RPM_BASE + 0x600,
- [MSM_RPM_PAGE_ACK] = MSM_RPM_BASE + 0xa00,
- },
-
- .irq_ack = RPM_APCC_CPU0_GP_HIGH_IRQ,
- .irq_err = RPM_APCC_CPU0_GP_LOW_IRQ,
- .irq_vmpm = RPM_APCC_CPU0_GP_MEDIUM_IRQ,
- .msm_apps_ipc_rpm_reg = MSM_APCS_GCC_BASE + 0x008,
- .msm_apps_ipc_rpm_val = 4,
-};
-
-static struct ks8851_pdata spi_eth_pdata = {
- .irq_gpio = KS8851_IRQ_GPIO,
- .rst_gpio = KS8851_RST_GPIO,
-};
-
-static struct spi_board_info spi_board_info[] __initdata = {
- {
- .modalias = "ks8851",
- .irq = MSM_GPIO_TO_INT(KS8851_IRQ_GPIO),
- .max_speed_hz = 19200000,
- .bus_num = 0,
- .chip_select = 0,
- .mode = SPI_MODE_0,
- .platform_data = &spi_eth_pdata
- },
- {
- .modalias = "dsi_novatek_3d_panel_spi",
- .max_speed_hz = 10800000,
- .bus_num = 0,
- .chip_select = 1,
- .mode = SPI_MODE_0,
- },
-};
-
-static struct platform_device msm_device_saw_core0 = {
- .name = "saw-regulator",
- .id = 0,
- .dev = {
- .platform_data = &msm_saw_regulator_pdata_s5,
- },
-};
-
-static struct platform_device msm_device_saw_core1 = {
- .name = "saw-regulator",
- .id = 1,
- .dev = {
- .platform_data = &msm_saw_regulator_pdata_s6,
- },
-};
-
-#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
-static struct platform_device wfd_device = {
- .name = "msm_wfd",
- .id = -1,
-};
-#endif
-
-static struct tsens_platform_data msm_tsens_pdata = {
- .slope = 910,
- .tsens_factor = 1000,
- .hw_type = MSM_8960,
- .tsens_num_sensor = 5,
-};
-
-static struct platform_device msm_tsens_device = {
- .name = "tsens8960-tm",
- .id = -1,
- .dev = {
- .platform_data = &msm_tsens_pdata,
- },
-};
-
-#ifdef CONFIG_MSM_FAKE_BATTERY
-static struct platform_device fish_battery_device = {
- .name = "fish_battery",
-};
-#endif
-
-static struct platform_device msm8960_device_ext_5v_vreg __devinitdata = {
- .name = GPIO_REGULATOR_DEV_NAME,
- .id = PM8921_MPP_PM_TO_SYS(7),
- .dev = {
- .platform_data = &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_5V],
- },
-};
-
-static struct platform_device msm8960_device_ext_l2_vreg __devinitdata = {
- .name = GPIO_REGULATOR_DEV_NAME,
- .id = 91,
- .dev = {
- .platform_data = &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_L2],
- },
-};
-
-static struct platform_device msm8960_device_ext_3p3v_vreg __devinitdata = {
- .name = GPIO_REGULATOR_DEV_NAME,
- .id = PM8921_GPIO_PM_TO_SYS(17),
- .dev = {
- .platform_data =
- &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_3P3V],
- },
-};
-
-static struct platform_device msm8960_device_rpm_regulator __devinitdata = {
- .name = "rpm-regulator",
- .id = -1,
- .dev = {
- .platform_data = &msm_rpm_regulator_pdata,
- },
-};
-
-static struct msm_rpm_log_platform_data msm_rpm_log_pdata = {
- .phys_addr_base = 0x0010C000,
- .reg_offsets = {
- [MSM_RPM_LOG_PAGE_INDICES] = 0x00000080,
- [MSM_RPM_LOG_PAGE_BUFFER] = 0x000000A0,
- },
- .phys_size = SZ_8K,
- .log_len = 4096, /* log's buffer length in bytes */
- .log_len_mask = (4096 >> 2) - 1, /* length mask in units of u32 */
-};
-
-static struct platform_device msm_rpm_log_device = {
- .name = "msm_rpm_log",
- .id = -1,
- .dev = {
- .platform_data = &msm_rpm_log_pdata,
- },
-};
-
-static struct platform_device *common_devices[] __initdata = {
- &msm8960_device_dmov,
- &msm_device_smd,
- &msm8960_device_uart_gsbi5,
- &msm_device_uart_dm6,
- &msm_device_saw_core0,
- &msm_device_saw_core1,
- &msm8960_device_ext_5v_vreg,
- &msm8960_device_ext_l2_vreg,
- &msm8960_device_ssbi_pm8921,
- &msm8960_device_qup_spi_gsbi1,
- &msm8960_device_qup_i2c_gsbi3,
- &msm8960_device_qup_i2c_gsbi4,
- &msm8960_device_qup_i2c_gsbi10,
-#ifndef CONFIG_MSM_DSPS
- &msm8960_device_qup_i2c_gsbi12,
-#endif
- &msm_slim_ctrl,
- &msm_device_wcnss_wlan,
-#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
- defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
- &qcrypto_device,
-#endif
-
-#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
- defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
- &qcedev_device,
-#endif
-#ifdef CONFIG_MSM_ROTATOR
- &msm_rotator_device,
-#endif
- &msm_device_sps,
-#ifdef CONFIG_MSM_FAKE_BATTERY
- &fish_battery_device,
-#endif
-#ifdef CONFIG_ANDROID_PMEM
-#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
- &android_pmem_device,
- &android_pmem_adsp_device,
-#endif
- &android_pmem_audio_device,
-#endif
- &msm_fb_device,
- &msm_device_vidc,
- &msm_device_bam_dmux,
- &msm_fm_platform_init,
-
-#ifdef CONFIG_HW_RANDOM_MSM
- &msm_device_rng,
-#endif
- &msm_rpm_device,
-#ifdef CONFIG_ION_MSM
- &ion_dev,
-#endif
- &msm_rpm_log_device,
- &msm_rpm_stat_device,
-#ifdef CONFIG_MSM_QDSS
- &msm_etb_device,
- &msm_tpiu_device,
- &msm_funnel_device,
- &msm_debug_device,
- &msm_ptm_device,
-#endif
- &msm_device_dspcrashd_8960,
- &msm8960_device_watchdog,
-#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
- &wfd_panel_device,
- &wfd_device,
-#endif
-};
-
-static struct platform_device *sim_devices[] __initdata = {
- &msm8960_device_otg,
- &msm8960_device_gadget_peripheral,
- &msm_device_hsusb_host,
- &msm_device_hsic_host,
- &android_usb_device,
- &msm_device_vidc,
- &mipi_dsi_simulator_panel_device,
- &msm_bus_apps_fabric,
- &msm_bus_sys_fabric,
- &msm_bus_mm_fabric,
- &msm_bus_sys_fpb,
- &msm_bus_cpss_fpb,
- &msm_pcm,
- &msm_pcm_routing,
- &msm_cpudai0,
- &msm_cpudai1,
- &msm_cpudai_hdmi_rx,
- &msm_cpudai_bt_rx,
- &msm_cpudai_bt_tx,
- &msm_cpudai_fm_rx,
- &msm_cpudai_fm_tx,
- &msm_cpudai_auxpcm_rx,
- &msm_cpudai_auxpcm_tx,
- &msm_cpu_fe,
- &msm_stub_codec,
- &msm_voice,
- &msm_voip,
- &msm_lpa_pcm,
-
-#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
- defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
- &qcrypto_device,
-#endif
-
-#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
- defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
- &qcedev_device,
-#endif
-};
-
-static struct platform_device *rumi3_devices[] __initdata = {
- &msm_kgsl_3d0,
- &msm_kgsl_2d0,
- &msm_kgsl_2d1,
- &mipi_dsi_renesas_panel_device,
-#ifdef CONFIG_MSM_GEMINI
- &msm8960_gemini_device,
-#endif
-};
-
-static struct platform_device *cdp_devices[] __initdata = {
- &msm8960_device_otg,
- &msm8960_device_gadget_peripheral,
- &msm_device_hsusb_host,
- &android_usb_device,
- &msm_pcm,
- &msm_pcm_routing,
- &msm_cpudai0,
- &msm_cpudai1,
- &msm_cpudai_hdmi_rx,
- &msm_cpudai_bt_rx,
- &msm_cpudai_bt_tx,
- &msm_cpudai_fm_rx,
- &msm_cpudai_fm_tx,
- &msm_cpudai_auxpcm_rx,
- &msm_cpudai_auxpcm_tx,
- &msm_cpu_fe,
- &msm_stub_codec,
- &msm_kgsl_3d0,
-#ifdef CONFIG_MSM_KGSL_2D
- &msm_kgsl_2d0,
- &msm_kgsl_2d1,
-#endif
- &mipi_dsi_novatek_panel_device,
-#ifdef CONFIG_MSM_GEMINI
- &msm8960_gemini_device,
-#endif
- &msm_voice,
- &msm_voip,
- &msm_lpa_pcm,
- &msm_cpudai_afe_01_rx,
- &msm_cpudai_afe_01_tx,
- &msm_cpudai_afe_02_rx,
- &msm_cpudai_afe_02_tx,
- &msm_pcm_afe,
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
- &hdmi_msm_device,
-#endif
- &msm_pcm_hostless,
- &msm_bus_apps_fabric,
- &msm_bus_sys_fabric,
- &msm_bus_mm_fabric,
- &msm_bus_sys_fpb,
- &msm_bus_cpss_fpb,
- &msm_tsens_device,
-};
-
-static void __init msm8960_i2c_init(void)
-{
- msm8960_device_qup_i2c_gsbi4.dev.platform_data =
- &msm8960_i2c_qup_gsbi4_pdata;
-
- msm8960_device_qup_i2c_gsbi3.dev.platform_data =
- &msm8960_i2c_qup_gsbi3_pdata;
-
- msm8960_device_qup_i2c_gsbi10.dev.platform_data =
- &msm8960_i2c_qup_gsbi10_pdata;
-
- msm8960_device_qup_i2c_gsbi12.dev.platform_data =
- &msm8960_i2c_qup_gsbi12_pdata;
-}
-
-static void __init msm8960_gfx_init(void)
-{
- uint32_t soc_platform_version = socinfo_get_version();
- if (SOCINFO_VERSION_MAJOR(soc_platform_version) == 1) {
- struct kgsl_device_platform_data *kgsl_3d0_pdata =
- msm_kgsl_3d0.dev.platform_data;
- kgsl_3d0_pdata->pwr_data.pwrlevel[0].gpu_freq =
- 320000000;
- kgsl_3d0_pdata->pwr_data.pwrlevel[1].gpu_freq =
- 266667000;
- }
-}
-
-static struct pm8xxx_irq_platform_data pm8xxx_irq_pdata __devinitdata = {
- .irq_base = PM8921_IRQ_BASE,
- .devirq = MSM_GPIO_TO_INT(104),
- .irq_trigger_flag = IRQF_TRIGGER_LOW,
-};
-
-static struct pm8xxx_gpio_platform_data pm8xxx_gpio_pdata __devinitdata = {
- .gpio_base = PM8921_GPIO_PM_TO_SYS(1),
-};
-
-static struct pm8xxx_mpp_platform_data pm8xxx_mpp_pdata __devinitdata = {
- .mpp_base = PM8921_MPP_PM_TO_SYS(1),
-};
-
-static struct pm8xxx_rtc_platform_data pm8xxx_rtc_pdata __devinitdata = {
- .rtc_write_enable = false,
- .rtc_alarm_powerup = false,
-};
-
-static struct pm8xxx_pwrkey_platform_data pm8xxx_pwrkey_pdata = {
- .pull_up = 1,
- .kpd_trigger_delay_us = 970,
- .wakeup = 1,
-};
-
-/* Rotate lock key is not available so use F1 */
-#define KEY_ROTATE_LOCK KEY_F1
-
-static const unsigned int keymap_liquid[] = {
- KEY(0, 0, KEY_VOLUMEUP),
- KEY(0, 1, KEY_VOLUMEDOWN),
- KEY(1, 3, KEY_ROTATE_LOCK),
- KEY(1, 4, KEY_HOME),
-};
-
-static struct matrix_keymap_data keymap_data_liquid = {
- .keymap_size = ARRAY_SIZE(keymap_liquid),
- .keymap = keymap_liquid,
-};
-
-static struct pm8xxx_keypad_platform_data keypad_data_liquid = {
- .input_name = "keypad_8960_liquid",
- .input_phys_device = "keypad_8960/input0",
- .num_rows = 2,
- .num_cols = 5,
- .rows_gpio_start = PM8921_GPIO_PM_TO_SYS(9),
- .cols_gpio_start = PM8921_GPIO_PM_TO_SYS(1),
- .debounce_ms = 15,
- .scan_delay_ms = 32,
- .row_hold_ns = 91500,
- .wakeup = 1,
- .keymap_data = &keymap_data_liquid,
-};
-
-
-static const unsigned int keymap[] = {
- KEY(0, 0, KEY_VOLUMEUP),
- KEY(0, 1, KEY_VOLUMEDOWN),
- KEY(0, 2, KEY_CAMERA_SNAPSHOT),
- KEY(0, 3, KEY_CAMERA_FOCUS),
-};
-
-static struct matrix_keymap_data keymap_data = {
- .keymap_size = ARRAY_SIZE(keymap),
- .keymap = keymap,
-};
-
-static struct pm8xxx_keypad_platform_data keypad_data = {
- .input_name = "keypad_8960",
- .input_phys_device = "keypad_8960/input0",
- .num_rows = 1,
- .num_cols = 5,
- .rows_gpio_start = PM8921_GPIO_PM_TO_SYS(9),
- .cols_gpio_start = PM8921_GPIO_PM_TO_SYS(1),
- .debounce_ms = 15,
- .scan_delay_ms = 32,
- .row_hold_ns = 91500,
- .wakeup = 1,
- .keymap_data = &keymap_data,
-};
-
-static const unsigned int keymap_sim[] = {
- KEY(0, 0, KEY_7),
- KEY(0, 1, KEY_DOWN),
- KEY(0, 2, KEY_UP),
- KEY(0, 3, KEY_RIGHT),
- KEY(0, 4, KEY_ENTER),
- KEY(0, 5, KEY_L),
- KEY(0, 6, KEY_BACK),
- KEY(0, 7, KEY_M),
-
- KEY(1, 0, KEY_LEFT),
- KEY(1, 1, KEY_SEND),
- KEY(1, 2, KEY_1),
- KEY(1, 3, KEY_4),
- KEY(1, 4, KEY_CLEAR),
- KEY(1, 5, KEY_MSDOS),
- KEY(1, 6, KEY_SPACE),
- KEY(1, 7, KEY_COMMA),
-
- KEY(2, 0, KEY_6),
- KEY(2, 1, KEY_5),
- KEY(2, 2, KEY_8),
- KEY(2, 3, KEY_3),
- KEY(2, 4, KEY_NUMERIC_STAR),
- KEY(2, 5, KEY_UP),
- KEY(2, 6, KEY_DOWN),
- KEY(2, 7, KEY_LEFTSHIFT),
-
- KEY(3, 0, KEY_9),
- KEY(3, 1, KEY_NUMERIC_POUND),
- KEY(3, 2, KEY_0),
- KEY(3, 3, KEY_2),
- KEY(3, 4, KEY_SLEEP),
- KEY(3, 5, KEY_F1),
- KEY(3, 6, KEY_F2),
- KEY(3, 7, KEY_F3),
-
- KEY(4, 0, KEY_BACK),
- KEY(4, 1, KEY_HOME),
- KEY(4, 2, KEY_MENU),
- KEY(4, 3, KEY_VOLUMEUP),
- KEY(4, 4, KEY_VOLUMEDOWN),
- KEY(4, 5, KEY_F4),
- KEY(4, 6, KEY_F5),
- KEY(4, 7, KEY_F6),
-
- KEY(5, 0, KEY_R),
- KEY(5, 1, KEY_T),
- KEY(5, 2, KEY_Y),
- KEY(5, 3, KEY_LEFTALT),
- KEY(5, 4, KEY_KPENTER),
- KEY(5, 5, KEY_Q),
- KEY(5, 6, KEY_W),
- KEY(5, 7, KEY_E),
-
- KEY(6, 0, KEY_F),
- KEY(6, 1, KEY_G),
- KEY(6, 2, KEY_H),
- KEY(6, 3, KEY_CAPSLOCK),
- KEY(6, 4, KEY_PAGEUP),
- KEY(6, 5, KEY_A),
- KEY(6, 6, KEY_S),
- KEY(6, 7, KEY_D),
-
- KEY(7, 0, KEY_V),
- KEY(7, 1, KEY_B),
- KEY(7, 2, KEY_N),
- KEY(7, 3, KEY_MENU),
- KEY(7, 4, KEY_PAGEDOWN),
- KEY(7, 5, KEY_Z),
- KEY(7, 6, KEY_X),
- KEY(7, 7, KEY_C),
-
- KEY(8, 0, KEY_P),
- KEY(8, 1, KEY_J),
- KEY(8, 2, KEY_K),
- KEY(8, 3, KEY_INSERT),
- KEY(8, 4, KEY_LINEFEED),
- KEY(8, 5, KEY_U),
- KEY(8, 6, KEY_I),
- KEY(8, 7, KEY_O),
-
- KEY(9, 0, KEY_4),
- KEY(9, 1, KEY_5),
- KEY(9, 2, KEY_6),
- KEY(9, 3, KEY_7),
- KEY(9, 4, KEY_8),
- KEY(9, 5, KEY_1),
- KEY(9, 6, KEY_2),
- KEY(9, 7, KEY_3),
-
- KEY(10, 0, KEY_F7),
- KEY(10, 1, KEY_F8),
- KEY(10, 2, KEY_F9),
- KEY(10, 3, KEY_F10),
- KEY(10, 4, KEY_FN),
- KEY(10, 5, KEY_9),
- KEY(10, 6, KEY_0),
- KEY(10, 7, KEY_DOT),
-
- KEY(11, 0, KEY_LEFTCTRL),
- KEY(11, 1, KEY_F11),
- KEY(11, 2, KEY_ENTER),
- KEY(11, 3, KEY_SEARCH),
- KEY(11, 4, KEY_DELETE),
- KEY(11, 5, KEY_RIGHT),
- KEY(11, 6, KEY_LEFT),
- KEY(11, 7, KEY_RIGHTSHIFT),
- KEY(0, 0, KEY_VOLUMEUP),
- KEY(0, 1, KEY_VOLUMEDOWN),
- KEY(0, 2, KEY_CAMERA_SNAPSHOT),
- KEY(0, 3, KEY_CAMERA_FOCUS),
-};
-
-static struct matrix_keymap_data keymap_data_sim = {
- .keymap_size = ARRAY_SIZE(keymap_sim),
- .keymap = keymap_sim,
-};
-
-static struct pm8xxx_keypad_platform_data keypad_data_sim = {
- .input_name = "keypad_8960",
- .input_phys_device = "keypad_8960/input0",
- .num_rows = 12,
- .num_cols = 8,
- .rows_gpio_start = PM8921_GPIO_PM_TO_SYS(9),
- .cols_gpio_start = PM8921_GPIO_PM_TO_SYS(1),
- .debounce_ms = 15,
- .scan_delay_ms = 32,
- .row_hold_ns = 91500,
- .wakeup = 1,
- .keymap_data = &keymap_data_sim,
-};
-
-static int pm8921_therm_mitigation[] = {
- 1100,
- 700,
- 600,
- 325,
-};
-
-static struct pm8921_charger_platform_data pm8921_chg_pdata __devinitdata = {
- .safety_time = 180,
- .update_time = 60000,
- .max_voltage = 4200,
- .min_voltage = 3200,
- .resume_voltage = 4100,
- .term_current = 100,
- .cool_temp = 10,
- .warm_temp = 40,
- .temp_check_period = 1,
- .max_bat_chg_current = 1100,
- .cool_bat_chg_current = 350,
- .warm_bat_chg_current = 350,
- .cool_bat_voltage = 4100,
- .warm_bat_voltage = 4100,
- .thermal_mitigation = pm8921_therm_mitigation,
- .thermal_levels = ARRAY_SIZE(pm8921_therm_mitigation),
-};
-
-static struct pm8xxx_misc_platform_data pm8xxx_misc_pdata = {
- .priority = 0,
-};
-
-static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
- .r_sense = 10,
- .i_test = 2500,
- .v_failure = 3000,
- .calib_delay_ms = 600000,
-};
-
-#define PM8921_LC_LED_MAX_CURRENT 4 /* I = 4mA */
-#define PM8XXX_LED_PWM_PERIOD 1000
-#define PM8XXX_LED_PWM_DUTY_MS 20
-/**
- * PM8XXX_PWM_CHANNEL_NONE shall be used when LED shall not be
- * driven using PWM feature.
- */
-#define PM8XXX_PWM_CHANNEL_NONE -1
-
-static struct led_info pm8921_led_info[] = {
- [0] = {
- .name = "led:battery_charging",
- .default_trigger = "battery-charging",
- },
- [1] = {
- .name = "led:battery_full",
- .default_trigger = "battery-full",
- },
-};
-
-static struct led_platform_data pm8921_led_core_pdata = {
- .num_leds = ARRAY_SIZE(pm8921_led_info),
- .leds = pm8921_led_info,
-};
-
-static int pm8921_led0_pwm_duty_pcts[56] = {
- 1, 4, 8, 12, 16, 20, 24, 28, 32, 36,
- 40, 44, 46, 52, 56, 60, 64, 68, 72, 76,
- 80, 84, 88, 92, 96, 100, 100, 100, 98, 95,
- 92, 88, 84, 82, 78, 74, 70, 66, 62, 58,
- 58, 54, 50, 48, 42, 38, 34, 30, 26, 22,
- 14, 10, 6, 4, 1
-};
-
-static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_duty_cycles = {
- .duty_pcts = (int *)&pm8921_led0_pwm_duty_pcts,
- .num_duty_pcts = ARRAY_SIZE(pm8921_led0_pwm_duty_pcts),
- .duty_ms = PM8XXX_LED_PWM_DUTY_MS,
- .start_idx = 0,
-};
-
-static struct pm8xxx_led_config pm8921_led_configs[] = {
- [0] = {
- .id = PM8XXX_ID_LED_0,
- .mode = PM8XXX_LED_MODE_PWM2,
- .max_current = PM8921_LC_LED_MAX_CURRENT,
- .pwm_channel = 5,
- .pwm_period_us = PM8XXX_LED_PWM_PERIOD,
- .pwm_duty_cycles = &pm8921_led0_pwm_duty_cycles,
- },
- [1] = {
- .id = PM8XXX_ID_LED_1,
- .mode = PM8XXX_LED_MODE_PWM1,
- .max_current = PM8921_LC_LED_MAX_CURRENT,
- .pwm_channel = 4,
- .pwm_period_us = PM8XXX_LED_PWM_PERIOD,
- },
-};
-
-static struct pm8xxx_led_platform_data pm8xxx_leds_pdata = {
- .led_core = &pm8921_led_core_pdata,
- .configs = pm8921_led_configs,
- .num_configs = ARRAY_SIZE(pm8921_led_configs),
-};
-
-static struct pm8921_platform_data pm8921_platform_data __devinitdata = {
- .irq_pdata = &pm8xxx_irq_pdata,
- .gpio_pdata = &pm8xxx_gpio_pdata,
- .mpp_pdata = &pm8xxx_mpp_pdata,
- .rtc_pdata = &pm8xxx_rtc_pdata,
- .pwrkey_pdata = &pm8xxx_pwrkey_pdata,
- .keypad_pdata = &keypad_data,
- .misc_pdata = &pm8xxx_misc_pdata,
- .regulator_pdatas = msm_pm8921_regulator_pdata,
- .charger_pdata = &pm8921_chg_pdata,
- .bms_pdata = &pm8921_bms_pdata,
- .adc_pdata = &pm8921_adc_pdata,
- .leds_pdata = &pm8xxx_leds_pdata,
-};
-
-static struct msm_ssbi_platform_data msm8960_ssbi_pm8921_pdata __devinitdata = {
- .controller_type = MSM_SBI_CTRL_PMIC_ARBITER,
- .slave = {
- .name = "pm8921-core",
- .platform_data = &pm8921_platform_data,
- },
-};
-
-static struct msm_cpuidle_state msm_cstates[] __initdata = {
- {0, 0, "C0", "WFI",
- MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
-
- {0, 1, "C1", "STANDALONE_POWER_COLLAPSE",
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
-
- {0, 2, "C2", "POWER_COLLAPSE",
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE},
-
- {1, 0, "C0", "WFI",
- MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
-
- {1, 1, "C1", "STANDALONE_POWER_COLLAPSE",
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
-};
-
-static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR * 2] = {
- [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
- .idle_supported = 1,
- .suspend_supported = 1,
- .idle_enabled = 0,
- .suspend_enabled = 0,
- },
-
- [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
- .idle_supported = 1,
- .suspend_supported = 1,
- .idle_enabled = 0,
- .suspend_enabled = 0,
- },
-
- [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
- .idle_supported = 1,
- .suspend_supported = 1,
- .idle_enabled = 1,
- .suspend_enabled = 1,
- },
-
- [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
- .idle_supported = 0,
- .suspend_supported = 1,
- .idle_enabled = 0,
- .suspend_enabled = 0,
- },
-
- [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
- .idle_supported = 1,
- .suspend_supported = 1,
- .idle_enabled = 0,
- .suspend_enabled = 0,
- },
-
- [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
- .idle_supported = 1,
- .suspend_supported = 0,
- .idle_enabled = 1,
- .suspend_enabled = 0,
- },
-};
-
-static struct msm_rpmrs_level msm_rpmrs_levels[] __initdata = {
- {
- MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
- MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
- true,
- 100, 8000, 100000, 1,
- },
-
- {
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
- MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
- true,
- 2000, 6000, 60100000, 3000,
- },
-
- {
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
- MSM_RPMRS_LIMITS(ON, GDHS, MAX, ACTIVE),
- false,
- 4200, 5000, 60350000, 3500,
- },
-
- {
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
- MSM_RPMRS_LIMITS(ON, HSFS_OPEN, MAX, ACTIVE),
- false,
- 6300, 4500, 65350000, 4800,
- },
- {
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
- MSM_RPMRS_LIMITS(ON, HSFS_OPEN, ACTIVE, RET_HIGH),
- false,
- 7000, 3500, 66600000, 5150,
- },
-
- {
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
- MSM_RPMRS_LIMITS(OFF, GDHS, MAX, ACTIVE),
- false,
- 11700, 2500, 67850000, 5500,
- },
-
- {
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
- MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, MAX, ACTIVE),
- false,
- 13800, 2000, 71850000, 6800,
- },
-
- {
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
- MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, ACTIVE, RET_HIGH),
- false,
- 29700, 500, 75850000, 8800,
- },
-
- {
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
- MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, RET_HIGH, RET_LOW),
- false,
- 29700, 0, 76350000, 9800,
- },
-};
-
-#ifdef CONFIG_I2C
-#define I2C_SURF 1
-#define I2C_FFA (1 << 1)
-#define I2C_RUMI (1 << 2)
-#define I2C_SIM (1 << 3)
-#define I2C_FLUID (1 << 4)
-#define I2C_LIQUID (1 << 5)
-
-struct i2c_registry {
- u8 machs;
- int bus;
- struct i2c_board_info *info;
- int len;
-};
-
-#ifdef CONFIG_MSM_CAMERA
-static struct i2c_board_info msm_camera_boardinfo[] __initdata = {
-#ifdef CONFIG_IMX074
- {
- I2C_BOARD_INFO("imx074", 0x1A),
- },
-#endif
-#ifdef CONFIG_OV2720
- {
- I2C_BOARD_INFO("ov2720", 0x6C),
- },
-#endif
- {
- I2C_BOARD_INFO("qs_mt9p017", 0x6C >> 1),
- },
-#ifdef CONFIG_MSM_CAMERA_FLASH_SC628A
- {
- I2C_BOARD_INFO("sc628a", 0x6E),
- },
-#endif
-};
-#endif
-
-/* Sensors DSPS platform data */
-#ifdef CONFIG_MSM_DSPS
-#define DSPS_PIL_GENERIC_NAME "dsps"
-#endif /* CONFIG_MSM_DSPS */
-
-static void __init msm8960_init_dsps(void)
-{
-#ifdef CONFIG_MSM_DSPS
- struct msm_dsps_platform_data *pdata =
- msm_dsps_device.dev.platform_data;
- pdata->pil_name = DSPS_PIL_GENERIC_NAME;
- pdata->gpios = NULL;
- pdata->gpios_num = 0;
-
- platform_device_register(&msm_dsps_device);
-#endif /* CONFIG_MSM_DSPS */
-}
-
-static void __init msm8960_init_hsic(void)
-{
-#ifdef CONFIG_USB_EHCI_MSM_HSIC
- uint32_t version = socinfo_get_version();
-
- pr_info("%s: version:%d mtp:%d\n", __func__,
- SOCINFO_VERSION_MAJOR(version),
- machine_is_msm8960_mtp());
-
- if ((SOCINFO_VERSION_MAJOR(version) == 1) ||
- machine_is_msm8960_mtp() ||
- machine_is_msm8960_fluid())
- return;
-
- msm_gpiomux_install(msm8960_hsic_configs,
- ARRAY_SIZE(msm8960_hsic_configs));
-
- platform_device_register(&msm_device_hsic_host);
-#endif
-}
-
-
-#ifdef CONFIG_ISL9519_CHARGER
-static struct isl_platform_data isl_data __initdata = {
- .valid_n_gpio = 0, /* Not required when notify-by-pmic */
- .chg_detection_config = NULL, /* Not required when notify-by-pmic */
- .max_system_voltage = 4200,
- .min_system_voltage = 3200,
- .chgcurrent = 1000, /* 1900, */
- .term_current = 400, /* Need fine tuning */
- .input_current = 2048,
-};
-
-static struct i2c_board_info isl_charger_i2c_info[] __initdata = {
- {
- I2C_BOARD_INFO("isl9519q", 0x9),
- .irq = 0, /* Not required when notify-by-pmic */
- .platform_data = &isl_data,
- },
-};
-#endif /* CONFIG_ISL9519_CHARGER */
-
-static struct i2c_registry msm8960_i2c_devices[] __initdata = {
-#ifdef CONFIG_MSM_CAMERA
- {
- I2C_SURF | I2C_FFA | I2C_FLUID | I2C_LIQUID | I2C_RUMI,
- MSM_8960_GSBI4_QUP_I2C_BUS_ID,
- msm_camera_boardinfo,
- ARRAY_SIZE(msm_camera_boardinfo),
- },
-#endif
-#ifdef CONFIG_ISL9519_CHARGER
- {
- I2C_LIQUID,
- MSM_8960_GSBI10_QUP_I2C_BUS_ID,
- isl_charger_i2c_info,
- ARRAY_SIZE(isl_charger_i2c_info),
- },
-#endif /* CONFIG_ISL9519_CHARGER */
- {
- I2C_SURF | I2C_FFA | I2C_FLUID,
- MSM_8960_GSBI3_QUP_I2C_BUS_ID,
- cyttsp_info,
- ARRAY_SIZE(cyttsp_info),
- },
- {
- I2C_LIQUID,
- MSM_8960_GSBI3_QUP_I2C_BUS_ID,
- mxt_device_info,
- ARRAY_SIZE(mxt_device_info),
- },
- {
- I2C_LIQUID,
- MSM_8960_GSBI10_QUP_I2C_BUS_ID,
- msm_isa1200_board_info,
- ARRAY_SIZE(msm_isa1200_board_info),
- },
-};
-#endif /* CONFIG_I2C */
-
-static void __init register_i2c_devices(void)
-{
-#ifdef CONFIG_I2C
- u8 mach_mask = 0;
- int i;
-
- /* Build the matching 'supported_machs' bitmask */
- if (machine_is_msm8960_cdp())
- mach_mask = I2C_SURF;
- else if (machine_is_msm8960_rumi3())
- mach_mask = I2C_RUMI;
- else if (machine_is_msm8960_sim())
- mach_mask = I2C_SIM;
- else if (machine_is_msm8960_fluid())
- mach_mask = I2C_FLUID;
- else if (machine_is_msm8960_liquid())
- mach_mask = I2C_LIQUID;
- else if (machine_is_msm8960_mtp())
- mach_mask = I2C_FFA;
- else
- pr_err("unmatched machine ID in register_i2c_devices\n");
-
- /* Run the array and install devices as appropriate */
- for (i = 0; i < ARRAY_SIZE(msm8960_i2c_devices); ++i) {
- if (msm8960_i2c_devices[i].machs & mach_mask)
- i2c_register_board_info(msm8960_i2c_devices[i].bus,
- msm8960_i2c_devices[i].info,
- msm8960_i2c_devices[i].len);
- }
-#endif
-}
-
-static void __init msm8960_sim_init(void)
-{
- struct msm_watchdog_pdata *wdog_pdata = (struct msm_watchdog_pdata *)
- &msm8960_device_watchdog.dev.platform_data;
-
- wdog_pdata->bark_time = 15000;
- BUG_ON(msm_rpm_init(&msm_rpm_data));
- BUG_ON(msm_rpmrs_levels_init(msm_rpmrs_levels,
- ARRAY_SIZE(msm_rpmrs_levels)));
- regulator_suppress_info_printing();
- platform_device_register(&msm8960_device_rpm_regulator);
- msm_clock_init(&msm8960_clock_init_data);
- msm8960_device_ssbi_pm8921.dev.platform_data =
- &msm8960_ssbi_pm8921_pdata;
- pm8921_platform_data.num_regulators = msm_pm8921_regulator_pdata_len;
-
- /* Simulator supports a QWERTY keypad */
- pm8921_platform_data.keypad_pdata = &keypad_data_sim;
-
- msm8960_device_otg.dev.platform_data = &msm_otg_pdata;
- gpiomux_init();
- msm8960_i2c_init();
- msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
- msm_spm_l2_init(msm_spm_l2_data);
- msm8960_init_buses();
- platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
- pm8921_gpio_mpp_init();
- platform_add_devices(sim_devices, ARRAY_SIZE(sim_devices));
- acpuclk_init(&acpuclk_8960_soc_data);
-
- msm8960_device_qup_spi_gsbi1.dev.platform_data =
- &msm8960_qup_spi_gsbi1_pdata;
- spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
-
- msm8960_init_mmc();
- msm_fb_add_devices();
- slim_register_board_info(msm_slim_devices,
- ARRAY_SIZE(msm_slim_devices));
- msm_pm_set_platform_data(msm_pm_data, ARRAY_SIZE(msm_pm_data));
- msm_pm_set_rpm_wakeup_irq(RPM_APCC_CPU0_WAKE_UP_IRQ);
- msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
- msm_pm_data);
- BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_TZ, NULL));
-}
-
-static void __init msm8960_rumi3_init(void)
-{
- BUG_ON(msm_rpm_init(&msm_rpm_data));
- BUG_ON(msm_rpmrs_levels_init(msm_rpmrs_levels,
- ARRAY_SIZE(msm_rpmrs_levels)));
- regulator_suppress_info_printing();
- platform_device_register(&msm8960_device_rpm_regulator);
- msm_clock_init(&msm8960_dummy_clock_init_data);
- gpiomux_init();
- msm8960_device_ssbi_pm8921.dev.platform_data =
- &msm8960_ssbi_pm8921_pdata;
- pm8921_platform_data.num_regulators = msm_pm8921_regulator_pdata_len;
- msm8960_device_qup_spi_gsbi1.dev.platform_data =
- &msm8960_qup_spi_gsbi1_pdata;
- spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
- msm8960_i2c_init();
- msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
- msm_spm_l2_init(msm_spm_l2_data);
- platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
- pm8921_gpio_mpp_init();
- platform_add_devices(rumi3_devices, ARRAY_SIZE(rumi3_devices));
- msm8960_init_mmc();
- register_i2c_devices();
- msm_fb_add_devices();
- slim_register_board_info(msm_slim_devices,
- ARRAY_SIZE(msm_slim_devices));
- msm_pm_set_platform_data(msm_pm_data, ARRAY_SIZE(msm_pm_data));
- msm_pm_set_rpm_wakeup_irq(RPM_APCC_CPU0_WAKE_UP_IRQ);
- msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
- msm_pm_data);
- BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_TZ, NULL));
-}
-
-static void __init msm8960_cdp_init(void)
-{
- if (meminfo_init(SYS_MEMORY, SZ_256M) < 0)
- pr_err("meminfo_init() failed!\n");
-
- BUG_ON(msm_rpm_init(&msm_rpm_data));
- BUG_ON(msm_rpmrs_levels_init(msm_rpmrs_levels,
- ARRAY_SIZE(msm_rpmrs_levels)));
-
- pmic_reset_irq = PM8921_IRQ_BASE + PM8921_RESOUT_IRQ;
- regulator_suppress_info_printing();
- if (msm_xo_init())
- pr_err("Failed to initialize XO votes\n");
- platform_device_register(&msm8960_device_rpm_regulator);
- msm_clock_init(&msm8960_clock_init_data);
- if (machine_is_msm8960_liquid())
- msm_otg_pdata.mhl_enable = true;
- msm8960_device_otg.dev.platform_data = &msm_otg_pdata;
-#ifdef CONFIG_USB_EHCI_MSM_HSIC
- if (machine_is_msm8960_liquid()) {
- if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2)
- msm_hsic_pdata.hub_reset = HSIC_HUB_RESET_GPIO;
- }
-#endif
- msm_device_hsic_host.dev.platform_data = &msm_hsic_pdata;
- gpiomux_init();
- if (machine_is_msm8960_liquid())
- pm8921_platform_data.keypad_pdata = &keypad_data_liquid;
- msm8960_device_qup_spi_gsbi1.dev.platform_data =
- &msm8960_qup_spi_gsbi1_pdata;
- spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
- msm8960_device_ssbi_pm8921.dev.platform_data =
- &msm8960_ssbi_pm8921_pdata;
- pm8921_platform_data.num_regulators = msm_pm8921_regulator_pdata_len;
- msm8960_i2c_init();
- msm8960_gfx_init();
- msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
- msm_spm_l2_init(msm_spm_l2_data);
- msm8960_init_buses();
- platform_add_devices(msm_footswitch_devices,
- msm_num_footswitch_devices);
- if (machine_is_msm8960_liquid())
- platform_device_register(&msm8960_device_ext_3p3v_vreg);
- platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
- pm8921_gpio_mpp_init();
- platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
- msm8960_init_hsic();
- msm8960_init_cam();
- msm8960_init_mmc();
- acpuclk_init(&acpuclk_8960_soc_data);
- if (machine_is_msm8960_liquid())
- mxt_init_hw_liquid();
- register_i2c_devices();
- msm_fb_add_devices();
- slim_register_board_info(msm_slim_devices,
- ARRAY_SIZE(msm_slim_devices));
- msm8960_init_dsps();
- msm_pm_set_platform_data(msm_pm_data, ARRAY_SIZE(msm_pm_data));
- msm_pm_set_rpm_wakeup_irq(RPM_APCC_CPU0_WAKE_UP_IRQ);
- msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
- msm_pm_data);
- change_memory_power = &msm8960_change_memory_power;
- BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_TZ, NULL));
-}
-
-MACHINE_START(MSM8960_SIM, "QCT MSM8960 SIMULATOR")
- .map_io = msm8960_map_io,
- .reserve = msm8960_reserve,
- .init_irq = msm8960_init_irq,
- .timer = &msm_timer,
- .init_machine = msm8960_sim_init,
- .init_early = msm8960_allocate_memory_regions,
- .init_very_early = msm8960_early_memory,
-MACHINE_END
-
-MACHINE_START(MSM8960_RUMI3, "QCT MSM8960 RUMI3")
- .map_io = msm8960_map_io,
- .reserve = msm8960_reserve,
- .init_irq = msm8960_init_irq,
- .timer = &msm_timer,
- .init_machine = msm8960_rumi3_init,
- .init_early = msm8960_allocate_memory_regions,
- .init_very_early = msm8960_early_memory,
-MACHINE_END
-
-MACHINE_START(MSM8960_CDP, "QCT MSM8960 CDP")
- .map_io = msm8960_map_io,
- .reserve = msm8960_reserve,
- .init_irq = msm8960_init_irq,
- .timer = &msm_timer,
- .init_machine = msm8960_cdp_init,
- .init_early = msm8960_allocate_memory_regions,
- .init_very_early = msm8960_early_memory,
-MACHINE_END
-
-MACHINE_START(MSM8960_MTP, "QCT MSM8960 MTP")
- .map_io = msm8960_map_io,
- .reserve = msm8960_reserve,
- .init_irq = msm8960_init_irq,
- .timer = &msm_timer,
- .init_machine = msm8960_cdp_init,
- .init_early = msm8960_allocate_memory_regions,
- .init_very_early = msm8960_early_memory,
-MACHINE_END
-
-MACHINE_START(MSM8960_FLUID, "QCT MSM8960 FLUID")
- .map_io = msm8960_map_io,
- .reserve = msm8960_reserve,
- .init_irq = msm8960_init_irq,
- .timer = &msm_timer,
- .init_machine = msm8960_cdp_init,
- .init_early = msm8960_allocate_memory_regions,
- .init_very_early = msm8960_early_memory,
-MACHINE_END
-
-MACHINE_START(MSM8960_LIQUID, "QCT MSM8960 LIQUID")
- .map_io = msm8960_map_io,
- .reserve = msm8960_reserve,
- .init_irq = msm8960_init_irq,
- .timer = &msm_timer,
- .init_machine = msm8960_cdp_init,
- .init_early = msm8960_allocate_memory_regions,
- .init_very_early = msm8960_early_memory,
-MACHINE_END
-
-#ifdef CONFIG_ARCH_MSM8930
-MACHINE_START(MSM8930_CDP, "QCT MSM8930 CDP")
- .map_io = msm8930_map_io,
- .reserve = msm8960_reserve,
- .init_irq = msm8960_init_irq,
- .timer = &msm_timer,
- .init_machine = msm8960_cdp_init,
- .init_early = msm8960_allocate_memory_regions,
- .init_very_early = msm8960_early_memory,
-MACHINE_END
-
-MACHINE_START(MSM8930_MTP, "QCT MSM8930 MTP")
- .map_io = msm8930_map_io,
- .reserve = msm8960_reserve,
- .init_irq = msm8960_init_irq,
- .timer = &msm_timer,
- .init_machine = msm8960_cdp_init,
- .init_early = msm8960_allocate_memory_regions,
- .init_very_early = msm8960_early_memory,
-MACHINE_END
-
-MACHINE_START(MSM8930_FLUID, "QCT MSM8930 FLUID")
- .map_io = msm8930_map_io,
- .reserve = msm8960_reserve,
- .init_irq = msm8960_init_irq,
- .timer = &msm_timer,
- .init_machine = msm8960_cdp_init,
- .init_early = msm8960_allocate_memory_regions,
- .init_very_early = msm8960_early_memory,
-MACHINE_END
-#endif
diff --git a/arch/arm/mach-msm/board-msm8960.h b/arch/arm/mach-msm/board-msm8960.h
deleted file mode 100644
index 1cfcfdd..0000000
--- a/arch/arm/mach-msm/board-msm8960.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef __ARCH_ARM_MACH_MSM_BOARD_MSM8960_H
-#define __ARCH_ARM_MACH_MSM_BOARD_MSM8960_H
-
-#include <mach/irqs.h>
-#include <mach/rpm-regulator.h>
-#include <linux/mfd/pm8xxx/pm8921.h>
-
-/* Macros assume PMIC GPIOs and MPPs start at 1 */
-#define PM8921_GPIO_BASE NR_GPIO_IRQS
-#define PM8921_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8921_GPIO_BASE)
-#define PM8921_MPP_BASE (PM8921_GPIO_BASE + PM8921_NR_GPIOS)
-#define PM8921_MPP_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8921_MPP_BASE)
-#define PM8921_IRQ_BASE (NR_MSM_IRQS + NR_GPIO_IRQS)
-
-extern struct pm8921_regulator_platform_data
- msm_pm8921_regulator_pdata[] __devinitdata;
-
-extern int msm_pm8921_regulator_pdata_len __devinitdata;
-
-#define GPIO_VREG_ID_EXT_5V 0
-#define GPIO_VREG_ID_EXT_L2 1
-#define GPIO_VREG_ID_EXT_3P3V 2
-
-extern struct gpio_regulator_platform_data
- msm_gpio_regulator_pdata[] __devinitdata;
-
-extern struct regulator_init_data msm_saw_regulator_pdata_s5;
-extern struct regulator_init_data msm_saw_regulator_pdata_s6;
-
-extern struct rpm_regulator_platform_data msm_rpm_regulator_pdata __devinitdata;
-
-#endif
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index b394710..3038ff0 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -19,21 +19,11 @@
#include <linux/msm_ssbi.h>
#include <linux/mfd/pmic8058.h>
-#include <linux/input/pmic8058-keypad.h>
-#include <linux/pmic8058-batt-alarm.h>
-#include <linux/pmic8058-pwrkey.h>
-#include <linux/rtc/rtc-pm8058.h>
-#include <linux/pmic8058-vibrator.h>
#include <linux/leds.h>
#include <linux/pmic8058-othc.h>
#include <linux/mfd/pmic8901.h>
-#include <linux/regulator/pmic8058-regulator.h>
#include <linux/regulator/pmic8901-regulator.h>
#include <linux/bootmem.h>
-#include <linux/pwm.h>
-#include <linux/pmic8058-pwm.h>
-#include <linux/leds-pmic8058.h>
-#include <linux/pmic8058-xoadc.h>
#include <linux/msm_adc.h>
#include <linux/m_adcproc.h>
#include <linux/mfd/marimba.h>
@@ -154,6 +144,10 @@
#define DSPS_PIL_GENERIC_NAME "dsps"
#define DSPS_PIL_FLUID_NAME "dsps_fluid"
+#ifdef CONFIG_ION_MSM
+static struct platform_device ion_dev;
+#endif
+
enum {
GPIO_EXPANDER_IRQ_BASE = PM8901_IRQ_BASE + NR_PMIC8901_IRQS,
GPIO_EXPANDER_GPIO_BASE = PM8901_GPIO_BASE + PM8901_MPPS,
@@ -274,6 +268,21 @@
GPIO_EPM_EXPANDER_IO15,
};
+struct pm8xxx_mpp_init_info {
+ unsigned mpp;
+ struct pm8xxx_mpp_config_data config;
+};
+
+#define PM8XXX_MPP_INIT(_mpp, _type, _level, _control) \
+{ \
+ .mpp = PM8058_MPP_PM_TO_SYS(_mpp), \
+ .config = { \
+ .type = PM8XXX_MPP_TYPE_##_type, \
+ .level = _level, \
+ .control = PM8XXX_MPP_##_control, \
+ } \
+}
+
/*
* The UI_INTx_N lines are pmic gpio lines which connect i2c
* gpio expanders to the pm8058.
@@ -1054,14 +1063,14 @@
{
unsigned ret = -ENODEV;
- struct pm8058_gpio pmic_id_cfg = {
+ struct pm_gpio pmic_id_cfg = {
.direction = PM_GPIO_DIR_IN,
.pull = PM_GPIO_PULL_UP_1P5,
.function = PM_GPIO_FUNC_NORMAL,
.vin_sel = 2,
.inv_int_pol = 0,
};
- struct pm8058_gpio pmic_id_uncfg = {
+ struct pm_gpio pmic_id_uncfg = {
.direction = PM_GPIO_DIR_IN,
.pull = PM_GPIO_PULL_NO,
.function = PM_GPIO_FUNC_NORMAL,
@@ -1080,8 +1089,8 @@
return -ENOTSUPP;
}
- if ((machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa()) &&
- !pmic_id_notif_supported) {
+ if ((machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa() ||
+ machine_is_msm8x60_ffa()) && !pmic_id_notif_supported) {
pr_debug("%s: USB_ID is not routed to PMIC"
"on V2 ffa\n", __func__);
return -ENOTSUPP;
@@ -1092,9 +1101,10 @@
if (init) {
notify_vbus_state_func_ptr = callback;
INIT_DELAYED_WORK(&pmic_id_det, pmic_id_detect);
- ret = pm8058_gpio_config(PMIC_ID_GPIO, &pmic_id_cfg);
+ ret = pm8xxx_gpio_config(PM8058_GPIO_PM_TO_SYS(PMIC_ID_GPIO),
+ &pmic_id_cfg);
if (ret) {
- pr_err("%s:return val of pm8058_gpio_config: %d\n",
+ pr_err("%s:return val of pm8xxx_gpio_config: %d\n",
__func__, ret);
return ret;
}
@@ -1110,9 +1120,10 @@
} else {
usb_phy_susp_dig_vol = 750000;
free_irq(PMICID_INT, 0);
- ret = pm8058_gpio_config(PMIC_ID_GPIO, &pmic_id_uncfg);
+ ret = pm8xxx_gpio_config(PM8058_GPIO_PM_TO_SYS(PMIC_ID_GPIO),
+ &pmic_id_uncfg);
if (ret) {
- pr_err("%s: return val of pm8058_gpio_config: %d\n",
+ pr_err("%s: return val of pm8xxx_gpio_config: %d\n",
__func__, ret);
return ret;
}
@@ -1516,7 +1527,7 @@
#endif
-
+
#ifdef CONFIG_MSM_VPE
static struct resource msm_vpe_resources[] = {
{
@@ -2518,11 +2529,6 @@
#endif
#ifdef CONFIG_I2C_SSBI
-/* PMIC SSBI */
-static struct msm_i2c_ssbi_platform_data msm_ssbi2_pdata = {
- .controller_type = MSM_SBI_CTRL_PMIC_ARBITER,
-};
-
/* CODEC/TSSC SSBI */
static struct msm_i2c_ssbi_platform_data msm_ssbi3_pdata = {
.controller_type = MSM_SBI_CTRL_SSBI,
@@ -2616,7 +2622,7 @@
#define MSM_FB_EXT_BUFT_SIZE 0
#endif
-#ifdef CONFIG_FB_MSM_OVERLAY_WRITEBACK
+#ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
/* width x height x 3 bpp x 2 frame buffer */
#define MSM_FB_WRITEBACK_SIZE (1024 * 600 * 3 * 2)
#define MSM_FB_WRITEBACK_OFFSET \
@@ -2655,7 +2661,7 @@
#define MSM_SMI_SIZE 0x4000000
#define KERNEL_SMI_BASE (MSM_SMI_BASE)
-#define KERNEL_SMI_SIZE 0x300000
+#define KERNEL_SMI_SIZE 0x600000
#define USER_SMI_BASE (KERNEL_SMI_BASE + KERNEL_SMI_SIZE)
#define USER_SMI_SIZE (MSM_SMI_SIZE - KERNEL_SMI_SIZE)
@@ -4186,7 +4192,6 @@
&msm_gsbi12_qup_i2c_device,
#endif
#ifdef CONFIG_I2C_SSBI
- &msm_device_ssbi2,
&msm_device_ssbi3,
#endif
#ifdef CONFIG_ANDROID_PMEM
@@ -4482,13 +4487,6 @@
#endif
#ifdef CONFIG_SENSORS_MSM_ADC
-static struct resource resources_adc[] = {
- {
- .start = PM8058_ADC_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_ADC_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
-};
static struct adc_access_fn xoadc_fn = {
pm8058_xoadc_select_chan_and_start_conv,
@@ -4837,37 +4835,33 @@
static void pmic8058_xoadc_mpp_config(void)
{
- int rc;
+ int rc, i;
+ struct pm8xxx_mpp_init_info xoadc_mpps[] = {
+ PM8XXX_MPP_INIT(XOADC_MPP_3, A_INPUT, PM8XXX_MPP_AIN_AMUX_CH5,
+ AOUT_CTRL_DISABLE),
+ PM8XXX_MPP_INIT(XOADC_MPP_5, A_INPUT, PM8XXX_MPP_AIN_AMUX_CH9,
+ AOUT_CTRL_DISABLE),
+ PM8XXX_MPP_INIT(XOADC_MPP_7, A_INPUT, PM8XXX_MPP_AIN_AMUX_CH6,
+ AOUT_CTRL_DISABLE),
+ PM8XXX_MPP_INIT(XOADC_MPP_8, A_INPUT, PM8XXX_MPP_AIN_AMUX_CH8,
+ AOUT_CTRL_DISABLE),
+ PM8XXX_MPP_INIT(XOADC_MPP_10, A_INPUT, PM8XXX_MPP_AIN_AMUX_CH7,
+ AOUT_CTRL_DISABLE),
+ };
rc = pm8901_mpp_config_digital_out(XOADC_MPP_4,
PM8901_MPP_DIG_LEVEL_S4, PM_MPP_DOUT_CTL_LOW);
if (rc)
pr_err("%s: Config mpp4 on pmic 8901 failed\n", __func__);
- rc = pm8058_mpp_config_analog_input(XOADC_MPP_3,
- PM_MPP_AIN_AMUX_CH5, PM_MPP_AOUT_CTL_DISABLE);
- if (rc)
- pr_err("%s: Config mpp3 on pmic 8058 failed\n", __func__);
-
- rc = pm8058_mpp_config_analog_input(XOADC_MPP_5,
- PM_MPP_AIN_AMUX_CH9, PM_MPP_AOUT_CTL_DISABLE);
- if (rc)
- pr_err("%s: Config mpp5 on pmic 8058 failed\n", __func__);
-
- rc = pm8058_mpp_config_analog_input(XOADC_MPP_7,
- PM_MPP_AIN_AMUX_CH6, PM_MPP_AOUT_CTL_DISABLE);
- if (rc)
- pr_err("%s: Config mpp7 on pmic 8058 failed\n", __func__);
-
- rc = pm8058_mpp_config_analog_input(XOADC_MPP_8,
- PM_MPP_AIN_AMUX_CH8, PM_MPP_AOUT_CTL_DISABLE);
- if (rc)
- pr_err("%s: Config mpp8 on pmic 8058 failed\n", __func__);
-
- rc = pm8058_mpp_config_analog_input(XOADC_MPP_10,
- PM_MPP_AIN_AMUX_CH7, PM_MPP_AOUT_CTL_DISABLE);
- if (rc)
- pr_err("%s: Config mpp10 on pmic 8058 failed\n", __func__);
+ for (i = 0; i < ARRAY_SIZE(xoadc_mpps); i++) {
+ rc = pm8xxx_mpp_config(xoadc_mpps[i].mpp,
+ &xoadc_mpps[i].config);
+ if (rc) {
+ pr_err("%s: Config MPP %d of PM8058 failed\n",
+ __func__, xoadc_mpps[i].mpp);
+ }
+ }
}
static struct regulator *vreg_ldo18_adc;
@@ -4932,7 +4926,7 @@
.conversiontime = 54,
};
-static struct xoadc_platform_data xoadc_pdata = {
+static struct xoadc_platform_data pm8058_xoadc_pdata = {
.xoadc_prop = &pm8058_xoadc_data,
.xoadc_mpp_config = pmic8058_xoadc_mpp_config,
.xoadc_vreg_set = pmic8058_xoadc_vreg_config,
@@ -5034,9 +5028,9 @@
#endif
#ifdef CONFIG_MSM_SSBI
&msm_device_ssbi_pmic1,
+ &msm_device_ssbi_pmic2,
#endif
#ifdef CONFIG_I2C_SSBI
- &msm_device_ssbi2,
&msm_device_ssbi3,
#endif
#if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
@@ -5168,7 +5162,7 @@
};
#ifdef CONFIG_ION_MSM
-struct ion_platform_data ion_pdata = {
+static struct ion_platform_data ion_pdata = {
.nr = MSM_ION_HEAP_NUM,
.heaps = {
{
@@ -5207,7 +5201,7 @@
}
};
-struct platform_device ion_dev = {
+static struct platform_device ion_dev = {
.name = "ion-msm",
.id = 1,
.dev = { .platform_data = &ion_pdata },
@@ -5314,18 +5308,28 @@
#define EXT_CHG_VALID_MPP 10
#define EXT_CHG_VALID_MPP_2 11
+static struct pm8xxx_mpp_init_info isl_mpp[] = {
+ PM8XXX_MPP_INIT(EXT_CHG_VALID_MPP, D_INPUT,
+ PM8058_MPP_DIG_LEVEL_S3, DIN_TO_INT),
+ PM8XXX_MPP_INIT(EXT_CHG_VALID_MPP_2, D_BI_DIR,
+ PM8058_MPP_DIG_LEVEL_S3, BI_PULLUP_10KOHM),
+};
+
#ifdef CONFIG_ISL9519_CHARGER
static int isl_detection_setup(void)
{
- int ret = 0;
+ int ret = 0, i;
- ret = pm8058_mpp_config_digital_in(EXT_CHG_VALID_MPP,
- PM8058_MPP_DIG_LEVEL_S3,
- PM_MPP_DIN_TO_INT);
- ret |= pm8058_mpp_config_bi_dir(EXT_CHG_VALID_MPP_2,
- PM8058_MPP_DIG_LEVEL_S3,
- PM_MPP_BI_PULLUP_10KOHM
- );
+ for (i = 0; i < ARRAY_SIZE(isl_mpp); i++) {
+ ret = pm8xxx_mpp_config(isl_mpp[i].mpp,
+ &isl_mpp[i].config);
+ if (ret) {
+ pr_err("%s: Config MPP %d of PM8058 failed\n",
+ __func__, isl_mpp[i].mpp);
+ return ret;
+ }
+ }
+
return ret;
}
@@ -5342,7 +5346,7 @@
static struct i2c_board_info isl_charger_i2c_info[] __initdata = {
{
I2C_BOARD_INFO("isl9519q", 0x9),
- .irq = PM8058_CBLPWR_IRQ(PM8058_IRQ_BASE),
+ .irq = PM8058_IRQ_BASE + PM8058_CBLPWR_IRQ,
.platform_data = &isl_data,
},
};
@@ -5351,14 +5355,18 @@
#if defined(CONFIG_SMB137B_CHARGER) || defined(CONFIG_SMB137B_CHARGER_MODULE)
static int smb137b_detection_setup(void)
{
- int ret = 0;
+ int ret = 0, i;
- ret = pm8058_mpp_config_digital_in(EXT_CHG_VALID_MPP,
- PM8058_MPP_DIG_LEVEL_S3,
- PM_MPP_DIN_TO_INT);
- ret |= pm8058_mpp_config_bi_dir(EXT_CHG_VALID_MPP_2,
- PM8058_MPP_DIG_LEVEL_S3,
- PM_MPP_BI_PULLUP_10KOHM);
+ for (i = 0; i < ARRAY_SIZE(isl_mpp); i++) {
+ ret = pm8xxx_mpp_config(isl_mpp[i].mpp,
+ &isl_mpp[i].config);
+ if (ret) {
+ pr_err("%s: Config MPP %d of PM8058 failed\n",
+ __func__, isl_mpp[i].mpp);
+ return ret;
+ }
+ }
+
return ret;
}
@@ -5371,7 +5379,7 @@
static struct i2c_board_info smb137b_charger_i2c_info[] __initdata = {
{
I2C_BOARD_INFO("smb137b", 0x08),
- .irq = PM8058_CBLPWR_IRQ(PM8058_IRQ_BASE),
+ .irq = PM8058_IRQ_BASE + PM8058_CBLPWR_IRQ,
.platform_data = &smb137b_data,
},
};
@@ -5387,12 +5395,12 @@
int rc;
struct pm8058_gpio_cfg {
int gpio;
- struct pm8058_gpio cfg;
+ struct pm_gpio cfg;
};
struct pm8058_gpio_cfg gpio_cfgs[] = {
{ /* FFA ethernet */
- 6,
+ PM8058_GPIO_PM_TO_SYS(6),
{
.direction = PM_GPIO_DIR_IN,
.pull = PM_GPIO_PULL_DN,
@@ -5403,7 +5411,7 @@
},
#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
{
- PMIC_GPIO_SDC3_DET - 1,
+ PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_SDC3_DET - 1),
{
.direction = PM_GPIO_DIR_IN,
.pull = PM_GPIO_PULL_UP_30,
@@ -5414,37 +5422,37 @@
},
#endif
{ /* core&surf gpio expander */
- UI_INT1_N,
+ PM8058_GPIO_PM_TO_SYS(UI_INT1_N),
{
.direction = PM_GPIO_DIR_IN,
.pull = PM_GPIO_PULL_NO,
- .vin_sel = PM_GPIO_VIN_S3,
+ .vin_sel = PM8058_GPIO_VIN_S3,
.function = PM_GPIO_FUNC_NORMAL,
.inv_int_pol = 0,
},
},
{ /* docking gpio expander */
- UI_INT2_N,
+ PM8058_GPIO_PM_TO_SYS(UI_INT2_N),
{
.direction = PM_GPIO_DIR_IN,
.pull = PM_GPIO_PULL_NO,
- .vin_sel = PM_GPIO_VIN_S3,
+ .vin_sel = PM8058_GPIO_VIN_S3,
.function = PM_GPIO_FUNC_NORMAL,
.inv_int_pol = 0,
},
},
{ /* FHA/keypad gpio expanders */
- UI_INT3_N,
+ PM8058_GPIO_PM_TO_SYS(UI_INT3_N),
{
.direction = PM_GPIO_DIR_IN,
.pull = PM_GPIO_PULL_NO,
- .vin_sel = PM_GPIO_VIN_S3,
+ .vin_sel = PM8058_GPIO_VIN_S3,
.function = PM_GPIO_FUNC_NORMAL,
.inv_int_pol = 0,
},
},
{ /* Timpani Reset */
- 20,
+ PM8058_GPIO_PM_TO_SYS(20),
{
.direction = PM_GPIO_DIR_OUT,
.output_value = 1,
@@ -5457,7 +5465,7 @@
}
},
{ /* PMIC ID interrupt */
- 36,
+ PM8058_GPIO_PM_TO_SYS(36),
{
.direction = PM_GPIO_DIR_IN,
.pull = PM_GPIO_PULL_NO,
@@ -5470,7 +5478,7 @@
#if defined(CONFIG_TOUCHDISC_VTD518_SHINETSU) || \
defined(CONFIG_TOUCHDISC_VTD518_SHINETSU_MODULE)
- struct pm8058_gpio touchdisc_intr_gpio_cfg = {
+ struct pm_gpio touchdisc_intr_gpio_cfg = {
.direction = PM_GPIO_DIR_IN,
.pull = PM_GPIO_PULL_UP_1P5,
.vin_sel = 2,
@@ -5480,7 +5488,7 @@
#if defined(CONFIG_HAPTIC_ISA1200) || \
defined(CONFIG_HAPTIC_ISA1200_MODULE)
- struct pm8058_gpio en_hap_gpio_cfg = {
+ struct pm_gpio en_hap_gpio_cfg = {
.direction = PM_GPIO_DIR_OUT,
.pull = PM_GPIO_PULL_NO,
.out_strength = PM_GPIO_STRENGTH_HIGH,
@@ -5494,7 +5502,7 @@
#if defined(CONFIG_PMIC8058_OTHC) || defined(CONFIG_PMIC8058_OTHC_MODULE)
struct pm8058_gpio_cfg line_in_gpio_cfg = {
- 18,
+ PM8058_GPIO_PM_TO_SYS(18),
{
.direction = PM_GPIO_DIR_IN,
.pull = PM_GPIO_PULL_UP_1P5,
@@ -5508,7 +5516,7 @@
#if defined(CONFIG_QS_S5K4E1)
{
struct pm8058_gpio_cfg qs_hc37_cam_pd_gpio_cfg = {
- 26,
+ PM8058_GPIO_PM_TO_SYS(26),
{
.direction = PM_GPIO_DIR_OUT,
.output_value = 0,
@@ -5523,32 +5531,33 @@
#endif
#ifdef CONFIG_FB_MSM_LCDC_NT35582_WVGA
struct pm8058_gpio_cfg pmic_lcdc_nt35582_gpio_cfg = {
- GPIO_NT35582_BL_EN_HW_PIN - 1,
+ PM8058_GPIO_PM_TO_SYS(GPIO_NT35582_BL_EN_HW_PIN - 1),
{
.direction = PM_GPIO_DIR_OUT,
.output_buffer = PM_GPIO_OUT_BUF_CMOS,
.output_value = 1,
.pull = PM_GPIO_PULL_UP_30,
/* 2.9V PM_GPIO_VIN_L2, which gives 2.6V */
- .vin_sel = PM_GPIO_VIN_L5,
+ .vin_sel = PM8058_GPIO_VIN_L5,
.out_strength = PM_GPIO_STRENGTH_HIGH,
.function = PM_GPIO_FUNC_NORMAL,
.inv_int_pol = 0,
}
};
#endif
-
#if defined(CONFIG_HAPTIC_ISA1200) || \
defined(CONFIG_HAPTIC_ISA1200_MODULE)
if (machine_is_msm8x60_fluid()) {
- rc = pm8058_gpio_config(PMIC_GPIO_HAP_ENABLE,
- &en_hap_gpio_cfg);
+ rc = pm8xxx_gpio_config(
+ PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_HAP_ENABLE),
+ &en_hap_gpio_cfg);
if (rc < 0) {
pr_err("%s: pmic haptics gpio config failed\n",
__func__);
}
- rc = pm8058_gpio_config(PMIC_GPIO_HAP_LDO_ENABLE,
- &en_hap_gpio_cfg);
+ rc = pm8xxx_gpio_config(
+ PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_HAP_LDO_ENABLE),
+ &en_hap_gpio_cfg);
if (rc < 0) {
pr_err("%s: pmic haptics ldo gpio config failed\n",
__func__);
@@ -5561,8 +5570,9 @@
defined(CONFIG_TOUCHDISC_VTD518_SHINETSU_MODULE)
if (machine_is_msm8x60_ffa() || machine_is_msm8x60_surf() ||
machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa()) {
- rc = pm8058_gpio_config(PMIC_GPIO_TOUCH_DISC_INTR,
- &touchdisc_intr_gpio_cfg);
+ rc = pm8xxx_gpio_config(
+ PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_TOUCH_DISC_INTR),
+ &touchdisc_intr_gpio_cfg);
if (rc < 0) {
pr_err("%s: Touchdisc interrupt gpio config failed\n",
__func__);
@@ -5575,7 +5585,7 @@
if (machine_is_msm8x60_ffa() || machine_is_msm8x60_surf() ||
machine_is_msm8x60_fusion() || machine_is_msm8x60_dragon() ||
machine_is_msm8x60_fusn_ffa()) {
- rc = pm8058_gpio_config(line_in_gpio_cfg.gpio,
+ rc = pm8xxx_gpio_config(line_in_gpio_cfg.gpio,
&line_in_gpio_cfg.cfg);
if (rc < 0) {
pr_err("%s pmic line_in gpio config failed\n",
@@ -5587,7 +5597,7 @@
#ifdef CONFIG_FB_MSM_LCDC_NT35582_WVGA
if (machine_is_msm8x60_dragon()) {
- rc = pm8058_gpio_config(pmic_lcdc_nt35582_gpio_cfg.gpio,
+ rc = pm8xxx_gpio_config(pmic_lcdc_nt35582_gpio_cfg.gpio,
&pmic_lcdc_nt35582_gpio_cfg.cfg);
if (rc < 0) {
pr_err("%s pmic gpio config failed\n", __func__);
@@ -5599,7 +5609,7 @@
#if defined(CONFIG_QS_S5K4E1)
/* qs_cam_hc37_cam_pd only for 8660 fluid qs camera*/
if (machine_is_msm8x60_fluid()) {
- rc = pm8058_gpio_config(qs_hc37_cam_pd_gpio_cfg.gpio,
+ rc = pm8xxx_gpio_config(qs_hc37_cam_pd_gpio_cfg.gpio,
&qs_hc37_cam_pd_gpio_cfg.cfg);
if (rc < 0) {
pr_err("%s pmic qs_hc37_cam_pd gpio config failed\n",
@@ -5611,7 +5621,7 @@
#endif
for (i = 0; i < ARRAY_SIZE(gpio_cfgs); ++i) {
- rc = pm8058_gpio_config(gpio_cfgs[i].gpio,
+ rc = pm8xxx_gpio_config(gpio_cfgs[i].gpio,
&gpio_cfgs[i].cfg);
if (rc < 0) {
pr_err("%s pmic gpio config failed\n",
@@ -5679,32 +5689,19 @@
KEY(4, 3, KEY_KBDILLUMTOGGLE),
};
-static struct resource resources_keypad[] = {
- {
- .start = PM8058_KEYPAD_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_KEYPAD_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .start = PM8058_KEYSTUCK_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_KEYSTUCK_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
-};
-
static struct matrix_keymap_data ffa_keymap_data = {
.keymap_size = ARRAY_SIZE(ffa_keymap),
.keymap = ffa_keymap,
};
-static struct pmic8058_keypad_data ffa_keypad_data = {
+static struct pm8xxx_keypad_platform_data ffa_keypad_data = {
.input_name = "ffa-keypad",
.input_phys_device = "ffa-keypad/input0",
.num_rows = 6,
.num_cols = 5,
- .rows_gpio_start = 8,
- .cols_gpio_start = 0,
- .debounce_ms = {8, 10},
+ .rows_gpio_start = PM8058_GPIO_PM_TO_SYS(8),
+ .cols_gpio_start = PM8058_GPIO_PM_TO_SYS(0),
+ .debounce_ms = 15,
.scan_delay_ms = 32,
.row_hold_ns = 91500,
.wakeup = 1,
@@ -5716,19 +5713,20 @@
.keymap = dragon_keymap,
};
-static struct pmic8058_keypad_data dragon_keypad_data = {
+static struct pm8xxx_keypad_platform_data dragon_keypad_data = {
.input_name = "dragon-keypad",
.input_phys_device = "dragon-keypad/input0",
.num_rows = 6,
.num_cols = 5,
- .rows_gpio_start = 8,
- .cols_gpio_start = 0,
- .debounce_ms = {8, 10},
+ .rows_gpio_start = PM8058_GPIO_PM_TO_SYS(8),
+ .cols_gpio_start = PM8058_GPIO_PM_TO_SYS(0),
+ .debounce_ms = 15,
.scan_delay_ms = 32,
.row_hold_ns = 91500,
.wakeup = 1,
.keymap_data = &dragon_keymap_data,
};
+
static const unsigned int fluid_keymap[] = {
KEY(0, 0, KEY_FN_F1), /* LS - PUSH1 */
KEY(0, 1, KEY_UP), /* NAV - UP */
@@ -5760,50 +5758,37 @@
.keymap = fluid_keymap,
};
-static struct pmic8058_keypad_data fluid_keypad_data = {
+static struct pm8xxx_keypad_platform_data fluid_keypad_data = {
.input_name = "fluid-keypad",
.input_phys_device = "fluid-keypad/input0",
.num_rows = 6,
.num_cols = 5,
- .rows_gpio_start = 8,
- .cols_gpio_start = 0,
- .debounce_ms = {8, 10},
+ .rows_gpio_start = PM8058_GPIO_PM_TO_SYS(8),
+ .cols_gpio_start = PM8058_GPIO_PM_TO_SYS(0),
+ .debounce_ms = 15,
.scan_delay_ms = 32,
.row_hold_ns = 91500,
.wakeup = 1,
.keymap_data = &fluid_keymap_data,
};
-static struct resource resources_pwrkey[] = {
- {
- .start = PM8058_PWRKEY_REL_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_PWRKEY_REL_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .start = PM8058_PWRKEY_PRESS_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_PWRKEY_PRESS_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct pmic8058_pwrkey_pdata pwrkey_pdata = {
- .pull_up = 1,
- .kpd_trigger_delay_us = 970,
- .wakeup = 1,
- .pwrkey_time_ms = 500,
-};
-
-static struct pmic8058_vibrator_pdata pmic_vib_pdata = {
+static struct pm8xxx_vibrator_platform_data pm8058_vib_pdata = {
.initial_vibrate_ms = 500,
.level_mV = 3000,
.max_timeout_ms = 15000,
};
-#if defined(CONFIG_PMIC8058_OTHC) || defined(CONFIG_PMIC8058_OTHC_MODULE)
-#define PM8058_OTHC_CNTR_BASE0 0xA0
-#define PM8058_OTHC_CNTR_BASE1 0x134
-#define PM8058_OTHC_CNTR_BASE2 0x137
+static struct pm8xxx_rtc_platform_data pm8058_rtc_pdata = {
+ .rtc_write_enable = false,
+ .rtc_alarm_powerup = false,
+};
+
+static struct pm8xxx_pwrkey_platform_data pm8058_pwrkey_pdata = {
+ .pull_up = 1,
+ .kpd_trigger_delay_us = 15625,
+ .wakeup = 1,
+};
+
#define PM8058_LINE_IN_DET_GPIO PM8058_GPIO_PM_TO_SYS(18)
static struct othc_accessory_info othc_accessories[] = {
@@ -5950,42 +5935,6 @@
.micbias_regulator = &othc_reg,
};
-static struct resource resources_othc_0[] = {
- {
- .name = "othc_base",
- .start = PM8058_OTHC_CNTR_BASE0,
- .end = PM8058_OTHC_CNTR_BASE0,
- .flags = IORESOURCE_IO,
- },
-};
-
-static struct resource resources_othc_1[] = {
- {
- .start = PM8058_SW_1_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_SW_1_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .start = PM8058_IR_1_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_IR_1_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "othc_base",
- .start = PM8058_OTHC_CNTR_BASE1,
- .end = PM8058_OTHC_CNTR_BASE1,
- .flags = IORESOURCE_IO,
- },
-};
-
-static struct resource resources_othc_2[] = {
- {
- .name = "othc_base",
- .start = PM8058_OTHC_CNTR_BASE2,
- .end = PM8058_OTHC_CNTR_BASE2,
- .flags = IORESOURCE_IO,
- },
-};
static void __init msm8x60_init_pm8058_othc(void)
{
@@ -6023,143 +5972,16 @@
}
}
}
-#endif
-static struct resource resources_pm8058_charger[] = {
- { .name = "CHGVAL",
- .start = PM8058_CHGVAL_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_CHGVAL_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- { .name = "CHGINVAL",
- .start = PM8058_CHGINVAL_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_CHGINVAL_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "CHGILIM",
- .start = PM8058_CHGILIM_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_CHGILIM_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "VCP",
- .start = PM8058_VCP_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_VCP_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "ATC_DONE",
- .start = PM8058_ATC_DONE_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_ATC_DONE_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "ATCFAIL",
- .start = PM8058_ATCFAIL_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_ATCFAIL_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "AUTO_CHGDONE",
- .start = PM8058_AUTO_CHGDONE_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_AUTO_CHGDONE_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "AUTO_CHGFAIL",
- .start = PM8058_AUTO_CHGFAIL_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_AUTO_CHGFAIL_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "CHGSTATE",
- .start = PM8058_CHGSTATE_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_CHGSTATE_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "FASTCHG",
- .start = PM8058_FASTCHG_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_FASTCHG_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "CHG_END",
- .start = PM8058_CHG_END_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_CHG_END_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "BATTTEMP",
- .start = PM8058_BATTTEMP_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_BATTTEMP_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "CHGHOT",
- .start = PM8058_CHGHOT_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_CHGHOT_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "CHGTLIMIT",
- .start = PM8058_CHGTLIMIT_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_CHGTLIMIT_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "CHG_GONE",
- .start = PM8058_CHG_GONE_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_CHG_GONE_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "VCPMAJOR",
- .start = PM8058_VCPMAJOR_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_VCPMAJOR_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "VBATDET",
- .start = PM8058_VBATDET_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_VBATDET_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "BATFET",
- .start = PM8058_BATFET_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_BATFET_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "BATT_REPLACE",
- .start = PM8058_BATT_REPLACE_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_BATT_REPLACE_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "BATTCONNECT",
- .start = PM8058_BATTCONNECT_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_BATTCONNECT_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "VBATDET_LOW",
- .start = PM8058_VBATDET_LOW_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_VBATDET_LOW_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
-};
static int pm8058_pwm_config(struct pwm_device *pwm, int ch, int on)
{
- struct pm8058_gpio pwm_gpio_config = {
+ struct pm_gpio pwm_gpio_config = {
.direction = PM_GPIO_DIR_OUT,
.output_buffer = PM_GPIO_OUT_BUF_CMOS,
.output_value = 0,
.pull = PM_GPIO_PULL_NO,
- .vin_sel = PM_GPIO_VIN_VPH,
+ .vin_sel = PM8058_GPIO_VIN_VPH,
.out_strength = PM_GPIO_STRENGTH_HIGH,
.function = PM_GPIO_FUNC_2,
};
@@ -6174,9 +5996,10 @@
case 2:
if (on) {
id = 24 + ch;
- rc = pm8058_gpio_config(id - 1, &pwm_gpio_config);
+ rc = pm8xxx_gpio_config(PM8058_GPIO_PM_TO_SYS(id - 1),
+ &pwm_gpio_config);
if (rc)
- pr_err("%s: pm8058_gpio_config(%d): rc=%d\n",
+ pr_err("%s: pm8xxx_gpio_config(%d): rc=%d\n",
__func__, id, rc);
}
break;
@@ -6217,34 +6040,6 @@
#define PM8058_GPIO_INT 88
-static struct pm8058_gpio_platform_data pm8058_gpio_data = {
- .gpio_base = PM8058_GPIO_PM_TO_SYS(0),
- .irq_base = PM8058_GPIO_IRQ(PM8058_IRQ_BASE, 0),
- .init = pm8058_gpios_init,
-};
-
-static struct pm8058_gpio_platform_data pm8058_mpp_data = {
- .gpio_base = PM8058_GPIO_PM_TO_SYS(PM8058_GPIOS),
- .irq_base = PM8058_MPP_IRQ(PM8058_IRQ_BASE, 0),
-};
-
-static struct resource resources_rtc[] = {
- {
- .start = PM8058_RTC_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_RTC_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
- {
- .start = PM8058_RTC_ALARM_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_RTC_ALARM_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct pm8058_rtc_platform_data pm8058_rtc_pdata = {
- .rtc_alarm_powerup = false,
-};
-
static struct pmic8058_led pmic8058_flash_leds[] = {
[0] = {
.name = "camera:flash0",
@@ -6322,156 +6117,48 @@
.leds = pmic8058_fluid_flash_leds,
};
-static struct resource resources_temp_alarm[] = {
- {
- .start = PM8058_TEMP_ALARM_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_TEMP_ALARM_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct resource resources_pm8058_misc[] = {
- {
- .start = PM8058_OSCHALT_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_OSCHALT_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct resource resources_pm8058_batt_alarm[] = {
- {
- .start = PM8058_BATT_ALARM_IRQ(PM8058_IRQ_BASE),
- .end = PM8058_BATT_ALARM_IRQ(PM8058_IRQ_BASE),
- .flags = IORESOURCE_IRQ,
- },
-};
-
-#define PM8058_SUBDEV_KPD 0
-#define PM8058_SUBDEV_LED 1
-#define PM8058_SUBDEV_VIB 2
-
-static struct mfd_cell pm8058_subdevs[] = {
- {
- .name = "pm8058-keypad",
- .id = -1,
- .num_resources = ARRAY_SIZE(resources_keypad),
- .resources = resources_keypad,
- },
- { .name = "pm8058-led",
- .id = -1,
- },
- {
- .name = "pm8058-vib",
- .id = -1,
- },
- { .name = "pm8058-gpio",
- .id = -1,
- .platform_data = &pm8058_gpio_data,
- .pdata_size = sizeof(pm8058_gpio_data),
- },
- { .name = "pm8058-mpp",
- .id = -1,
- .platform_data = &pm8058_mpp_data,
- .pdata_size = sizeof(pm8058_mpp_data),
- },
- { .name = "pm8058-pwrkey",
- .id = -1,
- .resources = resources_pwrkey,
- .num_resources = ARRAY_SIZE(resources_pwrkey),
- .platform_data = &pwrkey_pdata,
- .pdata_size = sizeof(pwrkey_pdata),
- },
- {
- .name = "pm8058-pwm",
- .id = -1,
- .platform_data = &pm8058_pwm_data,
- .pdata_size = sizeof(pm8058_pwm_data),
- },
-#ifdef CONFIG_SENSORS_MSM_ADC
- {
- .name = "pm8058-xoadc",
- .id = -1,
- .num_resources = ARRAY_SIZE(resources_adc),
- .resources = resources_adc,
- .platform_data = &xoadc_pdata,
- .pdata_size = sizeof(xoadc_pdata),
- },
-#endif
-#if defined(CONFIG_PMIC8058_OTHC) || defined(CONFIG_PMIC8058_OTHC_MODULE)
- {
- .name = "pm8058-othc",
- .id = 0,
- .platform_data = &othc_config_pdata_0,
- .pdata_size = sizeof(othc_config_pdata_0),
- .num_resources = ARRAY_SIZE(resources_othc_0),
- .resources = resources_othc_0,
- },
- {
- /* OTHC1 module has headset/switch dection */
- .name = "pm8058-othc",
- .id = 1,
- .num_resources = ARRAY_SIZE(resources_othc_1),
- .resources = resources_othc_1,
- .platform_data = &othc_config_pdata_1,
- .pdata_size = sizeof(othc_config_pdata_1),
- },
- {
- .name = "pm8058-othc",
- .id = 2,
- .platform_data = &othc_config_pdata_2,
- .pdata_size = sizeof(othc_config_pdata_2),
- .num_resources = ARRAY_SIZE(resources_othc_2),
- .resources = resources_othc_2,
- },
-#endif
- {
- .name = "pm8058-rtc",
- .id = -1,
- .num_resources = ARRAY_SIZE(resources_rtc),
- .resources = resources_rtc,
- .platform_data = &pm8058_rtc_pdata,
- },
- {
- .name = "pm8058-tm",
- .id = -1,
- .num_resources = ARRAY_SIZE(resources_temp_alarm),
- .resources = resources_temp_alarm,
- },
- { .name = "pm8058-upl",
- .id = -1,
- },
- {
- .name = "pm8058-misc",
- .id = -1,
- .num_resources = ARRAY_SIZE(resources_pm8058_misc),
- .resources = resources_pm8058_misc,
- },
- { .name = "pm8058-batt-alarm",
- .id = -1,
- .num_resources = ARRAY_SIZE(resources_pm8058_batt_alarm),
- .resources = resources_pm8058_batt_alarm,
- },
-};
-
static struct pmic8058_charger_data pmic8058_charger_dragon = {
+ .charger_data_valid = true,
.max_source_current = 1800,
.charger_type = CHG_TYPE_AC,
};
-static struct mfd_cell pm8058_charger_sub_dev = {
- .name = "pm8058-charger",
- .id = -1,
- .num_resources = ARRAY_SIZE(resources_pm8058_charger),
- .resources = resources_pm8058_charger,
+static struct pmic8058_charger_data pmic8058_charger_ffa_surf = {
+ .charger_data_valid = false,
+};
+
+static struct pm8xxx_misc_platform_data pm8058_misc_pdata = {
+ .priority = 0,
+};
+
+static struct pm8xxx_irq_platform_data pm8058_irq_pdata = {
+ .irq_base = PM8058_IRQ_BASE,
+ .devirq = MSM_GPIO_TO_INT(PM8058_GPIO_INT),
+ .irq_trigger_flag = IRQF_TRIGGER_LOW,
+};
+
+static struct pm8xxx_gpio_platform_data pm8058_gpio_pdata = {
+ .gpio_base = PM8058_GPIO_PM_TO_SYS(0),
+};
+
+static struct pm8xxx_mpp_platform_data pm8058_mpp_pdata = {
+ .mpp_base = PM8058_MPP_PM_TO_SYS(0),
};
static struct pm8058_platform_data pm8058_platform_data = {
- .irq_base = PM8058_IRQ_BASE,
- .irq = MSM_GPIO_TO_INT(PM8058_GPIO_INT),
-
- .num_subdevs = ARRAY_SIZE(pm8058_subdevs),
- .sub_devices = pm8058_subdevs,
- .irq_trigger_flags = IRQF_TRIGGER_LOW,
+ .irq_pdata = &pm8058_irq_pdata,
+ .gpio_pdata = &pm8058_gpio_pdata,
+ .mpp_pdata = &pm8058_mpp_pdata,
+ .rtc_pdata = &pm8058_rtc_pdata,
+ .pwrkey_pdata = &pm8058_pwrkey_pdata,
+ .othc0_pdata = &othc_config_pdata_0,
+ .othc1_pdata = &othc_config_pdata_1,
+ .othc2_pdata = &othc_config_pdata_2,
+ .pwm_pdata = &pm8058_pwm_data,
+ .misc_pdata = &pm8058_misc_pdata,
+#ifdef CONFIG_SENSORS_MSM_ADC
+ .xoadc_pdata = &pm8058_xoadc_pdata,
+#endif
};
#ifdef CONFIG_MSM_SSBI
@@ -6932,19 +6619,19 @@
static struct pm8901_platform_data pm8901_platform_data = {
.irq_base = PM8901_IRQ_BASE,
+ .irq = MSM_GPIO_TO_INT(PM8901_GPIO_INT),
.num_subdevs = ARRAY_SIZE(pm8901_subdevs),
.sub_devices = pm8901_subdevs,
.irq_trigger_flags = IRQF_TRIGGER_LOW,
};
-static struct i2c_board_info pm8901_boardinfo[] __initdata = {
- {
- I2C_BOARD_INFO("pm8901-core", 0x55),
- .irq = MSM_GPIO_TO_INT(PM8901_GPIO_INT),
+static struct msm_ssbi_platform_data msm8x60_ssbi_pm8901_pdata __devinitdata = {
+ .controller_type = MSM_SBI_CTRL_PMIC_ARBITER,
+ .slave = {
+ .name = "pm8901-core",
.platform_data = &pm8901_platform_data,
},
};
-
#endif /* CONFIG_PMIC8901 */
#if defined(CONFIG_MARIMBA_CORE) && (defined(CONFIG_GPIO_SX150X) \
@@ -7108,10 +6795,10 @@
static int fm_radio_setup(struct marimba_fm_platform_data *pdata)
{
int rc = 0;
- struct pm8058_gpio cfg = {
+ struct pm_gpio cfg = {
.direction = PM_GPIO_DIR_IN,
.pull = PM_GPIO_PULL_NO,
- .vin_sel = PM_GPIO_VIN_S3,
+ .vin_sel = PM8058_GPIO_VIN_S3,
.function = PM_GPIO_FUNC_NORMAL,
.inv_int_pol = 0,
};
@@ -7159,9 +6846,9 @@
}
/*GPIO 18 on PMIC is FM_IRQ*/
- rc = pm8058_gpio_config(FM_GPIO, &cfg);
+ rc = pm8xxx_gpio_config(PM8058_GPIO_PM_TO_SYS(FM_GPIO), &cfg);
if (rc) {
- printk(KERN_ERR "%s: return val of pm8058_gpio_config: %d\n",
+ printk(KERN_ERR "%s: return val of pm8xxx_gpio_config: %d\n",
__func__, rc);
goto fm_fail_clock;
}
@@ -7257,14 +6944,6 @@
};
static struct i2c_registry msm8x60_i2c_devices[] __initdata = {
-#ifdef CONFIG_PMIC8901
- {
- I2C_SURF | I2C_FFA | I2C_FLUID | I2C_DRAGON,
- MSM_SSBI2_I2C_BUS_ID,
- pm8901_boardinfo,
- ARRAY_SIZE(pm8901_boardinfo),
- },
-#endif
#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
{
I2C_SURF | I2C_FFA | I2C_DRAGON,
@@ -7527,13 +7206,14 @@
msm_gsbi1_qup_spi_device.dev.platform_data = &msm_gsbi1_qup_spi_pdata;
#endif
#ifdef CONFIG_I2C_SSBI
- msm_device_ssbi2.dev.platform_data = &msm_ssbi2_pdata;
msm_device_ssbi3.dev.platform_data = &msm_ssbi3_pdata;
#endif
#ifdef CONFIG_MSM_SSBI
msm_device_ssbi_pmic1.dev.platform_data =
&msm8x60_ssbi_pm8058_pdata;
+ msm_device_ssbi_pmic2.dev.platform_data =
+ &msm8x60_ssbi_pm8901_pdata;
#endif
if (machine_is_msm8x60_fluid()) {
@@ -9616,7 +9296,7 @@
goto out;
} else {
/* set ldo0 to LPM */
- rc = regulator_set_optimum_mode(ldo0, 9000);
+ rc = regulator_set_optimum_mode(ldo0, 1000);
if (rc < 0)
goto out;
}
@@ -10226,7 +9906,7 @@
{
uint32_t soc_platform_version;
- pmic_reset_irq = PM8058_RESOUT_IRQ(PM8058_IRQ_BASE);
+ pmic_reset_irq = PM8058_IRQ_BASE + PM8058_RESOUT_IRQ;
/*
* Initialize RPM first as other drivers and devices may need
@@ -10322,28 +10002,12 @@
msm8x60_init_pm8058_othc();
#endif
- if (machine_is_msm8x60_fluid()) {
- pm8058_platform_data.sub_devices[PM8058_SUBDEV_KPD].
- platform_data = &fluid_keypad_data;
- pm8058_platform_data.sub_devices[PM8058_SUBDEV_KPD].pdata_size
- = sizeof(fluid_keypad_data);
- } else if (machine_is_msm8x60_dragon()) {
- pm8058_platform_data.sub_devices[PM8058_SUBDEV_KPD].
- platform_data = &dragon_keypad_data;
- pm8058_platform_data.sub_devices[PM8058_SUBDEV_KPD].pdata_size
- = sizeof(dragon_keypad_data);
- } else {
- pm8058_platform_data.sub_devices[PM8058_SUBDEV_KPD].
- platform_data = &ffa_keypad_data;
- pm8058_platform_data.sub_devices[PM8058_SUBDEV_KPD].pdata_size
- = sizeof(ffa_keypad_data);
-
- }
-
- /* Disable END_CALL simulation function of powerkey on fluid */
- if (machine_is_msm8x60_fluid()) {
- pwrkey_pdata.pwrkey_time_ms = 0;
- }
+ if (machine_is_msm8x60_fluid())
+ pm8058_platform_data.keypad_pdata = &fluid_keypad_data;
+ else if (machine_is_msm8x60_dragon())
+ pm8058_platform_data.keypad_pdata = &dragon_keypad_data;
+ else
+ pm8058_platform_data.keypad_pdata = &ffa_keypad_data;
/* Specify reset pin for OV9726 */
if (machine_is_msm8x60_dragon()) {
@@ -10351,6 +10015,31 @@
ov9726_sensor_8660_info.mount_angle = 270;
}
+#ifdef CONFIG_BATTERY_MSM8X60
+ if (machine_is_msm8x60_surf() || machine_is_msm8x60_ffa() ||
+ machine_is_msm8x60_fusion() || machine_is_msm8x60_dragon() ||
+ machine_is_msm8x60_fusn_ffa() || machine_is_msm8x60_fluid())
+ platform_device_register(&msm_charger_device);
+#endif
+
+ if (machine_is_msm8x60_dragon())
+ pm8058_platform_data.charger_pdata = &pmic8058_charger_dragon;
+ if (!machine_is_msm8x60_fluid())
+ pm8058_platform_data.charger_pdata = &pmic8058_charger_ffa_surf;
+
+ /* configure pmic leds */
+ if (machine_is_msm8x60_fluid())
+ pm8058_platform_data.leds_pdata = &pm8058_fluid_flash_leds_data;
+ else if (machine_is_msm8x60_dragon())
+ pm8058_platform_data.leds_pdata = &pm8058_dragon_leds_data;
+ else
+ pm8058_platform_data.leds_pdata = &pm8058_flash_leds_data;
+
+ if (machine_is_msm8x60_ffa() || machine_is_msm8x60_fusn_ffa() ||
+ machine_is_msm8x60_dragon()) {
+ pm8058_platform_data.vibrator_pdata = &pm8058_vib_pdata;
+ }
+
if (machine_is_msm8x60_surf() || machine_is_msm8x60_ffa() ||
machine_is_msm8x60_fluid() || machine_is_msm8x60_fusion() ||
machine_is_msm8x60_fusn_ffa() || machine_is_msm8x60_dragon()) {
@@ -10398,25 +10087,10 @@
machine_is_msm8x60_dragon())
msm8x60_cfg_isp1763();
#endif
-#ifdef CONFIG_BATTERY_MSM8X60
- if (machine_is_msm8x60_surf() || machine_is_msm8x60_ffa() ||
- machine_is_msm8x60_fusion() || machine_is_msm8x60_dragon() ||
- machine_is_msm8x60_fusn_ffa() || machine_is_msm8x60_fluid())
- platform_device_register(&msm_charger_device);
-#endif
if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
platform_add_devices(charm_devices, ARRAY_SIZE(charm_devices));
- if (machine_is_msm8x60_dragon()) {
- pm8058_charger_sub_dev.platform_data
- = &pmic8058_charger_dragon;
- pm8058_charger_sub_dev.pdata_size
- = sizeof(pmic8058_charger_dragon);
- }
- if (!machine_is_msm8x60_fluid())
- pm8058_platform_data.charger_sub_device
- = &pm8058_charger_sub_dev;
#if defined(CONFIG_SPI_QUP) || defined(CONFIG_SPI_QUP_MODULE)
if (machine_is_msm8x60_fluid())
@@ -10473,6 +10147,8 @@
msm_pm_data);
BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_TZ, NULL));
+ pm8058_gpios_init();
+
#ifdef CONFIG_SENSORS_MSM_ADC
if (machine_is_msm8x60_fluid()) {
msm_adc_pdata.dev_names = msm_adc_fluid_device_names;
@@ -10494,32 +10170,6 @@
platform_device_register(&gpio_leds);
#endif
- /* configure pmic leds */
- if (machine_is_msm8x60_fluid()) {
- pm8058_platform_data.sub_devices[PM8058_SUBDEV_LED].
- platform_data = &pm8058_fluid_flash_leds_data;
- pm8058_platform_data.sub_devices[PM8058_SUBDEV_LED].pdata_size
- = sizeof(pm8058_fluid_flash_leds_data);
- } else if (machine_is_msm8x60_dragon()) {
- pm8058_platform_data.sub_devices[PM8058_SUBDEV_LED].
- platform_data = &pm8058_dragon_leds_data;
- pm8058_platform_data.sub_devices[PM8058_SUBDEV_LED].pdata_size
- = sizeof(pm8058_dragon_leds_data);
- } else {
- pm8058_platform_data.sub_devices[PM8058_SUBDEV_LED].
- platform_data = &pm8058_flash_leds_data;
- pm8058_platform_data.sub_devices[PM8058_SUBDEV_LED].pdata_size
- = sizeof(pm8058_flash_leds_data);
- }
-
- if (machine_is_msm8x60_ffa() || machine_is_msm8x60_fusn_ffa() ||
- machine_is_msm8x60_dragon()) {
- pm8058_platform_data.sub_devices[PM8058_SUBDEV_VIB].
- platform_data = &pmic_vib_pdata;
- pm8058_platform_data.sub_devices[PM8058_SUBDEV_VIB].
- pdata_size = sizeof(pmic_vib_pdata);
- }
-
msm8x60_multi_sdio_init();
if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 95b69e6..91bb455 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -26,6 +26,7 @@
#include <linux/power_supply.h>
#include <linux/input/rmi_platformdata.h>
#include <linux/input/rmi_i2c.h>
+#include <linux/regulator/consumer.h>
#include <asm/mach/mmc.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -35,10 +36,8 @@
#include <mach/rpc_hsusb.h>
#include <mach/rpc_pmapp.h>
#include <mach/usbdiag.h>
-#include <mach/usb_gadget_fserial.h>
#include <mach/msm_memtypes.h>
#include <mach/msm_serial_hs.h>
-#include <mach/vreg.h>
#include <mach/pmic.h>
#include <mach/socinfo.h>
#include <mach/vreg.h>
@@ -46,12 +45,13 @@
#include <mach/msm_battery.h>
#include <mach/rpc_server_handset.h>
#include <mach/socinfo.h>
-
+#include "board-msm7x27a-regulator.h"
#include "devices.h"
#include "devices-msm7x2xa.h"
#include "pm.h"
#include "timer.h"
#include "pm-boot.h"
+#include "board-msm7x27a-regulator.h"
#define PMEM_KERNEL_EBI1_SIZE 0x3A000
#define MSM_PMEM_AUDIO_SIZE 0x5B000
@@ -77,6 +77,7 @@
/* FM Platform power and shutdown routines */
#define FPGA_MSM_CNTRL_REG2 0x90008010
+#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
static void config_pcm_i2s_mode(int mode)
{
void __iomem *cfg_ptr;
@@ -277,7 +278,7 @@
return rc;
}
-static struct vreg *fm_regulator;
+static struct regulator *fm_regulator;
static int fm_radio_setup(struct marimba_fm_platform_data *pdata)
{
int rc = 0;
@@ -287,27 +288,25 @@
u8 value;
/* Voting for 1.8V Regulator */
- fm_regulator = vreg_get(NULL , "msme1");
+ fm_regulator = regulator_get(NULL , "msme1");
if (IS_ERR(fm_regulator)) {
- pr_err("%s: vreg get failed with : (%ld)\n",
- __func__, PTR_ERR(fm_regulator));
- return -EINVAL;
+ rc = PTR_ERR(fm_regulator);
+ pr_err("%s: could not get regulator: %d\n", __func__, rc);
+ goto out;
}
/* Set the voltage level to 1.8V */
- rc = vreg_set_level(fm_regulator, 1800);
+ rc = regulator_set_voltage(fm_regulator, 1800000, 1800000);
if (rc < 0) {
- pr_err("%s: set regulator level failed with :(%d)\n",
- __func__, rc);
- goto fm_vreg_fail;
+ pr_err("%s: could not set voltage: %d\n", __func__, rc);
+ goto reg_free;
}
/* Enabling the 1.8V regulator */
- rc = vreg_enable(fm_regulator);
+ rc = regulator_enable(fm_regulator);
if (rc) {
- pr_err("%s: enable regulator failed with :(%d)\n",
- __func__, rc);
- goto fm_vreg_fail;
+ pr_err("%s: could not enable regulator: %d\n", __func__, rc);
+ goto reg_free;
}
/* Voting for 19.2MHz clock */
@@ -316,13 +315,13 @@
if (rc < 0) {
pr_err("%s: clock vote failed with :(%d)\n",
__func__, rc);
- goto fm_clock_vote_fail;
+ goto reg_disable;
}
rc = bt_set_gpio(1);
if (rc) {
pr_err("%s: bt_set_gpio = %d", __func__, rc);
- goto fm_gpio_config_fail;
+ goto gpio_deconfig;
}
/*re-write FM Slave Id, after reset*/
value = BAHAMA_SLAVE_ID_FM_ADDR;
@@ -330,7 +329,7 @@
BAHAMA_SLAVE_ID_FM_REG, &value, 1, 0xFF);
if (rc < 0) {
pr_err("%s: FM Slave ID rewrite Failed = %d", __func__, rc);
- goto fm_gpio_config_fail;
+ goto gpio_deconfig;
}
/* Configuring the FM GPIO */
irqcfg = GPIO_CFG(FM_GPIO, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL,
@@ -340,21 +339,21 @@
if (rc) {
pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
__func__, irqcfg, rc);
- goto fm_gpio_config_fail;
+ goto gpio_deconfig;
}
return 0;
-fm_gpio_config_fail:
+gpio_deconfig:
pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
PMAPP_CLOCK_VOTE_OFF);
bt_set_gpio(0);
-fm_clock_vote_fail:
- vreg_disable(fm_regulator);
-
-fm_vreg_fail:
- vreg_put(fm_regulator);
-
+reg_disable:
+ regulator_disable(fm_regulator);
+reg_free:
+ regulator_put(fm_regulator);
+ fm_regulator = NULL;
+out:
return rc;
};
@@ -373,11 +372,12 @@
__func__, irqcfg, rc);
/* Releasing the 1.8V Regulator */
- if (fm_regulator != NULL) {
- rc = vreg_disable(fm_regulator);
+ if (!IS_ERR_OR_NULL(fm_regulator)) {
+ rc = regulator_disable(fm_regulator);
if (rc)
- pr_err("%s: disable regulator failed:(%d)\n",
- __func__, rc);
+ pr_err("%s: could not disable regulator: %d\n",
+ __func__, rc);
+ regulator_put(fm_regulator);
fm_regulator = NULL;
}
@@ -402,6 +402,7 @@
.is_fm_soc_i2s_master = true,
.config_i2s_gpio = msm_bahama_setup_pcm_i2s,
};
+#endif
static struct platform_device msm_wlan_ar6000_pm_device = {
.name = "wlan_ar6000_pm_dev",
@@ -421,18 +422,18 @@
struct bt_vreg_info {
const char *name;
unsigned int pmapp_id;
- unsigned int level;
+ unsigned int min_level;
+ unsigned int max_level;
unsigned int is_pin_controlled;
- struct vreg *vregs;
+ struct regulator *reg;
};
static struct bt_vreg_info bt_vregs[] = {
- {"msme1", 2, 1800, 0, NULL},
- {"bt", 21, 2900, 1, NULL}
+ {"msme1", 2, 1800000, 1800000, 0, NULL},
+ {"bt", 21, 2900000, 3050000, 1, NULL}
};
static int bahama_bt(int on)
{
-
int rc = 0;
int i;
@@ -585,73 +586,94 @@
const char *id = "BTPW";
for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
- if (!bt_vregs[i].vregs) {
- pr_err("%s: vreg_get %s failed(%d)\n",
- __func__, bt_vregs[i].name, rc);
- goto vreg_fail;
+ if (IS_ERR_OR_NULL(bt_vregs[i].reg)) {
+ rc = bt_vregs[i].reg ?
+ PTR_ERR(bt_vregs[i].reg) :
+ -ENODEV;
+ dev_err(&msm_bt_power_device.dev,
+ "%s: invalid regulator handle for %s: %d\n",
+ __func__, bt_vregs[i].name, rc);
+ goto reg_disable;
}
- rc = on ? vreg_set_level(bt_vregs[i].vregs,
- bt_vregs[i].level) : 0;
- if (rc < 0) {
- pr_err("%s: vreg set level failed (%d)\n",
- __func__, rc);
- goto vreg_set_level_fail;
+ rc = on ? regulator_set_voltage(bt_vregs[i].reg,
+ bt_vregs[i].min_level,
+ bt_vregs[i].max_level) : 0;
+ if (rc) {
+ dev_err(&msm_bt_power_device.dev,
+ "%s: could not set voltage for %s: %d\n",
+ __func__, bt_vregs[i].name, rc);
+ goto reg_disable;
}
- if (bt_vregs[i].is_pin_controlled == 1) {
- rc = pmapp_vreg_pincntrl_vote(id,
- bt_vregs[i].pmapp_id,
+
+ rc = on ? regulator_enable(bt_vregs[i].reg) : 0;
+ if (rc) {
+ dev_err(&msm_bt_power_device.dev,
+ "%s: could not %sable regulator %s: %d\n",
+ __func__, "en", bt_vregs[i].name, rc);
+ goto reg_disable;
+ }
+
+ if (bt_vregs[i].is_pin_controlled) {
+ rc = pmapp_vreg_lpm_pincntrl_vote(id,
+ bt_vregs[i].pmapp_id,
PMAPP_CLOCK_ID_D1,
on ? PMAPP_CLOCK_VOTE_ON :
- PMAPP_CLOCK_VOTE_OFF);
- } else {
- rc = on ? vreg_enable(bt_vregs[i].vregs) :
- vreg_disable(bt_vregs[i].vregs);
+ PMAPP_CLOCK_VOTE_OFF);
+ if (rc) {
+ dev_err(&msm_bt_power_device.dev,
+ "%s: pin control failed for %s: %d\n",
+ __func__, bt_vregs[i].name, rc);
+ goto pin_cnt_fail;
+ }
}
+ rc = on ? 0 : regulator_disable(bt_vregs[i].reg);
- if (rc < 0) {
- pr_err("%s: vreg %s %s failed(%d)\n",
- __func__, bt_vregs[i].name,
- on ? "enable" : "disable", rc);
- goto vreg_fail;
+ if (rc) {
+ dev_err(&msm_bt_power_device.dev,
+ "%s: could not %sable regulator %s: %d\n",
+ __func__, "dis", bt_vregs[i].name, rc);
+ goto reg_disable;
}
}
return rc;
-
-vreg_fail:
+pin_cnt_fail:
+ if (on)
+ regulator_disable(bt_vregs[i].reg);
+reg_disable:
while (i) {
- if (on)
- vreg_disable(bt_vregs[--i].vregs);
+ if (on) {
+ i--;
+ regulator_disable(bt_vregs[i].reg);
+ regulator_put(bt_vregs[i].reg);
}
-vreg_set_level_fail:
- vreg_put(bt_vregs[0].vregs);
- vreg_put(bt_vregs[1].vregs);
+ }
return rc;
}
+static struct regulator *reg_s3;
static unsigned int msm_bahama_setup_power(void)
{
int rc = 0;
- struct vreg *vreg_s3 = NULL;
- vreg_s3 = vreg_get(NULL, "msme1");
- if (IS_ERR(vreg_s3)) {
- pr_err("%s: vreg get failed (%ld)\n",
- __func__, PTR_ERR(vreg_s3));
- return PTR_ERR(vreg_s3);
+ reg_s3 = regulator_get(NULL, "msme1");
+ if (IS_ERR(reg_s3)) {
+ rc = PTR_ERR(reg_s3);
+ pr_err("%s: could not get regulator: %d\n", __func__, rc);
+ goto out;
}
- rc = vreg_set_level(vreg_s3, 1800);
+
+ rc = regulator_set_voltage(reg_s3, 1800000, 1800000);
if (rc < 0) {
- pr_err("%s: vreg set level failed (%d)\n",
- __func__, rc);
- goto vreg_fail;
+ pr_err("%s: could not set voltage: %d\n", __func__, rc);
+ goto reg_fail;
}
- rc = vreg_enable(vreg_s3);
+
+ rc = regulator_enable(reg_s3);
if (rc < 0) {
- pr_err("%s: vreg enable failed (%d)\n",
- __func__, rc);
- goto vreg_fail;
+ pr_err("%s: could not enable regulator: %d\n", __func__, rc);
+ goto reg_fail;
}
/*setup Bahama_sys_reset_n*/
@@ -659,48 +681,62 @@
if (rc < 0) {
pr_err("%s: gpio_request %d = %d\n", __func__,
GPIO_BT_SYS_REST_EN, rc);
- goto vreg_fail;
+ goto reg_disable;
}
+
rc = bt_set_gpio(1);
if (rc < 0) {
pr_err("%s: bt_set_gpio %d = %d\n", __func__,
GPIO_BT_SYS_REST_EN, rc);
goto gpio_fail;
}
+
return rc;
gpio_fail:
gpio_free(GPIO_BT_SYS_REST_EN);
-vreg_fail:
- vreg_put(vreg_s3);
+reg_disable:
+ regulator_disable(reg_s3);
+reg_fail:
+ regulator_put(reg_s3);
+out:
+ reg_s3 = NULL;
return rc;
}
static unsigned int msm_bahama_shutdown_power(int value)
{
int rc = 0;
- struct vreg *vreg_s3 = NULL;
- vreg_s3 = vreg_get(NULL, "msme1");
- if (IS_ERR(vreg_s3)) {
- pr_err("%s: vreg get failed (%ld)\n",
- __func__, PTR_ERR(vreg_s3));
- return PTR_ERR(vreg_s3);
+ if (IS_ERR_OR_NULL(reg_s3)) {
+ rc = reg_s3 ? PTR_ERR(reg_s3) : -ENODEV;
+ goto out;
}
- rc = vreg_disable(vreg_s3);
+
+ rc = regulator_disable(reg_s3);
if (rc) {
- pr_err("%s: vreg disable failed (%d)\n",
- __func__, rc);
- vreg_put(vreg_s3);
- return rc;
+ pr_err("%s: could not disable regulator: %d\n", __func__, rc);
+ goto out;
}
+
if (value == BAHAMA_ID) {
rc = bt_set_gpio(0);
if (rc) {
pr_err("%s: bt_set_gpio = %d\n",
__func__, rc);
+ goto reg_enable;
}
+ gpio_free(GPIO_BT_SYS_REST_EN);
}
+
+ regulator_put(reg_s3);
+ reg_s3 = NULL;
+
+ return 0;
+
+reg_enable:
+ regulator_enable(reg_s3);
+out:
return rc;
}
@@ -861,25 +897,27 @@
static int __init bt_power_init(void)
{
int i, rc = 0;
- for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
- bt_vregs[i].vregs = vreg_get(NULL,
- bt_vregs[i].name);
- if (IS_ERR(bt_vregs[i].vregs)) {
- pr_err("%s: vreg get %s failed (%ld)\n",
- __func__, bt_vregs[i].name,
- PTR_ERR(bt_vregs[i].vregs));
- rc = PTR_ERR(bt_vregs[i].vregs);
- goto vreg_get_fail;
- }
- }
+ struct device *dev = &msm_bt_power_device.dev;
- msm_bt_power_device.dev.platform_data = &bluetooth_power;
+ for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
+ bt_vregs[i].reg = regulator_get(dev, bt_vregs[i].name);
+ if (IS_ERR(bt_vregs[i].reg)) {
+ rc = PTR_ERR(bt_vregs[i].reg);
+ dev_err(dev, "%s: could not get regulator %s: %d\n",
+ __func__, bt_vregs[i].name, rc);
+ goto reg_get_fail;
+ }
+ }
+
+ dev->platform_data = &bluetooth_power;
return rc;
-vreg_get_fail:
- while (i)
- vreg_put(bt_vregs[--i].vregs);
+reg_get_fail:
+ while (i--) {
+ regulator_put(bt_vregs[i].reg);
+ bt_vregs[i].reg = NULL;
+ }
return rc;
}
@@ -1142,35 +1180,52 @@
return msm_hsusb_rpc_close();
}
-static struct vreg *vreg_3p3;
+static struct regulator *reg_hsusb;
static int msm_hsusb_ldo_init(int init)
{
- if (init) {
- vreg_3p3 = vreg_get(NULL, "usb");
- if (IS_ERR(vreg_3p3))
- return PTR_ERR(vreg_3p3);
- } else
- vreg_put(vreg_3p3);
+ int rc = 0;
- return 0;
+ if (init) {
+ reg_hsusb = regulator_get(NULL, "usb");
+ if (IS_ERR(reg_hsusb)) {
+ rc = PTR_ERR(reg_hsusb);
+ pr_err("%s: could not get regulator: %d\n",
+ __func__, rc);
+ goto out;
+ }
+
+ rc = regulator_set_voltage(reg_hsusb, 3300000, 3300000);
+ if (rc) {
+ pr_err("%s: could not set voltage: %d\n",
+ __func__, rc);
+ goto reg_free;
+ }
+
+ return 0;
+ }
+ /* else fall through */
+reg_free:
+ regulator_put(reg_hsusb);
+out:
+ reg_hsusb = NULL;
+ return rc;
}
static int msm_hsusb_ldo_enable(int enable)
{
static int ldo_status;
- if (!vreg_3p3 || IS_ERR(vreg_3p3))
- return -ENODEV;
+ if (IS_ERR_OR_NULL(reg_hsusb))
+ return reg_hsusb ? PTR_ERR(reg_hsusb) : -ENODEV;
if (ldo_status == enable)
return 0;
ldo_status = enable;
- if (enable)
- return vreg_enable(vreg_3p3);
-
- return vreg_disable(vreg_3p3);
+ return enable ?
+ regulator_enable(reg_hsusb) :
+ regulator_disable(reg_hsusb);
}
#ifndef CONFIG_USB_EHCI_MSM_72K
@@ -1217,15 +1272,6 @@
|| defined(CONFIG_MMC_MSM_SDC4_SUPPORT))
static unsigned long vreg_sts, gpio_sts;
-static struct vreg *vreg_mmc;
-static struct vreg *vreg_emmc;
-
-struct sdcc_vreg {
- struct vreg *vreg_data;
- unsigned level;
-};
-
-static struct sdcc_vreg sdcc_vreg_data[4];
struct sdcc_gpio {
struct msm_gpio *cfg_data;
@@ -1344,6 +1390,7 @@
},
};
+static struct regulator *sdcc_vreg_data[ARRAY_SIZE(sdcc_cfg_data)];
static int msm_sdcc_setup_gpio(int dev_id, unsigned int enable)
{
int rc = 0;
@@ -1374,27 +1421,31 @@
static int msm_sdcc_setup_vreg(int dev_id, unsigned int enable)
{
int rc = 0;
- struct sdcc_vreg *curr;
+ struct regulator *curr = sdcc_vreg_data[dev_id - 1];
- curr = &sdcc_vreg_data[dev_id - 1];
+ if (test_bit(dev_id, &vreg_sts) == enable)
+ return 0;
- if (!(test_bit(dev_id, &vreg_sts)^enable))
- return rc;
+ if (!curr)
+ return -ENODEV;
+
+ if (IS_ERR(curr))
+ return PTR_ERR(curr);
if (enable) {
set_bit(dev_id, &vreg_sts);
- rc = vreg_set_level(curr->vreg_data, curr->level);
- if (rc)
- pr_err("%s: vreg_set_level() = %d\n", __func__, rc);
- rc = vreg_enable(curr->vreg_data);
+ rc = regulator_enable(curr);
if (rc)
- pr_err("%s: vreg_enable() = %d\n", __func__, rc);
+ pr_err("%s: could not enable regulator: %d\n",
+ __func__, rc);
} else {
clear_bit(dev_id, &vreg_sts);
- rc = vreg_disable(curr->vreg_data);
+
+ rc = regulator_disable(curr);
if (rc)
- pr_err("%s: vreg_disable() = %d\n", __func__, rc);
+ pr_err("%s: could not disable regulator: %d\n",
+ __func__, rc);
}
return rc;
}
@@ -1642,45 +1693,65 @@
}
};
+static int __init mmc_regulator_init(int sdcc_no, const char *supply, int uV)
+{
+ int rc;
+
+ BUG_ON(sdcc_no < 1 || sdcc_no > 4);
+
+ sdcc_no--;
+
+ sdcc_vreg_data[sdcc_no] = regulator_get(NULL, supply);
+
+ if (IS_ERR(sdcc_vreg_data[sdcc_no])) {
+ rc = PTR_ERR(sdcc_vreg_data[sdcc_no]);
+ pr_err("%s: could not get regulator \"%s\": %d\n",
+ __func__, supply, rc);
+ goto out;
+ }
+
+ rc = regulator_set_voltage(sdcc_vreg_data[sdcc_no], uV, uV);
+
+ if (rc) {
+ pr_err("%s: could not set voltage for \"%s\" to %d uV: %d\n",
+ __func__, supply, uV, rc);
+ goto reg_free;
+ }
+
+ return rc;
+
+reg_free:
+ regulator_put(sdcc_vreg_data[sdcc_no]);
+out:
+ sdcc_vreg_data[sdcc_no] = NULL;
+ return rc;
+}
+
static void __init msm7627a_init_mmc(void)
{
- vreg_emmc = vreg_get(NULL, "emmc");
- if (IS_ERR(vreg_emmc)) {
- pr_err("%s: vreg get failed (%ld)\n",
- __func__, PTR_ERR(vreg_emmc));
- return;
- }
-
- vreg_mmc = vreg_get(NULL, "mmc");
- if (IS_ERR(vreg_mmc)) {
- pr_err("%s: vreg get failed (%ld)\n",
- __func__, PTR_ERR(vreg_mmc));
- return;
- }
-
/* eMMC slot */
#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
- sdcc_vreg_data[2].vreg_data = vreg_emmc;
- sdcc_vreg_data[2].level = 3000;
+ if (mmc_regulator_init(3, "emmc", 3000000))
+ return;
msm_add_sdcc(3, &sdc3_plat_data);
#endif
/* Micro-SD slot */
#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
- sdcc_vreg_data[0].vreg_data = vreg_mmc;
- sdcc_vreg_data[0].level = 2850;
+ if (mmc_regulator_init(1, "mmc", 2850000))
+ return;
msm_add_sdcc(1, &sdc1_plat_data);
#endif
/* SDIO WLAN slot */
#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
- sdcc_vreg_data[1].vreg_data = vreg_mmc;
- sdcc_vreg_data[1].level = 2850;
+ if (mmc_regulator_init(2, "mmc", 2850000))
+ return;
msm_add_sdcc(2, &sdc2_plat_data);
#endif
/* Not Used */
#if (defined(CONFIG_MMC_MSM_SDC4_SUPPORT)\
&& !defined(CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT))
- sdcc_vreg_data[3].vreg_data = vreg_mmc;
- sdcc_vreg_data[3].level = 2850;
+ if (mmc_regulator_init(4, "mmc", 2850000))
+ return;
msm_add_sdcc(4, &sdc4_plat_data);
#endif
}
@@ -1943,98 +2014,39 @@
}
#endif
-static struct vreg *vreg_gp1;
-static struct vreg *vreg_gp2;
-static struct vreg *vreg_gp3;
-static void msm_camera_vreg_config(int vreg_en)
+static struct regulator_bulk_data regs_camera[] = {
+ { .supply = "msme1", .min_uV = 1800000, .max_uV = 1800000 },
+ { .supply = "gp2", .min_uV = 2850000, .max_uV = 2850000 },
+ { .supply = "usb2", .min_uV = 1800000, .max_uV = 1800000 },
+};
+
+static void __init msm_camera_vreg_init(void)
{
int rc;
- if (vreg_gp1 == NULL) {
- vreg_gp1 = vreg_get(NULL, "msme1");
- if (IS_ERR(vreg_gp1)) {
- pr_err("%s: vreg_get(%s) failed (%ld)\n",
- __func__, "msme1", PTR_ERR(vreg_gp1));
- return;
- }
-
- rc = vreg_set_level(vreg_gp1, 1800);
- if (rc) {
- pr_err("%s: GP1 set_level failed (%d)\n",
- __func__, rc);
- return;
- }
+ rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs_camera), regs_camera);
+ if (rc) {
+ pr_err("%s: could not get regulators: %d\n", __func__, rc);
+ return;
}
- if (vreg_gp2 == NULL) {
- vreg_gp2 = vreg_get(NULL, "gp2");
- if (IS_ERR(vreg_gp2)) {
- pr_err("%s: vreg_get(%s) failed (%ld)\n",
- __func__, "gp2", PTR_ERR(vreg_gp2));
- return;
- }
-
- rc = vreg_set_level(vreg_gp2, 2850);
- if (rc) {
- pr_err("%s: GP2 set_level failed (%d)\n",
- __func__, rc);
- }
- }
-
- if (vreg_gp3 == NULL) {
- vreg_gp3 = vreg_get(NULL, "usb2");
- if (IS_ERR(vreg_gp3)) {
- pr_err("%s: vreg_get(%s) failed (%ld)\n",
- __func__, "gp3", PTR_ERR(vreg_gp3));
- return;
- }
-
- rc = vreg_set_level(vreg_gp3, 1800);
- if (rc) {
- pr_err("%s: GP3 set level failed (%d)\n",
- __func__, rc);
- }
- }
-
- if (vreg_en) {
- rc = vreg_enable(vreg_gp1);
- if (rc) {
- pr_err("%s: GP1 enable failed (%d)\n",
- __func__, rc);
- return;
- }
-
- rc = vreg_enable(vreg_gp2);
- if (rc) {
- pr_err("%s: GP2 enable failed (%d)\n",
- __func__, rc);
- }
-
- rc = vreg_enable(vreg_gp3);
- if (rc) {
- pr_err("%s: GP3 enable failed (%d)\n",
- __func__, rc);
- }
- } else {
- rc = vreg_disable(vreg_gp1);
- if (rc)
- pr_err("%s: GP1 disable failed (%d)\n",
- __func__, rc);
-
- rc = vreg_disable(vreg_gp2);
- if (rc) {
- pr_err("%s: GP2 disable failed (%d)\n",
- __func__, rc);
- }
-
- rc = vreg_disable(vreg_gp3);
- if (rc) {
- pr_err("%s: GP3 disable failed (%d)\n",
- __func__, rc);
- }
+ rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs_camera), regs_camera);
+ if (rc) {
+ pr_err("%s: could not set voltages: %d\n", __func__, rc);
+ return;
}
}
+static void msm_camera_vreg_config(int vreg_en)
+{
+ int rc = vreg_en ?
+ regulator_bulk_enable(ARRAY_SIZE(regs_camera), regs_camera) :
+ regulator_bulk_disable(ARRAY_SIZE(regs_camera), regs_camera);
+
+ if (rc)
+ pr_err("%s: could not %sable regulators: %d\n",
+ __func__, vreg_en ? "en" : "dis", rc);
+}
static int config_gpio_table(uint32_t *table, int len)
{
int rc = 0, i = 0;
@@ -2505,10 +2517,27 @@
},
};
+static struct platform_device msm_proccomm_regulator_dev = {
+ .name = PROCCOMM_REGULATOR_DEV_NAME,
+ .id = -1,
+ .dev = {
+ .platform_data = &msm7x27a_proccomm_regulator_data
+ }
+};
+
+static void __init msm7627a_init_regulators(void)
+{
+ int rc = platform_device_register(&msm_proccomm_regulator_dev);
+ if (rc)
+ pr_err("%s: could not register regulator device: %d\n",
+ __func__, rc);
+}
+
#define UART1DM_RX_GPIO 45
static void __init msm_qrd1_init(void)
{
msm7x2x_misc_init();
+ msm7627a_init_regulators();
msm_device_i2c_init();
msm7627a_init_mmc();
@@ -2544,6 +2573,7 @@
bt_power_init();
#endif
+ msm_camera_vreg_init();
i2c_register_board_info(MSM_GSBI0_QUP_I2C_BUS_ID, i2c_camera_devices,
ARRAY_SIZE(i2c_camera_devices));
diff --git a/arch/arm/mach-msm/board-sapphire-keypad.c b/arch/arm/mach-msm/board-sapphire-keypad.c
old mode 100755
new mode 100644
diff --git a/arch/arm/mach-msm/board-sapphire-mmc.c b/arch/arm/mach-msm/board-sapphire-mmc.c
old mode 100755
new mode 100644
diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c
index a478b6f..e716b25 100644
--- a/arch/arm/mach-msm/clock-7x30.c
+++ b/arch/arm/mach-msm/clock-7x30.c
@@ -2316,7 +2316,7 @@
static DEFINE_CLK_PCOM(p_grp_2d_clk, GRP_2D_CLK, CLKFLAG_SKIP_AUTO_OFF);
static DEFINE_CLK_PCOM(p_grp_2d_p_clk, GRP_2D_P_CLK, CLKFLAG_SKIP_AUTO_OFF);
static DEFINE_CLK_PCOM(p_hdmi_clk, HDMI_CLK, CLKFLAG_SKIP_AUTO_OFF);
-static DEFINE_CLK_PCOM(p_jpeg_clk, JPEG_CLK, 0);
+static DEFINE_CLK_PCOM(p_jpeg_clk, JPEG_CLK, CLKFLAG_MIN);
static DEFINE_CLK_PCOM(p_jpeg_p_clk, JPEG_P_CLK, 0);
static DEFINE_CLK_PCOM(p_lpa_codec_clk, LPA_CODEC_CLK, CLKFLAG_SKIP_AUTO_OFF);
static DEFINE_CLK_PCOM(p_lpa_core_clk, LPA_CORE_CLK, CLKFLAG_SKIP_AUTO_OFF);
@@ -2386,7 +2386,7 @@
static DEFINE_CLK_PCOM(p_csi0_clk, CSI0_CLK, CLKFLAG_SKIP_AUTO_OFF);
static DEFINE_CLK_PCOM(p_csi0_vfe_clk, CSI0_VFE_CLK, CLKFLAG_SKIP_AUTO_OFF);
static DEFINE_CLK_PCOM(p_csi0_p_clk, CSI0_P_CLK, CLKFLAG_SKIP_AUTO_OFF);
-static DEFINE_CLK_PCOM(p_mdp_clk, MDP_CLK, 0);
+static DEFINE_CLK_PCOM(p_mdp_clk, MDP_CLK, CLKFLAG_MIN);
static DEFINE_CLK_PCOM(p_mfc_clk, MFC_CLK, CLKFLAG_SKIP_AUTO_OFF);
static DEFINE_CLK_PCOM(p_mfc_div2_clk, MFC_DIV2_CLK, CLKFLAG_SKIP_AUTO_OFF);
static DEFINE_CLK_PCOM(p_mfc_p_clk, MFC_P_CLK, CLKFLAG_SKIP_AUTO_OFF);
@@ -3000,7 +3000,6 @@
.disable = rcg_clk_disable,
.auto_off = rcg_clk_disable,
.set_rate = rcg_clk_set_rate,
- .set_min_rate = rcg_clk_set_min_rate,
.get_rate = rcg_clk_get_rate,
.list_rate = rcg_clk_list_rate,
.is_enabled = rcg_clk_is_enabled,
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 66c6436..d7322b6 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -57,6 +57,8 @@
#define CLK_HALT_SFPB_MISC_STATE_REG REG(0x2FD8)
#define CLK_HALT_AFAB_SFAB_STATEB_REG REG(0x2FC4)
#define CLK_TEST_REG REG(0x2FA0)
+#define GPn_MD_REG(n) REG(0x2D00+(0x20*(n)))
+#define GPn_NS_REG(n) REG(0x2D24+(0x20*(n)))
#define GSBIn_HCLK_CTL_REG(n) REG(0x29C0+(0x20*((n)-1)))
#define GSBIn_QUP_APPS_MD_REG(n) REG(0x29C8+(0x20*((n)-1)))
#define GSBIn_QUP_APPS_NS_REG(n) REG(0x29CC+(0x20*((n)-1)))
@@ -319,7 +321,7 @@
/* MUX source input identifiers. */
#define pxo_to_bb_mux 0
-#define cxo_to_bb_mux pxo_to_bb_mux
+#define cxo_to_bb_mux 5
#define pll0_to_bb_mux 2
#define pll8_to_bb_mux 3
#define pll6_to_bb_mux 4
@@ -640,7 +642,6 @@
.auto_off = rcg_clk_disable,
.handoff = rcg_clk_handoff,
.set_rate = rcg_clk_set_rate,
- .set_min_rate = rcg_clk_set_min_rate,
.get_rate = rcg_clk_get_rate,
.list_rate = rcg_clk_list_rate,
.is_enabled = rcg_clk_is_enabled,
@@ -1222,6 +1223,55 @@
/*
* Peripheral Clocks
*/
+#define CLK_GP(i, n, h_r, h_b) \
+ struct rcg_clk i##_clk = { \
+ .b = { \
+ .ctl_reg = GPn_NS_REG(n), \
+ .en_mask = BIT(9), \
+ .halt_reg = h_r, \
+ .halt_bit = h_b, \
+ }, \
+ .ns_reg = GPn_NS_REG(n), \
+ .md_reg = GPn_MD_REG(n), \
+ .root_en_mask = BIT(11), \
+ .ns_mask = (BM(23, 16) | BM(6, 0)), \
+ .set_rate = set_rate_mnd, \
+ .freq_tbl = clk_tbl_gp, \
+ .current_freq = &rcg_dummy_freq, \
+ .c = { \
+ .dbg_name = #i "_clk", \
+ .ops = &clk_ops_rcg_8960, \
+ VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000), \
+ CLK_INIT(i##_clk.c), \
+ }, \
+ }
+#define F_GP(f, s, d, m, n) \
+ { \
+ .freq_hz = f, \
+ .src_clk = &s##_clk.c, \
+ .md_val = MD8(16, m, 0, n), \
+ .ns_val = NS(23, 16, n, m, 5, 4, 3, d, 2, 0, s##_to_bb_mux), \
+ .mnd_en_mask = BIT(8) * !!(n), \
+ }
+static struct clk_freq_tbl clk_tbl_gp[] = {
+ F_GP( 0, gnd, 1, 0, 0),
+ F_GP( 9600000, cxo, 2, 0, 0),
+ F_GP( 13500000, pxo, 2, 0, 0),
+ F_GP( 19200000, cxo, 1, 0, 0),
+ F_GP( 27000000, pxo, 1, 0, 0),
+ F_GP( 64000000, pll8, 2, 1, 3),
+ F_GP( 76800000, pll8, 1, 1, 5),
+ F_GP( 96000000, pll8, 4, 0, 0),
+ F_GP(128000000, pll8, 3, 0, 0),
+ F_GP(192000000, pll8, 2, 0, 0),
+ F_GP(384000000, pll8, 1, 0, 0),
+ F_END
+};
+
+static CLK_GP(gp0, 0, CLK_HALT_SFPB_MISC_STATE_REG, 7);
+static CLK_GP(gp1, 1, CLK_HALT_SFPB_MISC_STATE_REG, 6);
+static CLK_GP(gp2, 2, CLK_HALT_SFPB_MISC_STATE_REG, 5);
+
#define CLK_GSBI_UART(i, n, h_r, h_b) \
struct rcg_clk i##_clk = { \
.b = { \
@@ -1483,7 +1533,6 @@
.auto_off = qdss_clk_auto_off,
.handoff = qdss_clk_handoff,
.set_rate = rcg_clk_set_rate,
- .set_min_rate = rcg_clk_set_min_rate,
.get_rate = rcg_clk_get_rate,
.list_rate = rcg_clk_list_rate,
.is_enabled = rcg_clk_is_enabled,
@@ -1740,6 +1789,7 @@
F_SDC( 48000000, pll8, 4, 1, 2),
F_SDC( 64000000, pll8, 3, 1, 2),
F_SDC( 96000000, pll8, 4, 0, 0),
+ F_SDC(192000000, pll8, 2, 0, 0),
F_END
};
@@ -4428,22 +4478,8 @@
}, \
}
-#define F_AIF_BIT(d, s) \
- { \
- .freq_hz = d, \
- .ns_val = (BVAL(14, 14, s) | BVAL(13, 10, (d-1))) \
- }
-static struct clk_freq_tbl clk_tbl_aif_bit[] = {
- F_AIF_BIT(0, 1), /* Use external clock. */
- F_AIF_BIT(1, 0), F_AIF_BIT(2, 0), F_AIF_BIT(3, 0), F_AIF_BIT(4, 0),
- F_AIF_BIT(5, 0), F_AIF_BIT(6, 0), F_AIF_BIT(7, 0), F_AIF_BIT(8, 0),
- F_AIF_BIT(9, 0), F_AIF_BIT(10, 0), F_AIF_BIT(11, 0), F_AIF_BIT(12, 0),
- F_AIF_BIT(13, 0), F_AIF_BIT(14, 0), F_AIF_BIT(15, 0), F_AIF_BIT(16, 0),
- F_END
-};
-
#define CLK_AIF_BIT(i, ns, h_r) \
- struct rcg_clk i##_clk = { \
+ struct cdiv_clk i##_clk = { \
.b = { \
.ctl_reg = ns, \
.en_mask = BIT(15), \
@@ -4451,35 +4487,18 @@
.halt_check = DELAY, \
}, \
.ns_reg = ns, \
- .ns_mask = BM(14, 10), \
- .set_rate = set_rate_nop, \
- .freq_tbl = clk_tbl_aif_bit, \
- .current_freq = &rcg_dummy_freq, \
+ .ext_mask = BIT(14), \
+ .div_offset = 10, \
+ .max_div = 16, \
.c = { \
.dbg_name = #i "_clk", \
- .ops = &clk_ops_rcg_8960, \
+ .ops = &clk_ops_cdiv, \
CLK_INIT(i##_clk.c), \
}, \
}
-#define F_AIF_BIT_D(d, s) \
- { \
- .freq_hz = d, \
- .ns_val = (BVAL(18, 18, s) | BVAL(17, 10, (d-1))) \
- }
-static struct clk_freq_tbl clk_tbl_aif_bit_div[] = {
- F_AIF_BIT_D(0, 1), /* Use external clock. */
- F_AIF_BIT_D(1, 0), F_AIF_BIT_D(2, 0), F_AIF_BIT_D(3, 0),
- F_AIF_BIT_D(4, 0), F_AIF_BIT_D(5, 0), F_AIF_BIT_D(6, 0),
- F_AIF_BIT_D(7, 0), F_AIF_BIT_D(8, 0), F_AIF_BIT_D(9, 0),
- F_AIF_BIT_D(10, 0), F_AIF_BIT_D(11, 0), F_AIF_BIT_D(12, 0),
- F_AIF_BIT_D(13, 0), F_AIF_BIT_D(14, 0), F_AIF_BIT_D(15, 0),
- F_AIF_BIT_D(16, 0),
- F_END
-};
-
#define CLK_AIF_BIT_DIV(i, ns, h_r) \
- struct rcg_clk i##_clk = { \
+ struct cdiv_clk i##_clk = { \
.b = { \
.ctl_reg = ns, \
.en_mask = BIT(19), \
@@ -4487,13 +4506,12 @@
.halt_check = ENABLE, \
}, \
.ns_reg = ns, \
- .ns_mask = BM(18, 10), \
- .set_rate = set_rate_nop, \
- .freq_tbl = clk_tbl_aif_bit_div, \
- .current_freq = &rcg_dummy_freq, \
+ .ext_mask = BIT(18), \
+ .div_offset = 10, \
+ .max_div = 256, \
.c = { \
.dbg_name = #i "_clk", \
- .ops = &clk_ops_rcg_8960, \
+ .ops = &clk_ops_cdiv, \
CLK_INIT(i##_clk.c), \
}, \
}
@@ -4681,6 +4699,9 @@
{ TEST_PER_LS(0x19), &sdc4_clk.c },
{ TEST_PER_LS(0x1A), &sdc5_p_clk.c },
{ TEST_PER_LS(0x1B), &sdc5_clk.c },
+ { TEST_PER_LS(0x1F), &gp0_clk.c },
+ { TEST_PER_LS(0x20), &gp1_clk.c },
+ { TEST_PER_LS(0x21), &gp2_clk.c },
{ TEST_PER_LS(0x25), &dfab_clk.c },
{ TEST_PER_LS(0x25), &dfab_a_clk.c },
{ TEST_PER_LS(0x26), &pmem_clk.c },
@@ -4866,9 +4887,9 @@
{ TEST_LPA_HS(0x00), &q6_func_clk },
- { TEST_CPUL2(0x1), &l2_m_clk },
- { TEST_CPUL2(0x2), &krait0_m_clk },
- { TEST_CPUL2(0x3), &krait1_m_clk },
+ { TEST_CPUL2(0x2), &l2_m_clk },
+ { TEST_CPUL2(0x0), &krait0_m_clk },
+ { TEST_CPUL2(0x1), &krait1_m_clk },
};
static struct measure_sel *find_measure_sel(struct clk *clk)
@@ -5070,6 +5091,9 @@
CLK_DUMMY("sfpb_clk", SFPB_CLK, NULL, 0),
CLK_DUMMY("sfpb_a_clk", SFPB_A_CLK, NULL, 0),
+ CLK_LOOKUP("core_clk", gp0_clk.c, NULL),
+ CLK_LOOKUP("core_clk", gp1_clk.c, NULL),
+ CLK_LOOKUP("core_clk", gp2_clk.c, NULL),
CLK_LOOKUP("core_clk", gsbi1_uart_clk.c, NULL),
CLK_LOOKUP("core_clk", gsbi2_uart_clk.c, NULL),
CLK_LOOKUP("core_clk", gsbi3_uart_clk.c, NULL),
@@ -5086,7 +5110,7 @@
CLK_LOOKUP("core_clk", gsbi7_qup_clk.c, NULL),
CLK_LOOKUP("core_clk", pdm_clk.c, NULL),
CLK_LOOKUP("pmem_clk", pmem_clk.c, NULL),
- CLK_DUMMY("core_clk", PRNG_CLK, NULL, OFF),
+ CLK_DUMMY("core_clk", PRNG_CLK, "msm_rng.0", OFF),
CLK_LOOKUP("core_clk", sdc1_clk.c, "msm_sdcc.1"),
CLK_LOOKUP("core_clk", sdc2_clk.c, "msm_sdcc.2"),
CLK_LOOKUP("core_clk", sdc3_clk.c, "msm_sdcc.3"),
@@ -5101,8 +5125,14 @@
CLK_LOOKUP("usb_fs_sys_clk", usb_fs1_sys_clk.c, NULL),
CLK_LOOKUP("iface_clk", ce1_p_clk.c, NULL),
CLK_LOOKUP("core_clk", ce1_core_clk.c, NULL),
- CLK_LOOKUP("ref_clk", sata_phy_ref_clk.c, NULL),
+ CLK_LOOKUP("ref_clk", sata_phy_ref_clk.c, NULL),
CLK_LOOKUP("cfg_clk", sata_phy_cfg_clk.c, NULL),
+ CLK_LOOKUP("iface_clk", ce3_p_clk.c, "qce.0"),
+ CLK_LOOKUP("iface_clk", ce3_p_clk.c, "qcrypto.0"),
+ CLK_LOOKUP("core_clk", ce3_core_clk.c, "qce.0"),
+ CLK_LOOKUP("core_clk", ce3_core_clk.c, "qcrypto.0"),
+ CLK_LOOKUP("ce3_core_src_clk", ce3_src_clk.c, "qce.0"),
+ CLK_LOOKUP("ce3_core_src_clk", ce3_src_clk.c, "qcrypto.0"),
CLK_LOOKUP("dma_bam_pclk", dma_bam_p_clk.c, NULL),
CLK_LOOKUP("iface_clk", gsbi1_p_clk.c, NULL),
CLK_LOOKUP("iface_clk", gsbi2_p_clk.c, NULL),
@@ -5121,9 +5151,6 @@
CLK_LOOKUP("iface_clk", sdc3_p_clk.c, "msm_sdcc.3"),
CLK_LOOKUP("iface_clk", sdc4_p_clk.c, "msm_sdcc.4"),
CLK_LOOKUP("iface_clk", pcie_p_clk.c, NULL),
- CLK_LOOKUP("core_src_clk", ce3_src_clk.c, NULL),
- CLK_LOOKUP("core_clk", ce3_core_clk.c, NULL),
- CLK_LOOKUP("iface_clk", ce3_p_clk.c, NULL),
CLK_LOOKUP("core_clk", adm0_clk.c, "msm_dmov"),
CLK_LOOKUP("iface_clk", adm0_p_clk.c, "msm_dmov"),
CLK_LOOKUP("iface_clk", pmic_arb0_p_clk.c, NULL),
@@ -5163,7 +5190,7 @@
CLK_LOOKUP("dsi_esc_clk", dsi2_esc_clk.c, NULL),
CLK_DUMMY("rgb_tv_clk", RGB_TV_CLK, NULL, OFF),
CLK_DUMMY("npl_tv_clk", NPL_TV_CLK, NULL, OFF),
- CLK_LOOKUP("core_clk", gfx3d_clk.c, NULL),
+ CLK_LOOKUP("core_clk", gfx3d_clk.c, "kgsl-3d0.0"),
CLK_LOOKUP("core_clk", gfx3d_clk.c, "footswitch-8x60.2"),
CLK_LOOKUP("bus_clk", gfx3d_axi_clk.c, "footswitch-8x60.2"),
CLK_LOOKUP("iface_clk", vcap_p_clk.c, NULL),
@@ -5184,7 +5211,7 @@
CLK_LOOKUP("core_clk", rot_clk.c, "msm_rotator.0"),
CLK_LOOKUP("core_clk", rot_clk.c, "footswitch-8x60.6"),
CLK_DUMMY("tv_src_clk", TV_SRC_CLK, NULL, OFF),
- CLK_LOOKUP("core_clk", vcodec_clk.c, NULL),
+ CLK_LOOKUP("core_clk", vcodec_clk.c, "msm_vidc.0"),
CLK_LOOKUP("core_clk", vcodec_clk.c, "footswitch-8x60.7"),
CLK_DUMMY("mdp_tv_clk", MDP_TV_CLK, NULL, OFF),
CLK_DUMMY("hdmi_clk", HDMI_TV_CLK, NULL, OFF),
@@ -5207,7 +5234,7 @@
CLK_LOOKUP("dsi_s_pclk", dsi1_s_p_clk.c, NULL),
CLK_LOOKUP("dsi_m_pclk", dsi2_m_p_clk.c, NULL),
CLK_LOOKUP("dsi_s_pclk", dsi2_s_p_clk.c, NULL),
- CLK_LOOKUP("iface_clk", gfx3d_p_clk.c, NULL),
+ CLK_LOOKUP("iface_clk", gfx3d_p_clk.c, "kgsl-3d0.0"),
CLK_LOOKUP("iface_clk", gfx3d_p_clk.c, "footswitch-8x60.2"),
CLK_LOOKUP("master_iface_clk", hdmi_m_p_clk.c, NULL),
CLK_LOOKUP("slave_iface_clk", hdmi_s_p_clk.c, NULL),
@@ -5220,7 +5247,7 @@
CLK_LOOKUP("iface_clk", smmu_p_clk.c, NULL),
CLK_LOOKUP("iface_clk", rot_p_clk.c, "msm_rotator.0"),
CLK_LOOKUP("iface_clk", rot_p_clk.c, "footswitch-8x60.6"),
- CLK_LOOKUP("iface_clk", vcodec_p_clk.c, NULL),
+ CLK_LOOKUP("iface_clk", vcodec_p_clk.c, "msm_vidc.0"),
CLK_LOOKUP("iface_clk", vcodec_p_clk.c, "footswitch-8x60.7"),
CLK_LOOKUP("vfe_pclk", vfe_p_clk.c, NULL),
CLK_LOOKUP("iface_clk", vfe_p_clk.c, "footswitch-8x60.8"),
@@ -5298,6 +5325,9 @@
CLK_LOOKUP("sfpb_clk", sfpb_clk.c, NULL),
CLK_LOOKUP("sfpb_a_clk", sfpb_a_clk.c, NULL),
+ CLK_LOOKUP("core_clk", gp0_clk.c, NULL),
+ CLK_LOOKUP("core_clk", gp1_clk.c, NULL),
+ CLK_LOOKUP("core_clk", gp2_clk.c, NULL),
CLK_LOOKUP("core_clk", gsbi1_uart_clk.c, NULL),
CLK_LOOKUP("core_clk", gsbi2_uart_clk.c, NULL),
CLK_LOOKUP("core_clk", gsbi3_uart_clk.c, NULL),
@@ -5378,7 +5408,6 @@
CLK_LOOKUP("cam_clk", cam1_clk.c, NULL),
CLK_LOOKUP("cam_clk", cam0_clk.c, "msm_camera_imx074.0"),
CLK_LOOKUP("cam_clk", cam0_clk.c, "msm_camera_ov2720.0"),
- CLK_LOOKUP("cam_clk", cam0_clk.c, "msm_camera_qs_mt9p017.0"),
CLK_LOOKUP("csi_src_clk", csi0_src_clk.c, "msm_csid.0"),
CLK_LOOKUP("csi_src_clk", csi1_src_clk.c, "msm_csid.1"),
CLK_LOOKUP("csi_clk", csi0_clk.c, "msm_csid.0"),
@@ -5965,7 +5994,7 @@
if (WARN(IS_ERR(mmfpb_a_clk), "mmfpb_a_clk not found (%ld)\n",
PTR_ERR(mmfpb_a_clk)))
return PTR_ERR(mmfpb_a_clk);
- rc = clk_set_min_rate(mmfpb_a_clk, 76800000);
+ rc = clk_set_rate(mmfpb_a_clk, 76800000);
if (WARN(rc, "mmfpb_a_clk rate was not set (%d)\n", rc))
return rc;
rc = clk_enable(mmfpb_a_clk);
@@ -5976,7 +6005,7 @@
if (WARN(IS_ERR(cfpb_a_clk), "cfpb_a_clk not found (%ld)\n",
PTR_ERR(cfpb_a_clk)))
return PTR_ERR(cfpb_a_clk);
- rc = clk_set_min_rate(cfpb_a_clk, 64000000);
+ rc = clk_set_rate(cfpb_a_clk, 64000000);
if (WARN(rc, "cfpb_a_clk rate was not set (%d)\n", rc))
return rc;
rc = clk_enable(cfpb_a_clk);
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index 6707757..454e9cf 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -55,6 +55,8 @@
#define CLK_TEST_REG REG(0x2FA0)
#define EBI2_2X_CLK_CTL_REG REG(0x2660)
#define EBI2_CLK_CTL_REG REG(0x2664)
+#define GPn_MD_REG(n) REG(0x2D00+(0x20*(n)))
+#define GPn_NS_REG(n) REG(0x2D24+(0x20*(n)))
#define GSBIn_HCLK_CTL_REG(n) REG(0x29C0+(0x20*((n)-1)))
#define GSBIn_QUP_APPS_MD_REG(n) REG(0x29C8+(0x20*((n)-1)))
#define GSBIn_QUP_APPS_NS_REG(n) REG(0x29CC+(0x20*((n)-1)))
@@ -207,7 +209,7 @@
/* MUX source input identifiers. */
#define pxo_to_bb_mux 0
#define mxo_to_bb_mux 1
-#define cxo_to_bb_mux pxo_to_bb_mux
+#define cxo_to_bb_mux 5
#define pll0_to_bb_mux 2
#define pll8_to_bb_mux 3
#define pll6_to_bb_mux 4
@@ -544,7 +546,6 @@
.auto_off = rcg_clk_disable,
.handoff = rcg_clk_handoff,
.set_rate = rcg_clk_set_rate,
- .set_min_rate = rcg_clk_set_min_rate,
.get_rate = rcg_clk_get_rate,
.list_rate = rcg_clk_list_rate,
.is_enabled = rcg_clk_is_enabled,
@@ -1050,6 +1051,49 @@
/*
* Peripheral Clocks
*/
+#define CLK_GP(i, n, h_r, h_b) \
+ struct rcg_clk i##_clk = { \
+ .b = { \
+ .ctl_reg = GPn_NS_REG(n), \
+ .en_mask = BIT(9), \
+ .halt_reg = h_r, \
+ .halt_bit = h_b, \
+ }, \
+ .ns_reg = GPn_NS_REG(n), \
+ .md_reg = GPn_MD_REG(n), \
+ .root_en_mask = BIT(11), \
+ .ns_mask = (BM(23, 16) | BM(6, 0)), \
+ .set_rate = set_rate_mnd, \
+ .freq_tbl = clk_tbl_gp, \
+ .current_freq = &rcg_dummy_freq, \
+ .c = { \
+ .dbg_name = #i "_clk", \
+ .ops = &clk_ops_rcg_8x60, \
+ VDD_DIG_FMAX_MAP1(LOW, 27000000), \
+ CLK_INIT(i##_clk.c), \
+ }, \
+ }
+#define F_GP(f, s, d, m, n) \
+ { \
+ .freq_hz = f, \
+ .src_clk = &s##_clk.c, \
+ .md_val = MD8(16, m, 0, n), \
+ .ns_val = NS(23, 16, n, m, 5, 4, 3, d, 2, 0, s##_to_bb_mux), \
+ .mnd_en_mask = BIT(8) * !!(n), \
+ }
+static struct clk_freq_tbl clk_tbl_gp[] = {
+ F_GP( 0, gnd, 1, 0, 0),
+ F_GP( 9600000, cxo, 2, 0, 0),
+ F_GP( 13500000, pxo, 2, 0, 0),
+ F_GP( 19200000, cxo, 1, 0, 0),
+ F_GP( 27000000, pxo, 1, 0, 0),
+ F_END
+};
+
+static CLK_GP(gp0, 0, CLK_HALT_SFPB_MISC_STATE_REG, 7);
+static CLK_GP(gp1, 1, CLK_HALT_SFPB_MISC_STATE_REG, 6);
+static CLK_GP(gp2, 2, CLK_HALT_SFPB_MISC_STATE_REG, 5);
+
#define CLK_GSBI_UART(i, n, h_r, h_b) \
struct rcg_clk i##_clk = { \
.b = { \
@@ -3061,22 +3105,8 @@
}, \
}
-#define F_AIF_BIT(d, s) \
- { \
- .freq_hz = d, \
- .ns_val = (BVAL(14, 14, s) | BVAL(13, 10, (d-1))) \
- }
-static struct clk_freq_tbl clk_tbl_aif_bit[] = {
- F_AIF_BIT(0, 1), /* Use external clock. */
- F_AIF_BIT(1, 0), F_AIF_BIT(2, 0), F_AIF_BIT(3, 0), F_AIF_BIT(4, 0),
- F_AIF_BIT(5, 0), F_AIF_BIT(6, 0), F_AIF_BIT(7, 0), F_AIF_BIT(8, 0),
- F_AIF_BIT(9, 0), F_AIF_BIT(10, 0), F_AIF_BIT(11, 0), F_AIF_BIT(12, 0),
- F_AIF_BIT(13, 0), F_AIF_BIT(14, 0), F_AIF_BIT(15, 0), F_AIF_BIT(16, 0),
- F_END
-};
-
#define CLK_AIF_BIT(i, ns, h_r) \
- struct rcg_clk i##_clk = { \
+ struct cdiv_clk i##_clk = { \
.b = { \
.ctl_reg = ns, \
.en_mask = BIT(15), \
@@ -3084,13 +3114,12 @@
.halt_check = DELAY, \
}, \
.ns_reg = ns, \
- .ns_mask = BM(14, 10), \
- .set_rate = set_rate_nop, \
- .freq_tbl = clk_tbl_aif_bit, \
- .current_freq = &rcg_dummy_freq, \
+ .ext_mask = BIT(14), \
+ .div_offset = 10, \
+ .max_div = 16, \
.c = { \
.dbg_name = #i "_clk", \
- .ops = &clk_ops_rcg_8x60, \
+ .ops = &clk_ops_cdiv, \
CLK_INIT(i##_clk.c), \
}, \
}
@@ -3215,6 +3244,9 @@
{ TEST_PER_LS(0x1B), &sdc5_clk.c },
{ TEST_PER_LS(0x1D), &ebi2_2x_clk.c },
{ TEST_PER_LS(0x1E), &ebi2_clk.c },
+ { TEST_PER_LS(0x1F), &gp0_clk.c },
+ { TEST_PER_LS(0x20), &gp1_clk.c },
+ { TEST_PER_LS(0x21), &gp2_clk.c },
{ TEST_PER_LS(0x25), &dfab_clk.c },
{ TEST_PER_LS(0x25), &dfab_a_clk.c },
{ TEST_PER_LS(0x26), &pmem_clk.c },
@@ -3567,6 +3599,9 @@
CLK_LOOKUP("smi_clk", smi_clk.c, NULL),
CLK_LOOKUP("smi_a_clk", smi_a_clk.c, NULL),
+ CLK_LOOKUP("core_clk", gp0_clk.c, NULL),
+ CLK_LOOKUP("core_clk", gp1_clk.c, NULL),
+ CLK_LOOKUP("core_clk", gp2_clk.c, NULL),
CLK_LOOKUP("core_clk", gsbi1_uart_clk.c, NULL),
CLK_LOOKUP("core_clk", gsbi2_uart_clk.c, NULL),
CLK_LOOKUP("core_clk", gsbi3_uart_clk.c, "msm_serial_hsl.2"),
@@ -3910,7 +3945,7 @@
if (WARN(IS_ERR(mmfpb_a_clk), "mmfpb_a_clk not found (%ld)\n",
PTR_ERR(mmfpb_a_clk)))
return PTR_ERR(mmfpb_a_clk);
- rc = clk_set_min_rate(mmfpb_a_clk, 64000000);
+ rc = clk_set_rate(mmfpb_a_clk, 64000000);
if (WARN(rc, "mmfpb_a_clk rate was not set (%d)\n", rc))
return rc;
rc = clk_enable(mmfpb_a_clk);
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index cd028e4..553fb4d 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -50,6 +50,8 @@
#define CLK_HALT_MSS_KPSS_MISC_STATE_REG REG(0x2FDC)
#define CLK_HALT_SFPB_MISC_STATE_REG REG(0x2FD8)
#define CLK_TEST_REG REG(0x2FA0)
+#define GPn_MD_REG(n) REG(0x2D00+(0x20*(n)))
+#define GPn_NS_REG(n) REG(0x2D24+(0x20*(n)))
#define GSBIn_HCLK_CTL_REG(n) REG(0x29C0+(0x20*((n)-1)))
#define GSBIn_QUP_APPS_MD_REG(n) REG(0x29C8+(0x20*((n)-1)))
#define GSBIn_QUP_APPS_NS_REG(n) REG(0x29CC+(0x20*((n)-1)))
@@ -247,19 +249,83 @@
},
};
+static DEFINE_SPINLOCK(soft_vote_lock);
+
+static int pll_acpu_vote_clk_enable(struct clk *clk)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct pll_vote_clk *pll = to_pll_vote_clk(clk);
+
+ spin_lock_irqsave(&soft_vote_lock, flags);
+
+ if (!*pll->soft_vote)
+ ret = pll_vote_clk_enable(clk);
+ if (ret == 0)
+ *pll->soft_vote |= (pll->soft_vote_mask);
+
+ spin_unlock_irqrestore(&soft_vote_lock, flags);
+ return ret;
+}
+
+static void pll_acpu_vote_clk_disable(struct clk *clk)
+{
+ unsigned long flags;
+ struct pll_vote_clk *pll = to_pll_vote_clk(clk);
+
+ spin_lock_irqsave(&soft_vote_lock, flags);
+
+ *pll->soft_vote &= ~(pll->soft_vote_mask);
+ if (!*pll->soft_vote)
+ pll_vote_clk_disable(clk);
+
+ spin_unlock_irqrestore(&soft_vote_lock, flags);
+}
+
+static struct clk_ops clk_ops_pll_acpu_vote = {
+ .enable = pll_acpu_vote_clk_enable,
+ .disable = pll_acpu_vote_clk_disable,
+ .auto_off = pll_acpu_vote_clk_disable,
+ .is_enabled = pll_vote_clk_is_enabled,
+ .get_rate = pll_vote_clk_get_rate,
+ .get_parent = pll_vote_clk_get_parent,
+ .is_local = local_clk_is_local,
+};
+
+#define PLL_SOFT_VOTE_PRIMARY BIT(0)
+#define PLL_SOFT_VOTE_ACPU BIT(1)
+
+static unsigned int soft_vote_pll0;
+
static struct pll_vote_clk pll0_clk = {
.rate = 276000000,
.en_reg = BB_PLL_ENA_SC0_REG,
.en_mask = BIT(0),
.status_reg = BB_PLL0_STATUS_REG,
.parent = &cxo_clk.c,
+ .soft_vote = &soft_vote_pll0,
+ .soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
.c = {
.dbg_name = "pll0_clk",
- .ops = &clk_ops_pll_vote,
+ .ops = &clk_ops_pll_acpu_vote,
CLK_INIT(pll0_clk.c),
},
};
+static struct pll_vote_clk pll0_acpu_clk = {
+ .rate = 276000000,
+ .en_reg = BB_PLL_ENA_SC0_REG,
+ .en_mask = BIT(0),
+ .status_reg = BB_PLL0_STATUS_REG,
+ .soft_vote = &soft_vote_pll0,
+ .soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+ .c = {
+ .dbg_name = "pll0_acpu_clk",
+ .ops = &clk_ops_pll_acpu_vote,
+ CLK_INIT(pll0_acpu_clk.c),
+ },
+};
+
static struct pll_vote_clk pll4_clk = {
.rate = 393216000,
.en_reg = BB_PLL_ENA_SC0_REG,
@@ -273,32 +339,68 @@
},
};
+static unsigned int soft_vote_pll8;
+
static struct pll_vote_clk pll8_clk = {
.rate = 384000000,
.en_reg = BB_PLL_ENA_SC0_REG,
.en_mask = BIT(8),
.status_reg = BB_PLL8_STATUS_REG,
.parent = &cxo_clk.c,
+ .soft_vote = &soft_vote_pll8,
+ .soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
.c = {
.dbg_name = "pll8_clk",
- .ops = &clk_ops_pll_vote,
+ .ops = &clk_ops_pll_acpu_vote,
CLK_INIT(pll8_clk.c),
},
};
+static struct pll_vote_clk pll8_acpu_clk = {
+ .rate = 384000000,
+ .en_reg = BB_PLL_ENA_SC0_REG,
+ .en_mask = BIT(8),
+ .status_reg = BB_PLL8_STATUS_REG,
+ .soft_vote = &soft_vote_pll8,
+ .soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+ .c = {
+ .dbg_name = "pll8_acpu_clk",
+ .ops = &clk_ops_pll_acpu_vote,
+ CLK_INIT(pll8_acpu_clk.c),
+ },
+};
+
+static unsigned int soft_vote_pll9;
+
static struct pll_vote_clk pll9_clk = {
.rate = 440000000,
.en_reg = BB_PLL_ENA_SC0_REG,
.en_mask = BIT(9),
.status_reg = SC_PLL0_STATUS_REG,
.parent = &cxo_clk.c,
+ .soft_vote = &soft_vote_pll9,
+ .soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
.c = {
.dbg_name = "pll9_clk",
- .ops = &clk_ops_pll_vote,
+ .ops = &clk_ops_pll_acpu_vote,
CLK_INIT(pll9_clk.c),
},
};
+static struct pll_vote_clk pll9_acpu_clk = {
+ .rate = 440000000,
+ .en_reg = BB_PLL_ENA_SC0_REG,
+ .en_mask = BIT(9),
+ .soft_vote = &soft_vote_pll9,
+ .soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+ .status_reg = SC_PLL0_STATUS_REG,
+ .c = {
+ .dbg_name = "pll9_acpu_clk",
+ .ops = &clk_ops_pll_acpu_vote,
+ CLK_INIT(pll9_acpu_clk.c),
+ },
+};
+
static struct pll_vote_clk pll14_clk = {
.rate = 480000000,
.en_reg = BB_PLL_ENA_SC0_REG,
@@ -322,7 +424,6 @@
.disable = rcg_clk_disable,
.auto_off = rcg_clk_disable,
.set_rate = rcg_clk_set_rate,
- .set_min_rate = rcg_clk_set_min_rate,
.get_rate = rcg_clk_get_rate,
.list_rate = rcg_clk_list_rate,
.is_enabled = rcg_clk_is_enabled,
@@ -346,6 +447,47 @@
/*
* Peripheral Clocks
*/
+#define CLK_GP(i, n, h_r, h_b) \
+ struct rcg_clk i##_clk = { \
+ .b = { \
+ .ctl_reg = GPn_NS_REG(n), \
+ .en_mask = BIT(9), \
+ .halt_reg = h_r, \
+ .halt_bit = h_b, \
+ }, \
+ .ns_reg = GPn_NS_REG(n), \
+ .md_reg = GPn_MD_REG(n), \
+ .root_en_mask = BIT(11), \
+ .ns_mask = (BM(23, 16) | BM(6, 0)), \
+ .set_rate = set_rate_mnd, \
+ .freq_tbl = clk_tbl_gp, \
+ .current_freq = &rcg_dummy_freq, \
+ .c = { \
+ .dbg_name = #i "_clk", \
+ .ops = &clk_ops_rcg_9615, \
+ VDD_DIG_FMAX_MAP1(LOW, 27000000), \
+ CLK_INIT(i##_clk.c), \
+ }, \
+ }
+#define F_GP(f, s, d, m, n) \
+ { \
+ .freq_hz = f, \
+ .src_clk = &s##_clk.c, \
+ .md_val = MD8(16, m, 0, n), \
+ .ns_val = NS(23, 16, n, m, 5, 4, 3, d, 2, 0, s##_to_bb_mux), \
+ .mnd_en_mask = BIT(8) * !!(n), \
+ }
+static struct clk_freq_tbl clk_tbl_gp[] = {
+ F_GP( 0, gnd, 1, 0, 0),
+ F_GP( 9600000, cxo, 2, 0, 0),
+ F_GP( 19200000, cxo, 1, 0, 0),
+ F_END
+};
+
+static CLK_GP(gp0, 0, CLK_HALT_SFPB_MISC_STATE_REG, 7);
+static CLK_GP(gp1, 1, CLK_HALT_SFPB_MISC_STATE_REG, 6);
+static CLK_GP(gp2, 2, CLK_HALT_SFPB_MISC_STATE_REG, 5);
+
#define CLK_GSBI_UART(i, n, h_r, h_b) \
struct rcg_clk i##_clk = { \
.b = { \
@@ -1068,22 +1210,8 @@
}, \
}
-#define F_AIF_BIT(d, s) \
- { \
- .freq_hz = d, \
- .ns_val = (BVAL(14, 14, s) | BVAL(13, 10, (d-1))) \
- }
-static struct clk_freq_tbl clk_tbl_aif_bit[] = {
- F_AIF_BIT(0, 1), /* Use external clock. */
- F_AIF_BIT(1, 0), F_AIF_BIT(2, 0), F_AIF_BIT(3, 0), F_AIF_BIT(4, 0),
- F_AIF_BIT(5, 0), F_AIF_BIT(6, 0), F_AIF_BIT(7, 0), F_AIF_BIT(8, 0),
- F_AIF_BIT(9, 0), F_AIF_BIT(10, 0), F_AIF_BIT(11, 0), F_AIF_BIT(12, 0),
- F_AIF_BIT(13, 0), F_AIF_BIT(14, 0), F_AIF_BIT(15, 0), F_AIF_BIT(16, 0),
- F_END
-};
-
#define CLK_AIF_BIT(i, ns, h_r) \
- struct rcg_clk i##_clk = { \
+ struct cdiv_clk i##_clk = { \
.b = { \
.ctl_reg = ns, \
.en_mask = BIT(15), \
@@ -1091,35 +1219,18 @@
.halt_check = DELAY, \
}, \
.ns_reg = ns, \
- .ns_mask = BM(14, 10), \
- .set_rate = set_rate_nop, \
- .freq_tbl = clk_tbl_aif_bit, \
- .current_freq = &rcg_dummy_freq, \
+ .ext_mask = BIT(14), \
+ .div_offset = 10, \
+ .max_div = 16, \
.c = { \
.dbg_name = #i "_clk", \
- .ops = &clk_ops_rcg_9615, \
+ .ops = &clk_ops_cdiv, \
CLK_INIT(i##_clk.c), \
}, \
}
-#define F_AIF_BIT_D(d, s) \
- { \
- .freq_hz = d, \
- .ns_val = (BVAL(18, 18, s) | BVAL(17, 10, (d-1))) \
- }
-static struct clk_freq_tbl clk_tbl_aif_bit_div[] = {
- F_AIF_BIT_D(0, 1), /* Use external clock. */
- F_AIF_BIT_D(1, 0), F_AIF_BIT_D(2, 0), F_AIF_BIT_D(3, 0),
- F_AIF_BIT_D(4, 0), F_AIF_BIT_D(5, 0), F_AIF_BIT_D(6, 0),
- F_AIF_BIT_D(7, 0), F_AIF_BIT_D(8, 0), F_AIF_BIT_D(9, 0),
- F_AIF_BIT_D(10, 0), F_AIF_BIT_D(11, 0), F_AIF_BIT_D(12, 0),
- F_AIF_BIT_D(13, 0), F_AIF_BIT_D(14, 0), F_AIF_BIT_D(15, 0),
- F_AIF_BIT_D(16, 0),
- F_END
-};
-
#define CLK_AIF_BIT_DIV(i, ns, h_r) \
- struct rcg_clk i##_clk = { \
+ struct cdiv_clk i##_clk = { \
.b = { \
.ctl_reg = ns, \
.en_mask = BIT(19), \
@@ -1127,13 +1238,12 @@
.halt_check = ENABLE, \
}, \
.ns_reg = ns, \
- .ns_mask = BM(18, 10), \
- .set_rate = set_rate_nop, \
- .freq_tbl = clk_tbl_aif_bit_div, \
- .current_freq = &rcg_dummy_freq, \
+ .ext_mask = BIT(18), \
+ .div_offset = 10, \
+ .max_div = 256, \
.c = { \
.dbg_name = #i "_clk", \
- .ops = &clk_ops_rcg_9615, \
+ .ops = &clk_ops_cdiv, \
CLK_INIT(i##_clk.c), \
}, \
}
@@ -1298,6 +1408,9 @@
{ TEST_PER_LS(0x13), &sdc1_clk.c },
{ TEST_PER_LS(0x14), &sdc2_p_clk.c },
{ TEST_PER_LS(0x15), &sdc2_clk.c },
+ { TEST_PER_LS(0x1F), &gp0_clk.c },
+ { TEST_PER_LS(0x20), &gp1_clk.c },
+ { TEST_PER_LS(0x21), &gp2_clk.c },
{ TEST_PER_LS(0x26), &pmem_clk.c },
{ TEST_PER_LS(0x25), &dfab_clk.c },
{ TEST_PER_LS(0x25), &dfab_a_clk.c },
@@ -1511,6 +1624,11 @@
CLK_LOOKUP("pll8", pll8_clk.c, NULL),
CLK_LOOKUP("pll9", pll9_clk.c, NULL),
CLK_LOOKUP("pll14", pll14_clk.c, NULL),
+
+ CLK_LOOKUP("pll0", pll0_acpu_clk.c, "acpu"),
+ CLK_LOOKUP("pll8", pll8_acpu_clk.c, "acpu"),
+ CLK_LOOKUP("pll9", pll9_acpu_clk.c, "acpu"),
+
CLK_LOOKUP("measure", measure_clk.c, "debug"),
CLK_LOOKUP("cfpb_clk", cfpb_clk.c, NULL),
@@ -1524,14 +1642,14 @@
CLK_LOOKUP("sfpb_clk", sfpb_clk.c, NULL),
CLK_LOOKUP("sfpb_a_clk", sfpb_a_clk.c, NULL),
- CLK_LOOKUP("core_clk", gsbi1_uart_clk.c, NULL),
- CLK_LOOKUP("core_clk", gsbi2_uart_clk.c, NULL),
+ CLK_LOOKUP("core_clk", gp0_clk.c, NULL),
+ CLK_LOOKUP("core_clk", gp1_clk.c, NULL),
+ CLK_LOOKUP("core_clk", gp2_clk.c, NULL),
+
CLK_LOOKUP("core_clk", gsbi3_uart_clk.c, NULL),
CLK_LOOKUP("core_clk", gsbi4_uart_clk.c, "msm_serial_hsl.0"),
CLK_LOOKUP("core_clk", gsbi5_uart_clk.c, NULL),
- CLK_LOOKUP("core_clk", gsbi1_qup_clk.c, NULL),
- CLK_LOOKUP("core_clk", gsbi2_qup_clk.c, NULL),
CLK_LOOKUP("core_clk", gsbi3_qup_clk.c, "spi_qsd.0"),
CLK_LOOKUP("core_clk", gsbi4_qup_clk.c, NULL),
CLK_LOOKUP("core_clk", gsbi5_qup_clk.c, "qup_i2c.0"),
@@ -1545,8 +1663,6 @@
CLK_LOOKUP("core_clk", ce1_core_clk.c, NULL),
CLK_LOOKUP("dma_bam_pclk", dma_bam_p_clk.c, NULL),
- CLK_LOOKUP("iface_clk", gsbi1_p_clk.c, NULL),
- CLK_LOOKUP("iface_clk", gsbi2_p_clk.c, NULL),
CLK_LOOKUP("iface_clk", gsbi3_p_clk.c, "spi_qsd.0"),
CLK_LOOKUP("iface_clk", gsbi4_p_clk.c, "msm_serial_hsl.0"),
CLK_LOOKUP("iface_clk", gsbi5_p_clk.c, "qup_i2c.0"),
@@ -1611,7 +1727,7 @@
/* Program bias count */
regval &= ~BM(19, 14);
- regval |= BVAL(19, 14, 0x4);
+ regval |= BVAL(19, 14, 0x1);
writel_relaxed(regval, mode_reg);
/* Program lock count */
@@ -1722,6 +1838,19 @@
/* Enable PLL4 source on the LPASS Primary PLL Mux */
regval = readl_relaxed(LCC_PRI_PLL_CLK_CTL_REG);
writel_relaxed(regval | BIT(0), LCC_PRI_PLL_CLK_CTL_REG);
+
+ /* Disable hardware clock gating on certain clocks */
+ regval = readl_relaxed(USB_HSIC_HCLK_CTL_REG);
+ regval &= ~BIT(6);
+ writel_relaxed(regval, USB_HSIC_HCLK_CTL_REG);
+
+ regval = readl_relaxed(CE1_CORE_CLK_CTL_REG);
+ regval &= ~BIT(6);
+ writel_relaxed(regval, CE1_CORE_CLK_CTL_REG);
+
+ regval = readl_relaxed(USB_HS1_HCLK_CTL_REG);
+ regval &= ~BIT(6);
+ writel_relaxed(regval, USB_HS1_HCLK_CTL_REG);
}
/* Local clock driver initialization. */
diff --git a/arch/arm/mach-msm/clock-dummy.c b/arch/arm/mach-msm/clock-dummy.c
index feef984..dfd4a67 100644
--- a/arch/arm/mach-msm/clock-dummy.c
+++ b/arch/arm/mach-msm/clock-dummy.c
@@ -22,11 +22,6 @@
return 0;
}
-static int dummy_clk_set_min_rate(struct clk *clk, unsigned long rate)
-{
- return 0;
-}
-
static int dummy_clk_set_max_rate(struct clk *clk, unsigned long rate)
{
return 0;
@@ -55,7 +50,6 @@
static struct clk_ops clk_ops_dummy = {
.reset = dummy_clk_reset,
.set_rate = dummy_clk_set_rate,
- .set_min_rate = dummy_clk_set_min_rate,
.set_max_rate = dummy_clk_set_max_rate,
.set_flags = dummy_clk_set_flags,
.get_rate = dummy_clk_get_rate,
diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c
index c1cfb55..f8d84be 100644
--- a/arch/arm/mach-msm/clock-local.c
+++ b/arch/arm/mach-msm/clock-local.c
@@ -523,22 +523,6 @@
return _rcg_clk_set_rate(clk, nf);
}
-/* Set a clock to a rate greater than some minimum. */
-int rcg_clk_set_min_rate(struct clk *c, unsigned long rate)
-{
- struct rcg_clk *clk = to_rcg_clk(c);
- struct clk_freq_tbl *nf;
-
- for (nf = clk->freq_tbl; nf->freq_hz != FREQ_END
- && nf->freq_hz < rate; nf++)
- ;
-
- if (nf->freq_hz == FREQ_END)
- return -EINVAL;
-
- return _rcg_clk_set_rate(clk, nf);
-}
-
/* Get the currently-set rate of a clock in Hz. */
unsigned long rcg_clk_get_rate(struct clk *c)
{
@@ -641,7 +625,7 @@
return 1;
}
-static int pll_vote_clk_enable(struct clk *clk)
+int pll_vote_clk_enable(struct clk *clk)
{
u32 ena;
unsigned long flags;
@@ -660,7 +644,7 @@
return 0;
}
-static void pll_vote_clk_disable(struct clk *clk)
+void pll_vote_clk_disable(struct clk *clk)
{
u32 ena;
unsigned long flags;
@@ -673,19 +657,19 @@
spin_unlock_irqrestore(&local_clock_reg_lock, flags);
}
-static unsigned long pll_vote_clk_get_rate(struct clk *clk)
+unsigned long pll_vote_clk_get_rate(struct clk *clk)
{
struct pll_vote_clk *pll = to_pll_vote_clk(clk);
return pll->rate;
}
-static struct clk *pll_vote_clk_get_parent(struct clk *clk)
+struct clk *pll_vote_clk_get_parent(struct clk *clk)
{
struct pll_vote_clk *pll = to_pll_vote_clk(clk);
return pll->parent;
}
-static int pll_vote_clk_is_enabled(struct clk *clk)
+int pll_vote_clk_is_enabled(struct clk *clk)
{
struct pll_vote_clk *pll = to_pll_vote_clk(clk);
return !!(readl_relaxed(pll->status_reg) & BIT(16));
@@ -911,3 +895,97 @@
{
return branch_reset(&to_branch_clk(clk)->b, action);
}
+
+static int cdiv_clk_enable(struct clk *c)
+{
+ unsigned long flags;
+ struct cdiv_clk *clk = to_cdiv_clk(c);
+
+ spin_lock_irqsave(&local_clock_reg_lock, flags);
+ __branch_clk_enable_reg(&clk->b, clk->c.dbg_name);
+ spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+ return 0;
+}
+
+static void cdiv_clk_disable(struct clk *c)
+{
+ unsigned long flags;
+ struct cdiv_clk *clk = to_cdiv_clk(c);
+
+ spin_lock_irqsave(&local_clock_reg_lock, flags);
+ __branch_clk_disable_reg(&clk->b, clk->c.dbg_name);
+ spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+}
+
+static int cdiv_clk_set_rate(struct clk *c, unsigned long rate)
+{
+ struct cdiv_clk *clk = to_cdiv_clk(c);
+ u32 reg_val;
+
+ if (rate > clk->max_div)
+ return -EINVAL;
+ /* Check if frequency is actually changed. */
+ if (rate == clk->cur_div)
+ return 0;
+
+ spin_lock(&local_clock_reg_lock);
+ reg_val = readl_relaxed(clk->ns_reg);
+ reg_val &= ~(clk->ext_mask | (clk->max_div - 1) << clk->div_offset);
+ /* Non-zero rates mean set a divider, zero means use external input */
+ if (rate)
+ reg_val |= (rate - 1) << clk->div_offset;
+ else
+ reg_val |= clk->ext_mask;
+ writel_relaxed(reg_val, clk->ns_reg);
+ spin_unlock(&local_clock_reg_lock);
+
+ clk->cur_div = rate;
+ return 0;
+}
+
+static unsigned long cdiv_clk_get_rate(struct clk *c)
+{
+ struct cdiv_clk *clk = to_cdiv_clk(c);
+ return clk->cur_div;
+}
+
+static long cdiv_clk_round_rate(struct clk *c, unsigned long rate)
+{
+ struct cdiv_clk *clk = to_cdiv_clk(c);
+ return rate > clk->max_div ? -EPERM : rate;
+}
+
+static int cdiv_clk_list_rate(struct clk *c, unsigned n)
+{
+ struct cdiv_clk *clk = to_cdiv_clk(c);
+ return n > clk->max_div ? -ENXIO : n;
+}
+
+static int cdiv_clk_handoff(struct clk *c)
+{
+ struct cdiv_clk *clk = to_cdiv_clk(c);
+ u32 reg_val;
+
+ reg_val = readl_relaxed(clk->ns_reg);
+ if (reg_val & clk->ext_mask) {
+ clk->cur_div = 0;
+ } else {
+ reg_val >>= clk->div_offset;
+ clk->cur_div = (reg_val & (clk->max_div - 1)) + 1;
+ }
+
+ return 0;
+}
+
+struct clk_ops clk_ops_cdiv = {
+ .enable = cdiv_clk_enable,
+ .disable = cdiv_clk_disable,
+ .auto_off = cdiv_clk_disable,
+ .handoff = cdiv_clk_handoff,
+ .set_rate = cdiv_clk_set_rate,
+ .get_rate = cdiv_clk_get_rate,
+ .list_rate = cdiv_clk_list_rate,
+ .round_rate = cdiv_clk_round_rate,
+ .is_local = local_clk_is_local,
+};
diff --git a/arch/arm/mach-msm/clock-local.h b/arch/arm/mach-msm/clock-local.h
index 16a9955..2123513 100644
--- a/arch/arm/mach-msm/clock-local.h
+++ b/arch/arm/mach-msm/clock-local.h
@@ -144,7 +144,6 @@
int rcg_clk_enable(struct clk *clk);
void rcg_clk_disable(struct clk *clk);
int rcg_clk_set_rate(struct clk *clk, unsigned long rate);
-int rcg_clk_set_min_rate(struct clk *clk, unsigned long rate);
unsigned long rcg_clk_get_rate(struct clk *clk);
int rcg_clk_list_rate(struct clk *clk, unsigned n);
int rcg_clk_is_enabled(struct clk *clk);
@@ -153,6 +152,35 @@
int rcg_clk_handoff(struct clk *c);
/**
+ * struct cdiv_clk - integer divider clock with external source selection
+ * @ns_reg: source select and divider settings register
+ * @ext_mask: bit to set to select an external source
+ * @cur_div: current divider setting (or 0 for external source)
+ * @max_div: maximum divider value supported (must be power of 2)
+ * @div_offset: number of bits to shift divider left by in @ns_reg
+ * @b: branch
+ * @c: clock
+ */
+struct cdiv_clk {
+ void __iomem *const ns_reg;
+ u32 ext_mask;
+
+ unsigned long cur_div;
+ u8 div_offset;
+ u32 max_div;
+
+ struct branch b;
+ struct clk c;
+};
+
+static inline struct cdiv_clk *to_cdiv_clk(struct clk *clk)
+{
+ return container_of(clk, struct cdiv_clk, c);
+}
+
+extern struct clk_ops clk_ops_cdiv;
+
+/**
* struct fixed_clk - fixed rate clock (used for crystal oscillators)
* @rate: output rate
* @c: clk
@@ -177,6 +205,8 @@
/**
* struct pll_vote_clk - phase locked loop (HW voteable)
* @rate: output rate
+ * @soft_vote: soft voting variable for multiple PLL software instances
+ * @soft_vote_mask: soft voting mask for multiple PLL software instances
* @en_reg: enable register
* @en_mask: ORed with @en_reg to enable the clock
* @status_reg: status register
@@ -186,6 +216,8 @@
struct pll_vote_clk {
unsigned long rate;
+ u32 *soft_vote;
+ const u32 soft_vote_mask;
void __iomem *const en_reg;
const u32 en_mask;
@@ -288,6 +320,15 @@
bool local_clk_is_local(struct clk *clk);
/*
+ * PLL vote clock APIs
+ */
+int pll_vote_clk_enable(struct clk *clk);
+void pll_vote_clk_disable(struct clk *clk);
+unsigned long pll_vote_clk_get_rate(struct clk *clk);
+struct clk *pll_vote_clk_get_parent(struct clk *clk);
+int pll_vote_clk_is_enabled(struct clk *clk);
+
+/*
* Generic set-rate implementations
*/
void set_rate_mnd(struct rcg_clk *clk, struct clk_freq_tbl *nf);
diff --git a/arch/arm/mach-msm/clock-pcom-lookup.c b/arch/arm/mach-msm/clock-pcom-lookup.c
index d1a257d..dd31bd7 100644
--- a/arch/arm/mach-msm/clock-pcom-lookup.c
+++ b/arch/arm/mach-msm/clock-pcom-lookup.c
@@ -87,7 +87,7 @@
static DEFINE_CLK_PCOM(icodec_tx_clk, ICODEC_TX_CLK, CLKFLAG_SKIP_AUTO_OFF);
static DEFINE_CLK_PCOM(imem_clk, IMEM_CLK, 0);
static DEFINE_CLK_PCOM(mdc_clk, MDC_CLK, CLKFLAG_SKIP_AUTO_OFF);
-static DEFINE_CLK_PCOM(mdp_clk, MDP_CLK, 0);
+static DEFINE_CLK_PCOM(mdp_clk, MDP_CLK, CLKFLAG_MIN);
static DEFINE_CLK_PCOM(mdp_lcdc_pad_pclk_clk, MDP_LCDC_PAD_PCLK_CLK,
CLKFLAG_SKIP_AUTO_OFF);
static DEFINE_CLK_PCOM(mdp_lcdc_pclk_clk, MDP_LCDC_PCLK_CLK,
diff --git a/arch/arm/mach-msm/clock-pcom.c b/arch/arm/mach-msm/clock-pcom.c
index 79fe662..58cea99 100644
--- a/arch/arm/mach-msm/clock-pcom.c
+++ b/arch/arm/mach-msm/clock-pcom.c
@@ -74,7 +74,7 @@
return pc_clk_reset(id, action);
}
-static int pc_clk_set_rate(struct clk *clk, unsigned long rate)
+static int _pc_clk_set_rate(struct clk *clk, unsigned long rate)
{
/* The rate _might_ be rounded off to the nearest KHz value by the
* remote function. So a return value of 0 doesn't necessarily mean
@@ -89,7 +89,7 @@
return (int)id < 0 ? -EINVAL : 0;
}
-static int pc_clk_set_min_rate(struct clk *clk, unsigned long rate)
+static int _pc_clk_set_min_rate(struct clk *clk, unsigned long rate)
{
int rc;
int id = to_pcom_clk(clk)->id;
@@ -105,6 +105,14 @@
return (int)id < 0 ? -EINVAL : 0;
}
+static int pc_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ if (clk->flags & CLKFLAG_MIN)
+ return _pc_clk_set_min_rate(clk, rate);
+ else
+ return _pc_clk_set_rate(clk, rate);
+}
+
static int pc_clk_set_max_rate(struct clk *clk, unsigned long rate)
{
int id = to_pcom_clk(clk)->id;
@@ -173,7 +181,6 @@
.auto_off = pc_clk_disable,
.reset = pc_reset,
.set_rate = pc_clk_set_rate,
- .set_min_rate = pc_clk_set_min_rate,
.set_max_rate = pc_clk_set_max_rate,
.set_flags = pc_clk_set_flags,
.get_rate = pc_clk_get_rate,
@@ -188,7 +195,6 @@
.auto_off = pc_clk_disable,
.reset = pc_reset,
.set_rate = pc_clk_set_ext_config,
- .set_min_rate = pc_clk_set_min_rate,
.set_max_rate = pc_clk_set_max_rate,
.set_flags = pc_clk_set_flags,
.get_rate = pc_clk_get_rate,
diff --git a/arch/arm/mach-msm/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
index 75cba59..4757f7d 100644
--- a/arch/arm/mach-msm/clock-rpm.c
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -104,7 +104,7 @@
return;
}
-static int rpm_clk_set_min_rate(struct clk *clk, unsigned long rate)
+static int rpm_clk_set_rate(struct clk *clk, unsigned long rate)
{
unsigned long flags;
struct rpm_clk *r = to_rpm_clk(clk);
@@ -189,7 +189,7 @@
struct clk_ops clk_ops_rpm = {
.enable = rpm_clk_enable,
.disable = rpm_clk_disable,
- .set_min_rate = rpm_clk_set_min_rate,
+ .set_rate = rpm_clk_set_rate,
.get_rate = rpm_clk_get_rate,
.is_enabled = rpm_clk_is_enabled,
.round_rate = rpm_clk_round_rate,
diff --git a/arch/arm/mach-msm/clock-rpm.h b/arch/arm/mach-msm/clock-rpm.h
index 0a99a6d..24df9b6 100644
--- a/arch/arm/mach-msm/clock-rpm.h
+++ b/arch/arm/mach-msm/clock-rpm.h
@@ -45,7 +45,7 @@
.peer = &active, \
.c = { \
.ops = &clk_ops_rpm, \
- .flags = CLKFLAG_SKIP_AUTO_OFF | CLKFLAG_MIN, \
+ .flags = CLKFLAG_SKIP_AUTO_OFF, \
.dbg_name = #name, \
CLK_INIT(name.c), \
.depends = dep, \
@@ -58,7 +58,7 @@
.active_only = true, \
.c = { \
.ops = &clk_ops_rpm, \
- .flags = CLKFLAG_SKIP_AUTO_OFF | CLKFLAG_MIN, \
+ .flags = CLKFLAG_SKIP_AUTO_OFF, \
.dbg_name = #active, \
CLK_INIT(active.c), \
.depends = dep, \
diff --git a/arch/arm/mach-msm/clock-voter.c b/arch/arm/mach-msm/clock-voter.c
index 2624f6c..ef502b3 100644
--- a/arch/arm/mach-msm/clock-voter.c
+++ b/arch/arm/mach-msm/clock-voter.c
@@ -175,7 +175,6 @@
.enable = voter_clk_enable,
.disable = voter_clk_disable,
.set_rate = voter_clk_set_rate,
- .set_min_rate = voter_clk_set_rate,
.get_rate = voter_clk_get_rate,
.is_enabled = voter_clk_is_enabled,
.round_rate = voter_clk_round_rate,
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index d4f3e45..57fd749 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -228,13 +228,12 @@
}
EXPORT_SYMBOL(clk_get_rate);
-static int _clk_set_rate(struct clk *clk, unsigned long rate,
- int (*set_fn)(struct clk *, unsigned long))
+int clk_set_rate(struct clk *clk, unsigned long rate)
{
unsigned long start_rate, flags;
int rc;
- if (!set_fn)
+ if (!clk->ops->set_rate)
return -ENOSYS;
spin_lock_irqsave(&clk->lock, flags);
@@ -244,13 +243,13 @@
rc = vote_rate_vdd(clk, rate);
if (rc)
goto err_vote_vdd;
- rc = set_fn(clk, rate);
+ rc = clk->ops->set_rate(clk, rate);
if (rc)
goto err_set_rate;
/* Release vdd requirements for starting frequency. */
unvote_rate_vdd(clk, start_rate);
} else {
- rc = set_fn(clk, rate);
+ rc = clk->ops->set_rate(clk, rate);
}
if (!rc)
@@ -265,6 +264,7 @@
spin_unlock_irqrestore(&clk->lock, flags);
return rc;
}
+EXPORT_SYMBOL(clk_set_rate);
long clk_round_rate(struct clk *clk, unsigned long rate)
{
@@ -275,21 +275,6 @@
}
EXPORT_SYMBOL(clk_round_rate);
-int clk_set_rate(struct clk *clk, unsigned long rate)
-{
- if (clk->flags & CLKFLAG_MIN)
- return _clk_set_rate(clk, rate, clk->ops->set_min_rate);
- else
- return _clk_set_rate(clk, rate, clk->ops->set_rate);
-}
-EXPORT_SYMBOL(clk_set_rate);
-
-int clk_set_min_rate(struct clk *clk, unsigned long rate)
-{
- return _clk_set_rate(clk, rate, clk->ops->set_min_rate);
-}
-EXPORT_SYMBOL(clk_set_min_rate);
-
int clk_set_max_rate(struct clk *clk, unsigned long rate)
{
if (!clk->ops->set_max_rate)
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index 81f12c6..ec8ff6c 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -66,7 +66,6 @@
int (*handoff)(struct clk *clk);
int (*reset)(struct clk *clk, enum clk_reset_action action);
int (*set_rate)(struct clk *clk, unsigned long rate);
- int (*set_min_rate)(struct clk *clk, unsigned long rate);
int (*set_max_rate)(struct clk *clk, unsigned long rate);
int (*set_flags)(struct clk *clk, unsigned flags);
unsigned long (*get_rate)(struct clk *clk);
diff --git a/arch/arm/mach-msm/cpuidle.c b/arch/arm/mach-msm/cpuidle.c
index 4f22feb..6738955 100644
--- a/arch/arm/mach-msm/cpuidle.c
+++ b/arch/arm/mach-msm/cpuidle.c
@@ -14,6 +14,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/cpuidle.h>
+#include <linux/cpu_pm.h>
#include "cpuidle.h"
#include "pm.h"
@@ -61,8 +62,15 @@
atomic_notifier_call_chain(head, MSM_CPUIDLE_STATE_ENTER, NULL);
#endif
+#ifdef CONFIG_CPU_PM
+ cpu_pm_enter();
+#endif
ret = msm_pm_idle_enter((enum msm_pm_sleep_mode) (state->driver_data));
+#ifdef CONFIG_CPU_PM
+ cpu_pm_exit();
+#endif
+
#ifdef CONFIG_MSM_SLEEP_STATS
atomic_notifier_call_chain(head, MSM_CPUIDLE_STATE_EXIT, NULL);
#endif
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 9b8d5ac..7420bc0 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -581,6 +581,23 @@
.id = -1,
};
+#ifdef CONFIG_HW_RANDOM_MSM
+/* PRNG device */
+#define MSM_PRNG_PHYS 0x1A500000
+static struct resource rng_resources = {
+ .flags = IORESOURCE_MEM,
+ .start = MSM_PRNG_PHYS,
+ .end = MSM_PRNG_PHYS + SZ_512 - 1,
+};
+
+struct platform_device apq8064_device_rng = {
+ .name = "msm_rng",
+ .id = 0,
+ .num_resources = 1,
+ .resource = &rng_resources,
+};
+#endif
+
static struct clk_lookup msm_clocks_8064_dummy[] = {
CLK_DUMMY("pll2", PLL2, NULL, 0),
CLK_DUMMY("pll8", PLL8, NULL, 0),
@@ -625,7 +642,7 @@
CLK_DUMMY("core_clk", GSBI7_QUP_CLK, NULL, OFF),
CLK_DUMMY("core_clk", PDM_CLK, NULL, OFF),
CLK_DUMMY("mem_clk", PMEM_CLK, NULL, OFF),
- CLK_DUMMY("core_clk", PRNG_CLK, NULL, OFF),
+ CLK_DUMMY("core_clk", PRNG_CLK, "msm_rng.0", OFF),
CLK_DUMMY("core_clk", SDC1_CLK, NULL, OFF),
CLK_DUMMY("core_clk", SDC2_CLK, NULL, OFF),
CLK_DUMMY("core_clk", SDC3_CLK, NULL, OFF),
@@ -688,7 +705,7 @@
CLK_DUMMY("dsi_esc_clk", DSI2_ESC_CLK, NULL, OFF),
CLK_DUMMY("core_clk", VCAP_CLK, NULL, OFF),
CLK_DUMMY("npl_clk", VCAP_NPL_CLK, NULL, OFF),
- CLK_DUMMY("core_clk", GFX3D_CLK, NULL, OFF),
+ CLK_DUMMY("core_clk", GFX3D_CLK, "kgsl-3d0.0", OFF),
CLK_DUMMY("ijpeg_clk", IJPEG_CLK, NULL, OFF),
CLK_DUMMY("mem_clk", IMEM_CLK, NULL, OFF),
CLK_DUMMY("core_clk", JPEGD_CLK, NULL, OFF),
@@ -727,7 +744,7 @@
CLK_DUMMY("mdp_p2clk", MDP_P2CLK, NULL, OFF),
CLK_DUMMY("dsi2_pixel_clk", DSI2_PIXEL_CLK, NULL, OFF),
CLK_DUMMY("lvds_ref_clk", LVDS_REF_CLK, NULL, OFF),
- CLK_DUMMY("iface_clk", GFX3D_P_CLK, NULL, OFF),
+ CLK_DUMMY("iface_clk", GFX3D_P_CLK, "kgsl-3d0.0", OFF),
CLK_DUMMY("master_iface_clk", HDMI_M_P_CLK, "hdmi_msm.1", OFF),
CLK_DUMMY("slave_iface_clk", HDMI_S_P_CLK, "hdmi_msm.1", OFF),
CLK_DUMMY("ijpeg_pclk", IJPEG_P_CLK, NULL, OFF),
@@ -761,6 +778,12 @@
CLK_DUMMY("dfab_clk", DFAB_CLK, NULL, 0),
CLK_DUMMY("dma_bam_pclk", DMA_BAM_P_CLK, NULL, 0),
CLK_DUMMY("mem_clk", EBI1_ADM_CLK, "msm_dmov", 0),
+ CLK_DUMMY("ce3_core_src_clk", CE3_SRC_CLK, "qce.0", OFF),
+ CLK_DUMMY("ce3_core_src_clk", CE3_SRC_CLK, "qcrypto.0", OFF),
+ CLK_DUMMY("core_clk", CE3_CORE_CLK, "qce.0", OFF),
+ CLK_DUMMY("core_clk", CE3_CORE_CLK, "qcrypto.0", OFF),
+ CLK_DUMMY("iface_clk", CE3_P_CLK, "qce0.0", OFF),
+ CLK_DUMMY("iface_clk", CE3_P_CLK, "qcrypto.0", OFF),
};
struct clock_init_data apq8064_dummy_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 0765251..ad803f8 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -15,6 +15,7 @@
#include <linux/list.h>
#include <linux/platform_device.h>
#include <linux/msm_rotator.h>
+#include <linux/ion.h>
#include <linux/gpio.h>
#include <asm/clkdev.h>
#include <linux/msm_kgsl.h>
@@ -29,6 +30,7 @@
#include <mach/rpm.h>
#include <mach/msm_bus_board.h>
#include <mach/msm_memtypes.h>
+#include <mach/msm_xo.h>
#include <sound/msm-dai-q6.h>
#include <sound/apr_audio.h>
#include "clock.h"
@@ -37,6 +39,8 @@
#include "footswitch.h"
#include "msm_watchdog.h"
#include "rpm_stats.h"
+#include "pil-q6v4.h"
+#include "scm-pas.h"
#ifdef CONFIG_MSM_MPM
#include "mpm.h"
@@ -181,6 +185,22 @@
},
};
+#define SHARED_IMEM_TZ_BASE 0x2a03f720
+static struct resource tzlog_resources[] = {
+ {
+ .start = SHARED_IMEM_TZ_BASE,
+ .end = SHARED_IMEM_TZ_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device msm_device_tz_log = {
+ .name = "tz_log",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(tzlog_resources),
+ .resource = tzlog_resources,
+};
+
static struct resource resources_uart_gsbi2[] = {
{
.start = MSM8960_GSBI2_UARTDM_IRQ,
@@ -414,13 +434,13 @@
.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
.dst = MSM_BUS_SLAVE_EBI_CH0,
.ab = 372244480,
- .ib = 1861222400,
+ .ib = 2560000000U,
},
{
.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
.dst = MSM_BUS_SLAVE_EBI_CH0,
.ab = 501219328,
- .ib = 2004877312,
+ .ib = 2560000000U,
},
{
.src = MSM_BUS_MASTER_AMPSS_M0,
@@ -440,13 +460,13 @@
.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
.dst = MSM_BUS_SLAVE_EBI_CH0,
.ab = 222298112,
- .ib = 1778384896,
+ .ib = 2560000000U,
},
{
.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
.dst = MSM_BUS_SLAVE_EBI_CH0,
.ab = 330301440,
- .ib = 1321205760,
+ .ib = 2560000000U,
},
{
.src = MSM_BUS_MASTER_AMPSS_M0,
@@ -537,10 +557,11 @@
#ifdef CONFIG_MSM_BUS_SCALING
.vidc_bus_client_pdata = &vidc_bus_client_data,
#endif
- .memtype = MEMTYPE_EBI1,
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ .memtype = ION_HEAP_EBI_ID,
.enable_ion = 1,
#else
+ .memtype = MEMTYPE_EBI1,
.enable_ion = 0,
#endif
};
@@ -797,6 +818,113 @@
},
};
+#define MSM_LPASS_QDSP6SS_PHYS 0x28800000
+#define SFAB_LPASS_Q6_ACLK_CTL (MSM_CLK_CTL_BASE + 0x23A0)
+
+static struct resource msm_8960_q6_lpass_resources[] = {
+ {
+ .start = MSM_LPASS_QDSP6SS_PHYS,
+ .end = MSM_LPASS_QDSP6SS_PHYS + SZ_256 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct pil_q6v4_pdata msm_8960_q6_lpass_data = {
+ .strap_tcm_base = 0x01460000,
+ .strap_ahb_upper = 0x00290000,
+ .strap_ahb_lower = 0x00000280,
+ .aclk_reg = SFAB_LPASS_Q6_ACLK_CTL,
+ .xo_id = MSM_XO_PXO,
+ .name = "q6",
+ .pas_id = PAS_Q6,
+ .bus_port = MSM_BUS_MASTER_LPASS_PROC,
+};
+
+struct platform_device msm_8960_q6_lpass = {
+ .name = "pil_qdsp6v4",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(msm_8960_q6_lpass_resources),
+ .resource = msm_8960_q6_lpass_resources,
+ .dev.platform_data = &msm_8960_q6_lpass_data,
+};
+
+#define MSM_MSS_ENABLE_PHYS 0x08B00000
+#define MSM_FW_QDSP6SS_PHYS 0x08800000
+#define MSS_Q6FW_JTAG_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C6C)
+#define SFAB_MSS_Q6_FW_ACLK_CTL (MSM_CLK_CTL_BASE + 0x2044)
+
+static struct resource msm_8960_q6_mss_fw_resources[] = {
+ {
+ .start = MSM_FW_QDSP6SS_PHYS,
+ .end = MSM_FW_QDSP6SS_PHYS + SZ_256 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MSM_MSS_ENABLE_PHYS,
+ .end = MSM_MSS_ENABLE_PHYS + 4 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct pil_q6v4_pdata msm_8960_q6_mss_fw_data = {
+ .strap_tcm_base = 0x00400000,
+ .strap_ahb_upper = 0x00090000,
+ .strap_ahb_lower = 0x00000080,
+ .aclk_reg = SFAB_MSS_Q6_FW_ACLK_CTL,
+ .jtag_clk_reg = MSS_Q6FW_JTAG_CLK_CTL,
+ .xo_id = MSM_XO_TCXO_D0,
+ .name = "modem_fw",
+ .depends = "q6",
+ .pas_id = PAS_MODEM_FW,
+ .bus_port = MSM_BUS_MASTER_MSS_FW_PROC,
+};
+
+struct platform_device msm_8960_q6_mss_fw = {
+ .name = "pil_qdsp6v4",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(msm_8960_q6_mss_fw_resources),
+ .resource = msm_8960_q6_mss_fw_resources,
+ .dev.platform_data = &msm_8960_q6_mss_fw_data,
+};
+
+#define MSM_SW_QDSP6SS_PHYS 0x08900000
+#define SFAB_MSS_Q6_SW_ACLK_CTL (MSM_CLK_CTL_BASE + 0x2040)
+#define MSS_Q6SW_JTAG_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C68)
+
+static struct resource msm_8960_q6_mss_sw_resources[] = {
+ {
+ .start = MSM_SW_QDSP6SS_PHYS,
+ .end = MSM_SW_QDSP6SS_PHYS + SZ_256 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MSM_MSS_ENABLE_PHYS,
+ .end = MSM_MSS_ENABLE_PHYS + 4 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct pil_q6v4_pdata msm_8960_q6_mss_sw_data = {
+ .strap_tcm_base = 0x00420000,
+ .strap_ahb_upper = 0x00090000,
+ .strap_ahb_lower = 0x00000080,
+ .aclk_reg = SFAB_MSS_Q6_SW_ACLK_CTL,
+ .jtag_clk_reg = MSS_Q6SW_JTAG_CLK_CTL,
+ .xo_id = MSM_XO_TCXO_D0,
+ .name = "modem",
+ .depends = "modem_fw",
+ .pas_id = PAS_MODEM_SW,
+ .bus_port = MSM_BUS_MASTER_MSS_SW_PROC,
+};
+
+struct platform_device msm_8960_q6_mss_sw = {
+ .name = "pil_qdsp6v4",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(msm_8960_q6_mss_sw_resources),
+ .resource = msm_8960_q6_mss_sw_resources,
+ .dev.platform_data = &msm_8960_q6_mss_sw_data,
+};
+
struct platform_device msm_device_smd = {
.name = "msm_smd",
.id = -1,
@@ -983,10 +1111,6 @@
#ifdef CONFIG_MSM_CAMERA
struct resource msm_camera_resources[] = {
{
- .name = "vid_buf",
- .flags = IORESOURCE_DMA,
- },
- {
.name = "s3d_rw",
.start = 0x008003E0,
.end = 0x008003E0 + SZ_16 - 1,
@@ -1203,18 +1327,6 @@
.flags = IORESOURCE_IO,
},
{
- .name = "spi_cs",
- .start = 8,
- .end = 8,
- .flags = IORESOURCE_IO,
- },
- {
- .name = "spi_cs1",
- .start = 14,
- .end = 14,
- .flags = IORESOURCE_IO,
- },
- {
.name = "spi_miso",
.start = 7,
.end = 7,
@@ -1226,6 +1338,18 @@
.end = 6,
.flags = IORESOURCE_IO,
},
+ {
+ .name = "spi_cs",
+ .start = 8,
+ .end = 8,
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .name = "spi_cs1",
+ .start = 14,
+ .end = 14,
+ .flags = IORESOURCE_IO,
+ },
};
struct platform_device msm8960_device_qup_spi_gsbi1 = {
@@ -1333,6 +1457,11 @@
.id = -1,
};
+struct platform_device msm_compr_dsp = {
+ .name = "msm-compr-dsp",
+ .id = -1,
+};
+
struct platform_device msm_pcm_hostless = {
.name = "msm-pcm-hostless",
.id = -1,
@@ -2038,52 +2167,41 @@
};
static struct kgsl_device_platform_data kgsl_3d0_pdata = {
- .pwr_data = {
- .pwrlevel = {
- {
- .gpu_freq = 400000000,
- .bus_freq = 4,
- .io_fraction = 0,
- },
- {
- .gpu_freq = 300000000,
- .bus_freq = 3,
- .io_fraction = 33,
- },
- {
- .gpu_freq = 200000000,
- .bus_freq = 2,
- .io_fraction = 100,
- },
- {
- .gpu_freq = 128000000,
- .bus_freq = 1,
- .io_fraction = 100,
- },
- {
- .gpu_freq = 27000000,
- .bus_freq = 0,
- },
+ .pwrlevel = {
+ {
+ .gpu_freq = 400000000,
+ .bus_freq = 4,
+ .io_fraction = 0,
},
- .init_level = 0,
- .num_levels = 5,
- .set_grp_async = NULL,
- .idle_timeout = HZ/5,
- .nap_allowed = true,
+ {
+ .gpu_freq = 300000000,
+ .bus_freq = 3,
+ .io_fraction = 33,
+ },
+ {
+ .gpu_freq = 200000000,
+ .bus_freq = 2,
+ .io_fraction = 100,
+ },
+ {
+ .gpu_freq = 128000000,
+ .bus_freq = 1,
+ .io_fraction = 100,
+ },
+ {
+ .gpu_freq = 27000000,
+ .bus_freq = 0,
+ },
},
- .clk = {
- .name = {
- .clk = "core_clk",
- .pclk = "iface_clk",
- },
+ .init_level = 0,
+ .num_levels = 5,
+ .set_grp_async = NULL,
+ .idle_timeout = HZ/5,
+ .nap_allowed = true,
+ .clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE,
#ifdef CONFIG_MSM_BUS_SCALING
- .bus_scale_table = &grp3d_bus_scale_pdata,
+ .bus_scale_table = &grp3d_bus_scale_pdata,
#endif
- },
- .imem_clk_name = {
- .clk = NULL,
- .pclk = "mem_iface_clk",
- },
.iommu_user_ctx_name = "gfx3d_user",
.iommu_priv_ctx_name = NULL,
};
@@ -2114,33 +2232,25 @@
};
static struct kgsl_device_platform_data kgsl_2d0_pdata = {
- .pwr_data = {
- .pwrlevel = {
- {
- .gpu_freq = 200000000,
- .bus_freq = 1,
- },
- {
- .gpu_freq = 200000000,
- .bus_freq = 0,
- },
+ .pwrlevel = {
+ {
+ .gpu_freq = 200000000,
+ .bus_freq = 1,
},
- .init_level = 0,
- .num_levels = 2,
- .set_grp_async = NULL,
- .idle_timeout = HZ/10,
- .nap_allowed = true,
+ {
+ .gpu_freq = 200000000,
+ .bus_freq = 0,
+ },
},
- .clk = {
- .name = {
- /* note: 2d clocks disabled on v1 */
- .clk = "core_clk",
- .pclk = "iface_clk",
- },
+ .init_level = 0,
+ .num_levels = 2,
+ .set_grp_async = NULL,
+ .idle_timeout = HZ/10,
+ .nap_allowed = true,
+ .clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE,
#ifdef CONFIG_MSM_BUS_SCALING
- .bus_scale_table = &grp2d0_bus_scale_pdata,
+ .bus_scale_table = &grp2d0_bus_scale_pdata,
#endif
- },
.iommu_user_ctx_name = "gfx2d0_2d0",
.iommu_priv_ctx_name = NULL,
};
@@ -2171,32 +2281,25 @@
};
static struct kgsl_device_platform_data kgsl_2d1_pdata = {
- .pwr_data = {
- .pwrlevel = {
- {
- .gpu_freq = 200000000,
- .bus_freq = 1,
- },
- {
- .gpu_freq = 200000000,
- .bus_freq = 0,
- },
+ .pwrlevel = {
+ {
+ .gpu_freq = 200000000,
+ .bus_freq = 1,
},
- .init_level = 0,
- .num_levels = 2,
- .set_grp_async = NULL,
- .idle_timeout = HZ/10,
- .nap_allowed = true,
+ {
+ .gpu_freq = 200000000,
+ .bus_freq = 0,
+ },
},
- .clk = {
- .name = {
- .clk = "core_clk",
- .pclk = "iface_clk",
- },
+ .init_level = 0,
+ .num_levels = 2,
+ .set_grp_async = NULL,
+ .idle_timeout = HZ/10,
+ .nap_allowed = true,
+ .clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE,
#ifdef CONFIG_MSM_BUS_SCALING
- .bus_scale_table = &grp2d1_bus_scale_pdata,
+ .bus_scale_table = &grp2d1_bus_scale_pdata,
#endif
- },
.iommu_user_ctx_name = "gfx2d1_2d1",
.iommu_priv_ctx_name = NULL,
};
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index e5a3f20..012eb85 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -26,6 +26,7 @@
#include <mach/irqs.h>
#include <mach/socinfo.h>
#include <mach/rpm.h>
+#include <mach/msm_bus_board.h>
#include <asm/hardware/cache-l2x0.h>
#include <mach/msm_sps.h>
#include <mach/dma.h>
@@ -144,6 +145,31 @@
},
};
+static struct resource resources_hsusb_host[] = {
+ {
+ .start = MSM9615_HSUSB_PHYS,
+ .end = MSM9615_HSUSB_PHYS + MSM9615_HSUSB_PHYS - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = USB1_HS_IRQ,
+ .end = USB1_HS_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 dma_mask = DMA_BIT_MASK(32);
+struct platform_device msm_device_hsusb_host = {
+ .name = "msm_hsusb_host",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(resources_hsusb_host),
+ .resource = resources_hsusb_host,
+ .dev = {
+ .dma_mask = &dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+};
+
static struct resource resources_uart_gsbi4[] = {
{
.start = GSBI4_UARTDM_IRQ,
@@ -667,53 +693,47 @@
};
static uint16_t msm_mpm_irqs_m2a[MSM_MPM_NR_MPM_IRQS] = {
- [1] = MSM_GPIO_TO_INT(46),
- [2] = MSM_GPIO_TO_INT(150),
- [4] = MSM_GPIO_TO_INT(103),
- [5] = MSM_GPIO_TO_INT(104),
- [6] = MSM_GPIO_TO_INT(105),
- [7] = MSM_GPIO_TO_INT(106),
- [8] = MSM_GPIO_TO_INT(107),
- [9] = MSM_GPIO_TO_INT(7),
- [10] = MSM_GPIO_TO_INT(11),
- [11] = MSM_GPIO_TO_INT(15),
- [12] = MSM_GPIO_TO_INT(19),
- [13] = MSM_GPIO_TO_INT(23),
- [14] = MSM_GPIO_TO_INT(27),
- [15] = MSM_GPIO_TO_INT(31),
- [16] = MSM_GPIO_TO_INT(35),
- [19] = MSM_GPIO_TO_INT(90),
- [20] = MSM_GPIO_TO_INT(92),
- [23] = MSM_GPIO_TO_INT(85),
- [24] = MSM_GPIO_TO_INT(83),
+ [4] = MSM_GPIO_TO_INT(30),
+ [5] = MSM_GPIO_TO_INT(59),
+ [6] = MSM_GPIO_TO_INT(81),
+ [7] = MSM_GPIO_TO_INT(87),
+ [8] = MSM_GPIO_TO_INT(86),
+ [9] = MSM_GPIO_TO_INT(2),
+ [10] = MSM_GPIO_TO_INT(6),
+ [11] = MSM_GPIO_TO_INT(10),
+ [12] = MSM_GPIO_TO_INT(14),
+ [13] = MSM_GPIO_TO_INT(18),
+ [14] = MSM_GPIO_TO_INT(7),
+ [15] = MSM_GPIO_TO_INT(11),
+ [16] = MSM_GPIO_TO_INT(15),
+ [19] = MSM_GPIO_TO_INT(26),
+ [20] = MSM_GPIO_TO_INT(28),
+ [23] = MSM_GPIO_TO_INT(19),
+ [24] = MSM_GPIO_TO_INT(23),
[25] = USB1_HS_IRQ,
- /*[27] = HDMI_IRQ,*/
- [29] = MSM_GPIO_TO_INT(10),
- [30] = MSM_GPIO_TO_INT(102),
- [31] = MSM_GPIO_TO_INT(81),
- [32] = MSM_GPIO_TO_INT(78),
- [33] = MSM_GPIO_TO_INT(94),
- [34] = MSM_GPIO_TO_INT(72),
- [35] = MSM_GPIO_TO_INT(39),
- [36] = MSM_GPIO_TO_INT(43),
- [37] = MSM_GPIO_TO_INT(61),
- [38] = MSM_GPIO_TO_INT(50),
- [39] = MSM_GPIO_TO_INT(42),
- [41] = MSM_GPIO_TO_INT(62),
- [42] = MSM_GPIO_TO_INT(76),
- [43] = MSM_GPIO_TO_INT(75),
- [44] = MSM_GPIO_TO_INT(70),
- [45] = MSM_GPIO_TO_INT(69),
- [46] = MSM_GPIO_TO_INT(67),
- [47] = MSM_GPIO_TO_INT(65),
- [48] = MSM_GPIO_TO_INT(58),
- [49] = MSM_GPIO_TO_INT(54),
- [50] = MSM_GPIO_TO_INT(52),
- [51] = MSM_GPIO_TO_INT(49),
- [52] = MSM_GPIO_TO_INT(40),
- [53] = MSM_GPIO_TO_INT(37),
- [54] = MSM_GPIO_TO_INT(24),
- [55] = MSM_GPIO_TO_INT(14),
+ [26] = MSM_GPIO_TO_INT(3),
+ [27] = MSM_GPIO_TO_INT(68),
+ [29] = MSM_GPIO_TO_INT(78),
+ [31] = MSM_GPIO_TO_INT(0),
+ [32] = MSM_GPIO_TO_INT(4),
+ [33] = MSM_GPIO_TO_INT(22),
+ [34] = MSM_GPIO_TO_INT(17),
+ [37] = MSM_GPIO_TO_INT(20),
+ [39] = MSM_GPIO_TO_INT(84),
+ [42] = MSM_GPIO_TO_INT(24),
+ [43] = MSM_GPIO_TO_INT(79),
+ [44] = MSM_GPIO_TO_INT(80),
+ [45] = MSM_GPIO_TO_INT(82),
+ [46] = MSM_GPIO_TO_INT(85),
+ [47] = MSM_GPIO_TO_INT(45),
+ [48] = MSM_GPIO_TO_INT(50),
+ [49] = MSM_GPIO_TO_INT(51),
+ [50] = MSM_GPIO_TO_INT(69),
+ [51] = MSM_GPIO_TO_INT(77),
+ [52] = MSM_GPIO_TO_INT(1),
+ [53] = MSM_GPIO_TO_INT(5),
+ [54] = MSM_GPIO_TO_INT(40),
+ [55] = MSM_GPIO_TO_INT(27),
};
static uint16_t msm_mpm_bypassed_apps_irqs[] = {
@@ -860,3 +880,13 @@
irq_set_handler(i, handle_percpu_irq);
}
}
+
+struct platform_device msm_bus_9615_sys_fabric = {
+ .name = "msm_bus_fabric",
+ .id = MSM_BUS_FAB_SYSTEM,
+};
+
+struct platform_device msm_bus_def_fab = {
+ .name = "msm_bus_fabric",
+ .id = MSM_BUS_FAB_DEFAULT,
+};
diff --git a/arch/arm/mach-msm/devices-msm7x25.c b/arch/arm/mach-msm/devices-msm7x25.c
index d918315..71b57b4 100644
--- a/arch/arm/mach-msm/devices-msm7x25.c
+++ b/arch/arm/mach-msm/devices-msm7x25.c
@@ -31,7 +31,6 @@
#include <asm/mach/mmc.h>
#include <mach/msm_hsusb.h>
#include <mach/usbdiag.h>
-#include <mach/usb_gadget_fserial.h>
#include <mach/rpc_hsusb.h>
#include "clock-pcom.h"
diff --git a/arch/arm/mach-msm/devices-msm7x27.c b/arch/arm/mach-msm/devices-msm7x27.c
index 1bb9a21..0fb64dc 100644
--- a/arch/arm/mach-msm/devices-msm7x27.c
+++ b/arch/arm/mach-msm/devices-msm7x27.c
@@ -807,32 +807,22 @@
};
static struct kgsl_device_platform_data kgsl_3d0_pdata = {
- .pwr_data = {
- /* bus_freq has been set to 160000 for power savings.
- * OEMs may modify the value at their discretion for performance
- * The appropriate maximum replacement for 160000 is:
- * msm7x2x_clock_data.max_axi_khz
- */
- .pwrlevel = {
- {
- .gpu_freq = 0,
- .bus_freq = 160000000,
- },
- },
- .init_level = 0,
- .num_levels = 1,
- .set_grp_async = NULL,
- .idle_timeout = HZ/5,
- },
- .clk = {
- .name = {
- .clk = "core_clk",
- .pclk = "iface_clk",
+ /* bus_freq has been set to 160000 for power savings.
+ * OEMs may modify the value at their discretion for performance
+ * The appropriate maximum replacement for 160000 is:
+ * msm7x2x_clock_data.max_axi_khz
+ */
+ .pwrlevel = {
+ {
+ .gpu_freq = 0,
+ .bus_freq = 160000000,
},
},
- .imem_clk_name = {
- .clk = "mem_clk",
- },
+ .init_level = 0,
+ .num_levels = 1,
+ .set_grp_async = NULL,
+ .idle_timeout = HZ/5,
+ .clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM,
};
struct platform_device msm_kgsl_3d0 = {
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 7008bd5..2b08098 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -588,34 +588,22 @@
};
static struct kgsl_device_platform_data kgsl_3d0_pdata = {
- .pwr_data = {
- .pwrlevel = {
- {
- .gpu_freq = 245760000,
- .bus_freq = 200000000,
- },
- {
- .gpu_freq = 133330000,
- .bus_freq = 0,
- },
+ .pwrlevel = {
+ {
+ .gpu_freq = 245760000,
+ .bus_freq = 200000000,
},
- .init_level = 0,
- .num_levels = 2,
- .set_grp_async = set_grp_xbar_async,
- .idle_timeout = HZ/5,
- .nap_allowed = false,
- },
- .clk = {
- .name = {
- .clk = "core_clk",
- .pclk = "iface_clk",
+ {
+ .gpu_freq = 133330000,
+ .bus_freq = 0,
},
},
- .imem_clk_name = {
- .clk = "mem_clk",
- .pclk = NULL,
- },
-
+ .init_level = 0,
+ .num_levels = 2,
+ .set_grp_async = set_grp_xbar_async,
+ .idle_timeout = HZ/5,
+ .nap_allowed = false,
+ .clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM,
};
struct platform_device msm_kgsl_3d0 = {
@@ -631,10 +619,10 @@
void __init msm7x25a_kgsl_3d0_init(void)
{
if (cpu_is_msm7x25a() || cpu_is_msm7x25aa()) {
- kgsl_3d0_pdata.pwr_data.pwrlevel[0].gpu_freq = 133330000;
- kgsl_3d0_pdata.pwr_data.pwrlevel[0].bus_freq = 160000000;
- kgsl_3d0_pdata.pwr_data.pwrlevel[1].gpu_freq = 96000000;
- kgsl_3d0_pdata.pwr_data.pwrlevel[1].bus_freq = 0;
+ kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 133330000;
+ kgsl_3d0_pdata.pwrlevel[0].bus_freq = 160000000;
+ kgsl_3d0_pdata.pwrlevel[1].gpu_freq = 96000000;
+ kgsl_3d0_pdata.pwrlevel[1].bus_freq = 0;
}
}
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index 2a39e3c..41136d2 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -548,8 +548,8 @@
},
{
.name = "vbus_on",
- .start = PM8058_CHGVAL_IRQ(PMIC8058_IRQ_BASE),
- .end = PM8058_CHGVAL_IRQ(PMIC8058_IRQ_BASE),
+ .start = PMIC8058_IRQ_BASE + PM8058_CHGVAL_IRQ,
+ .end = PMIC8058_IRQ_BASE + PM8058_CHGVAL_IRQ,
.flags = IORESOURCE_IRQ,
},
};
@@ -1102,37 +1102,27 @@
};
static struct kgsl_device_platform_data kgsl_3d0_pdata = {
- .pwr_data = {
- .pwrlevel = {
- {
- .gpu_freq = 245760000,
- .bus_freq = 192000000,
- },
- {
- .gpu_freq = 192000000,
- .bus_freq = 152000000,
- },
- {
- .gpu_freq = 192000000,
- .bus_freq = 0,
- },
+ .pwrlevel = {
+ {
+ .gpu_freq = 245760000,
+ .bus_freq = 192000000,
},
- .init_level = 0,
- .num_levels = 3,
- .set_grp_async = set_grp3d_async,
- .idle_timeout = HZ/20,
- .nap_allowed = true,
- },
- .clk = {
- .name = {
- .clk = "core_clk",
- .pclk = "iface_clk",
+ {
+ .gpu_freq = 192000000,
+ .bus_freq = 152000000,
+ },
+ {
+ .gpu_freq = 192000000,
+ .bus_freq = 0,
},
},
- .imem_clk_name = {
- .clk = "mem_clk",
- .pclk = NULL,
- },
+ .init_level = 0,
+ .num_levels = 3,
+ .set_grp_async = set_grp3d_async,
+ .idle_timeout = HZ/20,
+ .nap_allowed = true,
+ .clk_map = KGSL_CLK_SRC | KGSL_CLK_CORE |
+ KGSL_CLK_IFACE | KGSL_CLK_MEM,
};
struct platform_device msm_kgsl_3d0 = {
@@ -1161,26 +1151,19 @@
};
static struct kgsl_device_platform_data kgsl_2d0_pdata = {
- .pwr_data = {
- .pwrlevel = {
- {
- .gpu_freq = 0,
- .bus_freq = 192000000,
- },
- },
- .init_level = 0,
- .num_levels = 1,
- /* HW workaround, run Z180 SYNC @ 192 MHZ */
- .set_grp_async = NULL,
- .idle_timeout = HZ/10,
- .nap_allowed = true,
- },
- .clk = {
- .name = {
- .clk = "core_clk",
- .pclk = "iface_clk",
+ .pwrlevel = {
+ {
+ .gpu_freq = 0,
+ .bus_freq = 192000000,
},
},
+ .init_level = 0,
+ .num_levels = 1,
+ /* HW workaround, run Z180 SYNC @ 192 MHZ */
+ .set_grp_async = NULL,
+ .idle_timeout = HZ/10,
+ .nap_allowed = true,
+ .clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE,
};
struct platform_device msm_kgsl_2d0 = {
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 52c62fd..b9ff604 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -15,6 +15,7 @@
#include <linux/platform_device.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/consumer.h>
+#include <linux/ion.h>
#include <mach/irqs.h>
#include <mach/dma.h>
#include <asm/mach/mmc.h>
@@ -652,52 +653,41 @@
};
static struct kgsl_device_platform_data kgsl_3d0_pdata = {
- .pwr_data = {
- .pwrlevel = {
- {
- .gpu_freq = 266667000,
- .bus_freq = 4,
- .io_fraction = 0,
- },
- {
- .gpu_freq = 228571000,
- .bus_freq = 3,
- .io_fraction = 33,
- },
- {
- .gpu_freq = 200000000,
- .bus_freq = 2,
- .io_fraction = 100,
- },
- {
- .gpu_freq = 177778000,
- .bus_freq = 1,
- .io_fraction = 100,
- },
- {
- .gpu_freq = 27000000,
- .bus_freq = 0,
- },
+ .pwrlevel = {
+ {
+ .gpu_freq = 266667000,
+ .bus_freq = 4,
+ .io_fraction = 0,
},
- .init_level = 0,
- .num_levels = 5,
- .set_grp_async = NULL,
- .idle_timeout = HZ/5,
- .nap_allowed = true,
+ {
+ .gpu_freq = 228571000,
+ .bus_freq = 3,
+ .io_fraction = 33,
+ },
+ {
+ .gpu_freq = 200000000,
+ .bus_freq = 2,
+ .io_fraction = 100,
+ },
+ {
+ .gpu_freq = 177778000,
+ .bus_freq = 1,
+ .io_fraction = 100,
+ },
+ {
+ .gpu_freq = 27000000,
+ .bus_freq = 0,
+ },
},
- .clk = {
- .name = {
- .clk = "core_clk",
- .pclk = "iface_clk",
- },
+ .init_level = 0,
+ .num_levels = 5,
+ .set_grp_async = NULL,
+ .idle_timeout = HZ/5,
+ .nap_allowed = true,
+ .clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE,
#ifdef CONFIG_MSM_BUS_SCALING
- .bus_scale_table = &grp3d_bus_scale_pdata,
+ .bus_scale_table = &grp3d_bus_scale_pdata,
#endif
- },
- .imem_clk_name = {
- .clk = NULL,
- .pclk = "mem_iface_clk",
- },
};
struct platform_device msm_kgsl_3d0 = {
@@ -726,33 +716,25 @@
};
static struct kgsl_device_platform_data kgsl_2d0_pdata = {
- .pwr_data = {
- .pwrlevel = {
- {
- .gpu_freq = 200000000,
- .bus_freq = 1,
- },
- {
- .gpu_freq = 200000000,
- .bus_freq = 0,
- },
+ .pwrlevel = {
+ {
+ .gpu_freq = 200000000,
+ .bus_freq = 1,
},
- .init_level = 0,
- .num_levels = 2,
- .set_grp_async = NULL,
- .idle_timeout = HZ/10,
- .nap_allowed = true,
+ {
+ .gpu_freq = 200000000,
+ .bus_freq = 0,
+ },
},
- .clk = {
- .name = {
- /* note: 2d clocks disabled on v1 */
- .clk = "core_clk",
- .pclk = "iface_clk",
- },
+ .init_level = 0,
+ .num_levels = 2,
+ .set_grp_async = NULL,
+ .idle_timeout = HZ/10,
+ .nap_allowed = true,
+ .clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE,
#ifdef CONFIG_MSM_BUS_SCALING
- .bus_scale_table = &grp2d0_bus_scale_pdata,
+ .bus_scale_table = &grp2d0_bus_scale_pdata,
#endif
- },
};
struct platform_device msm_kgsl_2d0 = {
@@ -781,32 +763,25 @@
};
static struct kgsl_device_platform_data kgsl_2d1_pdata = {
- .pwr_data = {
- .pwrlevel = {
- {
- .gpu_freq = 200000000,
- .bus_freq = 1,
- },
- {
- .gpu_freq = 200000000,
- .bus_freq = 0,
- },
+ .pwrlevel = {
+ {
+ .gpu_freq = 200000000,
+ .bus_freq = 1,
},
- .init_level = 0,
- .num_levels = 2,
- .set_grp_async = NULL,
- .idle_timeout = HZ/10,
- .nap_allowed = true,
+ {
+ .gpu_freq = 200000000,
+ .bus_freq = 0,
+ },
},
- .clk = {
- .name = {
- .clk = "gfx2d1_clk",
- .pclk = "gfx2d1_pclk",
- },
+ .init_level = 0,
+ .num_levels = 2,
+ .set_grp_async = NULL,
+ .idle_timeout = HZ/10,
+ .nap_allowed = true,
+ .clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE,
#ifdef CONFIG_MSM_BUS_SCALING
- .bus_scale_table = &grp2d1_bus_scale_pdata,
+ .bus_scale_table = &grp2d1_bus_scale_pdata,
#endif
- },
};
struct platform_device msm_kgsl_2d1 = {
@@ -830,8 +805,7 @@
if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1) &&
(SOCINFO_VERSION_MINOR(socinfo_get_version()) == 0)) {
printk(KERN_WARNING "kgsl: 2D cores disabled on 8660v1\n");
- kgsl_2d0_pdata.clk.name.clk = NULL;
- kgsl_2d1_pdata.clk.name.clk = NULL;
+ kgsl_2d0_pdata.clk_map = 0;
}
}
@@ -899,27 +873,25 @@
.resource = resources_ssbi_pmic1_resource,
.num_resources = ARRAY_SIZE(resources_ssbi_pmic1_resource),
};
-#endif
-#ifdef CONFIG_I2C_SSBI
-/* 8901 PMIC SSBI on /dev/i2c-7 */
#define MSM_SSBI2_PMIC2B_PHYS 0x00C00000
-static struct resource msm_ssbi2_resources[] = {
+static struct resource resources_ssbi_pmic2_resource[] = {
{
- .name = "ssbi_base",
.start = MSM_SSBI2_PMIC2B_PHYS,
.end = MSM_SSBI2_PMIC2B_PHYS + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
};
-struct platform_device msm_device_ssbi2 = {
- .name = "i2c_ssbi",
- .id = MSM_SSBI2_I2C_BUS_ID,
- .num_resources = ARRAY_SIZE(msm_ssbi2_resources),
- .resource = msm_ssbi2_resources,
+struct platform_device msm_device_ssbi_pmic2 = {
+ .name = "msm_ssbi",
+ .id = 1,
+ .resource = resources_ssbi_pmic2_resource,
+ .num_resources = ARRAY_SIZE(resources_ssbi_pmic2_resource),
};
+#endif
+#ifdef CONFIG_I2C_SSBI
/* CODEC SSBI on /dev/i2c-8 */
#define MSM_SSBI3_PHYS 0x18700000
static struct resource msm_ssbi3_resources[] = {
@@ -977,12 +949,6 @@
.flags = IORESOURCE_IO,
},
{
- .name = "spi_cs",
- .start = 35,
- .end = 35,
- .flags = IORESOURCE_IO,
- },
- {
.name = "spi_miso",
.start = 34,
.end = 34,
@@ -994,6 +960,12 @@
.end = 33,
.flags = IORESOURCE_IO,
},
+ {
+ .name = "spi_cs",
+ .start = 35,
+ .end = 35,
+ .flags = IORESOURCE_IO,
+ },
};
/* Use GSBI1 QUP for SPI-0 */
@@ -2150,10 +2122,11 @@
#ifdef CONFIG_MSM_BUS_SCALING
.vidc_bus_client_pdata = &vidc_bus_client_data,
#endif
- .memtype = MEMTYPE_SMI_KERNEL,
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ .memtype = ION_HEAP_SMI_ID,
.enable_ion = 1,
#else
+ .memtype = MEMTYPE_SMI_KERNEL,
.enable_ion = 0,
#endif
};
diff --git a/arch/arm/mach-msm/devices-msm8x60.h b/arch/arm/mach-msm/devices-msm8x60.h
index 1d5dee1..a2f6a1f 100644
--- a/arch/arm/mach-msm/devices-msm8x60.h
+++ b/arch/arm/mach-msm/devices-msm8x60.h
@@ -58,7 +58,7 @@
extern struct platform_device msm_device_vidc;
extern struct platform_device msm_charm_modem;
-
+extern struct platform_device msm_device_tz_log;
#ifdef CONFIG_HW_RANDOM_MSM
extern struct platform_device msm_device_rng;
#endif
diff --git a/arch/arm/mach-msm/devices-qsd8x50.c b/arch/arm/mach-msm/devices-qsd8x50.c
index 2367719..05efcdf 100644
--- a/arch/arm/mach-msm/devices-qsd8x50.c
+++ b/arch/arm/mach-msm/devices-qsd8x50.c
@@ -32,7 +32,6 @@
#include <asm/mach/mmc.h>
#include <mach/msm_hsusb.h>
#include <mach/usbdiag.h>
-#include <mach/usb_gadget_fserial.h>
#include <mach/rpc_hsusb.h>
static struct resource resources_uart1[] = {
@@ -911,26 +910,17 @@
};
static struct kgsl_device_platform_data kgsl_3d0_pdata = {
- .pwr_data = {
- .pwrlevel = {
- {
- .gpu_freq = 0,
- .bus_freq = 128000000,
- },
- },
- .init_level = 0,
- .num_levels = 1,
- .set_grp_async = NULL,
- .idle_timeout = HZ/5,
- },
- .clk = {
- .name = {
- .clk = "core_clk",
+ .pwrlevel = {
+ {
+ .gpu_freq = 0,
+ .bus_freq = 128000000,
},
},
- .imem_clk_name = {
- .clk = "mem_clk",
- },
+ .init_level = 0,
+ .num_levels = 1,
+ .set_grp_async = NULL,
+ .idle_timeout = HZ/5,
+ .clk_map = KGSL_CLK_CORE | KGSL_CLK_MEM,
};
struct platform_device msm_kgsl_3d0 = {
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index b5cadd3..1ba63c9 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -79,6 +79,8 @@
extern struct platform_device msm9615_device_qup_spi_gsbi3;
extern struct platform_device msm9615_device_ssbi_pmic1;
extern struct platform_device msm9615_device_tsens;
+extern struct platform_device msm_bus_9615_sys_fabric;
+extern struct platform_device msm_bus_def_fab;
extern struct platform_device msm_device_sdc1;
extern struct platform_device msm_device_sdc2;
@@ -136,6 +138,7 @@
extern struct platform_device msm_device_tsif[2];
extern struct platform_device msm_device_ssbi_pmic1;
+extern struct platform_device msm_device_ssbi_pmic2;
extern struct platform_device msm_device_ssbi1;
extern struct platform_device msm_device_ssbi2;
extern struct platform_device msm_device_ssbi3;
@@ -168,6 +171,11 @@
extern struct platform_device msm_cpudai_afe_02_rx;
extern struct platform_device msm_cpudai_afe_02_tx;
extern struct platform_device msm_pcm_afe;
+extern struct platform_device msm_compr_dsp;
+
+extern struct platform_device msm_8960_q6_lpass;
+extern struct platform_device msm_8960_q6_mss_fw;
+extern struct platform_device msm_8960_q6_mss_sw;
extern struct platform_device *msm_footswitch_devices[];
extern unsigned msm_num_footswitch_devices;
@@ -196,10 +204,10 @@
extern struct platform_device led_pdev;
-extern struct platform_device ion_dev;
extern struct platform_device msm_rpm_device;
extern struct platform_device msm_rpm_stat_device;
extern struct platform_device msm_device_rng;
+extern struct platform_device apq8064_device_rng;
#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
diff --git a/arch/arm/mach-msm/footswitch-8x60.c b/arch/arm/mach-msm/footswitch-8x60.c
index 98447fa..5006419 100644
--- a/arch/arm/mach-msm/footswitch-8x60.c
+++ b/arch/arm/mach-msm/footswitch-8x60.c
@@ -151,21 +151,21 @@
/* Make sure required clocks are on at the correct rates. */
rc = setup_clocks(fs);
if (rc)
- goto out;
+ return rc;
/* Un-halt all bus ports in the power domain. */
if (fs->bus_port1) {
rc = msm_bus_axi_portunhalt(fs->bus_port1);
if (rc) {
pr_err("%s: Port 1 unhalt failed.\n", __func__);
- goto out;
+ goto err;
}
}
if (fs->bus_port2) {
rc = msm_bus_axi_portunhalt(fs->bus_port2);
if (rc) {
pr_err("%s: Port 2 unhalt failed.\n", __func__);
- goto out;
+ goto err_port2_halt;
}
}
@@ -209,7 +209,12 @@
restore_clocks(fs);
fs->is_enabled = true;
-out:
+ return 0;
+
+err_port2_halt:
+ msm_bus_axi_porthalt(fs->bus_port1);
+err:
+ restore_clocks(fs);
return rc;
}
@@ -226,14 +231,14 @@
/* Make sure required clocks are on at the correct rates. */
rc = setup_clocks(fs);
if (rc)
- goto out;
+ return rc;
/* Halt all bus ports in the power domain. */
if (fs->bus_port1) {
rc = msm_bus_axi_porthalt(fs->bus_port1);
if (rc) {
pr_err("%s: Port 1 halt failed.\n", __func__);
- goto out;
+ goto err;
}
}
if (fs->bus_port2) {
@@ -256,6 +261,14 @@
udelay(RESET_DELAY_US);
/*
+ * Return clocks to their state before this function. For robustness
+ * if memory-retention across collapses is required, clocks should
+ * be disabled before asserting the clamps. Assuming clocks were off
+ * before entering footswitch_disable(), this will be true.
+ */
+ restore_clocks(fs);
+
+ /*
* Clamp the I/O ports of the core to ensure the values
* remain fixed while the core is collapsed.
*/
@@ -266,16 +279,13 @@
regval &= ~ENABLE_BIT;
writel_relaxed(regval, fs->gfs_ctl_reg);
- /* Return clocks to their state before this function. */
- restore_clocks(fs);
-
fs->is_enabled = false;
-
- return rc;
+ return 0;
err_port2_halt:
msm_bus_axi_portunhalt(fs->bus_port1);
-out:
+err:
+ restore_clocks(fs);
return rc;
}
@@ -296,14 +306,14 @@
/* Make sure required clocks are on at the correct rates. */
rc = setup_clocks(fs);
if (rc)
- goto out;
+ return rc;
/* Un-halt all bus ports in the power domain. */
if (fs->bus_port1) {
rc = msm_bus_axi_portunhalt(fs->bus_port1);
if (rc) {
pr_err("%s: Port 1 unhalt failed.\n", __func__);
- goto out;
+ goto err;
}
}
@@ -346,7 +356,10 @@
restore_clocks(fs);
fs->is_enabled = true;
-out:
+ return 0;
+
+err:
+ restore_clocks(fs);
return rc;
}
@@ -363,14 +376,14 @@
/* Make sure required clocks are on at the correct rates. */
rc = setup_clocks(fs);
if (rc)
- goto out;
+ return rc;
/* Halt all bus ports in the power domain. */
if (fs->bus_port1) {
rc = msm_bus_axi_porthalt(fs->bus_port1);
if (rc) {
pr_err("%s: Port 1 halt failed.\n", __func__);
- goto out;
+ goto err;
}
}
@@ -406,8 +419,10 @@
restore_clocks(fs);
fs->is_enabled = false;
+ return 0;
-out:
+err:
+ restore_clocks(fs);
return rc;
}
diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c
index 5a31f70..e8aa38e 100644
--- a/arch/arm/mach-msm/hotplug.c
+++ b/arch/arm/mach-msm/hotplug.c
@@ -12,6 +12,7 @@
#include <asm/cacheflush.h>
+#ifdef CONFIG_SMP
extern volatile int pen_release;
static inline void cpu_enter_lowpower(void)
@@ -55,6 +56,7 @@
pr_debug("CPU%u: spurious wakeup call\n", cpu);
}
}
+#endif
int platform_cpu_kill(unsigned int cpu)
{
@@ -68,6 +70,7 @@
*/
void platform_cpu_die(unsigned int cpu)
{
+#ifdef CONFIG_SMP
/*
* we're ready for shutdown now, so do it
*/
@@ -79,6 +82,7 @@
* coherency, and then restore interrupts
*/
cpu_leave_lowpower();
+#endif
}
int platform_cpu_disable(unsigned int cpu)
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
index aab93f4..40e13fa 100644
--- a/arch/arm/mach-msm/idle-v7.S
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -93,6 +93,7 @@
ldr r0, [r0]
mov r1, #0
mcr p15, 2, r1, c0, c0, 0 /*CCSELR*/
+ isb
mrc p15, 1, r1, c0, c0, 0 /*CCSIDR*/
mov r2, #1
and r1, r2, r1, ASR #30 /* Check if the cache is write back */
@@ -115,7 +116,8 @@
#ifdef CONFIG_ARCH_MSM_KRAIT
ldr r0, =SCM_SVC_BOOT
ldr r1, =SCM_CMD_TERMINATE_PC
- ldr r2, =0
+ ldr r2, =msm_pm_flush_l2_flag
+ ldr r2, [r2]
bl scm_call_atomic1
#else
wfi
diff --git a/arch/arm/mach-msm/include/mach/bam_dmux.h b/arch/arm/mach-msm/include/mach/bam_dmux.h
index a2b0126..fb70da4 100644
--- a/arch/arm/mach-msm/include/mach/bam_dmux.h
+++ b/arch/arm/mach-msm/include/mach/bam_dmux.h
@@ -59,6 +59,10 @@
int msm_bam_dmux_write(uint32_t id, struct sk_buff *skb);
void msm_bam_dmux_kickoff_ul_wakeup(void);
+
+int msm_bam_dmux_is_ch_full(uint32_t id);
+
+int msm_bam_dmux_is_ch_low(uint32_t id);
#else
int msm_bam_dmux_open(uint32_t id, void *priv,
void (*notify)(void *priv, int event_type,
@@ -80,5 +84,15 @@
void msm_bam_dmux_kickoff_ul_wakeup(void)
{
}
+
+int msm_bam_dmux_is_ch_full(uint32_t id)
+{
+ return -ENODEV;
+}
+
+int msm_bam_dmux_is_ch_low(uint32_t id)
+{
+ return -ENODEV;
+}
#endif
#endif /* _BAM_DMUX_H */
diff --git a/arch/arm/mach-msm/include/mach/barriers.h b/arch/arm/mach-msm/include/mach/barriers.h
index 919186b..2d4792c 100644
--- a/arch/arm/mach-msm/include/mach/barriers.h
+++ b/arch/arm/mach-msm/include/mach/barriers.h
@@ -10,6 +10,8 @@
* GNU General Public License for more details.
*
*/
+#include <mach/memory.h>
+
#define mb() do \
{ \
dsb();\
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index 1745f26..b41398e 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -635,7 +635,6 @@
void msm_camio_clk_rate_set(int rate);
int msm_camio_vfe_clk_rate_set(int rate);
void msm_camio_clk_rate_set_2(struct clk *clk, int rate);
-void msm_camio_clk_set_min_rate(struct clk *clk, int rate);
void msm_camio_clk_axi_rate_set(int rate);
void msm_disable_io_gpio_clk(struct platform_device *);
diff --git a/arch/arm/mach-msm/include/mach/clk.h b/arch/arm/mach-msm/include/mach/clk.h
index e8d3842..8c0ebfa 100644
--- a/arch/arm/mach-msm/include/mach/clk.h
+++ b/arch/arm/mach-msm/include/mach/clk.h
@@ -25,9 +25,6 @@
struct clk;
-/* Rate is minimum clock rate in Hz */
-int clk_set_min_rate(struct clk *clk, unsigned long rate);
-
/* Rate is maximum clock rate in Hz */
int clk_set_max_rate(struct clk *clk, unsigned long rate);
diff --git a/arch/arm/mach-msm/include/mach/debug-macro.S b/arch/arm/mach-msm/include/mach/debug-macro.S
index 5112888..deeb883 100644
--- a/arch/arm/mach-msm/include/mach/debug-macro.S
+++ b/arch/arm/mach-msm/include/mach/debug-macro.S
@@ -18,6 +18,7 @@
#include <mach/hardware.h>
#include <mach/msm_iomap.h>
+#include <mach/msm_serial_hsl_regs.h>
#ifdef MSM_DEBUG_UART_PHYS
.macro addruart, rp, rv
@@ -26,17 +27,17 @@
.endm
.macro senduart,rd,rx
-#ifdef CONFIG_SERIAL_MSM_HSL
+#ifdef CONFIG_MSM_HAS_DEBUG_UART_HS
@ Clear TX_READY by writing to the UARTDM_CR register
mov r12, #0x300
- str r12, [\rx, #0x10]
+ str r12, [\rx, #UARTDM_CR_OFFSET]
@ Write 0x1 to NCF register
mov r12, #0x1
- str r12, [\rx, #0x40]
+ str r12, [\rx, #UARTDM_NCF_TX_OFFSET]
@ UARTDM reg. Read to induce delay
- ldr r12, [\rx, #0x08]
+ ldr r12, [\rx, #UARTDM_SR_OFFSET]
@ Write the 1 character to UARTDM_TF
- str \rd, [\rx, #0x70]
+ str \rd, [\rx, #UARTDM_TF_OFFSET]
#else
teq \rx, #0
strne \rd, [\rx, #0x0C]
@@ -44,13 +45,13 @@
.endm
.macro waituart,rd,rx
-#ifdef CONFIG_SERIAL_MSM_HSL
+#ifdef CONFIG_MSM_HAS_DEBUG_UART_HS
@ check for TX_EMT in UARTDM_SR
- ldr \rd, [\rx, #0x08]
+ ldr \rd, [\rx, #UARTDM_SR_OFFSET]
tst \rd, #0x08
bne 1002f
@ wait for TXREADY in UARTDM_ISR
-1001: ldreq \rd, [\rx, #0x14]
+1001: ldreq \rd, [\rx, #UARTDM_ISR_OFFSET]
tst \rd, #0x80
dsb
beq 1001b
diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h
index 1474fcb..3cb79b7 100644
--- a/arch/arm/mach-msm/include/mach/dma.h
+++ b/arch/arm/mach-msm/include/mach/dma.h
@@ -245,6 +245,13 @@
#define DMOV_HSUART2_RX_CRCI 15
#endif
+/* channels for APQ8064 */
+#define DMOV8064_CE_IN_CHAN 2
+#define DMOV8064_CE_IN_CRCI 14
+
+#define DMOV8064_CE_OUT_CHAN 3
+#define DMOV8064_CE_OUT_CRCI 15
+
/* no client rate control ifc (eg, ram) */
#define DMOV_NONE_CRCI 0
diff --git a/arch/arm/mach-msm/include/mach/irqs-copper.h b/arch/arm/mach-msm/include/mach/irqs-copper.h
index d019047..24da0a4 100644
--- a/arch/arm/mach-msm/include/mach/irqs-copper.h
+++ b/arch/arm/mach-msm/include/mach/irqs-copper.h
@@ -24,9 +24,6 @@
#define GIC_PPI_START 16
#define GIC_SPI_START 32
-#define INT_VGIC (GIC_PPI_START + 0)
-#define INT_DEBUG_TIMER_EXP (GIC_PPI_START + 1)
-#define INT_GP_TIMER_EXP (GIC_PPI_START + 2)
#define AVS_SVICINT (GIC_PPI_START + 6)
#define AVS_SVICINTSWDONE (GIC_PPI_START + 7)
#define INT_ARMQC_PERFMON (GIC_PPI_START + 10)
diff --git a/include/linux/platform_data/usb_rmnet.h b/arch/arm/mach-msm/include/mach/mdm2.h
similarity index 76%
rename from include/linux/platform_data/usb_rmnet.h
rename to arch/arm/mach-msm/include/mach/mdm2.h
index 68c0db7..acfa38a 100644
--- a/include/linux/platform_data/usb_rmnet.h
+++ b/arch/arm/mach-msm/include/mach/mdm2.h
@@ -10,14 +10,12 @@
* GNU General Public License for more details.
*/
+#ifndef _ARCH_ARM_MACH_MSM_MDM2_H
+#define _ARCH_ARM_MACH_MSM_MDM2_H
-#ifndef __LINUX_USB_GADGET_RMNET_H__
-#define __LINUX_USB_GADGET_RMNET_H__
-
-#include <linux/platform_device.h>
-
-struct usb_rmnet_pdata {
- unsigned num_instances;
+struct mdm_platform_data {
+ char *mdm_version;
};
#endif
+
diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h
index f208d88..9cd73db 100644
--- a/arch/arm/mach-msm/include/mach/memory.h
+++ b/arch/arm/mach-msm/include/mach/memory.h
@@ -21,7 +21,7 @@
#define PLAT_PHYS_OFFSET UL(CONFIG_PHYS_OFFSET)
#define MAX_PHYSMEM_BITS 32
-#define SECTION_SIZE_BITS 29
+#define SECTION_SIZE_BITS 28
/* Maximum number of Memory Regions */
#define MAX_NR_REGIONS 4
@@ -58,8 +58,6 @@
#endif
-#define HAS_ARCH_IO_REMAP_PFN_RANGE
-
#ifndef __ASSEMBLY__
void *alloc_bootmem_aligned(unsigned long size, unsigned long alignment);
void *allocate_contiguous_ebi(unsigned long, unsigned long, int);
diff --git a/arch/arm/mach-msm/include/mach/msm_bus_board.h b/arch/arm/mach-msm/include/mach/msm_bus_board.h
index b0d69c7..ddbf959 100644
--- a/arch/arm/mach-msm/include/mach/msm_bus_board.h
+++ b/arch/arm/mach-msm/include/mach/msm_bus_board.h
@@ -92,6 +92,7 @@
#define NODE_ID(id) ((id) & (FABRIC_ID_KEY - 1))
#define IS_SLAVE(id) ((NODE_ID(id)) >= SLAVE_ID_KEY ? 1 : 0)
+#define CHECK_ID(iid, id) (((iid & id) != id) ? -ENXIO : iid)
/*
* The following macros are used to format the data for port halt
diff --git a/arch/arm/mach-msm/include/mach/msm_hdmi_audio.h b/arch/arm/mach-msm/include/mach/msm_hdmi_audio.h
index 3965a75..562a305 100644
--- a/arch/arm/mach-msm/include/mach/msm_hdmi_audio.h
+++ b/arch/arm/mach-msm/include/mach/msm_hdmi_audio.h
@@ -13,7 +13,19 @@
#ifndef __MSM_HDMI_AUDIO_H
#define __MSM_HDMI_AUDIO_H
+enum hdmi_supported_sample_rates {
+ HDMI_SAMPLE_RATE_32KHZ,
+ HDMI_SAMPLE_RATE_44_1KHZ,
+ HDMI_SAMPLE_RATE_48KHZ,
+ HDMI_SAMPLE_RATE_88_2KHZ,
+ HDMI_SAMPLE_RATE_96KHZ,
+ HDMI_SAMPLE_RATE_176_4KHZ,
+ HDMI_SAMPLE_RATE_192KHZ
+};
+
int hdmi_audio_enable(bool on , u32 fifo_water_mark);
int hdmi_audio_packet_enable(bool on);
+void hdmi_msm_audio_sample_rate_reset(int rate);
+int hdmi_msm_audio_get_sample_rate(void);
#endif /* __MSM_HDMI_AUDIO_H*/
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-copper.h b/arch/arm/mach-msm/include/mach/msm_iomap-copper.h
index 3999982..a3c9da8 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-copper.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-copper.h
@@ -29,13 +29,12 @@
#define COPPER_QGIC_CPU_PHYS 0xF9002000
#define COPPER_QGIC_CPU_SIZE SZ_4K
-#define COPPER_TLMM_PHYS 0xFC4A0000
+#define COPPER_TLMM_PHYS 0xFD400000
#define COPPER_TLMM_SIZE SZ_16K
-#define COPPER_TMR_PHYS 0xF900A000
-#define COPPER_TMR_SIZE SZ_4K
-
-#define COPPER_TMR0_PHYS 0xF908A000
-#define COPPER_TMR0_SIZE SZ_4K
+#ifdef CONFIG_DEBUG_MSMCOPPER_UART
+#define MSM_DEBUG_UART_BASE IOMEM(0xFA71E000)
+#define MSM_DEBUG_UART_PHYS 0xF991E000
+#endif
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_serial_hsl_regs.h b/arch/arm/mach-msm/include/mach/msm_serial_hsl_regs.h
new file mode 100644
index 0000000..b465b56
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_serial_hsl_regs.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. 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
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARCH_MSM_SERIAL_HSL_REGS_H
+#define __ASM_ARCH_MSM_SERIAL_HSL_REGS_H
+
+#ifdef CONFIG_MSM_HAS_DEBUG_UART_HS_V14
+#define UARTDM_MR2_OFFSET 0x4
+#define UARTDM_CSR_OFFSET 0xa0
+#define UARTDM_SR_OFFSET 0xa4
+#define UARTDM_CR_OFFSET 0xa8
+#define UARTDM_ISR_OFFSET 0xb4
+#define UARTDM_NCF_TX_OFFSET 0x40
+#define UARTDM_TF_OFFSET 0x100
+#else
+#define UARTDM_MR2_OFFSET 0x4
+#define UARTDM_CSR_OFFSET 0x8
+#define UARTDM_SR_OFFSET 0x8
+#define UARTDM_CR_OFFSET 0x10
+#define UARTDM_ISR_OFFSET 0x14
+#define UARTDM_NCF_TX_OFFSET 0x40
+#define UARTDM_TF_OFFSET 0x70
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index 0c2cd4b..6d45b7d 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -209,7 +209,13 @@
SMEM_SMEM_LOG_MPROC_WRAP,
SMEM_BOOT_INFO_FOR_APPS,
SMEM_SMSM_SIZE_INFO,
- SMEM_MEM_LAST = SMEM_SMSM_SIZE_INFO,
+ SMEM_SMD_LOOPBACK_REGISTER,
+ SMEM_SSR_REASON_MSS0,
+ SMEM_SSR_REASON_WCNSS0,
+ SMEM_SSR_REASON_LPASS0,
+ SMEM_SSR_REASON_DSPS0,
+ SMEM_SSR_REASON_VCODEC0,
+ SMEM_MEM_LAST = SMEM_SSR_REASON_VCODEC0,
SMEM_NUM_ITEMS,
};
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/q6voice.h b/arch/arm/mach-msm/include/mach/qdsp6v2/q6voice.h
index 1f8ce68..674cfe8 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/q6voice.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/q6voice.h
@@ -521,6 +521,8 @@
#define VSS_NETWORK_ID_VOIP_WV 0x00011242
/* Media types */
+#define VSS_MEDIA_ID_13K_MODEM 0x00010FC1
+/* Qcelp vocoder modem format */
#define VSS_MEDIA_ID_EVRC_MODEM 0x00010FC2
/* 80-VF690-47 CDMA enhanced variable rate vocoder modem format. */
#define VSS_MEDIA_ID_4GV_NB_MODEM 0x00010FC3
@@ -531,6 +533,12 @@
/* 80-VF690-47 UMTS AMR-NB vocoder modem format. */
#define VSS_MEDIA_ID_AMR_WB_MODEM 0x00010FC7
/* 80-VF690-47 UMTS AMR-WB vocoder modem format. */
+#define VSS_MEDIA_ID_EFR_MODEM 0x00010FC8
+/*EFR modem format */
+#define VSS_MEDIA_ID_FR_MODEM 0x00010FC9
+/*FR modem format */
+#define VSS_MEDIA_ID_HR_MODEM 0x00010FCA
+/*HR modem format */
#define VSS_MEDIA_ID_PCM_NB 0x00010FCB
/* Linear PCM (16-bit, little-endian). */
#define VSS_MEDIA_ID_PCM_WB 0x00010FCC
diff --git a/arch/arm/mach-msm/include/mach/sdio_tty.h b/arch/arm/mach-msm/include/mach/sdio_tty.h
deleted file mode 100644
index 86746b3..0000000
--- a/arch/arm/mach-msm/include/mach/sdio_tty.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * 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.
- */
-
-/*
- * SDIO TTY interface.
- */
-
-#ifndef __SDIO_TTY__
-#define __SDIO_TTY__
-
-/**
- * sdio_tty_init_tty - Initialize the SDIO TTY driver.
- *
- * @tty_name: tty name - identify the tty device.
- * @sdio_ch_name: channel name - identify the channel.
- * @return sdio_tty handle on success, NULL on error.
- *
- */
-void *sdio_tty_init_tty(char *tty_name, char* sdio_ch_name);
-
-/**
- * sdio_tty_uninit_tty - Uninitialize the SDIO TTY driver.
- *
- * @sdio_tty_handle: sdio_tty handle.
- * @return 0 on success, negative value on error.
- */
-int sdio_tty_uninit_tty(void *sdio_tty_handle);
-
-/**
- * sdio_tty_enable_debug_msg - Enable/Disable sdio_tty debug
- * messages.
- *
- * @enable: A flag to indicate if to enable or disable the debug
- * messages.
- * @return 0 on success, negative value on error.
- */
-void sdio_tty_enable_debug_msg(void *sdio_tty_handle, int enable);
-
-#endif /* __SDIO_TTY__ */
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index fba6efe2..a06b9ae 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -61,6 +61,7 @@
MSM_CPU_7X27AA,
MSM_CPU_9615,
MSM_CPU_COPPER,
+ MSM_CPU_8627,
};
enum msm_cpu socinfo_get_msm_cpu(void);
@@ -225,7 +226,18 @@
static inline int cpu_is_msm8930(void)
{
#ifdef CONFIG_ARCH_MSM8930
- return read_msm_cpu_type() == MSM_CPU_8930;
+ return (read_msm_cpu_type() == MSM_CPU_8930) ||
+ (read_msm_cpu_type() == MSM_CPU_8627);
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_msm8627(void)
+{
+/* 8930 and 8627 will share the same CONFIG_ARCH type unless otherwise needed */
+#ifdef CONFIG_ARCH_MSM8930
+ return read_msm_cpu_type() == MSM_CPU_8627;
#else
return 0;
#endif
diff --git a/arch/arm/mach-msm/include/mach/uncompress.h b/arch/arm/mach-msm/include/mach/uncompress.h
index 74cbda1..7560dc2 100644
--- a/arch/arm/mach-msm/include/mach/uncompress.h
+++ b/arch/arm/mach-msm/include/mach/uncompress.h
@@ -21,6 +21,7 @@
#include <asm/processor.h>
#include <mach/msm_iomap.h>
+#include <mach/msm_serial_hsl_regs.h>
#ifndef CONFIG_DEBUG_ICEDCC
static void putc(int c)
@@ -28,18 +29,18 @@
#if defined(MSM_DEBUG_UART_PHYS)
unsigned long base = MSM_DEBUG_UART_PHYS;
-#ifdef CONFIG_SERIAL_MSM_HSL
+#ifdef CONFIG_MSM_HAS_DEBUG_UART_HS
/*
* Wait for TX_READY to be set; but skip it if we have a
* TX underrun.
*/
- if (__raw_readl(base + 0x08) & 0x08)
- while (!(__raw_readl(base + 0x14) & 0x80))
+ if (!(__raw_readl(base + UARTDM_SR_OFFSET) & 0x08))
+ while (!(__raw_readl(base + UARTDM_ISR_OFFSET) & 0x80))
cpu_relax();
- __raw_writel(0x300, base + 0x10);
- __raw_writel(0x1, base + 0x40);
- __raw_writel(c, base + 0x70);
+ __raw_writel(0x300, base + UARTDM_CR_OFFSET);
+ __raw_writel(0x1, base + UARTDM_NCF_TX_OFFSET);
+ __raw_writel(c, base + UARTDM_TF_OFFSET);
#else
/* Wait for TX_READY to be set */
while (!(__raw_readl(base + 0x08) & 0x04))
diff --git a/arch/arm/mach-msm/include/mach/usb_bridge.h b/arch/arm/mach-msm/include/mach/usb_bridge.h
new file mode 100644
index 0000000..2b7e754
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/usb_bridge.h
@@ -0,0 +1,122 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 __LINUX_USB_BRIDGE_H__
+#define __LINUX_USB_BRIDGE_H__
+
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+
+/* bridge device 0: DUN
+ * bridge device 1 : Tethered RMNET
+ */
+#define MAX_BRIDGE_DEVICES 2
+
+/*PID 9001*/
+#define DUN_IFACE_NUM 2
+#define TETHERED_RMNET_IFACE_NUM 3
+
+struct bridge_ops {
+ int (*send_pkt)(void *, void *, size_t actual);
+ void (*send_cbits)(void *, unsigned int);
+
+ /* flow control */
+ void (*unthrottle_tx)(void *);
+};
+
+#define TX_THROTTLED BIT(0)
+#define RX_THROTTLED BIT(1)
+
+struct bridge {
+ /* context of the gadget port using bridge driver */
+ void *ctx;
+
+ /* bridge device array index mapped to the gadget port array index.
+ * data bridge[ch_id] <-- bridge --> gadget port[ch_id]
+ */
+ unsigned int ch_id;
+
+ /* flow control bits */
+ unsigned long flags;
+
+ /* data/ctrl bridge callbacks */
+ struct bridge_ops ops;
+};
+
+#if defined(CONFIG_USB_QCOM_MDM_BRIDGE) || \
+ defined(CONFIG_USB_QCOM_MDM_BRIDGE_MODULE)
+
+/* Bridge APIs called by gadget driver */
+int ctrl_bridge_open(struct bridge *);
+void ctrl_bridge_close(unsigned int);
+int ctrl_bridge_write(unsigned int, char *, size_t);
+int ctrl_bridge_set_cbits(unsigned int, unsigned int);
+unsigned int ctrl_bridge_get_cbits_tohost(unsigned int);
+int data_bridge_open(struct bridge *brdg);
+void data_bridge_close(unsigned int);
+int data_bridge_write(unsigned int , struct sk_buff *);
+int data_bridge_unthrottle_rx(unsigned int);
+
+/* defined in control bridge */
+int ctrl_bridge_probe(struct usb_interface *, struct usb_host_endpoint *, int);
+void ctrl_bridge_disconnect(unsigned int);
+int ctrl_bridge_resume(unsigned int);
+int ctrl_bridge_suspend(unsigned int);
+
+#else
+
+static inline int __maybe_unused ctrl_bridge_open(struct bridge *brdg)
+{
+ return -ENODEV;
+}
+
+static inline void __maybe_unused ctrl_bridge_close(unsigned int id) { }
+
+static inline int __maybe_unused ctrl_bridge_write(unsigned int id,
+ char *data, size_t size)
+{
+ return -ENODEV;
+}
+
+static inline int __maybe_unused ctrl_bridge_set_cbits(unsigned int id,
+ unsigned int cbits)
+{
+ return -ENODEV;
+}
+
+static inline unsigned int __maybe_unused
+ctrl_bridge_get_cbits_tohost(unsigned int id)
+{
+ return -ENODEV;
+}
+
+static inline int __maybe_unused data_bridge_open(struct bridge *brdg)
+{
+ return -ENODEV;
+}
+
+static inline void __maybe_unused data_bridge_close(unsigned int id) { }
+
+static inline int __maybe_unused data_bridge_write(unsigned int id,
+ struct sk_buff *skb)
+{
+ return -ENODEV;
+}
+
+static inline int __maybe_unused data_bridge_unthrottle_rx(unsigned int id)
+{
+ return -ENODEV;
+}
+
+#endif
+#endif
diff --git a/arch/arm/mach-msm/include/mach/usb_dun_bridge.h b/arch/arm/mach-msm/include/mach/usb_dun_bridge.h
deleted file mode 100644
index b4a8eef..0000000
--- a/arch/arm/mach-msm/include/mach/usb_dun_bridge.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * 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 __USB_DUN_BRIDGE_H
-#define __USB_DUN_BRIDGE_H
-
-/**
- * struct dun_bridge_ops - context and callbacks for DUN bridge
- *
- * @ctxt: caller private context
- * @read_complete: called when read is completed. buf and len correspond
- * to original passed-in values. actual length of buffer returned, or
- * negative error value.
- * @write_complete: called when write is completed. buf and len correspond
- * to original passed-in values. actual length of buffer returned, or
- * negative error value.
- * @ctrl_status: asynchronous notification of control status. ctrl_bits
- * is a bitfield of CDC ACM control status bits.
- */
-struct dun_bridge_ops {
- void *ctxt;
- void (*read_complete)(void *ctxt, char *buf, size_t len, size_t actual);
- void (*write_complete)(void *ctxt, char *buf,
- size_t len, size_t actual);
- void (*ctrl_status)(void *ctxt, unsigned int ctrl_bits);
-};
-
-#ifdef CONFIG_USB_QCOM_DUN_BRIDGE
-
-/**
- * dun_bridge_open - Open the DUN bridge
- *
- * @ops: pointer to ops struct containing private context and callback
- * pointers
- */
-int dun_bridge_open(struct dun_bridge_ops *ops);
-
-/**
- * dun_bridge_close - Closes the DUN bridge
- */
-int dun_bridge_close(void);
-
-/**
- * dun_bridge_read - Request to read data from the DUN bridge. This call is
- * asynchronous: user's read callback (ops->read_complete) will be called
- * when data is returned.
- *
- * @data: pointer to caller-allocated buffer to fill in
- * @len: size of the buffer
- */
-int dun_bridge_read(void *data, int len);
-
-/**
- * dun_bridge_write - Request to write data to the DUN bridge. This call is
- * asynchronous: user's write callback (ops->write_complete) will be called
- * upon completion of the write indicating status and number of bytes
- * written.
- *
- * @data: pointer to caller-allocated buffer to write
- * @len: length of the data in buffer
- */
-int dun_bridge_write(void *data, int len);
-
-/**
- * dun_bridge_send_ctrl_bits - Request to write line control data to the DUN
- * bridge. This call is asynchronous, however no callback will be issued
- * upon completion.
- *
- * @ctrl_bits: CDC ACM line control bits
- */
-int dun_bridge_send_ctrl_bits(unsigned ctrl_bits);
-
-#else
-
-#include <linux/errno.h>
-
-static int __maybe_unused dun_bridge_open(struct dun_bridge_ops *ops)
-{
- return -ENODEV;
-}
-
-static int __maybe_unused dun_bridge_close(void)
-{
- return -ENODEV;
-}
-
-static int __maybe_unused dun_bridge_read(void *data, int len)
-{
- return -ENODEV;
-}
-
-static int __maybe_unused dun_bridge_write(void *data, int len)
-{
- return -ENODEV;
-}
-
-static int __maybe_unused dun_bridge_send_ctrl_bits(unsigned ctrl_bits)
-{
- return -ENODEV;
-}
-
-#endif
-
-#endif
diff --git a/arch/arm/mach-msm/include/mach/usb_gadget_xport.h b/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
new file mode 100644
index 0000000..54566dc
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
@@ -0,0 +1,84 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 __LINUX_USB_GADGET_XPORT_H__
+#define __LINUX_USB_GADGET_XPORT_H__
+
+enum transport_type {
+ USB_GADGET_XPORT_UNDEF,
+ USB_GADGET_XPORT_TTY,
+ USB_GADGET_XPORT_SDIO,
+ USB_GADGET_XPORT_SMD,
+ USB_GADGET_XPORT_BAM,
+ USB_GADGET_XPORT_HSIC,
+ USB_GADGET_XPORT_NONE,
+};
+
+#define XPORT_STR_LEN 10
+
+static char *xport_to_str(enum transport_type t)
+{
+ switch (t) {
+ case USB_GADGET_XPORT_TTY:
+ return "TTY";
+ case USB_GADGET_XPORT_SDIO:
+ return "SDIO";
+ case USB_GADGET_XPORT_SMD:
+ return "SMD";
+ case USB_GADGET_XPORT_BAM:
+ return "BAM";
+ case USB_GADGET_XPORT_HSIC:
+ return "HSIC";
+ case USB_GADGET_XPORT_NONE:
+ return "NONE";
+ default:
+ return "UNDEFINED";
+ }
+}
+
+static enum transport_type str_to_xport(const char *name)
+{
+ if (!strncasecmp("TTY", name, XPORT_STR_LEN))
+ return USB_GADGET_XPORT_TTY;
+ if (!strncasecmp("SDIO", name, XPORT_STR_LEN))
+ return USB_GADGET_XPORT_SDIO;
+ if (!strncasecmp("SMD", name, XPORT_STR_LEN))
+ return USB_GADGET_XPORT_SMD;
+ if (!strncasecmp("BAM", name, XPORT_STR_LEN))
+ return USB_GADGET_XPORT_BAM;
+ if (!strncasecmp("HSIC", name, XPORT_STR_LEN))
+ return USB_GADGET_XPORT_HSIC;
+ if (!strncasecmp("", name, XPORT_STR_LEN))
+ return USB_GADGET_XPORT_NONE;
+
+ return USB_GADGET_XPORT_UNDEF;
+}
+
+enum gadget_type {
+ USB_GADGET_SERIAL,
+ USB_GADGET_RMNET,
+};
+
+#define NUM_RMNET_HSIC_PORTS 1
+#define NUM_DUN_HSIC_PORTS 1
+#define NUM_PORTS (NUM_RMNET_HSIC_PORTS \
+ + NUM_DUN_HSIC_PORTS)
+
+int ghsic_ctrl_connect(void *, int);
+void ghsic_ctrl_disconnect(void *, int);
+int ghsic_ctrl_setup(unsigned int, enum gadget_type);
+int ghsic_data_connect(void *, int);
+void ghsic_data_disconnect(void *, int);
+int ghsic_data_setup(unsigned int, enum gadget_type);
+
+#endif
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 8a79af7..2d5b0a4 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -284,8 +284,9 @@
MSM_CHIP_DEVICE(QGIC_DIST, COPPER),
MSM_CHIP_DEVICE(QGIC_CPU, COPPER),
MSM_CHIP_DEVICE(TLMM, COPPER),
- MSM_CHIP_DEVICE(TMR, COPPER),
- MSM_CHIP_DEVICE(TMR0, COPPER),
+#ifdef CONFIG_DEBUG_MSMCOPPER_UART
+ MSM_DEVICE(DEBUG_UART),
+#endif
};
void __init msm_map_copper_io(void)
diff --git a/arch/arm/mach-msm/iommu_dev.c b/arch/arm/mach-msm/iommu_dev.c
index d1dd3ed..1982082 100644
--- a/arch/arm/mach-msm/iommu_dev.c
+++ b/arch/arm/mach-msm/iommu_dev.c
@@ -24,7 +24,6 @@
#include <mach/iommu_hw-8xxx.h>
#include <mach/iommu.h>
-#include <mach/clk.h>
struct iommu_ctx_iter_data {
/* input */
@@ -164,8 +163,10 @@
iommu_clk = clk_get(&pdev->dev, "core_clk");
if (!IS_ERR(iommu_clk)) {
- if (clk_get_rate(iommu_clk) == 0)
- clk_set_min_rate(iommu_clk, 1);
+ if (clk_get_rate(iommu_clk) == 0) {
+ ret = clk_round_rate(iommu_clk, 1);
+ clk_set_rate(iommu_clk, ret);
+ }
ret = clk_enable(iommu_clk);
if (ret) {
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 3d34a30..8e9cc0f 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -1938,7 +1938,6 @@
}
mutex_unlock(&port_ptr->port_rx_q_lock);
- wake_lock_destroy(&port_ptr->port_rx_wake_lock);
if (port_ptr->type == SERVER_PORT) {
server = msm_ipc_router_lookup_server(
port_ptr->port_name.service,
@@ -1962,6 +1961,7 @@
mutex_unlock(&control_ports_lock);
}
+ wake_lock_destroy(&port_ptr->port_rx_wake_lock);
kfree(port_ptr);
return 0;
}
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
new file mode 100644
index 0000000..0737a81
--- /dev/null
+++ b/arch/arm/mach-msm/mdm2.c
@@ -0,0 +1,176 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <linux/debugfs.h>
+#include <linux/completion.h>
+#include <linux/workqueue.h>
+#include <linux/clk.h>
+#include <linux/mfd/pmic8058.h>
+#include <asm/mach-types.h>
+#include <asm/uaccess.h>
+#include <mach/mdm2.h>
+#include <mach/restart.h>
+#include <mach/subsystem_notif.h>
+#include <mach/subsystem_restart.h>
+#include <linux/msm_charm.h>
+#include "msm_watchdog.h"
+#include "devices.h"
+#include "clock.h"
+#include "mdm_private.h"
+
+#define MDM_MODEM_TIMEOUT 6000
+#define MDM_HOLD_TIME 4000
+#define MDM_MODEM_DELTA 100
+#define IFLINE_UP 1
+#define IFLINE_DOWN 0
+
+static int mdm_debug_on;
+static int ifline_status = IFLINE_UP;
+static struct mdm_callbacks mdm_cb;
+
+#define MDM_DBG(...) do { if (mdm_debug_on) \
+ pr_info(__VA_ARGS__); \
+ } while (0);
+
+static void power_on_mdm(struct mdm_modem_drv *mdm_drv)
+{
+ /* Remove hsic driver before powering on the modem. */
+ if (ifline_status == IFLINE_UP) {
+ MDM_DBG("%s: Removing hsic device\n", __func__);
+ platform_device_del(&msm_device_hsic_host);
+ ifline_status = IFLINE_DOWN;
+ }
+
+ /* Pull both ERR_FATAL and RESET low */
+ MDM_DBG("Pulling PWR and RESET gpio's low\n");
+ gpio_direction_output(mdm_drv->ap2mdm_pmic_reset_n_gpio, 0);
+ gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 0);
+ /* Wait for them to settle. */
+ usleep(1000);
+
+ /* Deassert RESET first and wait for ir to settle. */
+ MDM_DBG("%s: Pulling RESET gpio high\n", __func__);
+ gpio_direction_output(mdm_drv->ap2mdm_pmic_reset_n_gpio, 1);
+ usleep(1000);
+
+ /* Pull PWR gpio high and wait for it to settle. */
+ MDM_DBG("%s: Powering on mdm modem\n", __func__);
+ gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 1);
+ usleep(1000);
+
+ /* Add back hsic device after modem power up */
+ MDM_DBG("%s: Adding hsic device\n", __func__);
+ platform_device_add(&msm_device_hsic_host);
+ ifline_status = IFLINE_UP;
+
+ msleep(200);
+}
+
+static void power_down_mdm(struct mdm_modem_drv *mdm_drv)
+{
+ int i;
+
+ for (i = MDM_MODEM_TIMEOUT; i > 0; i -= MDM_MODEM_DELTA) {
+ pet_watchdog();
+ msleep(MDM_MODEM_DELTA);
+ if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
+ break;
+ }
+
+ if (i <= 0) {
+ pr_err("%s: MDM2AP_STATUS never went low.\n",
+ __func__);
+ gpio_direction_output(mdm_drv->ap2mdm_pmic_reset_n_gpio, 0);
+
+ for (i = MDM_HOLD_TIME; i > 0; i -= MDM_MODEM_DELTA) {
+ pet_watchdog();
+ msleep(MDM_MODEM_DELTA);
+ }
+ }
+ /* Also remove the hsic device on 9k power down. */
+ MDM_DBG("%s: Removing hsic device\n", __func__);
+ if (ifline_status == IFLINE_UP) {
+ platform_device_del(&msm_device_hsic_host);
+ ifline_status = IFLINE_DOWN;
+ }
+}
+
+static void normal_boot_done(struct mdm_modem_drv *mdm_drv)
+{
+}
+
+static void debug_state_changed(int value)
+{
+ mdm_debug_on = value;
+}
+
+static int __init mdm_modem_probe(struct platform_device *pdev)
+{
+ /* Instantiate driver object. */
+ mdm_cb.power_on_mdm_cb = power_on_mdm;
+ mdm_cb.power_down_mdm_cb = power_down_mdm;
+ mdm_cb.normal_boot_done_cb = normal_boot_done;
+ mdm_cb.debug_state_changed_cb = debug_state_changed;
+ return mdm_common_create(pdev, &mdm_cb);
+}
+
+static int __devexit mdm_modem_remove(struct platform_device *pdev)
+{
+ return mdm_common_modem_remove(pdev);
+}
+
+static void mdm_modem_shutdown(struct platform_device *pdev)
+{
+ mdm_common_modem_shutdown(pdev);
+}
+
+static struct platform_driver mdm_modem_driver = {
+ .remove = mdm_modem_remove,
+ .shutdown = mdm_modem_shutdown,
+ .driver = {
+ .name = "mdm2_modem",
+ .owner = THIS_MODULE
+ },
+};
+
+static int __init mdm_modem_init(void)
+{
+ return platform_driver_probe(&mdm_modem_driver, mdm_modem_probe);
+}
+
+static void __exit mdm_modem_exit(void)
+{
+ platform_driver_unregister(&mdm_modem_driver);
+}
+
+module_init(mdm_modem_init);
+module_exit(mdm_modem_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("mdm modem driver");
+MODULE_VERSION("2.0");
+MODULE_ALIAS("mdm_modem");
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
new file mode 100644
index 0000000..1262ce3
--- /dev/null
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -0,0 +1,505 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <linux/debugfs.h>
+#include <linux/completion.h>
+#include <linux/workqueue.h>
+#include <linux/clk.h>
+#include <linux/mfd/pmic8058.h>
+#include <asm/mach-types.h>
+#include <asm/uaccess.h>
+#include <mach/mdm2.h>
+#include <mach/restart.h>
+#include <mach/subsystem_notif.h>
+#include <mach/subsystem_restart.h>
+#include <linux/msm_charm.h>
+#include "msm_watchdog.h"
+#include "mdm_private.h"
+
+#define MDM_MODEM_TIMEOUT 6000
+#define MDM_MODEM_DELTA 100
+
+static int mdm_debug_on;
+static struct workqueue_struct *mdm_queue;
+
+#define EXTERNAL_MODEM "external_modem"
+
+#define MDM_DBG(...) do { if (mdm_debug_on) \
+ pr_info(__VA_ARGS__); \
+ } while (0);
+
+static struct mdm_modem_drv *mdm_drv;
+
+DECLARE_COMPLETION(mdm_needs_reload);
+DECLARE_COMPLETION(mdm_boot);
+DECLARE_COMPLETION(mdm_ram_dumps);
+
+static int first_boot = 1;
+
+long mdm_modem_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ int status, ret = 0;
+
+ if (_IOC_TYPE(cmd) != CHARM_CODE) {
+ pr_err("%s: invalid ioctl code\n", __func__);
+ return -EINVAL;
+ }
+
+ MDM_DBG("%s: Entering ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
+ switch (cmd) {
+ case WAKE_CHARM:
+ MDM_DBG("%s: Powering on\n", __func__);
+ mdm_drv->power_on_mdm_cb(mdm_drv);
+ break;
+ case CHECK_FOR_BOOT:
+ if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
+ put_user(1, (unsigned long __user *) arg);
+ else
+ put_user(0, (unsigned long __user *) arg);
+ break;
+ case NORMAL_BOOT_DONE:
+ MDM_DBG("%s: check if mdm is booted up\n", __func__);
+ get_user(status, (unsigned long __user *) arg);
+ if (status)
+ mdm_drv->mdm_boot_status = -EIO;
+ else
+ mdm_drv->mdm_boot_status = 0;
+ mdm_drv->mdm_ready = 1;
+
+ if (mdm_drv->normal_boot_done_cb != NULL)
+ mdm_drv->normal_boot_done_cb(mdm_drv);
+
+ if (!first_boot)
+ complete(&mdm_boot);
+ else
+ first_boot = 0;
+ break;
+ case RAM_DUMP_DONE:
+ MDM_DBG("%s: mdm done collecting RAM dumps\n", __func__);
+ get_user(status, (unsigned long __user *) arg);
+ if (status)
+ mdm_drv->mdm_ram_dump_status = -EIO;
+ else
+ mdm_drv->mdm_ram_dump_status = 0;
+ complete(&mdm_ram_dumps);
+ break;
+ case WAIT_FOR_RESTART:
+ MDM_DBG("%s: wait for mdm to need images reloaded\n",
+ __func__);
+ ret = wait_for_completion_interruptible(&mdm_needs_reload);
+ if (!ret)
+ put_user(mdm_drv->boot_type,
+ (unsigned long __user *) arg);
+ INIT_COMPLETION(mdm_needs_reload);
+ break;
+ default:
+ pr_err("%s: invalid ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static void mdm_fatal_fn(struct work_struct *work)
+{
+ MDM_DBG("%s: Reseting the mdm due to an errfatal\n", __func__);
+ subsystem_restart(EXTERNAL_MODEM);
+}
+
+static DECLARE_WORK(mdm_fatal_work, mdm_fatal_fn);
+
+static void mdm_status_fn(struct work_struct *work)
+{
+ MDM_DBG("%s: Reseting the mdm because status changed\n", __func__);
+ subsystem_restart(EXTERNAL_MODEM);
+}
+
+static DECLARE_WORK(mdm_status_work, mdm_status_fn);
+
+static void mdm_disable_irqs(void)
+{
+ disable_irq_nosync(mdm_drv->mdm_errfatal_irq);
+ disable_irq_nosync(mdm_drv->mdm_status_irq);
+
+}
+
+static irqreturn_t mdm_errfatal(int irq, void *dev_id)
+{
+ MDM_DBG("%s: mdm got errfatal interrupt\n", __func__);
+ if (mdm_drv->mdm_ready &&
+ (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 1)) {
+ MDM_DBG("%s: scheduling work now\n", __func__);
+ queue_work(mdm_queue, &mdm_fatal_work);
+ }
+ return IRQ_HANDLED;
+}
+
+static int mdm_modem_open(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static const struct file_operations mdm_modem_fops = {
+ .owner = THIS_MODULE,
+ .open = mdm_modem_open,
+ .unlocked_ioctl = mdm_modem_ioctl,
+};
+
+
+static struct miscdevice mdm_modem_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "mdm",
+ .fops = &mdm_modem_fops
+};
+
+static int mdm_panic_prep(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ int i;
+
+ MDM_DBG("%s: setting AP2MDM_ERRFATAL high for a non graceful reset\n",
+ __func__);
+ mdm_disable_irqs();
+ gpio_set_value(mdm_drv->ap2mdm_errfatal_gpio, 1);
+
+ if (mdm_drv->ap2mdm_wakeup_gpio > 0)
+ gpio_set_value(mdm_drv->ap2mdm_wakeup_gpio, 1);
+
+ for (i = MDM_MODEM_TIMEOUT; i > 0; i -= MDM_MODEM_DELTA) {
+ pet_watchdog();
+ mdelay(MDM_MODEM_DELTA);
+ if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
+ break;
+ }
+ if (i <= 0)
+ pr_err("%s: MDM2AP_STATUS never went low\n", __func__);
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block mdm_panic_blk = {
+ .notifier_call = mdm_panic_prep,
+};
+
+static irqreturn_t mdm_status_change(int irq, void *dev_id)
+{
+ MDM_DBG("%s: mdm sent status change interrupt\n", __func__);
+ if ((gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
+ && mdm_drv->mdm_ready) {
+ MDM_DBG("%s: scheduling work now\n", __func__);
+ queue_work(mdm_queue, &mdm_status_work);
+ } else if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 1) {
+ MDM_DBG("%s: mdm is now ready\n", __func__);
+ }
+ return IRQ_HANDLED;
+}
+
+static int mdm_subsys_shutdown(const struct subsys_data *crashed_subsys)
+{
+ mdm_drv->mdm_ready = 0;
+ gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 1);
+ mdm_drv->power_down_mdm_cb(mdm_drv);
+ return 0;
+}
+
+static int mdm_subsys_powerup(const struct subsys_data *crashed_subsys)
+{
+ mdm_drv->power_on_mdm_cb(mdm_drv);
+ mdm_drv->boot_type = CHARM_NORMAL_BOOT;
+ complete(&mdm_needs_reload);
+ wait_for_completion(&mdm_boot);
+ pr_info("%s: mdm modem has been restarted\n", __func__);
+ INIT_COMPLETION(mdm_boot);
+ return mdm_drv->mdm_boot_status;
+}
+
+static int mdm_subsys_ramdumps(int want_dumps,
+ const struct subsys_data *crashed_subsys)
+{
+ mdm_drv->mdm_ram_dump_status = 0;
+ if (want_dumps) {
+ mdm_drv->boot_type = CHARM_RAM_DUMPS;
+ complete(&mdm_needs_reload);
+ wait_for_completion(&mdm_ram_dumps);
+ INIT_COMPLETION(mdm_ram_dumps);
+ gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 1);
+ mdm_drv->power_down_mdm_cb(mdm_drv);
+ }
+ return mdm_drv->mdm_ram_dump_status;
+}
+
+static struct subsys_data mdm_subsystem = {
+ .shutdown = mdm_subsys_shutdown,
+ .ramdump = mdm_subsys_ramdumps,
+ .powerup = mdm_subsys_powerup,
+ .name = EXTERNAL_MODEM,
+};
+
+static int mdm_debug_on_set(void *data, u64 val)
+{
+ mdm_debug_on = val;
+ if (mdm_drv->debug_state_changed_cb)
+ mdm_drv->debug_state_changed_cb(mdm_debug_on);
+ return 0;
+}
+
+static int mdm_debug_on_get(void *data, u64 *val)
+{
+ *val = mdm_debug_on;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(mdm_debug_on_fops,
+ mdm_debug_on_get,
+ mdm_debug_on_set, "%llu\n");
+
+static int mdm_debugfs_init(void)
+{
+ struct dentry *dent;
+
+ dent = debugfs_create_dir("mdm_dbg", 0);
+ if (IS_ERR(dent))
+ return PTR_ERR(dent);
+
+ debugfs_create_file("debug_on", 0644, dent, NULL,
+ &mdm_debug_on_fops);
+ return 0;
+}
+
+static void mdm_modem_initialize_data(struct platform_device *pdev,
+ struct mdm_callbacks *p_mdm_cb)
+{
+ struct resource *pres;
+
+ /* MDM2AP_ERRFATAL */
+ pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
+ "MDM2AP_ERRFATAL");
+ if (pres)
+ mdm_drv->mdm2ap_errfatal_gpio = pres->start;
+
+ /* AP2MDM_ERRFATAL */
+ pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
+ "AP2MDM_ERRFATAL");
+ if (pres)
+ mdm_drv->ap2mdm_errfatal_gpio = pres->start;
+
+ /* MDM2AP_STATUS */
+ pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
+ "MDM2AP_STATUS");
+ if (pres)
+ mdm_drv->mdm2ap_status_gpio = pres->start;
+
+ /* AP2MDM_STATUS */
+ pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
+ "AP2MDM_STATUS");
+ if (pres)
+ mdm_drv->ap2mdm_status_gpio = pres->start;
+
+ /* MDM2AP_WAKEUP */
+ pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
+ "MDM2AP_WAKEUP");
+ if (pres)
+ mdm_drv->mdm2ap_wakeup_gpio = pres->start;
+
+ /* AP2MDM_WAKEUP */
+ pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
+ "AP2MDM_WAKEUP");
+ if (pres)
+ mdm_drv->ap2mdm_wakeup_gpio = pres->start;
+
+ /* AP2MDM_PMIC_RESET_N */
+ pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
+ "AP2MDM_PMIC_RESET_N");
+ if (pres)
+ mdm_drv->ap2mdm_pmic_reset_n_gpio = pres->start;
+
+ /* AP2MDM_KPDPWR_N */
+ pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
+ "AP2MDM_KPDPWR_N");
+ if (pres)
+ mdm_drv->ap2mdm_kpdpwr_n_gpio = pres->start;
+
+ mdm_drv->boot_type = CHARM_NORMAL_BOOT;
+
+ mdm_drv->power_on_mdm_cb = p_mdm_cb->power_on_mdm_cb;
+ mdm_drv->power_down_mdm_cb = p_mdm_cb->power_down_mdm_cb;
+ mdm_drv->normal_boot_done_cb = p_mdm_cb->normal_boot_done_cb;
+ mdm_drv->debug_state_changed_cb = p_mdm_cb->debug_state_changed_cb;
+}
+
+int mdm_common_create(struct platform_device *pdev,
+ struct mdm_callbacks *p_mdm_cb)
+{
+ int ret = -1, irq;
+
+ mdm_drv = kzalloc(sizeof(struct mdm_modem_drv), GFP_KERNEL);
+ if (mdm_drv == NULL) {
+ pr_err("%s: kzalloc fail.\n", __func__);
+ goto alloc_err;
+ }
+
+ mdm_modem_initialize_data(pdev, p_mdm_cb);
+ if (mdm_drv->debug_state_changed_cb)
+ mdm_drv->debug_state_changed_cb(mdm_debug_on);
+
+ gpio_request(mdm_drv->ap2mdm_status_gpio, "AP2MDM_STATUS");
+ gpio_request(mdm_drv->ap2mdm_errfatal_gpio, "AP2MDM_ERRFATAL");
+ gpio_request(mdm_drv->ap2mdm_kpdpwr_n_gpio, "AP2MDM_KPDPWR_N");
+ gpio_request(mdm_drv->ap2mdm_pmic_reset_n_gpio, "AP2MDM_PMIC_RESET_N");
+ gpio_request(mdm_drv->mdm2ap_status_gpio, "MDM2AP_STATUS");
+ gpio_request(mdm_drv->mdm2ap_errfatal_gpio, "MDM2AP_ERRFATAL");
+
+ if (mdm_drv->ap2mdm_wakeup_gpio > 0)
+ gpio_request(mdm_drv->ap2mdm_wakeup_gpio, "AP2MDM_WAKEUP");
+
+ gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
+ gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 0);
+
+ if (mdm_drv->ap2mdm_wakeup_gpio > 0)
+ gpio_direction_output(mdm_drv->ap2mdm_wakeup_gpio, 0);
+
+ gpio_direction_input(mdm_drv->mdm2ap_status_gpio);
+ gpio_direction_input(mdm_drv->mdm2ap_errfatal_gpio);
+
+ mdm_queue = create_singlethread_workqueue("mdm_queue");
+ if (!mdm_queue) {
+ pr_err("%s: could not create workqueue. All mdm "
+ "functionality will be disabled\n",
+ __func__);
+ ret = -ENOMEM;
+ goto fatal_err;
+ }
+
+ atomic_notifier_chain_register(&panic_notifier_list, &mdm_panic_blk);
+ mdm_debugfs_init();
+
+ /* Register subsystem handlers */
+ ssr_register_subsystem(&mdm_subsystem);
+
+ /* ERR_FATAL irq. */
+ irq = MSM_GPIO_TO_INT(mdm_drv->mdm2ap_errfatal_gpio);
+ if (irq < 0) {
+ pr_err("%s: could not get MDM2AP_ERRFATAL IRQ resource. "
+ "error=%d No IRQ will be generated on errfatal.",
+ __func__, irq);
+ goto errfatal_err;
+ }
+ ret = request_irq(irq, mdm_errfatal,
+ IRQF_TRIGGER_RISING , "mdm errfatal", NULL);
+
+ if (ret < 0) {
+ pr_err("%s: MDM2AP_ERRFATAL IRQ#%d request failed with error=%d"
+ ". No IRQ will be generated on errfatal.",
+ __func__, irq, ret);
+ goto errfatal_err;
+ }
+ mdm_drv->mdm_errfatal_irq = irq;
+
+errfatal_err:
+
+ /* status irq */
+ irq = MSM_GPIO_TO_INT(mdm_drv->mdm2ap_status_gpio);
+ if (irq < 0) {
+ pr_err("%s: could not get MDM2AP_STATUS IRQ resource. "
+ "error=%d No IRQ will be generated on status change.",
+ __func__, irq);
+ goto status_err;
+ }
+
+ ret = request_threaded_irq(irq, NULL, mdm_status_change,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "mdm status", NULL);
+
+ if (ret < 0) {
+ pr_err("%s: MDM2AP_STATUS IRQ#%d request failed with error=%d"
+ ". No IRQ will be generated on status change.",
+ __func__, irq, ret);
+ goto status_err;
+ }
+ mdm_drv->mdm_status_irq = irq;
+
+status_err:
+ pr_info("%s: Registering mdm modem\n", __func__);
+ return misc_register(&mdm_modem_misc);
+
+fatal_err:
+ gpio_free(mdm_drv->ap2mdm_status_gpio);
+ gpio_free(mdm_drv->ap2mdm_errfatal_gpio);
+ gpio_free(mdm_drv->ap2mdm_kpdpwr_n_gpio);
+ gpio_free(mdm_drv->ap2mdm_pmic_reset_n_gpio);
+ gpio_free(mdm_drv->mdm2ap_status_gpio);
+ gpio_free(mdm_drv->mdm2ap_errfatal_gpio);
+
+ if (mdm_drv->ap2mdm_wakeup_gpio > 0)
+ gpio_free(mdm_drv->ap2mdm_wakeup_gpio);
+
+ kfree(mdm_drv);
+ ret = -ENODEV;
+
+alloc_err:
+ return ret;
+}
+
+int mdm_common_modem_remove(struct platform_device *pdev)
+{
+ int ret;
+
+ gpio_free(mdm_drv->ap2mdm_status_gpio);
+ gpio_free(mdm_drv->ap2mdm_errfatal_gpio);
+ gpio_free(mdm_drv->ap2mdm_kpdpwr_n_gpio);
+ gpio_free(mdm_drv->ap2mdm_pmic_reset_n_gpio);
+ gpio_free(mdm_drv->mdm2ap_status_gpio);
+ gpio_free(mdm_drv->mdm2ap_errfatal_gpio);
+
+ if (mdm_drv->ap2mdm_wakeup_gpio > 0)
+ gpio_free(mdm_drv->ap2mdm_wakeup_gpio);
+
+ kfree(mdm_drv);
+
+ ret = misc_deregister(&mdm_modem_misc);
+ return ret;
+}
+
+void mdm_common_modem_shutdown(struct platform_device *pdev)
+{
+ MDM_DBG("%s: setting AP2MDM_STATUS low for a graceful restart\n",
+ __func__);
+
+ mdm_disable_irqs();
+
+ gpio_set_value(mdm_drv->ap2mdm_status_gpio, 0);
+
+ if (mdm_drv->ap2mdm_wakeup_gpio > 0)
+ gpio_set_value(mdm_drv->ap2mdm_wakeup_gpio, 1);
+
+ mdm_drv->power_down_mdm_cb(mdm_drv);
+
+ if (mdm_drv->ap2mdm_wakeup_gpio > 0)
+ gpio_set_value(mdm_drv->ap2mdm_wakeup_gpio, 0);
+}
+
diff --git a/arch/arm/mach-msm/mdm_private.h b/arch/arm/mach-msm/mdm_private.h
new file mode 100644
index 0000000..701eb7a
--- /dev/null
+++ b/arch/arm/mach-msm/mdm_private.h
@@ -0,0 +1,57 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _ARCH_ARM_MACH_MSM_MDM_PRIVATE_H
+#define _ARCH_ARM_MACH_MSM_MDM_PRIVATE_H
+
+struct mdm_modem_drv;
+
+/* Private mdm2 data structure */
+struct mdm_modem_drv {
+ unsigned mdm2ap_errfatal_gpio;
+ unsigned ap2mdm_errfatal_gpio;
+ unsigned mdm2ap_status_gpio;
+ unsigned ap2mdm_status_gpio;
+ unsigned mdm2ap_wakeup_gpio;
+ unsigned ap2mdm_wakeup_gpio;
+ unsigned ap2mdm_pmic_reset_n_gpio;
+ unsigned ap2mdm_kpdpwr_n_gpio;
+
+ int mdm_errfatal_irq;
+ int mdm_status_irq;
+ int mdm_ready;
+ int mdm_boot_status;
+ int mdm_ram_dump_status;
+ enum charm_boot_type boot_type;
+ int mdm_debug_on;
+
+ void (*power_on_mdm_cb)(struct mdm_modem_drv *mdm_drv);
+ void (*normal_boot_done_cb)(struct mdm_modem_drv *mdm_drv);
+ void (*power_down_mdm_cb)(struct mdm_modem_drv *mdm_drv);
+ void (*debug_state_changed_cb)(int value);
+};
+
+struct mdm_callbacks {
+ void (*power_on_mdm_cb)(struct mdm_modem_drv *mdm_drv);
+ void (*normal_boot_done_cb)(struct mdm_modem_drv *mdm_drv);
+ void (*power_down_mdm_cb)(struct mdm_modem_drv *mdm_drv);
+ void (*debug_state_changed_cb)(int value);
+};
+
+int mdm_common_create(struct platform_device *pdev,
+ struct mdm_callbacks *mdm_cb);
+int mdm_common_modem_remove(struct platform_device *pdev);
+void mdm_common_modem_shutdown(struct platform_device *pdev);
+void mdm_common_set_debug_state(int value);
+
+#endif
+
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index 00f315d..31fbd43 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -38,17 +38,6 @@
#include <mach/socinfo.h>
#include <../../mm/mm.h>
-int arch_io_remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
- unsigned long pfn, unsigned long size, pgprot_t prot)
-{
- unsigned long pfn_addr = pfn << PAGE_SHIFT;
- if ((pfn_addr >= 0x88000000) && (pfn_addr < 0xD0000000)) {
- prot = pgprot_device(prot);
- pr_debug("remapping device %lx\n", prot);
- }
- return remap_pfn_range(vma, addr, pfn, size, prot);
-}
-
void *strongly_ordered_page;
char strongly_ordered_mem[PAGE_SIZE*2-4];
diff --git a/arch/arm/mach-msm/memory_topology.c b/arch/arm/mach-msm/memory_topology.c
index b9d9d3b..7a75bc1 100644
--- a/arch/arm/mach-msm/memory_topology.c
+++ b/arch/arm/mach-msm/memory_topology.c
@@ -14,8 +14,11 @@
#include <asm/setup.h>
#include <asm/errno.h>
#include <asm/sizes.h>
+#include <asm/pgtable.h>
#include <linux/mutex.h>
+#include <linux/memory.h>
#include <mach/msm_memtypes.h>
+#include <mach/socinfo.h>
#include "smd_private.h"
#if defined(CONFIG_ARCH_MSM8960)
@@ -40,6 +43,14 @@
STATE_DEFAULT = STATE_ACTIVE
};
+enum {
+ MEM_NO_CHANGE = 0x0,
+ MEM_DEEP_POWER_DOWN,
+ MEM_SELF_REFRESH,
+};
+
+static unsigned int dmm_mode;
+
static int default_mask = ~0x0;
/* Return the number of chipselects populated with a memory bank */
@@ -103,27 +114,40 @@
static int switch_memory_state(int id, int new_state)
{
int mask;
- int disable_masks[MAX_NR_REGIONS] = { 0xFFFFFF00, 0xFFFF00FF,
+ int power_down_masks[MAX_NR_REGIONS] = { 0xFFFFFF00, 0xFFFF00FF,
0xFF00FFFF, 0x00FFFFFF };
+ int self_refresh_masks[MAX_NR_REGIONS] = { 0xFFFFFFF0, 0xFFFFFF0F,
+ 0xFFFFF0FF, 0xFFFF0FFF };
mutex_lock(&mem_regions[id].state_mutex);
if (new_state == mem_regions[id].state)
goto no_change;
- if (new_state == STATE_POWER_DOWN)
- mask = mem_regions[id].mask & disable_masks[id];
- else if (new_state == STATE_ACTIVE)
- mask = mem_regions[id].mask | (~disable_masks[id]);
+ pr_info("request memory %d state switch (%d->%d) mode %d\n", id,
+ mem_regions[id].state, new_state, dmm_mode);
+ if (new_state == STATE_POWER_DOWN) {
+ if (dmm_mode == MEM_DEEP_POWER_DOWN)
+ mask = mem_regions[id].mask & power_down_masks[id];
+ else
+ mask = mem_regions[id].mask & self_refresh_masks[id];
+ } else if (new_state == STATE_ACTIVE) {
+ if (dmm_mode == MEM_DEEP_POWER_DOWN)
+ mask = mem_regions[id].mask | (~power_down_masks[id]);
+ else
+ mask = mem_regions[id].mask | (~self_refresh_masks[id]);
+ }
- /* For now we only support Deep Power Down */
- /* So set the active and retention states as the same */
if (rpm_change_memory_state(mask, mask) == 0) {
mem_regions[id].state = new_state;
mem_regions[id].mask = mask;
+ pr_info("completed memory %d state switch to %d mode %d\n",
+ id, new_state, dmm_mode);
mutex_unlock(&mem_regions[id].state_mutex);
return 0;
}
+ pr_err("failed memory %d state switch (%d->%d) mode %d\n", id,
+ mem_regions[id].state, new_state, dmm_mode);
no_change:
mutex_unlock(&mem_regions[id].state_mutex);
return -EINVAL;
@@ -189,7 +213,12 @@
int __init meminfo_init(unsigned int type, unsigned int min_bank_size)
{
unsigned int i;
+ unsigned long bank_size;
+ unsigned long bank_start;
struct smem_ram_ptable *ram_ptable;
+ /* physical memory banks */
+ unsigned int nr_mem_banks = 0;
+ /* logical memory regions for dmm */
nr_mem_regions = 0;
ram_ptable = smem_alloc(SMEM_USABLE_RAM_PARTITION_TABLE,
@@ -200,22 +229,41 @@
return -EINVAL;
}
+ /* Determine power control mode based on the hw version */
+ /* This check will be removed when PASR is fully supported */
+ if (cpu_is_msm8960() &&
+ SOCINFO_VERSION_MAJOR(socinfo_get_version()) < 2)
+ dmm_mode = MEM_DEEP_POWER_DOWN;
+ else
+ dmm_mode = MEM_SELF_REFRESH;
+
pr_info("meminfo_init: smem ram ptable found: ver: %d len: %d\n",
ram_ptable->version, ram_ptable->len);
for (i = 0; i < ram_ptable->len; i++) {
if (ram_ptable->parts[i].type == type &&
ram_ptable->parts[i].size >= min_bank_size) {
- mem_regions[nr_mem_regions].start =
- ram_ptable->parts[i].start;
- mem_regions[nr_mem_regions].size =
- ram_ptable->parts[i].size;
- mutex_init(&mem_regions[nr_mem_regions].state_mutex);
- mem_regions[nr_mem_regions].state = STATE_DEFAULT;
- mem_regions[nr_mem_regions].mask = default_mask;
- nr_mem_regions++;
+ bank_start = ram_ptable->parts[i].start;
+ bank_size = ram_ptable->parts[i].size;
+ /* Divide into logical memory regions of same size */
+ while (bank_size) {
+ mem_regions[nr_mem_regions].start =
+ bank_start;
+ mem_regions[nr_mem_regions].size =
+ MIN_MEMORY_BLOCK_SIZE;
+ mutex_init(&mem_regions[nr_mem_regions]
+ .state_mutex);
+ mem_regions[nr_mem_regions].state =
+ STATE_DEFAULT;
+ mem_regions[nr_mem_regions].mask = default_mask;
+ bank_start += MIN_MEMORY_BLOCK_SIZE;
+ bank_size -= MIN_MEMORY_BLOCK_SIZE;
+ nr_mem_regions++;
+ }
+ nr_mem_banks++;
}
}
- pr_info("Found %d memory banks\n", nr_mem_regions);
+ pr_info("Found %d memory banks grouped into %d memory regions\n",
+ nr_mem_banks, nr_mem_regions);
return 0;
}
diff --git a/arch/arm/mach-msm/modem-8960.c b/arch/arm/mach-msm/modem-8960.c
index f0aa13c..7345a89 100644
--- a/arch/arm/mach-msm/modem-8960.c
+++ b/arch/arm/mach-msm/modem-8960.c
@@ -149,9 +149,58 @@
smsm_reset_modem(SMSM_RESET);
}
-int modem_ramdump(int enable, const struct subsys_data *subsys)
+/* FIXME: Get address, size from PIL */
+static struct ramdump_segment modemsw_segments[] = {
+ {0x89000000, 0x8D400000 - 0x89000000},
+};
+
+static struct ramdump_segment modemfw_segments[] = {
+ {0x8D400000, 0x8DA00000 - 0x8D400000},
+};
+
+static struct ramdump_segment smem_segments[] = {
+ {0x80000000, 0x00200000},
+};
+
+static void *modemfw_ramdump_dev;
+static void *modemsw_ramdump_dev;
+static void *smem_ramdump_dev;
+
+static int modem_ramdump(int enable,
+ const struct subsys_data *crashed_subsys)
{
- return 0;
+ int ret = 0;
+
+ if (enable) {
+ ret = do_ramdump(modemsw_ramdump_dev, modemsw_segments,
+ ARRAY_SIZE(modemsw_segments));
+
+ if (ret < 0) {
+ pr_err("Unable to dump modem sw memory (rc = %d).\n",
+ ret);
+ goto out;
+ }
+
+ ret = do_ramdump(modemfw_ramdump_dev, modemfw_segments,
+ ARRAY_SIZE(modemfw_segments));
+
+ if (ret < 0) {
+ pr_err("Unable to dump modem fw memory (rc = %d).\n",
+ ret);
+ goto out;
+ }
+
+ ret = do_ramdump(smem_ramdump_dev, smem_segments,
+ ARRAY_SIZE(smem_segments));
+
+ if (ret < 0) {
+ pr_err("Unable to dump smem memory (rc = %d).\n", ret);
+ goto out;
+ }
+ }
+
+out:
+ return ret;
}
static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
@@ -263,6 +312,33 @@
goto out;
}
+ modemfw_ramdump_dev = create_ramdump_device("modem_fw");
+
+ if (!modemfw_ramdump_dev) {
+ pr_err("%s: Unable to create modem fw ramdump device. (%d)\n",
+ __func__, -ENOMEM);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ modemsw_ramdump_dev = create_ramdump_device("modem_sw");
+
+ if (!modemsw_ramdump_dev) {
+ pr_err("%s: Unable to create modem sw ramdump device. (%d)\n",
+ __func__, -ENOMEM);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ smem_ramdump_dev = create_ramdump_device("smem");
+
+ if (!smem_ramdump_dev) {
+ pr_err("%s: Unable to create smem ramdump device. (%d)\n",
+ __func__, -ENOMEM);
+ ret = -ENOMEM;
+ goto out;
+ }
+
ret = modem_debugfs_init();
pr_info("%s: modem fatal driver init'ed.\n", __func__);
diff --git a/arch/arm/mach-msm/mpm.c b/arch/arm/mach-msm/mpm.c
index 040e126..70ee39b 100644
--- a/arch/arm/mach-msm/mpm.c
+++ b/arch/arm/mach-msm/mpm.c
@@ -260,6 +260,9 @@
uint32_t index = MSM_MPM_IRQ_INDEX(mpm_irq);
uint32_t mask = MSM_MPM_IRQ_MASK(mpm_irq);
+ if (index >= MSM_MPM_REG_WIDTH)
+ return -EFAULT;
+
if (flow_type & IRQ_TYPE_EDGE_BOTH)
msm_mpm_detect_ctl[index] |= mask;
else
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
index 7b9a16e..8175738 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
@@ -144,6 +144,11 @@
/* Are we there yet? */
if (src == dest) {
info = fabdev->algo->find_node(fabdev, src);
+ if (ZERO_OR_NULL_PTR(info)) {
+ MSM_BUS_ERR("Node %d not found\n", dest);
+ return -ENXIO;
+ }
+
for (i = 0; i <= info->num_pnodes; i++) {
if (info->pnode[i].next == -2) {
MSM_BUS_DBG("src = dst Reusing pnode for"
@@ -161,7 +166,7 @@
next_pnode_id = CREATE_PNODE_ID(src, (info->num_pnodes + 1));
pnode_num = add_path_node(info, next_pnode_id);
if (pnode_num < 0) {
- MSM_BUS_DBG("error adding path node\n");
+ MSM_BUS_ERR("Error adding path node\n");
return -ENXIO;
}
MSM_BUS_DBG("returning: %d, %d\n", GET_NODE(next_pnode_id),
@@ -173,6 +178,11 @@
* from the radix tree
*/
info = fabdev->algo->find_node(fabdev, dest);
+ if (ZERO_OR_NULL_PTR(info)) {
+ MSM_BUS_ERR("Node %d not found\n", dest);
+ return -ENXIO;
+ }
+
ret_pnode = getpath(info->node_info->priv_id, dest);
next_pnode_id = ret_pnode;
} else {
@@ -190,7 +200,7 @@
dest);
pnode_num = add_path_node(info, ret_pnode);
if (pnode_num < 0) {
- MSM_BUS_DBG("Error adding path node\n");
+ MSM_BUS_ERR("Error adding path node\n");
return -ENXIO;
}
next_pnode_id = CREATE_PNODE_ID(
@@ -213,24 +223,20 @@
info = fabnodeinfo->info;
ret_pnode = getpath(info->
node_info->priv_id, dest);
- if (ret_pnode >= 0) {
- pnode_num = add_path_node(info,
- ret_pnode);
- if (pnode_num < 0) {
- MSM_BUS_ERR("Malloc"
- "failure in adding"
- "path node\n");
- return -ENXIO;
- }
- next_pnode_id = CREATE_PNODE_ID(
- info->node_info->priv_id,
- pnode_num);
- break;
+ pnode_num = add_path_node(info,
+ ret_pnode);
+ if (pnode_num < 0) {
+ MSM_BUS_ERR("Malloc failure in"
+ " adding path node\n");
+ return -ENXIO;
}
+ next_pnode_id = CREATE_PNODE_ID(
+ info->node_info->priv_id, pnode_num);
+ break;
}
}
if (next_pnode_id < 0)
- return -EPERM;
+ return -ENXIO;
}
}
@@ -242,8 +248,9 @@
info = fabdev->algo->find_node(fabdev, src);
if (!info) {
MSM_BUS_ERR("Node info not found.\n");
- return -EPERM;
+ return -ENXIO;
}
+
pnode_num = add_path_node(info, next_pnode_id);
MSM_BUS_DBG(" Last: %d[%d] = (%d, %d)\n",
src, info->num_pnodes, GET_NODE(next_pnode_id),
@@ -466,12 +473,24 @@
}
src = msm_bus_board_get_iid(pdata->usecase->vectors[i].src);
+ if (src == -ENXIO) {
+ MSM_BUS_ERR("Master %d not supported. Client cannot be"
+ " registered\n",
+ pdata->usecase->vectors[i].src);
+ goto err;
+ }
dest = msm_bus_board_get_iid(pdata->usecase->vectors[i].dst);
+ if (dest == -ENXIO) {
+ MSM_BUS_ERR("Slave %d not supported. Client cannot be"
+ " registered\n",
+ pdata->usecase->vectors[i].dst);
+ goto err;
+ }
srcfab = msm_bus_get_fabric_device(GET_FABID(src));
srcfab->visited = true;
pnode[i] = getpath(src, dest);
bus_for_each_dev(&msm_bus_type, NULL, NULL, clearvisitedflag);
- if (pnode[i] < 0) {
+ if (pnode[i] == -ENXIO) {
MSM_BUS_ERR("Cannot register client now! Try again!\n");
goto err;
}
@@ -532,6 +551,20 @@
for (i = 0; i < pdata->usecase->num_paths; i++) {
src = msm_bus_board_get_iid(client->pdata->usecase[index].
vectors[i].src);
+ if (src == -ENXIO) {
+ MSM_BUS_ERR("Master %d not supported. Request cannot"
+ " be updated\n", client->pdata->usecase->
+ vectors[i].src);
+ goto err;
+ }
+
+ if (msm_bus_board_get_iid(client->pdata->usecase[index].
+ vectors[i].dst) == -ENXIO) {
+ MSM_BUS_ERR("Slave %d not supported. Request cannot"
+ " be updated\n", client->pdata->usecase->
+ vectors[i].dst);
+ }
+
pnode = client->src_pnode[i];
req_clk = client->pdata->usecase[index].vectors[i].ib;
req_bw = client->pdata->usecase[index].vectors[i].ab;
@@ -584,6 +617,7 @@
MSM_BUS_ERR("Cannot find node info!\n");
return -ENXIO;
}
+
MSM_BUS_DBG("Starting the loop--remove\n");
do {
struct msm_bus_inode_info *hop;
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8660.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8660.c
index d284b70..fc91291 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8660.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8660.c
@@ -826,8 +826,14 @@
static int msm_bus_board_8660_get_iid(int id)
{
- return ((id < SLAVE_ID_KEY) ? master_iids[id] : slave_iids[id -
- SLAVE_ID_KEY]);
+ if ((id < SLAVE_ID_KEY && id >= NMASTERS) ||
+ id >= (SLAVE_ID_KEY + NSLAVES)) {
+ MSM_BUS_ERR("Cannot get iid. Invalid id %d passed\n", id);
+ return -EINVAL;
+ }
+
+ return CHECK_ID(((id < SLAVE_ID_KEY) ? master_iids[id] :
+ slave_iids[id - SLAVE_ID_KEY]), id);
}
static struct msm_bus_board_algorithm msm_bus_board_algo = {
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
index 1dda082..97a3145 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
@@ -859,8 +859,8 @@
return -EINVAL;
}
- return ((id < SLAVE_ID_KEY) ? master_iids[id] : slave_iids[id -
- SLAVE_ID_KEY]);
+ return CHECK_ID(((id < SLAVE_ID_KEY) ? master_iids[id] :
+ slave_iids[id - SLAVE_ID_KEY]), id);
}
static struct msm_bus_board_algorithm msm_bus_board_algo = {
diff --git a/arch/arm/mach-msm/msm_dsps.c b/arch/arm/mach-msm/msm_dsps.c
index bcb777f..5419087 100644
--- a/arch/arm/mach-msm/msm_dsps.c
+++ b/arch/arm/mach-msm/msm_dsps.c
@@ -40,7 +40,7 @@
#include <mach/subsystem_notif.h>
#define DRV_NAME "msm_dsps"
-#define DRV_VERSION "3.00"
+#define DRV_VERSION "3.01"
#define PPSS_PAUSE_REG 0x1804
@@ -655,11 +655,12 @@
if (dsps_state & SMSM_RESET) {
pr_err("%s: DSPS fatal error detected. Resetting\n",
__func__);
+ panic("DSPS fatal error detected.");
} else {
pr_debug("%s: User-initiated DSPS reset. Resetting\n",
__func__);
+ panic("User-initiated DSPS reset.");
}
- subsystem_restart("dsps");
}
@@ -682,7 +683,7 @@
pr_err
("%s: SMSM_RESET state detected. restarting the DSPS\n",
__func__);
- subsystem_restart("dsps");
+ panic("SMSM_RESET state detected.");
}
}
diff --git a/arch/arm/mach-msm/msm_rq_stats.c b/arch/arm/mach-msm/msm_rq_stats.c
index 425000d..da7fb51 100644
--- a/arch/arm/mach-msm/msm_rq_stats.c
+++ b/arch/arm/mach-msm/msm_rq_stats.c
@@ -160,20 +160,20 @@
for (i = 0; i < attr_count - 1 ; i++) {
if (!attribs[i])
- goto rel;
+ goto rel2;
}
rq_info.attr_group = kzalloc(sizeof(struct attribute_group),
GFP_KERNEL);
if (!rq_info.attr_group)
- goto rel;
+ goto rel3;
rq_info.attr_group->attrs = attribs;
/* Create /sys/devices/system/cpu/cpu0/rq-stats/... */
rq_info.kobj = kobject_create_and_add("rq-stats",
&get_cpu_sysdev(0)->kobj);
if (!rq_info.kobj)
- goto rel;
+ goto rel3;
err = sysfs_create_group(rq_info.kobj, rq_info.attr_group);
if (err)
@@ -184,18 +184,22 @@
if (!err)
return err;
-rel:
- for (i = 0; i < attr_count - 1 ; i++)
- kfree(attribs[i]);
- kfree(attribs);
+rel3:
kfree(rq_info.attr_group);
kfree(rq_info.kobj);
+rel2:
+ for (i = 0; i < attr_count - 1; i++)
+ kfree(attribs[i]);
+rel:
+ kfree(attribs);
return -ENOMEM;
}
static int __init msm_rq_stats_init(void)
{
+ int ret;
+
rq_wq = create_singlethread_workqueue("rq_stats");
BUG_ON(!rq_wq);
INIT_WORK(&rq_info.def_timer_work, def_work_fn);
@@ -204,7 +208,9 @@
rq_info.def_timer_jiffies = DEFAULT_DEF_TIMER_JIFFIES;
rq_info.rq_poll_last_jiffy = 0;
rq_info.def_timer_last_jiffy = 0;
+ ret = init_rq_attribs();
+
rq_info.init = 1;
- return init_rq_attribs();
+ return ret;
}
late_initcall(msm_rq_stats_init);
diff --git a/arch/arm/mach-msm/msm_xo.c b/arch/arm/mach-msm/msm_xo.c
index 1e9c05f..29cb1a8 100644
--- a/arch/arm/mach-msm/msm_xo.c
+++ b/arch/arm/mach-msm/msm_xo.c
@@ -223,9 +223,10 @@
/*
* TODO: Remove early return for 8064 once RPM XO voting support
- * is available.
+ * is available. Remove early return for 8960 TCXO_D0 once all
+ * voters for it are in place.
*/
- if (cpu_is_apq8064())
+ if (cpu_is_apq8064() || (cpu_is_msm8960() && xo_id == MSM_XO_TCXO_D0))
return NULL;
if (xo_id >= NUM_MSM_XO_IDS) {
diff --git a/arch/arm/mach-msm/no-pm.c b/arch/arm/mach-msm/no-pm.c
index e34abb1..d6cdbe7 100644
--- a/arch/arm/mach-msm/no-pm.c
+++ b/arch/arm/mach-msm/no-pm.c
@@ -25,16 +25,3 @@
void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns) { }
EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
-
-int platform_cpu_disable(unsigned int cpu)
-{
- return -ENOSYS;
-}
-
-int platform_cpu_kill(unsigned int cpu)
-{
- return -ENOSYS;
-}
-
-void platform_cpu_die(unsigned int cpu)
-{ }
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index 672f332..b16b687 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -220,6 +220,7 @@
dev_err(pil->desc->dev, "Failed to bring out of reset\n");
goto release_fw;
}
+ dev_info(pil->desc->dev, "brought out of reset\n");
release_fw:
release_firmware(fw);
diff --git a/arch/arm/mach-msm/peripheral-reset-8960.c b/arch/arm/mach-msm/peripheral-reset-8960.c
index b964417..fa22e4e 100644
--- a/arch/arm/mach-msm/peripheral-reset-8960.c
+++ b/arch/arm/mach-msm/peripheral-reset-8960.c
@@ -28,49 +28,6 @@
#include "peripheral-loader.h"
#include "scm-pas.h"
-#define MSM_FW_QDSP6SS_PHYS 0x08800000
-#define MSM_SW_QDSP6SS_PHYS 0x08900000
-#define MSM_LPASS_QDSP6SS_PHYS 0x28800000
-#define MSM_MSS_ENABLE_PHYS 0x08B00000
-
-#define QDSP6SS_RST_EVB 0x0
-#define QDSP6SS_RESET 0x04
-#define QDSP6SS_CGC_OVERRIDE 0x18
-#define QDSP6SS_STRAP_TCM 0x1C
-#define QDSP6SS_STRAP_AHB 0x20
-#define QDSP6SS_GFMUX_CTL 0x30
-#define QDSP6SS_PWR_CTL 0x38
-
-#define MSS_S_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2C70)
-#define MSS_SLP_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C60)
-#define SFAB_MSS_M_ACLK_CTL (MSM_CLK_CTL_BASE + 0x2340)
-#define SFAB_MSS_S_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2C00)
-#define SFAB_MSS_Q6_FW_ACLK_CTL (MSM_CLK_CTL_BASE + 0x2044)
-#define SFAB_MSS_Q6_SW_ACLK_CTL (MSM_CLK_CTL_BASE + 0x2040)
-#define SFAB_LPASS_Q6_ACLK_CTL (MSM_CLK_CTL_BASE + 0x23A0)
-#define MSS_Q6FW_JTAG_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C6C)
-#define MSS_Q6SW_JTAG_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C68)
-#define MSS_RESET (MSM_CLK_CTL_BASE + 0x2C64)
-
-#define Q6SS_SS_ARES BIT(0)
-#define Q6SS_CORE_ARES BIT(1)
-#define Q6SS_ISDB_ARES BIT(2)
-#define Q6SS_ETM_ARES BIT(3)
-#define Q6SS_STOP_CORE_ARES BIT(4)
-#define Q6SS_PRIV_ARES BIT(5)
-
-#define Q6SS_L2DATA_SLP_NRET_N BIT(0)
-#define Q6SS_SLP_RET_N BIT(1)
-#define Q6SS_L1TCM_SLP_NRET_N BIT(2)
-#define Q6SS_L2TAG_SLP_NRET_N BIT(3)
-#define Q6SS_ETB_SLEEP_NRET_N BIT(4)
-#define Q6SS_ARR_STBY_N BIT(5)
-#define Q6SS_CLAMP_IO BIT(6)
-
-#define Q6SS_CLK_ENA BIT(1)
-#define Q6SS_SRC_SWITCH_CLK_OVR BIT(8)
-#define Q6SS_AXIS_ACLK_EN BIT(9)
-
#define MSM_RIVA_PHYS 0x03204000
#define RIVA_PMU_A2XB_CFG (msm_riva_base + 0xB8)
#define RIVA_PMU_A2XB_CFG_EN BIT(0)
@@ -121,339 +78,14 @@
#define PPSS_PROC_CLK_CTL (MSM_CLK_CTL_BASE + 0x2588)
#define PPSS_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2580)
-struct q6_data {
- const unsigned strap_tcm_base;
- const unsigned strap_ahb_upper;
- const unsigned strap_ahb_lower;
- const unsigned reg_base_phys;
- void __iomem *reg_base;
- void __iomem *aclk_reg;
- void __iomem *jtag_clk_reg;
- int start_addr;
- struct regulator *vreg;
- bool vreg_enabled;
- const char *name;
-};
-
-static struct q6_data q6_lpass = {
- .strap_tcm_base = (0x146 << 16),
- .strap_ahb_upper = (0x029 << 16),
- .strap_ahb_lower = (0x028 << 4),
- .reg_base_phys = MSM_LPASS_QDSP6SS_PHYS,
- .aclk_reg = SFAB_LPASS_Q6_ACLK_CTL,
- .name = "q6_lpass",
-};
-
-static struct q6_data q6_modem_fw = {
- .strap_tcm_base = (0x40 << 16),
- .strap_ahb_upper = (0x09 << 16),
- .strap_ahb_lower = (0x08 << 4),
- .reg_base_phys = MSM_FW_QDSP6SS_PHYS,
- .aclk_reg = SFAB_MSS_Q6_FW_ACLK_CTL,
- .jtag_clk_reg = MSS_Q6FW_JTAG_CLK_CTL,
- .name = "q6_modem_fw",
-};
-
-static struct q6_data q6_modem_sw = {
- .strap_tcm_base = (0x42 << 16),
- .strap_ahb_upper = (0x09 << 16),
- .strap_ahb_lower = (0x08 << 4),
- .reg_base_phys = MSM_SW_QDSP6SS_PHYS,
- .aclk_reg = SFAB_MSS_Q6_SW_ACLK_CTL,
- .jtag_clk_reg = MSS_Q6SW_JTAG_CLK_CTL,
- .name = "q6_modem_sw",
-};
-
-static void __iomem *mss_enable_reg;
static void __iomem *msm_riva_base;
static unsigned long riva_start;
-static int init_image_lpass_q6_trusted(struct pil_desc *pil,
- const u8 *metadata, size_t size)
-{
- return pas_init_image(PAS_Q6, metadata, size);
-}
-
-static int init_image_modem_fw_q6_trusted(struct pil_desc *pil,
- const u8 *metadata, size_t size)
-{
- return pas_init_image(PAS_MODEM_FW, metadata, size);
-}
-
-static int init_image_modem_sw_q6_trusted(struct pil_desc *pil,
- const u8 *metadata, size_t size)
-{
- return pas_init_image(PAS_MODEM_SW, metadata, size);
-}
-
-static int init_image_lpass_q6_untrusted(struct pil_desc *pil,
- const u8 *metadata, size_t size)
-{
- const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
- q6_lpass.start_addr = ehdr->e_entry;
- return 0;
-}
-
-static int init_image_modem_fw_q6_untrusted(struct pil_desc *pil,
- const u8 *metadata, size_t size)
-{
- const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
- q6_modem_fw.start_addr = ehdr->e_entry;
- return 0;
-}
-
-static int init_image_modem_sw_q6_untrusted(struct pil_desc *pil,
- const u8 *metadata, size_t size)
-{
- const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
- q6_modem_sw.start_addr = ehdr->e_entry;
- return 0;
-}
-
static int verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
{
return 0;
}
-static int power_up_q6(struct q6_data *q6)
-{
- int err;
-
- err = regulator_set_voltage(q6->vreg, 1050000, 1050000);
- if (err) {
- pr_err("Failed to set %s regulator's voltage.\n", q6->name);
- return err;
- }
- err = regulator_set_optimum_mode(q6->vreg, 100000);
- if (err < 0) {
- pr_err("Failed to set %s regulator's mode.\n", q6->name);
- return err;
- }
- err = regulator_enable(q6->vreg);
- if (err) {
- pr_err("Failed to enable %s's regulator.\n", q6->name);
- return err;
- }
- q6->vreg_enabled = true;
- return 0;
-}
-
-static int reset_q6_trusted(int id, struct q6_data *q6)
-{
- int err = power_up_q6(q6);
- if (err)
- return err;
- return pas_auth_and_reset(id);
-}
-
-static int reset_lpass_q6_trusted(struct pil_desc *pil)
-{
- return reset_q6_trusted(PAS_Q6, &q6_lpass);
-}
-
-static int reset_modem_fw_q6_trusted(struct pil_desc *pil)
-{
- return reset_q6_trusted(PAS_MODEM_FW, &q6_modem_fw);
-}
-
-static int reset_modem_sw_q6_trusted(struct pil_desc *pil)
-{
- return reset_q6_trusted(PAS_MODEM_SW, &q6_modem_sw);
-}
-
-static int reset_q6_untrusted(struct q6_data *q6)
-{
- u32 reg, err = 0;
-
- err = power_up_q6(q6);
- if (err)
- return err;
- /* Enable Q6 ACLK */
- writel_relaxed(0x10, q6->aclk_reg);
-
- if (q6 == &q6_modem_fw || q6 == &q6_modem_sw) {
- /* Enable MSS clocks */
- writel_relaxed(0x10, SFAB_MSS_M_ACLK_CTL);
- writel_relaxed(0x10, SFAB_MSS_S_HCLK_CTL);
- writel_relaxed(0x10, MSS_S_HCLK_CTL);
- writel_relaxed(0x10, MSS_SLP_CLK_CTL);
- /* Wait for clocks to enable */
- mb();
- udelay(10);
-
- /* Enable JTAG clocks */
- /* TODO: Remove if/when Q6 software enables them? */
- writel_relaxed(0x10, q6->jtag_clk_reg);
-
- /* De-assert MSS reset */
- writel_relaxed(0x0, MSS_RESET);
- mb();
- udelay(10);
-
- /* Enable MSS */
- writel_relaxed(0x7, mss_enable_reg);
- }
-
- /*
- * Assert AXIS_ACLK_EN override to allow for correct updating of the
- * QDSP6_CORE_STATE status bit. This is mandatory only for the SW Q6
- * in 8960v1 and optional elsewhere.
- */
- reg = readl_relaxed(q6->reg_base + QDSP6SS_CGC_OVERRIDE);
- reg |= Q6SS_AXIS_ACLK_EN;
- writel_relaxed(reg, q6->reg_base + QDSP6SS_CGC_OVERRIDE);
-
- /* Deassert Q6SS_SS_ARES */
- reg = readl_relaxed(q6->reg_base + QDSP6SS_RESET);
- reg &= ~(Q6SS_SS_ARES);
- writel_relaxed(reg, q6->reg_base + QDSP6SS_RESET);
-
- /* Program boot address */
- writel_relaxed((q6->start_addr >> 8) & 0xFFFFFF,
- q6->reg_base + QDSP6SS_RST_EVB);
-
- /* Program TCM and AHB address ranges */
- writel_relaxed(q6->strap_tcm_base, q6->reg_base + QDSP6SS_STRAP_TCM);
- writel_relaxed(q6->strap_ahb_upper | q6->strap_ahb_lower,
- q6->reg_base + QDSP6SS_STRAP_AHB);
-
- /* Turn off Q6 core clock */
- writel_relaxed(Q6SS_SRC_SWITCH_CLK_OVR,
- q6->reg_base + QDSP6SS_GFMUX_CTL);
-
- /* Put memories to sleep */
- writel_relaxed(Q6SS_CLAMP_IO, q6->reg_base + QDSP6SS_PWR_CTL);
-
- /* Assert resets */
- reg = readl_relaxed(q6->reg_base + QDSP6SS_RESET);
- reg |= (Q6SS_CORE_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES
- | Q6SS_STOP_CORE_ARES);
- writel_relaxed(reg, q6->reg_base + QDSP6SS_RESET);
-
- /* Wait 8 AHB cycles for Q6 to be fully reset (AHB = 1.5Mhz) */
- mb();
- usleep_range(20, 30);
-
- /* Turn on Q6 memories */
- reg = Q6SS_L2DATA_SLP_NRET_N | Q6SS_SLP_RET_N | Q6SS_L1TCM_SLP_NRET_N
- | Q6SS_L2TAG_SLP_NRET_N | Q6SS_ETB_SLEEP_NRET_N | Q6SS_ARR_STBY_N
- | Q6SS_CLAMP_IO;
- writel_relaxed(reg, q6->reg_base + QDSP6SS_PWR_CTL);
-
- /* Turn on Q6 core clock */
- reg = Q6SS_CLK_ENA | Q6SS_SRC_SWITCH_CLK_OVR;
- writel_relaxed(reg, q6->reg_base + QDSP6SS_GFMUX_CTL);
-
- /* Remove Q6SS_CLAMP_IO */
- reg = readl_relaxed(q6->reg_base + QDSP6SS_PWR_CTL);
- reg &= ~Q6SS_CLAMP_IO;
- writel_relaxed(reg, q6->reg_base + QDSP6SS_PWR_CTL);
-
- /* Bring Q6 core out of reset and start execution. */
- writel_relaxed(0x0, q6->reg_base + QDSP6SS_RESET);
-
- /*
- * Re-enable auto-gating of AXIS_ACLK at lease one AXI clock cycle
- * after resets are de-asserted.
- */
- mb();
- usleep_range(1, 10);
- reg = readl_relaxed(q6->reg_base + QDSP6SS_CGC_OVERRIDE);
- reg &= ~Q6SS_AXIS_ACLK_EN;
- writel_relaxed(reg, q6->reg_base + QDSP6SS_CGC_OVERRIDE);
-
- return 0;
-}
-
-static int reset_lpass_q6_untrusted(struct pil_desc *pil)
-{
- return reset_q6_untrusted(&q6_lpass);
-}
-
-static int reset_modem_fw_q6_untrusted(struct pil_desc *pil)
-{
- return reset_q6_untrusted(&q6_modem_fw);
-}
-
-static int reset_modem_sw_q6_untrusted(struct pil_desc *pil)
-{
- return reset_q6_untrusted(&q6_modem_sw);
-}
-
-static int shutdown_q6_trusted(int id, struct q6_data *q6)
-{
- int ret;
-
- ret = pas_shutdown(id);
- if (ret)
- return ret;
-
- if (q6->vreg_enabled) {
- regulator_disable(q6->vreg);
- q6->vreg_enabled = false;
- }
-
- return ret;
-}
-
-static int shutdown_lpass_q6_trusted(struct pil_desc *pil)
-{
- return shutdown_q6_trusted(PAS_Q6, &q6_lpass);
-}
-
-static int shutdown_modem_fw_q6_trusted(struct pil_desc *pil)
-{
- return shutdown_q6_trusted(PAS_MODEM_FW, &q6_modem_fw);
-}
-
-static int shutdown_modem_sw_q6_trusted(struct pil_desc *pil)
-{
- return shutdown_q6_trusted(PAS_MODEM_SW, &q6_modem_sw);
-}
-
-static int shutdown_q6_untrusted(struct q6_data *q6)
-{
- u32 reg;
-
- /* Turn off Q6 core clock */
- writel_relaxed(Q6SS_SRC_SWITCH_CLK_OVR,
- q6->reg_base + QDSP6SS_GFMUX_CTL);
-
- /* Assert resets */
- reg = (Q6SS_SS_ARES | Q6SS_CORE_ARES | Q6SS_ISDB_ARES
- | Q6SS_ETM_ARES | Q6SS_STOP_CORE_ARES | Q6SS_PRIV_ARES);
- writel_relaxed(reg, q6->reg_base + QDSP6SS_RESET);
-
- /* Turn off Q6 memories */
- writel_relaxed(Q6SS_CLAMP_IO, q6->reg_base + QDSP6SS_PWR_CTL);
-
- /* Put Modem Subsystem back into reset when shutting down FWQ6 */
- if (q6 == &q6_modem_fw)
- writel_relaxed(0x1, MSS_RESET);
-
- if (q6->vreg_enabled) {
- regulator_disable(q6->vreg);
- q6->vreg_enabled = false;
- }
-
- return 0;
-}
-
-static int shutdown_lpass_q6_untrusted(struct pil_desc *pil)
-{
- return shutdown_q6_untrusted(&q6_lpass);
-}
-
-static int shutdown_modem_fw_q6_untrusted(struct pil_desc *pil)
-{
- return shutdown_q6_untrusted(&q6_modem_fw);
-}
-
-static int shutdown_modem_sw_q6_untrusted(struct pil_desc *pil)
-{
- return shutdown_q6_untrusted(&q6_modem_sw);
-}
-
static int init_image_riva_untrusted(struct pil_desc *pil, const u8 *metadata,
size_t size)
{
@@ -468,49 +100,55 @@
bool xo;
/* Enable A2XB bridge */
- reg = readl(RIVA_PMU_A2XB_CFG);
+ reg = readl_relaxed(RIVA_PMU_A2XB_CFG);
reg |= RIVA_PMU_A2XB_CFG_EN;
- writel(reg, RIVA_PMU_A2XB_CFG);
+ writel_relaxed(reg, RIVA_PMU_A2XB_CFG);
/* Determine which XO to use */
- reg = readl(RIVA_PMU_CFG);
+ reg = readl_relaxed(RIVA_PMU_CFG);
xo = (reg & RIVA_PMU_CFG_IRIS_XO_MODE) == RIVA_PMU_CFG_IRIS_XO_MODE_48;
/* Program PLL 13 to 960 MHz */
- reg = readl(RIVA_PLL_MODE);
+ reg = readl_relaxed(RIVA_PLL_MODE);
reg &= ~(PLL_MODE_BYPASSNL | PLL_MODE_OUTCTRL | PLL_MODE_RESET_N);
- writel(reg, RIVA_PLL_MODE);
+ writel_relaxed(reg, RIVA_PLL_MODE);
if (xo)
- writel(0x40000C00 | 40, RIVA_PLL_L_VAL);
+ writel_relaxed(0x40000C00 | 40, RIVA_PLL_L_VAL);
else
- writel(0x40000C00 | 50, RIVA_PLL_L_VAL);
- writel(0, RIVA_PLL_M_VAL);
- writel(1, RIVA_PLL_N_VAL);
+ writel_relaxed(0x40000C00 | 50, RIVA_PLL_L_VAL);
+ writel_relaxed(0, RIVA_PLL_M_VAL);
+ writel_relaxed(1, RIVA_PLL_N_VAL);
writel_relaxed(0x01495227, RIVA_PLL_CONFIG);
- reg = readl(RIVA_PLL_MODE);
+ reg = readl_relaxed(RIVA_PLL_MODE);
reg &= ~(PLL_MODE_REF_XO_SEL);
reg |= xo ? PLL_MODE_REF_XO_SEL_RF : PLL_MODE_REF_XO_SEL_CXO;
- writel(reg, RIVA_PLL_MODE);
+ writel_relaxed(reg, RIVA_PLL_MODE);
/* Enable PLL 13 */
reg |= PLL_MODE_BYPASSNL;
- writel(reg, RIVA_PLL_MODE);
+ writel_relaxed(reg, RIVA_PLL_MODE);
+ /*
+ * H/W requires a 5us delay between disabling the bypass and
+ * de-asserting the reset. Delay 10us just to be safe.
+ */
+ mb();
usleep_range(10, 20);
reg |= PLL_MODE_RESET_N;
- writel(reg, RIVA_PLL_MODE);
+ writel_relaxed(reg, RIVA_PLL_MODE);
reg |= PLL_MODE_OUTCTRL;
- writel(reg, RIVA_PLL_MODE);
+ writel_relaxed(reg, RIVA_PLL_MODE);
/* Wait for PLL to settle */
+ mb();
usleep_range(50, 100);
/* Configure cCPU for 240 MHz */
- reg = readl(RIVA_PMU_CLK_ROOT3);
- if (readl(RIVA_PMU_ROOT_CLK_SEL) & RIVA_PMU_ROOT_CLK_SEL_3) {
+ reg = readl_relaxed(RIVA_PMU_CLK_ROOT3);
+ if (readl_relaxed(RIVA_PMU_ROOT_CLK_SEL) & RIVA_PMU_ROOT_CLK_SEL_3) {
reg &= ~(RIVA_PMU_CLK_ROOT3_SRC0_SEL |
RIVA_PMU_CLK_ROOT3_SRC0_DIV);
reg |= RIVA_PMU_CLK_ROOT3_SRC0_SEL_RIVA |
@@ -521,34 +159,34 @@
reg |= RIVA_PMU_CLK_ROOT3_SRC1_SEL_RIVA |
RIVA_PMU_CLK_ROOT3_SRC1_DIV_2;
}
- writel(reg, RIVA_PMU_CLK_ROOT3);
+ writel_relaxed(reg, RIVA_PMU_CLK_ROOT3);
reg |= RIVA_PMU_CLK_ROOT3_ENA;
- writel(reg, RIVA_PMU_CLK_ROOT3);
- reg = readl(RIVA_PMU_ROOT_CLK_SEL);
+ writel_relaxed(reg, RIVA_PMU_CLK_ROOT3);
+ reg = readl_relaxed(RIVA_PMU_ROOT_CLK_SEL);
reg ^= RIVA_PMU_ROOT_CLK_SEL_3;
- writel(reg, RIVA_PMU_ROOT_CLK_SEL);
+ writel_relaxed(reg, RIVA_PMU_ROOT_CLK_SEL);
/* Use the high vector table */
- reg = readl(RIVA_PMU_CCPU_CTL);
+ reg = readl_relaxed(RIVA_PMU_CCPU_CTL);
reg |= RIVA_PMU_CCPU_CTL_HIGH_IVT | RIVA_PMU_CCPU_CTL_REMAP_EN;
- writel(reg, RIVA_PMU_CCPU_CTL);
+ writel_relaxed(reg, RIVA_PMU_CCPU_CTL);
/* Set base memory address */
writel_relaxed(riva_start >> 16, RIVA_PMU_CCPU_BOOT_REMAP_ADDR);
/* Clear warmboot bit indicating this is a cold boot */
- reg = readl(RIVA_PMU_CFG);
+ reg = readl_relaxed(RIVA_PMU_CFG);
reg &= ~(RIVA_PMU_CFG_WARM_BOOT);
- writel(reg, RIVA_PMU_CFG);
+ writel_relaxed(reg, RIVA_PMU_CFG);
/* Enable the cCPU clock */
- reg = readl(RIVA_PMU_OVRD_VAL);
+ reg = readl_relaxed(RIVA_PMU_OVRD_VAL);
reg |= RIVA_PMU_OVRD_VAL_CCPU_CLK;
- writel(reg, RIVA_PMU_OVRD_VAL);
+ writel_relaxed(reg, RIVA_PMU_OVRD_VAL);
/* Take cCPU out of reset */
reg |= RIVA_PMU_OVRD_VAL_CCPU_RESET;
- writel(reg, RIVA_PMU_OVRD_VAL);
+ writel_relaxed(reg, RIVA_PMU_OVRD_VAL);
return 0;
}
@@ -557,9 +195,9 @@
{
u32 reg;
/* Put riva into reset */
- reg = readl(RIVA_PMU_OVRD_VAL);
+ reg = readl_relaxed(RIVA_PMU_OVRD_VAL);
reg &= ~(RIVA_PMU_OVRD_VAL_CCPU_RESET | RIVA_PMU_OVRD_VAL_CCPU_CLK);
- writel(reg, RIVA_PMU_OVRD_VAL);
+ writel_relaxed(reg, RIVA_PMU_OVRD_VAL);
return 0;
}
@@ -635,27 +273,6 @@
return pas_shutdown(PAS_TZAPPS);
}
-static struct pil_reset_ops pil_modem_fw_q6_ops = {
- .init_image = init_image_modem_fw_q6_untrusted,
- .verify_blob = verify_blob,
- .auth_and_reset = reset_modem_fw_q6_untrusted,
- .shutdown = shutdown_modem_fw_q6_untrusted,
-};
-
-static struct pil_reset_ops pil_modem_sw_q6_ops = {
- .init_image = init_image_modem_sw_q6_untrusted,
- .verify_blob = verify_blob,
- .auth_and_reset = reset_modem_sw_q6_untrusted,
- .shutdown = shutdown_modem_sw_q6_untrusted,
-};
-
-static struct pil_reset_ops pil_lpass_q6_ops = {
- .init_image = init_image_lpass_q6_untrusted,
- .verify_blob = verify_blob,
- .auth_and_reset = reset_lpass_q6_untrusted,
- .shutdown = shutdown_lpass_q6_untrusted,
-};
-
static struct pil_reset_ops pil_riva_ops = {
.init_image = init_image_riva_untrusted,
.verify_blob = verify_blob,
@@ -677,38 +294,6 @@
.shutdown = shutdown_tzapps,
};
-static struct platform_device pil_lpass_q6 = {
- .name = "pil_lpass_q6",
-};
-
-static struct pil_desc pil_lpass_q6_desc = {
- .name = "q6",
- .dev = &pil_lpass_q6.dev,
- .ops = &pil_lpass_q6_ops,
-};
-
-static struct platform_device pil_modem_fw_q6 = {
- .name = "pil_modem_fw_q6",
-};
-
-static struct pil_desc pil_modem_fw_q6_desc = {
- .name = "modem_fw",
- .depends_on = "q6",
- .dev = &pil_modem_fw_q6.dev,
- .ops = &pil_modem_fw_q6_ops,
-};
-
-static struct platform_device pil_modem_sw_q6 = {
- .name = "pil_modem_sw_q6",
-};
-
-static struct pil_desc pil_modem_sw_q6_desc = {
- .name = "modem",
- .depends_on = "modem_fw",
- .dev = &pil_modem_sw_q6.dev,
- .ops = &pil_modem_sw_q6_ops,
-};
-
static struct platform_device pil_riva = {
.name = "pil_riva",
};
@@ -739,51 +324,8 @@
.ops = &pil_tzapps_ops,
};
-static int __init q6_reset_init(struct q6_data *q6)
-{
- int err;
-
- q6->reg_base = ioremap(q6->reg_base_phys, SZ_256);
- if (!q6->reg_base) {
- err = -ENOMEM;
- goto err_map;
- }
-
- q6->vreg = regulator_get(NULL, q6->name);
- if (IS_ERR(q6->vreg)) {
- err = PTR_ERR(q6->vreg);
- goto err_vreg;
- }
-
- return 0;
-
-err_vreg:
- iounmap(q6->reg_base);
-err_map:
- return err;
-}
-
static void __init use_secure_pil(void)
{
-
- if (pas_supported(PAS_Q6) > 0) {
- pil_lpass_q6_ops.init_image = init_image_lpass_q6_trusted;
- pil_lpass_q6_ops.auth_and_reset = reset_lpass_q6_trusted;
- pil_lpass_q6_ops.shutdown = shutdown_lpass_q6_trusted;
- }
-
- if (pas_supported(PAS_MODEM_FW) > 0) {
- pil_modem_fw_q6_ops.init_image = init_image_modem_fw_q6_trusted;
- pil_modem_fw_q6_ops.auth_and_reset = reset_modem_fw_q6_trusted;
- pil_modem_fw_q6_ops.shutdown = shutdown_modem_fw_q6_trusted;
- }
-
- if (pas_supported(PAS_MODEM_SW) > 0) {
- pil_modem_sw_q6_ops.init_image = init_image_modem_sw_q6_trusted;
- pil_modem_sw_q6_ops.auth_and_reset = reset_modem_sw_q6_trusted;
- pil_modem_sw_q6_ops.shutdown = shutdown_modem_sw_q6_trusted;
- }
-
if (pas_supported(PAS_DSPS) > 0) {
pil_dsps_ops.init_image = init_image_dsps_trusted;
pil_dsps_ops.auth_and_reset = reset_dsps_trusted;
@@ -797,11 +339,8 @@
}
}
-
static int __init msm_peripheral_reset_init(void)
{
- int err;
-
/*
* Don't initialize PIL on simulated targets, as some
* subsystems may not be emulated on them.
@@ -811,34 +350,6 @@
use_secure_pil();
- err = q6_reset_init(&q6_lpass);
- if (err)
- return err;
- BUG_ON(platform_device_register(&pil_lpass_q6));
- BUG_ON(msm_pil_register(&pil_lpass_q6_desc));
-
- mss_enable_reg = ioremap(MSM_MSS_ENABLE_PHYS, 4);
- if (!mss_enable_reg)
- return -ENOMEM;
-
- err = q6_reset_init(&q6_modem_fw);
- if (err) {
- iounmap(mss_enable_reg);
- return err;
- }
- BUG_ON(platform_device_register(&pil_modem_fw_q6));
- if (err) {
- iounmap(mss_enable_reg);
- return err;
- }
- BUG_ON(msm_pil_register(&pil_modem_fw_q6_desc));
-
- err = q6_reset_init(&q6_modem_sw);
- if (err)
- return err;
- BUG_ON(platform_device_register(&pil_modem_sw_q6));
- BUG_ON(msm_pil_register(&pil_modem_sw_q6_desc));
-
BUG_ON(platform_device_register(&pil_dsps));
BUG_ON(msm_pil_register(&pil_dsps_desc));
BUG_ON(platform_device_register(&pil_tzapps));
diff --git a/arch/arm/mach-msm/pil-q6v4.c b/arch/arm/mach-msm/pil-q6v4.c
new file mode 100644
index 0000000..24c479c
--- /dev/null
+++ b/arch/arm/mach-msm/pil-q6v4.c
@@ -0,0 +1,460 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/regulator/consumer.h>
+#include <linux/elf.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+#include <mach/msm_bus.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_xo.h>
+
+#include "peripheral-loader.h"
+#include "pil-q6v4.h"
+#include "scm-pas.h"
+
+#define PROXY_VOTE_TIMEOUT 10000
+
+#define QDSP6SS_RST_EVB 0x0
+#define QDSP6SS_RESET 0x04
+#define QDSP6SS_CGC_OVERRIDE 0x18
+#define QDSP6SS_STRAP_TCM 0x1C
+#define QDSP6SS_STRAP_AHB 0x20
+#define QDSP6SS_GFMUX_CTL 0x30
+#define QDSP6SS_PWR_CTL 0x38
+
+#define MSS_S_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2C70)
+#define MSS_SLP_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C60)
+#define SFAB_MSS_M_ACLK_CTL (MSM_CLK_CTL_BASE + 0x2340)
+#define SFAB_MSS_S_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2C00)
+#define MSS_RESET (MSM_CLK_CTL_BASE + 0x2C64)
+
+#define Q6SS_SS_ARES BIT(0)
+#define Q6SS_CORE_ARES BIT(1)
+#define Q6SS_ISDB_ARES BIT(2)
+#define Q6SS_ETM_ARES BIT(3)
+#define Q6SS_STOP_CORE_ARES BIT(4)
+#define Q6SS_PRIV_ARES BIT(5)
+
+#define Q6SS_L2DATA_SLP_NRET_N BIT(0)
+#define Q6SS_SLP_RET_N BIT(1)
+#define Q6SS_L1TCM_SLP_NRET_N BIT(2)
+#define Q6SS_L2TAG_SLP_NRET_N BIT(3)
+#define Q6SS_ETB_SLEEP_NRET_N BIT(4)
+#define Q6SS_ARR_STBY_N BIT(5)
+#define Q6SS_CLAMP_IO BIT(6)
+
+#define Q6SS_CLK_ENA BIT(1)
+#define Q6SS_SRC_SWITCH_CLK_OVR BIT(8)
+#define Q6SS_AXIS_ACLK_EN BIT(9)
+
+struct q6v4_data {
+ void __iomem *base;
+ void __iomem *modem_base;
+ unsigned long start_addr;
+ struct regulator *vreg;
+ bool vreg_enabled;
+ struct msm_xo_voter *xo;
+ struct timer_list xo_timer;
+};
+
+static int pil_q6v4_init_image(struct pil_desc *pil, const u8 *metadata,
+ size_t size)
+{
+ const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
+ struct q6v4_data *drv = dev_get_drvdata(pil->dev);
+ drv->start_addr = ehdr->e_entry;
+ return 0;
+}
+
+static int nop_verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
+{
+ return 0;
+}
+
+static void pil_q6v4_make_xo_proxy_votes(struct device *dev)
+{
+ struct q6v4_data *drv = dev_get_drvdata(dev);
+
+ msm_xo_mode_vote(drv->xo, MSM_XO_MODE_ON);
+ mod_timer(&drv->xo_timer, jiffies+msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
+}
+
+static void pil_q6v4_remove_xo_proxy_votes(unsigned long data)
+{
+ struct q6v4_data *drv = (struct q6v4_data *)data;
+
+ msm_xo_mode_vote(drv->xo, MSM_XO_MODE_OFF);
+}
+
+static void pil_q6v4_remove_xo_proxy_votes_now(struct device *dev)
+{
+ struct q6v4_data *drv = dev_get_drvdata(dev);
+
+ if (del_timer(&drv->xo_timer))
+ pil_q6v4_remove_xo_proxy_votes((unsigned long)drv);
+}
+
+static int pil_q6v4_power_up(struct device *dev)
+{
+ int err;
+ struct q6v4_data *drv = dev_get_drvdata(dev);
+
+ err = regulator_set_voltage(drv->vreg, 1050000, 1050000);
+ if (err) {
+ dev_err(dev, "Failed to set regulator's voltage.\n");
+ return err;
+ }
+ err = regulator_set_optimum_mode(drv->vreg, 100000);
+ if (err < 0) {
+ dev_err(dev, "Failed to set regulator's mode.\n");
+ return err;
+ }
+ err = regulator_enable(drv->vreg);
+ if (err) {
+ dev_err(dev, "Failed to enable regulator.\n");
+ return err;
+ }
+ drv->vreg_enabled = true;
+ return 0;
+}
+
+static DEFINE_MUTEX(pil_q6v4_modem_lock);
+static unsigned pil_q6v4_modem_count;
+
+/* Bring modem subsystem out of reset */
+static void pil_q6v4_init_modem(void __iomem *base, void __iomem *jtag_clk)
+{
+ mutex_lock(&pil_q6v4_modem_lock);
+ if (!pil_q6v4_modem_count) {
+ /* Enable MSS clocks */
+ writel_relaxed(0x10, SFAB_MSS_M_ACLK_CTL);
+ writel_relaxed(0x10, SFAB_MSS_S_HCLK_CTL);
+ writel_relaxed(0x10, MSS_S_HCLK_CTL);
+ writel_relaxed(0x10, MSS_SLP_CLK_CTL);
+ /* Wait for clocks to enable */
+ mb();
+ udelay(10);
+
+ /* De-assert MSS reset */
+ writel_relaxed(0x0, MSS_RESET);
+ mb();
+ udelay(10);
+ /* Enable MSS */
+ writel_relaxed(0x7, base);
+ }
+
+ /* Enable JTAG clocks */
+ /* TODO: Remove if/when Q6 software enables them? */
+ writel_relaxed(0x10, jtag_clk);
+
+ pil_q6v4_modem_count++;
+ mutex_unlock(&pil_q6v4_modem_lock);
+}
+
+/* Put modem subsystem back into reset */
+static void pil_q6v4_shutdown_modem(void)
+{
+ mutex_lock(&pil_q6v4_modem_lock);
+ if (pil_q6v4_modem_count)
+ pil_q6v4_modem_count--;
+ if (pil_q6v4_modem_count == 0)
+ writel_relaxed(0x1, MSS_RESET);
+ mutex_unlock(&pil_q6v4_modem_lock);
+}
+
+static int pil_q6v4_reset(struct pil_desc *pil)
+{
+ u32 reg, err = 0;
+ const struct q6v4_data *drv = dev_get_drvdata(pil->dev);
+ const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
+
+ pil_q6v4_make_xo_proxy_votes(pil->dev);
+
+ err = pil_q6v4_power_up(pil->dev);
+ if (err)
+ return err;
+ /* Enable Q6 ACLK */
+ writel_relaxed(0x10, pdata->aclk_reg);
+
+ if (drv->modem_base)
+ pil_q6v4_init_modem(drv->modem_base, pdata->jtag_clk_reg);
+
+ /* Unhalt bus port */
+ err = msm_bus_axi_portunhalt(pdata->bus_port);
+ if (err)
+ dev_err(pil->dev, "Failed to unhalt bus port\n");
+
+ /*
+ * Assert AXIS_ACLK_EN override to allow for correct updating of the
+ * QDSP6_CORE_STATE status bit. This is mandatory only for the SW Q6
+ * in 8960v1 and optional elsewhere.
+ */
+ reg = readl_relaxed(drv->base + QDSP6SS_CGC_OVERRIDE);
+ reg |= Q6SS_AXIS_ACLK_EN;
+ writel_relaxed(reg, drv->base + QDSP6SS_CGC_OVERRIDE);
+
+ /* Deassert Q6SS_SS_ARES */
+ reg = readl_relaxed(drv->base + QDSP6SS_RESET);
+ reg &= ~(Q6SS_SS_ARES);
+ writel_relaxed(reg, drv->base + QDSP6SS_RESET);
+
+ /* Program boot address */
+ writel_relaxed((drv->start_addr >> 8) & 0xFFFFFF,
+ drv->base + QDSP6SS_RST_EVB);
+
+ /* Program TCM and AHB address ranges */
+ writel_relaxed(pdata->strap_tcm_base, drv->base + QDSP6SS_STRAP_TCM);
+ writel_relaxed(pdata->strap_ahb_upper | pdata->strap_ahb_lower,
+ drv->base + QDSP6SS_STRAP_AHB);
+
+ /* Turn off Q6 core clock */
+ writel_relaxed(Q6SS_SRC_SWITCH_CLK_OVR,
+ drv->base + QDSP6SS_GFMUX_CTL);
+
+ /* Put memories to sleep */
+ writel_relaxed(Q6SS_CLAMP_IO, drv->base + QDSP6SS_PWR_CTL);
+
+ /* Assert resets */
+ reg = readl_relaxed(drv->base + QDSP6SS_RESET);
+ reg |= (Q6SS_CORE_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES
+ | Q6SS_STOP_CORE_ARES);
+ writel_relaxed(reg, drv->base + QDSP6SS_RESET);
+
+ /* Wait 8 AHB cycles for Q6 to be fully reset (AHB = 1.5Mhz) */
+ mb();
+ usleep_range(20, 30);
+
+ /* Turn on Q6 memories */
+ reg = Q6SS_L2DATA_SLP_NRET_N | Q6SS_SLP_RET_N | Q6SS_L1TCM_SLP_NRET_N
+ | Q6SS_L2TAG_SLP_NRET_N | Q6SS_ETB_SLEEP_NRET_N | Q6SS_ARR_STBY_N
+ | Q6SS_CLAMP_IO;
+ writel_relaxed(reg, drv->base + QDSP6SS_PWR_CTL);
+
+ /* Turn on Q6 core clock */
+ reg = Q6SS_CLK_ENA | Q6SS_SRC_SWITCH_CLK_OVR;
+ writel_relaxed(reg, drv->base + QDSP6SS_GFMUX_CTL);
+
+ /* Remove Q6SS_CLAMP_IO */
+ reg = readl_relaxed(drv->base + QDSP6SS_PWR_CTL);
+ reg &= ~Q6SS_CLAMP_IO;
+ writel_relaxed(reg, drv->base + QDSP6SS_PWR_CTL);
+
+ /* Bring Q6 core out of reset and start execution. */
+ writel_relaxed(0x0, drv->base + QDSP6SS_RESET);
+
+ /*
+ * Re-enable auto-gating of AXIS_ACLK at lease one AXI clock cycle
+ * after resets are de-asserted.
+ */
+ mb();
+ usleep_range(1, 10);
+ reg = readl_relaxed(drv->base + QDSP6SS_CGC_OVERRIDE);
+ reg &= ~Q6SS_AXIS_ACLK_EN;
+ writel_relaxed(reg, drv->base + QDSP6SS_CGC_OVERRIDE);
+
+ return 0;
+}
+
+static int pil_q6v4_shutdown(struct pil_desc *pil)
+{
+ u32 reg;
+ struct q6v4_data *drv = dev_get_drvdata(pil->dev);
+ const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
+
+ /* Make sure bus port is halted */
+ msm_bus_axi_porthalt(pdata->bus_port);
+
+ /* Turn off Q6 core clock */
+ writel_relaxed(Q6SS_SRC_SWITCH_CLK_OVR,
+ drv->base + QDSP6SS_GFMUX_CTL);
+
+ /* Assert resets */
+ reg = (Q6SS_SS_ARES | Q6SS_CORE_ARES | Q6SS_ISDB_ARES
+ | Q6SS_ETM_ARES | Q6SS_STOP_CORE_ARES | Q6SS_PRIV_ARES);
+ writel_relaxed(reg, drv->base + QDSP6SS_RESET);
+
+ /* Turn off Q6 memories */
+ writel_relaxed(Q6SS_CLAMP_IO, drv->base + QDSP6SS_PWR_CTL);
+
+ if (drv->modem_base)
+ pil_q6v4_shutdown_modem();
+
+ if (drv->vreg_enabled) {
+ regulator_disable(drv->vreg);
+ drv->vreg_enabled = false;
+ }
+
+ pil_q6v4_remove_xo_proxy_votes_now(pil->dev);
+
+ return 0;
+}
+
+static struct pil_reset_ops pil_q6v4_ops = {
+ .init_image = pil_q6v4_init_image,
+ .verify_blob = nop_verify_blob,
+ .auth_and_reset = pil_q6v4_reset,
+ .shutdown = pil_q6v4_shutdown,
+};
+
+static int pil_q6v4_init_image_trusted(struct pil_desc *pil,
+ const u8 *metadata, size_t size)
+{
+ const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
+ return pas_init_image(pdata->pas_id, metadata, size);
+}
+
+static int pil_q6v4_reset_trusted(struct pil_desc *pil)
+{
+ const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
+ int err;
+
+ pil_q6v4_make_xo_proxy_votes(pil->dev);
+
+ err = pil_q6v4_power_up(pil->dev);
+ if (err)
+ return err;
+
+ /* Unhalt bus port */
+ err = msm_bus_axi_portunhalt(pdata->bus_port);
+ if (err)
+ dev_err(pil->dev, "Failed to unhalt bus port\n");
+ return pas_auth_and_reset(pdata->pas_id);
+}
+
+static int pil_q6v4_shutdown_trusted(struct pil_desc *pil)
+{
+ int ret;
+ struct q6v4_data *drv = dev_get_drvdata(pil->dev);
+ struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
+
+ /* Make sure bus port is halted */
+ msm_bus_axi_porthalt(pdata->bus_port);
+
+ ret = pas_shutdown(pdata->pas_id);
+ if (ret)
+ return ret;
+
+ if (drv->vreg_enabled) {
+ regulator_disable(drv->vreg);
+ drv->vreg_enabled = false;
+ }
+
+ pil_q6v4_remove_xo_proxy_votes_now(pil->dev);
+
+ return ret;
+}
+
+static struct pil_reset_ops pil_q6v4_ops_trusted = {
+ .init_image = pil_q6v4_init_image_trusted,
+ .verify_blob = nop_verify_blob,
+ .auth_and_reset = pil_q6v4_reset_trusted,
+ .shutdown = pil_q6v4_shutdown_trusted,
+};
+
+static int __devinit pil_q6v4_driver_probe(struct platform_device *pdev)
+{
+ const struct pil_q6v4_pdata *pdata = pdev->dev.platform_data;
+ struct q6v4_data *drv;
+ struct resource *res;
+ struct pil_desc *desc;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+
+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, drv);
+
+ drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!drv->base)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (res) {
+ drv->modem_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!drv->modem_base)
+ return -ENOMEM;
+ }
+
+ desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+
+ desc->name = pdata->name;
+ desc->depends_on = pdata->depends;
+ desc->dev = &pdev->dev;
+
+ if (pas_supported(pdata->pas_id) > 0) {
+ desc->ops = &pil_q6v4_ops_trusted;
+ dev_info(&pdev->dev, "using secure boot\n");
+ } else {
+ desc->ops = &pil_q6v4_ops;
+ dev_info(&pdev->dev, "using non-secure boot\n");
+ }
+
+ drv->vreg = regulator_get(&pdev->dev, "core_vdd");
+ if (IS_ERR(drv->vreg))
+ return PTR_ERR(drv->vreg);
+
+ setup_timer(&drv->xo_timer, pil_q6v4_remove_xo_proxy_votes,
+ (unsigned long)drv);
+ drv->xo = msm_xo_get(pdata->xo_id, pdata->name);
+ if (IS_ERR(drv->xo))
+ return PTR_ERR(drv->xo);
+
+ if (msm_pil_register(desc)) {
+ regulator_put(drv->vreg);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int __devexit pil_q6v4_driver_exit(struct platform_device *pdev)
+{
+ struct q6v4_data *drv = platform_get_drvdata(pdev);
+ regulator_put(drv->vreg);
+ return 0;
+}
+
+static struct platform_driver pil_q6v4_driver = {
+ .probe = pil_q6v4_driver_probe,
+ .remove = __devexit_p(pil_q6v4_driver_exit),
+ .driver = {
+ .name = "pil_qdsp6v4",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pil_q6v4_init(void)
+{
+ return platform_driver_register(&pil_q6v4_driver);
+}
+module_init(pil_q6v4_init);
+
+static void __exit pil_q6v4_exit(void)
+{
+ platform_driver_unregister(&pil_q6v4_driver);
+}
+module_exit(pil_q6v4_exit);
+
+MODULE_DESCRIPTION("Support for booting QDSP6v4 (Hexagon) processors");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/include/mach/usb_gadget_fserial.h b/arch/arm/mach-msm/pil-q6v4.h
similarity index 60%
rename from arch/arm/mach-msm/include/mach/usb_gadget_fserial.h
rename to arch/arm/mach-msm/pil-q6v4.h
index 4112885..54bdf88 100644
--- a/arch/arm/mach-msm/include/mach/usb_gadget_fserial.h
+++ b/arch/arm/mach-msm/pil-q6v4.h
@@ -8,19 +8,20 @@
* 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 __MSM_PIL_Q6V4_H
+#define __MSM_PIL_Q6V4_H
-#ifndef __LINUX_USB_GADGET_FSERIAL_H__
-#define __LINUX_USB_GADGET_FSERIAL_H__
-
-#include <linux/platform_device.h>
-
-enum transport_type {
- USB_GADGET_FSERIAL_TRANSPORT_TTY,
- USB_GADGET_FSERIAL_TRANSPORT_SDIO,
- USB_GADGET_FSERIAL_TRANSPORT_SMD,
+struct pil_q6v4_pdata {
+ const unsigned long strap_tcm_base;
+ const unsigned long strap_ahb_upper;
+ const unsigned long strap_ahb_lower;
+ void __iomem *aclk_reg;
+ void __iomem *jtag_clk_reg;
+ const int xo_id;
+ const char *name;
+ const char *depends;
+ const unsigned pas_id;
+ int bus_port;
};
-
-#define GSERIAL_NO_PORTS 2
#endif
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index cb5fcff..8db21f9 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -384,6 +384,9 @@
else
i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
+ if (i >= CONFIG_MSM_IDLE_STATS_BUCKET_COUNT)
+ i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
+
stats[id].bucket[i]++;
if (t < stats[id].min_time[i] || !stats[id].max_time[i])
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
index 6becc61..bcc4c64 100644
--- a/arch/arm/mach-msm/pm-boot.c
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
diff --git a/arch/arm/mach-msm/pm-boot.h b/arch/arm/mach-msm/pm-boot.h
index 7e1a439..2234192 100644
--- a/arch/arm/mach-msm/pm-boot.h
+++ b/arch/arm/mach-msm/pm-boot.h
@@ -18,7 +18,14 @@
MSM_PM_BOOT_CONFIG_RESET_VECTOR = 1,
};
+#ifdef CONFIG_PM
int __init msm_pm_boot_init(int boot_config, uint32_t* address);
+#else
+static inline int __init msm_pm_boot_init(int boot_config, uint32_t* address)
+{
+ return 0;
+}
+#endif
void msm_pm_boot_config_before_pc(unsigned int cpu, unsigned long entry);
void msm_pm_boot_config_after_pc(unsigned int cpu);
diff --git a/arch/arm/mach-msm/qdsp5/adsp.c b/arch/arm/mach-msm/qdsp5/adsp.c
index d392cce..33c5a53 100644
--- a/arch/arm/mach-msm/qdsp5/adsp.c
+++ b/arch/arm/mach-msm/qdsp5/adsp.c
@@ -55,7 +55,6 @@
#include <linux/io.h>
#include <mach/msm_iomap.h>
-#include <mach/clk.h>
#include <mach/msm_adsp.h>
#include "adsp.h"
@@ -1018,7 +1017,7 @@
int adsp_set_clkrate(struct msm_adsp_module *module, unsigned long clk_rate)
{
if (module->clk && clk_rate)
- return clk_set_min_rate(module->clk, clk_rate);
+ return clk_set_rate(module->clk, clk_rate);
return -EINVAL;
}
@@ -1196,8 +1195,7 @@
else
mod->clk = NULL;
if (mod->clk && adsp_info.module[i].clk_rate)
- clk_set_min_rate(mod->clk,
- adsp_info.module[i].clk_rate);
+ clk_set_rate(mod->clk, adsp_info.module[i].clk_rate);
mod->verify_cmd = adsp_info.module[i].verify_cmd;
mod->patch_event = adsp_info.module[i].patch_event;
INIT_HLIST_HEAD(&mod->pmem_regions);
diff --git a/arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c b/arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c
index b1d2ee8..492fa0e 100644
--- a/arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c
+++ b/arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c
@@ -82,7 +82,8 @@
unsigned long subframe_pkt_addr;
unsigned long subframe_pkt_size;
unsigned short *frame_header_pkt;
- int i, num_addr, skip, start_pos = 0, xdim_pos = 1, ydim_pos = 2;
+ int i, num_addr, col_addr = 0, skip;
+ int start_pos = 0, xdim_pos = 1, ydim_pos = 2;
unsigned short *frame_buffer_high, *frame_buffer_low;
unsigned long frame_buffer_size;
unsigned short frame_buffer_size_high, frame_buffer_size_low;
@@ -133,9 +134,10 @@
skip = 0;
start_pos = 5;
} else {
- num_addr = 33;
+ num_addr = 16;
skip = 0;
start_pos = 6;
+ col_addr = 17;
}
break;
case 0x8201: /* h.264 vld in arm */
@@ -216,6 +218,29 @@
NULL, NULL, NULL, NULL))
return -EINVAL;
}
+ if (col_addr) {
+ frame_buffer_high += 2;
+ frame_buffer_low += 2;
+ /* Patch the Co-located buffers.*/
+ frame_buffer_size = (72 * frame_header_pkt[xdim_pos] *
+ frame_header_pkt[ydim_pos]) >> 16;
+ ptr_to_high_low_short((void *)frame_buffer_size,
+ &frame_buffer_size_high,
+ &frame_buffer_size_low);
+ for (i = 0; i < col_addr; i++) {
+ if (frame_buffer_high && frame_buffer_low) {
+ if (pmem_fixup_high_low(frame_buffer_high,
+ frame_buffer_low,
+ frame_buffer_size_high,
+ frame_buffer_size_low,
+ module,
+ NULL, NULL, NULL, NULL))
+ return -EINVAL;
+ }
+ frame_buffer_high += 2;
+ frame_buffer_low += 2;
+ }
+ }
/*Flush the cached pmem subframe packet before sending to DSP*/
if (filp) {
pmem_addr.vaddr = subframe_pkt_addr;
diff --git a/arch/arm/mach-msm/qdsp5v2/Makefile b/arch/arm/mach-msm/qdsp5v2/Makefile
old mode 100755
new mode 100644
diff --git a/arch/arm/mach-msm/qdsp5v2/adsp.c b/arch/arm/mach-msm/qdsp5v2/adsp.c
index 6d4d074..b7b56c8 100644
--- a/arch/arm/mach-msm/qdsp5v2/adsp.c
+++ b/arch/arm/mach-msm/qdsp5v2/adsp.c
@@ -34,7 +34,6 @@
#include <linux/slab.h>
#include <linux/io.h>
#include <mach/msm_iomap.h>
-#include <mach/clk.h>
#include <mach/msm_adsp.h>
#include "adsp.h"
#include <mach/debug_mm.h>
@@ -851,7 +850,7 @@
int adsp_set_clkrate(struct msm_adsp_module *module, unsigned long clk_rate)
{
if (module->clk && clk_rate)
- return clk_set_min_rate(module->clk, clk_rate);
+ return clk_set_rate(module->clk, clk_rate);
return -EINVAL;
}
@@ -1015,8 +1014,7 @@
else
mod->clk = NULL;
if (mod->clk && adsp_info.module[i].clk_rate)
- clk_set_min_rate(mod->clk,
- adsp_info.module[i].clk_rate);
+ clk_set_rate(mod->clk, adsp_info.module[i].clk_rate);
mod->verify_cmd = adsp_info.module[i].verify_cmd;
mod->patch_event = adsp_info.module[i].patch_event;
INIT_HLIST_HEAD(&mod->pmem_regions);
diff --git a/arch/arm/mach-msm/qdsp6v2/Makefile b/arch/arm/mach-msm/qdsp6v2/Makefile
index 7759c74..6d36495 100644
--- a/arch/arm/mach-msm/qdsp6v2/Makefile
+++ b/arch/arm/mach-msm/qdsp6v2/Makefile
@@ -17,3 +17,4 @@
obj-y += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o audio_utils.o
obj-y += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_utils_aio.o
obj-$(CONFIG_MSM_ULTRASOUND) += ultrasound/
+obj-y += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
diff --git a/arch/arm/mach-msm/qdsp6v2/amrwb_in.c b/arch/arm/mach-msm/qdsp6v2/amrwb_in.c
new file mode 100644
index 0000000..030d08f
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/amrwb_in.c
@@ -0,0 +1,322 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/dma-mapping.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/msm_audio_amrwb.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <sound/apr_audio.h>
+#include <sound/q6asm.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include "audio_utils.h"
+
+/* Buffer with meta*/
+#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in))
+
+/* Maximum 10 frames in buffer with meta */
+#define FRAME_SIZE (1 + ((61+sizeof(struct meta_out_dsp)) * 10))
+
+void q6asm_amrwb_in_cb(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv)
+{
+ struct q6audio_in * audio = (struct q6audio_in *)priv;
+ unsigned long flags;
+
+ pr_debug("%s:session id %d: opcode - %d\n", __func__,
+ audio->ac->session, opcode);
+
+ spin_lock_irqsave(&audio->dsp_lock, flags);
+ switch (opcode) {
+ case ASM_DATA_EVENT_READ_DONE:
+ audio_in_get_dsp_frames(audio, token, payload);
+ break;
+ case ASM_DATA_EVENT_WRITE_DONE:
+ atomic_inc(&audio->in_count);
+ wake_up(&audio->write_wait);
+ break;
+ case ASM_DATA_CMDRSP_EOS:
+ audio->eos_rsp = 1;
+ wake_up(&audio->read_wait);
+ break;
+ case ASM_STREAM_CMDRSP_GET_ENCDEC_PARAM:
+ break;
+ case ASM_STREAM_CMDRSP_GET_PP_PARAMS:
+ break;
+ case ASM_SESSION_EVENT_TX_OVERFLOW:
+ pr_err("%s:session id %d: ASM_SESSION_EVENT_TX_OVERFLOW\n",
+ __func__, audio->ac->session);
+ break;
+ default:
+ pr_err("%s:session id %d: Ignore opcode[0x%x]\n", __func__,
+ audio->ac->session, opcode);
+ break;
+ }
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+static long amrwb_in_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+ int cnt = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ struct msm_audio_amrwb_enc_config *enc_cfg;
+ enc_cfg = audio->enc_cfg;
+ pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
+ audio->ac->session, audio->buf_alloc);
+ if (audio->enabled == 1) {
+ pr_info("%s:AUDIO_START already over\n", __func__);
+ rc = 0;
+ break;
+ }
+ rc = audio_in_buf_alloc(audio);
+ if (rc < 0) {
+ pr_err("%s:session id %d: buffer allocation failed\n",
+ __func__, audio->ac->session);
+ break;
+ }
+
+ rc = q6asm_enc_cfg_blk_amrwb(audio->ac,
+ audio->buf_cfg.frames_per_buf,
+ enc_cfg->band_mode,
+ enc_cfg->dtx_enable);
+
+ if (rc < 0) {
+ pr_err("%s:session id %d: cmd amrwb media format block"
+ "failed\n", __func__, audio->ac->session);
+ break;
+ }
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ rc = q6asm_media_format_block_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+
+ if (rc < 0) {
+ pr_err("%s:session id %d: media format block"
+ "failed\n", __func__, audio->ac->session);
+ break;
+ }
+ }
+ pr_debug("%s:session id %d: AUDIO_START enable[%d]\n",
+ __func__, audio->ac->session,
+ audio->enabled);
+ rc = audio_in_enable(audio);
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("%s:session id %d: Audio Start procedure failed"
+ "rc=%d\n", __func__, audio->ac->session, rc);
+ break;
+ }
+ while (cnt++ < audio->str_cfg.buffer_count)
+ q6asm_read(audio->ac); /* Push buffer to DSP */
+ rc = 0;
+ pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
+ __func__, audio->ac->session, audio->enabled);
+ break;
+ }
+ case AUDIO_STOP: {
+ pr_debug("%s:AUDIO_STOP\n", __func__);
+ rc = audio_in_disable(audio);
+ if (rc < 0) {
+ pr_err("%s:session id %d: Audio Stop procedure failed"
+ "rc=%d\n", __func__, audio->ac->session, rc);
+ break;
+ }
+ break;
+ }
+ case AUDIO_GET_AMRWB_ENC_CONFIG: {
+ if (copy_to_user((void *)arg, audio->enc_cfg,
+ sizeof(struct msm_audio_amrwb_enc_config)))
+ rc = -EFAULT;
+ break;
+ }
+ case AUDIO_SET_AMRWB_ENC_CONFIG: {
+ struct msm_audio_amrwb_enc_config cfg;
+ struct msm_audio_amrwb_enc_config *enc_cfg;
+ enc_cfg = audio->enc_cfg;
+ if (copy_from_user(&cfg, (void *) arg,
+ sizeof(struct msm_audio_amrwb_enc_config))) {
+ rc = -EFAULT;
+ break;
+ }
+ if (cfg.band_mode > 8) {
+ pr_err("%s:session id %d: invalid band mode\n",
+ __func__, audio->ac->session);
+ rc = -EINVAL;
+ break;
+ }
+ /* ToDo: AMR WB encoder accepts values between 0-8
+ while openmax provides value between 9-17
+ as per spec */
+ enc_cfg->band_mode = cfg.band_mode;
+ enc_cfg->dtx_enable = (cfg.dtx_enable ? 1 : 0);
+ /* Currently DSP does not support different frameformat */
+ enc_cfg->frame_format = 0;
+ pr_debug("%s:session id %d: band_mode = 0x%x dtx_enable=0x%x\n",
+ __func__, audio->ac->session,
+ enc_cfg->band_mode, enc_cfg->dtx_enable);
+ break;
+ }
+ default:
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+static int amrwb_in_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_in *audio = NULL;
+ struct msm_audio_amrwb_enc_config *enc_cfg;
+ int rc = 0;
+
+ audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
+
+ if (audio == NULL) {
+ pr_err("%s:session id %d: Could not allocate memory for amrwb"
+ "driver\n", __func__, audio->ac->session);
+ return -ENOMEM;
+ }
+ /* Allocate memory for encoder config param */
+ audio->enc_cfg = kzalloc(sizeof(struct msm_audio_amrwb_enc_config),
+ GFP_KERNEL);
+ if (audio->enc_cfg == NULL) {
+ pr_err("%s:session id %d: Could not allocate memory for amrwb"
+ "config param\n", __func__, audio->ac->session);
+ kfree(audio);
+ return -ENOMEM;
+ }
+ enc_cfg = audio->enc_cfg;
+
+ mutex_init(&audio->lock);
+ mutex_init(&audio->read_lock);
+ mutex_init(&audio->write_lock);
+ spin_lock_init(&audio->dsp_lock);
+ init_waitqueue_head(&audio->read_wait);
+ init_waitqueue_head(&audio->write_wait);
+
+ /* Settings will be re-config at AUDIO_SET_CONFIG,
+ * but at least we need to have initial config
+ */
+ audio->str_cfg.buffer_size = FRAME_SIZE;
+ audio->str_cfg.buffer_count = FRAME_NUM;
+ audio->min_frame_size = 32;
+ audio->max_frames_per_buf = 10;
+ audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
+ audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+ enc_cfg->band_mode = 8;
+ enc_cfg->dtx_enable = 0;
+ audio->pcm_cfg.channel_count = 1;
+ audio->pcm_cfg.sample_rate = 16000;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ audio->buf_cfg.frames_per_buf = 0x01;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_amrwb_in_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("%s:session id %d: Could not allocate memory for audio"
+ "client\n", __func__, audio->ac->session);
+ kfree(audio->enc_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ /* open amrwb encoder in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ audio->feedback = NON_TUNNEL_MODE;
+ rc = q6asm_open_read_write(audio->ac, FORMAT_AMRWB,
+ FORMAT_LINEAR_PCM);
+ if (rc < 0) {
+ pr_err("%s:session id %d: NT mode Open failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ pr_info("%s:session id %d: NT mode encoder success\n",
+ __func__, audio->ac->session);
+ } else if (!(file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ audio->feedback = TUNNEL_MODE;
+ rc = q6asm_open_read(audio->ac, FORMAT_AMRWB);
+ if (rc < 0) {
+ pr_err("%s:session id %d: T mode Open failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ /* register for tx overflow (valid for tunnel mode only) */
+ rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
+ if (rc < 0) {
+ pr_err("%s:session id %d: TX Overflow registration"
+ "failed rc=%d\n", __func__, audio->ac->session,
+ rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ pr_info("%s:session id %d: T mode encoder success\n",
+ __func__, audio->ac->session);
+ } else {
+ pr_err("%s:session id %d: Unexpected mode\n", __func__,
+ audio->ac->session);
+ rc = -EACCES;
+ goto fail;
+ }
+
+ audio->opened = 1;
+ atomic_set(&audio->in_count, PCM_BUF_COUNT);
+ atomic_set(&audio->out_count, 0x00);
+ audio->enc_ioctl = amrwb_in_ioctl;
+ file->private_data = audio;
+
+ pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
+ return 0;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->enc_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+ .owner = THIS_MODULE,
+ .open = amrwb_in_open,
+ .release = audio_in_release,
+ .read = audio_in_read,
+ .write = audio_in_write,
+ .unlocked_ioctl = audio_in_ioctl,
+};
+
+struct miscdevice audio_amrwb_in_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_amrwb_in",
+ .fops = &audio_in_fops,
+};
+
+static int __init amrwb_in_init(void)
+{
+ return misc_register(&audio_amrwb_in_misc);
+}
+
+device_initcall(amrwb_in_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/apr.c b/arch/arm/mach-msm/qdsp6v2/apr.c
index 78f6519..13d92d1 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr.c
@@ -266,23 +266,23 @@
if ((dest_id == APR_DEST_QDSP6) &&
(atomic_read(&dsp_state) == 0)) {
pr_info("%s: Wait for Lpass to bootup\n", __func__);
- rc = wait_event_interruptible(dsp_wait,
- (atomic_read(&dsp_state) == 1));
- if (rc < 0) {
+ rc = wait_event_interruptible_timeout(dsp_wait,
+ (atomic_read(&dsp_state) == 1), (1 * HZ));
+ if (rc == 0) {
pr_err("%s: DSP is not Up\n", __func__);
return NULL;
}
- pr_debug("%s: Lpass Up\n", __func__);
+ pr_info("%s: Lpass Up\n", __func__);
} else if ((dest_id == APR_DEST_MODEM) &&
(atomic_read(&modem_state) == 0)) {
pr_info("%s: Wait for modem to bootup\n", __func__);
- rc = wait_event_interruptible(modem_wait,
- (atomic_read(&modem_state) == 1));
- if (rc < 0) {
+ rc = wait_event_interruptible_timeout(modem_wait,
+ (atomic_read(&modem_state) == 1), (1 * HZ));
+ if (rc == 0) {
pr_err("%s: Modem is not Up\n", __func__);
return NULL;
}
- pr_debug("%s: modem Up\n", __func__);
+ pr_info("%s: modem Up\n", __func__);
}
if (!strcmp(svc_name, "AFE")) {
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c b/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c
new file mode 100644
index 0000000..6768f7a
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c
@@ -0,0 +1,179 @@
+/* amrnb audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2011, Code Aurora Forum. 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
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include "audio_utils_aio.h"
+
+static void q6_audio_amrnb_cb(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv)
+{
+ struct q6audio_aio *audio = (struct q6audio_aio *)priv;
+
+ pr_debug("%s:opcde = %d token = 0x%x\n", __func__, opcode, token);
+ switch (opcode) {
+ case ASM_DATA_EVENT_WRITE_DONE:
+ case ASM_DATA_EVENT_READ_DONE:
+ case ASM_DATA_CMDRSP_EOS:
+ audio_aio_cb(opcode, token, payload, audio);
+ break;
+ default:
+ pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
+ break;
+ }
+}
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_amrnb_debug_fops = {
+ .read = audio_aio_debug_read,
+ .open = audio_aio_debug_open,
+};
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ pr_debug("%s[%p]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+ if (rc < 0) {
+ pr_err("pcm output block config failed\n");
+ break;
+ }
+ }
+
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("Audio Start procedure failed rc=%d\n", rc);
+ break;
+ }
+ pr_debug("AUDIO_START success enable[%d]\n", audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ default:
+ pr_debug("%s[%p]: Calling utils ioctl\n", __func__, audio);
+ rc = audio->codec_ioctl(file, cmd, arg);
+ }
+ return rc;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = NULL;
+ int rc = 0;
+
+#ifdef CONFIG_DEBUG_FS
+ /* 4 bytes represents decoder number, 1 byte for terminate string */
+ char name[sizeof "msm_amrnb_" + 5];
+#endif
+ audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+ if (audio == NULL) {
+ pr_err("Could not allocate memory for wma decode driver\n");
+ return -ENOMEM;
+ }
+
+ audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_amrnb_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("Could not allocate memory for audio client\n");
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ /* open in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+ FORMAT_AMRNB);
+ if (rc < 0) {
+ pr_err("NT mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = NON_TUNNEL_MODE;
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_write(audio->ac, FORMAT_AMRNB);
+ if (rc < 0) {
+ pr_err("T mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = TUNNEL_MODE;
+ audio->buf_cfg.meta_info_enable = 0x00;
+ } else {
+ pr_err("Not supported mode\n");
+ rc = -EACCES;
+ goto fail;
+ }
+ rc = audio_aio_open(audio, file);
+
+#ifdef CONFIG_DEBUG_FS
+ snprintf(name, sizeof name, "msm_amrnb_%04x", audio->ac->session);
+ audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+ NULL, (void *)audio,
+ &audio_amrnb_debug_fops);
+
+ if (IS_ERR(audio->dentry))
+ pr_debug("debugfs_create_file failed\n");
+#endif
+ pr_info("%s:amrnb decoder open success, session_id = %d\n", __func__,
+ audio->ac->session);
+ return rc;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_amrnb_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_aio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .fsync = audio_aio_fsync,
+};
+
+struct miscdevice audio_amrnb_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_amrnb",
+ .fops = &audio_amrnb_fops,
+};
+
+static int __init audio_amrnb_init(void)
+{
+ return misc_register(&audio_amrnb_misc);
+}
+
+device_initcall(audio_amrnb_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c b/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c
new file mode 100644
index 0000000..f95e191
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c
@@ -0,0 +1,182 @@
+/* amrwb audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2011, Code Aurora Forum. 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
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "audio_utils_aio.h"
+
+static void q6_audio_amrwb_cb(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv)
+{
+ struct q6audio_aio *audio = (struct q6audio_aio *)priv;
+
+ pr_debug("%s:opcde = %d token = 0x%x\n", __func__, opcode, token);
+ switch (opcode) {
+ case ASM_DATA_EVENT_WRITE_DONE:
+ case ASM_DATA_EVENT_READ_DONE:
+ case ASM_DATA_CMDRSP_EOS:
+ audio_aio_cb(opcode, token, payload, audio);
+ break;
+ default:
+ pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
+ break;
+ }
+}
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_amrwb_debug_fops = {
+ .read = audio_aio_debug_read,
+ .open = audio_aio_debug_open,
+};
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ pr_debug("%s[%p]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+ if (rc < 0) {
+ pr_err("pcm output block config failed\n");
+ break;
+ }
+ }
+
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("Audio Start procedure failed rc=%d\n", rc);
+ break;
+ }
+ pr_debug("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+ audio->ac->session,
+ audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ default:
+ pr_debug("%s[%p]: Calling utils ioctl\n", __func__, audio);
+ rc = audio->codec_ioctl(file, cmd, arg);
+ }
+ return rc;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = NULL;
+ int rc = 0;
+
+#ifdef CONFIG_DEBUG_FS
+ /* 4 bytes represents decoder number, 1 byte for terminate string */
+ char name[sizeof "msm_amrwb_" + 5];
+#endif
+ audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+ if (audio == NULL) {
+ pr_err("Could not allocate memory for aac decode driver\n");
+ return -ENOMEM;
+ }
+ audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_amrwb_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("Could not allocate memory for audio client\n");
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ /* open in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+ FORMAT_AMRWB);
+ if (rc < 0) {
+ pr_err("NT mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = NON_TUNNEL_MODE;
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_write(audio->ac, FORMAT_AMRWB);
+ if (rc < 0) {
+ pr_err("T mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = TUNNEL_MODE;
+ audio->buf_cfg.meta_info_enable = 0x00;
+ } else {
+ pr_err("Not supported mode\n");
+ rc = -EACCES;
+ goto fail;
+ }
+ rc = audio_aio_open(audio, file);
+
+#ifdef CONFIG_DEBUG_FS
+ snprintf(name, sizeof name, "msm_amrwb_%04x", audio->ac->session);
+ audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+ NULL, (void *)audio,
+ &audio_amrwb_debug_fops);
+
+ if (IS_ERR(audio->dentry))
+ pr_debug("debugfs_create_file failed\n");
+#endif
+ pr_info("%s: AMRWB dec success mode[%d]session[%d]\n", __func__,
+ audio->feedback,
+ audio->ac->session);
+ return 0;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_amrwb_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_aio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .fsync = audio_aio_fsync,
+};
+
+struct miscdevice audio_amrwb_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_amrwb",
+ .fops = &audio_amrwb_fops,
+};
+
+static int __init audio_amrwb_init(void)
+{
+ return misc_register(&audio_amrwb_misc);
+}
+
+device_initcall(audio_amrwb_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_evrc.c b/arch/arm/mach-msm/qdsp6v2/audio_evrc.c
new file mode 100644
index 0000000..12c815d
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_evrc.c
@@ -0,0 +1,186 @@
+/* evrc audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2011, Code Aurora Forum. 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
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "audio_utils_aio.h"
+
+static void q6_audio_evrc_cb(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv)
+{
+ struct q6audio_aio *audio = (struct q6audio_aio *)priv;
+
+ pr_debug("%s:opcde = %d token = 0x%x\n", __func__, opcode, token);
+ switch (opcode) {
+ case ASM_DATA_EVENT_WRITE_DONE:
+ case ASM_DATA_EVENT_READ_DONE:
+ case ASM_DATA_CMDRSP_EOS:
+ audio_aio_cb(opcode, token, payload, audio);
+ break;
+ default:
+ pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
+ break;
+ }
+}
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_evrc_debug_fops = {
+ .read = audio_aio_debug_read,
+ .open = audio_aio_debug_open,
+};
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ pr_debug("%s[%p]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+ if (rc < 0) {
+ pr_err("pcm output block config failed\n");
+ break;
+ }
+ }
+
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("Audio Start procedure failed rc=%d\n", rc);
+ break;
+ }
+ pr_debug("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+ audio->ac->session,
+ audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ default:
+ pr_debug("%s[%p]: Calling utils ioctl\n", __func__, audio);
+ rc = audio->codec_ioctl(file, cmd, arg);
+ }
+ return rc;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = NULL;
+ int rc = 0;
+
+#ifdef CONFIG_DEBUG_FS
+ /* 4 bytes represents decoder number, 1 byte for terminate string */
+ char name[sizeof "msm_evrc_" + 5];
+#endif
+ audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+ if (audio == NULL) {
+ pr_err("Could not allocate memory for aac decode driver\n");
+ return -ENOMEM;
+ }
+
+ /* Settings will be re-config at AUDIO_SET_CONFIG,
+ * but at least we need to have initial config
+ */
+ audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_evrc_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("Could not allocate memory for audio client\n");
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ /* open in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+ FORMAT_EVRC);
+ if (rc < 0) {
+ pr_err("NT mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = NON_TUNNEL_MODE;
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_write(audio->ac, FORMAT_EVRC);
+ if (rc < 0) {
+ pr_err("T mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = TUNNEL_MODE;
+ audio->buf_cfg.meta_info_enable = 0x00;
+ } else {
+ pr_err("Not supported mode\n");
+ rc = -EACCES;
+ goto fail;
+ }
+ rc = audio_aio_open(audio, file);
+
+#ifdef CONFIG_DEBUG_FS
+ snprintf(name, sizeof name, "msm_evrc_%04x", audio->ac->session);
+ audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+ NULL, (void *)audio,
+ &audio_evrc_debug_fops);
+
+ if (IS_ERR(audio->dentry))
+ pr_debug("debugfs_create_file failed\n");
+#endif
+ pr_info("%s:dec success mode[%d]session[%d]\n", __func__,
+ audio->feedback,
+ audio->ac->session);
+ return rc;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_evrc_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_aio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .fsync = audio_aio_fsync,
+};
+
+struct miscdevice audio_evrc_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_evrc",
+ .fops = &audio_evrc_fops,
+};
+
+static int __init audio_evrc_init(void)
+{
+ return misc_register(&audio_evrc_misc);
+}
+
+device_initcall(audio_evrc_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_mp3.c b/arch/arm/mach-msm/qdsp6v2/audio_mp3.c
new file mode 100644
index 0000000..bb5dc96
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_mp3.c
@@ -0,0 +1,177 @@
+/* mp3 audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2011, Code Aurora Forum. 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
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "audio_utils_aio.h"
+
+static void q6_audio_mp3_cb(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv)
+{
+ struct q6audio_aio *audio = (struct q6audio_aio *)priv;
+
+ pr_debug("%s:opcde = %d token = 0x%x\n", __func__, opcode, token);
+ switch (opcode) {
+ case ASM_DATA_EVENT_WRITE_DONE:
+ case ASM_DATA_EVENT_READ_DONE:
+ case ASM_DATA_CMDRSP_EOS:
+ audio_aio_cb(opcode, token, payload, audio);
+ break;
+ default:
+ pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
+ break;
+ }
+}
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_mp3_debug_fops = {
+ .read = audio_aio_debug_read,
+ .open = audio_aio_debug_open,
+};
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+ switch (cmd) {
+ case AUDIO_START: {
+ pr_debug("%s[%p]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+ if (rc < 0) {
+ pr_err("pcm output block config failed\n");
+ break;
+ }
+ }
+
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("Audio Start procedure failed rc=%d\n", rc);
+ break;
+ }
+ pr_info("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+ audio->ac->session,
+ audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ default:
+ pr_debug("%s[%p]: Calling utils ioctl\n", __func__, audio);
+ rc = audio->codec_ioctl(file, cmd, arg);
+ }
+ return rc;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = NULL;
+ int rc = 0;
+
+#ifdef CONFIG_DEBUG_FS
+ /* 4 bytes represents decoder number, 1 byte for terminate string */
+ char name[sizeof "msm_mp3_" + 5];
+#endif
+ audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+ if (audio == NULL) {
+ pr_err("Could not allocate memory for mp3 decode driver\n");
+ return -ENOMEM;
+ }
+
+ audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_mp3_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("Could not allocate memory for audio client\n");
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ /* open in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+ FORMAT_MP3);
+ if (rc < 0) {
+ pr_err("NT mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = NON_TUNNEL_MODE;
+ /* open MP3 decoder, expected frames is always 1
+ audio->buf_cfg.frames_per_buf = 0x01;*/
+ audio->buf_cfg.meta_info_enable = 0x01;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ pr_err("%s: Tunnel Mode not supported\n", __func__);
+ return -EACCES;
+ } else {
+ pr_err("Not supported mode\n");
+ rc = -EACCES;
+ goto fail;
+ }
+ rc = audio_aio_open(audio, file);
+
+#ifdef CONFIG_DEBUG_FS
+ snprintf(name, sizeof name, "msm_mp3_%04x", audio->ac->session);
+ audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+ NULL, (void *)audio,
+ &audio_mp3_debug_fops);
+
+ if (IS_ERR(audio->dentry))
+ pr_debug("debugfs_create_file failed\n");
+#endif
+ pr_info("%s:mp3dec success mode[%d]session[%d]\n", __func__,
+ audio->feedback,
+ audio->ac->session);
+ return rc;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_mp3_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_aio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .fsync = audio_aio_fsync,
+};
+
+struct miscdevice audio_mp3_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_mp3",
+ .fops = &audio_mp3_fops,
+};
+
+static int __init audio_mp3_init(void)
+{
+ return misc_register(&audio_mp3_misc);
+}
+
+device_initcall(audio_mp3_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_mvs.c b/arch/arm/mach-msm/qdsp6v2/audio_mvs.c
index 0b4997c..6e7961c 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_mvs.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_mvs.c
@@ -205,6 +205,7 @@
break;
}
+ case MVS_MODE_G711:
case MVS_MODE_G711A: {
/* G711 frames are 10ms each, but the DSP works with
* 20ms frames and sends two 10ms frames per buffer.
@@ -212,11 +213,16 @@
* buffers.
*/
/* Remove the first DSP frame info header.
- * Header format:
+ * Header format: G711A
* Bits 0-1: Frame type
* Bits 2-3: Frame rate
+ *
+ * Header format: G711
+ * Bits 2-3: Frame rate
*/
- buf_node->frame.header.frame_type = (*voc_pkt) & 0x03;
+ if (audio->mvs_mode == MVS_MODE_G711A)
+ buf_node->frame.header.frame_type =
+ (*voc_pkt) & 0x03;
voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
/* There are two frames in the buffer. Length of the
@@ -247,7 +253,8 @@
* Bits 0-1: Frame type
* Bits 2-3: Frame rate
*/
- buf_node->frame.header.frame_type =
+ if (audio->mvs_mode == MVS_MODE_G711A)
+ buf_node->frame.header.frame_type =
(*voc_pkt) & 0x03;
voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
@@ -271,6 +278,7 @@
break;
}
+ case MVS_MODE_IS733:
case MVS_MODE_4GV_NB:
case MVS_MODE_4GV_WB: {
/* Remove the DSP frame info header.
@@ -284,6 +292,32 @@
memcpy(&buf_node->frame.voc_pkt[0],
voc_pkt,
buf_node->frame.len);
+
+ list_add_tail(&buf_node->list, &audio->out_queue);
+ break;
+ }
+
+ case MVS_MODE_EFR:
+ case MVS_MODE_FR:
+ case MVS_MODE_HR: {
+ /*
+ * Remove the DSP frame info header
+ * Header Format
+ * Bit 0: bfi unused for uplink
+ * Bit 1-2: sid applies to both uplink and downlink
+ * Bit 3: taf unused for uplink
+ * MVS_MODE_HR
+ * Bit 4: ufi unused for uplink
+ */
+ buf_node->frame.header.gsm_frame_type.sid =
+ ((*voc_pkt) & 0x06) >> 1;
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+ buf_node->frame.len = pkt_len - DSP_FRAME_HDR_LEN;
+
+ memcpy(&buf_node->frame.voc_pkt[0],
+ voc_pkt,
+ buf_node->frame.len);
+
list_add_tail(&buf_node->list, &audio->out_queue);
break;
}
@@ -353,7 +387,6 @@
case MVS_MODE_IS127: {
/* Add the DSP frame info header. Header format:
* Bits 0-3: Frame rate
- * Bits 4-7: Frame type
*/
*voc_pkt = buf_node->frame.header.packet_rate & 0x0F;
voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
@@ -423,6 +456,7 @@
break;
}
+ case MVS_MODE_G711:
case MVS_MODE_G711A: {
/* G711 frames are 10ms each but the DSP expects 20ms
* worth of data, so send two 10ms frames per buffer.
@@ -481,6 +515,7 @@
break;
}
+ case MVS_MODE_IS733:
case MVS_MODE_4GV_NB:
case MVS_MODE_4GV_WB: {
/* Add the DSP frame info header. Header format:
@@ -498,6 +533,48 @@
break;
}
+ case MVS_MODE_EFR:
+ case MVS_MODE_FR:
+ case MVS_MODE_HR: {
+ /*
+ * Remove the DSP frame info header
+ * Header Format
+ * Bit 0: bfi applies only for downlink
+ * Bit 1-2: sid applies for downlink and uplink
+ * Bit 3: taf applies only for downlink
+ * MVS_MODE_HR
+ * Bit 4: ufi applies only for downlink
+ */
+ *voc_pkt =
+ ((buf_node->frame.header.gsm_frame_type.bfi
+ & 0x01) |
+ ((buf_node->frame.header.gsm_frame_type.sid
+ & 0x03) << 1) |
+ ((buf_node->frame.header.gsm_frame_type.taf
+ & 0x01) << 3));
+
+ if (audio->mvs_mode == MVS_MODE_HR) {
+ *voc_pkt = (*voc_pkt |
+ ((buf_node->frame.header.gsm_frame_type.ufi
+ & 0x01) << 4) |
+ ((0 & 0x07) << 5));
+ } else {
+ *voc_pkt = (*voc_pkt |
+ ((0 & 0x0F) << 4));
+ }
+
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+ *pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
+
+ memcpy(voc_pkt,
+ &buf_node->frame.voc_pkt[0],
+ buf_node->frame.len);
+
+ list_add_tail(&buf_node->list, &audio->free_in_queue);
+
+ break;
+ }
+
default: {
*pkt_len = buf_node->frame.len;
@@ -523,6 +600,10 @@
uint32_t media_type;
switch (mvs_mode) {
+ case MVS_MODE_IS733:
+ media_type = VSS_MEDIA_ID_13K_MODEM;
+ break;
+
case MVS_MODE_IS127:
media_type = VSS_MEDIA_ID_EVRC_MODEM;
break;
@@ -539,6 +620,18 @@
media_type = VSS_MEDIA_ID_AMR_NB_MODEM;
break;
+ case MVS_MODE_EFR:
+ media_type = VSS_MEDIA_ID_EFR_MODEM;
+ break;
+
+ case MVS_MODE_FR:
+ media_type = VSS_MEDIA_ID_FR_MODEM;
+ break;
+
+ case MVS_MODE_HR:
+ media_type = VSS_MEDIA_ID_HR_MODEM;
+ break;
+
case MVS_MODE_LINEAR_PCM:
media_type = VSS_MEDIA_ID_PCM_NB;
break;
@@ -555,6 +648,7 @@
media_type = VSS_MEDIA_ID_G729;
break;
+ case MVS_MODE_G711:
case MVS_MODE_G711A:
if (rate_type == MVS_G711A_MODE_MULAW)
media_type = VSS_MEDIA_ID_G711_MULAW;
@@ -580,10 +674,15 @@
uint32_t network_type;
switch (mvs_mode) {
+ case MVS_MODE_IS733:
case MVS_MODE_IS127:
case MVS_MODE_4GV_NB:
case MVS_MODE_AMR:
+ case MVS_MODE_EFR:
+ case MVS_MODE_FR:
+ case MVS_MODE_HR:
case MVS_MODE_LINEAR_PCM:
+ case MVS_MODE_G711:
case MVS_MODE_PCM:
case MVS_MODE_G729A:
case MVS_MODE_G711A:
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c b/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c
new file mode 100644
index 0000000..7b72c97
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c
@@ -0,0 +1,192 @@
+/* qcelp(v13k) audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2011, Code Aurora Forum. 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
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "audio_utils_aio.h"
+
+#define FRAME_SIZE_DEC_QCELP ((32) + sizeof(struct dec_meta_in))
+
+static void q6_audio_qcelp_cb(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv)
+{
+ struct q6audio_aio *audio = (struct q6audio_aio *)priv;
+
+ switch (opcode) {
+ case ASM_DATA_EVENT_WRITE_DONE:
+ case ASM_DATA_EVENT_READ_DONE:
+ case ASM_DATA_CMDRSP_EOS:
+ audio_aio_cb(opcode, token, payload, audio);
+ break;
+ default:
+ pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
+ break;
+ }
+}
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_qcelp_debug_fops = {
+ .read = audio_aio_debug_read,
+ .open = audio_aio_debug_open,
+};
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ pr_debug("%s[%p]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+ if (rc < 0) {
+ pr_err("pcm output block config failed\n");
+ break;
+ }
+ }
+
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("Audio Start procedure failed rc=%d\n", rc);
+ break;
+ }
+ pr_debug("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+ audio->ac->session,
+ audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ default:
+ pr_debug("%s[%p]: Calling utils ioctl\n", __func__, audio);
+ rc = audio->codec_ioctl(file, cmd, arg);
+ }
+ return rc;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = NULL;
+ int rc = 0;
+
+#ifdef CONFIG_DEBUG_FS
+ /* 4 bytes represents decoder number, 1 byte for terminate string */
+ char name[sizeof "msm_qcelp_" + 5];
+#endif
+ audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+ if (audio == NULL) {
+ pr_err("Could not allocate memory for aac decode driver\n");
+ return -ENOMEM;
+ }
+
+ /* Settings will be re-config at AUDIO_SET_CONFIG,
+ * but at least we need to have initial config
+ */
+ audio->str_cfg.buffer_size = FRAME_SIZE_DEC_QCELP;
+ audio->str_cfg.buffer_count = FRAME_NUM;
+ audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+ audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+ audio->pcm_cfg.sample_rate = 8000;
+ audio->pcm_cfg.channel_count = 1;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_qcelp_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("Could not allocate memory for audio client\n");
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ /* open in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+ FORMAT_V13K);
+ if (rc < 0) {
+ pr_err("NT mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = NON_TUNNEL_MODE;
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_write(audio->ac, FORMAT_V13K);
+ if (rc < 0) {
+ pr_err("T mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = TUNNEL_MODE;
+ audio->buf_cfg.meta_info_enable = 0x00;
+ } else {
+ pr_err("Not supported mode\n");
+ rc = -EACCES;
+ goto fail;
+ }
+ rc = audio_aio_open(audio, file);
+
+#ifdef CONFIG_DEBUG_FS
+ snprintf(name, sizeof name, "msm_qcelp_%04x", audio->ac->session);
+ audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+ NULL, (void *)audio,
+ &audio_qcelp_debug_fops);
+
+ if (IS_ERR(audio->dentry))
+ pr_debug("debugfs_create_file failed\n");
+#endif
+ pr_info("%s:dec success mode[%d]session[%d]\n", __func__,
+ audio->feedback,
+ audio->ac->session);
+ return 0;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_qcelp_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_aio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .fsync = audio_aio_fsync,
+};
+
+struct miscdevice audio_qcelp_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_qcelp",
+ .fops = &audio_qcelp_fops,
+};
+
+static int __init audio_qcelp_init(void)
+{
+ return misc_register(&audio_qcelp_misc);
+}
+
+device_initcall(audio_qcelp_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils.c b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
index 65a2c54..f9445d8 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
@@ -661,6 +661,7 @@
q6asm_audio_client_free(audio->ac);
mutex_unlock(&audio->lock);
kfree(audio->enc_cfg);
+ kfree(audio->codec_cfg);
kfree(audio);
return 0;
}
diff --git a/arch/arm/mach-msm/qdsp6v2/board-msm8x60-audio.c b/arch/arm/mach-msm/qdsp6v2/board-msm8x60-audio.c
index 401c759..135dd03 100644
--- a/arch/arm/mach-msm/qdsp6v2/board-msm8x60-audio.c
+++ b/arch/arm/mach-msm/qdsp6v2/board-msm8x60-audio.c
@@ -297,6 +297,29 @@
return 0;
}
+static int config_class_d1_gpio(int enable)
+{
+ int rc;
+
+ if (enable) {
+ rc = gpio_request(SNDDEV_GPIO_CLASS_D1_EN, "CLASSD1_EN");
+
+ if (rc) {
+ pr_err("%s: Right Channel spkr gpio request"
+ " failed\n", __func__);
+ return rc;
+ }
+
+ gpio_direction_output(SNDDEV_GPIO_CLASS_D1_EN, 1);
+ gpio_set_value(SNDDEV_GPIO_CLASS_D1_EN, 1);
+
+ } else {
+ gpio_set_value(SNDDEV_GPIO_CLASS_D1_EN, 0);
+ gpio_free(SNDDEV_GPIO_CLASS_D1_EN);
+ }
+ return 0;
+}
+
static atomic_t pamp_ref_cnt;
static int msm_snddev_poweramp_on(void)
@@ -312,6 +335,11 @@
pr_err("%s: d0 gpio configuration failed\n", __func__);
goto config_gpio_fail;
}
+ rc = config_class_d1_gpio(1);
+ if (rc) {
+ pr_err("%s: d1 gpio configuration failed\n", __func__);
+ goto config_gpio_fail;
+ }
config_gpio_fail:
return rc;
}
@@ -321,6 +349,7 @@
if (atomic_dec_return(&pamp_ref_cnt) == 0) {
pr_debug("%s: disable stereo spkr amp\n", __func__);
config_class_d0_gpio(0);
+ config_class_d1_gpio(0);
msleep(30);
}
}
diff --git a/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c b/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
index 16258eb..c19fd85 100644
--- a/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
+++ b/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
@@ -43,7 +43,7 @@
struct lpa_if {
struct mutex lock;
struct msm_audio_config cfg;
- struct audio_buffer audio_buf[2];
+ struct audio_buffer audio_buf[6];
int cpu_buf; /* next buffer the CPU will touch */
int dma_buf; /* next buffer the DMA will touch */
u8 *buffer;
@@ -52,6 +52,7 @@
wait_queue_head_t wait;
u32 config;
u32 dma_period_sz;
+ unsigned int num_periods;
};
static struct lpa_if *lpa_if_ptr;
@@ -85,9 +86,11 @@
pr_debug("dma_buf %d used %d\n", lpa_if->dma_buf,
lpa_if->audio_buf[lpa_if->dma_buf].used);
+ lpa_if->dma_buf++;
+ lpa_if->dma_buf = lpa_if->dma_buf % lpa_if->cfg.buffer_count;
- lpa_if->dma_buf ^= 1;
-
+ if (lpa_if->dma_buf == lpa_if->cpu_buf)
+ pr_err("Err:both dma_buf and cpu_buf are on same index\n");
wake_up(&lpa_if->wait);
}
return IRQ_HANDLED;
@@ -114,7 +117,7 @@
dma_params.src_start = lpa_if->buffer_phys;
dma_params.buffer = lpa_if->buffer;
- dma_params.buffer_size = lpa_if->dma_period_sz * 2;
+ dma_params.buffer_size = lpa_if->dma_period_sz * lpa_if->num_periods;
dma_params.period_size = lpa_if->dma_period_sz;
dma_params.channels = 2;
@@ -143,7 +146,7 @@
{
struct lpa_if *lpa_if = file->private_data;
int rc = 0;
-
+ unsigned int i;
pr_debug("cmd %u\n", cmd);
mutex_lock(&lpa_if->lock);
@@ -181,33 +184,74 @@
rc = -EFAULT;
}
break;
- case AUDIO_SET_CONFIG:
+ case AUDIO_SET_CONFIG: {
+ /* Setting default rate as 48khz */
+ unsigned int cur_sample_rate =
+ HDMI_SAMPLE_RATE_48KHZ;
+ struct msm_audio_config config;
+
pr_debug("AUDIO_SET_CONFIG\n");
- if (copy_from_user(&lpa_if->dma_period_sz, (void *) arg,
- sizeof(unsigned int))) {
- pr_debug("%s:failed to copy from user\n", __func__);
+ if (copy_from_user(&config, (void *)arg, sizeof(config))) {
rc = -EFAULT;
+ break;
}
- if ((lpa_if->dma_period_sz * 2) > DMA_ALLOC_BUF_SZ) {
+ lpa_if->dma_period_sz = config.buffer_size;
+ if ((lpa_if->dma_period_sz * lpa_if->num_periods) >
+ DMA_ALLOC_BUF_SZ) {
pr_err("Dma buffer size greater than allocated size\n");
return -EINVAL;
}
pr_debug("Dma_period_sz %d\n", lpa_if->dma_period_sz);
- lpa_if->cfg.buffer_count = 2;
- lpa_if->cfg.buffer_size = lpa_if->dma_period_sz * 2;
+ if (lpa_if->dma_period_sz < (2 * SZ_4K))
+ lpa_if->num_periods = 6;
+ pr_debug("No. of Periods %d\n", lpa_if->num_periods);
- lpa_if->audio_buf[0].phys = lpa_if->buffer_phys;
- lpa_if->audio_buf[0].data = lpa_if->buffer;
- lpa_if->audio_buf[0].size = lpa_if->dma_period_sz;
- lpa_if->audio_buf[0].used = 0;
+ lpa_if->cfg.buffer_count = lpa_if->num_periods;
+ lpa_if->cfg.buffer_size = lpa_if->dma_period_sz *
+ lpa_if->num_periods;
- lpa_if->audio_buf[1].phys =
- lpa_if->buffer_phys + lpa_if->dma_period_sz;
- lpa_if->audio_buf[1].data =
- lpa_if->buffer + lpa_if->dma_period_sz;
- lpa_if->audio_buf[1].size = lpa_if->dma_period_sz;
- lpa_if->audio_buf[1].used = 0;
+ for (i = 0; i < lpa_if->cfg.buffer_count; i++) {
+ lpa_if->audio_buf[i].phys =
+ lpa_if->buffer_phys + i * lpa_if->dma_period_sz;
+ lpa_if->audio_buf[i].data =
+ lpa_if->buffer + i * lpa_if->dma_period_sz;
+ lpa_if->audio_buf[i].size = lpa_if->dma_period_sz;
+ lpa_if->audio_buf[i].used = 0;
+ }
+
+ pr_debug("Sample rate %d\n", config.sample_rate);
+ switch (config.sample_rate) {
+ case 48000:
+ cur_sample_rate = HDMI_SAMPLE_RATE_48KHZ;
+ break;
+ case 44100:
+ cur_sample_rate = HDMI_SAMPLE_RATE_44_1KHZ;
+ break;
+ case 32000:
+ cur_sample_rate = HDMI_SAMPLE_RATE_32KHZ;
+ break;
+ case 88200:
+ cur_sample_rate = HDMI_SAMPLE_RATE_88_2KHZ;
+ break;
+ case 96000:
+ cur_sample_rate = HDMI_SAMPLE_RATE_96KHZ;
+ break;
+ case 176400:
+ cur_sample_rate = HDMI_SAMPLE_RATE_176_4KHZ;
+ break;
+ case 192000:
+ cur_sample_rate = HDMI_SAMPLE_RATE_192KHZ;
+ break;
+ default:
+ cur_sample_rate = HDMI_SAMPLE_RATE_48KHZ;
+ }
+ if (cur_sample_rate != hdmi_msm_audio_get_sample_rate())
+ hdmi_msm_audio_sample_rate_reset(cur_sample_rate);
+ else
+ pr_debug("Previous sample rate and current"
+ "sample rate are same\n");
break;
+ }
default:
pr_err("UnKnown Ioctl\n");
rc = -EINVAL;
@@ -225,8 +269,9 @@
file->private_data = lpa_if_ptr;
dma_buf_index = 0;
- lpa_if_ptr->cpu_buf = 0;
+ lpa_if_ptr->cpu_buf = 2;
lpa_if_ptr->dma_buf = 0;
+ lpa_if_ptr->num_periods = 4;
core_req_bus_bandwith(AUDIO_IF_BUS_ID, 100000, 0);
mb();
@@ -234,6 +279,17 @@
return 0;
}
+static inline int rt_policy(int policy)
+{
+ if (unlikely(policy == SCHED_FIFO) || unlikely(policy == SCHED_RR))
+ return 1;
+ return 0;
+}
+
+static inline int task_has_rt_policy(struct task_struct *p)
+{
+ return rt_policy(p->policy);
+}
static ssize_t lpa_if_write(struct file *file, const char __user *buf,
size_t count, loff_t *pos)
{
@@ -241,7 +297,19 @@
struct audio_buffer *ab;
const char __user *start = buf;
int xfer, rc;
+ struct sched_param s = { .sched_priority = 1 };
+ int old_prio = current->rt_priority;
+ int old_policy = current->policy;
+ int cap_nice = cap_raised(current_cap(), CAP_SYS_NICE);
+ /* just for this write, set us real-time */
+ if (!task_has_rt_policy(current)) {
+ struct cred *new = prepare_creds();
+ cap_raise(new->cap_effective, CAP_SYS_NICE);
+ commit_creds(new);
+ if ((sched_setscheduler(current, SCHED_RR, &s)) < 0)
+ pr_err("sched_setscheduler failed\n");
+ }
mutex_lock(&lpa_if->lock);
if (dma_buf_index < 2) {
@@ -299,12 +367,23 @@
pr_debug("xfer %d, size %d, used %d cpu_buf %d\n",
xfer, ab->size, ab->used, lpa_if->cpu_buf);
-
- lpa_if->cpu_buf ^= 1;
+ lpa_if->cpu_buf++;
+ lpa_if->cpu_buf = lpa_if->cpu_buf % lpa_if->cfg.buffer_count;
}
rc = buf - start;
end:
mutex_unlock(&lpa_if->lock);
+ /* restore old scheduling policy */
+ if (!rt_policy(old_policy)) {
+ struct sched_param v = { .sched_priority = old_prio };
+ if ((sched_setscheduler(current, old_policy, &v)) < 0)
+ pr_err("sched_setscheduler failed\n");
+ if (likely(!cap_nice)) {
+ struct cred *new = prepare_creds();
+ cap_lower(new->cap_effective, CAP_SYS_NICE);
+ commit_creds(new);
+ }
+ }
return rc;
}
@@ -325,6 +404,9 @@
}
core_req_bus_bandwith(AUDIO_IF_BUS_ID, 0, 0);
+ if (hdmi_msm_audio_get_sample_rate() != HDMI_SAMPLE_RATE_48KHZ)
+ hdmi_msm_audio_sample_rate_reset(HDMI_SAMPLE_RATE_48KHZ);
+
return 0;
}
diff --git a/arch/arm/mach-msm/qdsp6v2/q6voice.c b/arch/arm/mach-msm/qdsp6v2/q6voice.c
index 1ab615a..34169c0 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6voice.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6voice.c
@@ -1117,6 +1117,7 @@
/* Set encoder properties. */
switch (common.mvs_info.media_type) {
+ case VSS_MEDIA_ID_13K_MODEM:
case VSS_MEDIA_ID_4GV_NB_MODEM:
case VSS_MEDIA_ID_4GV_WB_MODEM:
case VSS_MEDIA_ID_EVRC_MODEM: {
@@ -1253,6 +1254,9 @@
break;
}
+ case VSS_MEDIA_ID_EFR_MODEM:
+ case VSS_MEDIA_ID_FR_MODEM:
+ case VSS_MEDIA_ID_HR_MODEM:
case VSS_MEDIA_ID_G729:
case VSS_MEDIA_ID_G711_ALAW:
case VSS_MEDIA_ID_G711_MULAW: {
@@ -2499,17 +2503,6 @@
pr_debug("%s: session_id 0x%x\n", __func__, data->dest_port);
- v = voice_get_session(data->dest_port);
- if (v == NULL) {
- pr_err("%s: v is NULL\n", __func__);
- return -EINVAL;
- }
-
- pr_debug("%s: common data 0x%x, session 0x%x\n",
- __func__, (unsigned int)c, (unsigned int)v);
- pr_debug("%s: Payload Length = %d, opcode=%x\n", __func__,
- data->payload_size, data->opcode);
-
if (data->opcode == RESET_EVENTS) {
pr_debug("%s:Reset event received in Voice service\n",
__func__);
@@ -2525,6 +2518,17 @@
return 0;
}
+ v = voice_get_session(data->dest_port);
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: common data 0x%x, session 0x%x\n",
+ __func__, (unsigned int)c, (unsigned int)v);
+ pr_debug("%s: Payload Length = %d, opcode=%x\n", __func__,
+ data->payload_size, data->opcode);
+
if (data->opcode == APR_BASIC_RSP_RESULT) {
if (data->payload_size) {
ptr = data->payload;
@@ -2614,17 +2618,6 @@
pr_debug("%s: session_id 0x%x\n", __func__, data->dest_port);
- v = voice_get_session(data->dest_port);
- if (v == NULL) {
- pr_err("%s: v is NULL\n", __func__);
- return -EINVAL;
- }
-
- pr_debug("%s: common data 0x%x, session 0x%x\n",
- __func__, (unsigned int)c, (unsigned int)v);
- pr_debug("%s: Payload Length = %d, opcode=%x\n", __func__,
- data->payload_size, data->opcode);
-
if (data->opcode == RESET_EVENTS) {
pr_debug("%s:Reset event received in Voice service\n",
__func__);
@@ -2640,6 +2633,17 @@
return 0;
}
+ v = voice_get_session(data->dest_port);
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: common data 0x%x, session 0x%x\n",
+ __func__, (unsigned int)c, (unsigned int)v);
+ pr_debug("%s: Payload Length = %d, opcode=%x\n", __func__,
+ data->payload_size, data->opcode);
+
if (data->opcode == APR_BASIC_RSP_RESULT) {
if (data->payload_size) {
ptr = data->payload;
@@ -2812,17 +2816,6 @@
pr_debug("%s: session_id 0x%x\n", __func__, data->dest_port);
- v = voice_get_session(data->dest_port);
- if (v == NULL) {
- pr_err("%s: v is NULL\n", __func__);
- return -EINVAL;
- }
-
- pr_debug("%s: common data 0x%x, session 0x%x\n",
- __func__, (unsigned int)c, (unsigned int)v);
- pr_debug("%s: Payload Length = %d, opcode=%x\n", __func__,
- data->payload_size, data->opcode);
-
if (data->opcode == RESET_EVENTS) {
pr_debug("%s:Reset event received in Voice service\n",
__func__);
@@ -2838,6 +2831,17 @@
return 0;
}
+ v = voice_get_session(data->dest_port);
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: common data 0x%x, session 0x%x\n",
+ __func__, (unsigned int)c, (unsigned int)v);
+ pr_debug("%s: Payload Length = %d, opcode=%x\n", __func__,
+ data->payload_size, data->opcode);
+
if (data->opcode == APR_BASIC_RSP_RESULT) {
if (data->payload_size) {
ptr = data->payload;
diff --git a/arch/arm/mach-msm/qdss-ptm.c b/arch/arm/mach-msm/qdss-ptm.c
index 0d971d7..205e2b8 100644
--- a/arch/arm/mach-msm/qdss-ptm.c
+++ b/arch/arm/mach-msm/qdss-ptm.c
@@ -357,6 +357,7 @@
ptm_writel(ptm, cpu, ptm.cfg.extnd_ext_input_sel, ETMEXTINSELR);
ptm_writel(ptm, cpu, ptm.cfg.ts_event, ETMTSEVR);
ptm_writel(ptm, cpu, ptm.cfg.aux_control, ETMAUXCR);
+ ptm_writel(ptm, cpu, cpu+1, ETMTRACEIDR);
ptm_writel(ptm, cpu, ptm.cfg.vmid_comp_value, ETMVMIDCVR);
ptm_clear_prog(cpu);
@@ -640,6 +641,7 @@
ptm.state[i++] = ptm_readl(ptm, cpu, ETMEXTINSELR);
ptm.state[i++] = ptm_readl(ptm, cpu, ETMTSEVR);
ptm.state[i++] = ptm_readl(ptm, cpu, ETMAUXCR);
+ ptm.state[i++] = ptm_readl(ptm, cpu, ETMTRACEIDR);
ptm.state[i++] = ptm_readl(ptm, cpu, ETMVMIDCVR);
ptm.state[i++] = ptm_readl(ptm, cpu, CS_CLAIMSET);
ptm.state[i++] = ptm_readl(ptm, cpu, CS_CLAIMCLR);
@@ -696,6 +698,7 @@
ptm_writel(ptm, cpu, ptm.state[i++], ETMEXTINSELR);
ptm_writel(ptm, cpu, ptm.state[i++], ETMTSEVR);
ptm_writel(ptm, cpu, ptm.state[i++], ETMAUXCR);
+ ptm_writel(ptm, cpu, ptm.state[i++], ETMTRACEIDR);
ptm_writel(ptm, cpu, ptm.state[i++], ETMVMIDCVR);
ptm_writel(ptm, cpu, ptm.state[i++], CS_CLAIMSET);
ptm_writel(ptm, cpu, ptm.state[i++], CS_CLAIMCLR);
diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c
index 00be696..28bf064 100644
--- a/arch/arm/mach-msm/restart.c
+++ b/arch/arm/mach-msm/restart.c
@@ -120,11 +120,11 @@
#ifdef CONFIG_MSM_DLOAD_MODE
set_dload_mode(0);
#endif
- if (cpu_is_msm8x60()) {
- pm8058_reset_pwr_off(0);
- pm8901_reset_pwr_off(0);
- }
pm8xxx_reset_pwr_off(0);
+
+ if (cpu_is_msm8x60())
+ pm8901_reset_pwr_off(0);
+
if (lower_pshold) {
__raw_writel(0, PSHOLD_CTL_SU);
mdelay(10000);
@@ -202,8 +202,6 @@
printk(KERN_NOTICE "Going down for restart now\n");
- if (cpu_is_msm8x60())
- pm8058_reset_pwr_off(1);
pm8xxx_reset_pwr_off(1);
if (cmd != NULL) {
diff --git a/arch/arm/mach-msm/rpm-regulator.c b/arch/arm/mach-msm/rpm-regulator.c
index 5c2bb8e..e2ebbd4 100644
--- a/arch/arm/mach-msm/rpm-regulator.c
+++ b/arch/arm/mach-msm/rpm-regulator.c
@@ -51,14 +51,15 @@
#define SET_PART(_vreg, _part, _val) \
_vreg->req[_vreg->part->_part.word].value \
= (_vreg->req[_vreg->part->_part.word].value \
- & ~vreg->part->_part.mask) \
- | (((_val) << vreg->part->_part.shift) & vreg->part->_part.mask)
+ & ~_vreg->part->_part.mask) \
+ | (((_val) << _vreg->part->_part.shift) \
+ & _vreg->part->_part.mask)
#define GET_PART(_vreg, _part) \
- ((_vreg->req[_vreg->part->_part.word].value & vreg->part->_part.mask) \
- >> vreg->part->_part.shift)
+ ((_vreg->req[_vreg->part->_part.word].value & _vreg->part->_part.mask) \
+ >> _vreg->part->_part.shift)
-#define USES_PART(_vreg, _part) (vreg->part->_part.mask)
+#define USES_PART(_vreg, _part) (_vreg->part->_part.mask)
#define vreg_err(vreg, fmt, ...) \
pr_err("%s: " fmt, vreg->rdesc.name, ##__VA_ARGS__)
@@ -489,6 +490,14 @@
*/
uV = (uV - range->min_uV + range->step_uV - 1) / range->step_uV;
uV = uV * range->step_uV + range->min_uV;
+
+ if (uV > max_uV) {
+ vreg_err(vreg,
+ "request v=[%d, %d] cannot be met by any set point; "
+ "next set point: %d\n",
+ min_uV, max_uV, uV);
+ return -EINVAL;
+ }
}
if (vreg->part->uV.mask) {
@@ -811,6 +820,14 @@
uV = (uV - range->min_uV + range->step_uV - 1) / range->step_uV;
uV = uV * range->step_uV + range->min_uV;
+ if (uV > max_uV) {
+ vreg_err(vreg,
+ "request v=[%d, %d] cannot be met by any set point; "
+ "next set point: %d\n",
+ min_uV, max_uV, uV);
+ return -EINVAL;
+ }
+
if (vreg->part->uV.mask) {
val[vreg->part->uV.word] = uV << vreg->part->uV.shift;
mask[vreg->part->uV.word] = vreg->part->uV.mask;
diff --git a/arch/arm/mach-msm/rpm.c b/arch/arm/mach-msm/rpm.c
index bee3c3d..ef2956a 100644
--- a/arch/arm/mach-msm/rpm.c
+++ b/arch/arm/mach-msm/rpm.c
@@ -264,7 +264,7 @@
DECLARE_COMPLETION_ONSTACK(ack);
unsigned long flags;
uint32_t ctx_mask = msm_rpm_get_ctx_mask(ctx);
- uint32_t ctx_mask_ack;
+ uint32_t ctx_mask_ack = 0;
uint32_t sel_masks_ack[MSM_RPM_SEL_MASK_SIZE];
int i;
@@ -320,8 +320,9 @@
unsigned int irq = msm_rpm_platform->irq_ack;
unsigned long flags;
uint32_t ctx_mask = msm_rpm_get_ctx_mask(ctx);
- uint32_t ctx_mask_ack;
+ uint32_t ctx_mask_ack = 0;
uint32_t sel_masks_ack[MSM_RPM_SEL_MASK_SIZE];
+ struct irq_chip *irq_chip = NULL;
int i;
msm_rpm_request_poll_mode.req = req;
@@ -331,7 +332,12 @@
msm_rpm_request_poll_mode.done = NULL;
spin_lock_irqsave(&msm_rpm_irq_lock, flags);
- irq_get_chip(irq)->irq_mask(irq_get_irq_data(irq));
+ irq_chip = irq_get_chip(irq);
+ if (!irq_chip) {
+ spin_unlock_irqrestore(&msm_rpm_irq_lock, flags);
+ return -ENOSPC;
+ }
+ irq_chip->irq_mask(irq_get_irq_data(irq));
if (msm_rpm_request) {
msm_rpm_busy_wait_for_request_completion(true);
@@ -356,7 +362,7 @@
msm_rpm_busy_wait_for_request_completion(false);
BUG_ON(msm_rpm_request);
- irq_get_chip(irq)->irq_unmask(irq_get_irq_data(irq));
+ irq_chip->irq_unmask(irq_get_irq_data(irq));
spin_unlock_irqrestore(&msm_rpm_irq_lock, flags);
BUG_ON((ctx_mask_ack & ~(msm_rpm_get_ctx_mask(MSM_RPM_CTX_REJECTED)))
diff --git a/arch/arm/mach-msm/rpm_resources.c b/arch/arm/mach-msm/rpm_resources.c
index 3e6a7e5..3568070 100644
--- a/arch/arm/mach-msm/rpm_resources.c
+++ b/arch/arm/mach-msm/rpm_resources.c
@@ -65,10 +65,6 @@
static ssize_t msm_rpmrs_resource_attr_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count);
-static void *msm_rpmrs_l2_counter_addr;
-static int msm_rpmrs_l2_reset_count;
-#define L2_PC_COUNTER_ADDR 0x660
-
#define MSM_RPMRS_MAX_RS_REGISTER_COUNT 2
#define RPMRS_ATTR(_name) \
@@ -509,11 +505,6 @@
switch (limits->l2_cache) {
case MSM_RPMRS_L2_CACHE_HSFS_OPEN:
lpm = MSM_SPM_L2_MODE_POWER_COLLAPSE;
- /* Increment the counter for TZ to init L2 on warmboot */
- /* Barrier in msm_spm_l2_set_low_power_mode */
- BUG_ON(!msm_rpmrs_l2_counter_addr);
- writel_relaxed(++msm_rpmrs_l2_reset_count,
- msm_rpmrs_l2_counter_addr);
msm_pm_set_l2_flush_flag(1);
break;
case MSM_RPMRS_L2_CACHE_GDHS:
@@ -540,9 +531,6 @@
{
msm_spm_l2_set_low_power_mode(MSM_SPM_MODE_DISABLED, notify_rpm);
msm_pm_set_l2_flush_flag(0);
- if (!collapsed && (limits->l2_cache == MSM_RPMRS_L2_CACHE_HSFS_OPEN))
- writel_relaxed(--msm_rpmrs_l2_reset_count,
- msm_rpmrs_l2_counter_addr);
}
#else
static int msm_rpmrs_flush_L2(struct msm_rpmrs_limits *limits, int notify_rpm)
@@ -940,10 +928,6 @@
{
int rc = 0;
- rc = msm_rpmrs_flush_L2(limits, notify_rpm);
- if (rc)
- return rc;
-
if (notify_rpm) {
rc = msm_rpmrs_flush_buffer(sclk_count, limits, from_idle);
if (rc)
@@ -953,6 +937,7 @@
msm_mpm_enter_sleep(from_idle);
}
+ rc = msm_rpmrs_flush_L2(limits, notify_rpm);
return rc;
}
@@ -1059,13 +1044,9 @@
}
early_initcall(msm_rpmrs_early_init);
-static int __init msm_rpmrs_l2_counter_init(void)
+static int __init msm_rpmrs_l2_init(void)
{
if (cpu_is_msm8960() || cpu_is_msm8930()) {
- msm_rpmrs_l2_counter_addr = MSM_IMEM_BASE + L2_PC_COUNTER_ADDR;
- writel_relaxed(msm_rpmrs_l2_reset_count,
- msm_rpmrs_l2_counter_addr);
- mb();
msm_pm_set_l2_flush_flag(0);
@@ -1073,6 +1054,7 @@
msm_spm_l2_cache_beyond_limits;
msm_rpmrs_l2_cache.aggregate = NULL;
msm_rpmrs_l2_cache.restore = NULL;
+
register_hotcpu_notifier(&rpmrs_cpu_notifier);
} else if (cpu_is_msm9615()) {
@@ -1082,4 +1064,4 @@
}
return 0;
}
-early_initcall(msm_rpmrs_l2_counter_init);
+early_initcall(msm_rpmrs_l2_init);
diff --git a/arch/arm/mach-msm/sdio_al_test.c b/arch/arm/mach-msm/sdio_al_test.c
index 8b9abcf..a71aae3 100644
--- a/arch/arm/mach-msm/sdio_al_test.c
+++ b/arch/arm/mach-msm/sdio_al_test.c
@@ -298,6 +298,7 @@
uint32_t smem_counter;
struct platform_device *ciq_app_pdev;
+ struct platform_device *csvt_app_pdev;
wait_queue_head_t wait_q;
int test_completed;
@@ -6162,7 +6163,7 @@
int ret;
pr_debug(TEST_MODULE_NAME ":%s.\n", __func__);
- pr_info(TEST_MODULE_NAME ": init test cahnnel %s.\n", name);
+ pr_info(TEST_MODULE_NAME ": init test channel %s.\n", name);
ch_id = channel_name_to_id(name);
pr_debug(TEST_MODULE_NAME ":id = %d.\n", ch_id);
@@ -6324,6 +6325,35 @@
return sdio_test_channel_remove(pdev);
}
+static int sdio_test_channel_csvt_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ if (!pdev)
+ return -ENODEV;
+
+ test_ctx->csvt_app_pdev = platform_device_alloc("SDIO_CSVT_TEST_APP",
+ -1);
+ ret = platform_device_add(test_ctx->csvt_app_pdev);
+ if (ret) {
+ pr_err(MODULE_NAME ":platform_device_add failed, "
+ "ret=%d\n", ret);
+ return ret;
+ }
+
+ return sdio_test_channel_probe(pdev);
+}
+
+static int sdio_test_channel_csvt_remove(struct platform_device *pdev)
+{
+ if (!pdev)
+ return -ENODEV;
+
+ platform_device_unregister(test_ctx->csvt_app_pdev);
+
+ return sdio_test_channel_remove(pdev);
+}
+
static struct platform_driver sdio_rpc_drv = {
.probe = sdio_test_channel_probe,
.remove = sdio_test_channel_remove,
@@ -6388,8 +6418,8 @@
};
static struct platform_driver sdio_csvt_drv = {
- .probe = sdio_test_channel_probe,
- .remove = sdio_test_channel_remove,
+ .probe = sdio_test_channel_csvt_probe,
+ .remove = sdio_test_channel_csvt_remove,
.driver = {
.name = "SDIO_CSVT_TEST",
.owner = THIS_MODULE,
diff --git a/arch/arm/mach-msm/sdio_tty.c b/arch/arm/mach-msm/sdio_tty.c
index fca88d8..e249d06 100644
--- a/arch/arm/mach-msm/sdio_tty.c
+++ b/arch/arm/mach-msm/sdio_tty.c
@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
+#include <linux/module.h>
#include <mach/sdio_al.h>
#define INPUT_SPEED 4800
@@ -24,6 +25,19 @@
#define SDIO_TTY_MODULE_NAME "sdio_tty"
#define SDIO_TTY_MAX_PACKET_SIZE 4096
#define MAX_SDIO_TTY_DRV 1
+#define MAX_SDIO_TTY_DEVS 2
+#define MAX_SDIO_TTY_DEV_NAME_SIZE 25
+
+/* Configurations per channel device */
+/* CIQ */
+#define SDIO_TTY_CIQ_DEV "sdio_tty_ciq_0"
+#define SDIO_TTY_CIQ_TEST_DEV "sdio_tty_ciq_test_0"
+#define SDIO_TTY_CH_CIQ "SDIO_CIQ"
+
+/* CSVT */
+#define SDIO_TTY_CSVT_DEV "sdio_tty_csvt_0"
+#define SDIO_TTY_CSVT_TEST_DEV "sdio_tty_csvt_test_0"
+#define SDIO_TTY_CH_CSVT "SDIO_CSVT"
enum sdio_tty_state {
TTY_INITIAL = 0,
@@ -32,9 +46,27 @@
TTY_CLOSED = 3,
};
+enum sdio_tty_devices {
+ SDIO_CIQ,
+ SDIO_CIQ_TEST_APP,
+ SDIO_CSVT,
+ SDIO_CSVT_TEST_APP,
+};
+
+static const struct platform_device_id sdio_tty_id_table[] = {
+ { "SDIO_CIQ", SDIO_CIQ },
+ { "SDIO_CIQ_TEST_APP", SDIO_CIQ_TEST_APP },
+ { "SDIO_CSVT", SDIO_CSVT },
+ { "SDIO_CSVT_TEST_APP", SDIO_CSVT_TEST_APP },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, sdio_tty_id_table);
+
struct sdio_tty {
struct sdio_channel *ch;
char *sdio_ch_name;
+ char tty_dev_name[MAX_SDIO_TTY_DEV_NAME_SIZE];
+ int device_id;
struct workqueue_struct *workq;
struct work_struct work_read;
wait_queue_head_t waitq;
@@ -44,11 +76,21 @@
char *read_buf;
enum sdio_tty_state sdio_tty_state;
int is_sdio_open;
+ int tty_open_count;
};
-static struct sdio_tty *sdio_tty;
+static struct sdio_tty *sdio_tty[MAX_SDIO_TTY_DEVS];
-#define DEBUG_MSG(sdio_tty, x...) if (sdio_tty->debug_msg_on) pr_info(x)
+#define DEBUG_MSG(sdio_tty_drv, x...) if (sdio_tty_drv->debug_msg_on) pr_info(x)
+
+/*
+ * Enable sdio_tty debug messages
+ * By default the sdio_tty debug messages are turned off
+ */
+static int ciq_debug_msg_on;
+module_param(ciq_debug_msg_on, int, 0);
+static int csvt_debug_msg_on;
+module_param(csvt_debug_msg_on, int, 0);
static void sdio_tty_read(struct work_struct *work)
{
@@ -62,30 +104,30 @@
sdio_tty_drv = container_of(work, struct sdio_tty, work_read);
if (!sdio_tty_drv) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty",
- __func__);
+ pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty", __func__);
return ;
}
if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
- __func__, sdio_tty_drv->sdio_tty_state);
+ __func__, sdio_tty_drv->sdio_tty_state);
return;
}
if (!sdio_tty_drv->read_buf) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL read_buf", __func__);
+ pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL read_buf for dev %s",
+ __func__, sdio_tty_drv->tty_dev_name);
return;
}
- /* Read the data from teh SDIO channel as long as there is available
+ /* Read the data from the SDIO channel as long as there is available
data */
while (1) {
if (test_bit(TTY_THROTTLED, &sdio_tty_drv->tty_str->flags)) {
- DEBUG_MSG(sdio_tty_drv,
- SDIO_TTY_MODULE_NAME ": %s: TTY_THROTTLED bit"
- " is set, exit",
- __func__);
+ DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME
+ ": %s: TTY_THROTTLED bit is set for "
+ "dev %s, exit", __func__,
+ sdio_tty_drv->tty_dev_name);
return;
}
@@ -93,20 +135,22 @@
read_avail = sdio_read_avail(sdio_tty_drv->ch);
DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME
- ": %s: read_avail is %d", __func__,
- read_avail);
+ ": %s: read_avail is %d for dev %s", __func__,
+ read_avail, sdio_tty_drv->tty_dev_name);
if (read_avail == 0) {
- DEBUG_MSG(sdio_tty_drv,
- SDIO_TTY_MODULE_NAME ": %s: read_avail is 0",
- __func__);
+ DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME
+ ": %s: read_avail is 0 for dev %s",
+ __func__, sdio_tty_drv->tty_dev_name);
return;
}
if (read_avail > SDIO_TTY_MAX_PACKET_SIZE) {
pr_err(SDIO_TTY_MODULE_NAME ": %s: read_avail(%d) is "
- "bigger than SDIO_TTY_MAX_PACKET_SIZE(%d)",
- __func__, read_avail, SDIO_TTY_MAX_PACKET_SIZE);
+ "bigger than SDIO_TTY_MAX_PACKET_SIZE(%d) "
+ "for dev %s", __func__, read_avail,
+ SDIO_TTY_MAX_PACKET_SIZE,
+ sdio_tty_drv->tty_dev_name);
return;
}
@@ -114,8 +158,9 @@
sdio_tty_drv->read_buf,
read_avail);
if (ret < 0) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_read error(%d)",
- __func__, ret);
+ pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_read error(%d) "
+ "for dev %s", __func__, ret,
+ sdio_tty_drv->tty_dev_name);
return;
}
@@ -132,15 +177,17 @@
if (total_push != read_avail) {
pr_err(SDIO_TTY_MODULE_NAME ": %s: failed, total_push"
- "(%d) != read_avail(%d)\n",
- __func__, total_push, read_avail);
+ "(%d) != read_avail(%d) for dev %s\n",
+ __func__, total_push, read_avail,
+ sdio_tty_drv->tty_dev_name);
}
tty_flip_buffer_push(sdio_tty_drv->tty_str);
- DEBUG_MSG(sdio_tty_drv,
- SDIO_TTY_MODULE_NAME ": %s: End of read %d bytes",
- __func__, read_avail);
+ DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME
+ ": %s: End of read %d bytes for dev %s",
+ __func__, read_avail,
+ sdio_tty_drv->tty_dev_name);
}
}
@@ -159,27 +206,26 @@
struct sdio_tty *sdio_tty_drv = NULL;
if (!tty) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty",
- __func__);
+ pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
return -ENODEV;
}
sdio_tty_drv = tty->driver_data;
if (!sdio_tty_drv) {
pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
- __func__);
+ __func__);
return -ENODEV;
}
if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
- __func__, sdio_tty_drv->sdio_tty_state);
+ __func__, sdio_tty_drv->sdio_tty_state);
return -EPERM;
}
write_avail = sdio_write_avail(sdio_tty_drv->ch);
- DEBUG_MSG(sdio_tty_drv,
- SDIO_TTY_MODULE_NAME ": %s: write_avail=%d",
- __func__, write_avail);
+ DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: write_avail=%d "
+ "for dev %s", __func__, write_avail,
+ sdio_tty_drv->tty_dev_name);
return write_avail;
}
@@ -205,60 +251,60 @@
struct sdio_tty *sdio_tty_drv = NULL;
if (!tty) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty",
- __func__);
+ pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
return -ENODEV;
}
sdio_tty_drv = tty->driver_data;
if (!sdio_tty_drv) {
pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
- __func__);
+ __func__);
return -ENODEV;
}
if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
- __func__, sdio_tty_drv->sdio_tty_state);
+ __func__, sdio_tty_drv->sdio_tty_state);
return -EPERM;
}
- DEBUG_MSG(sdio_tty_drv,
- SDIO_TTY_MODULE_NAME ": %s: WRITING CALLBACK CALLED WITH "
- "%d bytes\n",
- __func__, count);
+ DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Write Callback "
+ "called with %d bytes for dev %s\n", __func__, count,
+ sdio_tty_drv->tty_dev_name);
write_avail = sdio_write_avail(sdio_tty_drv->ch);
if (write_avail == 0) {
- DEBUG_MSG(sdio_tty_drv,
- SDIO_TTY_MODULE_NAME ": %s: write_avail is 0\n",
- __func__);
+ DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: "
+ "write_avail is 0 for dev %s\n",
+ __func__, sdio_tty_drv->tty_dev_name);
return 0;
}
if (write_avail > SDIO_TTY_MAX_PACKET_SIZE) {
- DEBUG_MSG(sdio_tty_drv,
- SDIO_TTY_MODULE_NAME ": %s: write_avail(%d) is "
- "bigger than max packet size,(%d), setting to "
- "max_packet_size\n",
- __func__, write_avail, SDIO_TTY_MAX_PACKET_SIZE);
+ DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: "
+ "write_avail(%d) is bigger than max packet "
+ "size(%d) for dev %s, setting to "
+ "max_packet_size\n", __func__, write_avail,
+ SDIO_TTY_MAX_PACKET_SIZE,
+ sdio_tty_drv->tty_dev_name);
write_avail = SDIO_TTY_MAX_PACKET_SIZE;
}
if (write_avail < count) {
- DEBUG_MSG(sdio_tty_drv,
- SDIO_TTY_MODULE_NAME ": %s: write_avail(%d) is "
- "smaller than "
- "required(%d), writing only %d bytes\n",
- __func__, write_avail, count, write_avail);
+ DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: "
+ "write_avail(%d) is smaller than required(%d) "
+ "for dev %s, writing only %d bytes\n",
+ __func__, write_avail, count,
+ sdio_tty_drv->tty_dev_name, write_avail);
len = write_avail;
}
ret = sdio_write(sdio_tty_drv->ch, buf, len);
if (ret) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_write failed, ret=%d\n",
- __func__, ret);
+ pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_write failed for "
+ "dev %s, ret=%d\n", __func__,
+ sdio_tty_drv->tty_dev_name, ret);
return 0;
}
- DEBUG_MSG(sdio_tty_drv,
- SDIO_TTY_MODULE_NAME ": %s: End of function, len=%d bytes\n",
- __func__, len);
+ DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: End of function, "
+ "dev=%s, len=%d bytes\n", __func__,
+ sdio_tty_drv->tty_dev_name, len);
return len;
}
@@ -269,18 +315,18 @@
if (!sdio_tty_drv) {
pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
- __func__);
+ __func__);
}
if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
- __func__, sdio_tty_drv->sdio_tty_state);
+ __func__, sdio_tty_drv->sdio_tty_state);
return;
}
- DEBUG_MSG(sdio_tty_drv,
- SDIO_TTY_MODULE_NAME ": %s: event %d received\n", __func__,
- event);
+ DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: event %d "
+ "received for dev %s\n", __func__, event,
+ sdio_tty_drv->tty_dev_name);
if (event == SDIO_EVENT_DATA_READ_AVAIL)
queue_work(sdio_tty_drv->workq, &sdio_tty_drv->work_read);
@@ -298,20 +344,37 @@
static int sdio_tty_open(struct tty_struct *tty, struct file *file)
{
int ret = 0;
+ int i = 0;
struct sdio_tty *sdio_tty_drv = NULL;
if (!tty) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty",
- __func__);
+ pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
return -ENODEV;
}
- sdio_tty_drv = sdio_tty;
+
+ for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
+ if (sdio_tty[i] == NULL)
+ continue;
+ if (!strncmp(sdio_tty[i]->tty_dev_name, tty->name,
+ MAX_SDIO_TTY_DEV_NAME_SIZE)) {
+ sdio_tty_drv = sdio_tty[i];
+ break;
+ }
+ }
+
if (!sdio_tty_drv) {
pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
__func__);
return -ENODEV;
}
+ sdio_tty_drv->tty_open_count++;
+ if (sdio_tty_drv->sdio_tty_state == TTY_OPENED) {
+ pr_err(SDIO_TTY_MODULE_NAME ": %s: tty dev(%s) is already open",
+ __func__, sdio_tty_drv->tty_dev_name);
+ return -EBUSY;
+ }
+
tty->driver_data = sdio_tty_drv;
sdio_tty_drv->tty_str = tty;
@@ -321,36 +384,31 @@
sdio_tty_drv->read_buf = kzalloc(SDIO_TTY_MAX_PACKET_SIZE, GFP_KERNEL);
if (sdio_tty_drv->read_buf == NULL) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: failed to allocate read_buf",
- __func__);
+ pr_err(SDIO_TTY_MODULE_NAME ": %s: failed to allocate read_buf "
+ "for dev %s", __func__, sdio_tty_drv->tty_dev_name);
return -ENOMEM;
}
sdio_tty_drv->workq = create_singlethread_workqueue("sdio_tty_read");
if (!sdio_tty_drv->workq) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: failed to create workq",
- __func__);
+ pr_err(SDIO_TTY_MODULE_NAME ": %s: failed to create workq "
+ "for dev %s", __func__, sdio_tty_drv->tty_dev_name);
return -ENOMEM;
}
- if (sdio_tty_drv->sdio_tty_state == TTY_OPENED) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: tty is already open",
- __func__);
- return -EBUSY;
- }
-
if (!sdio_tty_drv->is_sdio_open) {
ret = sdio_open(sdio_tty_drv->sdio_ch_name, &sdio_tty_drv->ch,
sdio_tty_drv, sdio_tty_notify);
if (ret < 0) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_open err=%d\n",
- __func__, ret);
+ pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_open err=%d "
+ "for dev %s\n", __func__, ret,
+ sdio_tty_drv->tty_dev_name);
destroy_workqueue(sdio_tty_drv->workq);
return ret;
}
- pr_info(SDIO_TTY_MODULE_NAME ": %s: SDIO_TTY channel opened\n",
- __func__);
+ pr_info(SDIO_TTY_MODULE_NAME ": %s: SDIO_TTY channel(%s) opened "
+ "\n", __func__, sdio_tty_drv->sdio_ch_name);
sdio_tty_drv->is_sdio_open = 1;
} else {
@@ -363,8 +421,8 @@
sdio_tty_drv->sdio_tty_state = TTY_OPENED;
- pr_info(SDIO_TTY_MODULE_NAME ": %s: TTY device opened\n",
- __func__);
+ pr_info(SDIO_TTY_MODULE_NAME ": %s: TTY device(%s) opened\n",
+ __func__, sdio_tty_drv->tty_dev_name);
return ret;
}
@@ -385,8 +443,7 @@
struct sdio_tty *sdio_tty_drv = NULL;
if (!tty) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty",
- __func__);
+ pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
return;
}
sdio_tty_drv = tty->driver_data;
@@ -397,10 +454,11 @@
}
if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
pr_err(SDIO_TTY_MODULE_NAME ": %s: trying to close a "
- "TTY device that was not opened\n",
- __func__);
+ "TTY device that was not opened\n", __func__);
return;
}
+ if (--sdio_tty_drv->tty_open_count != 0)
+ return;
flush_workqueue(sdio_tty_drv->workq);
destroy_workqueue(sdio_tty_drv->workq);
@@ -410,8 +468,8 @@
sdio_tty_drv->sdio_tty_state = TTY_CLOSED;
- pr_info(SDIO_TTY_MODULE_NAME ": %s: SDIO_TTY channel closed\n",
- __func__);
+ pr_info(SDIO_TTY_MODULE_NAME ": %s: SDIO_TTY device(%s) closed\n",
+ __func__, sdio_tty_drv->tty_dev_name);
}
static void sdio_tty_unthrottle(struct tty_struct *tty)
@@ -419,8 +477,7 @@
struct sdio_tty *sdio_tty_drv = NULL;
if (!tty) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty",
- __func__);
+ pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
return;
}
sdio_tty_drv = tty->driver_data;
@@ -448,33 +505,53 @@
.unthrottle = sdio_tty_unthrottle,
};
-void *sdio_tty_init_tty(char *tty_name, char *sdio_ch_name)
+int sdio_tty_init_tty(char *tty_name, char *sdio_ch_name,
+ enum sdio_tty_devices device_id, int debug_msg_on)
{
int ret = 0;
- struct device *tty_dev;
- struct sdio_tty *sdio_tty_drv;
-
- pr_info(SDIO_TTY_MODULE_NAME ": %s\n", __func__);
+ int i = 0;
+ struct device *tty_dev = NULL;
+ struct sdio_tty *sdio_tty_drv = NULL;
sdio_tty_drv = kzalloc(sizeof(struct sdio_tty), GFP_KERNEL);
if (sdio_tty_drv == NULL) {
- pr_err(SDIO_TTY_MODULE_NAME "%s: failed to allocate sdio_tty",
- __func__);
- return NULL;
+ pr_err(SDIO_TTY_MODULE_NAME ": %s: failed to allocate sdio_tty "
+ "for dev %s", __func__, tty_name);
+ return -ENOMEM;
}
- sdio_tty = sdio_tty_drv;
+ for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
+ if (sdio_tty[i] == NULL) {
+ sdio_tty[i] = sdio_tty_drv;
+ break;
+ }
+ }
+
+ if (i == MAX_SDIO_TTY_DEVS) {
+ pr_err(SDIO_TTY_MODULE_NAME ": %s: tty dev(%s) creation failed,"
+ " max limit(%d) reached.", __func__, tty_name,
+ MAX_SDIO_TTY_DEVS);
+ kfree(sdio_tty_drv);
+ return -ENODEV;
+ }
+
+ snprintf(sdio_tty_drv->tty_dev_name, MAX_SDIO_TTY_DEV_NAME_SIZE,
+ "%s%d", tty_name, 0);
sdio_tty_drv->sdio_ch_name = sdio_ch_name;
+ sdio_tty_drv->device_id = device_id;
+ pr_info(SDIO_TTY_MODULE_NAME ": %s: dev=%s, id=%d, channel=%s\n",
+ __func__, sdio_tty_drv->tty_dev_name, sdio_tty_drv->device_id,
+ sdio_tty_drv->sdio_ch_name);
INIT_WORK(&sdio_tty_drv->work_read, sdio_tty_read);
sdio_tty_drv->tty_drv = alloc_tty_driver(MAX_SDIO_TTY_DRV);
if (!sdio_tty_drv->tty_drv) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s - tty_drv is NULL",
- __func__);
+ pr_err(SDIO_TTY_MODULE_NAME ": %s - tty_drv is NULL for dev %s",
+ __func__, sdio_tty_drv->tty_dev_name);
kfree(sdio_tty_drv);
- return NULL;
+ return -ENODEV;
}
sdio_tty_drv->tty_drv->name = tty_name;
@@ -500,31 +577,38 @@
if (ret) {
put_tty_driver(sdio_tty_drv->tty_drv);
pr_err(SDIO_TTY_MODULE_NAME ": %s: tty_register_driver() "
- "failed\n", __func__);
+ "failed for dev %s\n", __func__,
+ sdio_tty_drv->tty_dev_name);
sdio_tty_drv->tty_drv = NULL;
kfree(sdio_tty_drv);
- return NULL;
+ return -ENODEV;
}
tty_dev = tty_register_device(sdio_tty_drv->tty_drv, 0, NULL);
if (IS_ERR(tty_dev)) {
pr_err(SDIO_TTY_MODULE_NAME ": %s: tty_register_device() "
- "failed\n", __func__);
+ "failed for dev %s\n", __func__,
+ sdio_tty_drv->tty_dev_name);
tty_unregister_driver(sdio_tty_drv->tty_drv);
put_tty_driver(sdio_tty_drv->tty_drv);
kfree(sdio_tty_drv);
- return NULL;
+ return -ENODEV;
}
sdio_tty_drv->sdio_tty_state = TTY_REGISTERED;
- return sdio_tty_drv;
+ if (debug_msg_on) {
+ pr_info(SDIO_TTY_MODULE_NAME ": %s: turn on debug msg for %s",
+ __func__, sdio_tty_drv->tty_dev_name);
+ sdio_tty_drv->debug_msg_on = debug_msg_on;
+ }
+ return 0;
}
-EXPORT_SYMBOL(sdio_tty_init_tty);
int sdio_tty_uninit_tty(void *sdio_tty_handle)
{
int ret = 0;
+ int i = 0;
struct sdio_tty *sdio_tty_drv = sdio_tty_handle;
if (!sdio_tty_drv) {
@@ -546,51 +630,151 @@
ret = tty_unregister_driver(sdio_tty_drv->tty_drv);
if (ret) {
pr_err(SDIO_TTY_MODULE_NAME ": %s: "
- "tty_unregister_driver() failed\n", __func__);
+ "tty_unregister_driver() failed for dev %s\n",
+ __func__, sdio_tty_drv->tty_dev_name);
}
put_tty_driver(sdio_tty_drv->tty_drv);
sdio_tty_drv->sdio_tty_state = TTY_INITIAL;
sdio_tty_drv->tty_drv = NULL;
}
- pr_info(SDIO_TTY_MODULE_NAME ": %s: Freeing sdio_tty structure",
- __func__);
+ for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
+ if (sdio_tty[i] == NULL)
+ continue;
+ if (sdio_tty[i]->device_id == sdio_tty_drv->device_id) {
+ sdio_tty[i] = NULL;
+ break;
+ }
+ }
+
+ DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Freeing sdio_tty "
+ "structure, dev=%s", __func__,
+ sdio_tty_drv->tty_dev_name);
kfree(sdio_tty_drv);
return 0;
}
-EXPORT_SYMBOL(sdio_tty_uninit_tty);
-
-void sdio_tty_enable_debug_msg(void *sdio_tty_handle, int enable)
+static int sdio_tty_probe(struct platform_device *pdev)
{
- struct sdio_tty *sdio_tty_drv = sdio_tty_handle;
+ const struct platform_device_id *id = platform_get_device_id(pdev);
+ enum sdio_tty_devices device_id = id->driver_data;
+ char *device_name = NULL;
+ char *channel_name = NULL;
+ int debug_msg_on = 0;
+ int ret = 0;
+
+ pr_debug(SDIO_TTY_MODULE_NAME ": %s for %s", __func__, pdev->name);
+
+ switch (device_id) {
+ case SDIO_CIQ:
+ device_name = SDIO_TTY_CIQ_DEV;
+ channel_name = SDIO_TTY_CH_CIQ;
+ debug_msg_on = ciq_debug_msg_on;
+ break;
+ case SDIO_CIQ_TEST_APP:
+ device_name = SDIO_TTY_CIQ_TEST_DEV;
+ channel_name = SDIO_TTY_CH_CIQ;
+ debug_msg_on = ciq_debug_msg_on;
+ break;
+ case SDIO_CSVT:
+ device_name = SDIO_TTY_CSVT_DEV;
+ channel_name = SDIO_TTY_CH_CSVT;
+ debug_msg_on = csvt_debug_msg_on;
+ break;
+ case SDIO_CSVT_TEST_APP:
+ device_name = SDIO_TTY_CSVT_TEST_DEV;
+ channel_name = SDIO_TTY_CH_CSVT;
+ debug_msg_on = csvt_debug_msg_on;
+ break;
+ default:
+ pr_err(SDIO_TTY_MODULE_NAME ": %s Invalid device:%s, id:%d",
+ __func__, pdev->name, device_id);
+ ret = -ENODEV;
+ break;
+ }
+
+ if (device_name) {
+ ret = sdio_tty_init_tty(device_name, channel_name,
+ device_id, debug_msg_on);
+ if (ret) {
+ pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_init_tty "
+ "failed for dev:%s", __func__, device_name);
+ }
+ }
+ return ret;
+}
+
+static int sdio_tty_remove(struct platform_device *pdev)
+{
+ const struct platform_device_id *id = platform_get_device_id(pdev);
+ enum sdio_tty_devices device_id = id->driver_data;
+ struct sdio_tty *sdio_tty_drv = NULL;
+ int i = 0;
+ int ret = 0;
+
+ pr_debug(SDIO_TTY_MODULE_NAME ": %s for %s", __func__, pdev->name);
+
+ for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
+ if (sdio_tty[i] == NULL)
+ continue;
+ if (sdio_tty[i]->device_id == device_id) {
+ sdio_tty_drv = sdio_tty[i];
+ break;
+ }
+ }
if (!sdio_tty_drv) {
pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
__func__);
- return;
+ return -ENODEV;
}
- pr_info(SDIO_TTY_MODULE_NAME ": %s: setting debug_msg_on to %d",
- __func__, enable);
- sdio_tty_drv->debug_msg_on = enable;
+
+ ret = sdio_tty_uninit_tty(sdio_tty_drv);
+ if (ret) {
+ pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_uninit_tty "
+ "failed for %s", __func__, pdev->name);
+ }
+ return ret;
}
-EXPORT_SYMBOL(sdio_tty_enable_debug_msg);
+static struct platform_driver sdio_tty_pdrv = {
+ .probe = sdio_tty_probe,
+ .remove = sdio_tty_remove,
+ .id_table = sdio_tty_id_table,
+ .driver = {
+ .name = "SDIO_TTY",
+ .owner = THIS_MODULE,
+ },
+};
+/*
+ * Module Init.
+ *
+ * Register SDIO TTY driver.
+ *
+ */
static int __init sdio_tty_init(void)
{
- return 0;
+ int ret = 0;
+
+ ret = platform_driver_register(&sdio_tty_pdrv);
+ if (ret) {
+ pr_err(SDIO_TTY_MODULE_NAME ": %s: platform_driver_register "
+ "failed", __func__);
+ }
+ return ret;
};
/*
* Module Exit.
*
- * Unregister SDIO driver.
+ * Unregister SDIO TTY driver.
*
*/
static void __exit sdio_tty_exit(void)
{
+ platform_driver_unregister(&sdio_tty_pdrv);
}
module_init(sdio_tty_init);
diff --git a/arch/arm/mach-msm/sdio_tty_ciq.c b/arch/arm/mach-msm/sdio_tty_ciq.c
deleted file mode 100644
index 64b772d..0000000
--- a/arch/arm/mach-msm/sdio_tty_ciq.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * 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/slab.h>
-#include <linux/platform_device.h>
-#include <linux/debugfs.h>
-#include <mach/sdio_al.h>
-#include <mach/sdio_tty.h>
-
-#define SDIO_TTY_DEV "sdio_tty_ciq_0"
-#define SDIO_CIQ "sdio_ciq"
-#define SDIO_TTY_DEV_TEST "sdio_tty_ciq_test_0"
-#define TTY_CIQ_MODULE_NAME "sdio_tty_ciq"
-
-struct sdio_tty_ciq {
- void *sdio_tty_handle;
-};
-
-static struct sdio_tty_ciq sdio_tty_ciq;
-
-/*
- * Enable sdio_tty debug messages
- * By default the sdio_tty debug messages are turned off
- */
-static int debug_msg_on;
-module_param(debug_msg_on, int, 0);
-
-static int sdio_tty_probe(struct platform_device *pdev)
-{
- sdio_tty_ciq.sdio_tty_handle = sdio_tty_init_tty(SDIO_TTY_DEV,
- "SDIO_CIQ");
- if (!sdio_tty_ciq.sdio_tty_handle) {
- pr_err(TTY_CIQ_MODULE_NAME ": %s: NULL sdio_tty_handle",
- __func__);
- return -ENODEV;
- }
-
- if (debug_msg_on)
- sdio_tty_enable_debug_msg(sdio_tty_ciq.sdio_tty_handle,
- debug_msg_on);
-
- return 0;
-}
-
-static int sdio_tty_test_probe(struct platform_device *pdev)
-{
- sdio_tty_ciq.sdio_tty_handle = sdio_tty_init_tty(SDIO_TTY_DEV_TEST,
- "SDIO_CIQ");
- if (!sdio_tty_ciq.sdio_tty_handle) {
- pr_err(TTY_CIQ_MODULE_NAME ": %s: NULL sdio_tty_handle",
- __func__);
- return -ENODEV;
- }
-
- if (debug_msg_on)
- sdio_tty_enable_debug_msg(sdio_tty_ciq.sdio_tty_handle,
- debug_msg_on);
-
- return 0;
-}
-
-static int sdio_tty_remove(struct platform_device *pdev)
-{
- int ret = 0;
-
- pr_info(TTY_CIQ_MODULE_NAME ": %s", __func__);
- ret = sdio_tty_uninit_tty(sdio_tty_ciq.sdio_tty_handle);
- if (ret) {
- pr_err(TTY_CIQ_MODULE_NAME ": %s: sdio_tty_uninit_tty failed",
- __func__);
- return ret;
- }
-
- return 0;
-}
-
-static struct platform_driver sdio_tty_pdrv = {
- .probe = sdio_tty_probe,
- .remove = sdio_tty_remove,
- .driver = {
- .name = "SDIO_CIQ",
- .owner = THIS_MODULE,
- },
-};
-
-static struct platform_driver sdio_tty_test_pdrv = {
- .probe = sdio_tty_test_probe,
- .remove = sdio_tty_remove,
- .driver = {
- .name = "SDIO_CIQ_TEST_APP",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init sdio_tty_ciq_init(void)
-{
- int ret = 0;
-
- ret = platform_driver_register(&sdio_tty_pdrv);
- if (ret) {
- pr_err(TTY_CIQ_MODULE_NAME ": %s: platform_driver_register "
- "failed", __func__);
- return ret;
- }
- return platform_driver_register(&sdio_tty_test_pdrv);
-};
-
-/*
- * Module Exit.
- *
- * Unregister SDIO driver.
- *
- */
-static void __exit sdio_tty_ciq_exit(void)
-{
- platform_driver_unregister(&sdio_tty_pdrv);
- platform_driver_unregister(&sdio_tty_test_pdrv);
-}
-
-module_init(sdio_tty_ciq_init);
-module_exit(sdio_tty_ciq_exit);
-
-MODULE_DESCRIPTION("SDIO TTY CIQ");
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Maya Erez <merez@codeaurora.org>");
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index eeaab60..691dad2 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -660,9 +660,11 @@
if (smsm_info.state) {
writel_relaxed(0, SMSM_STATE_ADDR(restart_pid));
- /* clear apps SMSM to restart SMSM init handshake */
- if (restart_pid == SMSM_MODEM)
- writel_relaxed(0, SMSM_STATE_ADDR(SMSM_APPS));
+ /* restart SMSM init handshake */
+ if (restart_pid == SMSM_MODEM) {
+ smsm_change_state(SMSM_APPS_STATE,
+ SMSM_INIT | SMSM_SMD_LOOPBACK, 0);
+ }
/* notify SMSM processors */
smsm_irq_handler(0, 0);
@@ -919,6 +921,7 @@
if (ch->send->state == SMD_SS_OPENED) {
ch_set_state(ch, SMD_SS_CLOSING);
ch->current_packet = 0;
+ ch->pending_pkt_sz = 0;
ch->notify(ch->priv, SMD_EVENT_CLOSE);
}
break;
@@ -2540,8 +2543,10 @@
void *data);
static struct restart_notifier_block restart_notifiers[] = {
- {SMSM_MODEM, "modem", .nb.notifier_call = restart_notifier_cb},
- {SMSM_Q6, "lpass", .nb.notifier_call = restart_notifier_cb},
+ {SMD_MODEM, "modem", .nb.notifier_call = restart_notifier_cb},
+ {SMD_Q6, "lpass", .nb.notifier_call = restart_notifier_cb},
+ {SMD_WCNSS, "riva", .nb.notifier_call = restart_notifier_cb},
+ {SMD_DSPS, "dsps", .nb.notifier_call = restart_notifier_cb},
};
static int restart_notifier_cb(struct notifier_block *this,
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index 7c7a822..4744f1f 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -63,7 +63,6 @@
int i;
int blocking_write;
- int needed_space;
int is_open;
unsigned ch_size;
uint open_modem_wait;
@@ -155,7 +154,7 @@
smd_pkt_devp->is_open = 0;
wake_up(&smd_pkt_devp->ch_read_wait_queue);
- wake_up_interruptible(&smd_pkt_devp->ch_write_wait_queue);
+ wake_up(&smd_pkt_devp->ch_write_wait_queue);
wake_up_interruptible(&smd_pkt_devp->ch_opened_wait_queue);
}
@@ -305,7 +304,7 @@
size_t count,
loff_t *ppos)
{
- int r = 0;
+ int r = 0, bytes_written;
struct smd_pkt_dev *smd_pkt_devp;
DEFINE_WAIT(write_wait);
@@ -317,84 +316,56 @@
if (!smd_pkt_devp || !smd_pkt_devp->ch)
return -EINVAL;
- if (count > smd_pkt_devp->ch_size)
- return -EINVAL;
-
if (smd_pkt_devp->do_reset_notification) {
/* notify client that a reset occurred */
return notify_reset(smd_pkt_devp);
}
- if (smd_pkt_devp->blocking_write) {
- for (;;) {
- mutex_lock(&smd_pkt_devp->tx_lock);
- if (smd_pkt_devp->has_reset) {
- smd_disable_read_intr(smd_pkt_devp->ch);
- mutex_unlock(&smd_pkt_devp->tx_lock);
- return notify_reset(smd_pkt_devp);
- }
- if (signal_pending(current)) {
- smd_disable_read_intr(smd_pkt_devp->ch);
- mutex_unlock(&smd_pkt_devp->tx_lock);
- return -ERESTARTSYS;
- }
-
- prepare_to_wait(&smd_pkt_devp->ch_write_wait_queue,
- &write_wait, TASK_INTERRUPTIBLE);
- smd_enable_read_intr(smd_pkt_devp->ch);
- if (smd_write_avail(smd_pkt_devp->ch) < count) {
- if (!smd_pkt_devp->needed_space ||
- count < smd_pkt_devp->needed_space)
- smd_pkt_devp->needed_space = count;
- mutex_unlock(&smd_pkt_devp->tx_lock);
- schedule();
- } else
- break;
- }
- finish_wait(&smd_pkt_devp->ch_write_wait_queue, &write_wait);
- smd_disable_read_intr(smd_pkt_devp->ch);
- if (smd_pkt_devp->has_reset) {
- mutex_unlock(&smd_pkt_devp->tx_lock);
- return notify_reset(smd_pkt_devp);
- }
- if (signal_pending(current)) {
- mutex_unlock(&smd_pkt_devp->tx_lock);
- return -ERESTARTSYS;
- }
- } else {
- if (smd_pkt_devp->has_reset)
- return notify_reset(smd_pkt_devp);
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- mutex_lock(&smd_pkt_devp->tx_lock);
+ mutex_lock(&smd_pkt_devp->tx_lock);
+ if (!smd_pkt_devp->blocking_write) {
if (smd_write_avail(smd_pkt_devp->ch) < count) {
D(KERN_ERR "%s: Not enough space to write\n",
- __func__);
+ __func__);
mutex_unlock(&smd_pkt_devp->tx_lock);
return -ENOMEM;
}
}
- D_DUMP_BUFFER("write: ", count, buf);
-
- smd_pkt_devp->needed_space = 0;
-
- r = smd_write_user_buffer(smd_pkt_devp->ch, buf, count);
- if (r != count) {
+ r = smd_write_start(smd_pkt_devp->ch, count);
+ if (r < 0) {
mutex_unlock(&smd_pkt_devp->tx_lock);
- if (smd_pkt_devp->has_reset)
- return notify_reset(smd_pkt_devp);
-
- printk(KERN_ERR "ERROR:%s:%i:%s: "
- "smd_write(ch,buf,count = %i) ret %i.\n",
- __FILE__,
- __LINE__,
- __func__,
- count,
- r);
+ pr_err("%s: Error %d @ smd_write_start\n", __func__, r);
return r;
}
+
+ bytes_written = 0;
+ do {
+ prepare_to_wait(&smd_pkt_devp->ch_write_wait_queue,
+ &write_wait, TASK_UNINTERRUPTIBLE);
+ if (!smd_write_avail(smd_pkt_devp->ch) &&
+ !smd_pkt_devp->has_reset) {
+ smd_enable_read_intr(smd_pkt_devp->ch);
+ schedule();
+ }
+ finish_wait(&smd_pkt_devp->ch_write_wait_queue, &write_wait);
+ smd_disable_read_intr(smd_pkt_devp->ch);
+
+ if (smd_pkt_devp->has_reset) {
+ mutex_unlock(&smd_pkt_devp->tx_lock);
+ return notify_reset(smd_pkt_devp);
+ } else {
+ r = smd_write_segment(smd_pkt_devp->ch,
+ (void *)(buf + bytes_written),
+ (count - bytes_written), 1);
+ if (r < 0) {
+ mutex_unlock(&smd_pkt_devp->tx_lock);
+ if (smd_pkt_devp->has_reset)
+ return notify_reset(smd_pkt_devp);
+ }
+ bytes_written += r;
+ }
+ } while (bytes_written != count);
+ smd_write_end(smd_pkt_devp->ch);
mutex_unlock(&smd_pkt_devp->tx_lock);
D(KERN_ERR "%s: just wrote %i bytes\n",
@@ -451,11 +422,11 @@
return;
sz = smd_write_avail(smd_pkt_devp->ch);
- if (sz >= smd_pkt_devp->needed_space) {
+ if (sz) {
D(KERN_ERR "%s: %d bytes Write Space available\n",
__func__, sz);
smd_disable_read_intr(smd_pkt_devp->ch);
- wake_up_interruptible(&smd_pkt_devp->ch_write_wait_queue);
+ wake_up(&smd_pkt_devp->ch_write_wait_queue);
}
}
diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c
index 6f151cb..dc6ba5c 100644
--- a/arch/arm/mach-msm/smd_tty.c
+++ b/arch/arm/mach-msm/smd_tty.c
@@ -98,7 +98,15 @@
static void buf_req_retry(unsigned long param)
{
struct smd_tty_info *info = (struct smd_tty_info *)param;
- tasklet_hi_schedule(&info->tty_tsklt);
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->reset_lock, flags);
+ if (info->is_open) {
+ spin_unlock_irqrestore(&info->reset_lock, flags);
+ tasklet_hi_schedule(&info->tty_tsklt);
+ return;
+ }
+ spin_unlock_irqrestore(&info->reset_lock, flags);
}
static void smd_tty_read(unsigned long param)
@@ -163,6 +171,12 @@
switch (event) {
case SMD_EVENT_DATA:
+ spin_lock_irqsave(&info->reset_lock, flags);
+ if (!info->is_open) {
+ spin_unlock_irqrestore(&info->reset_lock, flags);
+ break;
+ }
+ spin_unlock_irqrestore(&info->reset_lock, flags);
/* There may be clients (tty framework) that are blocked
* waiting for space to write data, so if a possible read
* interrupt came in wake anyone waiting and disable the
@@ -323,12 +337,16 @@
static void smd_tty_close(struct tty_struct *tty, struct file *f)
{
struct smd_tty_info *info = tty->driver_data;
+ unsigned long flags;
if (info == 0)
return;
mutex_lock(&smd_tty_lock);
if (--info->open_count == 0) {
+ spin_lock_irqsave(&info->reset_lock, flags);
+ info->is_open = 0;
+ spin_unlock_irqrestore(&info->reset_lock, flags);
if (info->tty) {
tasklet_kill(&info->tty_tsklt);
wake_lock_destroy(&info->wake_lock);
@@ -386,8 +404,15 @@
static void smd_tty_unthrottle(struct tty_struct *tty)
{
struct smd_tty_info *info = tty->driver_data;
- tasklet_hi_schedule(&info->tty_tsklt);
- return;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->reset_lock, flags);
+ if (info->is_open) {
+ spin_unlock_irqrestore(&info->reset_lock, flags);
+ tasklet_hi_schedule(&info->tty_tsklt);
+ return;
+ }
+ spin_unlock_irqrestore(&info->reset_lock, flags);
}
/*
@@ -542,8 +567,6 @@
* Only register the platform driver for targets older than that.
*/
if (cpu_is_msm7x01() || cpu_is_msm7x25() || cpu_is_msm7x27() ||
- cpu_is_msm7x27a() || cpu_is_msm7x27aa() ||
- cpu_is_msm7x25a() || cpu_is_msm7x25aa() ||
cpu_is_msm7x30() || cpu_is_qsd8x50() ||
cpu_is_msm8x55() || (cpu_is_msm8x60() &&
socinfo_get_platform_subtype() == 0x1)) {
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 96a4563..87b6d3f 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -31,6 +31,7 @@
HW_PLATFORM_FLUID = 3,
HW_PLATFORM_SVLTE_FFA = 4,
HW_PLATFORM_SVLTE_SURF = 5,
+ HW_PLATFORM_LIQUID = 9,
/* Dragonboard platform id is assigned as 10 in CDT */
HW_PLATFORM_DRAGON = 10,
HW_PLATFORM_INVALID
@@ -41,6 +42,7 @@
[HW_PLATFORM_SURF] = "Surf",
[HW_PLATFORM_FFA] = "FFA",
[HW_PLATFORM_FLUID] = "Fluid",
+ [HW_PLATFORM_LIQUID] = "Liquid",
[HW_PLATFORM_SVLTE_FFA] = "SVLTE_FFA",
[HW_PLATFORM_SVLTE_SURF] = "SLVTE_SURF",
[HW_PLATFORM_DRAGON] = "Dragon"
@@ -215,6 +217,13 @@
/* 8930 IDs */
[116] = MSM_CPU_8930,
+ [117] = MSM_CPU_8930,
+ [118] = MSM_CPU_8930,
+ [119] = MSM_CPU_8930,
+
+ /* 8627 IDs */
+ [120] = MSM_CPU_8627,
+ [121] = MSM_CPU_8627,
/* 8660A ID */
[122] = MSM_CPU_8960,
diff --git a/arch/arm/mach-msm/subsystem_map.c b/arch/arm/mach-msm/subsystem_map.c
index db9ab30..b5ff244 100644
--- a/arch/arm/mach-msm/subsystem_map.c
+++ b/arch/arm/mach-msm/subsystem_map.c
@@ -440,6 +440,9 @@
int i, j, ret;
unsigned long temp_va;
+ if (IS_ERR_OR_NULL(buf))
+ goto out;
+
if (buf->vaddr)
node = find_buffer(buf->vaddr);
else
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 37469f8..78a6203 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -445,8 +445,8 @@
return -EINVAL;
}
- pr_info("Restart sequence requested for %s\n",
- subsys_name);
+ pr_info("Restart sequence requested for %s, restart_level = %d.\n",
+ subsys_name, restart_level);
/* List of subsystems is protected by a lock. New subsystems can
* still come in.
@@ -497,7 +497,8 @@
break;
case RESET_SOC:
- panic("subsys-restart: Resetting the SoC");
+ panic("subsys-restart: Resetting the SoC - %s crashed.",
+ subsys->name);
break;
default:
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 8f24d81..90a1c7e 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -235,11 +235,14 @@
t1 = __raw_readl(addr);
t2 = __raw_readl(addr);
t3 = __raw_readl(addr);
+ cpu_relax();
if ((t3-t2) <= 1)
return t3;
if ((t2-t1) <= 1)
return t2;
- if (++loop_count == 10) {
+ if ((t2 >= t1) && (t3 >= t2))
+ return t2;
+ if (++loop_count == 5) {
pr_err("msm_read_timer_count timer %s did not "
"stabilize: %u -> %u -> %u\n",
clock->clockevent.name, t1, t2, t3);
@@ -1017,12 +1020,13 @@
gpt->freq = 32765;
gpt_hz = 32765;
sclk_hz = 32765;
- gpt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
- dgt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
+ if (!machine_is_apq8064_rumi3()) {
+ gpt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
+ dgt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
+ }
} else {
WARN_ON("Timer running on unknown hardware. Configure this! "
"Assuming default configuration.\n");
- global_timer_offset = MSM_TMR0_BASE - MSM_TMR_BASE;
dgt->freq = 6750000;
}
diff --git a/arch/arm/mach-msm/tz_log.c b/arch/arm/mach-msm/tz_log.c
new file mode 100644
index 0000000..8d7196b
--- /dev/null
+++ b/arch/arm/mach-msm/tz_log.c
@@ -0,0 +1,559 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/debugfs.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <asm/uaccess.h>
+
+#define DEBUG_MAX_RW_BUF 4096
+
+/*
+ * Preprocessor Definitions and Constants
+ */
+#define TZBSP_CPU_COUNT 0x02
+/*
+ * Number of VMID Tables
+ */
+#define TZBSP_DIAG_NUM_OF_VMID 16
+/*
+ * VMID Description length
+ */
+#define TZBSP_DIAG_VMID_DESC_LEN 7
+/*
+ * Number of Interrupts
+ */
+#define TZBSP_DIAG_INT_NUM 32
+/*
+ * Length of descriptive name associated with Interrupt
+ */
+#define TZBSP_MAX_INT_DESC 16
+/*
+ * VMID Table
+ */
+struct tzdbg_vmid_t {
+ uint8_t vmid; /* Virtual Machine Identifier */
+ uint8_t desc[TZBSP_DIAG_VMID_DESC_LEN]; /* ASCII Text */
+};
+/*
+ * Boot Info Table
+ */
+struct tzdbg_boot_info_t {
+ uint32_t entry_cnt; /* Warmboot entry CPU Counter */
+ uint32_t exit_cnt; /* Warmboot exit CPU Counter */
+ uint32_t warm_jmp_addr; /* Last Warmboot Jump Address */
+ uint32_t spare; /* Reserved for future use. */
+};
+/*
+ * Reset Info Table
+ */
+struct tzdbg_reset_info_t {
+ uint32_t reset_type; /* Reset Reason */
+ uint32_t reset_cnt; /* Number of resets occured/CPU */
+};
+/*
+ * Interrupt Info Table
+ */
+struct tzdbg_int_t {
+ /*
+ * Type of Interrupt/exception
+ */
+ uint16_t int_info;
+ /*
+ * Availability of the slot
+ */
+ uint8_t avail;
+ /*
+ * Reserved for future use
+ */
+ uint8_t spare;
+ /*
+ * Interrupt # for IRQ and FIQ
+ */
+ uint32_t int_num;
+ /*
+ * ASCII text describing type of interrupt e.g:
+ * Secure Timer, EBI XPU. This string is always null terminated,
+ * supporting at most TZBSP_MAX_INT_DESC characters.
+ * Any additional characters are truncated.
+ */
+ uint8_t int_desc[TZBSP_MAX_INT_DESC];
+ uint64_t int_count[TZBSP_CPU_COUNT]; /* # of times seen per CPU */
+};
+/*
+ * Diagnostic Table
+ */
+struct tzdbg_t {
+ uint32_t magic_num;
+ uint32_t version;
+ /*
+ * Number of CPU's
+ */
+ uint32_t cpu_count;
+ /*
+ * Offset of VMID Table
+ */
+ uint32_t vmid_info_off;
+ /*
+ * Offset of Boot Table
+ */
+ uint32_t boot_info_off;
+ /*
+ * Offset of Reset info Table
+ */
+ uint32_t reset_info_off;
+ /*
+ * Offset of Interrupt info Table
+ */
+ uint32_t int_info_off;
+ /*
+ * Ring Buffer Offset
+ */
+ uint32_t ring_off;
+ /*
+ * Ring Buffer Length
+ */
+ uint32_t ring_len;
+ /*
+ * VMID to EE Mapping
+ */
+ struct tzdbg_vmid_t vmid_info[TZBSP_DIAG_NUM_OF_VMID];
+ /*
+ * Boot Info
+ */
+ struct tzdbg_boot_info_t boot_info[TZBSP_CPU_COUNT];
+ /*
+ * Reset Info
+ */
+ struct tzdbg_reset_info_t reset_info[TZBSP_CPU_COUNT];
+ uint32_t num_interrupts;
+ struct tzdbg_int_t int_info[TZBSP_DIAG_INT_NUM];
+ /*
+ * We need at least 2K for the ring buffer
+ */
+ uint8_t *ring_buffer; /* TZ Ring Buffer */
+};
+
+/*
+ * Enumeration order for VMID's
+ */
+enum tzdbg_stats_type {
+ TZDBG_BOOT = 0,
+ TZDBG_RESET,
+ TZDBG_INTERRUPT,
+ TZDBG_VMID,
+ TZDBG_GENERAL,
+ TZDBG_LOG,
+ TZDBG_STATS_MAX,
+};
+
+struct tzdbg_stat {
+ char *name;
+ char *data;
+};
+
+struct tzdbg {
+ void __iomem *virt_iobase;
+ struct tzdbg_t *diag_buf;
+ char *disp_buf;
+ int debug_tz[TZDBG_STATS_MAX];
+ struct tzdbg_stat stat[TZDBG_STATS_MAX];
+};
+
+static struct tzdbg tzdbg = {
+
+ .stat[TZDBG_BOOT].name = "boot",
+ .stat[TZDBG_RESET].name = "reset",
+ .stat[TZDBG_INTERRUPT].name = "interrupt",
+ .stat[TZDBG_VMID].name = "vmid",
+ .stat[TZDBG_GENERAL].name = "general",
+ .stat[TZDBG_LOG].name = "log",
+};
+
+
+/*
+ * Debugfs data structure and functions
+ */
+
+static int _disp_tz_general_stats(void)
+{
+ int len = 0;
+
+ len += snprintf(tzdbg.disp_buf + len, DEBUG_MAX_RW_BUF - 1,
+ " Version : 0x%x\n"
+ " Magic Number : 0x%x\n"
+ " Number of CPU : %d\n",
+ tzdbg.diag_buf->version,
+ tzdbg.diag_buf->magic_num,
+ tzdbg.diag_buf->cpu_count);
+ tzdbg.stat[TZDBG_GENERAL].data = tzdbg.disp_buf;
+ return len;
+}
+
+static int _disp_tz_vmid_stats(void)
+{
+ int i, num_vmid;
+ int len = 0;
+ struct tzdbg_vmid_t *ptr;
+
+ ptr = (struct tzdbg_vmid_t *)((unsigned char *)tzdbg.diag_buf +
+ tzdbg.diag_buf->vmid_info_off);
+ num_vmid = ((tzdbg.diag_buf->boot_info_off -
+ tzdbg.diag_buf->vmid_info_off)/
+ (sizeof(struct tzdbg_vmid_t)));
+
+ for (i = 0; i < num_vmid; i++) {
+ if (ptr->vmid < 0xFF) {
+ len += snprintf(tzdbg.disp_buf + len,
+ (DEBUG_MAX_RW_BUF - 1) - len,
+ " 0x%x %s\n",
+ (uint32_t)ptr->vmid, (uint8_t *)ptr->desc);
+ }
+ if (len > (DEBUG_MAX_RW_BUF - 1)) {
+ pr_warn("%s: Cannot fit all info into the buffer\n",
+ __func__);
+ break;
+ }
+ ptr++;
+ }
+
+ tzdbg.stat[TZDBG_VMID].data = tzdbg.disp_buf;
+ return len;
+}
+
+static int _disp_tz_boot_stats(void)
+{
+ int i;
+ int len = 0;
+ struct tzdbg_boot_info_t *ptr;
+
+ ptr = (struct tzdbg_boot_info_t *)((unsigned char *)tzdbg.diag_buf +
+ tzdbg.diag_buf->boot_info_off);
+
+ for (i = 0; i < tzdbg.diag_buf->cpu_count; i++) {
+ len += snprintf(tzdbg.disp_buf + len,
+ (DEBUG_MAX_RW_BUF - 1) - len,
+ " CPU #: %d\n"
+ " Warmboot jump address : 0x%x\n"
+ " Warmboot entry CPU counter: 0x%x\n"
+ " Warmboot exit CPU counter : 0x%x\n",
+ i, ptr->warm_jmp_addr, ptr->entry_cnt,
+ ptr->exit_cnt);
+
+ if (len > (DEBUG_MAX_RW_BUF - 1)) {
+ pr_warn("%s: Cannot fit all info into the buffer\n",
+ __func__);
+ break;
+ }
+ ptr++;
+ }
+ tzdbg.stat[TZDBG_BOOT].data = tzdbg.disp_buf;
+ return len;
+}
+
+static int _disp_tz_reset_stats(void)
+{
+ int i;
+ int len = 0;
+ struct tzdbg_reset_info_t *ptr;
+
+ ptr = (struct tzdbg_reset_info_t *)((unsigned char *)tzdbg.diag_buf +
+ tzdbg.diag_buf->reset_info_off);
+
+ for (i = 0; i < tzdbg.diag_buf->cpu_count; i++) {
+ len += snprintf(tzdbg.disp_buf + len,
+ (DEBUG_MAX_RW_BUF - 1) - len,
+ " CPU #: %d\n"
+ " Reset Type (reason) : 0x%x\n"
+ " Reset counter : 0x%x\n",
+ i, ptr->reset_type, ptr->reset_cnt);
+
+ if (len > (DEBUG_MAX_RW_BUF - 1)) {
+ pr_warn("%s: Cannot fit all info into the buffer\n",
+ __func__);
+ break;
+ }
+
+ ptr++;
+ }
+ tzdbg.stat[TZDBG_RESET].data = tzdbg.disp_buf;
+ return len;
+}
+
+static int _disp_tz_interrupt_stats(void)
+{
+ int i, j, int_info_size;
+ int len = 0;
+ int *num_int;
+ unsigned char *ptr;
+ struct tzdbg_int_t *tzdbg_ptr;
+
+ num_int = (uint32_t *)((unsigned char *)tzdbg.diag_buf +
+ (tzdbg.diag_buf->int_info_off - sizeof(uint32_t)));
+ ptr = ((unsigned char *)tzdbg.diag_buf +
+ tzdbg.diag_buf->int_info_off);
+ int_info_size = ((tzdbg.diag_buf->ring_off -
+ tzdbg.diag_buf->int_info_off)/(*num_int));
+
+ for (i = 0; i < (*num_int); i++) {
+ tzdbg_ptr = (struct tzdbg_int_t *)ptr;
+ len += snprintf(tzdbg.disp_buf + len,
+ (DEBUG_MAX_RW_BUF - 1) - len,
+ " Interrupt Number : 0x%x\n"
+ " Type of Interrupt : 0x%x\n"
+ " Description of interrupt : %s\n",
+ tzdbg_ptr->int_num,
+ (uint32_t)tzdbg_ptr->int_info,
+ (uint8_t *)tzdbg_ptr->int_desc);
+ for (j = 0; j < tzdbg.diag_buf->cpu_count; j++) {
+ len += snprintf(tzdbg.disp_buf + len,
+ (DEBUG_MAX_RW_BUF - 1) - len,
+ " int_count on CPU # %d : %u\n",
+ (uint32_t)j,
+ (uint32_t)tzdbg_ptr->int_count[j]);
+ }
+ len += snprintf(tzdbg.disp_buf + len, DEBUG_MAX_RW_BUF - 1,
+ "\n");
+
+ if (len > (DEBUG_MAX_RW_BUF - 1)) {
+ pr_warn("%s: Cannot fit all info into the buffer\n",
+ __func__);
+ break;
+ }
+
+ ptr += int_info_size;
+ }
+ tzdbg.stat[TZDBG_INTERRUPT].data = tzdbg.disp_buf;
+ return len;
+}
+
+static int _disp_tz_log_stats(void)
+{
+ int len = 0;
+ unsigned char *ptr;
+
+ ptr = (unsigned char *)tzdbg.diag_buf +
+ tzdbg.diag_buf->ring_off;
+ len += snprintf(tzdbg.disp_buf, (DEBUG_MAX_RW_BUF - 1) - len,
+ "%s\n", ptr);
+
+ tzdbg.stat[TZDBG_LOG].data = tzdbg.disp_buf;
+ return len;
+}
+
+static ssize_t tzdbgfs_read(struct file *file, char __user *buf,
+ size_t count, loff_t *offp)
+{
+ int len = 0;
+ int *tz_id = file->private_data;
+
+ memcpy_fromio((void *)tzdbg.diag_buf, tzdbg.virt_iobase,
+ DEBUG_MAX_RW_BUF);
+ switch (*tz_id) {
+ case TZDBG_BOOT:
+ len = _disp_tz_boot_stats();
+ break;
+ case TZDBG_RESET:
+ len = _disp_tz_reset_stats();
+ break;
+ case TZDBG_INTERRUPT:
+ len = _disp_tz_interrupt_stats();
+ break;
+ case TZDBG_GENERAL:
+ len = _disp_tz_general_stats();
+ break;
+ case TZDBG_VMID:
+ len = _disp_tz_vmid_stats();
+ break;
+ case TZDBG_LOG:
+ len = _disp_tz_log_stats();
+ break;
+ default:
+ break;
+ }
+
+ if (len > count)
+ len = count;
+
+ return simple_read_from_buffer(buf, len, offp,
+ tzdbg.stat[(*tz_id)].data, len);
+}
+
+static int tzdbgfs_open(struct inode *inode, struct file *pfile)
+{
+ pfile->private_data = inode->i_private;
+ return 0;
+}
+
+const struct file_operations tzdbg_fops = {
+ .owner = THIS_MODULE,
+ .read = tzdbgfs_read,
+ .open = tzdbgfs_open,
+};
+
+static int tzdbgfs_init(struct platform_device *pdev)
+{
+ int rc = 0;
+ int i;
+ struct dentry *dent_dir;
+ struct dentry *dent;
+
+ dent_dir = debugfs_create_dir("tzdbg", NULL);
+ if (dent_dir == NULL) {
+ dev_err(&pdev->dev, "tzdbg debugfs_create_dir failed\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < TZDBG_STATS_MAX; i++) {
+ tzdbg.debug_tz[i] = i;
+ dent = debugfs_create_file(tzdbg.stat[i].name,
+ S_IRUGO, dent_dir,
+ &tzdbg.debug_tz[i], &tzdbg_fops);
+ if (dent == NULL) {
+ dev_err(&pdev->dev, "TZ debugfs_create_file failed\n");
+ rc = -ENOMEM;
+ goto err;
+ }
+ }
+ tzdbg.disp_buf = kzalloc(DEBUG_MAX_RW_BUF, GFP_KERNEL);
+ if (tzdbg.disp_buf == NULL) {
+ pr_err("%s: Can't Allocate memory for tzdbg.disp_buf\n",
+ __func__);
+
+ goto err;
+ }
+ platform_set_drvdata(pdev, dent_dir);
+ return 0;
+err:
+ debugfs_remove_recursive(dent_dir);
+
+ return rc;
+}
+
+static void tzdbgfs_exit(struct platform_device *pdev)
+{
+ struct dentry *dent_dir;
+
+ kzfree(tzdbg.disp_buf);
+ dent_dir = platform_get_drvdata(pdev);
+ debugfs_remove_recursive(dent_dir);
+}
+
+/*
+ * Driver functions
+ */
+static int __devinit tz_log_probe(struct platform_device *pdev)
+{
+ struct resource *resource;
+ void __iomem *virt_iobase;
+ uint32_t tzdiag_phy_iobase;
+ uint32_t *ptr = NULL;
+
+ /*
+ * Get address that stores the physical location of 4KB
+ * diagnostic data
+ */
+ resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!resource) {
+ dev_err(&pdev->dev,
+ "%s: ERROR Missing MEM resource\n", __func__);
+ return -ENXIO;
+ };
+ /*
+ * Map address that stores the physical location of 4KB
+ * diagnostic data
+ */
+ virt_iobase = devm_ioremap_nocache(&pdev->dev, resource->start,
+ resource->end - resource->start + 1);
+ if (!virt_iobase) {
+ dev_err(&pdev->dev,
+ "%s: ERROR could not ioremap: start=%p, len=%u\n",
+ __func__, (void *) resource->start,
+ (resource->end - resource->start + 1));
+ return -ENXIO;
+ }
+ /*
+ * Retrieve the address of 4KB diagnostic data
+ */
+ tzdiag_phy_iobase = readl_relaxed(virt_iobase);
+
+ /*
+ * Map the 4KB diagnostic information area
+ */
+ tzdbg.virt_iobase = devm_ioremap_nocache(&pdev->dev,
+ tzdiag_phy_iobase, DEBUG_MAX_RW_BUF);
+
+ if (!tzdbg.virt_iobase) {
+ dev_err(&pdev->dev,
+ "%s: ERROR could not ioremap: start=%p, len=%u\n",
+ __func__, (void *) tzdiag_phy_iobase, DEBUG_MAX_RW_BUF);
+ return -ENXIO;
+ }
+
+ ptr = kzalloc(DEBUG_MAX_RW_BUF, GFP_KERNEL);
+ if (ptr == NULL) {
+ pr_err("%s: Can't Allocate memory: ptr\n",
+ __func__);
+ return -ENXIO;
+ }
+
+ tzdbg.diag_buf = (struct tzdbg_t *)ptr;
+
+ if (tzdbgfs_init(pdev))
+ goto err;
+
+ return 0;
+err:
+ kfree(tzdbg.diag_buf);
+ return -ENXIO;
+}
+
+
+static int __devexit tz_log_remove(struct platform_device *pdev)
+{
+ kzfree(tzdbg.diag_buf);
+ tzdbgfs_exit(pdev);
+
+ return 0;
+}
+
+static struct platform_driver tz_log_driver = {
+ .probe = tz_log_probe,
+ .remove = __devexit_p(tz_log_remove),
+ .driver = {
+ .name = "tz_log",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init tz_log_init(void)
+{
+ return platform_driver_register(&tz_log_driver);
+}
+
+static void __exit tz_log_exit(void)
+{
+ platform_driver_unregister(&tz_log_driver);
+}
+
+module_init(tz_log_init);
+module_exit(tz_log_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TZ Log driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:tz_log");
diff --git a/arch/arm/mach-msm/vreg.c b/arch/arm/mach-msm/vreg.c
index 8f782a9..cffa5c7 100644
--- a/arch/arm/mach-msm/vreg.c
+++ b/arch/arm/mach-msm/vreg.c
@@ -18,7 +18,12 @@
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/atomic.h>
#include <linux/debugfs.h>
+#include <linux/regulator/consumer.h>
#include <linux/string.h>
#include <mach/vreg.h>
@@ -33,173 +38,187 @@
#endif
struct vreg {
- const char *name;
- unsigned id;
- int status;
- unsigned refcnt;
+ struct list_head list;
+ struct mutex lock;
+ const char *name;
+ u64 refcnt;
+ unsigned mv;
+ struct regulator *reg;
};
-#define VREG(_name, _id, _status, _refcnt) \
- { .name = _name, .id = _id, .status = _status, .refcnt = _refcnt }
+static LIST_HEAD(vreg_list);
+static DEFINE_MUTEX(vreg_lock);
-static struct vreg vregs[] = {
- VREG("msma", 0, 0, 0),
- VREG("msmp", 1, 0, 0),
- VREG("msme1", 2, 0, 0),
- VREG("msmc1", 3, 0, 0),
- VREG("msmc2", 4, 0, 0),
- VREG("gp3", 5, 0, 0),
- VREG("msme2", 6, 0, 0),
- VREG("gp4", 7, 0, 0),
- VREG("gp1", 8, 0, 0),
- VREG("tcxo", 9, 0, 0),
- VREG("pa", 10, 0, 0),
- VREG("rftx", 11, 0, 0),
- VREG("rfrx1", 12, 0, 0),
- VREG("rfrx2", 13, 0, 0),
- VREG("synt", 14, 0, 0),
- VREG("wlan", 15, 0, 0),
- VREG("usb", 16, 0, 0),
- VREG("boost", 17, 0, 0),
- VREG("mmc", 18, 0, 0),
- VREG("ruim", 19, 0, 0),
- VREG("msmc0", 20, 0, 0),
- VREG("gp2", 21, 0, 0),
- VREG("gp5", 22, 0, 0),
- VREG("gp6", 23, 0, 0),
- VREG("rf", 24, 0, 0),
- VREG("rf_vco", 26, 0, 0),
- VREG("mpll", 27, 0, 0),
- VREG("s2", 28, 0, 0),
- VREG("s3", 29, 0, 0),
- VREG("rfubm", 30, 0, 0),
- VREG("ncp", 31, 0, 0),
- VREG("gp7", 32, 0, 0),
- VREG("gp8", 33, 0, 0),
- VREG("gp9", 34, 0, 0),
- VREG("gp10", 35, 0, 0),
- VREG("gp11", 36, 0, 0),
- VREG("gp12", 37, 0, 0),
- VREG("gp13", 38, 0, 0),
- VREG("gp14", 39, 0, 0),
- VREG("gp15", 40, 0, 0),
- VREG("gp16", 41, 0, 0),
- VREG("gp17", 42, 0, 0),
- VREG("s4", 43, 0, 0),
- VREG("usb2", 44, 0, 0),
- VREG("wlan2", 45, 0, 0),
- VREG("xo_out", 46, 0, 0),
- VREG("lvsw0", 47, 0, 0),
- VREG("lvsw1", 48, 0, 0),
- VREG("mddi", 49, 0, 0),
- VREG("pllx", 50, 0, 0),
- VREG("wlan3", 51, 0, 0),
- VREG("emmc", 52, 0, 0),
- VREG("wlan_tcx0", 53, 0, 0),
- VREG("usim2", 54, 0, 0),
- VREG("usim", 55, 0, 0),
- VREG("bt", 56, 0, 0),
- VREG("wlan4", 57, 0, 0),
-};
+#ifdef CONFIG_DEBUG_FS
+static void vreg_add_debugfs(struct vreg *vreg);
+#else
+static inline void vreg_add_debugfs(struct vreg *vreg) { }
+#endif
+
+static struct vreg *vreg_create(const char *id)
+{
+ int rc;
+ struct vreg *vreg;
+
+ vreg = kzalloc(sizeof(*vreg), GFP_KERNEL);
+ if (!vreg) {
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ INIT_LIST_HEAD(&vreg->list);
+ mutex_init(&vreg->lock);
+
+ vreg->reg = regulator_get(NULL, id);
+ if (IS_ERR(vreg->reg)) {
+ rc = PTR_ERR(vreg->reg);
+ goto free_vreg;
+ }
+
+ vreg->name = kstrdup(id, GFP_KERNEL);
+ if (!vreg->name) {
+ rc = -ENOMEM;
+ goto put_reg;
+ }
+
+ list_add_tail(&vreg->list, &vreg_list);
+ vreg_add_debugfs(vreg);
+
+ return vreg;
+
+put_reg:
+ regulator_put(vreg->reg);
+free_vreg:
+ kfree(vreg);
+error:
+ return ERR_PTR(rc);
+}
+
+static void vreg_destroy(struct vreg *vreg)
+{
+ if (!vreg)
+ return;
+
+ if (vreg->refcnt)
+ regulator_disable(vreg->reg);
+
+ kfree(vreg->name);
+ regulator_put(vreg->reg);
+ kfree(vreg);
+}
struct vreg *vreg_get(struct device *dev, const char *id)
{
- int n;
- for (n = 0; n < ARRAY_SIZE(vregs); n++) {
- if (!strcmp(vregs[n].name, id))
- return vregs + n;
+ struct vreg *vreg = NULL;
+
+ if (!id)
+ return ERR_PTR(-EINVAL);
+
+ mutex_lock(&vreg_lock);
+ list_for_each_entry(vreg, &vreg_list, list) {
+ if (!strncmp(vreg->name, id, 10))
+ goto ret;
}
- return ERR_PTR(-ENOENT);
+
+ vreg = vreg_create(id);
+
+ret:
+ mutex_unlock(&vreg_lock);
+ return vreg;
}
EXPORT_SYMBOL(vreg_get);
void vreg_put(struct vreg *vreg)
{
+ kfree(vreg->name);
+ regulator_put(vreg->reg);
}
int vreg_enable(struct vreg *vreg)
{
- unsigned id = vreg->id;
- int enable = VREG_SWITCH_ENABLE;
+ int rc = 0;
+ if (!vreg)
+ return -ENODEV;
- if (vreg->refcnt == 0)
- vreg->status = msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable);
+ mutex_lock(&vreg->lock);
+ if (vreg->refcnt == 0) {
+ rc = regulator_enable(vreg->reg);
+ if (!rc)
+ vreg->refcnt++;
+ } else {
+ rc = 0;
+ if (vreg->refcnt < UINT_MAX)
+ vreg->refcnt++;
+ }
+ mutex_unlock(&vreg->lock);
- if ((vreg->refcnt < UINT_MAX) && (!vreg->status))
- vreg->refcnt++;
-
- return vreg->status;
+ return rc;
}
EXPORT_SYMBOL(vreg_enable);
int vreg_disable(struct vreg *vreg)
{
- unsigned id = vreg->id;
- int disable = VREG_SWITCH_DISABLE;
+ int rc = 0;
+ if (!vreg)
+ return -ENODEV;
- if (!vreg->refcnt)
- return 0;
-
- if (vreg->refcnt == 1)
- vreg->status = msm_proc_comm(PCOM_VREG_SWITCH, &id, &disable);
-
- if (!vreg->status)
+ mutex_lock(&vreg->lock);
+ if (vreg->refcnt == 0) {
+ pr_warn("%s: unbalanced disables for vreg %s\n",
+ __func__, vreg->name);
+ rc = -EINVAL;
+ } else if (vreg->refcnt == 1) {
+ rc = regulator_disable(vreg->reg);
+ if (!rc)
+ vreg->refcnt--;
+ } else {
+ rc = 0;
vreg->refcnt--;
+ }
+ mutex_unlock(&vreg->lock);
- return vreg->status;
+ return rc;
}
EXPORT_SYMBOL(vreg_disable);
int vreg_set_level(struct vreg *vreg, unsigned mv)
{
- unsigned id = vreg->id;
+ unsigned uv;
+ int rc;
- vreg->status = msm_proc_comm(PCOM_VREG_SET_LEVEL, &id, &mv);
- return vreg->status;
+ if (!vreg)
+ return -EINVAL;
+
+ if (mv > (UINT_MAX / 1000))
+ return -ERANGE;
+
+ uv = mv * 1000;
+
+ mutex_lock(&vreg->lock);
+ rc = regulator_set_voltage(vreg->reg, uv, uv);
+ if (!rc)
+ vreg->mv = mv;
+ mutex_unlock(&vreg->lock);
+
+ return rc;
}
EXPORT_SYMBOL(vreg_set_level);
#if defined(CONFIG_DEBUG_FS)
-static int vreg_debug_set(void *data, u64 val)
-{
- struct vreg *vreg = data;
- switch (val) {
- case 0:
- vreg_disable(vreg);
- break;
- case 1:
- vreg_enable(vreg);
- break;
- default:
- vreg_set_level(vreg, val);
- break;
- }
- return 0;
-}
-
-static int vreg_debug_get(void *data, u64 *val)
+static int vreg_debug_enabled_set(void *data, u64 val)
{
struct vreg *vreg = data;
- if (!vreg->status)
- *val = 0;
+ if (val == 0)
+ return vreg_disable(vreg);
+ else if (val == 1)
+ return vreg_enable(vreg);
else
- *val = 1;
-
- return 0;
+ return -EINVAL;
}
-static int vreg_debug_count_set(void *data, u64 val)
-{
- struct vreg *vreg = data;
- if (val > UINT_MAX)
- val = UINT_MAX;
- vreg->refcnt = val;
- return 0;
-}
-
-static int vreg_debug_count_get(void *data, u64 *val)
+static int vreg_debug_enabled_get(void *data, u64 *val)
{
struct vreg *vreg = data;
@@ -208,33 +227,97 @@
return 0;
}
-DEFINE_SIMPLE_ATTRIBUTE(vreg_fops, vreg_debug_get, vreg_debug_set, "%llu\n");
-DEFINE_SIMPLE_ATTRIBUTE(vreg_count_fops, vreg_debug_count_get,
- vreg_debug_count_set, "%llu\n");
-
-static int __init vreg_debug_init(void)
+static int vreg_debug_voltage_set(void *data, u64 val)
{
- struct dentry *dent;
- int n;
- char name[32];
- const char *refcnt_name = "_refcnt";
+ struct vreg *vreg = data;
+ return vreg_set_level(vreg, val);
+}
- dent = debugfs_create_dir("vreg", 0);
- if (IS_ERR(dent))
- return 0;
+static int vreg_debug_voltage_get(void *data, u64 *val)
+{
+ struct vreg *vreg = data;
+ *val = vreg->mv;
+ return 0;
+}
- for (n = 0; n < ARRAY_SIZE(vregs); n++) {
- (void) debugfs_create_file(vregs[n].name, 0644,
- dent, vregs + n, &vreg_fops);
+DEFINE_SIMPLE_ATTRIBUTE(vreg_debug_enabled, vreg_debug_enabled_get,
+ vreg_debug_enabled_set, "%llu");
+DEFINE_SIMPLE_ATTRIBUTE(vreg_debug_voltage, vreg_debug_voltage_get,
+ vreg_debug_voltage_set, "%llu");
- strlcpy(name, vregs[n].name, sizeof(name));
- strlcat(name, refcnt_name, sizeof(name));
- (void) debugfs_create_file(name, 0644,
- dent, vregs + n, &vreg_count_fops);
+static struct dentry *root;
+
+static void vreg_add_debugfs(struct vreg *vreg)
+{
+ struct dentry *dir;
+
+ if (!root)
+ return;
+
+ dir = debugfs_create_dir(vreg->name, root);
+
+ if (IS_ERR_OR_NULL(dir))
+ goto err;
+
+ if (IS_ERR_OR_NULL(debugfs_create_file("enabled", 0644, dir, vreg,
+ &vreg_debug_enabled)))
+ goto destroy;
+
+ if (IS_ERR_OR_NULL(debugfs_create_file("voltage", 0644, dir, vreg,
+ &vreg_debug_voltage)))
+ goto destroy;
+
+ return;
+
+destroy:
+ debugfs_remove_recursive(dir);
+err:
+ pr_warn("%s: could not create debugfs for vreg %s\n",
+ __func__, vreg->name);
+}
+
+static int __devinit vreg_debug_init(void)
+{
+ root = debugfs_create_dir("vreg", NULL);
+
+ if (IS_ERR_OR_NULL(root)) {
+ pr_debug("%s: error initializing debugfs: %ld - "
+ "disabling debugfs\n",
+ __func__, root ? PTR_ERR(root) : 0);
+ root = NULL;
}
return 0;
}
-
-device_initcall(vreg_debug_init);
+static void __devexit vreg_debug_exit(void)
+{
+ if (root)
+ debugfs_remove_recursive(root);
+ root = NULL;
+}
+#else
+static inline int __init vreg_debug_init(void) { return 0; }
+static inline void __exit vreg_debug_exit(void) { return 0; }
#endif
+
+static int __init vreg_init(void)
+{
+ return vreg_debug_init();
+}
+module_init(vreg_init);
+
+static void __exit vreg_exit(void)
+{
+ struct vreg *vreg, *next;
+ vreg_debug_exit();
+
+ mutex_lock(&vreg_lock);
+ list_for_each_entry_safe(vreg, next, &vreg_list, list)
+ vreg_destroy(vreg);
+ mutex_unlock(&vreg_lock);
+}
+module_exit(vreg_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("vreg.c regulator shim");
+MODULE_VERSION("1.0");
diff --git a/arch/arm/mach-msm/wcnss-ssr-8960.c b/arch/arm/mach-msm/wcnss-ssr-8960.c
index 2ef5c61..18b7334 100644
--- a/arch/arm/mach-msm/wcnss-ssr-8960.c
+++ b/arch/arm/mach-msm/wcnss-ssr-8960.c
@@ -21,6 +21,7 @@
#include <mach/scm.h>
#include <mach/subsystem_restart.h>
#include <mach/subsystem_notif.h>
+#include <mach/peripheral-loader.h>
#include "smd_private.h"
#include "ramdump.h"
@@ -35,10 +36,14 @@
static void *riva_ramdump_dev;
static int riva_crash;
static int ss_restart_inprogress;
+static int enable_riva_ssr;
static void riva_smsm_cb_fn(struct work_struct *work)
{
- panic(MODULE_NAME ": SMSM reset request received from Riva");
+ if (!enable_riva_ssr)
+ panic(MODULE_NAME ": SMSM reset request received from Riva");
+ else
+ subsystem_restart("riva");
}
static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
@@ -74,13 +79,13 @@
/* Subsystem handlers */
static int riva_shutdown(const struct subsys_data *subsys)
{
- /* TODO for phase 3 */
+ pil_force_shutdown("wcnss");
return 0;
}
static int riva_powerup(const struct subsys_data *subsys)
{
- /* TODO for phase 3 */
+ pil_force_boot("wcnss");
return 0;
}
@@ -118,6 +123,23 @@
.crash_shutdown = riva_crash_shutdown
};
+static int enable_riva_ssr_set(const char *val, struct kernel_param *kp)
+{
+ int ret;
+
+ ret = param_set_int(val, kp);
+ if (ret)
+ return ret;
+
+ if (enable_riva_ssr)
+ pr_info(MODULE_NAME ": Subsystem restart activated for riva.\n");
+
+ return 0;
+}
+
+module_param_call(enable_riva_ssr, enable_riva_ssr_set, param_get_int,
+ &enable_riva_ssr, S_IRUGO | S_IWUSR);
+
static int __init riva_restart_init(void)
{
return ssr_register_subsystem(&riva_8960);
diff --git a/arch/arm/mach-shark/leds.c b/arch/arm/mach-shark/leds.c
index c9e32de..ccd4918 100644
--- a/arch/arm/mach-shark/leds.c
+++ b/arch/arm/mach-shark/leds.c
@@ -36,7 +36,7 @@
static short hw_led_state;
static short saved_state;
-static DEFINE_SPINLOCK(leds_lock);
+static DEFINE_RAW_SPINLOCK(leds_lock);
short sequoia_read(int addr) {
outw(addr,0x24);
@@ -52,7 +52,7 @@
{
unsigned long flags;
- spin_lock_irqsave(&leds_lock, flags);
+ raw_spin_lock_irqsave(&leds_lock, flags);
hw_led_state = sequoia_read(0x09);
@@ -144,7 +144,7 @@
if (led_state & LED_STATE_ENABLED)
sequoia_write(hw_led_state,0x09);
- spin_unlock_irqrestore(&leds_lock, flags);
+ raw_spin_unlock_irqrestore(&leds_lock, flags);
}
static int __init leds_init(void)
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
index f8b9392..9a9706c 100644
--- a/arch/arm/mach-ux500/Kconfig
+++ b/arch/arm/mach-ux500/Kconfig
@@ -6,6 +6,7 @@
select ARM_GIC
select HAS_MTU
select ARM_ERRATA_753970
+ select ARM_ERRATA_754322
menu "Ux500 SoC"
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 95a7079..bc5ffce 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -29,9 +29,20 @@
static void __iomem *l2x0_base;
static uint32_t aux_ctrl_save;
static uint32_t data_latency_ctrl;
-static DEFINE_SPINLOCK(l2x0_lock);
+static DEFINE_RAW_SPINLOCK(l2x0_lock);
+
static uint32_t l2x0_way_mask; /* Bitmask of active ways */
static uint32_t l2x0_size;
+static u32 l2x0_cache_id;
+static unsigned int l2x0_sets;
+static unsigned int l2x0_ways;
+
+static inline bool is_pl310_rev(int rev)
+{
+ return (l2x0_cache_id &
+ (L2X0_CACHE_ID_PART_MASK | L2X0_CACHE_ID_REV_MASK)) ==
+ (L2X0_CACHE_ID_PART_L310 | rev);
+}
static inline void cache_wait_way(void __iomem *reg, unsigned long mask)
{
@@ -116,9 +127,30 @@
void l2x0_cache_sync(void)
{
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&l2x0_lock, flags);
cache_sync();
+ raw_spin_unlock_irqrestore(&l2x0_lock, flags);
}
+#ifdef CONFIG_PL310_ERRATA_727915
+static void l2x0_for_each_set_way(void __iomem *reg)
+{
+ int set;
+ int way;
+ unsigned long flags;
+
+ for (way = 0; way < l2x0_ways; way++) {
+ spin_lock_irqsave(&l2x0_lock, flags);
+ for (set = 0; set < l2x0_sets; set++)
+ writel_relaxed((way << 28) | (set << 5), reg);
+ cache_sync();
+ spin_unlock_irqrestore(&l2x0_lock, flags);
+ }
+}
+#endif
+
static void __l2x0_flush_all(void)
{
debug_writel(0x03);
@@ -132,22 +164,38 @@
{
unsigned long flags;
+#ifdef CONFIG_PL310_ERRATA_727915
+ if (is_pl310_rev(REV_PL310_R2P0)) {
+ l2x0_for_each_set_way(l2x0_base + L2X0_CLEAN_INV_LINE_IDX);
+ return;
+ }
+#endif
+
/* clean all ways */
- spin_lock_irqsave(&l2x0_lock, flags);
+ raw_spin_lock_irqsave(&l2x0_lock, flags);
__l2x0_flush_all();
- spin_unlock_irqrestore(&l2x0_lock, flags);
+ raw_spin_unlock_irqrestore(&l2x0_lock, flags);
}
static void l2x0_clean_all(void)
{
unsigned long flags;
+#ifdef CONFIG_PL310_ERRATA_727915
+ if (is_pl310_rev(REV_PL310_R2P0)) {
+ l2x0_for_each_set_way(l2x0_base + L2X0_CLEAN_LINE_IDX);
+ return;
+ }
+#endif
+
/* clean all ways */
- spin_lock_irqsave(&l2x0_lock, flags);
+ raw_spin_lock_irqsave(&l2x0_lock, flags);
+ debug_writel(0x03);
writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_WAY);
cache_wait_way(l2x0_base + L2X0_CLEAN_WAY, l2x0_way_mask);
cache_sync();
- spin_unlock_irqrestore(&l2x0_lock, flags);
+ debug_writel(0x00);
+ raw_spin_unlock_irqrestore(&l2x0_lock, flags);
}
static void l2x0_inv_all(void)
@@ -155,13 +203,13 @@
unsigned long flags;
/* invalidate all ways */
- spin_lock_irqsave(&l2x0_lock, flags);
+ raw_spin_lock_irqsave(&l2x0_lock, flags);
/* Invalidating when L2 is enabled is a nono */
BUG_ON(readl(l2x0_base + L2X0_CTRL) & 1);
writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_INV_WAY);
cache_wait_way(l2x0_base + L2X0_INV_WAY, l2x0_way_mask);
cache_sync();
- spin_unlock_irqrestore(&l2x0_lock, flags);
+ raw_spin_unlock_irqrestore(&l2x0_lock, flags);
}
static void l2x0_inv_range(unsigned long start, unsigned long end)
@@ -169,7 +217,7 @@
void __iomem *base = l2x0_base;
unsigned long flags;
- spin_lock_irqsave(&l2x0_lock, flags);
+ raw_spin_lock_irqsave(&l2x0_lock, flags);
if (start & (CACHE_LINE_SIZE - 1)) {
start &= ~(CACHE_LINE_SIZE - 1);
debug_writel(0x03);
@@ -194,13 +242,13 @@
}
if (blk_end < end) {
- spin_unlock_irqrestore(&l2x0_lock, flags);
- spin_lock_irqsave(&l2x0_lock, flags);
+ raw_spin_unlock_irqrestore(&l2x0_lock, flags);
+ raw_spin_lock_irqsave(&l2x0_lock, flags);
}
}
cache_wait(base + L2X0_INV_LINE_PA, 1);
cache_sync();
- spin_unlock_irqrestore(&l2x0_lock, flags);
+ raw_spin_unlock_irqrestore(&l2x0_lock, flags);
}
static void l2x0_inv_range_atomic(unsigned long start, unsigned long end)
@@ -234,7 +282,7 @@
return;
}
- spin_lock_irqsave(&l2x0_lock, flags);
+ raw_spin_lock_irqsave(&l2x0_lock, flags);
start &= ~(CACHE_LINE_SIZE - 1);
while (start < end) {
unsigned long blk_end = start + min(end - start, 4096UL);
@@ -245,13 +293,13 @@
}
if (blk_end < end) {
- spin_unlock_irqrestore(&l2x0_lock, flags);
- spin_lock_irqsave(&l2x0_lock, flags);
+ raw_spin_unlock_irqrestore(&l2x0_lock, flags);
+ raw_spin_lock_irqsave(&l2x0_lock, flags);
}
}
cache_wait(base + L2X0_CLEAN_LINE_PA, 1);
cache_sync();
- spin_unlock_irqrestore(&l2x0_lock, flags);
+ raw_spin_unlock_irqrestore(&l2x0_lock, flags);
}
static void l2x0_clean_range_atomic(unsigned long start, unsigned long end)
@@ -275,7 +323,7 @@
return;
}
- spin_lock_irqsave(&l2x0_lock, flags);
+ raw_spin_lock_irqsave(&l2x0_lock, flags);
start &= ~(CACHE_LINE_SIZE - 1);
while (start < end) {
unsigned long blk_end = start + min(end - start, 4096UL);
@@ -288,13 +336,13 @@
debug_writel(0x00);
if (blk_end < end) {
- spin_unlock_irqrestore(&l2x0_lock, flags);
- spin_lock_irqsave(&l2x0_lock, flags);
+ raw_spin_unlock_irqrestore(&l2x0_lock, flags);
+ raw_spin_lock_irqsave(&l2x0_lock, flags);
}
}
cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1);
cache_sync();
- spin_unlock_irqrestore(&l2x0_lock, flags);
+ raw_spin_unlock_irqrestore(&l2x0_lock, flags);
}
void l2x0_flush_range_atomic(unsigned long start, unsigned long end)
@@ -312,23 +360,21 @@
{
unsigned long flags;
- spin_lock_irqsave(&l2x0_lock, flags);
+ raw_spin_lock_irqsave(&l2x0_lock, flags);
__l2x0_flush_all();
writel_relaxed(0, l2x0_base + L2X0_CTRL);
dsb();
- spin_unlock_irqrestore(&l2x0_lock, flags);
+ raw_spin_unlock_irqrestore(&l2x0_lock, flags);
}
void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
{
__u32 aux, bits;
- __u32 cache_id;
__u32 way_size = 0;
- int ways;
const char *type;
l2x0_base = base;
- cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID);
+ l2x0_cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID);
bits = readl_relaxed(l2x0_base + L2X0_CTRL);
bits &= ~0x01; /* clear bit 0 */
@@ -340,33 +386,34 @@
aux |= aux_val;
/* Determine the number of ways */
- switch (cache_id & L2X0_CACHE_ID_PART_MASK) {
+ switch (l2x0_cache_id & L2X0_CACHE_ID_PART_MASK) {
case L2X0_CACHE_ID_PART_L310:
if (aux & (1 << 16))
- ways = 16;
+ l2x0_ways = 16;
else
- ways = 8;
+ l2x0_ways = 8;
type = "L310";
break;
case L2X0_CACHE_ID_PART_L210:
- ways = (aux >> 13) & 0xf;
+ l2x0_ways = (aux >> 13) & 0xf;
type = "L210";
break;
default:
/* Assume unknown chips have 8 ways */
- ways = 8;
+ l2x0_ways = 8;
type = "L2x0 series";
break;
}
writel_relaxed(aux, l2x0_base + L2X0_AUX_CTRL);
- l2x0_way_mask = (1 << ways) - 1;
+ l2x0_way_mask = (1 << l2x0_ways) - 1;
/*
* L2 cache Size = Way size * Number of ways
*/
way_size = (aux & L2X0_AUX_CTRL_WAY_SIZE_MASK) >> 17;
- way_size = 1 << (way_size + 3);
- l2x0_size = ways * way_size * SZ_1K;
+ way_size = SZ_1K << (way_size + 3);
+ l2x0_size = l2x0_ways * way_size;
+ l2x0_sets = way_size / CACHE_LINE_SIZE;
l2x0_inv_all();
@@ -375,7 +422,7 @@
bits |= 0x01; /* set bit 0 */
writel_relaxed(bits, l2x0_base + L2X0_CTRL);
- switch (cache_id & L2X0_CACHE_ID_PART_MASK) {
+ switch (l2x0_cache_id & L2X0_CACHE_ID_PART_MASK) {
case L2X0_CACHE_ID_PART_L220:
outer_cache.inv_range = l2x0_inv_range;
outer_cache.clean_range = l2x0_clean_range;
@@ -407,7 +454,7 @@
mb();
printk(KERN_INFO "%s cache controller enabled\n", type);
printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d B\n",
- ways, cache_id, aux, l2x0_size);
+ l2x0_ways, l2x0_cache_id, aux, l2x0_size);
}
void l2x0_suspend(void)
diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S
index 0db2092..5cd1b05 100644
--- a/arch/arm/mm/cache-v7.S
+++ b/arch/arm/mm/cache-v7.S
@@ -174,6 +174,10 @@
dcache_line_size r2, r3
sub r3, r2, #1
bic r12, r0, r3
+#ifdef CONFIG_ARM_ERRATA_764369
+ ALT_SMP(W(dsb))
+ ALT_UP(W(nop))
+#endif
1:
USER( mcr p15, 0, r12, c7, c11, 1 ) @ clean D line to the point of unification
add r12, r12, r2
@@ -223,6 +227,10 @@
add r1, r0, r1
sub r3, r2, #1
bic r0, r0, r3
+#ifdef CONFIG_ARM_ERRATA_764369
+ ALT_SMP(W(dsb))
+ ALT_UP(W(nop))
+#endif
1:
mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D line / unified line
add r0, r0, r2
@@ -247,6 +255,10 @@
sub r3, r2, #1
tst r0, r3
bic r0, r0, r3
+#ifdef CONFIG_ARM_ERRATA_764369
+ ALT_SMP(W(dsb))
+ ALT_UP(W(nop))
+#endif
mcrne p15, 0, r0, c7, c14, 1 @ clean & invalidate D / U line
tst r1, r3
@@ -270,6 +282,10 @@
dcache_line_size r2, r3
sub r3, r2, #1
bic r0, r0, r3
+#ifdef CONFIG_ARM_ERRATA_764369
+ ALT_SMP(W(dsb))
+ ALT_UP(W(nop))
+#endif
1:
mcr p15, 0, r0, c7, c10, 1 @ clean D / U line
add r0, r0, r2
@@ -288,6 +304,10 @@
dcache_line_size r2, r3
sub r3, r2, #1
bic r0, r0, r3
+#ifdef CONFIG_ARM_ERRATA_764369
+ ALT_SMP(W(dsb))
+ ALT_UP(W(nop))
+#endif
1:
mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D / U line
add r0, r0, r2
diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c
index b0ee9ba..93aac06 100644
--- a/arch/arm/mm/context.c
+++ b/arch/arm/mm/context.c
@@ -16,7 +16,7 @@
#include <asm/mmu_context.h>
#include <asm/tlbflush.h>
-static DEFINE_SPINLOCK(cpu_asid_lock);
+static DEFINE_RAW_SPINLOCK(cpu_asid_lock);
unsigned int cpu_last_asid = ASID_FIRST_VERSION;
#ifdef CONFIG_SMP
DEFINE_PER_CPU(struct mm_struct *, current_mm);
@@ -31,7 +31,7 @@
void __init_new_context(struct task_struct *tsk, struct mm_struct *mm)
{
mm->context.id = 0;
- spin_lock_init(&mm->context.id_lock);
+ raw_spin_lock_init(&mm->context.id_lock);
}
static void flush_context(void)
@@ -58,7 +58,7 @@
* the broadcast. This function is also called via IPI so the
* mm->context.id_lock has to be IRQ-safe.
*/
- spin_lock_irqsave(&mm->context.id_lock, flags);
+ raw_spin_lock_irqsave(&mm->context.id_lock, flags);
if (likely((mm->context.id ^ cpu_last_asid) >> ASID_BITS)) {
/*
* Old version of ASID found. Set the new one and
@@ -67,7 +67,7 @@
mm->context.id = asid;
cpumask_clear(mm_cpumask(mm));
}
- spin_unlock_irqrestore(&mm->context.id_lock, flags);
+ raw_spin_unlock_irqrestore(&mm->context.id_lock, flags);
/*
* Set the mm_cpumask(mm) bit for the current CPU.
@@ -117,7 +117,7 @@
{
unsigned int asid;
- spin_lock(&cpu_asid_lock);
+ raw_spin_lock(&cpu_asid_lock);
#ifdef CONFIG_SMP
/*
* Check the ASID again, in case the change was broadcast from
@@ -125,7 +125,7 @@
*/
if (unlikely(((mm->context.id ^ cpu_last_asid) >> ASID_BITS) == 0)) {
cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));
- spin_unlock(&cpu_asid_lock);
+ raw_spin_unlock(&cpu_asid_lock);
return;
}
#endif
@@ -153,5 +153,5 @@
}
set_mm_context(mm, asid);
- spin_unlock(&cpu_asid_lock);
+ raw_spin_unlock(&cpu_asid_lock);
}
diff --git a/arch/arm/mm/copypage-v4mc.c b/arch/arm/mm/copypage-v4mc.c
index b806151..7d0a8c2 100644
--- a/arch/arm/mm/copypage-v4mc.c
+++ b/arch/arm/mm/copypage-v4mc.c
@@ -30,7 +30,7 @@
#define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \
L_PTE_MT_MINICACHE)
-static DEFINE_SPINLOCK(minicache_lock);
+static DEFINE_RAW_SPINLOCK(minicache_lock);
/*
* ARMv4 mini-dcache optimised copy_user_highpage
@@ -76,14 +76,14 @@
if (!test_and_set_bit(PG_dcache_clean, &from->flags))
__flush_dcache_page(page_mapping(from), from);
- spin_lock(&minicache_lock);
+ raw_spin_lock(&minicache_lock);
set_pte_ext(TOP_PTE(0xffff8000), pfn_pte(page_to_pfn(from), minicache_pgprot), 0);
flush_tlb_kernel_page(0xffff8000);
mc_copy_user_page((void *)0xffff8000, kto);
- spin_unlock(&minicache_lock);
+ raw_spin_unlock(&minicache_lock);
kunmap_atomic(kto, KM_USER1);
}
diff --git a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c
index bdba6c6..b2a8f9c 100644
--- a/arch/arm/mm/copypage-v6.c
+++ b/arch/arm/mm/copypage-v6.c
@@ -27,7 +27,7 @@
#define from_address (0xffff8000)
#define to_address (0xffffc000)
-static DEFINE_SPINLOCK(v6_lock);
+static DEFINE_RAW_SPINLOCK(v6_lock);
/*
* Copy the user page. No aliasing to deal with so we can just
@@ -89,7 +89,7 @@
* Now copy the page using the same cache colour as the
* pages ultimate destination.
*/
- spin_lock(&v6_lock);
+ raw_spin_lock(&v6_lock);
set_pte_ext(TOP_PTE(from_address) + offset, pfn_pte(page_to_pfn(from), PAGE_KERNEL), 0);
set_pte_ext(TOP_PTE(to_address) + offset, pfn_pte(page_to_pfn(to), PAGE_KERNEL), 0);
@@ -102,7 +102,7 @@
copy_page((void *)kto, (void *)kfrom);
- spin_unlock(&v6_lock);
+ raw_spin_unlock(&v6_lock);
}
/*
@@ -122,13 +122,13 @@
* Now clear the page using the same cache colour as
* the pages ultimate destination.
*/
- spin_lock(&v6_lock);
+ raw_spin_lock(&v6_lock);
set_pte_ext(TOP_PTE(to_address) + offset, pfn_pte(page_to_pfn(page), PAGE_KERNEL), 0);
flush_tlb_kernel_page(to);
clear_page((void *)to);
- spin_unlock(&v6_lock);
+ raw_spin_unlock(&v6_lock);
}
struct cpu_user_fns v6_user_fns __initdata = {
diff --git a/arch/arm/mm/copypage-xscale.c b/arch/arm/mm/copypage-xscale.c
index 649bbcd..610c24c 100644
--- a/arch/arm/mm/copypage-xscale.c
+++ b/arch/arm/mm/copypage-xscale.c
@@ -32,7 +32,7 @@
#define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \
L_PTE_MT_MINICACHE)
-static DEFINE_SPINLOCK(minicache_lock);
+static DEFINE_RAW_SPINLOCK(minicache_lock);
/*
* XScale mini-dcache optimised copy_user_highpage
@@ -98,14 +98,14 @@
if (!test_and_set_bit(PG_dcache_clean, &from->flags))
__flush_dcache_page(page_mapping(from), from);
- spin_lock(&minicache_lock);
+ raw_spin_lock(&minicache_lock);
set_pte_ext(TOP_PTE(COPYPAGE_MINICACHE), pfn_pte(page_to_pfn(from), minicache_pgprot), 0);
flush_tlb_kernel_page(COPYPAGE_MINICACHE);
mc_copy_user_page((void *)COPYPAGE_MINICACHE, kto);
- spin_unlock(&minicache_lock);
+ raw_spin_unlock(&minicache_lock);
kunmap_atomic(kto, KM_USER1);
}
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 4fc0e3f..340c2d0 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -322,6 +322,8 @@
if (addr)
*handle = pfn_to_dma(dev, page_to_pfn(page));
+ else
+ __dma_free_buffer(page, size);
return addr;
}
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 7cd02ff..e5e3486 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -546,6 +546,13 @@
*/
bank_start = min(bank_start,
ALIGN(prev_bank_end, PAGES_PER_SECTION));
+#else
+ /*
+ * Align down here since the VM subsystem insists that the
+ * memmap entries are valid from the bank start aligned to
+ * MAX_ORDER_NR_PAGES.
+ */
+ bank_start = round_down(bank_start, MAX_ORDER_NR_PAGES);
#endif
/*
* If we had a previous bank, and there is a space
@@ -630,6 +637,9 @@
extern u32 dtcm_end;
extern u32 itcm_end;
#endif
+#ifdef CONFIG_FIX_MOVABLE_ZONE
+ struct zone *zone;
+#endif
max_mapnr = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map;
@@ -675,6 +685,14 @@
#endif
}
+#ifdef CONFIG_FIX_MOVABLE_ZONE
+ for_each_zone(zone) {
+ if (zone_idx(zone) == ZONE_MOVABLE)
+ total_unmovable_pages = totalram_pages -
+ zone->spanned_pages;
+ }
+#endif
+
/*
* Since our memory may not be contiguous, calculate the
* real number of pages we have in this system
@@ -777,6 +795,7 @@
void free_initmem(void)
{
+ unsigned long reclaimed_initmem;
#ifdef CONFIG_HAVE_TCM
extern char __tcm_start, __tcm_end;
@@ -785,10 +804,15 @@
"TCM link");
#endif
- if (!machine_is_integrator() && !machine_is_cintegrator())
- totalram_pages += free_area(__phys_to_pfn(__pa(__init_begin)),
+ if (!machine_is_integrator() && !machine_is_cintegrator()) {
+ reclaimed_initmem = free_area(__phys_to_pfn(__pa(__init_begin)),
__phys_to_pfn(__pa(__init_end)),
"init");
+ totalram_pages += reclaimed_initmem;
+#ifdef CONFIG_FIX_MOVABLE_ZONE
+ total_unmovable_pages += reclaimed_initmem;
+#endif
+ }
}
#ifdef CONFIG_MEMORY_HOTPLUG
@@ -824,10 +848,16 @@
void free_initrd_mem(unsigned long start, unsigned long end)
{
- if (!keep_initrd)
- totalram_pages += free_area(__phys_to_pfn(__pa(start)),
+ unsigned long reclaimed_initrd_mem;
+ if (!keep_initrd) {
+ reclaimed_initrd_mem = free_area(__phys_to_pfn(__pa(start)),
__phys_to_pfn(__pa(end)),
"initrd");
+ totalram_pages += reclaimed_initrd_mem;
+#ifdef CONFIG_FIX_MOVABLE_ZONE
+ total_unmovable_pages += reclaimed_initrd_mem;
+#endif
+ }
}
static int __init keepinitrd_setup(char *__unused)
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 9beef12..0f79b76 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -796,14 +796,9 @@
int i, j, highmem = 0;
#if (defined CONFIG_HIGHMEM) && (defined CONFIG_FIX_MOVABLE_ZONE)
-
-/* For now, we must ensure that a small highmem zone exists
- * after most of it is transformed into the movable zone.
- */
-#define MIN_HIGHMEM_SIZE (5 * SECTION_SIZE)
void *v_movable_start;
- v_movable_start = __va(movable_reserved_start) - MIN_HIGHMEM_SIZE;
+ v_movable_start = __va(movable_reserved_start);
if (vmalloc_min > v_movable_start)
vmalloc_min = v_movable_start;
@@ -1129,6 +1124,20 @@
}
#endif
+void mem_text_write_kernel_word(unsigned long *addr, unsigned long word)
+{
+ unsigned long flags;
+
+ mem_text_writeable_spinlock(&flags);
+ mem_text_address_writeable((unsigned long)addr);
+ *addr = word;
+ flush_icache_range((unsigned long)addr,
+ ((unsigned long)addr + sizeof(long)));
+ mem_text_address_restore();
+ mem_text_writeable_spinunlock(&flags);
+}
+EXPORT_SYMBOL(mem_text_write_kernel_word);
+
static void __init map_lowmem(void)
{
struct memblock_region *reg;
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index 46729ee..5943005 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -219,7 +219,11 @@
* NOS = PRRR[24+n] = 1 - not outer shareable
*/
.equ PRRR, 0xff0a81a8
+#if defined (CONFIG_ARCH_MSM_SCORPIONMP)
+.equ NMRR, 0x40e080e0
+#else
.equ NMRR, 0x40e040e0
+#endif
/* Suspend/resume support: derived from arch/arm/mach-s5pv210/sleep.S */
.globl cpu_v7_suspend_size
diff --git a/arch/arm/plat-mxc/include/mach/iomux-v3.h b/arch/arm/plat-mxc/include/mach/iomux-v3.h
index 82620af..ebbce33 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-v3.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-v3.h
@@ -66,7 +66,6 @@
#define MUX_MODE_MASK ((iomux_v3_cfg_t)0x1f << MUX_MODE_SHIFT)
#define MUX_PAD_CTRL_SHIFT 41
#define MUX_PAD_CTRL_MASK ((iomux_v3_cfg_t)0x1ffff << MUX_PAD_CTRL_SHIFT)
-#define NO_PAD_CTRL ((iomux_v3_cfg_t)1 << (MUX_PAD_CTRL_SHIFT + 16))
#define MUX_SEL_INPUT_SHIFT 58
#define MUX_SEL_INPUT_MASK ((iomux_v3_cfg_t)0xf << MUX_SEL_INPUT_SHIFT)
@@ -85,6 +84,7 @@
* Use to set PAD control
*/
+#define NO_PAD_CTRL (1 << 16)
#define PAD_CTL_DVS (1 << 13)
#define PAD_CTL_HYS (1 << 8)
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index 190f707..baf3170 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -1129,3 +1129,6 @@
msm7627a_qrd1 MACH_MSM7627A_QRD1 MSM7627A_QRD1 3756
msm7625a_ffa MACH_MSM7625A_FFA MSM7625A_FFA 3771
msm7625a_surf MACH_MSM7625A_SURF MSM7625A_SURF 3772
+msm8627_cdp MACH_MSM8627_CDP MSM8627_CDP 3861
+msm8627_mtp MACH_MSM8627_MTP MSM8627_MTP 3862
+msm8625_rumi3 MACH_MSM8625_RUMI3 MSM8625_RUMI3 3871
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
index 9897dcf..404538a 100644
--- a/arch/arm/vfp/vfphw.S
+++ b/arch/arm/vfp/vfphw.S
@@ -77,15 +77,12 @@
bne look_for_VFP_exceptions @ VFP is already enabled
DBGSTR1 "enable %x", r10
- ldr r3, last_VFP_context_address
+ ldr r3, vfp_current_hw_state_address
orr r1, r1, #FPEXC_EN @ user FPEXC has the enable bit set
- ldr r4, [r3, r11, lsl #2] @ last_VFP_context pointer
+ ldr r4, [r3, r11, lsl #2] @ vfp_current_hw_state pointer
bic r5, r1, #FPEXC_EX @ make sure exceptions are disabled
- cmp r4, r10
- beq check_for_exception @ we are returning to the same
- @ process, so the registers are
- @ still there. In this case, we do
- @ not want to drop a pending exception.
+ cmp r4, r10 @ this thread owns the hw context?
+ beq vfp_hw_state_valid
VFPFMXR FPEXC, r5 @ enable VFP, disable any pending
@ exceptions, so we can get at the
@@ -116,7 +113,7 @@
no_old_VFP_process:
DBGSTR1 "load state %p", r10
- str r10, [r3, r11, lsl #2] @ update the last_VFP_context pointer
+ str r10, [r3, r11, lsl #2] @ update the vfp_current_hw_state pointer
@ Load the saved state back into the VFP
VFPFLDMIA r10, r5 @ reload the working registers while
@ FPEXC is in a safe state
@@ -132,7 +129,8 @@
#endif
VFPFMXR FPSCR, r5 @ restore status
-check_for_exception:
+@ The context stored in the VFP hardware is up to date with this thread
+vfp_hw_state_valid:
tst r1, #FPEXC_EX
bne process_exception @ might as well handle the pending
@ exception before retrying branch
@@ -207,8 +205,8 @@
ENDPROC(vfp_save_state)
.align
-last_VFP_context_address:
- .word last_VFP_context
+vfp_current_hw_state_address:
+ .word vfp_current_hw_state
.macro tbl_branch, base, tmp, shift
#ifdef CONFIG_THUMB2_KERNEL
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index a8a8925..d25fabf 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -33,7 +33,13 @@
void vfp_null_entry(void);
void (*vfp_vector)(void) = vfp_null_entry;
-union vfp_state *last_VFP_context[NR_CPUS];
+
+/*
+ * The pointer to the vfpstate structure of the thread which currently
+ * owns the context held in the VFP hardware, or NULL if the hardware
+ * context is invalid.
+ */
+union vfp_state *vfp_current_hw_state[NR_CPUS];
/*
* Dual-use variable.
@@ -57,12 +63,12 @@
/*
* Disable VFP to ensure we initialize it first. We must ensure
- * that the modification of last_VFP_context[] and hardware disable
+ * that the modification of vfp_current_hw_state[] and hardware disable
* are done for the same CPU and without preemption.
*/
cpu = get_cpu();
- if (last_VFP_context[cpu] == vfp)
- last_VFP_context[cpu] = NULL;
+ if (vfp_current_hw_state[cpu] == vfp)
+ vfp_current_hw_state[cpu] = NULL;
fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
put_cpu();
}
@@ -73,8 +79,8 @@
union vfp_state *vfp = &thread->vfpstate;
unsigned int cpu = get_cpu();
- if (last_VFP_context[cpu] == vfp)
- last_VFP_context[cpu] = NULL;
+ if (vfp_current_hw_state[cpu] == vfp)
+ vfp_current_hw_state[cpu] = NULL;
put_cpu();
}
@@ -129,9 +135,9 @@
* case the thread migrates to a different CPU. The
* restoring is done lazily.
*/
- if ((fpexc & FPEXC_EN) && last_VFP_context[cpu]) {
- vfp_save_state(last_VFP_context[cpu], fpexc);
- last_VFP_context[cpu]->hard.cpu = cpu;
+ if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu]) {
+ vfp_save_state(vfp_current_hw_state[cpu], fpexc);
+ vfp_current_hw_state[cpu]->hard.cpu = cpu;
}
/*
* Thread migration, just force the reloading of the
@@ -139,7 +145,7 @@
* contain stale data.
*/
if (thread->vfpstate.hard.cpu != cpu)
- last_VFP_context[cpu] = NULL;
+ vfp_current_hw_state[cpu] = NULL;
#endif
/*
@@ -413,22 +419,22 @@
#ifdef CONFIG_SMP
/* On SMP, if VFP is enabled, save the old state */
- if ((fpexc & FPEXC_EN) && last_VFP_context[cpu]) {
- last_VFP_context[cpu]->hard.cpu = cpu;
+ if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu]) {
+ vfp_current_hw_state[cpu]->hard.cpu = cpu;
#else
/* If there is a VFP context we must save it. */
- if (last_VFP_context[cpu]) {
+ if (vfp_current_hw_state[cpu]) {
/* Enable VFP so we can save the old state. */
fmxr(FPEXC, fpexc | FPEXC_EN);
isb();
#endif
- vfp_save_state(last_VFP_context[cpu], fpexc);
+ vfp_save_state(vfp_current_hw_state[cpu], fpexc);
/* disable, just in case */
fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
saved = 1;
}
- last_VFP_context[cpu] = NULL;
+ vfp_current_hw_state[cpu] = NULL;
local_irq_restore(flags);
@@ -481,7 +487,7 @@
* If the thread we're interested in is the current owner of the
* hardware VFP state, then we need to save its state.
*/
- if (last_VFP_context[cpu] == &thread->vfpstate) {
+ if (vfp_current_hw_state[cpu] == &thread->vfpstate) {
u32 fpexc = fmrx(FPEXC);
/*
@@ -503,7 +509,7 @@
* If the thread we're interested in is the current owner of the
* hardware VFP state, then we need to save its state.
*/
- if (last_VFP_context[cpu] == &thread->vfpstate) {
+ if (vfp_current_hw_state[cpu] == &thread->vfpstate) {
u32 fpexc = fmrx(FPEXC);
fmxr(FPEXC, fpexc & ~FPEXC_EN);
@@ -512,7 +518,7 @@
* Set the context to NULL to force a reload the next time
* the thread uses the VFP.
*/
- last_VFP_context[cpu] = NULL;
+ vfp_current_hw_state[cpu] = NULL;
}
#ifdef CONFIG_SMP
@@ -544,7 +550,7 @@
{
if (action == CPU_DYING || action == CPU_DYING_FROZEN) {
unsigned int cpu = (long)hcpu;
- last_VFP_context[cpu] = NULL;
+ vfp_current_hw_state[cpu] = NULL;
} else if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
vfp_enable(NULL);
return NOTIFY_OK;
@@ -623,7 +629,9 @@
if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100)
elf_hwcap |= HWCAP_NEON;
#endif
- if ((fmrx(MVFR1) & 0xf0000000) == 0x10000000)
+
+ if ((fmrx(MVFR1) & 0xf0000000) == 0x10000000 ||
+ (read_cpuid_id() & 0xff00fc00) == 0x51000400)
elf_hwcap |= HWCAP_VFPv4;
}
}
diff --git a/arch/cris/arch-v10/drivers/sync_serial.c b/arch/cris/arch-v10/drivers/sync_serial.c
index 85026537..466af40 100644
--- a/arch/cris/arch-v10/drivers/sync_serial.c
+++ b/arch/cris/arch-v10/drivers/sync_serial.c
@@ -158,7 +158,7 @@
static int sync_serial_release(struct inode *inode, struct file *file);
static unsigned int sync_serial_poll(struct file *filp, poll_table *wait);
-static int sync_serial_ioctl(struct file *file,
+static long sync_serial_ioctl(struct file *file,
unsigned int cmd, unsigned long arg);
static ssize_t sync_serial_write(struct file *file, const char *buf,
size_t count, loff_t *ppos);
@@ -625,11 +625,11 @@
*R_IRQ_MASK1_SET = 1 << port->data_avail_bit;
DEBUG(printk(KERN_DEBUG "sser%d rec started\n", dev));
}
- ret = 0;
+ err = 0;
out:
mutex_unlock(&sync_serial_mutex);
- return ret;
+ return err;
}
static int sync_serial_release(struct inode *inode, struct file *file)
diff --git a/arch/cris/arch-v10/kernel/irq.c b/arch/cris/arch-v10/kernel/irq.c
index 907cfb5..ba0e596 100644
--- a/arch/cris/arch-v10/kernel/irq.c
+++ b/arch/cris/arch-v10/kernel/irq.c
@@ -20,6 +20,9 @@
#define crisv10_mask_irq(irq_nr) (*R_VECT_MASK_CLR = 1 << (irq_nr));
#define crisv10_unmask_irq(irq_nr) (*R_VECT_MASK_SET = 1 << (irq_nr));
+extern void kgdb_init(void);
+extern void breakpoint(void);
+
/* don't use set_int_vector, it bypasses the linux interrupt handlers. it is
* global just so that the kernel gdb can use it.
*/
diff --git a/arch/cris/include/asm/thread_info.h b/arch/cris/include/asm/thread_info.h
index 29b74a1..332f19c 100644
--- a/arch/cris/include/asm/thread_info.h
+++ b/arch/cris/include/asm/thread_info.h
@@ -11,8 +11,6 @@
#ifdef __KERNEL__
-#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
-
#ifndef __ASSEMBLY__
#include <asm/types.h>
#include <asm/processor.h>
@@ -67,8 +65,10 @@
#define init_thread_info (init_thread_union.thread_info)
+#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
/* thread information allocation */
-#define alloc_thread_info(tsk, node) ((struct thread_info *) __get_free_pages(GFP_KERNEL,1))
+#define alloc_thread_info_node(tsk, node) \
+ ((struct thread_info *) __get_free_pages(GFP_KERNEL, 1))
#define free_thread_info(ti) free_pages((unsigned long) (ti), 1)
#endif /* !__ASSEMBLY__ */
diff --git a/arch/mips/jz4740/gpio.c b/arch/mips/jz4740/gpio.c
index 73031f7..4397972 100644
--- a/arch/mips/jz4740/gpio.c
+++ b/arch/mips/jz4740/gpio.c
@@ -18,7 +18,7 @@
#include <linux/init.h>
#include <linux/spinlock.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/delay.h>
@@ -86,7 +86,6 @@
spinlock_t lock;
struct gpio_chip gpio_chip;
- struct sys_device sysdev;
};
static struct jz_gpio_chip jz4740_gpio_chips[];
@@ -459,49 +458,47 @@
JZ4740_GPIO_CHIP(D),
};
-static inline struct jz_gpio_chip *sysdev_to_chip(struct sys_device *dev)
+static void jz4740_gpio_suspend_chip(struct jz_gpio_chip *chip)
{
- return container_of(dev, struct jz_gpio_chip, sysdev);
-}
-
-static int jz4740_gpio_suspend(struct sys_device *dev, pm_message_t state)
-{
- struct jz_gpio_chip *chip = sysdev_to_chip(dev);
-
chip->suspend_mask = readl(chip->base + JZ_REG_GPIO_MASK);
writel(~(chip->wakeup), chip->base + JZ_REG_GPIO_MASK_SET);
writel(chip->wakeup, chip->base + JZ_REG_GPIO_MASK_CLEAR);
+}
+
+static int jz4740_gpio_suspend(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); i++)
+ jz4740_gpio_suspend_chip(&jz4740_gpio_chips[i]);
return 0;
}
-static int jz4740_gpio_resume(struct sys_device *dev)
+static void jz4740_gpio_resume_chip(struct jz_gpio_chip *chip)
{
- struct jz_gpio_chip *chip = sysdev_to_chip(dev);
uint32_t mask = chip->suspend_mask;
writel(~mask, chip->base + JZ_REG_GPIO_MASK_CLEAR);
writel(mask, chip->base + JZ_REG_GPIO_MASK_SET);
-
- return 0;
}
-static struct sysdev_class jz4740_gpio_sysdev_class = {
- .name = "gpio",
+static void jz4740_gpio_resume(void)
+{
+ int i;
+
+ for (i = ARRAY_SIZE(jz4740_gpio_chips) - 1; i >= 0 ; i--)
+ jz4740_gpio_resume_chip(&jz4740_gpio_chips[i]);
+}
+
+static struct syscore_ops jz4740_gpio_syscore_ops = {
.suspend = jz4740_gpio_suspend,
.resume = jz4740_gpio_resume,
};
-static int jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id)
+static void jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id)
{
- int ret, irq;
-
- chip->sysdev.id = id;
- chip->sysdev.cls = &jz4740_gpio_sysdev_class;
- ret = sysdev_register(&chip->sysdev);
-
- if (ret)
- return ret;
+ int irq;
spin_lock_init(&chip->lock);
@@ -519,22 +516,17 @@
irq_set_chip_and_handler(irq, &jz_gpio_irq_chip,
handle_level_irq);
}
-
- return 0;
}
static int __init jz4740_gpio_init(void)
{
unsigned int i;
- int ret;
-
- ret = sysdev_class_register(&jz4740_gpio_sysdev_class);
- if (ret)
- return ret;
for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); ++i)
jz4740_gpio_chip_init(&jz4740_gpio_chips[i], i);
+ register_syscore_ops(&jz4740_gpio_syscore_ops);
+
printk(KERN_INFO "JZ4740 GPIO initialized\n");
return 0;
diff --git a/arch/parisc/include/asm/atomic.h b/arch/parisc/include/asm/atomic.h
index f819559..26fd114 100644
--- a/arch/parisc/include/asm/atomic.h
+++ b/arch/parisc/include/asm/atomic.h
@@ -259,10 +259,10 @@
#define ATOMIC64_INIT(i) ((atomic64_t) { (i) })
-static __inline__ int
+static __inline__ s64
__atomic64_add_return(s64 i, atomic64_t *v)
{
- int ret;
+ s64 ret;
unsigned long flags;
_atomic_spin_lock_irqsave(v, flags);
diff --git a/arch/parisc/include/asm/futex.h b/arch/parisc/include/asm/futex.h
index 67a33cc..2388bdb 100644
--- a/arch/parisc/include/asm/futex.h
+++ b/arch/parisc/include/asm/futex.h
@@ -5,11 +5,14 @@
#include <linux/futex.h>
#include <linux/uaccess.h>
+#include <asm/atomic.h>
#include <asm/errno.h>
static inline int
futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
+ unsigned long int flags;
+ u32 val;
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
int oparg = (encoded_op << 8) >> 20;
@@ -18,21 +21,58 @@
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;
- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(*uaddr)))
return -EFAULT;
pagefault_disable();
+ _atomic_spin_lock_irqsave(uaddr, flags);
+
switch (op) {
case FUTEX_OP_SET:
+ /* *(int *)UADDR2 = OPARG; */
+ ret = get_user(oldval, uaddr);
+ if (!ret)
+ ret = put_user(oparg, uaddr);
+ break;
case FUTEX_OP_ADD:
+ /* *(int *)UADDR2 += OPARG; */
+ ret = get_user(oldval, uaddr);
+ if (!ret) {
+ val = oldval + oparg;
+ ret = put_user(val, uaddr);
+ }
+ break;
case FUTEX_OP_OR:
+ /* *(int *)UADDR2 |= OPARG; */
+ ret = get_user(oldval, uaddr);
+ if (!ret) {
+ val = oldval | oparg;
+ ret = put_user(val, uaddr);
+ }
+ break;
case FUTEX_OP_ANDN:
+ /* *(int *)UADDR2 &= ~OPARG; */
+ ret = get_user(oldval, uaddr);
+ if (!ret) {
+ val = oldval & ~oparg;
+ ret = put_user(val, uaddr);
+ }
+ break;
case FUTEX_OP_XOR:
+ /* *(int *)UADDR2 ^= OPARG; */
+ ret = get_user(oldval, uaddr);
+ if (!ret) {
+ val = oldval ^ oparg;
+ ret = put_user(val, uaddr);
+ }
+ break;
default:
ret = -ENOSYS;
}
+ _atomic_spin_unlock_irqrestore(uaddr, flags);
+
pagefault_enable();
if (!ret) {
@@ -54,7 +94,9 @@
futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
u32 oldval, u32 newval)
{
+ int ret;
u32 val;
+ unsigned long flags;
/* futex.c wants to do a cmpxchg_inatomic on kernel NULL, which is
* our gateway page, and causes no end of trouble...
@@ -65,12 +107,24 @@
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;
- if (get_user(val, uaddr))
- return -EFAULT;
- if (val == oldval && put_user(newval, uaddr))
- return -EFAULT;
+ /* HPPA has no cmpxchg in hardware and therefore the
+ * best we can do here is use an array of locks. The
+ * lock selected is based on a hash of the userspace
+ * address. This should scale to a couple of CPUs.
+ */
+
+ _atomic_spin_lock_irqsave(uaddr, flags);
+
+ ret = get_user(val, uaddr);
+
+ if (!ret && val == oldval)
+ ret = put_user(newval, uaddr);
+
*uval = val;
- return 0;
+
+ _atomic_spin_unlock_irqrestore(uaddr, flags);
+
+ return ret;
}
#endif /*__KERNEL__*/
diff --git a/arch/parisc/include/asm/unistd.h b/arch/parisc/include/asm/unistd.h
index 3392de3..d61de64 100644
--- a/arch/parisc/include/asm/unistd.h
+++ b/arch/parisc/include/asm/unistd.h
@@ -821,8 +821,9 @@
#define __NR_open_by_handle_at (__NR_Linux + 326)
#define __NR_syncfs (__NR_Linux + 327)
#define __NR_setns (__NR_Linux + 328)
+#define __NR_sendmmsg (__NR_Linux + 329)
-#define __NR_Linux_syscalls (__NR_setns + 1)
+#define __NR_Linux_syscalls (__NR_sendmmsg + 1)
#define __IGNORE_select /* newselect */
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
index 34a4f5a..e66366f 100644
--- a/arch/parisc/kernel/syscall_table.S
+++ b/arch/parisc/kernel/syscall_table.S
@@ -427,6 +427,7 @@
ENTRY_COMP(open_by_handle_at)
ENTRY_SAME(syncfs)
ENTRY_SAME(setns)
+ ENTRY_COMP(sendmmsg)
/* Nothing yet */
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index c016033..3b22142 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -1020,7 +1020,7 @@
}
if (addr == 0)
return 0;
- RELOC(alloc_bottom) = addr;
+ RELOC(alloc_bottom) = addr + size;
prom_debug(" -> %x\n", addr);
prom_debug(" alloc_bottom : %x\n", RELOC(alloc_bottom));
@@ -1834,7 +1834,7 @@
chunk = alloc_up(room, 0);
if (chunk == 0)
prom_panic("No memory for flatten_device_tree (claim failed)");
- *mem_end = RELOC(alloc_top);
+ *mem_end = chunk + room;
}
ret = (void *)*mem_start;
@@ -2053,7 +2053,7 @@
mem_start = (unsigned long)alloc_up(room, PAGE_SIZE);
if (mem_start == 0)
prom_panic("Can't allocate initial device-tree chunk\n");
- mem_end = RELOC(alloc_top);
+ mem_end = mem_start + room;
/* Get root of tree */
root = call_prom("peer", 1, 1, (phandle)0);
diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c
index e919007..0e86563 100644
--- a/arch/powerpc/platforms/pseries/dtl.c
+++ b/arch/powerpc/platforms/pseries/dtl.c
@@ -181,7 +181,7 @@
lppaca_of(dtl->cpu).dtl_enable_mask = 0x0;
- unregister_dtl(hwcpu, __pa(dtl->buf));
+ unregister_dtl(hwcpu);
}
static u64 dtl_current_index(struct dtl *dtl)
diff --git a/arch/powerpc/platforms/pseries/kexec.c b/arch/powerpc/platforms/pseries/kexec.c
index 54cf3a4..1118cb7 100644
--- a/arch/powerpc/platforms/pseries/kexec.c
+++ b/arch/powerpc/platforms/pseries/kexec.c
@@ -26,6 +26,17 @@
/* Don't risk a hypervisor call if we're crashing */
if (firmware_has_feature(FW_FEATURE_SPLPAR) && !crash_shutdown) {
unsigned long addr;
+ int ret;
+
+ if (get_lppaca()->dtl_enable_mask) {
+ ret = unregister_dtl(hard_smp_processor_id());
+ if (ret) {
+ pr_err("WARNING: DTL deregistration for cpu "
+ "%d (hw %d) failed with %d\n",
+ smp_processor_id(),
+ hard_smp_processor_id(), ret);
+ }
+ }
addr = __pa(get_slb_shadow());
if (unregister_slb_shadow(hard_smp_processor_id(), addr))
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 39e6e0a..ed96b37 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -395,7 +395,7 @@
unsigned long ptel;
} ptes[4];
long lpar_rc;
- int i, j;
+ unsigned long i, j;
/* Read in batches of 4,
* invalidate only valid entries not in the VRMA
diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h
index 4bf2120..a6921ae 100644
--- a/arch/powerpc/platforms/pseries/plpar_wrappers.h
+++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h
@@ -73,9 +73,9 @@
return vpa_call(0x3, cpu, vpa);
}
-static inline long unregister_dtl(unsigned long cpu, unsigned long vpa)
+static inline long unregister_dtl(unsigned long cpu)
{
- return vpa_call(0x6, cpu, vpa);
+ return vpa_call(0x6, cpu, 0);
}
static inline long register_dtl(unsigned long cpu, unsigned long vpa)
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c
index b3fd081..cdd765b 100644
--- a/arch/powerpc/sysdev/fsl_rio.c
+++ b/arch/powerpc/sysdev/fsl_rio.c
@@ -54,6 +54,7 @@
#define ODSR_CLEAR 0x1c00
#define LTLEECSR_ENABLE_ALL 0xFFC000FC
#define ESCSR_CLEAR 0x07120204
+#define IECSR_CLEAR 0x80000000
#define RIO_PORT1_EDCSR 0x0640
#define RIO_PORT2_EDCSR 0x0680
@@ -1089,11 +1090,11 @@
if (offset == 0) {
out_be32((u32 *)(rio_regs_win + RIO_PORT1_EDCSR), 0);
- out_be32((u32 *)(rio_regs_win + RIO_PORT1_IECSR), 0);
+ out_be32((u32 *)(rio_regs_win + RIO_PORT1_IECSR), IECSR_CLEAR);
out_be32((u32 *)(rio_regs_win + RIO_ESCSR), ESCSR_CLEAR);
} else {
out_be32((u32 *)(rio_regs_win + RIO_PORT2_EDCSR), 0);
- out_be32((u32 *)(rio_regs_win + RIO_PORT2_IECSR), 0);
+ out_be32((u32 *)(rio_regs_win + RIO_PORT2_IECSR), IECSR_CLEAR);
out_be32((u32 *)(rio_regs_win + RIO_PORT2_ESCSR), ESCSR_CLEAR);
}
}
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 253986b..2e79419 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -53,6 +53,7 @@
select HAVE_PERF_EVENTS
select PERF_USE_VMALLOC
select IRQ_PREFLOW_FASTEOI
+ select HAVE_C_RECORDMCOUNT
config ARCH_DEFCONFIG
string
diff --git a/arch/sparc/include/asm/bitops_64.h b/arch/sparc/include/asm/bitops_64.h
index 38e9aa1..3fc595a 100644
--- a/arch/sparc/include/asm/bitops_64.h
+++ b/arch/sparc/include/asm/bitops_64.h
@@ -26,61 +26,28 @@
#define smp_mb__before_clear_bit() barrier()
#define smp_mb__after_clear_bit() barrier()
-#include <asm-generic/bitops/ffz.h>
-#include <asm-generic/bitops/__ffs.h>
#include <asm-generic/bitops/fls.h>
#include <asm-generic/bitops/__fls.h>
#include <asm-generic/bitops/fls64.h>
#ifdef __KERNEL__
+extern int ffs(int x);
+extern unsigned long __ffs(unsigned long);
+
+#include <asm-generic/bitops/ffz.h>
#include <asm-generic/bitops/sched.h>
-#include <asm-generic/bitops/ffs.h>
/*
* hweightN: returns the hamming weight (i.e. the number
* of bits set) of a N-bit word
*/
-#ifdef ULTRA_HAS_POPULATION_COUNT
+extern unsigned long __arch_hweight64(__u64 w);
+extern unsigned int __arch_hweight32(unsigned int w);
+extern unsigned int __arch_hweight16(unsigned int w);
+extern unsigned int __arch_hweight8(unsigned int w);
-static inline unsigned int __arch_hweight64(unsigned long w)
-{
- unsigned int res;
-
- __asm__ ("popc %1,%0" : "=r" (res) : "r" (w));
- return res;
-}
-
-static inline unsigned int __arch_hweight32(unsigned int w)
-{
- unsigned int res;
-
- __asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xffffffff));
- return res;
-}
-
-static inline unsigned int __arch_hweight16(unsigned int w)
-{
- unsigned int res;
-
- __asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xffff));
- return res;
-}
-
-static inline unsigned int __arch_hweight8(unsigned int w)
-{
- unsigned int res;
-
- __asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xff));
- return res;
-}
-
-#else
-
-#include <asm-generic/bitops/arch_hweight.h>
-
-#endif
#include <asm-generic/bitops/const_hweight.h>
#include <asm-generic/bitops/lock.h>
#endif /* __KERNEL__ */
diff --git a/arch/sparc/include/asm/elf_64.h b/arch/sparc/include/asm/elf_64.h
index e678803..7df8b7f 100644
--- a/arch/sparc/include/asm/elf_64.h
+++ b/arch/sparc/include/asm/elf_64.h
@@ -59,15 +59,33 @@
#define R_SPARC_6 45
/* Bits present in AT_HWCAP, primarily for Sparc32. */
+#define HWCAP_SPARC_FLUSH 0x00000001
+#define HWCAP_SPARC_STBAR 0x00000002
+#define HWCAP_SPARC_SWAP 0x00000004
+#define HWCAP_SPARC_MULDIV 0x00000008
+#define HWCAP_SPARC_V9 0x00000010
+#define HWCAP_SPARC_ULTRA3 0x00000020
+#define HWCAP_SPARC_BLKINIT 0x00000040
+#define HWCAP_SPARC_N2 0x00000080
-#define HWCAP_SPARC_FLUSH 1 /* CPU supports flush instruction. */
-#define HWCAP_SPARC_STBAR 2
-#define HWCAP_SPARC_SWAP 4
-#define HWCAP_SPARC_MULDIV 8
-#define HWCAP_SPARC_V9 16
-#define HWCAP_SPARC_ULTRA3 32
-#define HWCAP_SPARC_BLKINIT 64
-#define HWCAP_SPARC_N2 128
+/* Solaris compatible AT_HWCAP bits. */
+#define AV_SPARC_MUL32 0x00000100 /* 32x32 multiply is efficient */
+#define AV_SPARC_DIV32 0x00000200 /* 32x32 divide is efficient */
+#define AV_SPARC_FSMULD 0x00000400 /* 'fsmuld' is efficient */
+#define AV_SPARC_V8PLUS 0x00000800 /* v9 insn available to 32bit */
+#define AV_SPARC_POPC 0x00001000 /* 'popc' is efficient */
+#define AV_SPARC_VIS 0x00002000 /* VIS insns available */
+#define AV_SPARC_VIS2 0x00004000 /* VIS2 insns available */
+#define AV_SPARC_ASI_BLK_INIT 0x00008000 /* block init ASIs available */
+#define AV_SPARC_FMAF 0x00010000 /* fused multiply-add */
+#define AV_SPARC_VIS3 0x00020000 /* VIS3 insns available */
+#define AV_SPARC_HPC 0x00040000 /* HPC insns available */
+#define AV_SPARC_RANDOM 0x00080000 /* 'random' insn available */
+#define AV_SPARC_TRANS 0x00100000 /* transaction insns available */
+#define AV_SPARC_FJFMAU 0x00200000 /* unfused multiply-add */
+#define AV_SPARC_IMA 0x00400000 /* integer multiply-add */
+#define AV_SPARC_ASI_CACHE_SPARING \
+ 0x00800000 /* cache sparing ASIs available */
#define CORE_DUMP_USE_REGSET
@@ -162,31 +180,8 @@
#define ELF_ET_DYN_BASE 0x0000010000000000UL
#define COMPAT_ELF_ET_DYN_BASE 0x0000000070000000UL
-
-/* This yields a mask that user programs can use to figure out what
- instruction set this cpu supports. */
-
-/* On Ultra, we support all of the v8 capabilities. */
-static inline unsigned int sparc64_elf_hwcap(void)
-{
- unsigned int cap = (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR |
- HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV |
- HWCAP_SPARC_V9);
-
- if (tlb_type == cheetah || tlb_type == cheetah_plus)
- cap |= HWCAP_SPARC_ULTRA3;
- else if (tlb_type == hypervisor) {
- if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1 ||
- sun4v_chip_type == SUN4V_CHIP_NIAGARA2)
- cap |= HWCAP_SPARC_BLKINIT;
- if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2)
- cap |= HWCAP_SPARC_N2;
- }
-
- return cap;
-}
-
-#define ELF_HWCAP sparc64_elf_hwcap();
+extern unsigned long sparc64_elf_hwcap;
+#define ELF_HWCAP sparc64_elf_hwcap
/* This yields a string that ld.so will use to load implementation
specific libraries for optimization. This is more specific in
diff --git a/arch/sparc/include/asm/hypervisor.h b/arch/sparc/include/asm/hypervisor.h
index 7568640..015a761 100644
--- a/arch/sparc/include/asm/hypervisor.h
+++ b/arch/sparc/include/asm/hypervisor.h
@@ -2927,6 +2927,13 @@
#define HV_FAST_FIRE_GET_PERFREG 0x120
#define HV_FAST_FIRE_SET_PERFREG 0x121
+#define HV_FAST_REBOOT_DATA_SET 0x172
+
+#ifndef __ASSEMBLY__
+extern unsigned long sun4v_reboot_data_set(unsigned long ra,
+ unsigned long len);
+#endif
+
/* Function numbers for HV_CORE_TRAP. */
#define HV_CORE_SET_VER 0x00
#define HV_CORE_PUTCHAR 0x01
@@ -2940,16 +2947,23 @@
#define HV_GRP_CORE 0x0001
#define HV_GRP_INTR 0x0002
#define HV_GRP_SOFT_STATE 0x0003
+#define HV_GRP_TM 0x0080
#define HV_GRP_PCI 0x0100
#define HV_GRP_LDOM 0x0101
#define HV_GRP_SVC_CHAN 0x0102
#define HV_GRP_NCS 0x0103
#define HV_GRP_RNG 0x0104
+#define HV_GRP_PBOOT 0x0105
+#define HV_GRP_TPM 0x0107
+#define HV_GRP_SDIO 0x0108
+#define HV_GRP_SDIO_ERR 0x0109
+#define HV_GRP_REBOOT_DATA 0x0110
#define HV_GRP_NIAG_PERF 0x0200
#define HV_GRP_FIRE_PERF 0x0201
#define HV_GRP_N2_CPU 0x0202
#define HV_GRP_NIU 0x0204
#define HV_GRP_VF_CPU 0x0205
+#define HV_GRP_KT_CPU 0x0209
#define HV_GRP_DIAG 0x0300
#ifndef __ASSEMBLY__
diff --git a/arch/sparc/include/asm/sigcontext.h b/arch/sparc/include/asm/sigcontext.h
index a1607d1..69914d7 100644
--- a/arch/sparc/include/asm/sigcontext.h
+++ b/arch/sparc/include/asm/sigcontext.h
@@ -45,6 +45,19 @@
int si_mask;
} __siginfo32_t;
+#define __SIGC_MAXWIN 7
+
+typedef struct {
+ unsigned long locals[8];
+ unsigned long ins[8];
+} __siginfo_reg_window;
+
+typedef struct {
+ int wsaved;
+ __siginfo_reg_window reg_window[__SIGC_MAXWIN];
+ unsigned long rwbuf_stkptrs[__SIGC_MAXWIN];
+} __siginfo_rwin_t;
+
#ifdef CONFIG_SPARC64
typedef struct {
unsigned int si_float_regs [64];
@@ -73,6 +86,7 @@
unsigned long ss_size;
} sigc_stack;
unsigned long sigc_mask;
+ __siginfo_rwin_t * sigc_rwin_save;
};
#else
diff --git a/arch/sparc/include/asm/spinlock_32.h b/arch/sparc/include/asm/spinlock_32.h
index 5f5b8bf..bcc98fc 100644
--- a/arch/sparc/include/asm/spinlock_32.h
+++ b/arch/sparc/include/asm/spinlock_32.h
@@ -131,6 +131,15 @@
*(volatile __u32 *)&lp->lock = ~0U;
}
+static void inline arch_write_unlock(arch_rwlock_t *lock)
+{
+ __asm__ __volatile__(
+" st %%g0, [%0]"
+ : /* no outputs */
+ : "r" (lock)
+ : "memory");
+}
+
static inline int arch_write_trylock(arch_rwlock_t *rw)
{
unsigned int val;
@@ -175,8 +184,6 @@
res; \
})
-#define arch_write_unlock(rw) do { (rw)->lock = 0; } while(0)
-
#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
#define arch_read_lock_flags(rw, flags) arch_read_lock(rw)
#define arch_write_lock_flags(rw, flags) arch_write_lock(rw)
diff --git a/arch/sparc/include/asm/spinlock_64.h b/arch/sparc/include/asm/spinlock_64.h
index 073936a..9689176 100644
--- a/arch/sparc/include/asm/spinlock_64.h
+++ b/arch/sparc/include/asm/spinlock_64.h
@@ -210,14 +210,8 @@
return result;
}
-#define arch_read_lock(p) arch_read_lock(p)
#define arch_read_lock_flags(p, f) arch_read_lock(p)
-#define arch_read_trylock(p) arch_read_trylock(p)
-#define arch_read_unlock(p) arch_read_unlock(p)
-#define arch_write_lock(p) arch_write_lock(p)
#define arch_write_lock_flags(p, f) arch_write_lock(p)
-#define arch_write_unlock(p) arch_write_unlock(p)
-#define arch_write_trylock(p) arch_write_trylock(p)
#define arch_read_can_lock(rw) (!((rw)->lock & 0x80000000UL))
#define arch_write_can_lock(rw) (!(rw)->lock)
diff --git a/arch/sparc/include/asm/spitfire.h b/arch/sparc/include/asm/spitfire.h
index f0d0c40..55a17c6 100644
--- a/arch/sparc/include/asm/spitfire.h
+++ b/arch/sparc/include/asm/spitfire.h
@@ -42,6 +42,7 @@
#define SUN4V_CHIP_INVALID 0x00
#define SUN4V_CHIP_NIAGARA1 0x01
#define SUN4V_CHIP_NIAGARA2 0x02
+#define SUN4V_CHIP_NIAGARA3 0x03
#define SUN4V_CHIP_UNKNOWN 0xff
#ifndef __ASSEMBLY__
diff --git a/arch/sparc/include/asm/tsb.h b/arch/sparc/include/asm/tsb.h
index 83c571d..1a8afd1 100644
--- a/arch/sparc/include/asm/tsb.h
+++ b/arch/sparc/include/asm/tsb.h
@@ -133,29 +133,6 @@
sub TSB, 0x8, TSB; \
TSB_STORE(TSB, TAG);
-#define KTSB_LOAD_QUAD(TSB, REG) \
- ldda [TSB] ASI_NUCLEUS_QUAD_LDD, REG;
-
-#define KTSB_STORE(ADDR, VAL) \
- stxa VAL, [ADDR] ASI_N;
-
-#define KTSB_LOCK_TAG(TSB, REG1, REG2) \
-99: lduwa [TSB] ASI_N, REG1; \
- sethi %hi(TSB_TAG_LOCK_HIGH), REG2;\
- andcc REG1, REG2, %g0; \
- bne,pn %icc, 99b; \
- nop; \
- casa [TSB] ASI_N, REG1, REG2;\
- cmp REG1, REG2; \
- bne,pn %icc, 99b; \
- nop; \
-
-#define KTSB_WRITE(TSB, TTE, TAG) \
- add TSB, 0x8, TSB; \
- stxa TTE, [TSB] ASI_N; \
- sub TSB, 0x8, TSB; \
- stxa TAG, [TSB] ASI_N;
-
/* Do a kernel page table walk. Leaves physical PTE pointer in
* REG1. Jumps to FAIL_LABEL on early page table walk termination.
* VADDR will not be clobbered, but REG2 will.
@@ -239,6 +216,8 @@
(KERNEL_TSB_SIZE_BYTES / 16)
#define KERNEL_TSB4M_NENTRIES 4096
+#define KTSB_PHYS_SHIFT 15
+
/* Do a kernel TSB lookup at tl>0 on VADDR+TAG, branch to OK_LABEL
* on TSB hit. REG1, REG2, REG3, and REG4 are used as temporaries
* and the found TTE will be left in REG1. REG3 and REG4 must
@@ -247,13 +226,22 @@
* VADDR and TAG will be preserved and not clobbered by this macro.
*/
#define KERN_TSB_LOOKUP_TL1(VADDR, TAG, REG1, REG2, REG3, REG4, OK_LABEL) \
- sethi %hi(swapper_tsb), REG1; \
+661: sethi %hi(swapper_tsb), REG1; \
or REG1, %lo(swapper_tsb), REG1; \
+ .section .swapper_tsb_phys_patch, "ax"; \
+ .word 661b; \
+ .previous; \
+661: nop; \
+ .section .tsb_ldquad_phys_patch, "ax"; \
+ .word 661b; \
+ sllx REG1, KTSB_PHYS_SHIFT, REG1; \
+ sllx REG1, KTSB_PHYS_SHIFT, REG1; \
+ .previous; \
srlx VADDR, PAGE_SHIFT, REG2; \
and REG2, (KERNEL_TSB_NENTRIES - 1), REG2; \
sllx REG2, 4, REG2; \
add REG1, REG2, REG2; \
- KTSB_LOAD_QUAD(REG2, REG3); \
+ TSB_LOAD_QUAD(REG2, REG3); \
cmp REG3, TAG; \
be,a,pt %xcc, OK_LABEL; \
mov REG4, REG1;
@@ -263,12 +251,21 @@
* we can make use of that for the index computation.
*/
#define KERN_TSB4M_LOOKUP_TL1(TAG, REG1, REG2, REG3, REG4, OK_LABEL) \
- sethi %hi(swapper_4m_tsb), REG1; \
+661: sethi %hi(swapper_4m_tsb), REG1; \
or REG1, %lo(swapper_4m_tsb), REG1; \
+ .section .swapper_4m_tsb_phys_patch, "ax"; \
+ .word 661b; \
+ .previous; \
+661: nop; \
+ .section .tsb_ldquad_phys_patch, "ax"; \
+ .word 661b; \
+ sllx REG1, KTSB_PHYS_SHIFT, REG1; \
+ sllx REG1, KTSB_PHYS_SHIFT, REG1; \
+ .previous; \
and TAG, (KERNEL_TSB4M_NENTRIES - 1), REG2; \
sllx REG2, 4, REG2; \
add REG1, REG2, REG2; \
- KTSB_LOAD_QUAD(REG2, REG3); \
+ TSB_LOAD_QUAD(REG2, REG3); \
cmp REG3, TAG; \
be,a,pt %xcc, OK_LABEL; \
mov REG4, REG1;
diff --git a/arch/sparc/include/asm/xor_64.h b/arch/sparc/include/asm/xor_64.h
index bee4bf4..9ed6ff6 100644
--- a/arch/sparc/include/asm/xor_64.h
+++ b/arch/sparc/include/asm/xor_64.h
@@ -65,6 +65,7 @@
#define XOR_SELECT_TEMPLATE(FASTEST) \
((tlb_type == hypervisor && \
(sun4v_chip_type == SUN4V_CHIP_NIAGARA1 || \
- sun4v_chip_type == SUN4V_CHIP_NIAGARA2)) ? \
+ sun4v_chip_type == SUN4V_CHIP_NIAGARA2 || \
+ sun4v_chip_type == SUN4V_CHIP_NIAGARA3)) ? \
&xor_block_niagara : \
&xor_block_VIS)
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index b90b4a1..cb85458 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -32,6 +32,7 @@
obj-y += process_$(BITS).o
obj-y += signal_$(BITS).o
+obj-y += sigutil_$(BITS).o
obj-$(CONFIG_SPARC32) += ioport.o
obj-y += setup_$(BITS).o
obj-y += idprom.o
diff --git a/arch/sparc/kernel/cpu.c b/arch/sparc/kernel/cpu.c
index 138dbbc..9810fd8 100644
--- a/arch/sparc/kernel/cpu.c
+++ b/arch/sparc/kernel/cpu.c
@@ -396,6 +396,7 @@
, cpu_data(0).clock_tick
#endif
);
+ cpucap_info(m);
#ifdef CONFIG_SMP
smp_bogo(m);
#endif
@@ -474,11 +475,18 @@
sparc_pmu_type = "niagara2";
break;
+ case SUN4V_CHIP_NIAGARA3:
+ sparc_cpu_type = "UltraSparc T3 (Niagara3)";
+ sparc_fpu_type = "UltraSparc T3 integrated FPU";
+ sparc_pmu_type = "niagara3";
+ break;
+
default:
printk(KERN_WARNING "CPU: Unknown sun4v cpu type [%s]\n",
prom_cpu_compatible);
sparc_cpu_type = "Unknown SUN4V CPU";
sparc_fpu_type = "Unknown SUN4V FPU";
+ sparc_pmu_type = "Unknown SUN4V PMU";
break;
}
}
diff --git a/arch/sparc/kernel/cpumap.c b/arch/sparc/kernel/cpumap.c
index d91fd78..4197e8d 100644
--- a/arch/sparc/kernel/cpumap.c
+++ b/arch/sparc/kernel/cpumap.c
@@ -324,6 +324,7 @@
switch (sun4v_chip_type) {
case SUN4V_CHIP_NIAGARA1:
case SUN4V_CHIP_NIAGARA2:
+ case SUN4V_CHIP_NIAGARA3:
rover_inc_table = niagara_iterate_method;
break;
default:
diff --git a/arch/sparc/kernel/ds.c b/arch/sparc/kernel/ds.c
index dd1342c..7429b47 100644
--- a/arch/sparc/kernel/ds.c
+++ b/arch/sparc/kernel/ds.c
@@ -15,12 +15,15 @@
#include <linux/reboot.h>
#include <linux/cpu.h>
+#include <asm/hypervisor.h>
#include <asm/ldc.h>
#include <asm/vio.h>
#include <asm/mdesc.h>
#include <asm/head.h>
#include <asm/irq.h>
+#include "kernel.h"
+
#define DRV_MODULE_NAME "ds"
#define PFX DRV_MODULE_NAME ": "
#define DRV_MODULE_VERSION "1.0"
@@ -828,18 +831,32 @@
}
}
+static char full_boot_str[256] __attribute__((aligned(32)));
+static int reboot_data_supported;
+
void ldom_reboot(const char *boot_command)
{
/* Don't bother with any of this if the boot_command
* is empty.
*/
if (boot_command && strlen(boot_command)) {
- char full_boot_str[256];
+ unsigned long len;
strcpy(full_boot_str, "boot ");
strcpy(full_boot_str + strlen("boot "), boot_command);
+ len = strlen(full_boot_str);
- ldom_set_var("reboot-command", full_boot_str);
+ if (reboot_data_supported) {
+ unsigned long ra = kimage_addr_to_ra(full_boot_str);
+ unsigned long hv_ret;
+
+ hv_ret = sun4v_reboot_data_set(ra, len);
+ if (hv_ret != HV_EOK)
+ pr_err("SUN4V: Unable to set reboot data "
+ "hv_ret=%lu\n", hv_ret);
+ } else {
+ ldom_set_var("reboot-command", full_boot_str);
+ }
}
sun4v_mach_sir();
}
@@ -1237,6 +1254,16 @@
static int __init ds_init(void)
{
+ unsigned long hv_ret, major, minor;
+
+ if (tlb_type == hypervisor) {
+ hv_ret = sun4v_get_version(HV_GRP_REBOOT_DATA, &major, &minor);
+ if (hv_ret == HV_EOK) {
+ pr_info("SUN4V: Reboot data supported (maj=%lu,min=%lu).\n",
+ major, minor);
+ reboot_data_supported = 1;
+ }
+ }
kthread_run(ds_thread, NULL, "kldomd");
return vio_register_driver(&ds_driver);
diff --git a/arch/sparc/kernel/entry.h b/arch/sparc/kernel/entry.h
index d1f1361..e27f8ea 100644
--- a/arch/sparc/kernel/entry.h
+++ b/arch/sparc/kernel/entry.h
@@ -42,6 +42,20 @@
extern void fpload(unsigned long *fpregs, unsigned long *fsr);
#else /* CONFIG_SPARC32 */
+struct popc_3insn_patch_entry {
+ unsigned int addr;
+ unsigned int insns[3];
+};
+extern struct popc_3insn_patch_entry __popc_3insn_patch,
+ __popc_3insn_patch_end;
+
+struct popc_6insn_patch_entry {
+ unsigned int addr;
+ unsigned int insns[6];
+};
+extern struct popc_6insn_patch_entry __popc_6insn_patch,
+ __popc_6insn_patch_end;
+
extern void __init per_cpu_patch(void);
extern void __init sun4v_patch(void);
extern void __init boot_cpu_id_too_large(int cpu);
diff --git a/arch/sparc/kernel/head_64.S b/arch/sparc/kernel/head_64.S
index aa594c7..0cbab31 100644
--- a/arch/sparc/kernel/head_64.S
+++ b/arch/sparc/kernel/head_64.S
@@ -132,6 +132,8 @@
.asciz "sun4v"
prom_niagara_prefix:
.asciz "SUNW,UltraSPARC-T"
+prom_sparc_prefix:
+ .asciz "SPARC-T"
.align 4
prom_root_compatible:
.skip 64
@@ -382,6 +384,22 @@
90: ldub [%g7], %g2
ldub [%g1], %g4
cmp %g2, %g4
+ bne,pn %icc, 89f
+ add %g7, 1, %g7
+ subcc %g3, 1, %g3
+ bne,pt %xcc, 90b
+ add %g1, 1, %g1
+ ba,pt %xcc, 91f
+ nop
+
+89: sethi %hi(prom_cpu_compatible), %g1
+ or %g1, %lo(prom_cpu_compatible), %g1
+ sethi %hi(prom_sparc_prefix), %g7
+ or %g7, %lo(prom_sparc_prefix), %g7
+ mov 7, %g3
+90: ldub [%g7], %g2
+ ldub [%g1], %g4
+ cmp %g2, %g4
bne,pn %icc, 4f
add %g7, 1, %g7
subcc %g3, 1, %g3
@@ -390,6 +408,15 @@
sethi %hi(prom_cpu_compatible), %g1
or %g1, %lo(prom_cpu_compatible), %g1
+ ldub [%g1 + 7], %g2
+ cmp %g2, '3'
+ be,pt %xcc, 5f
+ mov SUN4V_CHIP_NIAGARA3, %g4
+ ba,pt %xcc, 4f
+ nop
+
+91: sethi %hi(prom_cpu_compatible), %g1
+ or %g1, %lo(prom_cpu_compatible), %g1
ldub [%g1 + 17], %g2
cmp %g2, '1'
be,pt %xcc, 5f
@@ -397,6 +424,7 @@
cmp %g2, '2'
be,pt %xcc, 5f
mov SUN4V_CHIP_NIAGARA2, %g4
+
4:
mov SUN4V_CHIP_UNKNOWN, %g4
5: sethi %hi(sun4v_chip_type), %g2
@@ -514,6 +542,9 @@
cmp %g1, SUN4V_CHIP_NIAGARA2
be,pt %xcc, niagara2_patch
nop
+ cmp %g1, SUN4V_CHIP_NIAGARA3
+ be,pt %xcc, niagara2_patch
+ nop
call generic_patch_copyops
nop
@@ -528,7 +559,7 @@
nop
call niagara_patch_bzero
nop
- call niagara2_patch_pageops
+ call niagara_patch_pageops
nop
ba,a,pt %xcc, 80f
diff --git a/arch/sparc/kernel/hvapi.c b/arch/sparc/kernel/hvapi.c
index 7c60afb..c2d055d 100644
--- a/arch/sparc/kernel/hvapi.c
+++ b/arch/sparc/kernel/hvapi.c
@@ -28,16 +28,23 @@
{ .group = HV_GRP_CORE, .flags = FLAG_PRE_API },
{ .group = HV_GRP_INTR, },
{ .group = HV_GRP_SOFT_STATE, },
+ { .group = HV_GRP_TM, },
{ .group = HV_GRP_PCI, .flags = FLAG_PRE_API },
{ .group = HV_GRP_LDOM, },
{ .group = HV_GRP_SVC_CHAN, .flags = FLAG_PRE_API },
{ .group = HV_GRP_NCS, .flags = FLAG_PRE_API },
{ .group = HV_GRP_RNG, },
+ { .group = HV_GRP_PBOOT, },
+ { .group = HV_GRP_TPM, },
+ { .group = HV_GRP_SDIO, },
+ { .group = HV_GRP_SDIO_ERR, },
+ { .group = HV_GRP_REBOOT_DATA, },
{ .group = HV_GRP_NIAG_PERF, .flags = FLAG_PRE_API },
{ .group = HV_GRP_FIRE_PERF, },
{ .group = HV_GRP_N2_CPU, },
{ .group = HV_GRP_NIU, },
{ .group = HV_GRP_VF_CPU, },
+ { .group = HV_GRP_KT_CPU, },
{ .group = HV_GRP_DIAG, .flags = FLAG_PRE_API },
};
diff --git a/arch/sparc/kernel/hvcalls.S b/arch/sparc/kernel/hvcalls.S
index 8a5f35f..58d60de 100644
--- a/arch/sparc/kernel/hvcalls.S
+++ b/arch/sparc/kernel/hvcalls.S
@@ -798,3 +798,10 @@
retl
nop
ENDPROC(sun4v_niagara2_setperf)
+
+ENTRY(sun4v_reboot_data_set)
+ mov HV_FAST_REBOOT_DATA_SET, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_reboot_data_set)
diff --git a/arch/sparc/kernel/irq.h b/arch/sparc/kernel/irq.h
index 100b9c2..4285112 100644
--- a/arch/sparc/kernel/irq.h
+++ b/arch/sparc/kernel/irq.h
@@ -88,7 +88,7 @@
#define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu)
/* All SUN4D IPIs are sent on this IRQ, may be shared with hard IRQs */
-#define SUN4D_IPI_IRQ 14
+#define SUN4D_IPI_IRQ 13
extern void sun4d_ipi_interrupt(void);
diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h
index 6f6544c..fd6c36b 100644
--- a/arch/sparc/kernel/kernel.h
+++ b/arch/sparc/kernel/kernel.h
@@ -4,12 +4,27 @@
#include <linux/interrupt.h>
#include <asm/traps.h>
+#include <asm/head.h>
+#include <asm/io.h>
/* cpu.c */
extern const char *sparc_pmu_type;
extern unsigned int fsr_storage;
extern int ncpus_probed;
+#ifdef CONFIG_SPARC64
+/* setup_64.c */
+struct seq_file;
+extern void cpucap_info(struct seq_file *);
+
+static inline unsigned long kimage_addr_to_ra(const char *p)
+{
+ unsigned long val = (unsigned long) p;
+
+ return kern_base + (val - KERNBASE);
+}
+#endif
+
#ifdef CONFIG_SPARC32
/* cpu.c */
extern void cpu_probe(void);
diff --git a/arch/sparc/kernel/ktlb.S b/arch/sparc/kernel/ktlb.S
index 1d36147..79f3103 100644
--- a/arch/sparc/kernel/ktlb.S
+++ b/arch/sparc/kernel/ktlb.S
@@ -47,16 +47,16 @@
kvmap_itlb_vmalloc_addr:
KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_itlb_longpath)
- KTSB_LOCK_TAG(%g1, %g2, %g7)
+ TSB_LOCK_TAG(%g1, %g2, %g7)
/* Load and check PTE. */
ldxa [%g5] ASI_PHYS_USE_EC, %g5
mov 1, %g7
sllx %g7, TSB_TAG_INVALID_BIT, %g7
brgez,a,pn %g5, kvmap_itlb_longpath
- KTSB_STORE(%g1, %g7)
+ TSB_STORE(%g1, %g7)
- KTSB_WRITE(%g1, %g5, %g6)
+ TSB_WRITE(%g1, %g5, %g6)
/* fallthrough to TLB load */
@@ -102,9 +102,9 @@
kvmap_itlb_obp:
OBP_TRANS_LOOKUP(%g4, %g5, %g2, %g3, kvmap_itlb_longpath)
- KTSB_LOCK_TAG(%g1, %g2, %g7)
+ TSB_LOCK_TAG(%g1, %g2, %g7)
- KTSB_WRITE(%g1, %g5, %g6)
+ TSB_WRITE(%g1, %g5, %g6)
ba,pt %xcc, kvmap_itlb_load
nop
@@ -112,17 +112,17 @@
kvmap_dtlb_obp:
OBP_TRANS_LOOKUP(%g4, %g5, %g2, %g3, kvmap_dtlb_longpath)
- KTSB_LOCK_TAG(%g1, %g2, %g7)
+ TSB_LOCK_TAG(%g1, %g2, %g7)
- KTSB_WRITE(%g1, %g5, %g6)
+ TSB_WRITE(%g1, %g5, %g6)
ba,pt %xcc, kvmap_dtlb_load
nop
.align 32
kvmap_dtlb_tsb4m_load:
- KTSB_LOCK_TAG(%g1, %g2, %g7)
- KTSB_WRITE(%g1, %g5, %g6)
+ TSB_LOCK_TAG(%g1, %g2, %g7)
+ TSB_WRITE(%g1, %g5, %g6)
ba,pt %xcc, kvmap_dtlb_load
nop
@@ -222,16 +222,16 @@
kvmap_dtlb_vmalloc_addr:
KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_dtlb_longpath)
- KTSB_LOCK_TAG(%g1, %g2, %g7)
+ TSB_LOCK_TAG(%g1, %g2, %g7)
/* Load and check PTE. */
ldxa [%g5] ASI_PHYS_USE_EC, %g5
mov 1, %g7
sllx %g7, TSB_TAG_INVALID_BIT, %g7
brgez,a,pn %g5, kvmap_dtlb_longpath
- KTSB_STORE(%g1, %g7)
+ TSB_STORE(%g1, %g7)
- KTSB_WRITE(%g1, %g5, %g6)
+ TSB_WRITE(%g1, %g5, %g6)
/* fallthrough to TLB load */
diff --git a/arch/sparc/kernel/mdesc.c b/arch/sparc/kernel/mdesc.c
index 42f28c7..acaebb6 100644
--- a/arch/sparc/kernel/mdesc.c
+++ b/arch/sparc/kernel/mdesc.c
@@ -508,6 +508,8 @@
}
EXPORT_SYMBOL(mdesc_node_name);
+static u64 max_cpus = 64;
+
static void __init report_platform_properties(void)
{
struct mdesc_handle *hp = mdesc_grab();
@@ -543,8 +545,10 @@
if (v)
printk("PLATFORM: watchdog-max-timeout [%llu ms]\n", *v);
v = mdesc_get_property(hp, pn, "max-cpus", NULL);
- if (v)
- printk("PLATFORM: max-cpus [%llu]\n", *v);
+ if (v) {
+ max_cpus = *v;
+ printk("PLATFORM: max-cpus [%llu]\n", max_cpus);
+ }
#ifdef CONFIG_SMP
{
@@ -715,7 +719,7 @@
}
static void __cpuinit get_one_mondo_bits(const u64 *p, unsigned int *mask,
- unsigned char def)
+ unsigned long def, unsigned long max)
{
u64 val;
@@ -726,6 +730,9 @@
if (!val || val >= 64)
goto use_default;
+ if (val > max)
+ val = max;
+
*mask = ((1U << val) * 64U) - 1U;
return;
@@ -736,19 +743,28 @@
static void __cpuinit get_mondo_data(struct mdesc_handle *hp, u64 mp,
struct trap_per_cpu *tb)
{
+ static int printed;
const u64 *val;
val = mdesc_get_property(hp, mp, "q-cpu-mondo-#bits", NULL);
- get_one_mondo_bits(val, &tb->cpu_mondo_qmask, 7);
+ get_one_mondo_bits(val, &tb->cpu_mondo_qmask, 7, ilog2(max_cpus * 2));
val = mdesc_get_property(hp, mp, "q-dev-mondo-#bits", NULL);
- get_one_mondo_bits(val, &tb->dev_mondo_qmask, 7);
+ get_one_mondo_bits(val, &tb->dev_mondo_qmask, 7, 8);
val = mdesc_get_property(hp, mp, "q-resumable-#bits", NULL);
- get_one_mondo_bits(val, &tb->resum_qmask, 6);
+ get_one_mondo_bits(val, &tb->resum_qmask, 6, 7);
val = mdesc_get_property(hp, mp, "q-nonresumable-#bits", NULL);
- get_one_mondo_bits(val, &tb->nonresum_qmask, 2);
+ get_one_mondo_bits(val, &tb->nonresum_qmask, 2, 2);
+ if (!printed++) {
+ pr_info("SUN4V: Mondo queue sizes "
+ "[cpu(%u) dev(%u) r(%u) nr(%u)]\n",
+ tb->cpu_mondo_qmask + 1,
+ tb->dev_mondo_qmask + 1,
+ tb->resum_qmask + 1,
+ tb->nonresum_qmask + 1);
+ }
}
static void * __cpuinit mdesc_iterate_over_cpus(void *(*func)(struct mdesc_handle *, u64, int, void *), void *arg, cpumask_t *mask)
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index 948601a..6418ba6 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -352,8 +352,8 @@
strcpy(pbm->prom_name, namebuf);
{
- extern volatile int t_nmi[1];
- extern int pcic_nmi_trap_patch[1];
+ extern volatile int t_nmi[4];
+ extern int pcic_nmi_trap_patch[4];
t_nmi[0] = pcic_nmi_trap_patch[0];
t_nmi[1] = pcic_nmi_trap_patch[1];
diff --git a/arch/sparc/kernel/pcr.c b/arch/sparc/kernel/pcr.c
index 8ac23e6..343b0f9 100644
--- a/arch/sparc/kernel/pcr.c
+++ b/arch/sparc/kernel/pcr.c
@@ -80,8 +80,11 @@
{
unsigned long ret;
- ret = sun4v_niagara2_setperf(HV_N2_PERF_SPARC_CTL, val);
- if (ret != HV_EOK)
+ if (val & PCR_N2_HTRACE) {
+ ret = sun4v_niagara2_setperf(HV_N2_PERF_SPARC_CTL, val);
+ if (ret != HV_EOK)
+ write_pcr(val);
+ } else
write_pcr(val);
}
@@ -106,6 +109,10 @@
perf_hsvc_group = HV_GRP_N2_CPU;
break;
+ case SUN4V_CHIP_NIAGARA3:
+ perf_hsvc_group = HV_GRP_KT_CPU;
+ break;
+
default:
return -ENODEV;
}
diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c
index 2cb0e1c..6860d40 100644
--- a/arch/sparc/kernel/perf_event.c
+++ b/arch/sparc/kernel/perf_event.c
@@ -1301,7 +1301,8 @@
sparc_pmu = &niagara1_pmu;
return true;
}
- if (!strcmp(sparc_pmu_type, "niagara2")) {
+ if (!strcmp(sparc_pmu_type, "niagara2") ||
+ !strcmp(sparc_pmu_type, "niagara3")) {
sparc_pmu = &niagara2_pmu;
return true;
}
diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c
index c4dd099..3c5bb78 100644
--- a/arch/sparc/kernel/setup_64.c
+++ b/arch/sparc/kernel/setup_64.c
@@ -29,6 +29,7 @@
#include <linux/interrupt.h>
#include <linux/cpu.h>
#include <linux/initrd.h>
+#include <linux/module.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -46,6 +47,8 @@
#include <asm/mmu.h>
#include <asm/ns87303.h>
#include <asm/btext.h>
+#include <asm/elf.h>
+#include <asm/mdesc.h>
#ifdef CONFIG_IP_PNP
#include <net/ipconfig.h>
@@ -269,6 +272,40 @@
sun4v_hvapi_init();
}
+static void __init popc_patch(void)
+{
+ struct popc_3insn_patch_entry *p3;
+ struct popc_6insn_patch_entry *p6;
+
+ p3 = &__popc_3insn_patch;
+ while (p3 < &__popc_3insn_patch_end) {
+ unsigned long i, addr = p3->addr;
+
+ for (i = 0; i < 3; i++) {
+ *(unsigned int *) (addr + (i * 4)) = p3->insns[i];
+ wmb();
+ __asm__ __volatile__("flush %0"
+ : : "r" (addr + (i * 4)));
+ }
+
+ p3++;
+ }
+
+ p6 = &__popc_6insn_patch;
+ while (p6 < &__popc_6insn_patch_end) {
+ unsigned long i, addr = p6->addr;
+
+ for (i = 0; i < 6; i++) {
+ *(unsigned int *) (addr + (i * 4)) = p6->insns[i];
+ wmb();
+ __asm__ __volatile__("flush %0"
+ : : "r" (addr + (i * 4)));
+ }
+
+ p6++;
+ }
+}
+
#ifdef CONFIG_SMP
void __init boot_cpu_id_too_large(int cpu)
{
@@ -278,6 +315,160 @@
}
#endif
+/* On Ultra, we support all of the v8 capabilities. */
+unsigned long sparc64_elf_hwcap = (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR |
+ HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV |
+ HWCAP_SPARC_V9);
+EXPORT_SYMBOL(sparc64_elf_hwcap);
+
+static const char *hwcaps[] = {
+ "flush", "stbar", "swap", "muldiv", "v9",
+ "ultra3", "blkinit", "n2",
+
+ /* These strings are as they appear in the machine description
+ * 'hwcap-list' property for cpu nodes.
+ */
+ "mul32", "div32", "fsmuld", "v8plus", "popc", "vis", "vis2",
+ "ASIBlkInit", "fmaf", "vis3", "hpc", "random", "trans", "fjfmau",
+ "ima", "cspare",
+};
+
+void cpucap_info(struct seq_file *m)
+{
+ unsigned long caps = sparc64_elf_hwcap;
+ int i, printed = 0;
+
+ seq_puts(m, "cpucaps\t\t: ");
+ for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
+ unsigned long bit = 1UL << i;
+ if (caps & bit) {
+ seq_printf(m, "%s%s",
+ printed ? "," : "", hwcaps[i]);
+ printed++;
+ }
+ }
+ seq_putc(m, '\n');
+}
+
+static void __init report_hwcaps(unsigned long caps)
+{
+ int i, printed = 0;
+
+ printk(KERN_INFO "CPU CAPS: [");
+ for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
+ unsigned long bit = 1UL << i;
+ if (caps & bit) {
+ printk(KERN_CONT "%s%s",
+ printed ? "," : "", hwcaps[i]);
+ if (++printed == 8) {
+ printk(KERN_CONT "]\n");
+ printk(KERN_INFO "CPU CAPS: [");
+ printed = 0;
+ }
+ }
+ }
+ printk(KERN_CONT "]\n");
+}
+
+static unsigned long __init mdesc_cpu_hwcap_list(void)
+{
+ struct mdesc_handle *hp;
+ unsigned long caps = 0;
+ const char *prop;
+ int len;
+ u64 pn;
+
+ hp = mdesc_grab();
+ if (!hp)
+ return 0;
+
+ pn = mdesc_node_by_name(hp, MDESC_NODE_NULL, "cpu");
+ if (pn == MDESC_NODE_NULL)
+ goto out;
+
+ prop = mdesc_get_property(hp, pn, "hwcap-list", &len);
+ if (!prop)
+ goto out;
+
+ while (len) {
+ int i, plen;
+
+ for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
+ unsigned long bit = 1UL << i;
+
+ if (!strcmp(prop, hwcaps[i])) {
+ caps |= bit;
+ break;
+ }
+ }
+
+ plen = strlen(prop) + 1;
+ prop += plen;
+ len -= plen;
+ }
+
+out:
+ mdesc_release(hp);
+ return caps;
+}
+
+/* This yields a mask that user programs can use to figure out what
+ * instruction set this cpu supports.
+ */
+static void __init init_sparc64_elf_hwcap(void)
+{
+ unsigned long cap = sparc64_elf_hwcap;
+ unsigned long mdesc_caps;
+
+ if (tlb_type == cheetah || tlb_type == cheetah_plus)
+ cap |= HWCAP_SPARC_ULTRA3;
+ else if (tlb_type == hypervisor) {
+ if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1 ||
+ sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
+ sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
+ cap |= HWCAP_SPARC_BLKINIT;
+ if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
+ sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
+ cap |= HWCAP_SPARC_N2;
+ }
+
+ cap |= (AV_SPARC_MUL32 | AV_SPARC_DIV32 | AV_SPARC_V8PLUS);
+
+ mdesc_caps = mdesc_cpu_hwcap_list();
+ if (!mdesc_caps) {
+ if (tlb_type == spitfire)
+ cap |= AV_SPARC_VIS;
+ if (tlb_type == cheetah || tlb_type == cheetah_plus)
+ cap |= AV_SPARC_VIS | AV_SPARC_VIS2;
+ if (tlb_type == cheetah_plus) {
+ unsigned long impl, ver;
+
+ __asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver));
+ impl = ((ver >> 32) & 0xffff);
+ if (impl == PANTHER_IMPL)
+ cap |= AV_SPARC_POPC;
+ }
+ if (tlb_type == hypervisor) {
+ if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1)
+ cap |= AV_SPARC_ASI_BLK_INIT;
+ if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
+ sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
+ cap |= (AV_SPARC_VIS | AV_SPARC_VIS2 |
+ AV_SPARC_ASI_BLK_INIT |
+ AV_SPARC_POPC);
+ if (sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
+ cap |= (AV_SPARC_VIS3 | AV_SPARC_HPC |
+ AV_SPARC_FMAF);
+ }
+ }
+ sparc64_elf_hwcap = cap | mdesc_caps;
+
+ report_hwcaps(sparc64_elf_hwcap);
+
+ if (sparc64_elf_hwcap & AV_SPARC_POPC)
+ popc_patch();
+}
+
void __init setup_arch(char **cmdline_p)
{
/* Initialize PROM console and command line. */
@@ -337,6 +528,7 @@
init_cur_cpu_trap(current_thread_info());
paging_init();
+ init_sparc64_elf_hwcap();
}
extern int stop_a_enabled;
diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c
index 75fad42..5d92488 100644
--- a/arch/sparc/kernel/signal32.c
+++ b/arch/sparc/kernel/signal32.c
@@ -29,6 +29,8 @@
#include <asm/visasm.h>
#include <asm/compat_signal.h>
+#include "sigutil.h"
+
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
/* This magic should be in g_upper[0] for all upper parts
@@ -44,14 +46,14 @@
struct signal_frame32 {
struct sparc_stackf32 ss;
__siginfo32_t info;
- /* __siginfo_fpu32_t * */ u32 fpu_save;
+ /* __siginfo_fpu_t * */ u32 fpu_save;
unsigned int insns[2];
unsigned int extramask[_COMPAT_NSIG_WORDS - 1];
unsigned int extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
/* Only valid if (info.si_regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
siginfo_extra_v8plus_t v8plus;
- __siginfo_fpu_t fpu_state;
-};
+ /* __siginfo_rwin_t * */u32 rwin_save;
+} __attribute__((aligned(8)));
typedef struct compat_siginfo{
int si_signo;
@@ -110,18 +112,14 @@
compat_siginfo_t info;
struct pt_regs32 regs;
compat_sigset_t mask;
- /* __siginfo_fpu32_t * */ u32 fpu_save;
+ /* __siginfo_fpu_t * */ u32 fpu_save;
unsigned int insns[2];
stack_t32 stack;
unsigned int extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
/* Only valid if (regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
siginfo_extra_v8plus_t v8plus;
- __siginfo_fpu_t fpu_state;
-};
-
-/* Align macros */
-#define SF_ALIGNEDSZ (((sizeof(struct signal_frame32) + 15) & (~15)))
-#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame32) + 15) & (~15)))
+ /* __siginfo_rwin_t * */u32 rwin_save;
+} __attribute__((aligned(8)));
int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
{
@@ -192,30 +190,13 @@
return 0;
}
-static int restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
- unsigned long *fpregs = current_thread_info()->fpregs;
- unsigned long fprs;
- int err;
-
- err = __get_user(fprs, &fpu->si_fprs);
- fprs_write(0);
- regs->tstate &= ~TSTATE_PEF;
- if (fprs & FPRS_DL)
- err |= copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 32));
- if (fprs & FPRS_DU)
- err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32], (sizeof(unsigned int) * 32));
- err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
- err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
- current_thread_info()->fpsaved[0] |= fprs;
- return err;
-}
-
void do_sigreturn32(struct pt_regs *regs)
{
struct signal_frame32 __user *sf;
+ compat_uptr_t fpu_save;
+ compat_uptr_t rwin_save;
unsigned int psr;
- unsigned pc, npc, fpu_save;
+ unsigned pc, npc;
sigset_t set;
unsigned seta[_COMPAT_NSIG_WORDS];
int err, i;
@@ -273,8 +254,13 @@
pt_regs_clear_syscall(regs);
err |= __get_user(fpu_save, &sf->fpu_save);
- if (fpu_save)
- err |= restore_fpu_state32(regs, &sf->fpu_state);
+ if (!err && fpu_save)
+ err |= restore_fpu_state(regs, compat_ptr(fpu_save));
+ err |= __get_user(rwin_save, &sf->rwin_save);
+ if (!err && rwin_save) {
+ if (restore_rwin_state(compat_ptr(rwin_save)))
+ goto segv;
+ }
err |= __get_user(seta[0], &sf->info.si_mask);
err |= copy_from_user(seta+1, &sf->extramask,
(_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
@@ -300,7 +286,9 @@
asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
{
struct rt_signal_frame32 __user *sf;
- unsigned int psr, pc, npc, fpu_save, u_ss_sp;
+ unsigned int psr, pc, npc, u_ss_sp;
+ compat_uptr_t fpu_save;
+ compat_uptr_t rwin_save;
mm_segment_t old_fs;
sigset_t set;
compat_sigset_t seta;
@@ -359,8 +347,8 @@
pt_regs_clear_syscall(regs);
err |= __get_user(fpu_save, &sf->fpu_save);
- if (fpu_save)
- err |= restore_fpu_state32(regs, &sf->fpu_state);
+ if (!err && fpu_save)
+ err |= restore_fpu_state(regs, compat_ptr(fpu_save));
err |= copy_from_user(&seta, &sf->mask, sizeof(compat_sigset_t));
err |= __get_user(u_ss_sp, &sf->stack.ss_sp);
st.ss_sp = compat_ptr(u_ss_sp);
@@ -376,6 +364,12 @@
do_sigaltstack((stack_t __user *) &st, NULL, (unsigned long)sf);
set_fs(old_fs);
+ err |= __get_user(rwin_save, &sf->rwin_save);
+ if (!err && rwin_save) {
+ if (restore_rwin_state(compat_ptr(rwin_save)))
+ goto segv;
+ }
+
switch (_NSIG_WORDS) {
case 4: set.sig[3] = seta.sig[6] + (((long)seta.sig[7]) << 32);
case 3: set.sig[2] = seta.sig[4] + (((long)seta.sig[5]) << 32);
@@ -433,26 +427,6 @@
return (void __user *) sp;
}
-static int save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
- unsigned long *fpregs = current_thread_info()->fpregs;
- unsigned long fprs;
- int err = 0;
-
- fprs = current_thread_info()->fpsaved[0];
- if (fprs & FPRS_DL)
- err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
- (sizeof(unsigned int) * 32));
- if (fprs & FPRS_DU)
- err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
- (sizeof(unsigned int) * 32));
- err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
- err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
- err |= __put_user(fprs, &fpu->si_fprs);
-
- return err;
-}
-
/* The I-cache flush instruction only works in the primary ASI, which
* right now is the nucleus, aka. kernel space.
*
@@ -515,18 +489,23 @@
int signo, sigset_t *oldset)
{
struct signal_frame32 __user *sf;
+ int i, err, wsaved;
+ void __user *tail;
int sigframe_size;
u32 psr;
- int i, err;
unsigned int seta[_COMPAT_NSIG_WORDS];
/* 1. Make sure everything is clean */
synchronize_user_stack();
save_and_clear_fpu();
- sigframe_size = SF_ALIGNEDSZ;
- if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
- sigframe_size -= sizeof(__siginfo_fpu_t);
+ wsaved = get_thread_wsaved();
+
+ sigframe_size = sizeof(*sf);
+ if (current_thread_info()->fpsaved[0] & FPRS_FEF)
+ sigframe_size += sizeof(__siginfo_fpu_t);
+ if (wsaved)
+ sigframe_size += sizeof(__siginfo_rwin_t);
sf = (struct signal_frame32 __user *)
get_sigframe(&ka->sa, regs, sigframe_size);
@@ -534,8 +513,7 @@
if (invalid_frame_pointer(sf, sigframe_size))
goto sigill;
- if (get_thread_wsaved() != 0)
- goto sigill;
+ tail = (sf + 1);
/* 2. Save the current process state */
if (test_thread_flag(TIF_32BIT)) {
@@ -560,11 +538,22 @@
&sf->v8plus.asi);
if (psr & PSR_EF) {
- err |= save_fpu_state32(regs, &sf->fpu_state);
- err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
+ __siginfo_fpu_t __user *fp = tail;
+ tail += sizeof(*fp);
+ err |= save_fpu_state(regs, fp);
+ err |= __put_user((u64)fp, &sf->fpu_save);
} else {
err |= __put_user(0, &sf->fpu_save);
}
+ if (wsaved) {
+ __siginfo_rwin_t __user *rwp = tail;
+ tail += sizeof(*rwp);
+ err |= save_rwin_state(wsaved, rwp);
+ err |= __put_user((u64)rwp, &sf->rwin_save);
+ set_thread_wsaved(0);
+ } else {
+ err |= __put_user(0, &sf->rwin_save);
+ }
switch (_NSIG_WORDS) {
case 4: seta[7] = (oldset->sig[3] >> 32);
@@ -580,10 +569,21 @@
err |= __copy_to_user(sf->extramask, seta + 1,
(_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
- err |= copy_in_user((u32 __user *)sf,
- (u32 __user *)(regs->u_regs[UREG_FP]),
- sizeof(struct reg_window32));
-
+ if (!wsaved) {
+ err |= copy_in_user((u32 __user *)sf,
+ (u32 __user *)(regs->u_regs[UREG_FP]),
+ sizeof(struct reg_window32));
+ } else {
+ struct reg_window *rp;
+
+ rp = ¤t_thread_info()->reg_window[wsaved - 1];
+ for (i = 0; i < 8; i++)
+ err |= __put_user(rp->locals[i], &sf->ss.locals[i]);
+ for (i = 0; i < 6; i++)
+ err |= __put_user(rp->ins[i], &sf->ss.ins[i]);
+ err |= __put_user(rp->ins[6], &sf->ss.fp);
+ err |= __put_user(rp->ins[7], &sf->ss.callers_pc);
+ }
if (err)
goto sigsegv;
@@ -613,7 +613,6 @@
err |= __put_user(0x91d02010, &sf->insns[1]); /*t 0x10*/
if (err)
goto sigsegv;
-
flush_signal_insns(address);
}
return 0;
@@ -632,18 +631,23 @@
siginfo_t *info)
{
struct rt_signal_frame32 __user *sf;
+ int i, err, wsaved;
+ void __user *tail;
int sigframe_size;
u32 psr;
- int i, err;
compat_sigset_t seta;
/* 1. Make sure everything is clean */
synchronize_user_stack();
save_and_clear_fpu();
- sigframe_size = RT_ALIGNEDSZ;
- if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
- sigframe_size -= sizeof(__siginfo_fpu_t);
+ wsaved = get_thread_wsaved();
+
+ sigframe_size = sizeof(*sf);
+ if (current_thread_info()->fpsaved[0] & FPRS_FEF)
+ sigframe_size += sizeof(__siginfo_fpu_t);
+ if (wsaved)
+ sigframe_size += sizeof(__siginfo_rwin_t);
sf = (struct rt_signal_frame32 __user *)
get_sigframe(&ka->sa, regs, sigframe_size);
@@ -651,8 +655,7 @@
if (invalid_frame_pointer(sf, sigframe_size))
goto sigill;
- if (get_thread_wsaved() != 0)
- goto sigill;
+ tail = (sf + 1);
/* 2. Save the current process state */
if (test_thread_flag(TIF_32BIT)) {
@@ -677,11 +680,22 @@
&sf->v8plus.asi);
if (psr & PSR_EF) {
- err |= save_fpu_state32(regs, &sf->fpu_state);
- err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
+ __siginfo_fpu_t __user *fp = tail;
+ tail += sizeof(*fp);
+ err |= save_fpu_state(regs, fp);
+ err |= __put_user((u64)fp, &sf->fpu_save);
} else {
err |= __put_user(0, &sf->fpu_save);
}
+ if (wsaved) {
+ __siginfo_rwin_t __user *rwp = tail;
+ tail += sizeof(*rwp);
+ err |= save_rwin_state(wsaved, rwp);
+ err |= __put_user((u64)rwp, &sf->rwin_save);
+ set_thread_wsaved(0);
+ } else {
+ err |= __put_user(0, &sf->rwin_save);
+ }
/* Update the siginfo structure. */
err |= copy_siginfo_to_user32(&sf->info, info);
@@ -703,9 +717,21 @@
}
err |= __copy_to_user(&sf->mask, &seta, sizeof(compat_sigset_t));
- err |= copy_in_user((u32 __user *)sf,
- (u32 __user *)(regs->u_regs[UREG_FP]),
- sizeof(struct reg_window32));
+ if (!wsaved) {
+ err |= copy_in_user((u32 __user *)sf,
+ (u32 __user *)(regs->u_regs[UREG_FP]),
+ sizeof(struct reg_window32));
+ } else {
+ struct reg_window *rp;
+
+ rp = ¤t_thread_info()->reg_window[wsaved - 1];
+ for (i = 0; i < 8; i++)
+ err |= __put_user(rp->locals[i], &sf->ss.locals[i]);
+ for (i = 0; i < 6; i++)
+ err |= __put_user(rp->ins[i], &sf->ss.ins[i]);
+ err |= __put_user(rp->ins[6], &sf->ss.fp);
+ err |= __put_user(rp->ins[7], &sf->ss.callers_pc);
+ }
if (err)
goto sigsegv;
diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c
index 5e5c5fd..04ede8f 100644
--- a/arch/sparc/kernel/signal_32.c
+++ b/arch/sparc/kernel/signal_32.c
@@ -26,6 +26,8 @@
#include <asm/pgtable.h>
#include <asm/cacheflush.h> /* flush_sig_insns */
+#include "sigutil.h"
+
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
@@ -39,8 +41,8 @@
unsigned long insns[2] __attribute__ ((aligned (8)));
unsigned int extramask[_NSIG_WORDS - 1];
unsigned int extra_size; /* Should be 0 */
- __siginfo_fpu_t fpu_state;
-};
+ __siginfo_rwin_t __user *rwin_save;
+} __attribute__((aligned(8)));
struct rt_signal_frame {
struct sparc_stackf ss;
@@ -51,8 +53,8 @@
unsigned int insns[2];
stack_t stack;
unsigned int extra_size; /* Should be 0 */
- __siginfo_fpu_t fpu_state;
-};
+ __siginfo_rwin_t __user *rwin_save;
+} __attribute__((aligned(8)));
/* Align macros */
#define SF_ALIGNEDSZ (((sizeof(struct signal_frame) + 7) & (~7)))
@@ -79,43 +81,13 @@
return _sigpause_common(set);
}
-static inline int
-restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
- int err;
-#ifdef CONFIG_SMP
- if (test_tsk_thread_flag(current, TIF_USEDFPU))
- regs->psr &= ~PSR_EF;
-#else
- if (current == last_task_used_math) {
- last_task_used_math = NULL;
- regs->psr &= ~PSR_EF;
- }
-#endif
- set_used_math();
- clear_tsk_thread_flag(current, TIF_USEDFPU);
-
- if (!access_ok(VERIFY_READ, fpu, sizeof(*fpu)))
- return -EFAULT;
-
- err = __copy_from_user(¤t->thread.float_regs[0], &fpu->si_float_regs[0],
- (sizeof(unsigned long) * 32));
- err |= __get_user(current->thread.fsr, &fpu->si_fsr);
- err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
- if (current->thread.fpqdepth != 0)
- err |= __copy_from_user(¤t->thread.fpqueue[0],
- &fpu->si_fpqueue[0],
- ((sizeof(unsigned long) +
- (sizeof(unsigned long *)))*16));
- return err;
-}
-
asmlinkage void do_sigreturn(struct pt_regs *regs)
{
struct signal_frame __user *sf;
unsigned long up_psr, pc, npc;
sigset_t set;
__siginfo_fpu_t __user *fpu_save;
+ __siginfo_rwin_t __user *rwin_save;
int err;
/* Always make any pending restarted system calls return -EINTR */
@@ -150,9 +122,11 @@
pt_regs_clear_syscall(regs);
err |= __get_user(fpu_save, &sf->fpu_save);
-
if (fpu_save)
err |= restore_fpu_state(regs, fpu_save);
+ err |= __get_user(rwin_save, &sf->rwin_save);
+ if (rwin_save)
+ err |= restore_rwin_state(rwin_save);
/* This is pretty much atomic, no amount locking would prevent
* the races which exist anyways.
@@ -180,6 +154,7 @@
struct rt_signal_frame __user *sf;
unsigned int psr, pc, npc;
__siginfo_fpu_t __user *fpu_save;
+ __siginfo_rwin_t __user *rwin_save;
mm_segment_t old_fs;
sigset_t set;
stack_t st;
@@ -207,8 +182,7 @@
pt_regs_clear_syscall(regs);
err |= __get_user(fpu_save, &sf->fpu_save);
-
- if (fpu_save)
+ if (!err && fpu_save)
err |= restore_fpu_state(regs, fpu_save);
err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
@@ -228,6 +202,12 @@
do_sigaltstack((const stack_t __user *) &st, NULL, (unsigned long)sf);
set_fs(old_fs);
+ err |= __get_user(rwin_save, &sf->rwin_save);
+ if (!err && rwin_save) {
+ if (restore_rwin_state(rwin_save))
+ goto segv;
+ }
+
sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(¤t->sighand->siglock);
current->blocked = set;
@@ -280,53 +260,23 @@
return (void __user *) sp;
}
-static inline int
-save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
- int err = 0;
-#ifdef CONFIG_SMP
- if (test_tsk_thread_flag(current, TIF_USEDFPU)) {
- put_psr(get_psr() | PSR_EF);
- fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr,
- ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth);
- regs->psr &= ~(PSR_EF);
- clear_tsk_thread_flag(current, TIF_USEDFPU);
- }
-#else
- if (current == last_task_used_math) {
- put_psr(get_psr() | PSR_EF);
- fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr,
- ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth);
- last_task_used_math = NULL;
- regs->psr &= ~(PSR_EF);
- }
-#endif
- err |= __copy_to_user(&fpu->si_float_regs[0],
- ¤t->thread.float_regs[0],
- (sizeof(unsigned long) * 32));
- err |= __put_user(current->thread.fsr, &fpu->si_fsr);
- err |= __put_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
- if (current->thread.fpqdepth != 0)
- err |= __copy_to_user(&fpu->si_fpqueue[0],
- ¤t->thread.fpqueue[0],
- ((sizeof(unsigned long) +
- (sizeof(unsigned long *)))*16));
- clear_used_math();
- return err;
-}
-
static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
int signo, sigset_t *oldset)
{
struct signal_frame __user *sf;
- int sigframe_size, err;
+ int sigframe_size, err, wsaved;
+ void __user *tail;
/* 1. Make sure everything is clean */
synchronize_user_stack();
- sigframe_size = SF_ALIGNEDSZ;
- if (!used_math())
- sigframe_size -= sizeof(__siginfo_fpu_t);
+ wsaved = current_thread_info()->w_saved;
+
+ sigframe_size = sizeof(*sf);
+ if (used_math())
+ sigframe_size += sizeof(__siginfo_fpu_t);
+ if (wsaved)
+ sigframe_size += sizeof(__siginfo_rwin_t);
sf = (struct signal_frame __user *)
get_sigframe(&ka->sa, regs, sigframe_size);
@@ -334,8 +284,7 @@
if (invalid_frame_pointer(sf, sigframe_size))
goto sigill_and_return;
- if (current_thread_info()->w_saved != 0)
- goto sigill_and_return;
+ tail = sf + 1;
/* 2. Save the current process state */
err = __copy_to_user(&sf->info.si_regs, regs, sizeof(struct pt_regs));
@@ -343,17 +292,34 @@
err |= __put_user(0, &sf->extra_size);
if (used_math()) {
- err |= save_fpu_state(regs, &sf->fpu_state);
- err |= __put_user(&sf->fpu_state, &sf->fpu_save);
+ __siginfo_fpu_t __user *fp = tail;
+ tail += sizeof(*fp);
+ err |= save_fpu_state(regs, fp);
+ err |= __put_user(fp, &sf->fpu_save);
} else {
err |= __put_user(0, &sf->fpu_save);
}
+ if (wsaved) {
+ __siginfo_rwin_t __user *rwp = tail;
+ tail += sizeof(*rwp);
+ err |= save_rwin_state(wsaved, rwp);
+ err |= __put_user(rwp, &sf->rwin_save);
+ } else {
+ err |= __put_user(0, &sf->rwin_save);
+ }
err |= __put_user(oldset->sig[0], &sf->info.si_mask);
err |= __copy_to_user(sf->extramask, &oldset->sig[1],
(_NSIG_WORDS - 1) * sizeof(unsigned int));
- err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
- sizeof(struct reg_window32));
+ if (!wsaved) {
+ err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
+ sizeof(struct reg_window32));
+ } else {
+ struct reg_window32 *rp;
+
+ rp = ¤t_thread_info()->reg_window[wsaved - 1];
+ err |= __copy_to_user(sf, rp, sizeof(struct reg_window32));
+ }
if (err)
goto sigsegv;
@@ -399,21 +365,24 @@
int signo, sigset_t *oldset, siginfo_t *info)
{
struct rt_signal_frame __user *sf;
- int sigframe_size;
+ int sigframe_size, wsaved;
+ void __user *tail;
unsigned int psr;
int err;
synchronize_user_stack();
- sigframe_size = RT_ALIGNEDSZ;
- if (!used_math())
- sigframe_size -= sizeof(__siginfo_fpu_t);
+ wsaved = current_thread_info()->w_saved;
+ sigframe_size = sizeof(*sf);
+ if (used_math())
+ sigframe_size += sizeof(__siginfo_fpu_t);
+ if (wsaved)
+ sigframe_size += sizeof(__siginfo_rwin_t);
sf = (struct rt_signal_frame __user *)
get_sigframe(&ka->sa, regs, sigframe_size);
if (invalid_frame_pointer(sf, sigframe_size))
goto sigill;
- if (current_thread_info()->w_saved != 0)
- goto sigill;
+ tail = sf + 1;
err = __put_user(regs->pc, &sf->regs.pc);
err |= __put_user(regs->npc, &sf->regs.npc);
err |= __put_user(regs->y, &sf->regs.y);
@@ -425,11 +394,21 @@
err |= __put_user(0, &sf->extra_size);
if (psr & PSR_EF) {
- err |= save_fpu_state(regs, &sf->fpu_state);
- err |= __put_user(&sf->fpu_state, &sf->fpu_save);
+ __siginfo_fpu_t *fp = tail;
+ tail += sizeof(*fp);
+ err |= save_fpu_state(regs, fp);
+ err |= __put_user(fp, &sf->fpu_save);
} else {
err |= __put_user(0, &sf->fpu_save);
}
+ if (wsaved) {
+ __siginfo_rwin_t *rwp = tail;
+ tail += sizeof(*rwp);
+ err |= save_rwin_state(wsaved, rwp);
+ err |= __put_user(rwp, &sf->rwin_save);
+ } else {
+ err |= __put_user(0, &sf->rwin_save);
+ }
err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t));
/* Setup sigaltstack */
@@ -437,8 +416,15 @@
err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
- err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
- sizeof(struct reg_window32));
+ if (!wsaved) {
+ err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
+ sizeof(struct reg_window32));
+ } else {
+ struct reg_window32 *rp;
+
+ rp = ¤t_thread_info()->reg_window[wsaved - 1];
+ err |= __copy_to_user(sf, rp, sizeof(struct reg_window32));
+ }
err |= copy_siginfo_to_user(&sf->info, info);
diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c
index 006fe45..47509df 100644
--- a/arch/sparc/kernel/signal_64.c
+++ b/arch/sparc/kernel/signal_64.c
@@ -34,6 +34,7 @@
#include "entry.h"
#include "systbls.h"
+#include "sigutil.h"
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
@@ -236,7 +237,7 @@
__siginfo_fpu_t __user *fpu_save;
stack_t stack;
sigset_t mask;
- __siginfo_fpu_t fpu_state;
+ __siginfo_rwin_t *rwin_save;
};
static long _sigpause_common(old_sigset_t set)
@@ -266,33 +267,12 @@
return _sigpause_common(set);
}
-static inline int
-restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
- unsigned long *fpregs = current_thread_info()->fpregs;
- unsigned long fprs;
- int err;
-
- err = __get_user(fprs, &fpu->si_fprs);
- fprs_write(0);
- regs->tstate &= ~TSTATE_PEF;
- if (fprs & FPRS_DL)
- err |= copy_from_user(fpregs, &fpu->si_float_regs[0],
- (sizeof(unsigned int) * 32));
- if (fprs & FPRS_DU)
- err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32],
- (sizeof(unsigned int) * 32));
- err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
- err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
- current_thread_info()->fpsaved[0] |= fprs;
- return err;
-}
-
void do_rt_sigreturn(struct pt_regs *regs)
{
struct rt_signal_frame __user *sf;
unsigned long tpc, tnpc, tstate;
__siginfo_fpu_t __user *fpu_save;
+ __siginfo_rwin_t __user *rwin_save;
sigset_t set;
int err;
@@ -325,8 +305,8 @@
regs->tstate |= (tstate & (TSTATE_ASI | TSTATE_ICC | TSTATE_XCC));
err |= __get_user(fpu_save, &sf->fpu_save);
- if (fpu_save)
- err |= restore_fpu_state(regs, &sf->fpu_state);
+ if (!err && fpu_save)
+ err |= restore_fpu_state(regs, fpu_save);
err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
err |= do_sigaltstack(&sf->stack, NULL, (unsigned long)sf);
@@ -334,6 +314,12 @@
if (err)
goto segv;
+ err |= __get_user(rwin_save, &sf->rwin_save);
+ if (!err && rwin_save) {
+ if (restore_rwin_state(rwin_save))
+ goto segv;
+ }
+
regs->tpc = tpc;
regs->tnpc = tnpc;
@@ -351,34 +337,13 @@
}
/* Checks if the fp is valid */
-static int invalid_frame_pointer(void __user *fp, int fplen)
+static int invalid_frame_pointer(void __user *fp)
{
if (((unsigned long) fp) & 15)
return 1;
return 0;
}
-static inline int
-save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
- unsigned long *fpregs = current_thread_info()->fpregs;
- unsigned long fprs;
- int err = 0;
-
- fprs = current_thread_info()->fpsaved[0];
- if (fprs & FPRS_DL)
- err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
- (sizeof(unsigned int) * 32));
- if (fprs & FPRS_DU)
- err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
- (sizeof(unsigned int) * 32));
- err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
- err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
- err |= __put_user(fprs, &fpu->si_fprs);
-
- return err;
-}
-
static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, unsigned long framesize)
{
unsigned long sp = regs->u_regs[UREG_FP] + STACK_BIAS;
@@ -414,34 +379,48 @@
int signo, sigset_t *oldset, siginfo_t *info)
{
struct rt_signal_frame __user *sf;
- int sigframe_size, err;
+ int wsaved, err, sf_size;
+ void __user *tail;
/* 1. Make sure everything is clean */
synchronize_user_stack();
save_and_clear_fpu();
- sigframe_size = sizeof(struct rt_signal_frame);
- if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
- sigframe_size -= sizeof(__siginfo_fpu_t);
+ wsaved = get_thread_wsaved();
+ sf_size = sizeof(struct rt_signal_frame);
+ if (current_thread_info()->fpsaved[0] & FPRS_FEF)
+ sf_size += sizeof(__siginfo_fpu_t);
+ if (wsaved)
+ sf_size += sizeof(__siginfo_rwin_t);
sf = (struct rt_signal_frame __user *)
- get_sigframe(ka, regs, sigframe_size);
-
- if (invalid_frame_pointer (sf, sigframe_size))
+ get_sigframe(ka, regs, sf_size);
+
+ if (invalid_frame_pointer (sf))
goto sigill;
- if (get_thread_wsaved() != 0)
- goto sigill;
+ tail = (sf + 1);
/* 2. Save the current process state */
err = copy_to_user(&sf->regs, regs, sizeof (*regs));
if (current_thread_info()->fpsaved[0] & FPRS_FEF) {
- err |= save_fpu_state(regs, &sf->fpu_state);
- err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
+ __siginfo_fpu_t __user *fpu_save = tail;
+ tail += sizeof(__siginfo_fpu_t);
+ err |= save_fpu_state(regs, fpu_save);
+ err |= __put_user((u64)fpu_save, &sf->fpu_save);
} else {
err |= __put_user(0, &sf->fpu_save);
}
+ if (wsaved) {
+ __siginfo_rwin_t __user *rwin_save = tail;
+ tail += sizeof(__siginfo_rwin_t);
+ err |= save_rwin_state(wsaved, rwin_save);
+ err |= __put_user((u64)rwin_save, &sf->rwin_save);
+ set_thread_wsaved(0);
+ } else {
+ err |= __put_user(0, &sf->rwin_save);
+ }
/* Setup sigaltstack */
err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
@@ -450,10 +429,17 @@
err |= copy_to_user(&sf->mask, oldset, sizeof(sigset_t));
- err |= copy_in_user((u64 __user *)sf,
- (u64 __user *)(regs->u_regs[UREG_FP]+STACK_BIAS),
- sizeof(struct reg_window));
+ if (!wsaved) {
+ err |= copy_in_user((u64 __user *)sf,
+ (u64 __user *)(regs->u_regs[UREG_FP] +
+ STACK_BIAS),
+ sizeof(struct reg_window));
+ } else {
+ struct reg_window *rp;
+ rp = ¤t_thread_info()->reg_window[wsaved - 1];
+ err |= copy_to_user(sf, rp, sizeof(struct reg_window));
+ }
if (info)
err |= copy_siginfo_to_user(&sf->info, info);
else {
diff --git a/arch/sparc/kernel/sigutil.h b/arch/sparc/kernel/sigutil.h
new file mode 100644
index 0000000..d223aa4
--- /dev/null
+++ b/arch/sparc/kernel/sigutil.h
@@ -0,0 +1,9 @@
+#ifndef _SIGUTIL_H
+#define _SIGUTIL_H
+
+int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu);
+int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu);
+int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin);
+int restore_rwin_state(__siginfo_rwin_t __user *rp);
+
+#endif /* _SIGUTIL_H */
diff --git a/arch/sparc/kernel/sigutil_32.c b/arch/sparc/kernel/sigutil_32.c
new file mode 100644
index 0000000..35c7897
--- /dev/null
+++ b/arch/sparc/kernel/sigutil_32.c
@@ -0,0 +1,120 @@
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/thread_info.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+
+#include <asm/sigcontext.h>
+#include <asm/fpumacro.h>
+#include <asm/ptrace.h>
+
+#include "sigutil.h"
+
+int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
+{
+ int err = 0;
+#ifdef CONFIG_SMP
+ if (test_tsk_thread_flag(current, TIF_USEDFPU)) {
+ put_psr(get_psr() | PSR_EF);
+ fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr,
+ ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth);
+ regs->psr &= ~(PSR_EF);
+ clear_tsk_thread_flag(current, TIF_USEDFPU);
+ }
+#else
+ if (current == last_task_used_math) {
+ put_psr(get_psr() | PSR_EF);
+ fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr,
+ ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth);
+ last_task_used_math = NULL;
+ regs->psr &= ~(PSR_EF);
+ }
+#endif
+ err |= __copy_to_user(&fpu->si_float_regs[0],
+ ¤t->thread.float_regs[0],
+ (sizeof(unsigned long) * 32));
+ err |= __put_user(current->thread.fsr, &fpu->si_fsr);
+ err |= __put_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
+ if (current->thread.fpqdepth != 0)
+ err |= __copy_to_user(&fpu->si_fpqueue[0],
+ ¤t->thread.fpqueue[0],
+ ((sizeof(unsigned long) +
+ (sizeof(unsigned long *)))*16));
+ clear_used_math();
+ return err;
+}
+
+int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
+{
+ int err;
+#ifdef CONFIG_SMP
+ if (test_tsk_thread_flag(current, TIF_USEDFPU))
+ regs->psr &= ~PSR_EF;
+#else
+ if (current == last_task_used_math) {
+ last_task_used_math = NULL;
+ regs->psr &= ~PSR_EF;
+ }
+#endif
+ set_used_math();
+ clear_tsk_thread_flag(current, TIF_USEDFPU);
+
+ if (!access_ok(VERIFY_READ, fpu, sizeof(*fpu)))
+ return -EFAULT;
+
+ err = __copy_from_user(¤t->thread.float_regs[0], &fpu->si_float_regs[0],
+ (sizeof(unsigned long) * 32));
+ err |= __get_user(current->thread.fsr, &fpu->si_fsr);
+ err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
+ if (current->thread.fpqdepth != 0)
+ err |= __copy_from_user(¤t->thread.fpqueue[0],
+ &fpu->si_fpqueue[0],
+ ((sizeof(unsigned long) +
+ (sizeof(unsigned long *)))*16));
+ return err;
+}
+
+int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin)
+{
+ int i, err = __put_user(wsaved, &rwin->wsaved);
+
+ for (i = 0; i < wsaved; i++) {
+ struct reg_window32 *rp;
+ unsigned long fp;
+
+ rp = ¤t_thread_info()->reg_window[i];
+ fp = current_thread_info()->rwbuf_stkptrs[i];
+ err |= copy_to_user(&rwin->reg_window[i], rp,
+ sizeof(struct reg_window32));
+ err |= __put_user(fp, &rwin->rwbuf_stkptrs[i]);
+ }
+ return err;
+}
+
+int restore_rwin_state(__siginfo_rwin_t __user *rp)
+{
+ struct thread_info *t = current_thread_info();
+ int i, wsaved, err;
+
+ __get_user(wsaved, &rp->wsaved);
+ if (wsaved > NSWINS)
+ return -EFAULT;
+
+ err = 0;
+ for (i = 0; i < wsaved; i++) {
+ err |= copy_from_user(&t->reg_window[i],
+ &rp->reg_window[i],
+ sizeof(struct reg_window32));
+ err |= __get_user(t->rwbuf_stkptrs[i],
+ &rp->rwbuf_stkptrs[i]);
+ }
+ if (err)
+ return err;
+
+ t->w_saved = wsaved;
+ synchronize_user_stack();
+ if (t->w_saved)
+ return -EFAULT;
+ return 0;
+
+}
diff --git a/arch/sparc/kernel/sigutil_64.c b/arch/sparc/kernel/sigutil_64.c
new file mode 100644
index 0000000..6edc4e5
--- /dev/null
+++ b/arch/sparc/kernel/sigutil_64.c
@@ -0,0 +1,93 @@
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/thread_info.h>
+#include <linux/uaccess.h>
+
+#include <asm/sigcontext.h>
+#include <asm/fpumacro.h>
+#include <asm/ptrace.h>
+
+#include "sigutil.h"
+
+int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
+{
+ unsigned long *fpregs = current_thread_info()->fpregs;
+ unsigned long fprs;
+ int err = 0;
+
+ fprs = current_thread_info()->fpsaved[0];
+ if (fprs & FPRS_DL)
+ err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
+ (sizeof(unsigned int) * 32));
+ if (fprs & FPRS_DU)
+ err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
+ (sizeof(unsigned int) * 32));
+ err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
+ err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
+ err |= __put_user(fprs, &fpu->si_fprs);
+
+ return err;
+}
+
+int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
+{
+ unsigned long *fpregs = current_thread_info()->fpregs;
+ unsigned long fprs;
+ int err;
+
+ err = __get_user(fprs, &fpu->si_fprs);
+ fprs_write(0);
+ regs->tstate &= ~TSTATE_PEF;
+ if (fprs & FPRS_DL)
+ err |= copy_from_user(fpregs, &fpu->si_float_regs[0],
+ (sizeof(unsigned int) * 32));
+ if (fprs & FPRS_DU)
+ err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32],
+ (sizeof(unsigned int) * 32));
+ err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
+ err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
+ current_thread_info()->fpsaved[0] |= fprs;
+ return err;
+}
+
+int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin)
+{
+ int i, err = __put_user(wsaved, &rwin->wsaved);
+
+ for (i = 0; i < wsaved; i++) {
+ struct reg_window *rp = ¤t_thread_info()->reg_window[i];
+ unsigned long fp = current_thread_info()->rwbuf_stkptrs[i];
+
+ err |= copy_to_user(&rwin->reg_window[i], rp,
+ sizeof(struct reg_window));
+ err |= __put_user(fp, &rwin->rwbuf_stkptrs[i]);
+ }
+ return err;
+}
+
+int restore_rwin_state(__siginfo_rwin_t __user *rp)
+{
+ struct thread_info *t = current_thread_info();
+ int i, wsaved, err;
+
+ __get_user(wsaved, &rp->wsaved);
+ if (wsaved > NSWINS)
+ return -EFAULT;
+
+ err = 0;
+ for (i = 0; i < wsaved; i++) {
+ err |= copy_from_user(&t->reg_window[i],
+ &rp->reg_window[i],
+ sizeof(struct reg_window));
+ err |= __get_user(t->rwbuf_stkptrs[i],
+ &rp->rwbuf_stkptrs[i]);
+ }
+ if (err)
+ return err;
+
+ set_thread_wsaved(wsaved);
+ synchronize_user_stack();
+ if (get_thread_wsaved())
+ return -EFAULT;
+ return 0;
+}
diff --git a/arch/sparc/kernel/sparc_ksyms_64.c b/arch/sparc/kernel/sparc_ksyms_64.c
index 372ad59..83b47ab 100644
--- a/arch/sparc/kernel/sparc_ksyms_64.c
+++ b/arch/sparc/kernel/sparc_ksyms_64.c
@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>
+#include <linux/bitops.h>
#include <asm/system.h>
#include <asm/cpudata.h>
@@ -38,5 +39,15 @@
EXPORT_SYMBOL(sun4v_niagara2_getperf);
EXPORT_SYMBOL(sun4v_niagara2_setperf);
+/* from hweight.S */
+EXPORT_SYMBOL(__arch_hweight8);
+EXPORT_SYMBOL(__arch_hweight16);
+EXPORT_SYMBOL(__arch_hweight32);
+EXPORT_SYMBOL(__arch_hweight64);
+
+/* from ffs_ffz.S */
+EXPORT_SYMBOL(ffs);
+EXPORT_SYMBOL(__ffs);
+
/* Exporting a symbol from /init/main.c */
EXPORT_SYMBOL(saved_command_line);
diff --git a/arch/sparc/kernel/sstate.c b/arch/sparc/kernel/sstate.c
index 8cdbe59..c59af54 100644
--- a/arch/sparc/kernel/sstate.c
+++ b/arch/sparc/kernel/sstate.c
@@ -14,15 +14,10 @@
#include <asm/head.h>
#include <asm/io.h>
+#include "kernel.h"
+
static int hv_supports_soft_state;
-static unsigned long kimage_addr_to_ra(const char *p)
-{
- unsigned long val = (unsigned long) p;
-
- return kern_base + (val - KERNBASE);
-}
-
static void do_set_sstate(unsigned long state, const char *msg)
{
unsigned long err;
diff --git a/arch/sparc/kernel/unaligned_64.c b/arch/sparc/kernel/unaligned_64.c
index b2b019e..9043106 100644
--- a/arch/sparc/kernel/unaligned_64.c
+++ b/arch/sparc/kernel/unaligned_64.c
@@ -22,6 +22,7 @@
#include <linux/bitops.h>
#include <linux/perf_event.h>
#include <linux/ratelimit.h>
+#include <linux/bitops.h>
#include <asm/fpumacro.h>
enum direction {
@@ -373,16 +374,11 @@
}
}
-static char popc_helper[] = {
-0, 1, 1, 2, 1, 2, 2, 3,
-1, 2, 2, 3, 2, 3, 3, 4,
-};
-
int handle_popc(u32 insn, struct pt_regs *regs)
{
- u64 value;
- int ret, i, rd = ((insn >> 25) & 0x1f);
int from_kernel = (regs->tstate & TSTATE_PRIV) != 0;
+ int ret, rd = ((insn >> 25) & 0x1f);
+ u64 value;
perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, 0);
if (insn & 0x2000) {
@@ -392,10 +388,7 @@
maybe_flush_windows(0, insn & 0x1f, rd, from_kernel);
value = fetch_reg(insn & 0x1f, regs);
}
- for (ret = 0, i = 0; i < 16; i++) {
- ret += popc_helper[value & 0xf];
- value >>= 4;
- }
+ ret = hweight64(value);
if (rd < 16) {
if (rd)
regs->u_regs[rd] = ret;
diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S
index c022075..0e16056 100644
--- a/arch/sparc/kernel/vmlinux.lds.S
+++ b/arch/sparc/kernel/vmlinux.lds.S
@@ -107,7 +107,26 @@
*(.sun4v_2insn_patch)
__sun4v_2insn_patch_end = .;
}
-
+ .swapper_tsb_phys_patch : {
+ __swapper_tsb_phys_patch = .;
+ *(.swapper_tsb_phys_patch)
+ __swapper_tsb_phys_patch_end = .;
+ }
+ .swapper_4m_tsb_phys_patch : {
+ __swapper_4m_tsb_phys_patch = .;
+ *(.swapper_4m_tsb_phys_patch)
+ __swapper_4m_tsb_phys_patch_end = .;
+ }
+ .popc_3insn_patch : {
+ __popc_3insn_patch = .;
+ *(.popc_3insn_patch)
+ __popc_3insn_patch_end = .;
+ }
+ .popc_6insn_patch : {
+ __popc_6insn_patch = .;
+ *(.popc_6insn_patch)
+ __popc_6insn_patch_end = .;
+ }
PERCPU_SECTION(SMP_CACHE_BYTES)
. = ALIGN(PAGE_SIZE);
diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile
index 7f01b8f..a3fc437 100644
--- a/arch/sparc/lib/Makefile
+++ b/arch/sparc/lib/Makefile
@@ -31,13 +31,13 @@
lib-$(CONFIG_SPARC64) += NGpatch.o NGpage.o NGbzero.o
lib-$(CONFIG_SPARC64) += NG2memcpy.o NG2copy_from_user.o NG2copy_to_user.o
-lib-$(CONFIG_SPARC64) += NG2patch.o NG2page.o
+lib-$(CONFIG_SPARC64) += NG2patch.o
lib-$(CONFIG_SPARC64) += GENmemcpy.o GENcopy_from_user.o GENcopy_to_user.o
lib-$(CONFIG_SPARC64) += GENpatch.o GENpage.o GENbzero.o
lib-$(CONFIG_SPARC64) += copy_in_user.o user_fixup.o memmove.o
-lib-$(CONFIG_SPARC64) += mcount.o ipcsum.o xor.o
+lib-$(CONFIG_SPARC64) += mcount.o ipcsum.o xor.o hweight.o ffs.o
obj-y += iomap.o
obj-$(CONFIG_SPARC32) += atomic32.o
diff --git a/arch/sparc/lib/NG2page.S b/arch/sparc/lib/NG2page.S
deleted file mode 100644
index 73b6b7c..0000000
--- a/arch/sparc/lib/NG2page.S
+++ /dev/null
@@ -1,61 +0,0 @@
-/* NG2page.S: Niagara-2 optimized clear and copy page.
- *
- * Copyright (C) 2007 (davem@davemloft.net)
- */
-
-#include <asm/asi.h>
-#include <asm/page.h>
-#include <asm/visasm.h>
-
- .text
- .align 32
-
- /* This is heavily simplified from the sun4u variants
- * because Niagara-2 does not have any D-cache aliasing issues.
- */
-NG2copy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */
- prefetch [%o1 + 0x00], #one_read
- prefetch [%o1 + 0x40], #one_read
- VISEntryHalf
- set PAGE_SIZE, %g7
- sub %o0, %o1, %g3
-1: stxa %g0, [%o1 + %g3] ASI_BLK_INIT_QUAD_LDD_P
- subcc %g7, 64, %g7
- ldda [%o1] ASI_BLK_P, %f0
- stda %f0, [%o1 + %g3] ASI_BLK_P
- add %o1, 64, %o1
- bne,pt %xcc, 1b
- prefetch [%o1 + 0x40], #one_read
- membar #Sync
- VISExitHalf
- retl
- nop
-
-#define BRANCH_ALWAYS 0x10680000
-#define NOP 0x01000000
-#define NG_DO_PATCH(OLD, NEW) \
- sethi %hi(NEW), %g1; \
- or %g1, %lo(NEW), %g1; \
- sethi %hi(OLD), %g2; \
- or %g2, %lo(OLD), %g2; \
- sub %g1, %g2, %g1; \
- sethi %hi(BRANCH_ALWAYS), %g3; \
- sll %g1, 11, %g1; \
- srl %g1, 11 + 2, %g1; \
- or %g3, %lo(BRANCH_ALWAYS), %g3; \
- or %g3, %g1, %g3; \
- stw %g3, [%g2]; \
- sethi %hi(NOP), %g3; \
- or %g3, %lo(NOP), %g3; \
- stw %g3, [%g2 + 0x4]; \
- flush %g2;
-
- .globl niagara2_patch_pageops
- .type niagara2_patch_pageops,#function
-niagara2_patch_pageops:
- NG_DO_PATCH(copy_user_page, NG2copy_user_page)
- NG_DO_PATCH(_clear_page, NGclear_page)
- NG_DO_PATCH(clear_user_page, NGclear_user_page)
- retl
- nop
- .size niagara2_patch_pageops,.-niagara2_patch_pageops
diff --git a/arch/sparc/lib/NGpage.S b/arch/sparc/lib/NGpage.S
index 428920d..b9e790b 100644
--- a/arch/sparc/lib/NGpage.S
+++ b/arch/sparc/lib/NGpage.S
@@ -16,55 +16,91 @@
*/
NGcopy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */
- prefetch [%o1 + 0x00], #one_read
- mov 8, %g1
- mov 16, %g2
- mov 24, %g3
+ save %sp, -192, %sp
+ rd %asi, %g3
+ wr %g0, ASI_BLK_INIT_QUAD_LDD_P, %asi
set PAGE_SIZE, %g7
+ prefetch [%i1 + 0x00], #one_read
+ prefetch [%i1 + 0x40], #one_read
-1: ldda [%o1 + %g0] ASI_BLK_INIT_QUAD_LDD_P, %o2
- ldda [%o1 + %g2] ASI_BLK_INIT_QUAD_LDD_P, %o4
- prefetch [%o1 + 0x40], #one_read
- add %o1, 32, %o1
- stxa %o2, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P
- stxa %o3, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P
- ldda [%o1 + %g0] ASI_BLK_INIT_QUAD_LDD_P, %o2
- stxa %o4, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P
- stxa %o5, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P
- ldda [%o1 + %g2] ASI_BLK_INIT_QUAD_LDD_P, %o4
- add %o1, 32, %o1
- add %o0, 32, %o0
- stxa %o2, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P
- stxa %o3, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P
- stxa %o4, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P
- stxa %o5, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P
- subcc %g7, 64, %g7
+1: prefetch [%i1 + 0x80], #one_read
+ prefetch [%i1 + 0xc0], #one_read
+ ldda [%i1 + 0x00] %asi, %o2
+ ldda [%i1 + 0x10] %asi, %o4
+ ldda [%i1 + 0x20] %asi, %l2
+ ldda [%i1 + 0x30] %asi, %l4
+ stxa %o2, [%i0 + 0x00] %asi
+ stxa %o3, [%i0 + 0x08] %asi
+ stxa %o4, [%i0 + 0x10] %asi
+ stxa %o5, [%i0 + 0x18] %asi
+ stxa %l2, [%i0 + 0x20] %asi
+ stxa %l3, [%i0 + 0x28] %asi
+ stxa %l4, [%i0 + 0x30] %asi
+ stxa %l5, [%i0 + 0x38] %asi
+ ldda [%i1 + 0x40] %asi, %o2
+ ldda [%i1 + 0x50] %asi, %o4
+ ldda [%i1 + 0x60] %asi, %l2
+ ldda [%i1 + 0x70] %asi, %l4
+ stxa %o2, [%i0 + 0x40] %asi
+ stxa %o3, [%i0 + 0x48] %asi
+ stxa %o4, [%i0 + 0x50] %asi
+ stxa %o5, [%i0 + 0x58] %asi
+ stxa %l2, [%i0 + 0x60] %asi
+ stxa %l3, [%i0 + 0x68] %asi
+ stxa %l4, [%i0 + 0x70] %asi
+ stxa %l5, [%i0 + 0x78] %asi
+ add %i1, 128, %i1
+ subcc %g7, 128, %g7
bne,pt %xcc, 1b
- add %o0, 32, %o0
+ add %i0, 128, %i0
+ wr %g3, 0x0, %asi
membar #Sync
- retl
- nop
+ ret
+ restore
- .globl NGclear_page, NGclear_user_page
+ .align 32
NGclear_page: /* %o0=dest */
NGclear_user_page: /* %o0=dest, %o1=vaddr */
- mov 8, %g1
- mov 16, %g2
- mov 24, %g3
+ rd %asi, %g3
+ wr %g0, ASI_BLK_INIT_QUAD_LDD_P, %asi
set PAGE_SIZE, %g7
-1: stxa %g0, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P
- stxa %g0, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P
- stxa %g0, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P
- stxa %g0, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P
- add %o0, 32, %o0
- stxa %g0, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P
- stxa %g0, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P
- stxa %g0, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P
- stxa %g0, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P
- subcc %g7, 64, %g7
+1: stxa %g0, [%o0 + 0x00] %asi
+ stxa %g0, [%o0 + 0x08] %asi
+ stxa %g0, [%o0 + 0x10] %asi
+ stxa %g0, [%o0 + 0x18] %asi
+ stxa %g0, [%o0 + 0x20] %asi
+ stxa %g0, [%o0 + 0x28] %asi
+ stxa %g0, [%o0 + 0x30] %asi
+ stxa %g0, [%o0 + 0x38] %asi
+ stxa %g0, [%o0 + 0x40] %asi
+ stxa %g0, [%o0 + 0x48] %asi
+ stxa %g0, [%o0 + 0x50] %asi
+ stxa %g0, [%o0 + 0x58] %asi
+ stxa %g0, [%o0 + 0x60] %asi
+ stxa %g0, [%o0 + 0x68] %asi
+ stxa %g0, [%o0 + 0x70] %asi
+ stxa %g0, [%o0 + 0x78] %asi
+ stxa %g0, [%o0 + 0x80] %asi
+ stxa %g0, [%o0 + 0x88] %asi
+ stxa %g0, [%o0 + 0x90] %asi
+ stxa %g0, [%o0 + 0x98] %asi
+ stxa %g0, [%o0 + 0xa0] %asi
+ stxa %g0, [%o0 + 0xa8] %asi
+ stxa %g0, [%o0 + 0xb0] %asi
+ stxa %g0, [%o0 + 0xb8] %asi
+ stxa %g0, [%o0 + 0xc0] %asi
+ stxa %g0, [%o0 + 0xc8] %asi
+ stxa %g0, [%o0 + 0xd0] %asi
+ stxa %g0, [%o0 + 0xd8] %asi
+ stxa %g0, [%o0 + 0xe0] %asi
+ stxa %g0, [%o0 + 0xe8] %asi
+ stxa %g0, [%o0 + 0xf0] %asi
+ stxa %g0, [%o0 + 0xf8] %asi
+ subcc %g7, 256, %g7
bne,pt %xcc, 1b
- add %o0, 32, %o0
+ add %o0, 256, %o0
+ wr %g3, 0x0, %asi
membar #Sync
retl
nop
diff --git a/arch/sparc/lib/ffs.S b/arch/sparc/lib/ffs.S
new file mode 100644
index 0000000..b39389f
--- /dev/null
+++ b/arch/sparc/lib/ffs.S
@@ -0,0 +1,84 @@
+#include <linux/linkage.h>
+
+ .register %g2,#scratch
+
+ .text
+ .align 32
+
+ENTRY(ffs)
+ brnz,pt %o0, 1f
+ mov 1, %o1
+ retl
+ clr %o0
+ nop
+ nop
+ENTRY(__ffs)
+ sllx %o0, 32, %g1 /* 1 */
+ srlx %o0, 32, %g2
+
+ clr %o1 /* 2 */
+ movrz %g1, %g2, %o0
+
+ movrz %g1, 32, %o1 /* 3 */
+1: clr %o2
+
+ sllx %o0, (64 - 16), %g1 /* 4 */
+ srlx %o0, 16, %g2
+
+ movrz %g1, %g2, %o0 /* 5 */
+ clr %o3
+
+ movrz %g1, 16, %o2 /* 6 */
+ clr %o4
+
+ and %o0, 0xff, %g1 /* 7 */
+ srlx %o0, 8, %g2
+
+ movrz %g1, %g2, %o0 /* 8 */
+ clr %o5
+
+ movrz %g1, 8, %o3 /* 9 */
+ add %o2, %o1, %o2
+
+ and %o0, 0xf, %g1 /* 10 */
+ srlx %o0, 4, %g2
+
+ movrz %g1, %g2, %o0 /* 11 */
+ add %o2, %o3, %o2
+
+ movrz %g1, 4, %o4 /* 12 */
+
+ and %o0, 0x3, %g1 /* 13 */
+ srlx %o0, 2, %g2
+
+ movrz %g1, %g2, %o0 /* 14 */
+ add %o2, %o4, %o2
+
+ movrz %g1, 2, %o5 /* 15 */
+
+ and %o0, 0x1, %g1 /* 16 */
+
+ add %o2, %o5, %o2 /* 17 */
+ xor %g1, 0x1, %g1
+
+ retl /* 18 */
+ add %o2, %g1, %o0
+ENDPROC(ffs)
+ENDPROC(__ffs)
+
+ .section .popc_6insn_patch, "ax"
+ .word ffs
+ brz,pn %o0, 98f
+ neg %o0, %g1
+ xnor %o0, %g1, %o1
+ popc %o1, %o0
+98: retl
+ nop
+ .word __ffs
+ neg %o0, %g1
+ xnor %o0, %g1, %o1
+ popc %o1, %o0
+ retl
+ sub %o0, 1, %o0
+ nop
+ .previous
diff --git a/arch/sparc/lib/hweight.S b/arch/sparc/lib/hweight.S
new file mode 100644
index 0000000..95414e0
--- /dev/null
+++ b/arch/sparc/lib/hweight.S
@@ -0,0 +1,51 @@
+#include <linux/linkage.h>
+
+ .text
+ .align 32
+ENTRY(__arch_hweight8)
+ ba,pt %xcc, __sw_hweight8
+ nop
+ nop
+ENDPROC(__arch_hweight8)
+ .section .popc_3insn_patch, "ax"
+ .word __arch_hweight8
+ sllx %o0, 64-8, %g1
+ retl
+ popc %g1, %o0
+ .previous
+
+ENTRY(__arch_hweight16)
+ ba,pt %xcc, __sw_hweight16
+ nop
+ nop
+ENDPROC(__arch_hweight16)
+ .section .popc_3insn_patch, "ax"
+ .word __arch_hweight16
+ sllx %o0, 64-16, %g1
+ retl
+ popc %g1, %o0
+ .previous
+
+ENTRY(__arch_hweight32)
+ ba,pt %xcc, __sw_hweight32
+ nop
+ nop
+ENDPROC(__arch_hweight32)
+ .section .popc_3insn_patch, "ax"
+ .word __arch_hweight32
+ sllx %o0, 64-32, %g1
+ retl
+ popc %g1, %o0
+ .previous
+
+ENTRY(__arch_hweight64)
+ ba,pt %xcc, __sw_hweight64
+ nop
+ nop
+ENDPROC(__arch_hweight64)
+ .section .popc_3insn_patch, "ax"
+ .word __arch_hweight64
+ retl
+ popc %o0, %o0
+ nop
+ .previous
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c
index 3fd8e18..8e073d8 100644
--- a/arch/sparc/mm/init_64.c
+++ b/arch/sparc/mm/init_64.c
@@ -511,6 +511,11 @@
for (i = 0; i < prom_trans_ents; i++)
prom_trans[i].data &= ~0x0003fe0000000000UL;
}
+
+ /* Force execute bit on. */
+ for (i = 0; i < prom_trans_ents; i++)
+ prom_trans[i].data |= (tlb_type == hypervisor ?
+ _PAGE_EXEC_4V : _PAGE_EXEC_4U);
}
static void __init hypervisor_tlb_lock(unsigned long vaddr,
@@ -1597,6 +1602,44 @@
static struct hv_tsb_descr ktsb_descr[NUM_KTSB_DESCR];
extern struct tsb swapper_tsb[KERNEL_TSB_NENTRIES];
+static void patch_one_ktsb_phys(unsigned int *start, unsigned int *end, unsigned long pa)
+{
+ pa >>= KTSB_PHYS_SHIFT;
+
+ while (start < end) {
+ unsigned int *ia = (unsigned int *)(unsigned long)*start;
+
+ ia[0] = (ia[0] & ~0x3fffff) | (pa >> 10);
+ __asm__ __volatile__("flush %0" : : "r" (ia));
+
+ ia[1] = (ia[1] & ~0x3ff) | (pa & 0x3ff);
+ __asm__ __volatile__("flush %0" : : "r" (ia + 1));
+
+ start++;
+ }
+}
+
+static void ktsb_phys_patch(void)
+{
+ extern unsigned int __swapper_tsb_phys_patch;
+ extern unsigned int __swapper_tsb_phys_patch_end;
+ unsigned long ktsb_pa;
+
+ ktsb_pa = kern_base + ((unsigned long)&swapper_tsb[0] - KERNBASE);
+ patch_one_ktsb_phys(&__swapper_tsb_phys_patch,
+ &__swapper_tsb_phys_patch_end, ktsb_pa);
+#ifndef CONFIG_DEBUG_PAGEALLOC
+ {
+ extern unsigned int __swapper_4m_tsb_phys_patch;
+ extern unsigned int __swapper_4m_tsb_phys_patch_end;
+ ktsb_pa = (kern_base +
+ ((unsigned long)&swapper_4m_tsb[0] - KERNBASE));
+ patch_one_ktsb_phys(&__swapper_4m_tsb_phys_patch,
+ &__swapper_4m_tsb_phys_patch_end, ktsb_pa);
+ }
+#endif
+}
+
static void __init sun4v_ktsb_init(void)
{
unsigned long ktsb_pa;
@@ -1716,8 +1759,10 @@
sun4u_pgprot_init();
if (tlb_type == cheetah_plus ||
- tlb_type == hypervisor)
+ tlb_type == hypervisor) {
tsb_phys_patch();
+ ktsb_phys_patch();
+ }
if (tlb_type == hypervisor) {
sun4v_patch_tlb_handlers();
diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h
index 64a619d..7ff4669 100644
--- a/arch/x86/include/asm/xen/page.h
+++ b/arch/x86/include/asm/xen/page.h
@@ -39,7 +39,7 @@
((unsigned long)((u64)CONFIG_XEN_MAX_DOMAIN_MEMORY * 1024 * 1024 * 1024 / PAGE_SIZE))
extern unsigned long *machine_to_phys_mapping;
-extern unsigned int machine_to_phys_order;
+extern unsigned long machine_to_phys_nr;
extern unsigned long get_phys_to_machine(unsigned long pfn);
extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn);
@@ -87,7 +87,7 @@
if (xen_feature(XENFEAT_auto_translated_physmap))
return mfn;
- if (unlikely((mfn >> machine_to_phys_order) != 0)) {
+ if (unlikely(mfn >= machine_to_phys_nr)) {
pfn = ~0;
goto try_override;
}
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index 7c3a95e..d3d9d50 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -531,7 +531,9 @@
* Writes the command to the IOMMUs command buffer and informs the
* hardware about the new command.
*/
-static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd)
+static int iommu_queue_command_sync(struct amd_iommu *iommu,
+ struct iommu_cmd *cmd,
+ bool sync)
{
u32 left, tail, head, next_tail;
unsigned long flags;
@@ -565,13 +567,18 @@
copy_cmd_to_buffer(iommu, cmd, tail);
/* We need to sync now to make sure all commands are processed */
- iommu->need_sync = true;
+ iommu->need_sync = sync;
spin_unlock_irqrestore(&iommu->lock, flags);
return 0;
}
+static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd)
+{
+ return iommu_queue_command_sync(iommu, cmd, true);
+}
+
/*
* This function queues a completion wait command into the command
* buffer of an IOMMU
@@ -587,7 +594,7 @@
build_completion_wait(&cmd, (u64)&sem);
- ret = iommu_queue_command(iommu, &cmd);
+ ret = iommu_queue_command_sync(iommu, &cmd, false);
if (ret)
return ret;
@@ -773,14 +780,9 @@
static void domain_flush_devices(struct protection_domain *domain)
{
struct iommu_dev_data *dev_data;
- unsigned long flags;
-
- spin_lock_irqsave(&domain->lock, flags);
list_for_each_entry(dev_data, &domain->dev_list, list)
device_flush_dte(dev_data->dev);
-
- spin_unlock_irqrestore(&domain->lock, flags);
}
/****************************************************************************
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c
index adc66c3..34b1859 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -207,7 +207,6 @@
((start_rip << UVH_IPI_INT_VECTOR_SHFT) >> 12) |
APIC_DM_INIT;
uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
- mdelay(10);
val = (1UL << UVH_IPI_INT_SEND_SHFT) |
(phys_apicid << UVH_IPI_INT_APIC_ID_SHFT) |
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index da0d779..ed6086e 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -465,11 +465,11 @@
u64 epb;
rdmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb);
- if ((epb & 0xF) == 0) {
- printk_once(KERN_WARNING, "x86: updated energy_perf_bias"
- " to 'normal' from 'performance'\n"
- "You can view and update epb via utility,"
- " such as x86_energy_perf_policy(8)\n");
+ if ((epb & 0xF) == ENERGY_PERF_BIAS_PERFORMANCE) {
+ printk_once(KERN_WARNING "ENERGY_PERF_BIAS:"
+ " Set to 'normal', was 'performance'\n"
+ "ENERGY_PERF_BIAS: View and update with"
+ " x86_energy_perf_policy(8)\n");
epb = (epb & ~0xF) | ENERGY_PERF_BIAS_NORMAL;
wrmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb);
}
diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c
index 929739a..3d17bc7 100644
--- a/arch/x86/kernel/cpu/mtrr/main.c
+++ b/arch/x86/kernel/cpu/mtrr/main.c
@@ -248,6 +248,25 @@
unsigned long flags;
int cpu;
+#ifdef CONFIG_SMP
+ /*
+ * If this cpu is not yet active, we are in the cpu online path. There
+ * can be no stop_machine() in parallel, as stop machine ensures this
+ * by using get_online_cpus(). We can skip taking the stop_cpus_mutex,
+ * as we don't need it and also we can't afford to block while waiting
+ * for the mutex.
+ *
+ * If this cpu is active, we need to prevent stop_machine() happening
+ * in parallel by taking the stop cpus mutex.
+ *
+ * Also, this is called in the context of cpu online path or in the
+ * context where cpu hotplug is prevented. So checking the active status
+ * of the raw_smp_processor_id() is safe.
+ */
+ if (cpu_active(raw_smp_processor_id()))
+ mutex_lock(&stop_cpus_mutex);
+#endif
+
preempt_disable();
data.smp_reg = reg;
@@ -330,6 +349,10 @@
local_irq_restore(flags);
preempt_enable();
+#ifdef CONFIG_SMP
+ if (cpu_active(raw_smp_processor_id()))
+ mutex_unlock(&stop_cpus_mutex);
+#endif
}
/**
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index 3a0338b..bf6d692 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -1856,6 +1856,9 @@
perf_callchain_store(entry, regs->ip);
+ if (!current->mm)
+ return;
+
if (perf_callchain_user32(regs, entry))
return;
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c
index 41178c8..dd208a8 100644
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -1495,6 +1495,7 @@
break;
case 42: /* SandyBridge */
+ case 45: /* SandyBridge, "Romely-EP" */
memcpy(hw_cache_event_ids, snb_hw_cache_event_ids,
sizeof(hw_cache_event_ids));
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index 3032644..87488b9 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -63,9 +63,8 @@
#ifdef CONFIG_X86_32
/* for fixmap */
tables += roundup(__end_of_fixed_addresses * sizeof(pte_t), PAGE_SIZE);
-
- good_end = max_pfn_mapped << PAGE_SHIFT;
#endif
+ good_end = max_pfn_mapped << PAGE_SHIFT;
base = memblock_find_in_range(start, good_end, tables, PAGE_SIZE);
if (base == MEMBLOCK_ERROR)
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 68c3c13..50b3f14 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -43,6 +43,17 @@
DMI_MATCH(DMI_PRODUCT_NAME, "ALiveSATA2-GLAN"),
},
},
+ /* https://bugzilla.kernel.org/show_bug.cgi?id=30552 */
+ /* 2006 AMD HT/VIA system with two host bridges */
+ {
+ .callback = set_use_crs,
+ .ident = "ASUS M2V-MX SE",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "M2V-MX SE"),
+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
+ },
+ },
{}
};
diff --git a/arch/x86/platform/olpc/olpc.c b/arch/x86/platform/olpc/olpc.c
index 0060fd5..02e3934 100644
--- a/arch/x86/platform/olpc/olpc.c
+++ b/arch/x86/platform/olpc/olpc.c
@@ -157,13 +157,13 @@
if (inbuf && inlen) {
/* write data to EC */
for (i = 0; i < inlen; i++) {
+ pr_devel("olpc-ec: sending cmd arg 0x%x\n", inbuf[i]);
+ outb(inbuf[i], 0x68);
if (wait_on_ibf(0x6c, 0)) {
printk(KERN_ERR "olpc-ec: timeout waiting for"
" EC accept data!\n");
goto err;
}
- pr_devel("olpc-ec: sending cmd arg 0x%x\n", inbuf[i]);
- outb(inbuf[i], 0x68);
}
}
if (outbuf && outlen) {
diff --git a/arch/x86/vdso/vdso32/sysenter.S b/arch/x86/vdso/vdso32/sysenter.S
index e2800af..e354bce 100644
--- a/arch/x86/vdso/vdso32/sysenter.S
+++ b/arch/x86/vdso/vdso32/sysenter.S
@@ -43,7 +43,7 @@
.space 7,0x90
/* 14: System call restart point is here! (SYSENTER_RETURN-2) */
- jmp .Lenter_kernel
+ int $0x80
/* 16: System call normal return point is here! */
VDSO32_SYSENTER_RETURN: /* Symbol used by sysenter.c via vdso32-syms.h */
pop %ebp
diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile
index 17c565d..a6575b9 100644
--- a/arch/x86/xen/Makefile
+++ b/arch/x86/xen/Makefile
@@ -18,5 +18,5 @@
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o
obj-$(CONFIG_XEN_DEBUG_FS) += debugfs.o
-
+obj-$(CONFIG_XEN_DOM0) += vga.o
obj-$(CONFIG_SWIOTLB_XEN) += pci-swiotlb-xen.o
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 5525163..67d69f1 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -77,8 +77,8 @@
unsigned long *machine_to_phys_mapping = (void *)MACH2PHYS_VIRT_START;
EXPORT_SYMBOL(machine_to_phys_mapping);
-unsigned int machine_to_phys_order;
-EXPORT_SYMBOL(machine_to_phys_order);
+unsigned long machine_to_phys_nr;
+EXPORT_SYMBOL(machine_to_phys_nr);
struct start_info *xen_start_info;
EXPORT_SYMBOL_GPL(xen_start_info);
@@ -1248,6 +1248,14 @@
if (pci_xen)
x86_init.pci.arch_init = pci_xen_init;
} else {
+ const struct dom0_vga_console_info *info =
+ (void *)((char *)xen_start_info +
+ xen_start_info->console.dom0.info_off);
+
+ xen_init_vga(info, xen_start_info->console.dom0.info_size);
+ xen_start_info->console.domU.mfn = 0;
+ xen_start_info->console.domU.evtchn = 0;
+
/* Make sure ACS will be enabled */
pci_request_acs();
}
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 0343708..70b16fc 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -1626,15 +1626,19 @@
void __init xen_setup_machphys_mapping(void)
{
struct xen_machphys_mapping mapping;
- unsigned long machine_to_phys_nr_ents;
if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) {
machine_to_phys_mapping = (unsigned long *)mapping.v_start;
- machine_to_phys_nr_ents = mapping.max_mfn + 1;
+ machine_to_phys_nr = mapping.max_mfn + 1;
} else {
- machine_to_phys_nr_ents = MACH2PHYS_NR_ENTRIES;
+ machine_to_phys_nr = MACH2PHYS_NR_ENTRIES;
}
- machine_to_phys_order = fls(machine_to_phys_nr_ents - 1);
+#ifdef CONFIG_X86_32
+ if ((machine_to_phys_mapping + machine_to_phys_nr)
+ < machine_to_phys_mapping)
+ machine_to_phys_nr = (unsigned long *)NULL
+ - machine_to_phys_mapping;
+#endif
}
#ifdef CONFIG_X86_64
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
index 60aeeb5..acea42e 100644
--- a/arch/x86/xen/setup.c
+++ b/arch/x86/xen/setup.c
@@ -185,6 +185,19 @@
PFN_UP(start_pci), PFN_DOWN(last));
return identity;
}
+
+static unsigned long __init xen_get_max_pages(void)
+{
+ unsigned long max_pages = MAX_DOMAIN_PAGES;
+ domid_t domid = DOMID_SELF;
+ int ret;
+
+ ret = HYPERVISOR_memory_op(XENMEM_maximum_reservation, &domid);
+ if (ret > 0)
+ max_pages = ret;
+ return min(max_pages, MAX_DOMAIN_PAGES);
+}
+
/**
* machine_specific_memory_setup - Hook for machine specific memory setup.
**/
@@ -293,6 +306,14 @@
sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
+ extra_limit = xen_get_max_pages();
+ if (max_pfn + extra_pages > extra_limit) {
+ if (extra_limit > max_pfn)
+ extra_pages = extra_limit - max_pfn;
+ else
+ extra_pages = 0;
+ }
+
extra_pages += xen_return_unused_memory(xen_start_info->nr_pages, &e820);
/*
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index b4533a8..d4fc6d4 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -32,6 +32,7 @@
#include <xen/page.h>
#include <xen/events.h>
+#include <xen/hvc-console.h>
#include "xen-ops.h"
#include "mmu.h"
@@ -207,6 +208,15 @@
unsigned cpu;
unsigned int i;
+ if (skip_ioapic_setup) {
+ char *m = (max_cpus == 0) ?
+ "The nosmp parameter is incompatible with Xen; " \
+ "use Xen dom0_max_vcpus=1 parameter" :
+ "The noapic parameter is incompatible with Xen";
+
+ xen_raw_printk(m);
+ panic(m);
+ }
xen_init_lock_cpu(0);
smp_store_cpu_info(0);
@@ -521,8 +531,6 @@
native_smp_prepare_cpus(max_cpus);
WARN_ON(xen_smp_intr_init(0));
- if (!xen_have_vector_callback)
- return;
xen_init_lock_cpu(0);
xen_init_spinlocks();
}
@@ -546,6 +554,8 @@
void __init xen_hvm_smp_init(void)
{
+ if (!xen_have_vector_callback)
+ return;
smp_ops.smp_prepare_cpus = xen_hvm_smp_prepare_cpus;
smp_ops.smp_send_reschedule = xen_smp_send_reschedule;
smp_ops.cpu_up = xen_hvm_cpu_up;
diff --git a/arch/x86/xen/vga.c b/arch/x86/xen/vga.c
new file mode 100644
index 0000000..1cd7f4d
--- /dev/null
+++ b/arch/x86/xen/vga.c
@@ -0,0 +1,67 @@
+#include <linux/screen_info.h>
+#include <linux/init.h>
+
+#include <asm/bootparam.h>
+#include <asm/setup.h>
+
+#include <xen/interface/xen.h>
+
+#include "xen-ops.h"
+
+void __init xen_init_vga(const struct dom0_vga_console_info *info, size_t size)
+{
+ struct screen_info *screen_info = &boot_params.screen_info;
+
+ /* This is drawn from a dump from vgacon:startup in
+ * standard Linux. */
+ screen_info->orig_video_mode = 3;
+ screen_info->orig_video_isVGA = 1;
+ screen_info->orig_video_lines = 25;
+ screen_info->orig_video_cols = 80;
+ screen_info->orig_video_ega_bx = 3;
+ screen_info->orig_video_points = 16;
+ screen_info->orig_y = screen_info->orig_video_lines - 1;
+
+ switch (info->video_type) {
+ case XEN_VGATYPE_TEXT_MODE_3:
+ if (size < offsetof(struct dom0_vga_console_info, u.text_mode_3)
+ + sizeof(info->u.text_mode_3))
+ break;
+ screen_info->orig_video_lines = info->u.text_mode_3.rows;
+ screen_info->orig_video_cols = info->u.text_mode_3.columns;
+ screen_info->orig_x = info->u.text_mode_3.cursor_x;
+ screen_info->orig_y = info->u.text_mode_3.cursor_y;
+ screen_info->orig_video_points =
+ info->u.text_mode_3.font_height;
+ break;
+
+ case XEN_VGATYPE_VESA_LFB:
+ if (size < offsetof(struct dom0_vga_console_info,
+ u.vesa_lfb.gbl_caps))
+ break;
+ screen_info->orig_video_isVGA = VIDEO_TYPE_VLFB;
+ screen_info->lfb_width = info->u.vesa_lfb.width;
+ screen_info->lfb_height = info->u.vesa_lfb.height;
+ screen_info->lfb_depth = info->u.vesa_lfb.bits_per_pixel;
+ screen_info->lfb_base = info->u.vesa_lfb.lfb_base;
+ screen_info->lfb_size = info->u.vesa_lfb.lfb_size;
+ screen_info->lfb_linelength = info->u.vesa_lfb.bytes_per_line;
+ screen_info->red_size = info->u.vesa_lfb.red_size;
+ screen_info->red_pos = info->u.vesa_lfb.red_pos;
+ screen_info->green_size = info->u.vesa_lfb.green_size;
+ screen_info->green_pos = info->u.vesa_lfb.green_pos;
+ screen_info->blue_size = info->u.vesa_lfb.blue_size;
+ screen_info->blue_pos = info->u.vesa_lfb.blue_pos;
+ screen_info->rsvd_size = info->u.vesa_lfb.rsvd_size;
+ screen_info->rsvd_pos = info->u.vesa_lfb.rsvd_pos;
+ if (size >= offsetof(struct dom0_vga_console_info,
+ u.vesa_lfb.gbl_caps)
+ + sizeof(info->u.vesa_lfb.gbl_caps))
+ screen_info->capabilities = info->u.vesa_lfb.gbl_caps;
+ if (size >= offsetof(struct dom0_vga_console_info,
+ u.vesa_lfb.mode_attrs)
+ + sizeof(info->u.vesa_lfb.mode_attrs))
+ screen_info->vesa_attributes = info->u.vesa_lfb.mode_attrs;
+ break;
+ }
+}
diff --git a/arch/x86/xen/xen-asm_32.S b/arch/x86/xen/xen-asm_32.S
index 22a2093..b040b0e 100644
--- a/arch/x86/xen/xen-asm_32.S
+++ b/arch/x86/xen/xen-asm_32.S
@@ -113,11 +113,13 @@
/*
* If there's something pending, mask events again so we can
- * jump back into xen_hypervisor_callback
+ * jump back into xen_hypervisor_callback. Otherwise do not
+ * touch XEN_vcpu_info_mask.
*/
- sete XEN_vcpu_info_mask(%eax)
+ jne 1f
+ movb $1, XEN_vcpu_info_mask(%eax)
- popl %eax
+1: popl %eax
/*
* From this point on the registers are restored and the stack
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index 97dfdc8..b095739 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -88,6 +88,17 @@
}
#endif
+struct dom0_vga_console_info;
+
+#ifdef CONFIG_XEN_DOM0
+void __init xen_init_vga(const struct dom0_vga_console_info *, size_t size);
+#else
+static inline void __init xen_init_vga(const struct dom0_vga_console_info *info,
+ size_t size)
+{
+}
+#endif
+
/* Declare an asm function, along with symbols needed to make it
inlineable */
#define DECL_ASM(ret, name, ...) \
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index bcaf16e..b596e54 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -785,10 +785,10 @@
{
char *s[4], *p, *major_s = NULL, *minor_s = NULL;
int ret;
- unsigned long major, minor, temp;
+ unsigned long major, minor;
int i = 0;
dev_t dev;
- u64 bps, iops;
+ u64 temp;
memset(s, 0, sizeof(s));
@@ -826,20 +826,23 @@
dev = MKDEV(major, minor);
- ret = blkio_check_dev_num(dev);
+ ret = strict_strtoull(s[1], 10, &temp);
if (ret)
- return ret;
+ return -EINVAL;
+
+ /* For rule removal, do not check for device presence. */
+ if (temp) {
+ ret = blkio_check_dev_num(dev);
+ if (ret)
+ return ret;
+ }
newpn->dev = dev;
- if (s[1] == NULL)
- return -EINVAL;
-
switch (plid) {
case BLKIO_POLICY_PROP:
- ret = strict_strtoul(s[1], 10, &temp);
- if (ret || (temp < BLKIO_WEIGHT_MIN && temp > 0) ||
- temp > BLKIO_WEIGHT_MAX)
+ if ((temp < BLKIO_WEIGHT_MIN && temp > 0) ||
+ temp > BLKIO_WEIGHT_MAX)
return -EINVAL;
newpn->plid = plid;
@@ -850,26 +853,18 @@
switch(fileid) {
case BLKIO_THROTL_read_bps_device:
case BLKIO_THROTL_write_bps_device:
- ret = strict_strtoull(s[1], 10, &bps);
- if (ret)
- return -EINVAL;
-
newpn->plid = plid;
newpn->fileid = fileid;
- newpn->val.bps = bps;
+ newpn->val.bps = temp;
break;
case BLKIO_THROTL_read_iops_device:
case BLKIO_THROTL_write_iops_device:
- ret = strict_strtoull(s[1], 10, &iops);
- if (ret)
- return -EINVAL;
-
- if (iops > THROTL_IOPS_MAX)
+ if (temp > THROTL_IOPS_MAX)
return -EINVAL;
newpn->plid = plid;
newpn->fileid = fileid;
- newpn->val.iops = (unsigned int)iops;
+ newpn->val.iops = (unsigned int)temp;
break;
}
break;
diff --git a/block/blk-core.c b/block/blk-core.c
index 1d49e1c..847d04e 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -348,9 +348,10 @@
EXPORT_SYMBOL(blk_put_queue);
/*
- * Note: If a driver supplied the queue lock, it should not zap that lock
- * unexpectedly as some queue cleanup components like elevator_exit() and
- * blk_throtl_exit() need queue lock.
+ * Note: If a driver supplied the queue lock, it is disconnected
+ * by this function. The actual state of the lock doesn't matter
+ * here as the request_queue isn't accessible after this point
+ * (QUEUE_FLAG_DEAD is set) and no other requests will be queued.
*/
void blk_cleanup_queue(struct request_queue *q)
{
@@ -367,10 +368,8 @@
queue_flag_set_unlocked(QUEUE_FLAG_DEAD, q);
mutex_unlock(&q->sysfs_lock);
- if (q->elevator)
- elevator_exit(q->elevator);
-
- blk_throtl_exit(q);
+ if (q->queue_lock != &q->__queue_lock)
+ q->queue_lock = &q->__queue_lock;
blk_put_queue(q);
}
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index d935bd8..45c56d8 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -472,6 +472,11 @@
blk_sync_queue(q);
+ if (q->elevator)
+ elevator_exit(q->elevator);
+
+ blk_throtl_exit(q);
+
if (rl->rq_pool)
mempool_destroy(rl->rq_pool);
diff --git a/crypto/ghash-generic.c b/crypto/ghash-generic.c
index be44256..7835b8f 100644
--- a/crypto/ghash-generic.c
+++ b/crypto/ghash-generic.c
@@ -67,6 +67,9 @@
struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
u8 *dst = dctx->buffer;
+ if (!ctx->gf128)
+ return -ENOKEY;
+
if (dctx->bytes) {
int n = min(srclen, dctx->bytes);
u8 *pos = dst + (GHASH_BLOCK_SIZE - dctx->bytes);
@@ -119,6 +122,9 @@
struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
u8 *buf = dctx->buffer;
+ if (!ctx->gf128)
+ return -ENOKEY;
+
ghash_flush(ctx, dctx);
memcpy(dst, buf, GHASH_BLOCK_SIZE);
diff --git a/crypto/md5.c b/crypto/md5.c
index 30efc7d..7febeaa 100644
--- a/crypto/md5.c
+++ b/crypto/md5.c
@@ -21,99 +21,9 @@
#include <linux/module.h>
#include <linux/string.h>
#include <linux/types.h>
+#include <linux/cryptohash.h>
#include <asm/byteorder.h>
-#define F1(x, y, z) (z ^ (x & (y ^ z)))
-#define F2(x, y, z) F1(z, x, y)
-#define F3(x, y, z) (x ^ y ^ z)
-#define F4(x, y, z) (y ^ (x | ~z))
-
-#define MD5STEP(f, w, x, y, z, in, s) \
- (w += f(x, y, z) + in, w = (w<<s | w>>(32-s)) + x)
-
-static void md5_transform(u32 *hash, u32 const *in)
-{
- u32 a, b, c, d;
-
- a = hash[0];
- b = hash[1];
- c = hash[2];
- d = hash[3];
-
- MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
- MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
- MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
- MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
- MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
- MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
- MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
- MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
- MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
- MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
- MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
- MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
- MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
- MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
- MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
- MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
-
- MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
- MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
- MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
- MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
- MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
- MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
- MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
- MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
- MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
- MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
- MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
- MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
- MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
- MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
- MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
- MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
-
- MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
- MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
- MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
- MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
- MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
- MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
- MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
- MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
- MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
- MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
- MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
- MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
- MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
- MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
- MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
- MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
-
- MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
- MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
- MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
- MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
- MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
- MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
- MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
- MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
- MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
- MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
- MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
- MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
- MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
- MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
- MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
- MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
-
- hash[0] += a;
- hash[1] += b;
- hash[2] += c;
- hash[3] += d;
-}
-
/* XXX: this stuff can be optimized */
static inline void le32_to_cpu_array(u32 *buf, unsigned int words)
{
diff --git a/drivers/acpi/acpica/acconfig.h b/drivers/acpi/acpica/acconfig.h
index bc533dd..f895a24 100644
--- a/drivers/acpi/acpica/acconfig.h
+++ b/drivers/acpi/acpica/acconfig.h
@@ -121,7 +121,7 @@
/* Maximum sleep allowed via Sleep() operator */
-#define ACPI_MAX_SLEEP 20000 /* Two seconds */
+#define ACPI_MAX_SLEEP 2000 /* Two seconds */
/******************************************************************************
*
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index c7f743c..5552125 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -357,6 +357,7 @@
char *pathname;
const union acpi_predefined_info *predefined;
union acpi_operand_object *parent_package;
+ struct acpi_namespace_node *node;
u32 flags;
u8 node_flags;
};
diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c
index 9fb03fa..dc00582 100644
--- a/drivers/acpi/acpica/nspredef.c
+++ b/drivers/acpi/acpica/nspredef.c
@@ -212,6 +212,7 @@
goto cleanup;
}
data->predefined = predefined;
+ data->node = node;
data->node_flags = node->flags;
data->pathname = pathname;
diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c
index 973883b..024c4f2 100644
--- a/drivers/acpi/acpica/nsrepair2.c
+++ b/drivers/acpi/acpica/nsrepair2.c
@@ -503,6 +503,21 @@
{
union acpi_operand_object *return_object = *return_object_ptr;
acpi_status status;
+ struct acpi_namespace_node *node;
+
+ /*
+ * We can only sort the _TSS return package if there is no _PSS in the
+ * same scope. This is because if _PSS is present, the ACPI specification
+ * dictates that the _TSS Power Dissipation field is to be ignored, and
+ * therefore some BIOSs leave garbage values in the _TSS Power field(s).
+ * In this case, it is best to just return the _TSS package as-is.
+ * (May, 2011)
+ */
+ status =
+ acpi_ns_get_node(data->node, "^_PSS", ACPI_NS_NO_UPSEARCH, &node);
+ if (ACPI_SUCCESS(status)) {
+ return (AE_OK);
+ }
status = acpi_ns_check_sorted_list(data, return_object, 5, 1,
ACPI_SORT_DESCENDING,
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 71afe03..1e9ab9b 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -267,6 +267,7 @@
{ PCI_VDEVICE(INTEL, 0x1e05), board_ahci }, /* Panther Point RAID */
{ PCI_VDEVICE(INTEL, 0x1e06), board_ahci }, /* Panther Point RAID */
{ PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point RAID */
+ { PCI_VDEVICE(INTEL, 0x1e0e), board_ahci }, /* Panther Point RAID */
/* JMicron 360/1/3/5/6, match class to avoid IDE function */
{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -811,6 +812,18 @@
DMI_MATCH(DMI_BOARD_NAME, "MS-7376"),
},
},
+ /*
+ * All BIOS versions for the Asus M3A support 64bit DMA.
+ * (all release versions from 0301 to 1206 were tested)
+ */
+ {
+ .ident = "ASUS M3A",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR,
+ "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "M3A"),
+ },
+ },
{ }
};
const struct dmi_system_id *match;
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index ac8d7d9..d6d4f57 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -124,6 +124,17 @@
{ NULL }
};
+static const struct dmi_system_id no_atapi_dma_dmi_table[] = {
+ {
+ .ident = "AVERATEC 3200",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AVERATEC"),
+ DMI_MATCH(DMI_BOARD_NAME, "3200"),
+ },
+ },
+ { }
+};
+
struct via_port {
u8 cached_device;
};
@@ -355,6 +366,13 @@
mask &= ~ ATA_MASK_UDMA;
}
}
+
+ if (dev->class == ATA_DEV_ATAPI &&
+ dmi_check_system(no_atapi_dma_dmi_table)) {
+ ata_dev_printk(dev, KERN_WARNING, "controller locks up on ATAPI DMA, forcing PIO\n");
+ mask &= ATA_MASK_PIO;
+ }
+
return mask;
}
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index d57e8d0..12f5c47 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -168,4 +168,18 @@
bool
default n
+config GENLOCK
+ bool "Enable a generic cross-process locking mechanism"
+ depends on ANON_INODES
+ help
+ Enable a generic cross-process locking API to provide protection
+ for shared memory objects such as graphics buffers.
+
+config GENLOCK_MISCDEVICE
+ bool "Enable a misc-device for userspace to access the genlock engine"
+ depends on GENLOCK
+ help
+ Create a miscdevice for the purposes of allowing userspace to create
+ and interact with locks created using genlock.
+
endmenu
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 4c5701c..d3e2ec1 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -8,6 +8,7 @@
obj-y += power/
obj-$(CONFIG_HAS_DMA) += dma-mapping.o
obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
+obj-$(CONFIG_GENLOCK) += genlock.o
obj-$(CONFIG_ISA) += isa.o
obj-$(CONFIG_FW_LOADER) += firmware_class.o
obj-$(CONFIG_NUMA) += node.o
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index bbb03e6..06ed6b4 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -521,11 +521,6 @@
if (!firmware_p)
return -EINVAL;
- if (WARN_ON(usermodehelper_is_disabled())) {
- dev_err(device, "firmware: %s will not be loaded\n", name);
- return -EBUSY;
- }
-
*firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
if (!firmware) {
dev_err(device, "%s: kmalloc(struct firmware) failed\n",
@@ -539,6 +534,12 @@
return 0;
}
+ if (WARN_ON(usermodehelper_is_disabled())) {
+ dev_err(device, "firmware: %s will not be loaded\n", name);
+ retval = -EBUSY;
+ goto out;
+ }
+
if (uevent)
dev_dbg(device, "firmware: requesting %s\n", name);
diff --git a/drivers/base/genlock.c b/drivers/base/genlock.c
new file mode 100644
index 0000000..41bbd3a
--- /dev/null
+++ b/drivers/base/genlock.c
@@ -0,0 +1,639 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/fb.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/file.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+#include <linux/anon_inodes.h>
+#include <linux/miscdevice.h>
+#include <linux/genlock.h>
+
+/* Lock states - can either be unlocked, held as an exclusive write lock or a
+ * shared read lock
+ */
+
+#define _UNLOCKED 0
+#define _RDLOCK GENLOCK_RDLOCK
+#define _WRLOCK GENLOCK_WRLOCK
+
+struct genlock {
+ struct list_head active; /* List of handles holding lock */
+ spinlock_t lock; /* Spinlock to protect the lock internals */
+ wait_queue_head_t queue; /* Holding pen for processes pending lock */
+ struct file *file; /* File structure for exported lock */
+ int state; /* Current state of the lock */
+ struct kref refcount;
+};
+
+struct genlock_handle {
+ struct genlock *lock; /* Lock currently attached to the handle */
+ struct list_head entry; /* List node for attaching to a lock */
+ struct file *file; /* File structure associated with handle */
+ int active; /* Number of times the active lock has been
+ taken */
+};
+
+static void genlock_destroy(struct kref *kref)
+{
+ struct genlock *lock = container_of(kref, struct genlock,
+ refcount);
+
+ kfree(lock);
+}
+
+/*
+ * Release the genlock object. Called when all the references to
+ * the genlock file descriptor are released
+ */
+
+static int genlock_release(struct inode *inodep, struct file *file)
+{
+ return 0;
+}
+
+static const struct file_operations genlock_fops = {
+ .release = genlock_release,
+};
+
+/**
+ * genlock_create_lock - Create a new lock
+ * @handle - genlock handle to attach the lock to
+ *
+ * Returns: a pointer to the genlock
+ */
+
+struct genlock *genlock_create_lock(struct genlock_handle *handle)
+{
+ struct genlock *lock;
+
+ if (handle->lock != NULL)
+ return ERR_PTR(-EINVAL);
+
+ lock = kzalloc(sizeof(*lock), GFP_KERNEL);
+ if (lock == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_LIST_HEAD(&lock->active);
+ init_waitqueue_head(&lock->queue);
+ spin_lock_init(&lock->lock);
+
+ lock->state = _UNLOCKED;
+
+ /*
+ * Create an anonyonmous inode for the object that can exported to
+ * other processes
+ */
+
+ lock->file = anon_inode_getfile("genlock", &genlock_fops,
+ lock, O_RDWR);
+
+ /* Attach the new lock to the handle */
+ handle->lock = lock;
+ kref_init(&lock->refcount);
+
+ return lock;
+}
+EXPORT_SYMBOL(genlock_create_lock);
+
+/*
+ * Get a file descriptor reference to a lock suitable for sharing with
+ * other processes
+ */
+
+static int genlock_get_fd(struct genlock *lock)
+{
+ int ret;
+
+ if (!lock->file)
+ return -EINVAL;
+
+ ret = get_unused_fd_flags(0);
+ if (ret < 0)
+ return ret;
+ fd_install(ret, lock->file);
+ return ret;
+}
+
+/**
+ * genlock_attach_lock - Attach an existing lock to a handle
+ * @handle - Pointer to a genlock handle to attach the lock to
+ * @fd - file descriptor for the exported lock
+ *
+ * Returns: A pointer to the attached lock structure
+ */
+
+struct genlock *genlock_attach_lock(struct genlock_handle *handle, int fd)
+{
+ struct file *file;
+ struct genlock *lock;
+
+ if (handle->lock != NULL)
+ return ERR_PTR(-EINVAL);
+
+ file = fget(fd);
+ if (file == NULL)
+ return ERR_PTR(-EBADF);
+
+ lock = file->private_data;
+
+ fput(file);
+
+ if (lock == NULL)
+ return ERR_PTR(-EINVAL);
+
+ handle->lock = lock;
+ kref_get(&lock->refcount);
+
+ return lock;
+}
+EXPORT_SYMBOL(genlock_attach_lock);
+
+/* Helper function that returns 1 if the specified handle holds the lock */
+
+static int handle_has_lock(struct genlock *lock, struct genlock_handle *handle)
+{
+ struct genlock_handle *h;
+
+ list_for_each_entry(h, &lock->active, entry) {
+ if (h == handle)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* If the lock just became available, signal the next entity waiting for it */
+
+static void _genlock_signal(struct genlock *lock)
+{
+ if (list_empty(&lock->active)) {
+ /* If the list is empty, then the lock is free */
+ lock->state = _UNLOCKED;
+ /* Wake up the first process sitting in the queue */
+ wake_up(&lock->queue);
+ }
+}
+
+/* Attempt to release the handle's ownership of the lock */
+
+static int _genlock_unlock(struct genlock *lock, struct genlock_handle *handle)
+{
+ int ret = -EINVAL;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&lock->lock, irqflags);
+
+ if (lock->state == _UNLOCKED)
+ goto done;
+
+ /* Make sure this handle is an owner of the lock */
+ if (!handle_has_lock(lock, handle))
+ goto done;
+
+ /* If the handle holds no more references to the lock then
+ release it (maybe) */
+
+ if (--handle->active == 0) {
+ list_del(&handle->entry);
+ _genlock_signal(lock);
+ }
+
+ ret = 0;
+
+done:
+ spin_unlock_irqrestore(&lock->lock, irqflags);
+ return ret;
+}
+
+/* Attempt to acquire the lock for the handle */
+
+static int _genlock_lock(struct genlock *lock, struct genlock_handle *handle,
+ int op, int flags, uint32_t timeout)
+{
+ unsigned long irqflags;
+ int ret = 0;
+ unsigned int ticks = msecs_to_jiffies(timeout);
+
+ spin_lock_irqsave(&lock->lock, irqflags);
+
+ /* Sanity check - no blocking locks in a debug context. Even if it
+ * succeed to not block, the mere idea is too dangerous to continue
+ */
+
+ if (in_interrupt() && !(flags & GENLOCK_NOBLOCK))
+ BUG();
+
+ /* Fast path - the lock is unlocked, so go do the needful */
+
+ if (lock->state == _UNLOCKED)
+ goto dolock;
+
+ if (handle_has_lock(lock, handle)) {
+
+ /*
+ * If the handle already holds the lock and the type matches,
+ * then just increment the active pointer. This allows the
+ * handle to do recursive locks
+ */
+
+ if (lock->state == op) {
+ handle->active++;
+ goto done;
+ }
+
+ /*
+ * If the handle holds a write lock then the owner can switch
+ * to a read lock if they want. Do the transition atomically
+ * then wake up any pending waiters in case they want a read
+ * lock too.
+ */
+
+ if (op == _RDLOCK && handle->active == 1) {
+ lock->state = _RDLOCK;
+ wake_up(&lock->queue);
+ goto done;
+ }
+
+ /*
+ * Otherwise the user tried to turn a read into a write, and we
+ * don't allow that.
+ */
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /*
+ * If we request a read and the lock is held by a read, then go
+ * ahead and share the lock
+ */
+
+ if (op == GENLOCK_RDLOCK && lock->state == _RDLOCK)
+ goto dolock;
+
+ /* Treat timeout 0 just like a NOBLOCK flag and return if the
+ lock cannot be aquired without blocking */
+
+ if (flags & GENLOCK_NOBLOCK || timeout == 0) {
+ ret = -EAGAIN;
+ goto done;
+ }
+
+ /* Wait while the lock remains in an incompatible state */
+
+ while (lock->state != _UNLOCKED) {
+ unsigned int elapsed;
+
+ spin_unlock_irqrestore(&lock->lock, irqflags);
+
+ elapsed = wait_event_interruptible_timeout(lock->queue,
+ lock->state == _UNLOCKED, ticks);
+
+ spin_lock_irqsave(&lock->lock, irqflags);
+
+ if (elapsed <= 0) {
+ ret = (elapsed < 0) ? elapsed : -ETIMEDOUT;
+ goto done;
+ }
+
+ ticks = elapsed;
+ }
+
+dolock:
+ /* We can now get the lock, add ourselves to the list of owners */
+
+ list_add_tail(&handle->entry, &lock->active);
+ lock->state = op;
+ handle->active = 1;
+
+done:
+ spin_unlock_irqrestore(&lock->lock, irqflags);
+ return ret;
+
+}
+
+/**
+ * genlock_lock - Acquire or release a lock
+ * @handle - pointer to the genlock handle that is requesting the lock
+ * @op - the operation to perform (RDLOCK, WRLOCK, UNLOCK)
+ * @flags - flags to control the operation
+ * @timeout - optional timeout to wait for the lock to come free
+ *
+ * Returns: 0 on success or error code on failure
+ */
+
+int genlock_lock(struct genlock_handle *handle, int op, int flags,
+ uint32_t timeout)
+{
+ struct genlock *lock = handle->lock;
+ int ret = 0;
+
+ if (lock == NULL)
+ return -EINVAL;
+
+ switch (op) {
+ case GENLOCK_UNLOCK:
+ ret = _genlock_unlock(lock, handle);
+ break;
+ case GENLOCK_RDLOCK:
+ case GENLOCK_WRLOCK:
+ ret = _genlock_lock(lock, handle, op, flags, timeout);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(genlock_lock);
+
+/**
+ * genlock_wait - Wait for the lock to be released
+ * @handle - pointer to the genlock handle that is waiting for the lock
+ * @timeout - optional timeout to wait for the lock to get released
+ */
+
+int genlock_wait(struct genlock_handle *handle, uint32_t timeout)
+{
+ struct genlock *lock = handle->lock;
+ unsigned long irqflags;
+ int ret = 0;
+ unsigned int ticks = msecs_to_jiffies(timeout);
+
+ if (lock == NULL)
+ return -EINVAL;
+
+ spin_lock_irqsave(&lock->lock, irqflags);
+
+ /*
+ * if timeout is 0 and the lock is already unlocked, then success
+ * otherwise return -EAGAIN
+ */
+
+ if (timeout == 0) {
+ ret = (lock->state == _UNLOCKED) ? 0 : -EAGAIN;
+ goto done;
+ }
+
+ while (lock->state != _UNLOCKED) {
+ unsigned int elapsed;
+
+ spin_unlock_irqrestore(&lock->lock, irqflags);
+
+ elapsed = wait_event_interruptible_timeout(lock->queue,
+ lock->state == _UNLOCKED, ticks);
+
+ spin_lock_irqsave(&lock->lock, irqflags);
+
+ if (elapsed <= 0) {
+ ret = (elapsed < 0) ? elapsed : -ETIMEDOUT;
+ break;
+ }
+
+ ticks = elapsed;
+ }
+
+done:
+ spin_unlock_irqrestore(&lock->lock, irqflags);
+ return ret;
+}
+
+/**
+ * genlock_release_lock - Release a lock attached to a handle
+ * @handle - Pointer to the handle holding the lock
+ */
+
+void genlock_release_lock(struct genlock_handle *handle)
+{
+ unsigned long flags;
+
+ if (handle == NULL || handle->lock == NULL)
+ return;
+
+ spin_lock_irqsave(&handle->lock->lock, flags);
+
+ /* If the handle is holding the lock, then force it closed */
+
+ if (handle_has_lock(handle->lock, handle)) {
+ list_del(&handle->entry);
+ _genlock_signal(handle->lock);
+ }
+ spin_unlock_irqrestore(&handle->lock->lock, flags);
+
+ kref_put(&handle->lock->refcount, genlock_destroy);
+ handle->lock = NULL;
+ handle->active = 0;
+}
+EXPORT_SYMBOL(genlock_release_lock);
+
+/*
+ * Release function called when all references to a handle are released
+ */
+
+static int genlock_handle_release(struct inode *inodep, struct file *file)
+{
+ struct genlock_handle *handle = file->private_data;
+
+ genlock_release_lock(handle);
+ kfree(handle);
+
+ return 0;
+}
+
+static const struct file_operations genlock_handle_fops = {
+ .release = genlock_handle_release
+};
+
+/*
+ * Allocate a new genlock handle
+ */
+
+static struct genlock_handle *_genlock_get_handle(void)
+{
+ struct genlock_handle *handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+ if (handle == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ return handle;
+}
+
+/**
+ * genlock_get_handle - Create a new genlock handle
+ *
+ * Returns: A pointer to a new genlock handle
+ */
+
+struct genlock_handle *genlock_get_handle(void)
+{
+ struct genlock_handle *handle = _genlock_get_handle();
+ if (IS_ERR(handle))
+ return handle;
+
+ handle->file = anon_inode_getfile("genlock-handle",
+ &genlock_handle_fops, handle, O_RDWR);
+
+ return handle;
+}
+EXPORT_SYMBOL(genlock_get_handle);
+
+/**
+ * genlock_put_handle - release a reference to a genlock handle
+ * @handle - A pointer to the handle to release
+ */
+
+void genlock_put_handle(struct genlock_handle *handle)
+{
+ if (handle)
+ fput(handle->file);
+}
+EXPORT_SYMBOL(genlock_put_handle);
+
+/**
+ * genlock_get_handle_fd - Get a handle reference from a file descriptor
+ * @fd - The file descriptor for a genlock handle
+ */
+
+struct genlock_handle *genlock_get_handle_fd(int fd)
+{
+ struct file *file = fget(fd);
+
+ if (file == NULL)
+ return ERR_PTR(-EINVAL);
+
+ return file->private_data;
+}
+EXPORT_SYMBOL(genlock_get_handle_fd);
+
+#ifdef CONFIG_GENLOCK_MISCDEVICE
+
+static long genlock_dev_ioctl(struct file *filep, unsigned int cmd,
+ unsigned long arg)
+{
+ struct genlock_lock param;
+ struct genlock_handle *handle = filep->private_data;
+ struct genlock *lock;
+ int ret;
+
+ switch (cmd) {
+ case GENLOCK_IOC_NEW: {
+ lock = genlock_create_lock(handle);
+ if (IS_ERR(lock))
+ return PTR_ERR(lock);
+
+ return 0;
+ }
+ case GENLOCK_IOC_EXPORT: {
+ if (handle->lock == NULL)
+ return -EINVAL;
+
+ ret = genlock_get_fd(handle->lock);
+ if (ret < 0)
+ return ret;
+
+ param.fd = ret;
+
+ if (copy_to_user((void __user *) arg, ¶m,
+ sizeof(param)))
+ return -EFAULT;
+
+ return 0;
+ }
+ case GENLOCK_IOC_ATTACH: {
+ if (copy_from_user(¶m, (void __user *) arg,
+ sizeof(param)))
+ return -EFAULT;
+
+ lock = genlock_attach_lock(handle, param.fd);
+ if (IS_ERR(lock))
+ return PTR_ERR(lock);
+
+ return 0;
+ }
+ case GENLOCK_IOC_LOCK: {
+ if (copy_from_user(¶m, (void __user *) arg,
+ sizeof(param)))
+ return -EFAULT;
+
+ return genlock_lock(handle, param.op, param.flags,
+ param.timeout);
+ }
+ case GENLOCK_IOC_WAIT: {
+ if (copy_from_user(¶m, (void __user *) arg,
+ sizeof(param)))
+ return -EFAULT;
+
+ return genlock_wait(handle, param.timeout);
+ }
+ case GENLOCK_IOC_RELEASE: {
+ genlock_release_lock(handle);
+ return 0;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int genlock_dev_release(struct inode *inodep, struct file *file)
+{
+ struct genlock_handle *handle = file->private_data;
+
+ genlock_release_lock(handle);
+ kfree(handle);
+
+ return 0;
+}
+
+static int genlock_dev_open(struct inode *inodep, struct file *file)
+{
+ struct genlock_handle *handle = _genlock_get_handle();
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ handle->file = file;
+ file->private_data = handle;
+ return 0;
+}
+
+static const struct file_operations genlock_dev_fops = {
+ .open = genlock_dev_open,
+ .release = genlock_dev_release,
+ .unlocked_ioctl = genlock_dev_ioctl,
+};
+
+static struct miscdevice genlock_dev;
+
+static int genlock_dev_init(void)
+{
+ genlock_dev.minor = MISC_DYNAMIC_MINOR;
+ genlock_dev.name = "genlock";
+ genlock_dev.fops = &genlock_dev_fops;
+ genlock_dev.parent = NULL;
+
+ return misc_register(&genlock_dev);
+}
+
+static void genlock_dev_close(void)
+{
+ misc_deregister(&genlock_dev);
+}
+
+module_init(genlock_dev_init);
+module_exit(genlock_dev_close);
+
+#endif
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 0d4587b..577f4fd 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -732,6 +732,8 @@
unsigned long flags;
int retval;
+ might_sleep_if(!(rpmflags & RPM_ASYNC));
+
if (rpmflags & RPM_GET_PUT) {
if (!atomic_dec_and_test(&dev->power.usage_count))
return 0;
@@ -761,6 +763,8 @@
unsigned long flags;
int retval;
+ might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe);
+
if (rpmflags & RPM_GET_PUT) {
if (!atomic_dec_and_test(&dev->power.usage_count))
return 0;
@@ -789,6 +793,8 @@
unsigned long flags;
int retval;
+ might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe);
+
if (rpmflags & RPM_GET_PUT)
atomic_inc(&dev->power.usage_count);
@@ -978,6 +984,7 @@
*/
void __pm_runtime_disable(struct device *dev, bool check_resume)
{
+ might_sleep();
spin_lock_irq(&dev->power.lock);
if (dev->power.disable_depth > 0) {
@@ -1184,6 +1191,8 @@
{
int old_delay, old_use;
+ might_sleep();
+
spin_lock_irq(&dev->power.lock);
old_delay = dev->power.autosuspend_delay;
old_use = dev->power.use_autosuspend;
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 98de8f4..9955a53 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -4250,7 +4250,7 @@
use_virtual_dma = can_use_virtual_dma & 1;
fdc_state[0].address = FDC1;
if (fdc_state[0].address == -1) {
- del_timer(&fd_timeout);
+ del_timer_sync(&fd_timeout);
err = -ENODEV;
goto out_unreg_region;
}
@@ -4261,7 +4261,7 @@
fdc = 0; /* reset fdc in case of unexpected interrupt */
err = floppy_grab_irq_and_dma();
if (err) {
- del_timer(&fd_timeout);
+ del_timer_sync(&fd_timeout);
err = -EBUSY;
goto out_unreg_region;
}
@@ -4318,7 +4318,7 @@
user_reset_fdc(-1, FD_RESET_ALWAYS, false);
}
fdc = 0;
- del_timer(&fd_timeout);
+ del_timer_sync(&fd_timeout);
current_drive = 0;
initialized = true;
if (have_no_fdc) {
@@ -4368,7 +4368,7 @@
unregister_blkdev(FLOPPY_MAJOR, "fd");
out_put_disk:
while (dr--) {
- del_timer(&motor_off_timer[dr]);
+ del_timer_sync(&motor_off_timer[dr]);
if (disks[dr]->queue)
blk_cleanup_queue(disks[dr]->queue);
put_disk(disks[dr]);
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 76c8da7..2ebacf0 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -750,10 +750,10 @@
ssize_t ret;
char *p = NULL;
- mutex_lock(&lo->lo_ctl_mutex);
+ spin_lock_irq(&lo->lo_lock);
if (lo->lo_backing_file)
p = d_path(&lo->lo_backing_file->f_path, buf, PAGE_SIZE - 1);
- mutex_unlock(&lo->lo_ctl_mutex);
+ spin_unlock_irq(&lo->lo_lock);
if (IS_ERR_OR_NULL(p))
ret = PTR_ERR(p);
@@ -1007,7 +1007,9 @@
kthread_stop(lo->lo_thread);
+ spin_lock_irq(&lo->lo_lock);
lo->lo_backing_file = NULL;
+ spin_unlock_irq(&lo->lo_lock);
loop_release_xfer(lo);
lo->transfer = NULL;
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index b536a9c..9ea8c25 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -123,8 +123,8 @@
#define BLKIF_MINOR_EXT(dev) ((dev)&(~EXTENDED))
#define EMULATED_HD_DISK_MINOR_OFFSET (0)
#define EMULATED_HD_DISK_NAME_OFFSET (EMULATED_HD_DISK_MINOR_OFFSET / 256)
-#define EMULATED_SD_DISK_MINOR_OFFSET (EMULATED_HD_DISK_MINOR_OFFSET + (4 * 16))
-#define EMULATED_SD_DISK_NAME_OFFSET (EMULATED_HD_DISK_NAME_OFFSET + 4)
+#define EMULATED_SD_DISK_MINOR_OFFSET (0)
+#define EMULATED_SD_DISK_NAME_OFFSET (EMULATED_SD_DISK_MINOR_OFFSET / 256)
#define DEV_NAME "xvd" /* name in /dev */
@@ -529,7 +529,7 @@
minor = BLKIF_MINOR_EXT(info->vdevice);
nr_parts = PARTS_PER_EXT_DISK;
offset = minor / nr_parts;
- if (xen_hvm_domain() && offset <= EMULATED_HD_DISK_NAME_OFFSET + 4)
+ if (xen_hvm_domain() && offset < EMULATED_HD_DISK_NAME_OFFSET + 4)
printk(KERN_WARNING "blkfront: vdevice 0x%x might conflict with "
"emulated IDE disks,\n\t choose an xvd device name"
"from xvde on\n", info->vdevice);
diff --git a/drivers/bluetooth/hci_smd.c b/drivers/bluetooth/hci_smd.c
index 118bbb3..a321849 100644
--- a/drivers/bluetooth/hci_smd.c
+++ b/drivers/bluetooth/hci_smd.c
@@ -140,20 +140,20 @@
wake_lock(&hs.wake_lock_rx);
len = smd_read_avail(hsmd->data_channel);
- if (len <= 0) {
- BT_ERR("Nothing to read from SMD channel\n");
+ if (len > HCI_MAX_FRAME_SIZE) {
+ BT_ERR("Frame larger than the allowed size");
goto out_data;
}
while (len > 0) {
skb = bt_skb_alloc(len, GFP_ATOMIC);
if (!skb) {
- BT_ERR("Error in allocating socket buffer\n");
+ BT_ERR("Error in allocating socket buffer");
goto out_data;
}
buf = kmalloc(len, GFP_ATOMIC);
if (!buf) {
- BT_ERR("Error in allocating buffer\n");
+ BT_ERR("Error in allocating buffer");
rc = -ENOMEM;
goto out_data;
}
@@ -188,7 +188,7 @@
* Start the timer to monitor whether the Rx queue is
* empty for releasing the Rx wake lock
*/
- BT_DBG("Rx Timer is starting\n");
+ BT_DBG("Rx Timer is starting");
mod_timer(&hsmd->rx_q_timer,
jiffies + msecs_to_jiffies(RX_Q_MONITOR));
}
@@ -214,20 +214,17 @@
if (len > HCI_MAX_FRAME_SIZE) {
BT_ERR("Frame larger than the allowed size");
goto out_event;
- } else if (len <= 0) {
- BT_ERR("Nothing to read from SMD channel\n");
- goto out_event;
}
while (len > 0) {
skb = bt_skb_alloc(len, GFP_ATOMIC);
if (!skb) {
- BT_ERR("Error in allocating socket buffer\n");
+ BT_ERR("Error in allocating socket buffer");
goto out_event;
}
buf = kmalloc(len, GFP_ATOMIC);
if (!buf) {
- BT_ERR("Error in allocating buffer\n");
+ BT_ERR("Error in allocating buffer");
rc = -ENOMEM;
goto out_event;
}
@@ -261,7 +258,7 @@
* Start the timer to monitor whether the Rx queue is
* empty for releasing the Rx wake lock
*/
- BT_DBG("Rx Timer is starting\n");
+ BT_DBG("Rx Timer is starting");
mod_timer(&hsmd->rx_q_timer,
jiffies + msecs_to_jiffies(RX_Q_MONITOR));
}
@@ -308,7 +305,7 @@
}
break;
default:
- BT_ERR("Uknown packet type\n");
+ BT_ERR("Uknown packet type");
ret = -ENODEV;
break;
}
@@ -322,6 +319,8 @@
static void hci_smd_notify_event(void *data, unsigned int event)
{
struct hci_dev *hdev = hs.hdev;
+ struct hci_smd_data *hsmd = &hs;
+ int len = 0;
if (!hdev) {
BT_ERR("Frame for unknown HCI device (hdev=NULL)");
@@ -330,12 +329,19 @@
switch (event) {
case SMD_EVENT_DATA:
- tasklet_hi_schedule(&hs.hci_event_task);
+ len = smd_read_avail(hsmd->event_channel);
+ if (len > 0)
+ tasklet_hi_schedule(&hs.hci_event_task);
+ else if (len < 0)
+ BT_ERR("Failed to read event from smd %d", len);
+
break;
case SMD_EVENT_OPEN:
+ BT_INFO("opening HCI-SMD channel :%s", EVENT_CHANNEL);
hci_smd_open(hdev);
break;
case SMD_EVENT_CLOSE:
+ BT_INFO("Closing HCI-SMD channel :%s", EVENT_CHANNEL);
hci_smd_close(hdev);
break;
default:
@@ -346,6 +352,9 @@
static void hci_smd_notify_data(void *data, unsigned int event)
{
struct hci_dev *hdev = hs.hdev;
+ struct hci_smd_data *hsmd = &hs;
+ int len = 0;
+
if (!hdev) {
BT_ERR("HCI device (hdev=NULL)");
return;
@@ -353,12 +362,18 @@
switch (event) {
case SMD_EVENT_DATA:
- tasklet_hi_schedule(&hs.hci_data_task);
+ len = smd_read_avail(hsmd->data_channel);
+ if (len > 0)
+ tasklet_hi_schedule(&hs.hci_data_task);
+ else if (len < 0)
+ BT_ERR("Failed to read data from smd %d", len);
break;
case SMD_EVENT_OPEN:
+ BT_INFO("opening HCI-SMD channel :%s", DATA_CHANNEL);
hci_smd_open(hdev);
break;
case SMD_EVENT_CLOSE:
+ BT_INFO("Closing HCI-SMD channel :%s", DATA_CHANNEL);
hci_smd_close(hdev);
break;
default:
@@ -419,7 +434,7 @@
rc = smd_named_open_on_edge(DATA_CHANNEL, SMD_APPS_WCNSS,
&hsmd->data_channel, hdev, hci_smd_notify_data);
if (rc < 0) {
- BT_ERR("Failed to open the Data channel\n");
+ BT_ERR("Failed to open the Data channel");
hci_free_dev(hdev);
return -ENODEV;
}
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index cac5c81..58c9b9a 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -43,7 +43,7 @@
unsigned char diag_debug_buf[1024];
static unsigned int buf_tbl_size = 8; /*Number of entries in table of buffers */
struct diag_master_table entry;
-
+smd_channel_t *ch_temp;
struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
@@ -1149,8 +1149,12 @@
if (event == SMD_EVENT_CLOSE) {
pr_info("diag: clean modem registration\n");
diag_clear_reg(MODEM_PROC);
- } else
- queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
+ driver->ch = 0;
+ return;
+ } else if (event == SMD_EVENT_OPEN) {
+ driver->ch = ch_temp;
+ }
+ queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
}
#if defined(CONFIG_MSM_N_WAY_SMD)
@@ -1169,8 +1173,10 @@
{
int r = 0;
- if (pdev->id == SMD_APPS_MODEM)
+ if (pdev->id == SMD_APPS_MODEM) {
r = smd_open("DIAG", &driver->ch, driver, diag_smd_notify);
+ ch_temp = driver->ch;
+ }
#if defined(CONFIG_MSM_N_WAY_SMD)
if (pdev->id == SMD_APPS_QDSP)
r = smd_named_open_on_edge("DIAG", SMD_APPS_QDSP
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index 696a7bd..edf5c27 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -19,7 +19,6 @@
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/clk.h>
-#include <mach/clk.h>
#include <linux/android_pmem.h>
#include <linux/msm_rotator.h>
#include <linux/io.h>
@@ -1339,7 +1338,7 @@
goto error_imem_clk;
}
if (pdata->rotator_clks[i].clk_rate)
- clk_set_min_rate(msm_rotator_dev->imem_clk,
+ clk_set_rate(msm_rotator_dev->imem_clk,
pdata->rotator_clks[i].clk_rate);
}
if (pdata->rotator_clks[i].clk_type == ROTATOR_PCLK) {
@@ -1355,7 +1354,7 @@
}
if (pdata->rotator_clks[i].clk_rate)
- clk_set_min_rate(msm_rotator_dev->pclk,
+ clk_set_rate(msm_rotator_dev->pclk,
pdata->rotator_clks[i].clk_rate);
}
@@ -1372,7 +1371,7 @@
}
if (pdata->rotator_clks[i].clk_rate)
- clk_set_min_rate(msm_rotator_dev->core_clk,
+ clk_set_rate(msm_rotator_dev->core_clk,
pdata->rotator_clks[i].clk_rate);
}
}
diff --git a/drivers/char/random.c b/drivers/char/random.c
index d4ddeba..c35a785 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1300,330 +1300,14 @@
};
#endif /* CONFIG_SYSCTL */
-/********************************************************************
- *
- * Random functions for networking
- *
- ********************************************************************/
+static u32 random_int_secret[MD5_MESSAGE_BYTES / 4] ____cacheline_aligned;
-/*
- * TCP initial sequence number picking. This uses the random number
- * generator to pick an initial secret value. This value is hashed
- * along with the TCP endpoint information to provide a unique
- * starting point for each pair of TCP endpoints. This defeats
- * attacks which rely on guessing the initial TCP sequence number.
- * This algorithm was suggested by Steve Bellovin.
- *
- * Using a very strong hash was taking an appreciable amount of the total
- * TCP connection establishment time, so this is a weaker hash,
- * compensated for by changing the secret periodically.
- */
-
-/* F, G and H are basic MD4 functions: selection, majority, parity */
-#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
-#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-
-/*
- * The generic round function. The application is so specific that
- * we don't bother protecting all the arguments with parens, as is generally
- * good macro practice, in favor of extra legibility.
- * Rotation is separate from addition to prevent recomputation
- */
-#define ROUND(f, a, b, c, d, x, s) \
- (a += f(b, c, d) + x, a = (a << s) | (a >> (32 - s)))
-#define K1 0
-#define K2 013240474631UL
-#define K3 015666365641UL
-
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-
-static __u32 twothirdsMD4Transform(__u32 const buf[4], __u32 const in[12])
+static int __init random_int_secret_init(void)
{
- __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
-
- /* Round 1 */
- ROUND(F, a, b, c, d, in[ 0] + K1, 3);
- ROUND(F, d, a, b, c, in[ 1] + K1, 7);
- ROUND(F, c, d, a, b, in[ 2] + K1, 11);
- ROUND(F, b, c, d, a, in[ 3] + K1, 19);
- ROUND(F, a, b, c, d, in[ 4] + K1, 3);
- ROUND(F, d, a, b, c, in[ 5] + K1, 7);
- ROUND(F, c, d, a, b, in[ 6] + K1, 11);
- ROUND(F, b, c, d, a, in[ 7] + K1, 19);
- ROUND(F, a, b, c, d, in[ 8] + K1, 3);
- ROUND(F, d, a, b, c, in[ 9] + K1, 7);
- ROUND(F, c, d, a, b, in[10] + K1, 11);
- ROUND(F, b, c, d, a, in[11] + K1, 19);
-
- /* Round 2 */
- ROUND(G, a, b, c, d, in[ 1] + K2, 3);
- ROUND(G, d, a, b, c, in[ 3] + K2, 5);
- ROUND(G, c, d, a, b, in[ 5] + K2, 9);
- ROUND(G, b, c, d, a, in[ 7] + K2, 13);
- ROUND(G, a, b, c, d, in[ 9] + K2, 3);
- ROUND(G, d, a, b, c, in[11] + K2, 5);
- ROUND(G, c, d, a, b, in[ 0] + K2, 9);
- ROUND(G, b, c, d, a, in[ 2] + K2, 13);
- ROUND(G, a, b, c, d, in[ 4] + K2, 3);
- ROUND(G, d, a, b, c, in[ 6] + K2, 5);
- ROUND(G, c, d, a, b, in[ 8] + K2, 9);
- ROUND(G, b, c, d, a, in[10] + K2, 13);
-
- /* Round 3 */
- ROUND(H, a, b, c, d, in[ 3] + K3, 3);
- ROUND(H, d, a, b, c, in[ 7] + K3, 9);
- ROUND(H, c, d, a, b, in[11] + K3, 11);
- ROUND(H, b, c, d, a, in[ 2] + K3, 15);
- ROUND(H, a, b, c, d, in[ 6] + K3, 3);
- ROUND(H, d, a, b, c, in[10] + K3, 9);
- ROUND(H, c, d, a, b, in[ 1] + K3, 11);
- ROUND(H, b, c, d, a, in[ 5] + K3, 15);
- ROUND(H, a, b, c, d, in[ 9] + K3, 3);
- ROUND(H, d, a, b, c, in[ 0] + K3, 9);
- ROUND(H, c, d, a, b, in[ 4] + K3, 11);
- ROUND(H, b, c, d, a, in[ 8] + K3, 15);
-
- return buf[1] + b; /* "most hashed" word */
- /* Alternative: return sum of all words? */
-}
-#endif
-
-#undef ROUND
-#undef F
-#undef G
-#undef H
-#undef K1
-#undef K2
-#undef K3
-
-/* This should not be decreased so low that ISNs wrap too fast. */
-#define REKEY_INTERVAL (300 * HZ)
-/*
- * Bit layout of the tcp sequence numbers (before adding current time):
- * bit 24-31: increased after every key exchange
- * bit 0-23: hash(source,dest)
- *
- * The implementation is similar to the algorithm described
- * in the Appendix of RFC 1185, except that
- * - it uses a 1 MHz clock instead of a 250 kHz clock
- * - it performs a rekey every 5 minutes, which is equivalent
- * to a (source,dest) tulple dependent forward jump of the
- * clock by 0..2^(HASH_BITS+1)
- *
- * Thus the average ISN wraparound time is 68 minutes instead of
- * 4.55 hours.
- *
- * SMP cleanup and lock avoidance with poor man's RCU.
- * Manfred Spraul <manfred@colorfullife.com>
- *
- */
-#define COUNT_BITS 8
-#define COUNT_MASK ((1 << COUNT_BITS) - 1)
-#define HASH_BITS 24
-#define HASH_MASK ((1 << HASH_BITS) - 1)
-
-static struct keydata {
- __u32 count; /* already shifted to the final position */
- __u32 secret[12];
-} ____cacheline_aligned ip_keydata[2];
-
-static unsigned int ip_cnt;
-
-static void rekey_seq_generator(struct work_struct *work);
-
-static DECLARE_DELAYED_WORK(rekey_work, rekey_seq_generator);
-
-/*
- * Lock avoidance:
- * The ISN generation runs lockless - it's just a hash over random data.
- * State changes happen every 5 minutes when the random key is replaced.
- * Synchronization is performed by having two copies of the hash function
- * state and rekey_seq_generator always updates the inactive copy.
- * The copy is then activated by updating ip_cnt.
- * The implementation breaks down if someone blocks the thread
- * that processes SYN requests for more than 5 minutes. Should never
- * happen, and even if that happens only a not perfectly compliant
- * ISN is generated, nothing fatal.
- */
-static void rekey_seq_generator(struct work_struct *work)
-{
- struct keydata *keyptr = &ip_keydata[1 ^ (ip_cnt & 1)];
-
- get_random_bytes(keyptr->secret, sizeof(keyptr->secret));
- keyptr->count = (ip_cnt & COUNT_MASK) << HASH_BITS;
- smp_wmb();
- ip_cnt++;
- schedule_delayed_work(&rekey_work,
- round_jiffies_relative(REKEY_INTERVAL));
-}
-
-static inline struct keydata *get_keyptr(void)
-{
- struct keydata *keyptr = &ip_keydata[ip_cnt & 1];
-
- smp_rmb();
-
- return keyptr;
-}
-
-static __init int seqgen_init(void)
-{
- rekey_seq_generator(NULL);
+ get_random_bytes(random_int_secret, sizeof(random_int_secret));
return 0;
}
-late_initcall(seqgen_init);
-
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-__u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr,
- __be16 sport, __be16 dport)
-{
- __u32 seq;
- __u32 hash[12];
- struct keydata *keyptr = get_keyptr();
-
- /* The procedure is the same as for IPv4, but addresses are longer.
- * Thus we must use twothirdsMD4Transform.
- */
-
- memcpy(hash, saddr, 16);
- hash[4] = ((__force u16)sport << 16) + (__force u16)dport;
- memcpy(&hash[5], keyptr->secret, sizeof(__u32) * 7);
-
- seq = twothirdsMD4Transform((const __u32 *)daddr, hash) & HASH_MASK;
- seq += keyptr->count;
-
- seq += ktime_to_ns(ktime_get_real());
-
- return seq;
-}
-EXPORT_SYMBOL(secure_tcpv6_sequence_number);
-#endif
-
-/* The code below is shamelessly stolen from secure_tcp_sequence_number().
- * All blames to Andrey V. Savochkin <saw@msu.ru>.
- */
-__u32 secure_ip_id(__be32 daddr)
-{
- struct keydata *keyptr;
- __u32 hash[4];
-
- keyptr = get_keyptr();
-
- /*
- * Pick a unique starting offset for each IP destination.
- * The dest ip address is placed in the starting vector,
- * which is then hashed with random data.
- */
- hash[0] = (__force __u32)daddr;
- hash[1] = keyptr->secret[9];
- hash[2] = keyptr->secret[10];
- hash[3] = keyptr->secret[11];
-
- return half_md4_transform(hash, keyptr->secret);
-}
-
-#ifdef CONFIG_INET
-
-__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
- __be16 sport, __be16 dport)
-{
- __u32 seq;
- __u32 hash[4];
- struct keydata *keyptr = get_keyptr();
-
- /*
- * Pick a unique starting offset for each TCP connection endpoints
- * (saddr, daddr, sport, dport).
- * Note that the words are placed into the starting vector, which is
- * then mixed with a partial MD4 over random data.
- */
- hash[0] = (__force u32)saddr;
- hash[1] = (__force u32)daddr;
- hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
- hash[3] = keyptr->secret[11];
-
- seq = half_md4_transform(hash, keyptr->secret) & HASH_MASK;
- seq += keyptr->count;
- /*
- * As close as possible to RFC 793, which
- * suggests using a 250 kHz clock.
- * Further reading shows this assumes 2 Mb/s networks.
- * For 10 Mb/s Ethernet, a 1 MHz clock is appropriate.
- * For 10 Gb/s Ethernet, a 1 GHz clock should be ok, but
- * we also need to limit the resolution so that the u32 seq
- * overlaps less than one time per MSL (2 minutes).
- * Choosing a clock of 64 ns period is OK. (period of 274 s)
- */
- seq += ktime_to_ns(ktime_get_real()) >> 6;
-
- return seq;
-}
-
-/* Generate secure starting point for ephemeral IPV4 transport port search */
-u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport)
-{
- struct keydata *keyptr = get_keyptr();
- u32 hash[4];
-
- /*
- * Pick a unique starting offset for each ephemeral port search
- * (saddr, daddr, dport) and 48bits of random data.
- */
- hash[0] = (__force u32)saddr;
- hash[1] = (__force u32)daddr;
- hash[2] = (__force u32)dport ^ keyptr->secret[10];
- hash[3] = keyptr->secret[11];
-
- return half_md4_transform(hash, keyptr->secret);
-}
-EXPORT_SYMBOL_GPL(secure_ipv4_port_ephemeral);
-
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
- __be16 dport)
-{
- struct keydata *keyptr = get_keyptr();
- u32 hash[12];
-
- memcpy(hash, saddr, 16);
- hash[4] = (__force u32)dport;
- memcpy(&hash[5], keyptr->secret, sizeof(__u32) * 7);
-
- return twothirdsMD4Transform((const __u32 *)daddr, hash);
-}
-#endif
-
-#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE)
-/* Similar to secure_tcp_sequence_number but generate a 48 bit value
- * bit's 32-47 increase every key exchange
- * 0-31 hash(source, dest)
- */
-u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
- __be16 sport, __be16 dport)
-{
- u64 seq;
- __u32 hash[4];
- struct keydata *keyptr = get_keyptr();
-
- hash[0] = (__force u32)saddr;
- hash[1] = (__force u32)daddr;
- hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
- hash[3] = keyptr->secret[11];
-
- seq = half_md4_transform(hash, keyptr->secret);
- seq |= ((u64)keyptr->count) << (32 - HASH_BITS);
-
- seq += ktime_to_ns(ktime_get_real());
- seq &= (1ull << 48) - 1;
-
- return seq;
-}
-EXPORT_SYMBOL(secure_dccp_sequence_number);
-#endif
-
-#endif /* CONFIG_INET */
-
+late_initcall(random_int_secret_init);
/*
* Get a random word for internal kernel use only. Similar to urandom but
@@ -1631,17 +1315,15 @@
* value is not cryptographically secure but for several uses the cost of
* depleting entropy is too high
*/
-DEFINE_PER_CPU(__u32 [4], get_random_int_hash);
+DEFINE_PER_CPU(__u32 [MD5_DIGEST_WORDS], get_random_int_hash);
unsigned int get_random_int(void)
{
- struct keydata *keyptr;
__u32 *hash = get_cpu_var(get_random_int_hash);
- int ret;
+ unsigned int ret;
- keyptr = get_keyptr();
hash[0] += current->pid + jiffies + get_cycles();
-
- ret = half_md4_transform(hash, keyptr->secret);
+ md5_transform(hash, random_int_secret);
+ ret = hash[0];
put_cpu_var(get_random_int_hash);
return ret;
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 7beb0e2..b85ee76 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -383,6 +383,9 @@
u32 count, ordinal;
unsigned long stop;
+ if (bufsiz > TPM_BUFSIZE)
+ bufsiz = TPM_BUFSIZE;
+
count = be32_to_cpu(*((__be32 *) (buf + 2)));
ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
if (count == 0)
@@ -1052,6 +1055,7 @@
{
struct tpm_chip *chip = file->private_data;
ssize_t ret_size;
+ int rc;
del_singleshot_timer_sync(&chip->user_read_timer);
flush_work_sync(&chip->work);
@@ -1062,8 +1066,11 @@
ret_size = size;
mutex_lock(&chip->buffer_mutex);
- if (copy_to_user(buf, chip->data_buffer, ret_size))
+ rc = copy_to_user(buf, chip->data_buffer, ret_size);
+ memset(chip->data_buffer, 0, ret_size);
+ if (rc)
ret_size = -EFAULT;
+
mutex_unlock(&chip->buffer_mutex);
}
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
index f90d3a5..45266d5 100644
--- a/drivers/cpufreq/cpufreq_interactive.c
+++ b/drivers/cpufreq/cpufreq_interactive.c
@@ -22,9 +22,11 @@
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/tick.h>
+#include <linux/time.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/kthread.h>
+#include <linux/mutex.h>
#include <asm/cputime.h>
@@ -55,21 +57,25 @@
static spinlock_t up_cpumask_lock;
static cpumask_t down_cpumask;
static spinlock_t down_cpumask_lock;
+static struct mutex set_speed_lock;
-/* Go to max speed when CPU load at or above this value. */
-#define DEFAULT_GO_MAXSPEED_LOAD 85
-static unsigned long go_maxspeed_load;
+/* Hi speed to bump to from lo speed when load burst (default max) */
+static u64 hispeed_freq;
+
+/* Go to hi speed when CPU load at or above this value. */
+#define DEFAULT_GO_HISPEED_LOAD 95
+static unsigned long go_hispeed_load;
/*
* The minimum amount of time to spend at a frequency before we can ramp down.
*/
-#define DEFAULT_MIN_SAMPLE_TIME 80000;
+#define DEFAULT_MIN_SAMPLE_TIME 20 * USEC_PER_MSEC
static unsigned long min_sample_time;
/*
* The sample rate of the timer used to increase frequency
*/
-#define DEFAULT_TIMER_RATE 30000;
+#define DEFAULT_TIMER_RATE 20 * USEC_PER_MSEC
static unsigned long timer_rate;
static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
@@ -143,7 +149,7 @@
delta_time = (unsigned int) cputime64_sub(pcpu->timer_run_time,
pcpu->freq_change_time);
- if (delta_idle > delta_time)
+ if ((delta_time == 0) || (delta_idle > delta_time))
load_since_change = 0;
else
load_since_change =
@@ -157,10 +163,14 @@
if (load_since_change > cpu_load)
cpu_load = load_since_change;
- if (cpu_load >= go_maxspeed_load)
- new_freq = pcpu->policy->max;
- else
- new_freq = pcpu->policy->max * cpu_load / 100;
+ if (cpu_load >= go_hispeed_load) {
+ if (pcpu->policy->cur == pcpu->policy->min)
+ new_freq = hispeed_freq;
+ else
+ new_freq = pcpu->policy->max * cpu_load / 100;
+ } else {
+ new_freq = pcpu->policy->cur * cpu_load / 100;
+ }
if (cpufreq_frequency_table_target(pcpu->policy, pcpu->freq_table,
new_freq, CPUFREQ_RELATION_H,
@@ -339,22 +349,36 @@
}
set_current_state(TASK_RUNNING);
-
tmp_mask = up_cpumask;
cpumask_clear(&up_cpumask);
spin_unlock_irqrestore(&up_cpumask_lock, flags);
for_each_cpu(cpu, &tmp_mask) {
- pcpu = &per_cpu(cpuinfo, cpu);
+ unsigned int j;
+ unsigned int max_freq = 0;
+ pcpu = &per_cpu(cpuinfo, cpu);
smp_rmb();
if (!pcpu->governor_enabled)
continue;
- __cpufreq_driver_target(pcpu->policy,
- pcpu->target_freq,
- CPUFREQ_RELATION_H);
+ mutex_lock(&set_speed_lock);
+
+ for_each_cpu(j, pcpu->policy->cpus) {
+ struct cpufreq_interactive_cpuinfo *pjcpu =
+ &per_cpu(cpuinfo, j);
+
+ if (pjcpu->target_freq > max_freq)
+ max_freq = pjcpu->target_freq;
+ }
+
+ if (max_freq != pcpu->policy->cur)
+ __cpufreq_driver_target(pcpu->policy,
+ max_freq,
+ CPUFREQ_RELATION_H);
+ mutex_unlock(&set_speed_lock);
+
pcpu->freq_change_time_in_idle =
get_cpu_idle_time_us(cpu,
&pcpu->freq_change_time);
@@ -377,29 +401,67 @@
spin_unlock_irqrestore(&down_cpumask_lock, flags);
for_each_cpu(cpu, &tmp_mask) {
- pcpu = &per_cpu(cpuinfo, cpu);
+ unsigned int j;
+ unsigned int max_freq = 0;
+ pcpu = &per_cpu(cpuinfo, cpu);
smp_rmb();
if (!pcpu->governor_enabled)
continue;
- __cpufreq_driver_target(pcpu->policy,
- pcpu->target_freq,
- CPUFREQ_RELATION_H);
+ mutex_lock(&set_speed_lock);
+
+ for_each_cpu(j, pcpu->policy->cpus) {
+ struct cpufreq_interactive_cpuinfo *pjcpu =
+ &per_cpu(cpuinfo, j);
+
+ if (pjcpu->target_freq > max_freq)
+ max_freq = pjcpu->target_freq;
+ }
+
+ if (max_freq != pcpu->policy->cur)
+ __cpufreq_driver_target(pcpu->policy, max_freq,
+ CPUFREQ_RELATION_H);
+
+ mutex_unlock(&set_speed_lock);
pcpu->freq_change_time_in_idle =
get_cpu_idle_time_us(cpu,
&pcpu->freq_change_time);
}
}
-static ssize_t show_go_maxspeed_load(struct kobject *kobj,
- struct attribute *attr, char *buf)
+static ssize_t show_hispeed_freq(struct kobject *kobj,
+ struct attribute *attr, char *buf)
{
- return sprintf(buf, "%lu\n", go_maxspeed_load);
+ return sprintf(buf, "%llu\n", hispeed_freq);
}
-static ssize_t store_go_maxspeed_load(struct kobject *kobj,
+static ssize_t store_hispeed_freq(struct kobject *kobj,
+ struct attribute *attr, const char *buf,
+ size_t count)
+{
+ int ret;
+ u64 val;
+
+ ret = strict_strtoull(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+ hispeed_freq = val;
+ return count;
+}
+
+static struct global_attr hispeed_freq_attr = __ATTR(hispeed_freq, 0644,
+ show_hispeed_freq, store_hispeed_freq);
+
+
+static ssize_t show_go_hispeed_load(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ return sprintf(buf, "%lu\n", go_hispeed_load);
+}
+
+static ssize_t store_go_hispeed_load(struct kobject *kobj,
struct attribute *attr, const char *buf, size_t count)
{
int ret;
@@ -408,12 +470,12 @@
ret = strict_strtoul(buf, 0, &val);
if (ret < 0)
return ret;
- go_maxspeed_load = val;
+ go_hispeed_load = val;
return count;
}
-static struct global_attr go_maxspeed_load_attr = __ATTR(go_maxspeed_load, 0644,
- show_go_maxspeed_load, store_go_maxspeed_load);
+static struct global_attr go_hispeed_load_attr = __ATTR(go_hispeed_load, 0644,
+ show_go_hispeed_load, store_go_hispeed_load);
static ssize_t show_min_sample_time(struct kobject *kobj,
struct attribute *attr, char *buf)
@@ -460,7 +522,8 @@
show_timer_rate, store_timer_rate);
static struct attribute *interactive_attributes[] = {
- &go_maxspeed_load_attr.attr,
+ &hispeed_freq_attr.attr,
+ &go_hispeed_load_attr.attr,
&min_sample_time_attr.attr,
&timer_rate_attr.attr,
NULL,
@@ -499,6 +562,9 @@
smp_wmb();
}
+ if (!hispeed_freq)
+ hispeed_freq = policy->max;
+
/*
* Do not register the idle hook and create sysfs
* entries if we have already done so.
@@ -576,7 +642,7 @@
struct cpufreq_interactive_cpuinfo *pcpu;
struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
- go_maxspeed_load = DEFAULT_GO_MAXSPEED_LOAD;
+ go_hispeed_load = DEFAULT_GO_HISPEED_LOAD;
min_sample_time = DEFAULT_MIN_SAMPLE_TIME;
timer_rate = DEFAULT_TIMER_RATE;
@@ -608,6 +674,7 @@
spin_lock_init(&up_cpumask_lock);
spin_lock_init(&down_cpumask_lock);
+ mutex_init(&set_speed_lock);
idle_notifier_register(&cpufreq_interactive_idle_nb);
diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c
index 7b0603e..cdc02ac 100644
--- a/drivers/cpufreq/pcc-cpufreq.c
+++ b/drivers/cpufreq/pcc-cpufreq.c
@@ -261,6 +261,9 @@
pr = per_cpu(processors, cpu);
pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu);
+ if (!pr)
+ return -ENODEV;
+
status = acpi_evaluate_object(pr->handle, "PCCP", NULL, &buffer);
if (ACPI_FAILURE(status))
return -ENODEV;
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index c47f3d0..bddc80f 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -125,14 +125,6 @@
#define LOAD_INT(x) ((x) >> FSHIFT)
#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
-static int get_loadavg(void)
-{
- unsigned long this = this_cpu_load();
-
-
- return LOAD_INT(this) * 10 + LOAD_FRAC(this) / 10;
-}
-
static inline int which_bucket(unsigned int duration)
{
int bucket = 0;
@@ -170,10 +162,6 @@
{
int mult = 1;
- /* for higher loadavg, we are more reluctant */
-
- mult += 2 * get_loadavg();
-
/* for IO wait tasks (per cpu!) we add 5x each */
mult += 10 * nr_iowait_cpu(smp_processor_id());
diff --git a/drivers/crypto/msm/qce40.c b/drivers/crypto/msm/qce40.c
index 893933b..d725851 100644
--- a/drivers/crypto/msm/qce40.c
+++ b/drivers/crypto/msm/qce40.c
@@ -58,8 +58,9 @@
void __iomem *iobase; /* Virtual io base of CE HW */
unsigned int phy_iobase; /* Physical io base of CE HW */
- struct clk *ce_core_clk; /* Handle to CE clk */
- struct clk *ce_clk; /* Handle to CE clk */
+ struct clk *ce_core_src_clk; /* Handle to CE src clk*/
+ struct clk *ce_core_clk; /* Handle to CE clk */
+ struct clk *ce_clk; /* Handle to CE clk */
qce_comp_func_ptr_t qce_cb; /* qce callback function pointer */
@@ -207,6 +208,7 @@
static int _init_ce_engine(struct qce_device *pce_dev)
{
+ int status;
/* Reset ce */
clk_reset(pce_dev->ce_core_clk, CLK_RESET_ASSERT);
clk_reset(pce_dev->ce_core_clk, CLK_RESET_DEASSERT);
@@ -223,6 +225,11 @@
config_ce_engine(pce_dev);
/*
+ * Clear ACCESS_VIOL bit in CRYPTO_STATUS REGISTER
+ */
+ status = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS_REG);
+ *((uint32_t *)(pce_dev->ce_dm.buffer.status)) = status & (~0x40000);
+ /*
* Ensure ce configuration is completed.
*/
mb();
@@ -473,12 +480,20 @@
}
}
- if (creq->mode == QCE_MODE_CCM)
+ switch (creq->mode) {
+ case QCE_MODE_CCM:
pce_dev->ce_dm.chan_ce_out_cmd->cmdptr =
- cmdptrlist->aead_ce_out;
- else
+ cmdptrlist->aead_ce_out;
+ break;
+ case QCE_MODE_ECB:
pce_dev->ce_dm.chan_ce_out_cmd->cmdptr =
- cmdptrlist->cipher_ce_out;
+ cmdptrlist->cipher_ce_out;
+ break;
+ default:
+ pce_dev->ce_dm.chan_ce_out_cmd->cmdptr =
+ cmdptrlist->cipher_ce_out_get_iv;
+ break;
+ }
return 0;
}
@@ -1329,21 +1344,6 @@
pscmd->src = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.encr_cntr_iv);
pscmd++;
- pce_dev->ce_dm.cmdlist.get_cipher_aes_iv = pscmd;
- pscmd->cmd = CMD_LC | CMD_SRC_SWAP_BYTES |
- CMD_SRC_SWAP_SHORTS | CMD_MODE_SINGLE;
- pscmd->src = (unsigned) (CRYPTO_CNTR0_IV0_REG + pce_dev->phy_iobase);
- pscmd->len = CRYPTO_REG_SIZE * 4;
- pscmd->dst = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.encr_cntr_iv);
- pscmd++;
-
- pce_dev->ce_dm.cmdlist.get_cipher_aes_xts_iv = pscmd;
- pscmd->cmd = CMD_LC | CMD_MODE_SINGLE;
- pscmd->src = (unsigned) (CRYPTO_CNTR0_IV0_REG + pce_dev->phy_iobase);
- pscmd->len = CRYPTO_REG_SIZE * 4;
- pscmd->dst = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.encr_cntr_iv);
- pscmd++;
-
pce_dev->ce_dm.cmdlist.set_cipher_des_iv = pscmd;
pscmd->cmd = CMD_LC | CMD_SRC_SWAP_BYTES |
CMD_SRC_SWAP_SHORTS | CMD_MODE_SINGLE;
@@ -1352,11 +1352,11 @@
pscmd->src = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.encr_cntr_iv);
pscmd++;
- pce_dev->ce_dm.cmdlist.get_cipher_des_iv = pscmd;
+ pce_dev->ce_dm.cmdlist.get_cipher_iv = pscmd;
pscmd->cmd = CMD_LC | CMD_SRC_SWAP_BYTES |
CMD_SRC_SWAP_SHORTS | CMD_MODE_SINGLE;
pscmd->src = (unsigned) (CRYPTO_CNTR0_IV0_REG + pce_dev->phy_iobase);
- pscmd->len = CRYPTO_REG_SIZE * 2;
+ pscmd->len = CRYPTO_REG_SIZE * 4;
pscmd->dst = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.encr_cntr_iv);
pscmd++;
@@ -1612,6 +1612,14 @@
pscmd->dst = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.status);
pscmd++;
+ /* CLEAR STATUS COMMAND LIST */
+ pce_dev->ce_dm.cmdlist.clear_status = pscmd;
+ pscmd->cmd = CMD_LC | CMD_MODE_SINGLE | CMD_OCU;
+ pscmd->dst = (unsigned) (CRYPTO_STATUS_REG + pce_dev->phy_iobase);
+ pscmd->len = CRYPTO_REG_SIZE;
+ pscmd->src = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.status);
+ pscmd++;
+
/* SET GO_PROC REGISTERS COMMAND LIST */
pce_dev->ce_dm.cmdlist.set_go_proc = pscmd;
pscmd->cmd = CMD_LC | CMD_MODE_SINGLE;
@@ -1692,8 +1700,7 @@
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_mask);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_go_proc);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in);
- *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_cipher_aes_iv);
+ *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->ce_data_in);
cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->cipher_aes_256_cbc_ctr = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
@@ -1705,8 +1712,7 @@
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_mask);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_go_proc);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in);
- *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_cipher_aes_iv);
+ *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->ce_data_in);
cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->cipher_aes_128_ecb = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
@@ -1742,8 +1748,7 @@
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_xts_du_size);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_mask);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_go_proc);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in);
- *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_cipher_aes_xts_iv);
+ *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->ce_data_in);
cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->cipher_aes_256_xts = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
@@ -1757,8 +1762,7 @@
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_xts_du_size);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_mask);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_go_proc);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in);
- *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_cipher_aes_xts_iv);
+ *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->ce_data_in);
cmd_ptr_vaddr = (uint32_t *)ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->cipher_des_cbc = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
@@ -1769,8 +1773,7 @@
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_des_iv);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_go_proc);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in);
- *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_cipher_des_iv);
+ *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->ce_data_in);
cmd_ptr_vaddr = (uint32_t *)ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->cipher_des_ecb = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
@@ -1791,8 +1794,7 @@
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_des_iv);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_go_proc);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in);
- *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_cipher_des_iv);
+ *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->ce_data_in);
cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->cipher_3des_ecb = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
@@ -1809,6 +1811,14 @@
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_out);
*cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_status_ocu);
+
+ cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
+ cmdptrlist->cipher_ce_out_get_iv = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
+
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_out);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_cipher_iv);
+ *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_status_ocu);
+
*pvaddr = (unsigned char *) cmd_ptr_vaddr;
return 0;
@@ -2007,6 +2017,7 @@
cmdptrlist->probe_ce_hw = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_hw_version);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->clear_status);
*cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_status_ocu);
*pvaddr = (unsigned char *) cmd_ptr_vaddr;
@@ -2391,6 +2402,8 @@
struct resource *resource;
struct clk *ce_core_clk;
struct clk *ce_clk;
+ struct clk *ce_core_src_clk;
+ int ret = 0;
pce_dev = kzalloc(sizeof(struct qce_device), GFP_KERNEL);
if (!pce_dev) {
@@ -2461,10 +2474,26 @@
goto err;
}
+ /* Get CE3 src core clk. */
+ ce_core_src_clk = clk_get(pce_dev->pdev, "ce3_core_src_clk");
+ if (!IS_ERR(ce_core_src_clk)) {
+ pce_dev->ce_core_src_clk = ce_core_src_clk;
+
+ /* Set the core src clk @100Mhz */
+ ret = clk_set_rate(pce_dev->ce_core_src_clk, 100000000);
+ if (ret) {
+ clk_put(pce_dev->ce_core_src_clk);
+ goto err;
+ }
+ } else
+ pce_dev->ce_core_src_clk = NULL;
+
/* Get CE core clk */
ce_core_clk = clk_get(pce_dev->pdev, "core_clk");
if (IS_ERR(ce_core_clk)) {
*rc = PTR_ERR(ce_core_clk);
+ if (pce_dev->ce_core_src_clk != NULL)
+ clk_put(pce_dev->ce_core_src_clk);
goto err;
}
pce_dev->ce_core_clk = ce_core_clk;
@@ -2472,6 +2501,8 @@
ce_clk = clk_get(pce_dev->pdev, "iface_clk");
if (IS_ERR(ce_clk)) {
*rc = PTR_ERR(ce_clk);
+ if (pce_dev->ce_core_src_clk != NULL)
+ clk_put(pce_dev->ce_core_src_clk);
clk_put(pce_dev->ce_core_clk);
goto err;
}
@@ -2480,6 +2511,8 @@
/* Enable CE core clk */
*rc = clk_enable(pce_dev->ce_core_clk);
if (*rc) {
+ if (pce_dev->ce_core_src_clk != NULL)
+ clk_put(pce_dev->ce_core_src_clk);
clk_put(pce_dev->ce_core_clk);
clk_put(pce_dev->ce_clk);
goto err;
@@ -2488,6 +2521,8 @@
*rc = clk_enable(pce_dev->ce_clk);
if (*rc) {
clk_disable(pce_dev->ce_core_clk);
+ if (pce_dev->ce_core_src_clk != NULL)
+ clk_put(pce_dev->ce_core_src_clk);
clk_put(pce_dev->ce_core_clk);
clk_put(pce_dev->ce_clk);
goto err;
@@ -2539,6 +2574,9 @@
clk_disable(pce_dev->ce_clk);
clk_disable(pce_dev->ce_core_clk);
+ if (pce_dev->ce_core_src_clk != NULL)
+ clk_put(pce_dev->ce_core_src_clk);
+
clk_put(pce_dev->ce_clk);
clk_put(pce_dev->ce_core_clk);
@@ -2571,4 +2609,4 @@
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Mona Hossain <mhossain@codeaurora.org>");
MODULE_DESCRIPTION("Crypto Engine driver");
-MODULE_VERSION("2.13");
+MODULE_VERSION("2.14");
diff --git a/drivers/crypto/msm/qce40.h b/drivers/crypto/msm/qce40.h
index c9fbb17..809ba7f 100644
--- a/drivers/crypto/msm/qce40.h
+++ b/drivers/crypto/msm/qce40.h
@@ -117,6 +117,7 @@
/* CE Command lists */
struct ce_cmdlists {
dmov_s *get_hw_version;
+ dmov_s *clear_status;
dmov_s *get_status_ocu;
dmov_s *set_cipher_cfg;
@@ -132,10 +133,8 @@
dmov_s *set_cipher_aes_iv;
dmov_s *set_cipher_aes_xts_iv;
- dmov_s *get_cipher_aes_iv;
- dmov_s *get_cipher_aes_xts_iv;
dmov_s *set_cipher_des_iv;
- dmov_s *get_cipher_des_iv;
+ dmov_s *get_cipher_iv;
dmov_s *set_cipher_mask;
@@ -195,6 +194,7 @@
uint32_t aead_aes_256_ccm;
uint32_t cipher_ce_out;
+ uint32_t cipher_ce_out_get_iv;
uint32_t aead_ce_out;
};
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
index 04f1e7c..f6cf448 100644
--- a/drivers/edac/i7core_edac.c
+++ b/drivers/edac/i7core_edac.c
@@ -1670,7 +1670,7 @@
char *type, *optype, *err, *msg;
unsigned long error = m->status & 0x1ff0000l;
u32 optypenum = (m->status >> 4) & 0x07;
- u32 core_err_cnt = (m->status >> 38) && 0x7fff;
+ u32 core_err_cnt = (m->status >> 38) & 0x7fff;
u32 dimm = (m->misc >> 16) & 0x3;
u32 channel = (m->misc >> 18) & 0x3;
u32 syndrome = m->misc >> 32;
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index ebb8973..ee76c8e 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -291,6 +291,9 @@
{PCI_VENDOR_ID_NEC, PCI_ANY_ID, PCI_ANY_ID,
QUIRK_CYCLE_TIMER},
+ {PCI_VENDOR_ID_O2, PCI_ANY_ID, PCI_ANY_ID,
+ QUIRK_NO_MSI},
+
{PCI_VENDOR_ID_RICOH, PCI_ANY_ID, PCI_ANY_ID,
QUIRK_CYCLE_TIMER},
diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c
index 41841a3..17cef86 100644
--- a/drivers/firewire/sbp2.c
+++ b/drivers/firewire/sbp2.c
@@ -1198,6 +1198,10 @@
{
struct fw_unit *unit = fw_unit(dev);
struct sbp2_target *tgt = dev_get_drvdata(&unit->device);
+ struct sbp2_logical_unit *lu;
+
+ list_for_each_entry(lu, &tgt->lu_list, link)
+ cancel_delayed_work_sync(&lu->work);
sbp2_target_put(tgt);
return 0;
diff --git a/drivers/gpio/pm8xxx-gpio.c b/drivers/gpio/pm8xxx-gpio.c
index 377510f..53305e3 100644
--- a/drivers/gpio/pm8xxx-gpio.c
+++ b/drivers/gpio/pm8xxx-gpio.c
@@ -432,7 +432,7 @@
return rc;
}
-EXPORT_SYMBOL_GPL(pm8xxx_gpio_config);
+EXPORT_SYMBOL(pm8xxx_gpio_config);
static struct platform_driver pm_gpio_driver = {
.probe = pm_gpio_probe,
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 0929219..1bbb85b 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -127,6 +127,23 @@
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
};
+ /*
+ * Sanity check the header of the base EDID block. Return 8 if the header
+ * is perfect, down to 0 if it's totally wrong.
+ */
+int drm_edid_header_is_valid(const u8 *raw_edid)
+{
+ int i, score = 0;
+
+ for (i = 0; i < sizeof(edid_header); i++)
+ if (raw_edid[i] == edid_header[i])
+ score++;
+
+ return score;
+}
+EXPORT_SYMBOL(drm_edid_header_is_valid);
+
+
/*
* Sanity check the EDID block (base or extension). Return 0 if the block
* doesn't check out, or 1 if it's valid.
@@ -139,12 +156,7 @@
struct edid *edid = (struct edid *)raw_edid;
if (raw_edid[0] == 0x00) {
- int score = 0;
-
- for (i = 0; i < sizeof(edid_header); i++)
- if (raw_edid[i] == edid_header[i])
- score++;
-
+ int score = drm_edid_header_is_valid(raw_edid);
if (score == 8) ;
else if (score >= 6) {
DRM_DEBUG("Fixing EDID header, your hardware may be failing\n");
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 296fbd6..7eef6e1 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -61,7 +61,6 @@
static int i915_init_phys_hws(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- struct intel_ring_buffer *ring = LP_RING(dev_priv);
/* Program Hardware Status Page */
dev_priv->status_page_dmah =
@@ -71,10 +70,9 @@
DRM_ERROR("Can not allocate hardware status page\n");
return -ENOMEM;
}
- ring->status_page.page_addr =
- (void __force __iomem *)dev_priv->status_page_dmah->vaddr;
- memset_io(ring->status_page.page_addr, 0, PAGE_SIZE);
+ memset_io((void __force __iomem *)dev_priv->status_page_dmah->vaddr,
+ 0, PAGE_SIZE);
i915_write_hws_pga(dev);
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 3b03f85..9b1d669 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -306,12 +306,15 @@
struct drm_mode_config *mode_config = &dev->mode_config;
struct intel_encoder *encoder;
+ mutex_lock(&mode_config->mutex);
DRM_DEBUG_KMS("running encoder hotplug functions\n");
list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
if (encoder->hot_plug)
encoder->hot_plug(encoder);
+ mutex_unlock(&mode_config->mutex);
+
/* Just fire off a uevent and let userspace tell us what to do */
drm_helper_hpd_irq_event(dev);
}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 0f1c799..5609c06 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2699,14 +2699,18 @@
I915_WRITE(PF_WIN_SZ(pipe), dev_priv->pch_pf_size);
}
+ /*
+ * On ILK+ LUT must be loaded before the pipe is running but with
+ * clocks enabled
+ */
+ intel_crtc_load_lut(crtc);
+
intel_enable_pipe(dev_priv, pipe, is_pch_port);
intel_enable_plane(dev_priv, plane, pipe);
if (is_pch_port)
ironlake_pch_enable(crtc);
- intel_crtc_load_lut(crtc);
-
mutex_lock(&dev->struct_mutex);
intel_update_fbc(dev);
mutex_unlock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index a06ff07..05f500c 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -83,11 +83,15 @@
u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
if (scaled_width > scaled_height) { /* pillar */
width = scaled_height / mode->vdisplay;
+ if (width & 1)
+ width++;
x = (adjusted_mode->hdisplay - width + 1) / 2;
y = 0;
height = adjusted_mode->vdisplay;
} else if (scaled_width < scaled_height) { /* letter */
height = scaled_width / mode->hdisplay;
+ if (height & 1)
+ height++;
y = (adjusted_mode->vdisplay - height + 1) / 2;
x = 0;
width = adjusted_mode->hdisplay;
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 95c4b14..1f61fc7 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -1319,6 +1319,9 @@
ring->get_seqno = pc_render_get_seqno;
}
+ if (!I915_NEED_GFX_HWS(dev))
+ ring->status_page.page_addr = dev_priv->status_page_dmah->vaddr;
+
ring->dev = dev;
INIT_LIST_HEAD(&ring->active_list);
INIT_LIST_HEAD(&ring->request_list);
diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
index 82fad91..ca6028f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
@@ -37,8 +37,11 @@
return -ENOMEM;
nvbe->ttm_alloced = kmalloc(sizeof(bool) * num_pages, GFP_KERNEL);
- if (!nvbe->ttm_alloced)
+ if (!nvbe->ttm_alloced) {
+ kfree(nvbe->pages);
+ nvbe->pages = NULL;
return -ENOMEM;
+ }
nvbe->nr_pages = 0;
while (num_pages--) {
diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c
index ebdb0fd..9a0aee2 100644
--- a/drivers/gpu/drm/radeon/atom.c
+++ b/drivers/gpu/drm/radeon/atom.c
@@ -277,7 +277,12 @@
case ATOM_ARG_FB:
idx = U8(*ptr);
(*ptr)++;
- val = gctx->scratch[((gctx->fb_base + idx) / 4)];
+ if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) {
+ DRM_ERROR("ATOM: fb read beyond scratch region: %d vs. %d\n",
+ gctx->fb_base + (idx * 4), gctx->scratch_size_bytes);
+ val = 0;
+ } else
+ val = gctx->scratch[(gctx->fb_base / 4) + idx];
if (print)
DEBUG("FB[0x%02X]", idx);
break;
@@ -531,7 +536,11 @@
case ATOM_ARG_FB:
idx = U8(*ptr);
(*ptr)++;
- gctx->scratch[((gctx->fb_base + idx) / 4)] = val;
+ if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) {
+ DRM_ERROR("ATOM: fb write beyond scratch region: %d vs. %d\n",
+ gctx->fb_base + (idx * 4), gctx->scratch_size_bytes);
+ } else
+ gctx->scratch[(gctx->fb_base / 4) + idx] = val;
DEBUG("FB[0x%02X]", idx);
break;
case ATOM_ARG_PLL:
@@ -1367,11 +1376,13 @@
usage_bytes = firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb * 1024;
}
+ ctx->scratch_size_bytes = 0;
if (usage_bytes == 0)
usage_bytes = 20 * 1024;
/* allocate some scratch memory */
ctx->scratch = kzalloc(usage_bytes, GFP_KERNEL);
if (!ctx->scratch)
return -ENOMEM;
+ ctx->scratch_size_bytes = usage_bytes;
return 0;
}
diff --git a/drivers/gpu/drm/radeon/atom.h b/drivers/gpu/drm/radeon/atom.h
index a589a55..93cfe20 100644
--- a/drivers/gpu/drm/radeon/atom.h
+++ b/drivers/gpu/drm/radeon/atom.h
@@ -137,6 +137,7 @@
int cs_equal, cs_above;
int io_mode;
uint32_t *scratch;
+ int scratch_size_bytes;
};
extern int atom_debug;
diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c
index 645b84b..79e8ebc 100644
--- a/drivers/gpu/drm/radeon/atombios_dp.c
+++ b/drivers/gpu/drm/radeon/atombios_dp.c
@@ -115,6 +115,7 @@
u8 msg[20];
int msg_bytes = send_bytes + 4;
u8 ack;
+ unsigned retry;
if (send_bytes > 16)
return -1;
@@ -125,20 +126,22 @@
msg[3] = (msg_bytes << 4) | (send_bytes - 1);
memcpy(&msg[4], send, send_bytes);
- while (1) {
+ for (retry = 0; retry < 4; retry++) {
ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus,
msg, msg_bytes, NULL, 0, delay, &ack);
- if (ret < 0)
+ if (ret == -EBUSY)
+ continue;
+ else if (ret < 0)
return ret;
if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
- break;
+ return send_bytes;
else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
udelay(400);
else
return -EIO;
}
- return send_bytes;
+ return -EIO;
}
static int radeon_dp_aux_native_read(struct radeon_connector *radeon_connector,
@@ -149,26 +152,31 @@
int msg_bytes = 4;
u8 ack;
int ret;
+ unsigned retry;
msg[0] = address;
msg[1] = address >> 8;
msg[2] = AUX_NATIVE_READ << 4;
msg[3] = (msg_bytes << 4) | (recv_bytes - 1);
- while (1) {
+ for (retry = 0; retry < 4; retry++) {
ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus,
msg, msg_bytes, recv, recv_bytes, delay, &ack);
- if (ret == 0)
- return -EPROTO;
- if (ret < 0)
+ if (ret == -EBUSY)
+ continue;
+ else if (ret < 0)
return ret;
if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
return ret;
else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
udelay(400);
+ else if (ret == 0)
+ return -EPROTO;
else
return -EIO;
}
+
+ return -EIO;
}
static void radeon_write_dpcd_reg(struct radeon_connector *radeon_connector,
@@ -232,7 +240,9 @@
for (retry = 0; retry < 4; retry++) {
ret = radeon_process_aux_ch(auxch,
msg, msg_bytes, reply, reply_bytes, 0, &ack);
- if (ret < 0) {
+ if (ret == -EBUSY)
+ continue;
+ else if (ret < 0) {
DRM_DEBUG_KMS("aux_ch failed %d\n", ret);
return ret;
}
@@ -613,6 +623,18 @@
return true;
}
+bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector)
+{
+ u8 link_status[DP_LINK_STATUS_SIZE];
+ struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
+
+ if (!radeon_dp_get_link_status(radeon_connector, link_status))
+ return false;
+ if (dp_channel_eq_ok(link_status, dig->dp_lane_count))
+ return false;
+ return true;
+}
+
struct radeon_dp_link_train_info {
struct radeon_device *rdev;
struct drm_encoder *encoder;
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 15bd047..ea7a24e 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -41,6 +41,31 @@
void evergreen_fini(struct radeon_device *rdev);
static void evergreen_pcie_gen2_enable(struct radeon_device *rdev);
+void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev)
+{
+ u16 ctl, v;
+ int cap, err;
+
+ cap = pci_pcie_cap(rdev->pdev);
+ if (!cap)
+ return;
+
+ err = pci_read_config_word(rdev->pdev, cap + PCI_EXP_DEVCTL, &ctl);
+ if (err)
+ return;
+
+ v = (ctl & PCI_EXP_DEVCTL_READRQ) >> 12;
+
+ /* if bios or OS sets MAX_READ_REQUEST_SIZE to an invalid value, fix it
+ * to avoid hangs or perfomance issues
+ */
+ if ((v == 0) || (v == 6) || (v == 7)) {
+ ctl &= ~PCI_EXP_DEVCTL_READRQ;
+ ctl |= (2 << 12);
+ pci_write_config_word(rdev->pdev, cap + PCI_EXP_DEVCTL, ctl);
+ }
+}
+
void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc)
{
/* enable the pflip int */
@@ -1357,6 +1382,7 @@
SOFT_RESET_PA |
SOFT_RESET_SH |
SOFT_RESET_VGT |
+ SOFT_RESET_SPI |
SOFT_RESET_SX));
RREG32(GRBM_SOFT_RESET);
mdelay(15);
@@ -1378,7 +1404,8 @@
/* Initialize the ring buffer's read and write pointers */
WREG32(CP_RB_CNTL, tmp | RB_RPTR_WR_ENA);
WREG32(CP_RB_RPTR_WR, 0);
- WREG32(CP_RB_WPTR, 0);
+ rdev->cp.wptr = 0;
+ WREG32(CP_RB_WPTR, rdev->cp.wptr);
/* set the wb address wether it's enabled or not */
WREG32(CP_RB_RPTR_ADDR,
@@ -1403,7 +1430,6 @@
WREG32(CP_DEBUG, (1 << 27) | (1 << 28));
rdev->cp.rptr = RREG32(CP_RB_RPTR);
- rdev->cp.wptr = RREG32(CP_RB_WPTR);
evergreen_cp_start(rdev);
rdev->cp.ready = true;
@@ -1567,48 +1593,6 @@
return backend_map;
}
-static void evergreen_program_channel_remap(struct radeon_device *rdev)
-{
- u32 tcp_chan_steer_lo, tcp_chan_steer_hi, mc_shared_chremap, tmp;
-
- tmp = RREG32(MC_SHARED_CHMAP);
- switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
- case 0:
- case 1:
- case 2:
- case 3:
- default:
- /* default mapping */
- mc_shared_chremap = 0x00fac688;
- break;
- }
-
- switch (rdev->family) {
- case CHIP_HEMLOCK:
- case CHIP_CYPRESS:
- case CHIP_BARTS:
- tcp_chan_steer_lo = 0x54763210;
- tcp_chan_steer_hi = 0x0000ba98;
- break;
- case CHIP_JUNIPER:
- case CHIP_REDWOOD:
- case CHIP_CEDAR:
- case CHIP_PALM:
- case CHIP_SUMO:
- case CHIP_SUMO2:
- case CHIP_TURKS:
- case CHIP_CAICOS:
- default:
- tcp_chan_steer_lo = 0x76543210;
- tcp_chan_steer_hi = 0x0000ba98;
- break;
- }
-
- WREG32(TCP_CHAN_STEER_LO, tcp_chan_steer_lo);
- WREG32(TCP_CHAN_STEER_HI, tcp_chan_steer_hi);
- WREG32(MC_SHARED_CHREMAP, mc_shared_chremap);
-}
-
static void evergreen_gpu_init(struct radeon_device *rdev)
{
u32 cc_rb_backend_disable = 0;
@@ -1865,6 +1849,8 @@
WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff));
+ evergreen_fix_pci_max_read_req_size(rdev);
+
cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG) & ~2;
cc_gc_shader_pipe_config |=
@@ -2052,8 +2038,6 @@
WREG32(DMIF_ADDR_CONFIG, gb_addr_config);
WREG32(HDP_ADDR_CONFIG, gb_addr_config);
- evergreen_program_channel_remap(rdev);
-
num_shader_engines = ((RREG32(GB_ADDR_CONFIG) & NUM_SHADER_ENGINES(3)) >> 12) + 1;
grbm_gfx_index = INSTANCE_BROADCAST_WRITES;
@@ -3142,21 +3126,23 @@
}
int evergreen_copy_blit(struct radeon_device *rdev,
- uint64_t src_offset, uint64_t dst_offset,
- unsigned num_pages, struct radeon_fence *fence)
+ uint64_t src_offset,
+ uint64_t dst_offset,
+ unsigned num_gpu_pages,
+ struct radeon_fence *fence)
{
int r;
mutex_lock(&rdev->r600_blit.mutex);
rdev->r600_blit.vb_ib = NULL;
- r = evergreen_blit_prepare_copy(rdev, num_pages * RADEON_GPU_PAGE_SIZE);
+ r = evergreen_blit_prepare_copy(rdev, num_gpu_pages * RADEON_GPU_PAGE_SIZE);
if (r) {
if (rdev->r600_blit.vb_ib)
radeon_ib_free(rdev, &rdev->r600_blit.vb_ib);
mutex_unlock(&rdev->r600_blit.mutex);
return r;
}
- evergreen_kms_blit_copy(rdev, src_offset, dst_offset, num_pages * RADEON_GPU_PAGE_SIZE);
+ evergreen_kms_blit_copy(rdev, src_offset, dst_offset, num_gpu_pages * RADEON_GPU_PAGE_SIZE);
evergreen_blit_done_copy(rdev, fence);
mutex_unlock(&rdev->r600_blit.mutex);
return 0;
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index 559dbd4..0c460c4 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -39,6 +39,7 @@
extern void evergreen_mc_program(struct radeon_device *rdev);
extern void evergreen_irq_suspend(struct radeon_device *rdev);
extern int evergreen_mc_init(struct radeon_device *rdev);
+extern void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev);
#define EVERGREEN_PFP_UCODE_SIZE 1120
#define EVERGREEN_PM4_UCODE_SIZE 1376
@@ -568,36 +569,6 @@
return backend_map;
}
-static void cayman_program_channel_remap(struct radeon_device *rdev)
-{
- u32 tcp_chan_steer_lo, tcp_chan_steer_hi, mc_shared_chremap, tmp;
-
- tmp = RREG32(MC_SHARED_CHMAP);
- switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
- case 0:
- case 1:
- case 2:
- case 3:
- default:
- /* default mapping */
- mc_shared_chremap = 0x00fac688;
- break;
- }
-
- switch (rdev->family) {
- case CHIP_CAYMAN:
- default:
- //tcp_chan_steer_lo = 0x54763210
- tcp_chan_steer_lo = 0x76543210;
- tcp_chan_steer_hi = 0x0000ba98;
- break;
- }
-
- WREG32(TCP_CHAN_STEER_LO, tcp_chan_steer_lo);
- WREG32(TCP_CHAN_STEER_HI, tcp_chan_steer_hi);
- WREG32(MC_SHARED_CHREMAP, mc_shared_chremap);
-}
-
static u32 cayman_get_disable_mask_per_asic(struct radeon_device *rdev,
u32 disable_mask_per_se,
u32 max_disable_mask_per_se,
@@ -669,6 +640,8 @@
WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff));
+ evergreen_fix_pci_max_read_req_size(rdev);
+
mc_shared_chmap = RREG32(MC_SHARED_CHMAP);
mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG);
@@ -838,8 +811,6 @@
WREG32(DMIF_ADDR_CONFIG, gb_addr_config);
WREG32(HDP_ADDR_CONFIG, gb_addr_config);
- cayman_program_channel_remap(rdev);
-
/* primary versions */
WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable);
WREG32(CC_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable);
@@ -1158,6 +1129,7 @@
SOFT_RESET_PA |
SOFT_RESET_SH |
SOFT_RESET_VGT |
+ SOFT_RESET_SPI |
SOFT_RESET_SX));
RREG32(GRBM_SOFT_RESET);
mdelay(15);
@@ -1182,7 +1154,8 @@
/* Initialize the ring buffer's read and write pointers */
WREG32(CP_RB0_CNTL, tmp | RB_RPTR_WR_ENA);
- WREG32(CP_RB0_WPTR, 0);
+ rdev->cp.wptr = 0;
+ WREG32(CP_RB0_WPTR, rdev->cp.wptr);
/* set the wb address wether it's enabled or not */
WREG32(CP_RB0_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC);
@@ -1202,7 +1175,6 @@
WREG32(CP_RB0_BASE, rdev->cp.gpu_addr >> 8);
rdev->cp.rptr = RREG32(CP_RB0_RPTR);
- rdev->cp.wptr = RREG32(CP_RB0_WPTR);
/* ring1 - compute only */
/* Set ring buffer size */
@@ -1215,7 +1187,8 @@
/* Initialize the ring buffer's read and write pointers */
WREG32(CP_RB1_CNTL, tmp | RB_RPTR_WR_ENA);
- WREG32(CP_RB1_WPTR, 0);
+ rdev->cp1.wptr = 0;
+ WREG32(CP_RB1_WPTR, rdev->cp1.wptr);
/* set the wb address wether it's enabled or not */
WREG32(CP_RB1_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP1_RPTR_OFFSET) & 0xFFFFFFFC);
@@ -1227,7 +1200,6 @@
WREG32(CP_RB1_BASE, rdev->cp1.gpu_addr >> 8);
rdev->cp1.rptr = RREG32(CP_RB1_RPTR);
- rdev->cp1.wptr = RREG32(CP_RB1_WPTR);
/* ring2 - compute only */
/* Set ring buffer size */
@@ -1240,7 +1212,8 @@
/* Initialize the ring buffer's read and write pointers */
WREG32(CP_RB2_CNTL, tmp | RB_RPTR_WR_ENA);
- WREG32(CP_RB2_WPTR, 0);
+ rdev->cp2.wptr = 0;
+ WREG32(CP_RB2_WPTR, rdev->cp2.wptr);
/* set the wb address wether it's enabled or not */
WREG32(CP_RB2_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP2_RPTR_OFFSET) & 0xFFFFFFFC);
@@ -1252,7 +1225,6 @@
WREG32(CP_RB2_BASE, rdev->cp2.gpu_addr >> 8);
rdev->cp2.rptr = RREG32(CP_RB2_RPTR);
- rdev->cp2.wptr = RREG32(CP_RB2_WPTR);
/* start the rings */
cayman_cp_start(rdev);
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index f2204cb..7fcdbbb 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -721,11 +721,11 @@
int r100_copy_blit(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
- unsigned num_pages,
+ unsigned num_gpu_pages,
struct radeon_fence *fence)
{
uint32_t cur_pages;
- uint32_t stride_bytes = PAGE_SIZE;
+ uint32_t stride_bytes = RADEON_GPU_PAGE_SIZE;
uint32_t pitch;
uint32_t stride_pixels;
unsigned ndw;
@@ -737,7 +737,7 @@
/* radeon pitch is /64 */
pitch = stride_bytes / 64;
stride_pixels = stride_bytes / 4;
- num_loops = DIV_ROUND_UP(num_pages, 8191);
+ num_loops = DIV_ROUND_UP(num_gpu_pages, 8191);
/* Ask for enough room for blit + flush + fence */
ndw = 64 + (10 * num_loops);
@@ -746,12 +746,12 @@
DRM_ERROR("radeon: moving bo (%d) asking for %u dw.\n", r, ndw);
return -EINVAL;
}
- while (num_pages > 0) {
- cur_pages = num_pages;
+ while (num_gpu_pages > 0) {
+ cur_pages = num_gpu_pages;
if (cur_pages > 8191) {
cur_pages = 8191;
}
- num_pages -= cur_pages;
+ num_gpu_pages -= cur_pages;
/* pages are in Y direction - height
page width in X direction - width */
@@ -773,8 +773,8 @@
radeon_ring_write(rdev, (0x1fff) | (0x1fff << 16));
radeon_ring_write(rdev, 0);
radeon_ring_write(rdev, (0x1fff) | (0x1fff << 16));
- radeon_ring_write(rdev, num_pages);
- radeon_ring_write(rdev, num_pages);
+ radeon_ring_write(rdev, num_gpu_pages);
+ radeon_ring_write(rdev, num_gpu_pages);
radeon_ring_write(rdev, cur_pages | (stride_pixels << 16));
}
radeon_ring_write(rdev, PACKET0(RADEON_DSTCACHE_CTLSTAT, 0));
@@ -990,7 +990,8 @@
/* Force read & write ptr to 0 */
WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA | RADEON_RB_NO_UPDATE);
WREG32(RADEON_CP_RB_RPTR_WR, 0);
- WREG32(RADEON_CP_RB_WPTR, 0);
+ rdev->cp.wptr = 0;
+ WREG32(RADEON_CP_RB_WPTR, rdev->cp.wptr);
/* set the wb address whether it's enabled or not */
WREG32(R_00070C_CP_RB_RPTR_ADDR,
@@ -1007,9 +1008,6 @@
WREG32(RADEON_CP_RB_CNTL, tmp);
udelay(10);
rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR);
- rdev->cp.wptr = RREG32(RADEON_CP_RB_WPTR);
- /* protect against crazy HW on resume */
- rdev->cp.wptr &= rdev->cp.ptr_mask;
/* Set cp mode to bus mastering & enable cp*/
WREG32(RADEON_CP_CSQ_MODE,
REG_SET(RADEON_INDIRECT2_START, indirect2_start) |
diff --git a/drivers/gpu/drm/radeon/r200.c b/drivers/gpu/drm/radeon/r200.c
index f240583..a1f3ba0 100644
--- a/drivers/gpu/drm/radeon/r200.c
+++ b/drivers/gpu/drm/radeon/r200.c
@@ -84,7 +84,7 @@
int r200_copy_dma(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
- unsigned num_pages,
+ unsigned num_gpu_pages,
struct radeon_fence *fence)
{
uint32_t size;
@@ -93,7 +93,7 @@
int r = 0;
/* radeon pitch is /64 */
- size = num_pages << PAGE_SHIFT;
+ size = num_gpu_pages << RADEON_GPU_PAGE_SHIFT;
num_loops = DIV_ROUND_UP(size, 0x1FFFFF);
r = radeon_ring_lock(rdev, num_loops * 4 + 64);
if (r) {
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index bc54b26..1dea9d6 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -2208,7 +2208,8 @@
/* Initialize the ring buffer's read and write pointers */
WREG32(CP_RB_CNTL, tmp | RB_RPTR_WR_ENA);
WREG32(CP_RB_RPTR_WR, 0);
- WREG32(CP_RB_WPTR, 0);
+ rdev->cp.wptr = 0;
+ WREG32(CP_RB_WPTR, rdev->cp.wptr);
/* set the wb address whether it's enabled or not */
WREG32(CP_RB_RPTR_ADDR,
@@ -2233,7 +2234,6 @@
WREG32(CP_DEBUG, (1 << 27) | (1 << 28));
rdev->cp.rptr = RREG32(CP_RB_RPTR);
- rdev->cp.wptr = RREG32(CP_RB_WPTR);
r600_cp_start(rdev);
rdev->cp.ready = true;
@@ -2355,21 +2355,23 @@
}
int r600_copy_blit(struct radeon_device *rdev,
- uint64_t src_offset, uint64_t dst_offset,
- unsigned num_pages, struct radeon_fence *fence)
+ uint64_t src_offset,
+ uint64_t dst_offset,
+ unsigned num_gpu_pages,
+ struct radeon_fence *fence)
{
int r;
mutex_lock(&rdev->r600_blit.mutex);
rdev->r600_blit.vb_ib = NULL;
- r = r600_blit_prepare_copy(rdev, num_pages * RADEON_GPU_PAGE_SIZE);
+ r = r600_blit_prepare_copy(rdev, num_gpu_pages * RADEON_GPU_PAGE_SIZE);
if (r) {
if (rdev->r600_blit.vb_ib)
radeon_ib_free(rdev, &rdev->r600_blit.vb_ib);
mutex_unlock(&rdev->r600_blit.mutex);
return r;
}
- r600_kms_blit_copy(rdev, src_offset, dst_offset, num_pages * RADEON_GPU_PAGE_SIZE);
+ r600_kms_blit_copy(rdev, src_offset, dst_offset, num_gpu_pages * RADEON_GPU_PAGE_SIZE);
r600_blit_done_copy(rdev, fence);
mutex_unlock(&rdev->r600_blit.mutex);
return 0;
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index ef0e0e0..0bb4ddf 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -322,6 +322,7 @@
#define RADEON_GPU_PAGE_SIZE 4096
#define RADEON_GPU_PAGE_MASK (RADEON_GPU_PAGE_SIZE - 1)
+#define RADEON_GPU_PAGE_SHIFT 12
struct radeon_gart {
dma_addr_t table_addr;
@@ -914,17 +915,17 @@
int (*copy_blit)(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
- unsigned num_pages,
+ unsigned num_gpu_pages,
struct radeon_fence *fence);
int (*copy_dma)(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
- unsigned num_pages,
+ unsigned num_gpu_pages,
struct radeon_fence *fence);
int (*copy)(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
- unsigned num_pages,
+ unsigned num_gpu_pages,
struct radeon_fence *fence);
uint32_t (*get_engine_clock)(struct radeon_device *rdev);
void (*set_engine_clock)(struct radeon_device *rdev, uint32_t eng_clock);
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 3d7a0d7..3dedaa0 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -75,7 +75,7 @@
int r100_copy_blit(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
- unsigned num_pages,
+ unsigned num_gpu_pages,
struct radeon_fence *fence);
int r100_set_surface_reg(struct radeon_device *rdev, int reg,
uint32_t tiling_flags, uint32_t pitch,
@@ -143,7 +143,7 @@
extern int r200_copy_dma(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
- unsigned num_pages,
+ unsigned num_gpu_pages,
struct radeon_fence *fence);
void r200_set_safe_registers(struct radeon_device *rdev);
@@ -311,7 +311,7 @@
int r600_ring_test(struct radeon_device *rdev);
int r600_copy_blit(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
- unsigned num_pages, struct radeon_fence *fence);
+ unsigned num_gpu_pages, struct radeon_fence *fence);
void r600_hpd_init(struct radeon_device *rdev);
void r600_hpd_fini(struct radeon_device *rdev);
bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd);
@@ -403,7 +403,7 @@
void evergreen_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
int evergreen_copy_blit(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
- unsigned num_pages, struct radeon_fence *fence);
+ unsigned num_gpu_pages, struct radeon_fence *fence);
void evergreen_hpd_init(struct radeon_device *rdev);
void evergreen_hpd_fini(struct radeon_device *rdev);
bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd);
diff --git a/drivers/gpu/drm/radeon/radeon_clocks.c b/drivers/gpu/drm/radeon/radeon_clocks.c
index 2d48e7a..b956cf1 100644
--- a/drivers/gpu/drm/radeon/radeon_clocks.c
+++ b/drivers/gpu/drm/radeon/radeon_clocks.c
@@ -219,6 +219,9 @@
} else {
DRM_INFO("Using generic clock info\n");
+ /* may need to be per card */
+ rdev->clock.max_pixel_clock = 35000;
+
if (rdev->flags & RADEON_IS_IGP) {
p1pll->reference_freq = 1432;
p2pll->reference_freq = 1432;
diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c
index a74217c..cd3c86c 100644
--- a/drivers/gpu/drm/radeon/radeon_combios.c
+++ b/drivers/gpu/drm/radeon/radeon_combios.c
@@ -3279,6 +3279,14 @@
rdev->pdev->subsystem_device == 0x30a4)
return;
+ /* quirk for rs4xx Compaq Presario V5245EU laptop to make it resume
+ * - it hangs on resume inside the dynclk 1 table.
+ */
+ if (rdev->family == CHIP_RS480 &&
+ rdev->pdev->subsystem_vendor == 0x103c &&
+ rdev->pdev->subsystem_device == 0x30ae)
+ return;
+
/* DYN CLK 1 */
table = combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE);
if (table)
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 9792d4f..05b8b2c 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -60,18 +60,20 @@
radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
- /* powering up/down the eDP panel generates hpd events which
- * can interfere with modesetting.
- */
- if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
+ /* if the connector is already off, don't turn it back on */
+ if (connector->dpms != DRM_MODE_DPMS_ON)
return;
- /* pre-r600 did not always have the hpd pins mapped accurately to connectors */
- if (rdev->family >= CHIP_R600) {
- if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
- drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
- else
+ /* just deal with DP (not eDP) here. */
+ if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
+ int saved_dpms = connector->dpms;
+
+ /* Only turn off the display it it's physically disconnected */
+ if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+ else if (radeon_dp_needs_link_train(radeon_connector))
+ drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
+ connector->dpms = saved_dpms;
}
}
@@ -430,6 +432,55 @@
return 0;
}
+/*
+ * Some integrated ATI Radeon chipset implementations (e. g.
+ * Asus M2A-VM HDMI) may indicate the availability of a DDC,
+ * even when there's no monitor connected. For these connectors
+ * following DDC probe extension will be applied: check also for the
+ * availability of EDID with at least a correct EDID header. Only then,
+ * DDC is assumed to be available. This prevents drm_get_edid() and
+ * drm_edid_block_valid() from periodically dumping data and kernel
+ * errors into the logs and onto the terminal.
+ */
+static bool radeon_connector_needs_extended_probe(struct radeon_device *dev,
+ uint32_t supported_device,
+ int connector_type)
+{
+ /* Asus M2A-VM HDMI board sends data to i2c bus even,
+ * if HDMI add-on card is not plugged in or HDMI is disabled in
+ * BIOS. Valid DDC can only be assumed, if also a valid EDID header
+ * can be retrieved via i2c bus during DDC probe */
+ if ((dev->pdev->device == 0x791e) &&
+ (dev->pdev->subsystem_vendor == 0x1043) &&
+ (dev->pdev->subsystem_device == 0x826d)) {
+ if ((connector_type == DRM_MODE_CONNECTOR_HDMIA) &&
+ (supported_device == ATOM_DEVICE_DFP2_SUPPORT))
+ return true;
+ }
+ /* ECS A740GM-M with ATI RADEON 2100 sends data to i2c bus
+ * for a DVI connector that is not implemented */
+ if ((dev->pdev->device == 0x796e) &&
+ (dev->pdev->subsystem_vendor == 0x1019) &&
+ (dev->pdev->subsystem_device == 0x2615)) {
+ if ((connector_type == DRM_MODE_CONNECTOR_DVID) &&
+ (supported_device == ATOM_DEVICE_DFP2_SUPPORT))
+ return true;
+ }
+ /* TOSHIBA Satellite L300D with ATI Mobility Radeon x1100
+ * (RS690M) sends data to i2c bus for a HDMI connector that
+ * is not implemented */
+ if ((dev->pdev->device == 0x791f) &&
+ (dev->pdev->subsystem_vendor == 0x1179) &&
+ (dev->pdev->subsystem_device == 0xff68)) {
+ if ((connector_type == DRM_MODE_CONNECTOR_HDMIA) &&
+ (supported_device == ATOM_DEVICE_DFP2_SUPPORT))
+ return true;
+ }
+
+ /* Default: no EDID header probe required for DDC probing */
+ return false;
+}
+
static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder,
struct drm_connector *connector)
{
@@ -661,7 +712,8 @@
ret = connector_status_disconnected;
if (radeon_connector->ddc_bus)
- dret = radeon_ddc_probe(radeon_connector);
+ dret = radeon_ddc_probe(radeon_connector,
+ radeon_connector->requires_extended_probe);
if (dret) {
if (radeon_connector->edid) {
kfree(radeon_connector->edid);
@@ -833,7 +885,8 @@
bool dret = false;
if (radeon_connector->ddc_bus)
- dret = radeon_ddc_probe(radeon_connector);
+ dret = radeon_ddc_probe(radeon_connector,
+ radeon_connector->requires_extended_probe);
if (dret) {
if (radeon_connector->edid) {
kfree(radeon_connector->edid);
@@ -1251,7 +1304,8 @@
if (radeon_dp_getdpcd(radeon_connector))
ret = connector_status_connected;
} else {
- if (radeon_ddc_probe(radeon_connector))
+ if (radeon_ddc_probe(radeon_connector,
+ radeon_connector->requires_extended_probe))
ret = connector_status_connected;
}
}
@@ -1406,6 +1460,9 @@
radeon_connector->shared_ddc = shared_ddc;
radeon_connector->connector_object_id = connector_object_id;
radeon_connector->hpd = *hpd;
+ radeon_connector->requires_extended_probe =
+ radeon_connector_needs_extended_probe(rdev, supported_device,
+ connector_type);
radeon_connector->router = *router;
if (router->ddc_valid || router->cd_valid) {
radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info);
@@ -1752,6 +1809,9 @@
radeon_connector->devices = supported_device;
radeon_connector->connector_object_id = connector_object_id;
radeon_connector->hpd = *hpd;
+ radeon_connector->requires_extended_probe =
+ radeon_connector_needs_extended_probe(rdev, supported_device,
+ connector_type);
switch (connector_type) {
case DRM_MODE_CONNECTOR_VGA:
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c
index 3189a7e..f59a682 100644
--- a/drivers/gpu/drm/radeon/radeon_cursor.c
+++ b/drivers/gpu/drm/radeon/radeon_cursor.c
@@ -208,6 +208,13 @@
int xorigin = 0, yorigin = 0;
int w = radeon_crtc->cursor_width;
+ if (ASIC_IS_AVIVO(rdev)) {
+ /* avivo cursor are offset into the total surface */
+ x += crtc->x;
+ y += crtc->y;
+ }
+ DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
+
if (x < 0)
xorigin = -x + 1;
if (y < 0)
@@ -221,11 +228,6 @@
int i = 0;
struct drm_crtc *crtc_p;
- /* avivo cursor are offset into the total surface */
- x += crtc->x;
- y += crtc->y;
- DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
-
/* avivo cursor image can't end on 128 pixel boundary or
* go past the end of the frame if both crtcs are enabled
*/
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 7cfaa7e..440e6ec 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -704,8 +704,9 @@
rdev->gpu_lockup = false;
rdev->accel_working = false;
- DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X).\n",
- radeon_family_name[rdev->family], pdev->vendor, pdev->device);
+ DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X 0x%04X:0x%04X).\n",
+ radeon_family_name[rdev->family], pdev->vendor, pdev->device,
+ pdev->subsystem_vendor, pdev->subsystem_device);
/* mutex initialization are all done here so we
* can recall function without having locking issues */
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 292f73f..ed085ce 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -777,8 +777,17 @@
if (!radeon_connector->ddc_bus)
return -1;
edid = drm_get_edid(connector, &radeon_connector->ddc_bus->adapter);
+ /* Log EDID retrieval status here. In particular with regard to
+ * connectors with requires_extended_probe flag set, that will prevent
+ * function radeon_dvi_detect() to fetch EDID on this connector,
+ * as long as there is no valid EDID header found */
if (edid) {
+ DRM_INFO("Radeon display connector %s: Found valid EDID",
+ drm_get_connector_name(connector));
kfree(edid);
+ } else {
+ DRM_INFO("Radeon display connector %s: No monitor connected or invalid EDID",
+ drm_get_connector_name(connector));
}
return ret;
}
diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c
index b293487..8a171b2 100644
--- a/drivers/gpu/drm/radeon/radeon_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_encoders.c
@@ -1507,7 +1507,14 @@
switch (mode) {
case DRM_MODE_DPMS_ON:
args.ucAction = ATOM_ENABLE;
- atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+ /* workaround for DVOOutputControl on some RS690 systems */
+ if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DDI) {
+ u32 reg = RREG32(RADEON_BIOS_3_SCRATCH);
+ WREG32(RADEON_BIOS_3_SCRATCH, reg & ~ATOM_S3_DFP2I_ACTIVE);
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+ WREG32(RADEON_BIOS_3_SCRATCH, reg);
+ } else
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
args.ucAction = ATOM_LCD_BLON;
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
@@ -1748,9 +1755,12 @@
/* DCE4/5 */
if (ASIC_IS_DCE4(rdev)) {
dig = radeon_encoder->enc_priv;
- if (ASIC_IS_DCE41(rdev))
- return radeon_crtc->crtc_id;
- else {
+ if (ASIC_IS_DCE41(rdev)) {
+ if (dig->linkb)
+ return 1;
+ else
+ return 0;
+ } else {
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
if (dig->linkb)
@@ -2323,6 +2333,9 @@
default:
encoder->possible_crtcs = 0x3;
break;
+ case 4:
+ encoder->possible_crtcs = 0xf;
+ break;
case 6:
encoder->possible_crtcs = 0x3f;
break;
diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c
index 781196d..6c111c1 100644
--- a/drivers/gpu/drm/radeon/radeon_i2c.c
+++ b/drivers/gpu/drm/radeon/radeon_i2c.c
@@ -32,17 +32,17 @@
* radeon_ddc_probe
*
*/
-bool radeon_ddc_probe(struct radeon_connector *radeon_connector)
+bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool requires_extended_probe)
{
- u8 out_buf[] = { 0x0, 0x0};
- u8 buf[2];
+ u8 out = 0x0;
+ u8 buf[8];
int ret;
struct i2c_msg msgs[] = {
{
.addr = 0x50,
.flags = 0,
.len = 1,
- .buf = out_buf,
+ .buf = &out,
},
{
.addr = 0x50,
@@ -52,15 +52,31 @@
}
};
+ /* Read 8 bytes from i2c for extended probe of EDID header */
+ if (requires_extended_probe)
+ msgs[1].len = 8;
+
/* on hw with routers, select right port */
if (radeon_connector->router.ddc_valid)
radeon_router_select_ddc_port(radeon_connector);
ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2);
- if (ret == 2)
- return true;
-
- return false;
+ if (ret != 2)
+ /* Couldn't find an accessible DDC on this connector */
+ return false;
+ if (requires_extended_probe) {
+ /* Probe also for valid EDID header
+ * EDID header starts with:
+ * 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00.
+ * Only the first 6 bytes must be valid as
+ * drm_edid_block_valid() can fix the last 2 bytes */
+ if (drm_edid_header_is_valid(buf) < 6) {
+ /* Couldn't find an accessible EDID on this
+ * connector */
+ return false;
+ }
+ }
+ return true;
}
/* bit banging i2c */
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 6df4e3c..68820f5 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -438,6 +438,9 @@
struct radeon_i2c_chan *ddc_bus;
/* some systems have an hdmi and vga port with a shared ddc line */
bool shared_ddc;
+ /* for some Radeon chip families we apply an additional EDID header
+ check as part of the DDC probe */
+ bool requires_extended_probe;
bool use_digital;
/* we need to mind the EDID between detect
and get modes due to analog/digital/tvencoder */
@@ -476,6 +479,7 @@
struct drm_display_mode *mode);
extern void radeon_dp_link_train(struct drm_encoder *encoder,
struct drm_connector *connector);
+extern bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector);
extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector);
extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector);
extern void atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode);
@@ -514,7 +518,8 @@
u8 val);
extern void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector);
extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector);
-extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector);
+extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector,
+ bool requires_extended_probe);
extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector);
extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector);
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index 60125dd..3e9b41b 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -277,7 +277,12 @@
DRM_ERROR("Trying to move memory with CP turned off.\n");
return -EINVAL;
}
- r = radeon_copy(rdev, old_start, new_start, new_mem->num_pages, fence);
+
+ BUILD_BUG_ON((PAGE_SIZE % RADEON_GPU_PAGE_SIZE) != 0);
+
+ r = radeon_copy(rdev, old_start, new_start,
+ new_mem->num_pages * (PAGE_SIZE / RADEON_GPU_PAGE_SIZE), /* GPU pages */
+ fence);
/* FIXME: handle copy error */
r = ttm_bo_move_accel_cleanup(bo, (void *)fence, NULL,
evict, no_wait_reserve, no_wait_gpu, new_mem);
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 4de5189..f2516e6 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -536,55 +536,6 @@
return backend_map;
}
-static void rv770_program_channel_remap(struct radeon_device *rdev)
-{
- u32 tcp_chan_steer, mc_shared_chremap, tmp;
- bool force_no_swizzle;
-
- switch (rdev->family) {
- case CHIP_RV770:
- case CHIP_RV730:
- force_no_swizzle = false;
- break;
- case CHIP_RV710:
- case CHIP_RV740:
- default:
- force_no_swizzle = true;
- break;
- }
-
- tmp = RREG32(MC_SHARED_CHMAP);
- switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
- case 0:
- case 1:
- default:
- /* default mapping */
- mc_shared_chremap = 0x00fac688;
- break;
- case 2:
- case 3:
- if (force_no_swizzle)
- mc_shared_chremap = 0x00fac688;
- else
- mc_shared_chremap = 0x00bbc298;
- break;
- }
-
- if (rdev->family == CHIP_RV740)
- tcp_chan_steer = 0x00ef2a60;
- else
- tcp_chan_steer = 0x00fac688;
-
- /* RV770 CE has special chremap setup */
- if (rdev->pdev->device == 0x944e) {
- tcp_chan_steer = 0x00b08b08;
- mc_shared_chremap = 0x00b08b08;
- }
-
- WREG32(TCP_CHAN_STEER, tcp_chan_steer);
- WREG32(MC_SHARED_CHREMAP, mc_shared_chremap);
-}
-
static void rv770_gpu_init(struct radeon_device *rdev)
{
int i, j, num_qd_pipes;
@@ -784,8 +735,6 @@
WREG32(DCP_TILING_CONFIG, (gb_tiling_config & 0xffff));
WREG32(HDP_TILING_CONFIG, (gb_tiling_config & 0xffff));
- rv770_program_channel_remap(rdev);
-
WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable);
WREG32(CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
WREG32(GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 2e618b5..e2b2d78 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -353,8 +353,10 @@
ret = ttm_tt_set_user(bo->ttm, current,
bo->buffer_start, bo->num_pages);
- if (unlikely(ret != 0))
+ if (unlikely(ret != 0)) {
ttm_tt_destroy(bo->ttm);
+ bo->ttm = NULL;
+ }
break;
default:
printk(KERN_ERR TTM_PFX "Illegal buffer object type\n");
@@ -390,10 +392,12 @@
* Create and bind a ttm if required.
*/
- if (!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED) && (bo->ttm == NULL)) {
- ret = ttm_bo_add_ttm(bo, false);
- if (ret)
- goto out_err;
+ if (!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED)) {
+ if (bo->ttm == NULL) {
+ ret = ttm_bo_add_ttm(bo, false);
+ if (ret)
+ goto out_err;
+ }
ret = ttm_tt_set_placement_caching(bo->ttm, mem->placement);
if (ret)
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
index 77dbf40..ae3c6f5 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -635,13 +635,13 @@
if (ret)
return ret;
- ttm_bo_free_old_node(bo);
if ((man->flags & TTM_MEMTYPE_FLAG_FIXED) &&
(bo->ttm != NULL)) {
ttm_tt_unbind(bo->ttm);
ttm_tt_destroy(bo->ttm);
bo->ttm = NULL;
}
+ ttm_bo_free_old_node(bo);
} else {
/**
* This should help pipeline ordinary buffer moves.
diff --git a/drivers/gpu/ion/Makefile b/drivers/gpu/ion/Makefile
index c0a47d8..3911950 100644
--- a/drivers/gpu/ion/Makefile
+++ b/drivers/gpu/ion/Makefile
@@ -1,3 +1,3 @@
-obj-$(CONFIG_ION) += ion.o ion_heap.o ion_system_heap.o ion_carveout_heap.o
+obj-$(CONFIG_ION) += ion.o ion_heap.o ion_system_heap.o ion_carveout_heap.o ion_iommu_heap.o
obj-$(CONFIG_ION_TEGRA) += tegra/
obj-$(CONFIG_ION_MSM) += msm/
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 60bc276..1428315 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -30,6 +30,7 @@
#include <linux/uaccess.h>
#include <linux/debugfs.h>
+#include <mach/iommu_domains.h>
#include "ion_priv.h"
#define DEBUG
@@ -102,8 +103,27 @@
unsigned int kmap_cnt;
unsigned int dmap_cnt;
unsigned int usermap_cnt;
+ unsigned int iommu_map_cnt;
};
+static int ion_validate_buffer_flags(struct ion_buffer *buffer,
+ unsigned long flags)
+{
+ if (buffer->kmap_cnt || buffer->dmap_cnt || buffer->umap_cnt ||
+ buffer->iommu_map_cnt) {
+ if (buffer->flags != flags) {
+ pr_err("%s: buffer was already mapped with flags %lx,"
+ " cannot map with flags %lx\n", __func__,
+ buffer->flags, flags);
+ return 1;
+ }
+
+ } else {
+ buffer->flags = flags;
+ }
+ return 0;
+}
+
/* this function should only be called while dev->lock is held */
static void ion_buffer_add(struct ion_device *dev,
struct ion_buffer *buffer)
@@ -130,6 +150,61 @@
rb_insert_color(&buffer->node, &dev->buffers);
}
+void ion_iommu_add(struct ion_buffer *buffer,
+ struct ion_iommu_map *iommu)
+{
+ struct rb_node **p = &buffer->iommu_maps.rb_node;
+ struct rb_node *parent = NULL;
+ struct ion_iommu_map *entry;
+
+ while (*p) {
+ parent = *p;
+ entry = rb_entry(parent, struct ion_iommu_map, node);
+
+ if (iommu->key < entry->key) {
+ p = &(*p)->rb_left;
+ } else if (iommu->key > entry->key) {
+ p = &(*p)->rb_right;
+ } else {
+ pr_err("%s: buffer %p already has mapping for domain %d"
+ " and partition %d\n", __func__,
+ buffer,
+ iommu_map_domain(iommu),
+ iommu_map_partition(iommu));
+ BUG();
+ }
+ }
+
+ rb_link_node(&iommu->node, parent, p);
+ rb_insert_color(&iommu->node, &buffer->iommu_maps);
+
+}
+
+static struct ion_iommu_map *ion_iommu_lookup(struct ion_buffer *buffer,
+ unsigned int domain_no,
+ unsigned int partition_no)
+{
+ struct rb_node **p = &buffer->iommu_maps.rb_node;
+ struct rb_node *parent = NULL;
+ struct ion_iommu_map *entry;
+ uint64_t key = domain_no;
+ key = key << 32 | partition_no;
+
+ while (*p) {
+ parent = *p;
+ entry = rb_entry(parent, struct ion_iommu_map, node);
+
+ if (key < entry->key)
+ p = &(*p)->rb_left;
+ else if (key > entry->key)
+ p = &(*p)->rb_right;
+ else
+ return entry;
+ }
+
+ return NULL;
+}
+
/* this function should only be called while dev->lock is held */
static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
struct ion_device *dev,
@@ -433,17 +508,9 @@
return ERR_PTR(-ENODEV);
}
- if (buffer->kmap_cnt || buffer->dmap_cnt || buffer->umap_cnt) {
- if (buffer->flags != flags) {
- pr_err("%s: buffer was already mapped with flags %lx,"
- " cannot map with flags %lx\n", __func__,
- buffer->flags, flags);
+ if (ion_validate_buffer_flags(buffer, flags)) {
vaddr = ERR_PTR(-EEXIST);
goto out;
- }
-
- } else {
- buffer->flags = flags;
}
if (_ion_map(&buffer->kmap_cnt, &handle->kmap_cnt)) {
@@ -462,6 +529,179 @@
return vaddr;
}
+int __ion_iommu_map(struct ion_buffer *buffer,
+ int domain_num, int partition_num, unsigned long align,
+ unsigned long iova_length, unsigned long flags,
+ unsigned long *iova)
+{
+ struct ion_iommu_map *data;
+ int ret;
+
+ data = kmalloc(sizeof(*data), GFP_ATOMIC);
+
+ if (!data)
+ return -ENOMEM;
+
+ data->buffer = buffer;
+ iommu_map_domain(data) = domain_num;
+ iommu_map_partition(data) = partition_num;
+
+ ret = buffer->heap->ops->map_iommu(buffer, data,
+ domain_num,
+ partition_num,
+ align,
+ iova_length,
+ flags);
+
+ if (ret)
+ goto out;
+
+ kref_init(&data->ref);
+ *iova = data->iova_addr;
+
+ ion_iommu_add(buffer, data);
+
+ return 0;
+
+out:
+ msm_free_iova_address(data->iova_addr, domain_num, partition_num,
+ buffer->size);
+ kfree(data);
+ return ret;
+}
+
+int ion_map_iommu(struct ion_client *client, struct ion_handle *handle,
+ int domain_num, int partition_num, unsigned long align,
+ unsigned long iova_length, unsigned long *iova,
+ unsigned long *buffer_size,
+ unsigned long flags)
+{
+ struct ion_buffer *buffer;
+ struct ion_iommu_map *iommu_map;
+ int ret = 0;
+
+ mutex_lock(&client->lock);
+ if (!ion_handle_validate(client, handle)) {
+ pr_err("%s: invalid handle passed to map_kernel.\n",
+ __func__);
+ mutex_unlock(&client->lock);
+ return -EINVAL;
+ }
+
+ buffer = handle->buffer;
+ mutex_lock(&buffer->lock);
+
+ if (!handle->buffer->heap->ops->map_iommu) {
+ pr_err("%s: map_iommu is not implemented by this heap.\n",
+ __func__);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ if (ion_validate_buffer_flags(buffer, flags)) {
+ ret = -EEXIST;
+ goto out;
+ }
+
+ /*
+ * If clients don't want a custom iova length, just use whatever
+ * the buffer size is
+ */
+ if (!iova_length)
+ iova_length = buffer->size;
+
+ if (buffer->size > iova_length) {
+ pr_debug("%s: iova length %lx is not at least buffer size"
+ " %x\n", __func__, iova_length, buffer->size);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (buffer->size & ~PAGE_MASK) {
+ pr_debug("%s: buffer size %x is not aligned to %lx", __func__,
+ buffer->size, PAGE_SIZE);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (iova_length & ~PAGE_MASK) {
+ pr_debug("%s: iova_length %lx is not aligned to %lx", __func__,
+ iova_length, PAGE_SIZE);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ iommu_map = ion_iommu_lookup(buffer, domain_num, partition_num);
+ if (_ion_map(&buffer->iommu_map_cnt, &handle->iommu_map_cnt) ||
+ !iommu_map) {
+ ret = __ion_iommu_map(buffer, domain_num, partition_num, align,
+ iova_length, flags, iova);
+ if (ret < 0)
+ _ion_unmap(&buffer->iommu_map_cnt,
+ &handle->iommu_map_cnt);
+ } else {
+ if (iommu_map->mapped_size != iova_length) {
+ pr_err("%s: handle %p is already mapped with length"
+ " %x, trying to map with length %lx\n",
+ __func__, handle, iommu_map->mapped_size,
+ iova_length);
+ _ion_unmap(&buffer->iommu_map_cnt,
+ &handle->iommu_map_cnt);
+ ret = -EINVAL;
+ } else {
+ kref_get(&iommu_map->ref);
+ *iova = iommu_map->iova_addr;
+ }
+ }
+ *buffer_size = buffer->size;
+out:
+ mutex_unlock(&buffer->lock);
+ mutex_unlock(&client->lock);
+ return ret;
+}
+EXPORT_SYMBOL(ion_map_iommu);
+
+static void ion_iommu_release(struct kref *kref)
+{
+ struct ion_iommu_map *map = container_of(kref, struct ion_iommu_map,
+ ref);
+ struct ion_buffer *buffer = map->buffer;
+
+ rb_erase(&map->node, &buffer->iommu_maps);
+ buffer->heap->ops->unmap_iommu(map);
+ kfree(map);
+}
+
+void ion_unmap_iommu(struct ion_client *client, struct ion_handle *handle,
+ int domain_num, int partition_num)
+{
+ struct ion_iommu_map *iommu_map;
+ struct ion_buffer *buffer;
+
+ mutex_lock(&client->lock);
+ buffer = handle->buffer;
+
+ mutex_lock(&buffer->lock);
+
+ iommu_map = ion_iommu_lookup(buffer, domain_num, partition_num);
+
+ if (!iommu_map) {
+ WARN(1, "%s: (%d,%d) was never mapped for %p\n", __func__,
+ domain_num, partition_num, buffer);
+ goto out;
+ }
+
+ _ion_unmap(&buffer->iommu_map_cnt, &handle->iommu_map_cnt);
+ kref_put(&iommu_map->ref, ion_iommu_release);
+
+out:
+ mutex_unlock(&buffer->lock);
+
+ mutex_unlock(&client->lock);
+
+}
+EXPORT_SYMBOL(ion_unmap_iommu);
+
struct scatterlist *ion_map_dma(struct ion_client *client,
struct ion_handle *handle,
unsigned long flags)
@@ -487,17 +727,9 @@
return ERR_PTR(-ENODEV);
}
- if (buffer->kmap_cnt || buffer->dmap_cnt || buffer->umap_cnt) {
- if (buffer->flags != flags) {
- pr_err("%s: buffer was already mapped with flags %lx,"
- " cannot map with flags %lx\n", __func__,
- buffer->flags, flags);
- sglist = ERR_PTR(-EEXIST);
- goto out;
- }
-
- } else {
- buffer->flags = flags;
+ if (ion_validate_buffer_flags(buffer, flags)) {
+ sglist = ERR_PTR(-EEXIST);
+ goto out;
}
if (_ion_map(&buffer->dmap_cnt, &handle->dmap_cnt)) {
@@ -618,7 +850,6 @@
unsigned int cmd)
{
struct ion_buffer *buffer;
- unsigned long start, end;
int ret = -EINVAL;
mutex_lock(&client->lock);
@@ -643,14 +874,6 @@
goto out;
}
- start = (unsigned long) uaddr;
- end = (unsigned long) uaddr + len;
-
- if (check_vaddr_bounds(start, end)) {
- pr_err("%s: virtual address %p is out of bounds\n",
- __func__, uaddr);
- goto out;
- }
ret = buffer->heap->ops->cache_op(buffer->heap, buffer, uaddr,
offset, len, cmd);
@@ -755,7 +978,6 @@
struct rb_node **p;
struct rb_node *parent = NULL;
struct ion_client *entry;
- char debug_name[64];
pid_t pid;
get_task_struct(current->group_leader);
@@ -825,8 +1047,8 @@
rb_insert_color(&client->node, &dev->kernel_clients);
}
- snprintf(debug_name, 64, "%u", client->pid);
- client->debug_root = debugfs_create_file(debug_name, 0664,
+
+ client->debug_root = debugfs_create_file(name, 0664,
dev->debug_root, client,
&debug_client_fops);
mutex_unlock(&dev->lock);
@@ -897,14 +1119,33 @@
}
EXPORT_SYMBOL(ion_handle_get_flags);
+int ion_handle_get_size(struct ion_client *client, struct ion_handle *handle,
+ unsigned long *size)
+{
+ struct ion_buffer *buffer;
+
+ mutex_lock(&client->lock);
+ if (!ion_handle_validate(client, handle)) {
+ pr_err("%s: invalid handle passed to %s.\n",
+ __func__, __func__);
+ mutex_unlock(&client->lock);
+ return -EINVAL;
+ }
+ buffer = handle->buffer;
+ mutex_lock(&buffer->lock);
+ *size = buffer->size;
+ mutex_unlock(&buffer->lock);
+ mutex_unlock(&client->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(ion_handle_get_size);
+
static int ion_share_release(struct inode *inode, struct file* file)
{
struct ion_buffer *buffer = file->private_data;
pr_debug("%s: %d\n", __func__, __LINE__);
- mutex_lock(&buffer->lock);
- buffer->umap_cnt--;
- mutex_unlock(&buffer->lock);
/* drop the reference to the buffer -- this prevents the
buffer from going away because the client holding it exited
while it was being passed */
@@ -927,6 +1168,10 @@
vma->vm_private_data = NULL;
return;
}
+ ion_handle_get(handle);
+ mutex_lock(&buffer->lock);
+ buffer->umap_cnt++;
+ mutex_unlock(&buffer->lock);
pr_debug("%s: %d client_cnt %d handle_cnt %d alloc_cnt %d\n",
__func__, __LINE__,
atomic_read(&client->ref.refcount),
@@ -945,6 +1190,14 @@
if (!handle)
return;
client = handle->client;
+ mutex_lock(&buffer->lock);
+ buffer->umap_cnt--;
+ mutex_unlock(&buffer->lock);
+
+ if (buffer->heap->ops->unmap_user)
+ buffer->heap->ops->unmap_user(buffer->heap, buffer);
+
+
pr_debug("%s: %d client_cnt %d handle_cnt %d alloc_cnt %d\n",
__func__, __LINE__,
atomic_read(&client->ref.refcount),
@@ -1010,23 +1263,16 @@
}
mutex_lock(&buffer->lock);
- if (buffer->kmap_cnt || buffer->dmap_cnt || buffer->umap_cnt) {
- if (buffer->flags != flags) {
- pr_err("%s: buffer was already mapped with flags %lx,"
- " cannot map with flags %lx\n", __func__,
- buffer->flags, flags);
- ret = -EEXIST;
- mutex_unlock(&buffer->lock);
- goto err1;
- }
- } else {
- buffer->flags = flags;
+ if (ion_validate_buffer_flags(buffer, flags)) {
+ ret = -EEXIST;
+ mutex_unlock(&buffer->lock);
+ goto err1;
}
+
/* now map it to userspace */
ret = buffer->heap->ops->map_user(buffer->heap, buffer, vma,
flags);
- buffer->umap_cnt++;
mutex_unlock(&buffer->lock);
if (ret) {
pr_err("%s: failure mapping buffer to userspace\n",
@@ -1102,6 +1348,10 @@
return -EFAULT;
data.handle = ion_alloc(client, data.len, data.align,
data.flags);
+
+ if (IS_ERR_OR_NULL(data.handle))
+ return PTR_ERR(data.handle);
+
if (copy_to_user((void __user *)arg, &data, sizeof(data)))
return -EFAULT;
break;
@@ -1174,13 +1424,41 @@
case ION_IOC_CLEAN_INV_CACHES:
{
struct ion_flush_data data;
+ unsigned long start, end;
+ struct ion_handle *handle = NULL;
+ int ret;
if (copy_from_user(&data, (void __user *)arg,
sizeof(struct ion_flush_data)))
return -EFAULT;
- return ion_do_cache_op(client, data.handle, data.vaddr,
- data.offset, data.length, cmd);
+ start = (unsigned long) data.vaddr;
+ end = (unsigned long) data.vaddr + data.length;
+
+ if (check_vaddr_bounds(start, end)) {
+ pr_err("%s: virtual address %p is out of bounds\n",
+ __func__, data.vaddr);
+ return -EINVAL;
+ }
+
+ if (!data.handle) {
+ handle = ion_import_fd(client, data.fd);
+ if (IS_ERR_OR_NULL(handle)) {
+ pr_info("%s: Could not import handle: %d\n",
+ __func__, (int)handle);
+ return -EINVAL;
+ }
+ }
+
+ ret = ion_do_cache_op(client,
+ data.handle ? data.handle : handle,
+ data.vaddr, data.offset, data.length,
+ cmd);
+
+ if (!data.handle)
+ ion_free(client, handle);
+
+ break;
}
case ION_IOC_GET_FLAGS:
@@ -1219,9 +1497,11 @@
struct miscdevice *miscdev = file->private_data;
struct ion_device *dev = container_of(miscdev, struct ion_device, dev);
struct ion_client *client;
+ char debug_name[64];
pr_debug("%s: %d\n", __func__, __LINE__);
- client = ion_client_create(dev, -1, "user");
+ snprintf(debug_name, 64, "%u", task_pid_nr(current->group_leader));
+ client = ion_client_create(dev, -1, debug_name);
if (IS_ERR_OR_NULL(client))
return PTR_ERR(client);
file->private_data = client;
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index 71dea89..9cb338a 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -2,6 +2,7 @@
* drivers/gpu/ion/ion_carveout_heap.c
*
* Copyright (C) 2011 Google, Inc.
+ * Copyright (c) 2011, Code Aurora Forum. 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
@@ -23,8 +24,10 @@
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
+#include <linux/iommu.h>
#include "ion_priv.h"
+#include <mach/iommu_domains.h>
#include <asm/mach/map.h>
struct ion_carveout_heap {
@@ -33,6 +36,10 @@
ion_phys_addr_t base;
unsigned long allocated_bytes;
unsigned long total_size;
+ void (*request_region)(void *);
+ void (*release_region)(void *);
+ atomic_t map_count;
+ void *bus_id;
};
ion_phys_addr_t ion_carveout_allocate(struct ion_heap *heap,
@@ -128,6 +135,13 @@
struct ion_buffer *buffer,
unsigned long flags)
{
+ struct ion_carveout_heap *carveout_heap =
+ container_of(heap, struct ion_carveout_heap, heap);
+
+ if (atomic_inc_return(&carveout_heap->map_count) == 1)
+ if (carveout_heap->request_region)
+ carveout_heap->request_region(carveout_heap->bus_id);
+
if (ION_IS_CACHED(flags))
return ioremap_cached(buffer->priv_phys, buffer->size);
else
@@ -137,26 +151,52 @@
void ion_carveout_heap_unmap_kernel(struct ion_heap *heap,
struct ion_buffer *buffer)
{
+ struct ion_carveout_heap *carveout_heap =
+ container_of(heap, struct ion_carveout_heap, heap);
+
__arch_iounmap(buffer->vaddr);
buffer->vaddr = NULL;
+
+ if (atomic_dec_and_test(&carveout_heap->map_count))
+ if (carveout_heap->release_region)
+ carveout_heap->release_region(carveout_heap->bus_id);
+
return;
}
int ion_carveout_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
struct vm_area_struct *vma, unsigned long flags)
{
+ struct ion_carveout_heap *carveout_heap =
+ container_of(heap, struct ion_carveout_heap, heap);
+
+ if (atomic_inc_return(&carveout_heap->map_count) == 1)
+ if (carveout_heap->request_region)
+ carveout_heap->request_region(carveout_heap->bus_id);
+
if (ION_IS_CACHED(flags))
return remap_pfn_range(vma, vma->vm_start,
__phys_to_pfn(buffer->priv_phys) + vma->vm_pgoff,
- buffer->size,
+ vma->vm_end - vma->vm_start,
vma->vm_page_prot);
else
return remap_pfn_range(vma, vma->vm_start,
__phys_to_pfn(buffer->priv_phys) + vma->vm_pgoff,
- buffer->size,
+ vma->vm_end - vma->vm_start,
pgprot_noncached(vma->vm_page_prot));
}
+void ion_carveout_heap_unmap_user(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+ struct ion_carveout_heap *carveout_heap =
+ container_of(heap, struct ion_carveout_heap, heap);
+
+ if (atomic_dec_and_test(&carveout_heap->map_count))
+ if (carveout_heap->release_region)
+ carveout_heap->release_region(carveout_heap->bus_id);
+}
+
int ion_carveout_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer,
void *vaddr, unsigned int offset, unsigned int length,
unsigned int cmd)
@@ -199,18 +239,123 @@
return carveout_heap->total_size;
}
+int ion_carveout_heap_map_iommu(struct ion_buffer *buffer,
+ struct ion_iommu_map *data,
+ unsigned int domain_num,
+ unsigned int partition_num,
+ unsigned long align,
+ unsigned long iova_length,
+ unsigned long flags)
+{
+ unsigned long temp_phys, temp_iova;
+ struct iommu_domain *domain;
+ int i, ret = 0;
+ unsigned long extra;
+
+ data->mapped_size = iova_length;
+
+ if (!msm_use_iommu()) {
+ data->iova_addr = buffer->priv_phys;
+ return 0;
+ }
+
+ extra = iova_length - buffer->size;
+
+ data->iova_addr = msm_allocate_iova_address(domain_num, partition_num,
+ data->mapped_size, align);
+
+ if (!data->iova_addr) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ domain = msm_get_iommu_domain(domain_num);
+
+ if (!domain) {
+ ret = -ENOMEM;
+ goto out1;
+ }
+
+ temp_iova = data->iova_addr;
+ temp_phys = buffer->priv_phys;
+ for (i = buffer->size; i > 0; i -= SZ_4K, temp_iova += SZ_4K,
+ temp_phys += SZ_4K) {
+ ret = iommu_map(domain, temp_iova, temp_phys,
+ get_order(SZ_4K),
+ ION_IS_CACHED(flags) ? 1 : 0);
+
+ if (ret) {
+ pr_err("%s: could not map %lx to %lx in domain %p\n",
+ __func__, temp_iova, temp_phys, domain);
+ goto out2;
+ }
+ }
+
+ if (extra && (msm_iommu_map_extra(domain, temp_iova, extra, flags) < 0))
+ goto out2;
+
+ return 0;
+
+
+out2:
+ for ( ; i < buffer->size; i += SZ_4K, temp_iova -= SZ_4K)
+ iommu_unmap(domain, temp_iova, get_order(SZ_4K));
+
+out1:
+ msm_free_iova_address(data->iova_addr, domain_num, partition_num,
+ data->mapped_size);
+
+out:
+
+ return ret;
+}
+
+void ion_carveout_heap_unmap_iommu(struct ion_iommu_map *data)
+{
+ int i;
+ unsigned long temp_iova;
+ unsigned int domain_num;
+ unsigned int partition_num;
+ struct iommu_domain *domain;
+
+ if (!msm_use_iommu())
+ return;
+
+ domain_num = iommu_map_domain(data);
+ partition_num = iommu_map_partition(data);
+
+ domain = msm_get_iommu_domain(domain_num);
+
+ if (!domain) {
+ WARN(1, "Could not get domain %d. Corruption?\n", domain_num);
+ return;
+ }
+
+ temp_iova = data->iova_addr;
+ for (i = data->mapped_size; i > 0; i -= SZ_4K, temp_iova += SZ_4K)
+ iommu_unmap(domain, temp_iova, get_order(SZ_4K));
+
+ msm_free_iova_address(data->iova_addr, domain_num, partition_num,
+ data->mapped_size);
+
+ return;
+}
+
static struct ion_heap_ops carveout_heap_ops = {
.allocate = ion_carveout_heap_allocate,
.free = ion_carveout_heap_free,
.phys = ion_carveout_heap_phys,
.map_user = ion_carveout_heap_map_user,
.map_kernel = ion_carveout_heap_map_kernel,
+ .unmap_user = ion_carveout_heap_unmap_user,
.unmap_kernel = ion_carveout_heap_unmap_kernel,
.map_dma = ion_carveout_heap_map_dma,
.unmap_dma = ion_carveout_heap_unmap_dma,
.cache_op = ion_carveout_cache_ops,
.get_allocated = ion_carveout_get_allocated,
.get_total = ion_carveout_get_total,
+ .map_iommu = ion_carveout_heap_map_iommu,
+ .unmap_iommu = ion_carveout_heap_unmap_iommu,
};
struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *heap_data)
@@ -238,6 +383,12 @@
carveout_heap->heap.type = ION_HEAP_TYPE_CARVEOUT;
carveout_heap->allocated_bytes = 0;
carveout_heap->total_size = heap_data->size;
+ if (heap_data->setup_region)
+ carveout_heap->bus_id = heap_data->setup_region();
+ if (heap_data->request_region)
+ carveout_heap->request_region = heap_data->request_region;
+ if (heap_data->release_region)
+ carveout_heap->release_region = heap_data->release_region;
return &carveout_heap->heap;
}
diff --git a/drivers/gpu/ion/ion_heap.c b/drivers/gpu/ion/ion_heap.c
index 8ce3c19..900f445 100644
--- a/drivers/gpu/ion/ion_heap.c
+++ b/drivers/gpu/ion/ion_heap.c
@@ -32,6 +32,9 @@
case ION_HEAP_TYPE_CARVEOUT:
heap = ion_carveout_heap_create(heap_data);
break;
+ case ION_HEAP_TYPE_IOMMU:
+ heap = ion_iommu_heap_create(heap_data);
+ break;
default:
pr_err("%s: Invalid heap type %d\n", __func__,
heap_data->type);
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
new file mode 100644
index 0000000..d37a811
--- /dev/null
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/err.h>
+#include <linux/io.h>
+#include <linux/ion.h>
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/iommu.h>
+#include <linux/pfn.h>
+#include "ion_priv.h"
+
+#include <asm/mach/map.h>
+#include <asm/page.h>
+#include <mach/iommu_domains.h>
+
+struct ion_iommu_heap {
+ struct ion_heap heap;
+};
+
+struct ion_iommu_priv_data {
+ struct page **pages;
+ int nrpages;
+ unsigned long size;
+};
+
+static int ion_iommu_heap_allocate(struct ion_heap *heap,
+ struct ion_buffer *buffer,
+ unsigned long size, unsigned long align,
+ unsigned long flags)
+{
+ int ret, i;
+ struct ion_iommu_priv_data *data = NULL;
+
+ if (msm_use_iommu()) {
+ data = kmalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->size = PFN_ALIGN(size);
+ data->nrpages = data->size >> PAGE_SHIFT;
+ data->pages = kzalloc(sizeof(struct page *)*data->nrpages,
+ GFP_KERNEL);
+ if (!data->pages) {
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ for (i = 0; i < data->nrpages; i++) {
+ data->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ if (!data->pages[i])
+ goto err2;
+ }
+
+
+ buffer->priv_virt = data;
+ return 0;
+
+ } else {
+ return -ENOMEM;
+ }
+
+
+err2:
+ for (i = 0; i < data->nrpages; i++) {
+ if (data->pages[i])
+ __free_page(data->pages[i]);
+ }
+ kfree(data->pages);
+err1:
+ kfree(data);
+ return ret;
+}
+
+static void ion_iommu_heap_free(struct ion_buffer *buffer)
+{
+ struct ion_iommu_priv_data *data = buffer->priv_virt;
+ int i;
+
+ if (!data)
+ return;
+
+ for (i = 0; i < data->nrpages; i++)
+ __free_page(data->pages[i]);
+
+ kfree(data->pages);
+ kfree(data);
+}
+
+void *ion_iommu_heap_map_kernel(struct ion_heap *heap,
+ struct ion_buffer *buffer,
+ unsigned long flags)
+{
+ struct ion_iommu_priv_data *data = buffer->priv_virt;
+ pgprot_t page_prot = PAGE_KERNEL;
+
+ if (!data)
+ return NULL;
+
+ if (!ION_IS_CACHED(flags))
+ page_prot = pgprot_noncached(page_prot);
+
+ buffer->vaddr = vmap(data->pages, data->nrpages, VM_IOREMAP, page_prot);
+
+ return buffer->vaddr;
+}
+
+void ion_iommu_heap_unmap_kernel(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+ if (!buffer->vaddr)
+ return;
+
+ vunmap(buffer->vaddr);
+ buffer->vaddr = NULL;
+}
+
+int ion_iommu_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
+ struct vm_area_struct *vma, unsigned long flags)
+{
+ struct ion_iommu_priv_data *data = buffer->priv_virt;
+ int i;
+
+ if (!data)
+ return -EINVAL;
+
+ if (!ION_IS_CACHED(flags))
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ for (i = 0; i < data->nrpages; i++)
+ if (vm_insert_page(vma, vma->vm_start + i * PAGE_SIZE,
+ data->pages[i]))
+ /*
+ * This will fail the mmap which will
+ * clean up the vma space properly.
+ */
+ return -EINVAL;
+
+ return 0;
+}
+
+int ion_iommu_heap_map_iommu(struct ion_buffer *buffer,
+ struct ion_iommu_map *data,
+ unsigned int domain_num,
+ unsigned int partition_num,
+ unsigned long align,
+ unsigned long iova_length,
+ unsigned long flags)
+{
+ unsigned long temp_iova;
+ struct iommu_domain *domain;
+ struct ion_iommu_priv_data *buffer_data = buffer->priv_virt;
+ int i, j, ret = 0;
+ unsigned long extra;
+
+ BUG_ON(!msm_use_iommu());
+
+ data->mapped_size = iova_length;
+ extra = iova_length - buffer->size;
+
+ data->iova_addr = msm_allocate_iova_address(domain_num, partition_num,
+ data->mapped_size, align);
+
+ if (!data->iova_addr) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ domain = msm_get_iommu_domain(domain_num);
+
+ if (!domain) {
+ ret = -ENOMEM;
+ goto out1;
+ }
+
+ temp_iova = data->iova_addr;
+ for (i = buffer->size, j = 0; i > 0; j++, i -= SZ_4K,
+ temp_iova += SZ_4K) {
+ ret = iommu_map(domain, temp_iova,
+ page_to_phys(buffer_data->pages[j]),
+ get_order(SZ_4K),
+ ION_IS_CACHED(flags) ? 1 : 0);
+
+ if (ret) {
+ pr_err("%s: could not map %lx to %x in domain %p\n",
+ __func__, temp_iova,
+ page_to_phys(buffer_data->pages[j]),
+ domain);
+ goto out2;
+ }
+ }
+
+
+ if (extra &&
+ msm_iommu_map_extra
+ (domain, temp_iova, extra, flags) < 0)
+ goto out2;
+
+ return 0;
+
+
+out2:
+ for ( ; i < buffer->size; i += SZ_4K, temp_iova -= SZ_4K)
+ iommu_unmap(domain, temp_iova, get_order(SZ_4K));
+
+out1:
+ msm_free_iova_address(data->iova_addr, domain_num, partition_num,
+ buffer->size);
+
+out:
+
+ return ret;
+}
+
+void ion_iommu_heap_unmap_iommu(struct ion_iommu_map *data)
+{
+ int i;
+ unsigned long temp_iova;
+ unsigned int domain_num;
+ unsigned int partition_num;
+ struct iommu_domain *domain;
+
+ BUG_ON(!msm_use_iommu());
+
+ domain_num = iommu_map_domain(data);
+ partition_num = iommu_map_partition(data);
+
+ domain = msm_get_iommu_domain(domain_num);
+
+ if (!domain) {
+ WARN(1, "Could not get domain %d. Corruption?\n", domain_num);
+ return;
+ }
+
+ temp_iova = data->iova_addr;
+ for (i = data->mapped_size; i > 0; i -= SZ_4K, temp_iova += SZ_4K)
+ iommu_unmap(domain, temp_iova, get_order(SZ_4K));
+
+ msm_free_iova_address(data->iova_addr, domain_num, partition_num,
+ data->mapped_size);
+
+ return;
+}
+
+
+static struct ion_heap_ops iommu_heap_ops = {
+ .allocate = ion_iommu_heap_allocate,
+ .free = ion_iommu_heap_free,
+ .map_user = ion_iommu_heap_map_user,
+ .map_kernel = ion_iommu_heap_map_kernel,
+ .unmap_kernel = ion_iommu_heap_unmap_kernel,
+ .map_iommu = ion_iommu_heap_map_iommu,
+ .unmap_iommu = ion_iommu_heap_unmap_iommu,
+};
+
+struct ion_heap *ion_iommu_heap_create(struct ion_platform_heap *heap_data)
+{
+ struct ion_iommu_heap *iommu_heap;
+
+ iommu_heap = kzalloc(sizeof(struct ion_iommu_heap), GFP_KERNEL);
+ if (!iommu_heap)
+ return ERR_PTR(-ENOMEM);
+
+ iommu_heap->heap.ops = &iommu_heap_ops;
+ iommu_heap->heap.type = ION_HEAP_TYPE_IOMMU;
+
+ return &iommu_heap->heap;
+}
+
+void ion_iommu_heap_destroy(struct ion_heap *heap)
+{
+ struct ion_iommu_heap *iommu_heap =
+ container_of(heap, struct ion_iommu_heap, heap);
+
+ kfree(iommu_heap);
+ iommu_heap = NULL;
+}
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 888b599..77b73e2 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -22,6 +22,7 @@
#include <linux/mutex.h>
#include <linux/rbtree.h>
#include <linux/ion.h>
+#include <linux/iommu.h>
struct ion_mapping;
@@ -35,6 +36,34 @@
void *vaddr;
};
+/**
+ * struct ion_iommu_map - represents a mapping of an ion buffer to an iommu
+ * @iova_addr - iommu virtual address
+ * @node - rb node to exist in the buffer's tree of iommu mappings
+ * @domain_info - contains the partition number and domain number
+ * domain_info[1] = domain number
+ * domain_info[0] = partition number
+ * @ref - for reference counting this mapping
+ * @mapped_size - size of the iova space mapped
+ * (may not be the same as the buffer size)
+ *
+ * Represents a mapping of one ion buffer to a particular iommu domain
+ * and address range. There may exist other mappings of this buffer in
+ * different domains or address ranges. All mappings will have the same
+ * cacheability and security.
+ */
+struct ion_iommu_map {
+ unsigned long iova_addr;
+ struct rb_node node;
+ union {
+ int domain_info[2];
+ uint64_t key;
+ };
+ struct ion_buffer *buffer;
+ struct kref ref;
+ int mapped_size;
+};
+
struct ion_buffer *ion_handle_buffer(struct ion_handle *handle);
/**
@@ -72,6 +101,8 @@
int dmap_cnt;
struct scatterlist *sglist;
int umap_cnt;
+ unsigned int iommu_map_cnt;
+ struct rb_root iommu_maps;
int marked;
};
@@ -86,6 +117,7 @@
* @map_kernel map memory to the kernel
* @unmap_kernel unmap memory to the kernel
* @map_user map memory to userspace
+ * @unmap_user unmap memory to userspace
*/
struct ion_heap_ops {
int (*allocate) (struct ion_heap *heap,
@@ -102,11 +134,21 @@
void (*unmap_kernel) (struct ion_heap *heap, struct ion_buffer *buffer);
int (*map_user) (struct ion_heap *mapper, struct ion_buffer *buffer,
struct vm_area_struct *vma, unsigned long flags);
+ void (*unmap_user) (struct ion_heap *mapper, struct ion_buffer *buffer);
int (*cache_op)(struct ion_heap *heap, struct ion_buffer *buffer,
void *vaddr, unsigned int offset,
unsigned int length, unsigned int cmd);
unsigned long (*get_allocated)(struct ion_heap *heap);
unsigned long (*get_total)(struct ion_heap *heap);
+ int (*map_iommu)(struct ion_buffer *buffer,
+ struct ion_iommu_map *map_data,
+ unsigned int domain_num,
+ unsigned int partition_num,
+ unsigned long align,
+ unsigned long iova_length,
+ unsigned long flags);
+ void (*unmap_iommu)(struct ion_iommu_map *data);
+
};
/**
@@ -134,6 +176,11 @@
const char *name;
};
+
+
+#define iommu_map_domain(__m) ((__m)->domain_info[1])
+#define iommu_map_partition(__m) ((__m)->domain_info[0])
+
/**
* ion_device_create - allocates and returns an ion device
* @custom_ioctl: arch specific ioctl function if applicable
@@ -175,6 +222,10 @@
struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *);
void ion_carveout_heap_destroy(struct ion_heap *);
+
+struct ion_heap *ion_iommu_heap_create(struct ion_platform_heap *);
+void ion_iommu_heap_destroy(struct ion_heap *);
+
/**
* kernel api to allocate/free from carveout -- used when carveout is
* used to back an architecture specific custom heap
@@ -183,6 +234,9 @@
unsigned long align);
void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr,
unsigned long size);
+
+
+struct ion_heap *msm_get_contiguous_heap(void);
/**
* The carveout heap returns physical addresses, since 0 may be a valid
* physical address, this is used to indicate allocation failed
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index b26d48c..5957658 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -2,6 +2,7 @@
* drivers/gpu/ion/ion_system_heap.c
*
* Copyright (C) 2011 Google, Inc.
+ * Copyright (c) 2011, Code Aurora Forum. 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
@@ -20,6 +21,8 @@
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
+#include <linux/iommu.h>
+#include <mach/iommu_domains.h>
#include "ion_priv.h"
#include <mach/memory.h>
@@ -98,6 +101,37 @@
{
}
+void ion_system_heap_unmap_iommu(struct ion_iommu_map *data)
+{
+ int i;
+ unsigned long temp_iova;
+ unsigned int domain_num;
+ unsigned int partition_num;
+ struct iommu_domain *domain;
+
+ if (!msm_use_iommu())
+ return;
+
+ domain_num = iommu_map_domain(data);
+ partition_num = iommu_map_partition(data);
+
+ domain = msm_get_iommu_domain(domain_num);
+
+ if (!domain) {
+ WARN(1, "Could not get domain %d. Corruption?\n", domain_num);
+ return;
+ }
+
+ temp_iova = data->iova_addr;
+ for (i = data->mapped_size; i > 0; i -= SZ_4K, temp_iova += SZ_4K)
+ iommu_unmap(domain, temp_iova, get_order(SZ_4K));
+
+ msm_free_iova_address(data->iova_addr, domain_num, partition_num,
+ data->mapped_size);
+
+ return;
+}
+
int ion_system_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
struct vm_area_struct *vma, unsigned long flags)
{
@@ -160,6 +194,77 @@
return atomic_read(&system_heap_allocated);
}
+int ion_system_heap_map_iommu(struct ion_buffer *buffer,
+ struct ion_iommu_map *data,
+ unsigned int domain_num,
+ unsigned int partition_num,
+ unsigned long align,
+ unsigned long iova_length,
+ unsigned long flags)
+{
+ int ret, i;
+ unsigned long temp_iova;
+ struct iommu_domain *domain;
+ void *temp_phys;
+ unsigned long extra;
+
+ if (!ION_IS_CACHED(flags))
+ return -EINVAL;
+
+ if (!msm_use_iommu())
+ return -EINVAL;
+
+ data->mapped_size = iova_length;
+ extra = iova_length - buffer->size;
+
+ data->iova_addr = msm_allocate_iova_address(domain_num, partition_num,
+ data->mapped_size, align);
+
+ if (!data->iova_addr) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ domain = msm_get_iommu_domain(domain_num);
+
+ if (!domain) {
+ ret = -ENOMEM;
+ goto out1;
+ }
+
+ temp_iova = data->iova_addr;
+ temp_phys = buffer->vaddr;
+ for (i = buffer->size; i > 0; i -= SZ_4K, temp_iova += SZ_4K,
+ temp_phys += SZ_4K) {
+ ret = iommu_map(domain, temp_iova,
+ page_to_phys(vmalloc_to_page(temp_phys)),
+ get_order(SZ_4K), ION_IS_CACHED(flags) ? 1 : 0);
+
+ if (ret) {
+ pr_err("%s: could not map %lx to %x in domain %p\n",
+ __func__, temp_iova,
+ page_to_phys(vmalloc_to_page(temp_phys)),
+ domain);
+ goto out2;
+ }
+ }
+
+ if (extra && (msm_iommu_map_extra(domain, temp_iova, extra, flags) < 0))
+ goto out2;
+
+ return 0;
+
+out2:
+ for ( ; i < buffer->size; i += SZ_4K, temp_iova -= SZ_4K)
+ iommu_unmap(domain, temp_iova, get_order(SZ_4K));
+
+out1:
+ msm_free_iova_address(data->iova_addr, domain_num, partition_num,
+ data->mapped_size);
+out:
+ return ret;
+}
+
static struct ion_heap_ops vmalloc_ops = {
.allocate = ion_system_heap_allocate,
.free = ion_system_heap_free,
@@ -170,6 +275,8 @@
.map_user = ion_system_heap_map_user,
.cache_op = ion_system_heap_cache_ops,
.get_allocated = ion_system_heap_get_allocated,
+ .map_iommu = ion_system_heap_map_iommu,
+ .unmap_iommu = ion_system_heap_unmap_iommu,
};
struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused)
@@ -285,6 +392,74 @@
return atomic_read(&system_contig_heap_allocated);
}
+int ion_system_contig_heap_map_iommu(struct ion_buffer *buffer,
+ struct ion_iommu_map *data,
+ unsigned int domain_num,
+ unsigned int partition_num,
+ unsigned long align,
+ unsigned long iova_length,
+ unsigned long flags)
+{
+ int ret, i;
+ struct iommu_domain *domain;
+ unsigned long temp_phys, temp_iova;
+ unsigned long extra;
+
+ if (!ION_IS_CACHED(flags))
+ return -EINVAL;
+
+ if (!msm_use_iommu()) {
+ data->iova_addr = virt_to_phys(buffer->vaddr);
+ return 0;
+ }
+
+ data->mapped_size = iova_length;
+ extra = iova_length - buffer->size;
+
+ data->iova_addr = msm_allocate_iova_address(domain_num, partition_num,
+ data->mapped_size, align);
+
+ if (!data->iova_addr) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ domain = msm_get_iommu_domain(domain_num);
+
+ if (!domain) {
+ ret = -ENOMEM;
+ goto out1;
+ }
+ temp_iova = data->iova_addr;
+ temp_phys = virt_to_phys(buffer->vaddr);
+ for (i = buffer->size; i > 0; i -= SZ_4K, temp_iova += SZ_4K,
+ temp_phys += SZ_4K) {
+ ret = iommu_map(domain, temp_iova,
+ temp_phys,
+ get_order(SZ_4K), ION_IS_CACHED(flags) ? 1 : 0);
+
+ if (ret) {
+ pr_err("%s: could not map %lx to %lx in domain %p\n",
+ __func__, temp_iova, temp_phys, domain);
+ goto out2;
+ }
+ }
+
+ if (extra && (msm_iommu_map_extra(domain, temp_iova, extra, flags) < 0))
+ goto out2;
+
+ return 0;
+out2:
+ for ( ; i < buffer->size; i += SZ_4K, temp_iova -= SZ_4K)
+ iommu_unmap(domain, temp_iova, get_order(SZ_4K));
+
+out1:
+ msm_free_iova_address(data->iova_addr, domain_num, partition_num,
+ data->mapped_size);
+out:
+ return ret;
+}
+
static struct ion_heap_ops kmalloc_ops = {
.allocate = ion_system_contig_heap_allocate,
.free = ion_system_contig_heap_free,
@@ -296,6 +471,8 @@
.map_user = ion_system_contig_heap_map_user,
.cache_op = ion_system_contig_heap_cache_ops,
.get_allocated = ion_system_contig_heap_get_allocated,
+ .map_iommu = ion_system_contig_heap_map_iommu,
+ .unmap_iommu = ion_system_heap_unmap_iommu,
};
struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *unused)
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 54dd056..0c96eaf 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -89,6 +89,7 @@
heaps[i] = 0;
continue;
}
+
ion_device_add_heap(idev, heaps[i]);
}
platform_set_drvdata(pdev, idev);
diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile
index b4cd286..39a7b04 100644
--- a/drivers/gpu/msm/Makefile
+++ b/drivers/gpu/msm/Makefile
@@ -1,7 +1,8 @@
-ccflags-y := -Iinclude/drm
+ccflags-y := -Iinclude/drm -Idrivers/gpu/msm
msm_kgsl_core-y = \
kgsl.o \
+ kgsl_trace.o \
kgsl_sharedmem.o \
kgsl_pwrctrl.o \
kgsl_pwrscale.o \
@@ -20,11 +21,14 @@
adreno_drawctxt.o \
adreno_postmortem.o \
adreno_a2xx.o \
+ adreno_a2xx_trace.o \
adreno.o
msm_adreno-$(CONFIG_DEBUG_FS) += adreno_debugfs.o
-msm_z180-y += z180.o
+msm_z180-y += \
+ z180.o \
+ z180_trace.o
msm_kgsl_core-objs = $(msm_kgsl_core-y)
msm_adreno-objs = $(msm_adreno-y)
diff --git a/drivers/gpu/msm/a2xx_reg.h b/drivers/gpu/msm/a2xx_reg.h
index d859d61..5ffdea1 100644
--- a/drivers/gpu/msm/a2xx_reg.h
+++ b/drivers/gpu/msm/a2xx_reg.h
@@ -413,6 +413,7 @@
#define REG_A225_RB_COLOR_INFO3 0x2005
#define REG_A225_PC_MULTI_PRIM_IB_RESET_INDX 0x2103
#define REG_A225_GRAS_UCP0X 0x2340
+#define REG_A225_GRAS_UCP5W 0x2357
#define REG_A225_GRAS_UCP_ENABLED 0x2360
#endif /* __A200_REG_H */
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 0693f46..2681263 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -93,7 +93,6 @@
.pwrctrl = {
.regulator_name = "fs_gfx3d",
.irq_name = KGSL_3D0_IRQ,
- .src_clk_name = "src_clk",
},
.mutex = __MUTEX_INITIALIZER(device_3d0.dev.mutex),
.state = KGSL_STATE_INIT,
@@ -114,8 +113,10 @@
},
.pfp_fw = NULL,
.pm4_fw = NULL,
+ .wait_timeout = 10000, /* in milliseconds */
};
+
/*
* This is the master list of all GPU cores that are supported by this
* driver.
@@ -148,6 +149,9 @@
{ ADRENO_REV_A225, 2, 2, 0, 5,
"a225p5_pm4.fw", "a225_pfp.fw", &adreno_a2xx_gpudev,
1536, 768 },
+ { ADRENO_REV_A225, 2, 2, 0, 6,
+ "a225_pm4.fw", "a225_pfp.fw", &adreno_a2xx_gpudev,
+ 1536, 768 },
{ ADRENO_REV_A225, 2, 2, ANY_ID, ANY_ID,
"a225_pm4.fw", "a225_pfp.fw", &adreno_a2xx_gpudev,
1536, 768 },
@@ -269,10 +273,13 @@
int sizedwords = 0;
unsigned int mh_mmu_invalidate = 0x00000003; /*invalidate all and tc */
- /* If possible, then set the state via the command stream to avoid
- a CPU idle. Otherwise, use the default setstate which uses register
- writes */
- if (adreno_dev->drawctxt_active) {
+ /*
+ * If possible, then set the state via the command stream to avoid
+ * a CPU idle. Otherwise, use the default setstate which uses register
+ * writes For CFF dump we must idle and use the registers so that it is
+ * easier to filter out the mmu accesses from the dump
+ */
+ if (!kgsl_cff_dump_enable && adreno_dev->drawctxt_active) {
if (flags & KGSL_MMUFLAGS_PTUPDATE) {
/* wait for graphics pipe to be idle */
*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
@@ -357,6 +364,7 @@
{
unsigned int chipid = 0;
unsigned int coreid, majorid, minorid, patchid, revid;
+ uint32_t soc_platform_version = socinfo_get_version();
adreno_regread(device, REG_RBBM_PERIPHID1, &coreid);
adreno_regread(device, REG_RBBM_PERIPHID2, &majorid);
@@ -378,8 +386,12 @@
patchid = ((revid >> 16) & 0xFF);
/* 8x50 returns 0 for patch release, but it should be 1 */
+ /* 8960v3 returns 5 for patch release, but it should be 6 */
if (cpu_is_qsd8x50())
patchid = 1;
+ else if (cpu_is_msm8960() &&
+ SOCINFO_VERSION_MAJOR(soc_platform_version) == 3)
+ patchid = 6;
chipid |= (minorid << 8) | patchid;
@@ -435,8 +447,6 @@
adreno_dev = ADRENO_DEVICE(device);
device->parentdev = &pdev->dev;
- adreno_dev->wait_timeout = 10000; /* default value in milliseconds */
-
init_completion(&device->recovery_gate);
status = adreno_ringbuffer_init(device);
@@ -837,6 +847,12 @@
return status;
}
+static inline void adreno_poke(struct kgsl_device *device)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ adreno_regwrite(device, REG_CP_RB_WPTR, adreno_dev->ringbuffer.wptr);
+}
+
/* Caller must hold the device mutex. */
int adreno_idle(struct kgsl_device *device, unsigned int timeout)
{
@@ -855,6 +871,7 @@
retry:
if (rb->flags & KGSL_FLAGS_STARTED) {
do {
+ adreno_poke(device);
GSL_RB_GET_READPTR(rb, &rb->rptr);
if (time_after(jiffies, wait_time)) {
KGSL_DRV_ERR(device, "rptr: %x, wptr: %x\n",
@@ -920,29 +937,27 @@
return status;
}
-uint8_t *kgsl_sharedmem_convertaddr(struct kgsl_device *device,
- unsigned int pt_base, unsigned int gpuaddr, unsigned int *size)
+const struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device,
+ unsigned int pt_base,
+ unsigned int gpuaddr,
+ unsigned int size)
{
- uint8_t *result = NULL;
+ struct kgsl_memdesc *result = NULL;
struct kgsl_mem_entry *entry;
struct kgsl_process_private *priv;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_ringbuffer *ringbuffer = &adreno_dev->ringbuffer;
+ struct kgsl_context *context;
+ int next = 0;
- if (kgsl_gpuaddr_in_memdesc(&ringbuffer->buffer_desc, gpuaddr)) {
- return kgsl_gpuaddr_to_vaddr(&ringbuffer->buffer_desc,
- gpuaddr, size);
- }
+ if (kgsl_gpuaddr_in_memdesc(&ringbuffer->buffer_desc, gpuaddr, size))
+ return &ringbuffer->buffer_desc;
- if (kgsl_gpuaddr_in_memdesc(&ringbuffer->memptrs_desc, gpuaddr)) {
- return kgsl_gpuaddr_to_vaddr(&ringbuffer->memptrs_desc,
- gpuaddr, size);
- }
+ if (kgsl_gpuaddr_in_memdesc(&ringbuffer->memptrs_desc, gpuaddr, size))
+ return &ringbuffer->memptrs_desc;
- if (kgsl_gpuaddr_in_memdesc(&device->memstore, gpuaddr)) {
- return kgsl_gpuaddr_to_vaddr(&device->memstore,
- gpuaddr, size);
- }
+ if (kgsl_gpuaddr_in_memdesc(&device->memstore, gpuaddr, size))
+ return &device->memstore;
mutex_lock(&kgsl_driver.process_mutex);
list_for_each_entry(priv, &kgsl_driver.process_list, list) {
@@ -952,8 +967,7 @@
entry = kgsl_sharedmem_find_region(priv, gpuaddr,
sizeof(unsigned int));
if (entry) {
- result = kgsl_gpuaddr_to_vaddr(&entry->memdesc,
- gpuaddr, size);
+ result = &entry->memdesc;
spin_unlock(&priv->mem_lock);
mutex_unlock(&kgsl_driver.process_mutex);
return result;
@@ -964,14 +978,52 @@
BUG_ON(!mutex_is_locked(&device->mutex));
list_for_each_entry(entry, &device->memqueue, list) {
- if (kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr)) {
- result = kgsl_gpuaddr_to_vaddr(&entry->memdesc,
- gpuaddr, size);
- break;
+ if (kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr, size)) {
+ result = &entry->memdesc;
+ return result;
}
}
- return result;
+
+ while (1) {
+ struct adreno_context *adreno_context = NULL;
+ struct kgsl_memdesc *gpustate;
+ struct kgsl_memdesc *gmemshadow;
+ context = idr_get_next(&device->context_idr, &next);
+ if (context == NULL)
+ break;
+
+ adreno_context = (struct adreno_context *)context->devctxt;
+
+ if (!kgsl_mmu_pt_equal(adreno_context->pagetable, pt_base))
+ continue;
+
+ gpustate = &adreno_context->gpustate;
+ if (kgsl_gpuaddr_in_memdesc(gpustate, gpuaddr, size)) {
+ result = gpustate;
+ return result;
+ }
+ gmemshadow = &adreno_context->context_gmem_shadow.gmemshadow;
+ if (kgsl_gpuaddr_in_memdesc(gmemshadow, gpuaddr, size)) {
+ result = gmemshadow;
+ return result;
+ }
+
+ next = next + 1;
+ }
+
+ return NULL;
+
+}
+
+uint8_t *adreno_convertaddr(struct kgsl_device *device, unsigned int pt_base,
+ unsigned int gpuaddr, unsigned int size)
+{
+ const struct kgsl_memdesc *memdesc;
+
+ memdesc = adreno_find_region(device, pt_base, gpuaddr, size);
+
+ return memdesc ? kgsl_gpuaddr_to_vaddr(memdesc, gpuaddr) : NULL;
}
void adreno_regread(struct kgsl_device *device, unsigned int offsetwords,
@@ -1028,7 +1080,7 @@
kgsl_sharedmem_readl(&device->memstore, &ref_ts,
KGSL_DEVICE_MEMSTORE_OFFSET(ref_wait_ts));
mb();
- if (timestamp_cmp(ref_ts, timestamp)) {
+ if (timestamp_cmp(ref_ts, timestamp) >= 0) {
kgsl_sharedmem_writel(&device->memstore,
KGSL_DEVICE_MEMSTORE_OFFSET(ref_wait_ts),
timestamp);
@@ -1083,57 +1135,79 @@
static uint io_cnt;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+ int retries;
+ unsigned int msecs_first;
+ unsigned int msecs_part;
/* Don't wait forever, set a max value for now */
if (msecs == -1)
msecs = adreno_dev->wait_timeout;
- if (timestamp != adreno_dev->ringbuffer.timestamp &&
- timestamp_cmp(timestamp,
- adreno_dev->ringbuffer.timestamp)) {
+ if (timestamp_cmp(timestamp, adreno_dev->ringbuffer.timestamp) > 0) {
KGSL_DRV_ERR(device, "Cannot wait for invalid ts: %x, "
"rb->timestamp: %x\n",
timestamp, adreno_dev->ringbuffer.timestamp);
status = -EINVAL;
goto done;
}
- if (!kgsl_check_timestamp(device, timestamp)) {
- io_cnt = (io_cnt + 1) % 100;
- if (io_cnt < pwr->pwrlevels[pwr->active_pwrlevel].io_fraction)
- io = 0;
- mutex_unlock(&device->mutex);
- /* We need to make sure that the process is placed in wait-q
- * before its condition is called */
- status = kgsl_wait_event_interruptible_timeout(
- device->wait_queue,
- kgsl_check_interrupt_timestamp(device,
- timestamp),
- msecs_to_jiffies(msecs), io);
- mutex_lock(&device->mutex);
- if (status > 0)
- status = 0;
- else if (status == 0) {
- if (!kgsl_check_timestamp(device, timestamp)) {
- status = -ETIMEDOUT;
- KGSL_DRV_ERR(device,
- "Device hang detected while waiting "
- "for timestamp: %x, last "
- "submitted(rb->timestamp): %x, wptr: "
- "%x\n", timestamp,
- adreno_dev->ringbuffer.timestamp,
- adreno_dev->ringbuffer.wptr);
- if (!adreno_dump_and_recover(device)) {
- /* wait for idle after recovery as the
- * timestamp that this process wanted
- * to wait on may be invalid */
- if (!adreno_idle(device,
- KGSL_TIMEOUT_DEFAULT))
- status = 0;
- }
+ /* Keep the first timeout as 100msecs before rewriting
+ * the WPTR. Less visible impact if the WPTR has not
+ * been updated properly.
+ */
+ msecs_first = (msecs <= 100) ? ((msecs + 4) / 5) : 100;
+ msecs_part = (msecs - msecs_first + 3) / 4;
+ for (retries = 0; retries < 5; retries++) {
+ if (!kgsl_check_timestamp(device, timestamp)) {
+ adreno_poke(device);
+ io_cnt = (io_cnt + 1) % 100;
+ if (io_cnt <
+ pwr->pwrlevels[pwr->active_pwrlevel].
+ io_fraction)
+ io = 0;
+ mutex_unlock(&device->mutex);
+ /* We need to make sure that the process is
+ * placed in wait-q before its condition is called
+ */
+ status = kgsl_wait_event_interruptible_timeout(
+ device->wait_queue,
+ kgsl_check_interrupt_timestamp(device,
+ timestamp),
+ msecs_to_jiffies(retries ?
+ msecs_part : msecs_first), io);
+ mutex_lock(&device->mutex);
+
+ if (status > 0) {
+ /*completed before the wait finished */
+ status = 0;
+ goto done;
+ } else if (status < 0) {
+ /*an error occurred*/
+ goto done;
}
+ /*this wait timed out*/
}
}
+ if (!kgsl_check_timestamp(device, timestamp)) {
+ status = -ETIMEDOUT;
+ KGSL_DRV_ERR(device,
+ "Device hang detected while waiting "
+ "for timestamp: %x, last "
+ "submitted(rb->timestamp): %x, wptr: "
+ "%x\n", timestamp,
+ adreno_dev->ringbuffer.timestamp,
+ adreno_dev->ringbuffer.wptr);
+ if (!adreno_dump_and_recover(device)) {
+ /* wait for idle after recovery as the
+ * timestamp that this process wanted
+ * to wait on may be invalid */
+ if (!adreno_idle(device,
+ KGSL_TIMEOUT_DEFAULT))
+ status = 0;
+ }
+ } else {
+ status = 0;
+ }
done:
return (int)status;
@@ -1243,6 +1317,18 @@
adreno_dev->gpudev->irq_control(adreno_dev, state);
}
+static unsigned int adreno_gpuid(struct kgsl_device *device)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+ /* Standard KGSL gpuid format:
+ * top word is 0x0002 for 2D or 0x0003 for 3D
+ * Bottom word is core specific identifer
+ */
+
+ return (0x0003 << 16) | ((int) adreno_dev->gpurev);
+}
+
static const struct kgsl_functable adreno_functable = {
/* Mandatory functions */
.regread = adreno_regread,
@@ -1261,6 +1347,7 @@
.cleanup_pt = adreno_cleanup_pt,
.power_stats = adreno_power_stats,
.irqctrl = adreno_irqctrl,
+ .gpuid = adreno_gpuid,
/* Optional functions */
.setstate = adreno_setstate,
.drawctxt_create = adreno_drawctxt_create,
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 0776a24..99c6c52 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -43,6 +43,7 @@
*/
#define ADRENO_ISTORE_BYTES 12
#define ADRENO_ISTORE_WORDS 3
+#define ADRENO_ISTORE_START 0x5000
enum adreno_gpurev {
ADRENO_REV_UNKNOWN = 0,
@@ -93,8 +94,13 @@
void adreno_regwrite(struct kgsl_device *device, unsigned int offsetwords,
unsigned int value);
-uint8_t *kgsl_sharedmem_convertaddr(struct kgsl_device *device,
- unsigned int pt_base, unsigned int gpuaddr, unsigned int *size);
+const struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device,
+ unsigned int pt_base,
+ unsigned int gpuaddr,
+ unsigned int size);
+
+uint8_t *adreno_convertaddr(struct kgsl_device *device,
+ unsigned int pt_base, unsigned int gpuaddr, unsigned int size);
static inline int adreno_is_a200(struct adreno_device *adreno_dev)
{
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index 6003846..d083586 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -15,6 +15,7 @@
#include "kgsl_sharedmem.h"
#include "kgsl_cffdump.h"
#include "adreno.h"
+#include "adreno_a2xx_trace.h"
/*
*
@@ -408,7 +409,8 @@
REG_A220_PC_VERTEX_REUSE_BLOCK_CNTL,
REG_A220_PC_VERTEX_REUSE_BLOCK_CNTL,
REG_RB_COPY_CONTROL, REG_RB_DEPTH_CLEAR,
- REG_A225_GRAS_UCP0X, REG_A225_GRAS_UCP_ENABLED
+ REG_A225_GRAS_UCP0X, REG_A225_GRAS_UCP5W,
+ REG_A225_GRAS_UCP_ENABLED, REG_A225_GRAS_UCP_ENABLED
};
@@ -597,7 +599,7 @@
/* Repartition shaders */
*cmds++ = cp_type0_packet(REG_SQ_INST_STORE_MANAGMENT, 1);
- *cmds++ = 0x180;
+ *cmds++ = adreno_dev->pix_shader_start;
/* Invalidate Vertex & Pixel instruction code address and sizes */
*cmds++ = cp_type3_packet(CP_INVALIDATE_STATE, 1);
@@ -799,7 +801,7 @@
/* Repartition shaders */
*cmds++ = cp_type0_packet(REG_SQ_INST_STORE_MANAGMENT, 1);
- *cmds++ = 0x180;
+ *cmds++ = adreno_dev->pix_shader_start;
/* Invalidate Vertex & Pixel instruction code address and sizes */
*cmds++ = cp_type3_packet(CP_INVALIDATE_STATE, 1);
@@ -1322,6 +1324,7 @@
struct adreno_context *context)
{
struct kgsl_device *device = &adreno_dev->dev;
+ unsigned int cmd[22];
if (context == NULL)
return;
@@ -1363,6 +1366,30 @@
context->chicken_restore, 3);
context->flags |= CTXT_FLAGS_GMEM_RESTORE;
+ } else if (adreno_is_a225(adreno_dev)) {
+ unsigned int *cmds = &cmd[0];
+ /*
+ * Issue an empty draw call to avoid possible hangs due to
+ * repeated idles without intervening draw calls.
+ * On adreno 225 the PC block has a cache that is only
+ * flushed on draw calls and repeated idles can make it
+ * overflow. The gmem save path contains draw calls so
+ * this workaround isn't needed there.
+ */
+ *cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
+ *cmds++ = (0x4 << 16) | (REG_PA_SU_SC_MODE_CNTL - 0x2000);
+ *cmds++ = 0;
+ *cmds++ = cp_type3_packet(CP_DRAW_INDX, 5);
+ *cmds++ = 0;
+ *cmds++ = 1<<14;
+ *cmds++ = 0;
+ *cmds++ = device->mmu.setstate_memory.gpuaddr;
+ *cmds++ = 0;
+ *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+ *cmds++ = 0x00000000;
+
+ adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_PMODE,
+ &cmd[0], 11);
}
}
@@ -1485,6 +1512,9 @@
KGSL_DRV_WARN(device,
"Looped %d times to read REG_CP_INT_STATUS\n",
num_reads);
+
+ trace_kgsl_a2xx_irq_status(device, master_status, status);
+
if (!status) {
if (master_status & MASTER_INT_SIGNAL__CP_INT_STAT) {
/* This indicates that we could not read CP_INT_STAT.
diff --git a/include/linux/platform_data/usb_rmnet.h b/drivers/gpu/msm/adreno_a2xx_trace.c
similarity index 74%
copy from include/linux/platform_data/usb_rmnet.h
copy to drivers/gpu/msm/adreno_a2xx_trace.c
index 68c0db7..c91d1a0 100644
--- a/include/linux/platform_data/usb_rmnet.h
+++ b/drivers/gpu/msm/adreno_a2xx_trace.c
@@ -8,16 +8,12 @@
* 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 "kgsl.h"
+#include "adreno.h"
-#ifndef __LINUX_USB_GADGET_RMNET_H__
-#define __LINUX_USB_GADGET_RMNET_H__
-
-#include <linux/platform_device.h>
-
-struct usb_rmnet_pdata {
- unsigned num_instances;
-};
-
-#endif
+/* Instantiate tracepoints */
+#define CREATE_TRACE_POINTS
+#include "adreno_a2xx_trace.h"
diff --git a/drivers/gpu/msm/adreno_a2xx_trace.h b/drivers/gpu/msm/adreno_a2xx_trace.h
new file mode 100644
index 0000000..2528e15
--- /dev/null
+++ b/drivers/gpu/msm/adreno_a2xx_trace.h
@@ -0,0 +1,78 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ *
+ */
+
+#if !defined(_ADRENO_A2XX_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _ADRENO_A2XX_TRACE_H
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM kgsl
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE adreno_a2xx_trace
+
+#include <linux/tracepoint.h>
+
+struct kgsl_device;
+
+/*
+ * Tracepoint for a2xx irq. Includes status info
+ */
+TRACE_EVENT(kgsl_a2xx_irq_status,
+
+ TP_PROTO(struct kgsl_device *device, unsigned int master_status,
+ unsigned int status),
+
+ TP_ARGS(device, master_status, status),
+
+ TP_STRUCT__entry(
+ __string(device_name, device->name)
+ __field(unsigned int, master_status)
+ __field(unsigned int, status)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device_name, device->name);
+ __entry->master_status = master_status;
+ __entry->status = status;
+ ),
+
+ TP_printk(
+ "d_name=%s master=%s status=%s",
+ __get_str(device_name),
+ __entry->master_status ? __print_flags(__entry->master_status,
+ "|",
+ { MASTER_INT_SIGNAL__MH_INT_STAT, "MH" },
+ { MASTER_INT_SIGNAL__SQ_INT_STAT, "SQ" },
+ { MASTER_INT_SIGNAL__CP_INT_STAT, "CP" },
+ { MASTER_INT_SIGNAL__RBBM_INT_STAT, "RBBM" }) : "None",
+ __entry->status ? __print_flags(__entry->status, "|",
+ { CP_INT_CNTL__SW_INT_MASK, "SW" },
+ { CP_INT_CNTL__T0_PACKET_IN_IB_MASK,
+ "T0_PACKET_IN_IB" },
+ { CP_INT_CNTL__OPCODE_ERROR_MASK, "OPCODE_ERROR" },
+ { CP_INT_CNTL__PROTECTED_MODE_ERROR_MASK,
+ "PROTECTED_MODE_ERROR" },
+ { CP_INT_CNTL__RESERVED_BIT_ERROR_MASK,
+ "RESERVED_BIT_ERROR" },
+ { CP_INT_CNTL__IB_ERROR_MASK, "IB_ERROR" },
+ { CP_INT_CNTL__IB2_INT_MASK, "IB2" },
+ { CP_INT_CNTL__IB1_INT_MASK, "IB1" },
+ { CP_INT_CNTL__RB_INT_MASK, "RB" }) : "None"
+ )
+);
+
+#endif /* _ADRENO_A2XX_TRACE_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c
index 419ce9d..c1b9e4c 100644
--- a/drivers/gpu/msm/adreno_debugfs.c
+++ b/drivers/gpu/msm/adreno_debugfs.c
@@ -25,9 +25,6 @@
unsigned int kgsl_cff_dump_enable;
int kgsl_pm_regs_enabled;
-static uint32_t kgsl_ib_base;
-static uint32_t kgsl_ib_size;
-
static struct dentry *pm_d_debugfs;
static int pm_dump_set(void *data, u64 val)
@@ -115,98 +112,6 @@
return ss;
}
-static ssize_t kgsl_ib_dump_read(
- struct file *file,
- char __user *buff,
- size_t buff_count,
- loff_t *ppos)
-{
- int i, count = kgsl_ib_size, remaining, pos = 0, tot = 0, ss;
- struct kgsl_device *device = file->private_data;
- const int rowc = 32;
- unsigned int pt_base, ib_memsize;
- uint8_t *base_addr;
- char linebuf[80];
-
- if (!ppos || !device || !kgsl_ib_base)
- return 0;
-
- kgsl_regread(device, MH_MMU_PT_BASE, &pt_base);
- base_addr = kgsl_sharedmem_convertaddr(device, pt_base, kgsl_ib_base,
- &ib_memsize);
-
- if (!base_addr)
- return 0;
-
- pr_info("%s ppos=%ld, buff_count=%d, count=%d\n", __func__, (long)*ppos,
- buff_count, count);
- ss = snprintf(linebuf, sizeof(linebuf), "IB: base=%08x(%08x"
- "), size=%d, memsize=%d\n", kgsl_ib_base,
- (uint32_t)base_addr, kgsl_ib_size, ib_memsize);
- if (*ppos == 0) {
- if (copy_to_user(buff, linebuf, ss+1))
- return -EFAULT;
- tot += ss;
- buff += ss;
- *ppos += ss;
- }
- pos += ss;
- remaining = count;
- for (i = 0; i < count; i += rowc) {
- int linec = min(remaining, rowc);
-
- remaining -= rowc;
- ss = kgsl_hex_dump("IB: %05x: ", i, base_addr, rowc, linec,
- buff);
- if (ss < 0)
- return ss;
-
- if (pos >= *ppos) {
- if (tot+ss >= buff_count) {
- ss = copy_to_user(buff, "", 1);
- return tot;
- }
- tot += ss;
- buff += ss;
- *ppos += ss;
- }
- pos += ss;
- base_addr += linec;
- }
-
- return tot;
-}
-
-static ssize_t kgsl_ib_dump_write(
- struct file *file,
- const char __user *buff,
- size_t count,
- loff_t *ppos)
-{
- char local_buff[64];
-
- if (count >= sizeof(local_buff))
- return -EFAULT;
-
- if (copy_from_user(local_buff, buff, count))
- return -EFAULT;
-
- local_buff[count] = 0; /* end of string */
- sscanf(local_buff, "%x %d", &kgsl_ib_base, &kgsl_ib_size);
-
- pr_info("%s: base=%08X size=%d\n", __func__, kgsl_ib_base,
- kgsl_ib_size);
-
- return count;
-}
-
-static const struct file_operations kgsl_ib_dump_fops = {
- .open = kgsl_dbgfs_open,
- .release = kgsl_dbgfs_release,
- .read = kgsl_ib_dump_read,
- .write = kgsl_ib_dump_write,
-};
-
static int kgsl_regread_nolock(struct kgsl_device *device,
unsigned int offsetwords, unsigned int *value)
{
@@ -223,7 +128,6 @@
return 0;
}
-#define ADRENO_ISTORE_START 0x5000
static ssize_t kgsl_istore_read(
struct file *file,
char __user *buff,
@@ -429,8 +333,6 @@
if (!device->d_debugfs || IS_ERR(device->d_debugfs))
return;
- debugfs_create_file("ib_dump", 0600, device->d_debugfs, device,
- &kgsl_ib_dump_fops);
debugfs_create_file("istore", 0400, device->d_debugfs, device,
&kgsl_istore_fops);
debugfs_create_file("sx_debug", 0400, device->d_debugfs, device,
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index cc69360..c6b850e 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -247,9 +247,8 @@
static void dump_ib(struct kgsl_device *device, char* buffId, uint32_t pt_base,
uint32_t base_offset, uint32_t ib_base, uint32_t ib_size, bool dump)
{
- unsigned int memsize;
- uint8_t *base_addr = kgsl_sharedmem_convertaddr(device, pt_base,
- ib_base, &memsize);
+ uint8_t *base_addr = adreno_convertaddr(device, pt_base,
+ ib_base, ib_size*sizeof(uint32_t));
if (base_addr && dump)
print_hex_dump(KERN_ERR, buffId, DUMP_PREFIX_OFFSET,
@@ -277,14 +276,13 @@
int i, j;
uint32_t value;
uint32_t *ib1_addr;
- unsigned int memsize;
dump_ib(device, "IB1:", pt_base, base_offset, ib1_base,
ib1_size, dump);
/* fetch virtual address for given IB base */
- ib1_addr = (uint32_t *)kgsl_sharedmem_convertaddr(device, pt_base,
- ib1_base, &memsize);
+ ib1_addr = (uint32_t *)adreno_convertaddr(device, pt_base,
+ ib1_base, ib1_size*sizeof(uint32_t));
if (!ib1_addr)
return;
@@ -466,7 +464,7 @@
const uint32_t *rb_vaddr;
int num_item = 0;
int read_idx, write_idx;
- unsigned int ts_processed, rb_memsize;
+ unsigned int ts_processed;
static struct ib_list ib_list;
@@ -681,11 +679,16 @@
KGSL_LOG_DUMP(device, "RB: rd_addr:%8.8x rb_size:%d num_item:%d\n",
cp_rb_base, rb_count<<2, num_item);
- rb_vaddr = (const uint32_t *)kgsl_sharedmem_convertaddr(device,
- cur_pt_base, cp_rb_base, &rb_memsize);
+
+ if (adreno_dev->ringbuffer.buffer_desc.gpuaddr != cp_rb_base)
+ KGSL_LOG_POSTMORTEM_WRITE(device,
+ "rb address mismatch, should be 0x%08x\n",
+ adreno_dev->ringbuffer.buffer_desc.gpuaddr);
+
+ rb_vaddr = adreno_dev->ringbuffer.buffer_desc.hostptr;
if (!rb_vaddr) {
KGSL_LOG_POSTMORTEM_WRITE(device,
- "Can't fetch vaddr for CP_RB_BASE\n");
+ "rb has no kernel mapping!\n");
goto error_vfree;
}
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index e84d473..7a42dcd 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -20,10 +20,12 @@
#include <linux/android_pmem.h>
#include <linux/vmalloc.h>
#include <linux/pm_runtime.h>
+#include <linux/genlock.h>
#include <linux/ashmem.h>
#include <linux/major.h>
#include <linux/ion.h>
+#include <mach/socinfo.h>
#include "kgsl.h"
#include "kgsl_debugfs.h"
@@ -31,6 +33,7 @@
#include "kgsl_log.h"
#include "kgsl_sharedmem.h"
#include "kgsl_device.h"
+#include "kgsl_trace.h"
#undef MODULE_PARAM_PREFIX
#define MODULE_PARAM_PREFIX "kgsl."
@@ -46,6 +49,63 @@
static struct ion_client *kgsl_ion_client;
+#ifdef CONFIG_GENLOCK
+
+/**
+ * kgsl_add_event - Add a new timstamp event for the KGSL device
+ * @device - KGSL device for the new event
+ * @ts - the timestamp to trigger the event on
+ * @cb - callback function to call when the timestamp expires
+ * @priv - private data for the specific event type
+ *
+ * @returns - 0 on success or error code on failure
+ */
+
+static int kgsl_add_event(struct kgsl_device *device, u32 ts,
+ void (*cb)(struct kgsl_device *, void *, u32), void *priv)
+{
+ struct kgsl_event *event;
+ struct list_head *n;
+ unsigned int cur = device->ftbl->readtimestamp(device,
+ KGSL_TIMESTAMP_RETIRED);
+
+ if (cb == NULL)
+ return -EINVAL;
+
+ /* Check to see if the requested timestamp has already fired */
+
+ if (timestamp_cmp(cur, ts) >= 0) {
+ cb(device, priv, cur);
+ return 0;
+ }
+
+ event = kzalloc(sizeof(*event), GFP_KERNEL);
+ if (event == NULL)
+ return -ENOMEM;
+
+ event->timestamp = ts;
+ event->priv = priv;
+ event->func = cb;
+
+ /* Add the event in order to the list */
+
+ for (n = device->events.next ; n != &device->events; n = n->next) {
+ struct kgsl_event *e =
+ list_entry(n, struct kgsl_event, list);
+
+ if (timestamp_cmp(e->timestamp, ts) > 0) {
+ list_add(&event->list, n->prev);
+ break;
+ }
+ }
+
+ if (n == &device->events)
+ list_add_tail(&event->list, &device->events);
+
+ return 0;
+}
+#endif
+
static inline struct kgsl_mem_entry *
kgsl_mem_entry_create(void)
{
@@ -204,6 +264,7 @@
struct kgsl_device *device = container_of(work, struct kgsl_device,
ts_expired_ws);
struct kgsl_mem_entry *entry, *entry_tmp;
+ struct kgsl_event *event, *event_tmp;
uint32_t ts_processed;
mutex_lock(&device->mutex);
@@ -214,13 +275,25 @@
/* Flush the freememontimestamp queue */
list_for_each_entry_safe(entry, entry_tmp, &device->memqueue, list) {
- if (!timestamp_cmp(ts_processed, entry->free_timestamp))
+ if (timestamp_cmp(ts_processed, entry->free_timestamp) < 0)
break;
list_del(&entry->list);
kgsl_mem_entry_put(entry);
}
+ /* Process expired events */
+ list_for_each_entry_safe(event, event_tmp, &device->events, list) {
+ if (timestamp_cmp(ts_processed, event->timestamp) < 0)
+ break;
+
+ if (event->func)
+ event->func(device, event->priv, ts_processed);
+
+ list_del(&event->list);
+ kfree(event);
+ }
+
mutex_unlock(&device->mutex);
}
@@ -302,7 +375,7 @@
ts_processed = device->ftbl->readtimestamp(device,
KGSL_TIMESTAMP_RETIRED);
- return timestamp_cmp(ts_processed, timestamp);
+ return (timestamp_cmp(ts_processed, timestamp) >= 0);
}
EXPORT_SYMBOL(kgsl_check_timestamp);
@@ -701,9 +774,7 @@
BUG_ON(private == NULL);
list_for_each_entry(entry, &private->mem_list, list) {
- if (gpuaddr >= entry->memdesc.gpuaddr &&
- ((gpuaddr + size) <=
- (entry->memdesc.gpuaddr + entry->memdesc.size))) {
+ if (kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr, size)) {
result = entry;
break;
}
@@ -713,20 +784,6 @@
}
EXPORT_SYMBOL(kgsl_sharedmem_find_region);
-uint8_t *kgsl_gpuaddr_to_vaddr(const struct kgsl_memdesc *memdesc,
- unsigned int gpuaddr, unsigned int *size)
-{
- BUG_ON(memdesc->hostptr == NULL);
-
- if (memdesc->gpuaddr == 0 || (gpuaddr < memdesc->gpuaddr ||
- gpuaddr >= memdesc->gpuaddr + memdesc->size))
- return NULL;
-
- *size = memdesc->size - (gpuaddr - memdesc->gpuaddr);
- return memdesc->hostptr + (gpuaddr - memdesc->gpuaddr);
-}
-EXPORT_SYMBOL(kgsl_gpuaddr_to_vaddr);
-
/*call all ioctl sub functions with driver locked*/
static long kgsl_ioctl_device_getproperty(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
@@ -775,10 +832,14 @@
dev_priv->device->active_cnt++;
+ trace_kgsl_waittimestamp_entry(dev_priv->device, param);
+
result = dev_priv->device->ftbl->waittimestamp(dev_priv->device,
param->timestamp,
param->timeout);
+ trace_kgsl_waittimestamp_exit(dev_priv->device, result);
+
/* Fire off any pending suspend operations that are in flight */
INIT_COMPLETION(dev_priv->device->suspend_gate);
@@ -903,6 +964,8 @@
¶m->timestamp,
param->flags);
+ trace_kgsl_issueibcmds(dev_priv->device, param, result);
+
if (result != 0)
goto free_ibdesc;
@@ -936,6 +999,8 @@
dev_priv->device->ftbl->readtimestamp(dev_priv->device,
param->type);
+ trace_kgsl_readtimestamp(dev_priv->device, param);
+
return 0;
}
@@ -1599,11 +1664,6 @@
result = -EINVAL;
goto done;
}
- if (!entry->memdesc.hostptr)
- entry->memdesc.hostptr =
- kgsl_gpuaddr_to_vaddr(&entry->memdesc,
- param->gpuaddr, &entry->memdesc.size);
-
if (!entry->memdesc.hostptr) {
KGSL_CORE_ERR("invalid hostptr with gpuaddr %08x\n",
param->gpuaddr);
@@ -1675,6 +1735,114 @@
return result;
}
+#ifdef CONFIG_GENLOCK
+struct kgsl_genlock_event_priv {
+ struct genlock_handle *handle;
+ struct genlock *lock;
+};
+
+/**
+ * kgsl_genlock_event_cb - Event callback for a genlock timestamp event
+ * @device - The KGSL device that expired the timestamp
+ * @priv - private data for the event
+ * @timestamp - the timestamp that triggered the event
+ *
+ * Release a genlock lock following the expiration of a timestamp
+ */
+
+static void kgsl_genlock_event_cb(struct kgsl_device *device,
+ void *priv, u32 timestamp)
+{
+ struct kgsl_genlock_event_priv *ev = priv;
+ int ret;
+
+ ret = genlock_lock(ev->handle, GENLOCK_UNLOCK, 0, 0);
+ if (ret)
+ KGSL_CORE_ERR("Error while unlocking genlock: %d\n", ret);
+
+ genlock_put_handle(ev->handle);
+
+ kfree(ev);
+}
+
+/**
+ * kgsl_add_genlock-event - Create a new genlock event
+ * @device - KGSL device to create the event on
+ * @timestamp - Timestamp to trigger the event
+ * @data - User space buffer containing struct kgsl_genlock_event_priv
+ * @len - length of the userspace buffer
+ * @returns 0 on success or error code on error
+ *
+ * Attack to a genlock handle and register an event to release the
+ * genlock lock when the timestamp expires
+ */
+
+static int kgsl_add_genlock_event(struct kgsl_device *device,
+ u32 timestamp, void __user *data, int len)
+{
+ struct kgsl_genlock_event_priv *event;
+ struct kgsl_timestamp_event_genlock priv;
+ int ret;
+
+ if (len != sizeof(priv))
+ return -EINVAL;
+
+ if (copy_from_user(&priv, data, sizeof(priv)))
+ return -EFAULT;
+
+ event = kzalloc(sizeof(*event), GFP_KERNEL);
+
+ if (event == NULL)
+ return -ENOMEM;
+
+ event->handle = genlock_get_handle_fd(priv.handle);
+
+ if (IS_ERR(event->handle)) {
+ int ret = PTR_ERR(event->handle);
+ kfree(event);
+ return ret;
+ }
+
+ ret = kgsl_add_event(device, timestamp, kgsl_genlock_event_cb, event);
+ if (ret)
+ kfree(event);
+
+ return ret;
+}
+#else
+static long kgsl_add_genlock_event(struct kgsl_device *device,
+ u32 timestamp, void __user *data, int len)
+{
+ return -EINVAL;
+}
+#endif
+
+/**
+ * kgsl_ioctl_timestamp_event - Register a new timestamp event from userspace
+ * @dev_priv - pointer to the private device structure
+ * @cmd - the ioctl cmd passed from kgsl_ioctl
+ * @data - the user data buffer from kgsl_ioctl
+ * @returns 0 on success or error code on failure
+ */
+
+static long kgsl_ioctl_timestamp_event(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data)
+{
+ struct kgsl_timestamp_event *param = data;
+ int ret;
+
+ switch (param->type) {
+ case KGSL_TIMESTAMP_EVENT_GENLOCK:
+ ret = kgsl_add_genlock_event(dev_priv->device,
+ param->timestamp, param->priv, param->len);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
typedef long (*kgsl_ioctl_func_t)(struct kgsl_device_private *,
unsigned int, void *);
@@ -1716,6 +1884,8 @@
kgsl_ioctl_cff_syncmem, 0),
KGSL_IOCTL_FUNC(IOCTL_KGSL_CFF_USER_EVENT,
kgsl_ioctl_cff_user_event, 0),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_TIMESTAMP_EVENT,
+ kgsl_ioctl_timestamp_event, 1),
};
static long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
@@ -1939,8 +2109,8 @@
kgsl_cffdump_close(device->id);
kgsl_pwrctrl_uninit_sysfs(device);
- wake_lock_destroy(&device->idle_wakelock);
- pm_qos_remove_request(&device->pm_qos_req_dma);
+ if (cpu_is_msm8x60())
+ wake_lock_destroy(&device->idle_wakelock);
idr_destroy(&device->context_idr);
@@ -2020,6 +2190,7 @@
INIT_WORK(&device->ts_expired_ws, kgsl_timestamp_expired);
INIT_LIST_HEAD(&device->memqueue);
+ INIT_LIST_HEAD(&device->events);
ret = kgsl_mmu_init(device);
if (ret != 0)
@@ -2031,9 +2202,9 @@
if (ret != 0)
goto err_close_mmu;
- wake_lock_init(&device->idle_wakelock, WAKE_LOCK_IDLE, device->name);
- pm_qos_add_request(&device->pm_qos_req_dma, PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
+ if (cpu_is_msm8x60())
+ wake_lock_init(&device->idle_wakelock,
+ WAKE_LOCK_IDLE, device->name);
idr_init(&device->context_idr);
@@ -2264,8 +2435,6 @@
if (result)
goto err;
- kgsl_mmu_set_mmutype(ksgl_mmu_type);
-
return 0;
err:
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index b5c24f0..1135adb 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -145,8 +145,6 @@
#endif
void kgsl_mem_entry_destroy(struct kref *kref);
-uint8_t *kgsl_gpuaddr_to_vaddr(const struct kgsl_memdesc *memdesc,
- unsigned int gpuaddr, unsigned int *size);
struct kgsl_mem_entry *kgsl_sharedmem_find_region(
struct kgsl_process_private *private, unsigned int gpuaddr,
size_t size);
@@ -175,19 +173,33 @@
#endif
static inline int kgsl_gpuaddr_in_memdesc(const struct kgsl_memdesc *memdesc,
- unsigned int gpuaddr)
+ unsigned int gpuaddr, unsigned int size)
{
- if (gpuaddr >= memdesc->gpuaddr && (gpuaddr + sizeof(unsigned int)) <=
- (memdesc->gpuaddr + memdesc->size)) {
+ if (gpuaddr >= memdesc->gpuaddr &&
+ ((gpuaddr + size) <= (memdesc->gpuaddr + memdesc->size))) {
return 1;
}
return 0;
}
+static inline uint8_t *kgsl_gpuaddr_to_vaddr(const struct kgsl_memdesc *memdesc,
+ unsigned int gpuaddr)
+{
+ if (memdesc->hostptr == NULL || memdesc->gpuaddr == 0 ||
+ (gpuaddr < memdesc->gpuaddr ||
+ gpuaddr >= memdesc->gpuaddr + memdesc->size))
+ return NULL;
-static inline bool timestamp_cmp(unsigned int new, unsigned int old)
+ return memdesc->hostptr + (gpuaddr - memdesc->gpuaddr);
+}
+
+static inline int timestamp_cmp(unsigned int new, unsigned int old)
{
int ts_diff = new - old;
- return (ts_diff >= 0) || (ts_diff < -20000);
+
+ if (ts_diff == 0)
+ return 0;
+
+ return ((ts_diff > 0) || (ts_diff < -20000)) ? 1 : -1;
}
static inline void
diff --git a/drivers/gpu/msm/kgsl_cffdump.c b/drivers/gpu/msm/kgsl_cffdump.c
index aa33152..e9455cb 100644
--- a/drivers/gpu/msm/kgsl_cffdump.c
+++ b/drivers/gpu/msm/kgsl_cffdump.c
@@ -231,8 +231,6 @@
spin_lock(&cffdump_lock);
if (opcode == CFF_OP_WRITE_MEM) {
- if (op1 < 0x40000000 || op1 >= 0x60000000)
- KGSL_CORE_ERR("addr out-of-range: op1=%08x", op1);
if ((cff_op_write_membuf.addr != op1 &&
cff_op_write_membuf.count)
|| (cff_op_write_membuf.count == MEMBUF_SIZE))
@@ -360,15 +358,7 @@
void kgsl_cffdump_open(enum kgsl_deviceid device_id)
{
- /*TODO: move this to where we can report correct gmemsize*/
- unsigned int va_base;
-
- if (cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_msm8930())
- va_base = 0x40000000;
- else
- va_base = 0x20000000;
-
- kgsl_cffdump_memory_base(device_id, va_base,
+ kgsl_cffdump_memory_base(device_id, KGSL_PAGETABLE_BASE,
CONFIG_MSM_KGSL_PAGE_TABLE_SIZE, SZ_256K);
}
@@ -401,8 +391,6 @@
bool clean_cache)
{
const void *src;
- uint host_size;
- uint physaddr;
if (!kgsl_cff_dump_enable)
return;
@@ -422,13 +410,9 @@
}
memdesc = &entry->memdesc;
}
- BUG_ON(memdesc->gpuaddr == 0);
- BUG_ON(gpuaddr == 0);
- physaddr = kgsl_get_realaddr(memdesc) + (gpuaddr - memdesc->gpuaddr);
-
- src = kgsl_gpuaddr_to_vaddr(memdesc, gpuaddr, &host_size);
- if (src == NULL || host_size < sizebytes) {
- KGSL_CORE_ERR("did not find mapping for "
+ src = (uint *)kgsl_gpuaddr_to_vaddr(memdesc, gpuaddr);
+ if (memdesc->hostptr == NULL) {
+ KGSL_CORE_ERR("no kernel mapping for "
"gpuaddr: 0x%08x, m->host: 0x%p, phys: 0x%08x\n",
gpuaddr, memdesc->hostptr, memdesc->physaddr);
return;
@@ -444,7 +428,6 @@
KGSL_CACHE_OP_INV);
}
- BUG_ON(physaddr > 0x66000000 && physaddr < 0x66ffffff);
while (sizebytes > 3) {
cffdump_printline(-1, CFF_OP_WRITE_MEM, gpuaddr, *(uint *)src,
0, 0, 0);
@@ -462,7 +445,6 @@
if (!kgsl_cff_dump_enable)
return;
- BUG_ON(addr > 0x66000000 && addr < 0x66ffffff);
while (sizebytes > 3) {
/* Use 32bit memory writes as long as there's at least
* 4 bytes left */
@@ -575,7 +557,6 @@
{
static uint level; /* recursion level */
bool ret = true;
- uint host_size;
uint *hostaddr, *hoststart;
int dwords_left = sizedwords; /* dwords left in the current command
buffer */
@@ -596,10 +577,9 @@
}
memdesc = &entry->memdesc;
}
-
- hostaddr = (uint *)kgsl_gpuaddr_to_vaddr(memdesc, gpuaddr, &host_size);
+ hostaddr = (uint *)kgsl_gpuaddr_to_vaddr(memdesc, gpuaddr);
if (hostaddr == NULL) {
- KGSL_CORE_ERR("did not find mapping for "
+ KGSL_CORE_ERR("no kernel mapping for "
"gpuaddr: 0x%08x\n", gpuaddr);
return true;
}
@@ -608,14 +588,9 @@
level++;
- if (!memdesc->physaddr) {
- KGSL_CORE_ERR("no physaddr");
- } else {
- mb();
- kgsl_cache_range_op((struct kgsl_memdesc *)memdesc,
+ mb();
+ kgsl_cache_range_op((struct kgsl_memdesc *)memdesc,
KGSL_CACHE_OP_INV);
- }
-
#ifdef DEBUG
pr_info("kgsl: cffdump: ib: gpuaddr:0x%08x, wc:%d, hptr:%p\n",
gpuaddr, sizedwords, hostaddr);
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 6ae9258..3ef11ce 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -15,7 +15,6 @@
#include <linux/idr.h>
#include <linux/wakelock.h>
-#include <linux/pm_qos_params.h>
#include <linux/earlysuspend.h>
#include "kgsl.h"
@@ -90,6 +89,7 @@
void (*power_stats)(struct kgsl_device *device,
struct kgsl_power_stats *stats);
void (*irqctrl)(struct kgsl_device *device, int state);
+ unsigned int (*gpuid)(struct kgsl_device *device);
/* Optional functions - these functions are not mandatory. The
driver will check that the function pointer is not NULL before
calling the hook */
@@ -119,6 +119,14 @@
int mpu_range;
};
+struct kgsl_event {
+ uint32_t timestamp;
+ void (*func)(struct kgsl_device *, void *, u32);
+ void *priv;
+ struct list_head list;
+};
+
+
struct kgsl_device {
struct device *dev;
const char *name;
@@ -165,8 +173,8 @@
struct wake_lock idle_wakelock;
struct kgsl_pwrscale pwrscale;
struct kobject pwrscale_kobj;
- struct pm_qos_request_list pm_qos_req_dma;
struct work_struct ts_expired_ws;
+ struct list_head events;
};
struct kgsl_context {
@@ -233,6 +241,11 @@
return device->ftbl->idle(device, timeout);
}
+static inline unsigned int kgsl_gpuid(struct kgsl_device *device)
+{
+ return device->ftbl->gpuid(device);
+}
+
static inline int kgsl_create_device_sysfs_files(struct device *root,
const struct device_attribute **list)
{
@@ -270,10 +283,11 @@
static inline int kgsl_create_device_workqueue(struct kgsl_device *device)
{
- device->work_queue = create_workqueue(device->name);
+ device->work_queue = create_singlethread_workqueue(device->name);
if (!device->work_queue) {
- KGSL_DRV_ERR(device, "create_workqueue(%s) failed\n",
- device->name);
+ KGSL_DRV_ERR(device,
+ "create_singlethread_workqueue(%s) failed\n",
+ device->name);
return -EINVAL;
}
return 0;
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 715b9d6..36248ef 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -22,6 +22,7 @@
#include "kgsl_mmu.h"
#include "kgsl_device.h"
#include "kgsl_sharedmem.h"
+#include "adreno_postmortem.h"
#define KGSL_MMU_ALIGN_SHIFT 13
#define KGSL_MMU_ALIGN_MASK (~((1 << KGSL_MMU_ALIGN_SHIFT) - 1))
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 8ec9572..dd7b1d6 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -13,6 +13,7 @@
#include <linux/interrupt.h>
#include <mach/msm_iomap.h>
#include <mach/msm_bus.h>
+#include <mach/socinfo.h>
#include "kgsl.h"
#include "kgsl_pwrscale.h"
@@ -23,10 +24,37 @@
#define KGSL_PWRFLAGS_AXI_ON 2
#define KGSL_PWRFLAGS_IRQ_ON 3
-#define GPU_SWFI_LATENCY 3
#define UPDATE_BUSY_VAL 1000000
#define UPDATE_BUSY 50
+struct clk_pair {
+ const char *name;
+ uint map;
+};
+
+struct clk_pair clks[KGSL_MAX_CLKS] = {
+ {
+ .name = "src_clk",
+ .map = KGSL_CLK_SRC,
+ },
+ {
+ .name = "core_clk",
+ .map = KGSL_CLK_CORE,
+ },
+ {
+ .name = "iface_clk",
+ .map = KGSL_CLK_IFACE,
+ },
+ {
+ .name = "mem_clk",
+ .map = KGSL_CLK_MEM,
+ },
+ {
+ .name = "mem_iface_clk",
+ .map = KGSL_CLK_MEM_IFACE,
+ },
+};
+
void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
unsigned int new_level)
{
@@ -434,49 +462,43 @@
struct platform_device *pdev =
container_of(device->parentdev, struct platform_device, dev);
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
- struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
- struct kgsl_device_pwr_data *pdata_pwr = &pdata_dev->pwr_data;
- const char *clk_names[KGSL_MAX_CLKS] = {pwr->src_clk_name,
- pdata_dev->clk.name.clk,
- pdata_dev->clk.name.pclk,
- pdata_dev->imem_clk_name.clk,
- pdata_dev->imem_clk_name.pclk};
+ struct kgsl_device_platform_data *pdata = pdev->dev.platform_data;
/*acquire clocks */
- for (i = 1; i < KGSL_MAX_CLKS; i++) {
- if (clk_names[i]) {
- clk = clk_get(&pdev->dev, clk_names[i]);
+ for (i = 0; i < KGSL_MAX_CLKS; i++) {
+ if (pdata->clk_map & clks[i].map) {
+ clk = clk_get(&pdev->dev, clks[i].name);
if (IS_ERR(clk))
goto clk_err;
pwr->grp_clks[i] = clk;
}
}
/* Make sure we have a source clk for freq setting */
- clk = clk_get(&pdev->dev, clk_names[0]);
- pwr->grp_clks[0] = (IS_ERR(clk)) ? pwr->grp_clks[1] : clk;
+ if (pwr->grp_clks[0] == NULL)
+ pwr->grp_clks[0] = pwr->grp_clks[1];
/* put the AXI bus into asynchronous mode with the graphics cores */
- if (pdata_pwr->set_grp_async != NULL)
- pdata_pwr->set_grp_async();
+ if (pdata->set_grp_async != NULL)
+ pdata->set_grp_async();
- if (pdata_pwr->num_levels > KGSL_MAX_PWRLEVELS) {
+ if (pdata->num_levels > KGSL_MAX_PWRLEVELS) {
KGSL_PWR_ERR(device, "invalid power level count: %d\n",
- pdata_pwr->num_levels);
+ pdata->num_levels);
result = -EINVAL;
goto done;
}
- pwr->num_pwrlevels = pdata_pwr->num_levels;
- pwr->active_pwrlevel = pdata_pwr->init_level;
- for (i = 0; i < pdata_pwr->num_levels; i++) {
+ pwr->num_pwrlevels = pdata->num_levels;
+ pwr->active_pwrlevel = pdata->init_level;
+ for (i = 0; i < pdata->num_levels; i++) {
pwr->pwrlevels[i].gpu_freq =
- (pdata_pwr->pwrlevel[i].gpu_freq > 0) ?
+ (pdata->pwrlevel[i].gpu_freq > 0) ?
clk_round_rate(pwr->grp_clks[0],
- pdata_pwr->pwrlevel[i].
+ pdata->pwrlevel[i].
gpu_freq) : 0;
pwr->pwrlevels[i].bus_freq =
- pdata_pwr->pwrlevel[i].bus_freq;
+ pdata->pwrlevel[i].bus_freq;
pwr->pwrlevels[i].io_fraction =
- pdata_pwr->pwrlevel[i].io_fraction;
+ pdata->pwrlevel[i].io_fraction;
}
/* Do not set_rate for targets in sync with AXI */
if (pwr->pwrlevels[0].gpu_freq > 0)
@@ -489,8 +511,8 @@
pwr->power_flags = 0;
- pwr->nap_allowed = pdata_pwr->nap_allowed;
- pwr->interval_timeout = pdata_pwr->idle_timeout;
+ pwr->nap_allowed = pdata->nap_allowed;
+ pwr->interval_timeout = pdata->idle_timeout;
pwr->ebi1_clk = clk_get(&pdev->dev, "bus_clk");
if (IS_ERR(pwr->ebi1_clk))
pwr->ebi1_clk = NULL;
@@ -498,15 +520,14 @@
clk_set_rate(pwr->ebi1_clk,
pwr->pwrlevels[pwr->active_pwrlevel].
bus_freq);
- if (pdata_dev->clk.bus_scale_table != NULL) {
- pwr->pcl =
- msm_bus_scale_register_client(pdata_dev->clk.
+ if (pdata->bus_scale_table != NULL) {
+ pwr->pcl = msm_bus_scale_register_client(pdata->
bus_scale_table);
if (!pwr->pcl) {
KGSL_PWR_ERR(device,
"msm_bus_scale_register_client failed: "
"id %d table %p", device->id,
- pdata_dev->clk.bus_scale_table);
+ pdata->bus_scale_table);
result = -EINVAL;
goto done;
}
@@ -529,7 +550,7 @@
clk_err:
result = PTR_ERR(clk);
KGSL_PWR_ERR(device, "clk_get(%s) failed: %d\n",
- clk_names[i], result);
+ clks[i].name, result);
done:
return result;
@@ -697,6 +718,8 @@
goto slumber;
}
} else if (device->requested_state == KGSL_STATE_SLUMBER) {
+ if (device->state == KGSL_STATE_INIT)
+ return 0;
if (device->ftbl->isidle(device))
goto slumber;
}
@@ -729,9 +752,8 @@
device->state = device->requested_state;
device->requested_state = KGSL_STATE_NONE;
- wake_unlock(&device->idle_wakelock);
- pm_qos_update_request(&device->pm_qos_req_dma,
- PM_QOS_DEFAULT_VALUE);
+ if (device->idle_wakelock.name)
+ wake_unlock(&device->idle_wakelock);
KGSL_PWR_WARN(device, "state -> NAP/SLEEP(%d), device %d\n",
device->state, device->id);
@@ -761,7 +783,7 @@
/* Caller must hold the device mutex. */
void kgsl_pwrctrl_wake(struct kgsl_device *device)
{
- if (device->state == KGSL_STATE_SUSPEND)
+ if (device->state & (KGSL_STATE_SUSPEND | KGSL_STATE_INIT))
return;
if (device->state == KGSL_STATE_SLUMBER)
@@ -784,8 +806,9 @@
mod_timer(&device->idle_timer,
jiffies + device->pwrctrl.interval_timeout);
- wake_lock(&device->idle_wakelock);
- pm_qos_update_request(&device->pm_qos_req_dma, GPU_SWFI_LATENCY);
+ if (device->idle_wakelock.name)
+ wake_lock(&device->idle_wakelock);
+
KGSL_PWR_INFO(device, "wake return for device %d\n", device->id);
}
EXPORT_SYMBOL(kgsl_pwrctrl_wake);
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 9bf3c0f..8b33fcd 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -52,7 +52,6 @@
unsigned int nap_allowed;
const char *regulator_name;
const char *irq_name;
- const char *src_clk_name;
s64 time;
struct kgsl_busy busy;
unsigned int restore_slumber;
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index b59761d..ec91b39 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -655,7 +655,7 @@
BUG_ON(memdesc == NULL || memdesc->hostptr == NULL);
BUG_ON(offsetbytes + sizeof(unsigned int) > memdesc->size);
- kgsl_cffdump_setmem(memdesc->physaddr + offsetbytes,
+ kgsl_cffdump_setmem(memdesc->gpuaddr + offsetbytes,
src, sizeof(uint));
writel_relaxed(src, memdesc->hostptr + offsetbytes);
return 0;
@@ -669,8 +669,8 @@
BUG_ON(memdesc == NULL || memdesc->hostptr == NULL);
BUG_ON(offsetbytes + sizebytes > memdesc->size);
- kgsl_cffdump_setmem(memdesc->physaddr + offsetbytes, value,
- sizebytes);
+ kgsl_cffdump_setmem(memdesc->gpuaddr + offsetbytes, value,
+ sizebytes);
memset(memdesc->hostptr + offsetbytes, value, sizebytes);
return 0;
}
diff --git a/include/linux/platform_data/usb_rmnet.h b/drivers/gpu/msm/kgsl_trace.c
similarity index 74%
copy from include/linux/platform_data/usb_rmnet.h
copy to drivers/gpu/msm/kgsl_trace.c
index 68c0db7..2bcca15 100644
--- a/include/linux/platform_data/usb_rmnet.h
+++ b/drivers/gpu/msm/kgsl_trace.c
@@ -8,16 +8,12 @@
* 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 "kgsl.h"
+#include "kgsl_device.h"
-#ifndef __LINUX_USB_GADGET_RMNET_H__
-#define __LINUX_USB_GADGET_RMNET_H__
-
-#include <linux/platform_device.h>
-
-struct usb_rmnet_pdata {
- unsigned num_instances;
-};
-
-#endif
+/* Instantiate tracepoints */
+#define CREATE_TRACE_POINTS
+#include "kgsl_trace.h"
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
new file mode 100644
index 0000000..7c14ac1
--- /dev/null
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -0,0 +1,161 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ *
+ */
+
+#if !defined(_KGSL_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _KGSL_TRACE_H
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM kgsl
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE kgsl_trace
+
+#include <linux/tracepoint.h>
+
+struct kgsl_device;
+struct kgsl_ringbuffer_issueibcmds;
+struct kgsl_device_waittimestamp;
+
+/*
+ * Tracepoint for kgsl issue ib commands
+ */
+TRACE_EVENT(kgsl_issueibcmds,
+
+ TP_PROTO(struct kgsl_device *device,
+ struct kgsl_ringbuffer_issueibcmds *cmd, int result),
+
+ TP_ARGS(device, cmd, result),
+
+ TP_STRUCT__entry(
+ __string(device_name, device->name)
+ __field(unsigned int, drawctxt_id)
+ __field(unsigned int, ibdesc_addr)
+ __field(unsigned int, numibs)
+ __field(unsigned int, timestamp)
+ __field(unsigned int, flags)
+ __field(int, result)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device_name, device->name);
+ __entry->drawctxt_id = cmd->drawctxt_id;
+ __entry->ibdesc_addr = cmd->ibdesc_addr;
+ __entry->numibs = cmd->numibs;
+ __entry->timestamp = cmd->timestamp;
+ __entry->flags = cmd->flags;
+ __entry->result = result;
+ ),
+
+ TP_printk(
+ "d_name=%s ctx=%u ib=%u numibs=%u timestamp=%u "
+ "flags=%u result=%d",
+ __get_str(device_name),
+ __entry->drawctxt_id,
+ __entry->ibdesc_addr,
+ __entry->numibs,
+ __entry->timestamp,
+ __entry->flags,
+ __entry->result
+ )
+);
+
+/*
+ * Tracepoint for kgsl readtimestamp
+ */
+TRACE_EVENT(kgsl_readtimestamp,
+
+ TP_PROTO(struct kgsl_device *device,
+ struct kgsl_cmdstream_readtimestamp *cmd),
+
+ TP_ARGS(device, cmd),
+
+ TP_STRUCT__entry(
+ __string(device_name, device->name)
+ __field(unsigned int, type)
+ __field(unsigned int, timestamp)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device_name, device->name);
+ __entry->type = cmd->type;
+ __entry->timestamp = cmd->timestamp;
+ ),
+
+ TP_printk(
+ "d_name=%s type=%u timestamp=%u",
+ __get_str(device_name),
+ __entry->type,
+ __entry->timestamp
+ )
+);
+
+/*
+ * Tracepoint for kgsl waittimestamp entry
+ */
+TRACE_EVENT(kgsl_waittimestamp_entry,
+
+ TP_PROTO(struct kgsl_device *device,
+ struct kgsl_device_waittimestamp *cmd),
+
+ TP_ARGS(device, cmd),
+
+ TP_STRUCT__entry(
+ __string(device_name, device->name)
+ __field(unsigned int, timestamp)
+ __field(unsigned int, timeout)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device_name, device->name);
+ __entry->timestamp = cmd->timestamp;
+ __entry->timeout = cmd->timeout;
+ ),
+
+ TP_printk(
+ "d_name=%s timestamp=%u timeout=%u",
+ __get_str(device_name),
+ __entry->timestamp,
+ __entry->timeout
+ )
+);
+
+/*
+ * Tracepoint for kgsl waittimestamp exit
+ */
+TRACE_EVENT(kgsl_waittimestamp_exit,
+
+ TP_PROTO(struct kgsl_device *device, int result),
+
+ TP_ARGS(device, result),
+
+ TP_STRUCT__entry(
+ __string(device_name, device->name)
+ __field(int, result)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device_name, device->name);
+ __entry->result = result;
+ ),
+
+ TP_printk(
+ "d_name=%s result=%d",
+ __get_str(device_name),
+ __entry->result
+ )
+);
+#endif /* _KGSL_TRACE_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 9e14247..cf74e64 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -18,6 +18,7 @@
#include "z180.h"
#include "z180_reg.h"
+#include "z180_trace.h"
#define DRIVER_VERSION_MAJOR 3
#define DRIVER_VERSION_MINOR 1
@@ -213,6 +214,8 @@
z180_regread(device, ADDR_VGC_IRQSTATUS >> 2, &status);
+ trace_kgsl_z180_irq_status(device, status);
+
if (status & GSL_VGC_INT_MASK) {
z180_regwrite(device,
ADDR_VGC_IRQSTATUS >> 2, status & GSL_VGC_INT_MASK);
@@ -378,7 +381,8 @@
int status = 0;
struct z180_device *z180_dev = Z180_DEVICE(device);
- if (z180_dev->current_timestamp > z180_dev->timestamp)
+ if (timestamp_cmp(z180_dev->current_timestamp,
+ z180_dev->timestamp) > 0)
status = z180_wait(device, z180_dev->current_timestamp,
timeout);
@@ -644,15 +648,10 @@
static unsigned int z180_isidle(struct kgsl_device *device)
{
- int status = false;
struct z180_device *z180_dev = Z180_DEVICE(device);
- int timestamp = z180_dev->timestamp;
-
- if (timestamp == z180_dev->current_timestamp)
- status = true;
-
- return status;
+ return (timestamp_cmp(z180_dev->timestamp,
+ z180_dev->current_timestamp) == 0) ? true : false;
}
static int z180_suspend_context(struct kgsl_device *device)
@@ -889,6 +888,16 @@
}
}
+static unsigned int z180_gpuid(struct kgsl_device *device)
+{
+ /* Standard KGSL gpuid format:
+ * top word is 0x0002 for 2D or 0x0003 for 3D
+ * Bottom word is core specific identifer
+ */
+
+ return (0x0002 << 16) | 180;
+}
+
static const struct kgsl_functable z180_functable = {
/* Mandatory functions */
.regread = z180_regread,
@@ -906,6 +915,7 @@
.cleanup_pt = z180_cleanup_pt,
.power_stats = z180_power_stats,
.irqctrl = z180_irqctrl,
+ .gpuid = z180_gpuid,
/* Optional functions */
.drawctxt_create = NULL,
.drawctxt_destroy = z180_drawctxt_destroy,
diff --git a/include/linux/platform_data/usb_rmnet.h b/drivers/gpu/msm/z180_trace.c
similarity index 74%
copy from include/linux/platform_data/usb_rmnet.h
copy to drivers/gpu/msm/z180_trace.c
index 68c0db7..29b519c 100644
--- a/include/linux/platform_data/usb_rmnet.h
+++ b/drivers/gpu/msm/z180_trace.c
@@ -8,16 +8,13 @@
* 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 "kgsl.h"
+#include "z180.h"
+#include "z180_reg.h"
-#ifndef __LINUX_USB_GADGET_RMNET_H__
-#define __LINUX_USB_GADGET_RMNET_H__
-
-#include <linux/platform_device.h>
-
-struct usb_rmnet_pdata {
- unsigned num_instances;
-};
-
-#endif
+/* Instantiate tracepoints */
+#define CREATE_TRACE_POINTS
+#include "z180_trace.h"
diff --git a/drivers/gpu/msm/z180_trace.h b/drivers/gpu/msm/z180_trace.h
new file mode 100644
index 0000000..fbe1fe5
--- /dev/null
+++ b/drivers/gpu/msm/z180_trace.h
@@ -0,0 +1,60 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ *
+ */
+
+#if !defined(_Z180_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _Z180_TRACE_H
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM kgsl
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE z180_trace
+
+#include <linux/tracepoint.h>
+
+struct kgsl_device;
+
+/*
+ * Tracepoint for z180 irq. Includes status info
+ */
+TRACE_EVENT(kgsl_z180_irq_status,
+
+ TP_PROTO(struct kgsl_device *device, unsigned int status),
+
+ TP_ARGS(device, status),
+
+ TP_STRUCT__entry(
+ __string(device_name, device->name)
+ __field(unsigned int, status)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device_name, device->name);
+ __entry->status = status;
+ ),
+
+ TP_printk(
+ "d_name=%s status=%s",
+ __get_str(device_name),
+ __entry->status ? __print_flags(__entry->status, "|",
+ { REG_VGC_IRQSTATUS__MH_MASK, "MH" },
+ { REG_VGC_IRQSTATUS__G2D_MASK, "G2D" },
+ { REG_VGC_IRQSTATUS__FIFO_MASK, "FIFO" }) : "None"
+ )
+);
+
+#endif /* _Z180_TRACE_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index a756ee6..c946d90 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -568,6 +568,9 @@
#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001
#define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE 0x0600
+#define USB_VENDOR_ID_SIGMA_MICRO 0x1c4f
+#define USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD 0x0002
+
#define USB_VENDOR_ID_SKYCABLE 0x1223
#define USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER 0x3F07
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 6559e2e..1483c82 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -971,6 +971,9 @@
* UGCI) cram a lot of unrelated inputs into the
* same interface. */
hidinput->report = report;
+ if (hid->driver->input_register &&
+ hid->driver->input_register(hid, hidinput))
+ goto out_cleanup;
if (input_register_device(hidinput->input))
goto out_cleanup;
hidinput = NULL;
@@ -978,6 +981,10 @@
}
}
+ if (hidinput && hid->driver->input_register &&
+ hid->driver->input_register(hid, hidinput))
+ goto out_cleanup;
+
if (hidinput && input_register_device(hidinput->input))
goto out_cleanup;
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index 56d0539..c696f7f 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -365,8 +365,10 @@
return 1;
}
-static void magicmouse_setup_input(struct input_dev *input, struct hid_device *hdev)
+static int magicmouse_setup_input(struct hid_device *hdev, struct hid_input *hi)
{
+ struct input_dev *input = hi->input;
+
__set_bit(EV_KEY, input->evbit);
if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
@@ -426,6 +428,8 @@
__set_bit(EV_MSC, input->evbit);
__set_bit(MSC_RAW, input->mscbit);
}
+
+ return 0;
}
static int magicmouse_input_mapping(struct hid_device *hdev,
@@ -478,12 +482,6 @@
goto err_free;
}
- /* We do this after hid-input is done parsing reports so that
- * hid-input uses the most natural button and axis IDs.
- */
- if (msc->input)
- magicmouse_setup_input(msc->input, hdev);
-
if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE)
report = hid_register_report(hdev, HID_INPUT_REPORT,
MOUSE_REPORT_ID);
@@ -548,6 +546,7 @@
.remove = magicmouse_remove,
.raw_event = magicmouse_raw_event,
.input_mapping = magicmouse_input_mapping,
+ .input_register = magicmouse_setup_input,
};
static int __init magicmouse_init(void)
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 621959d..4bdb5d4 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -89,6 +89,7 @@
{ USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_SIGMA_MICRO, USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD, HID_QUIRK_NO_INIT_REPORTS },
{ 0, 0 }
};
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index f3cd0ad..92fd1d78 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -788,18 +788,9 @@
internally uses an array of LTC2499 and EPM ADCs in a differential
configuration to provide a flat set of channels that can be addressed.
-config SENSORS_PM8921_ADC
- tristate "Support for Qualcomm PM8921 ADC"
- depends on MFD_PM8921_CORE
- help
- This is the ADC arbiter driver for Qualcomm PM8921 Chip.
-
- The driver supports reading the HKADC, XOADC and support to set and receive
- temperature threshold notifications using the Battery temperature module.
-
config SENSORS_PM8XXX_ADC
tristate "Support for Qualcomm PM8XXX ADC"
- depends on MFD_PM8018_CORE
+ depends on MFD_PM8018_CORE || MFD_PM8921_CORE
help
This is the ADC arbiter driver for Qualcomm PM8XXX Chip.
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 10d0699..137f469 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -120,7 +120,6 @@
obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o
obj-$(CONFIG_SENSORS_WPCE775X) += wpce775x.o
obj-$(CONFIG_SENSORS_MSM_ADC) += msm_adc.o m_adcproc.o
-obj-$(CONFIG_SENSORS_PM8921_ADC) += pm8921-adc.o msmproc_adc.o
obj-$(CONFIG_SENSORS_PM8XXX_ADC) += pm8xxx-adc.o pm8xxx-adc-scale.o
# PMBus drivers
diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c
index 257957c..4f7c3fc 100644
--- a/drivers/hwmon/ds620.c
+++ b/drivers/hwmon/ds620.c
@@ -72,7 +72,7 @@
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
- u16 temp[3]; /* Register values, word */
+ s16 temp[3]; /* Register values, word */
};
/*
diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c
index 1a409c5..c316294 100644
--- a/drivers/hwmon/ibmaem.c
+++ b/drivers/hwmon/ibmaem.c
@@ -432,13 +432,15 @@
aem_send_message(ipmi);
res = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT);
- if (!res)
- return -ETIMEDOUT;
+ if (!res) {
+ res = -ETIMEDOUT;
+ goto out;
+ }
if (ipmi->rx_result || ipmi->rx_msg_len != rs_size ||
memcmp(&rs_resp->id, &system_x_id, sizeof(system_x_id))) {
- kfree(rs_resp);
- return -ENOENT;
+ res = -ENOENT;
+ goto out;
}
switch (size) {
@@ -463,8 +465,11 @@
break;
}
}
+ res = 0;
- return 0;
+out:
+ kfree(rs_resp);
+ return res;
}
/* Update AEM energy registers */
diff --git a/drivers/hwmon/max16065.c b/drivers/hwmon/max16065.c
index d94a24f..dd2d7b9 100644
--- a/drivers/hwmon/max16065.c
+++ b/drivers/hwmon/max16065.c
@@ -124,7 +124,7 @@
static inline int ADC_TO_CURR(int adc, int gain)
{
- return adc * 1400000 / gain * 255;
+ return adc * 1400000 / (gain * 255);
}
/*
diff --git a/drivers/hwmon/msmproc_adc.c b/drivers/hwmon/msmproc_adc.c
deleted file mode 100644
index fa6949e..0000000
--- a/drivers/hwmon/msmproc_adc.c
+++ /dev/null
@@ -1,638 +0,0 @@
-/*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/mfd/pm8xxx/pm8921-adc.h>
-#define KELVINMIL_DEGMIL 273160
-
-static const struct pm8921_adc_map_pt adcmap_batttherm[] = {
- {41001, -30},
- {40017, -20},
- {38721, -10},
- {37186, 0},
- {35554, 10},
- {33980, 20},
- {33253, 25},
- {32580, 30},
- {31412, 40},
- {30481, 50},
- {29759, 60},
- {29209, 70},
- {28794, 80}
-};
-
-static const struct pm8921_adc_map_pt adcmap_btm_threshold[] = {
- {-30, 1642},
- {-20, 1544},
- {-10, 1414},
- {0, 1260},
- {1, 1244},
- {2, 1228},
- {3, 1212},
- {4, 1195},
- {5, 1179},
- {6, 1162},
- {7, 1146},
- {8, 1129},
- {9, 1113},
- {10, 1097},
- {11, 1080},
- {12, 1064},
- {13, 1048},
- {14, 1032},
- {15, 1016},
- {16, 1000},
- {17, 985},
- {18, 969},
- {19, 954},
- {20, 939},
- {21, 924},
- {22, 909},
- {23, 894},
- {24, 880},
- {25, 866},
- {26, 852},
- {27, 838},
- {28, 824},
- {29, 811},
- {30, 798},
- {31, 785},
- {32, 773},
- {33, 760},
- {34, 748},
- {35, 736},
- {36, 725},
- {37, 713},
- {38, 702},
- {39, 691},
- {40, 681},
- {41, 670},
- {42, 660},
- {43, 650},
- {44, 640},
- {45, 631},
- {46, 622},
- {47, 613},
- {48, 604},
- {49, 595},
- {50, 587},
- {51, 579},
- {52, 571},
- {53, 563},
- {54, 556},
- {55, 548},
- {56, 541},
- {57, 534},
- {58, 527},
- {59, 521},
- {60, 514},
- {61, 508},
- {62, 502},
- {63, 496},
- {64, 490},
- {65, 485},
- {66, 281},
- {67, 274},
- {68, 267},
- {69, 260},
- {70, 254},
- {71, 247},
- {72, 241},
- {73, 235},
- {74, 229},
- {75, 224},
- {76, 218},
- {77, 213},
- {78, 208},
- {79, 203}
-};
-
-static const struct pm8921_adc_map_pt adcmap_pa_therm[] = {
- {41350, -30},
- {41282, -29},
- {41211, -28},
- {41137, -27},
- {41060, -26},
- {40980, -25},
- {40897, -24},
- {40811, -23},
- {40721, -22},
- {40629, -21},
- {40533, -20},
- {40434, -19},
- {40331, -18},
- {40226, -17},
- {40116, -16},
- {40004, -15},
- {39888, -14},
- {39769, -13},
- {39647, -12},
- {39521, -11},
- {39392, -10},
- {39260, -9},
- {39124, -8},
- {38986, -7},
- {38845, -6},
- {38700, -5},
- {38553, -4},
- {38403, -3},
- {38250, -2},
- {38094, -1},
- {37936, 0},
- {37776, 1},
- {37613, 2},
- {37448, 3},
- {37281, 4},
- {37112, 5},
- {36942, 6},
- {36770, 7},
- {36596, 8},
- {36421, 9},
- {36245, 10},
- {36068, 11},
- {35890, 12},
- {35712, 13},
- {35532, 14},
- {35353, 15},
- {35173, 16},
- {34993, 17},
- {34813, 18},
- {34634, 19},
- {34455, 20},
- {34276, 21},
- {34098, 22},
- {33921, 23},
- {33745, 24},
- {33569, 25},
- {33395, 26},
- {33223, 27},
- {33051, 28},
- {32881, 29},
- {32713, 30},
- {32547, 31},
- {32382, 32},
- {32219, 33},
- {32058, 34},
- {31899, 35},
- {31743, 36},
- {31588, 37},
- {31436, 38},
- {31285, 39},
- {31138, 40},
- {30992, 41},
- {30849, 42},
- {30708, 43},
- {30570, 44},
- {30434, 45},
- {30300, 46},
- {30169, 47},
- {30041, 48},
- {29915, 49},
- {29791, 50},
- {29670, 51},
- {29551, 52},
- {29435, 53},
- {29321, 54},
- {29210, 55},
- {29101, 56},
- {28994, 57},
- {28890, 58},
- {28788, 59},
- {28688, 60},
- {28590, 61},
- {28495, 62},
- {28402, 63},
- {28311, 64},
- {28222, 65},
- {28136, 66},
- {28051, 67},
- {27968, 68},
- {27888, 69},
- {27809, 70},
- {27732, 71},
- {27658, 72},
- {27584, 73},
- {27513, 74},
- {27444, 75},
- {27376, 76},
- {27310, 77},
- {27245, 78},
- {27183, 79},
- {27121, 80},
- {27062, 81},
- {27004, 82},
- {26947, 83},
- {26892, 84},
- {26838, 85},
- {26785, 86},
- {26734, 87},
- {26684, 88},
- {26636, 89},
- {26588, 90}
-};
-
-static const struct pm8921_adc_map_pt adcmap_ntcg_104ef_104fb[] = {
- {696483, -40960},
- {649148, -39936},
- {605368, -38912},
- {564809, -37888},
- {527215, -36864},
- {492322, -35840},
- {460007, -34816},
- {429982, -33792},
- {402099, -32768},
- {376192, -31744},
- {352075, -30720},
- {329714, -29696},
- {308876, -28672},
- {289480, -27648},
- {271417, -26624},
- {254574, -25600},
- {238903, -24576},
- {224276, -23552},
- {210631, -22528},
- {197896, -21504},
- {186007, -20480},
- {174899, -19456},
- {164521, -18432},
- {154818, -17408},
- {145744, -16384},
- {137265, -15360},
- {129307, -14336},
- {121866, -13312},
- {114896, -12288},
- {108365, -11264},
- {102252, -10240},
- {96499, -9216},
- {91111, -8192},
- {86055, -7168},
- {81308, -6144},
- {76857, -5120},
- {72660, -4096},
- {68722, -3072},
- {65020, -2048},
- {61538, -1024},
- {58261, 0},
- {55177, 1024},
- {52274, 2048},
- {49538, 3072},
- {46962, 4096},
- {44531, 5120},
- {42243, 6144},
- {40083, 7168},
- {38045, 8192},
- {36122, 9216},
- {34308, 10240},
- {32592, 11264},
- {30972, 12288},
- {29442, 13312},
- {27995, 14336},
- {26624, 15360},
- {25333, 16384},
- {24109, 17408},
- {22951, 18432},
- {21854, 19456},
- {20807, 20480},
- {19831, 21504},
- {18899, 22528},
- {18016, 23552},
- {17178, 24576},
- {16384, 25600},
- {15631, 26624},
- {14916, 27648},
- {14237, 28672},
- {13593, 29696},
- {12976, 30720},
- {12400, 31744},
- {11848, 32768},
- {11324, 33792},
- {10825, 34816},
- {10354, 35840},
- {9900, 36864},
- {9471, 37888},
- {9062, 38912},
- {8674, 39936},
- {8306, 40960},
- {7951, 41984},
- {7616, 43008},
- {7296, 44032},
- {6991, 45056},
- {6701, 46080},
- {6424, 47104},
- {6160, 48128},
- {5908, 49152},
- {5667, 50176},
- {5439, 51200},
- {5219, 52224},
- {5010, 53248},
- {4810, 54272},
- {4619, 55296},
- {4440, 56320},
- {4263, 57344},
- {4097, 58368},
- {3938, 59392},
- {3785, 60416},
- {3637, 61440},
- {3501, 62464},
- {3368, 63488},
- {3240, 64512},
- {3118, 65536},
- {2998, 66560},
- {2889, 67584},
- {2782, 68608},
- {2680, 69632},
- {2581, 70656},
- {2490, 71680},
- {2397, 72704},
- {2310, 73728},
- {2227, 74752},
- {2147, 75776},
- {2064, 76800},
- {1998, 77824},
- {1927, 78848},
- {1860, 79872},
- {1795, 80896},
- {1736, 81920},
- {1673, 82944},
- {1615, 83968},
- {1560, 84992},
- {1507, 86016},
- {1456, 87040},
- {1407, 88064},
- {1360, 89088},
- {1314, 90112},
- {1271, 91136},
- {1228, 92160},
- {1189, 93184},
- {1150, 94208},
- {1112, 95232},
- {1076, 96256},
- {1042, 97280},
- {1008, 98304},
- {976, 99328},
- {945, 100352},
- {915, 101376},
- {886, 102400},
- {859, 103424},
- {832, 104448},
- {807, 105472},
- {782, 106496},
- {756, 107520},
- {735, 108544},
- {712, 109568},
- {691, 110592},
- {670, 111616},
- {650, 112640},
- {631, 113664},
- {612, 114688},
- {594, 115712},
- {577, 116736},
- {560, 117760},
- {544, 118784},
- {528, 119808},
- {513, 120832},
- {498, 121856},
- {483, 122880},
- {470, 123904},
- {457, 124928},
- {444, 125952},
- {431, 126976},
- {419, 128000}
-};
-
-static int32_t pm8921_adc_map_linear(const struct pm8921_adc_map_pt *pts,
- uint32_t tablesize, int32_t input, int64_t *output)
-{
- bool descending = 1;
- uint32_t i = 0;
-
- if ((pts == NULL) || (output == NULL))
- return -EINVAL;
-
- /* Check if table is descending or ascending */
- if (tablesize > 1) {
- if (pts[0].x < pts[1].x)
- descending = 0;
- }
-
- while (i < tablesize) {
- if ((descending == 1) && (pts[i].x < input)) {
- /* table entry is less than measured
- value and table is descending, stop */
- break;
- } else if ((descending == 0) &&
- (pts[i].x > input)) {
- /* table entry is greater than measured
- value and table is ascending, stop */
- break;
- } else {
- i++;
- }
- }
-
- if (i == 0)
- *output = pts[0].y;
- else if (i == tablesize)
- *output = pts[tablesize-1].y;
- else {
- /* result is between search_index and search_index-1 */
- /* interpolate linearly */
- *output = (((int32_t) ((pts[i].y - pts[i-1].y)*
- (input - pts[i-1].x))/
- (pts[i].x - pts[i-1].x))+
- pts[i-1].y);
- }
-
- return 0;
-}
-
-int32_t pm8921_adc_scale_default(int32_t adc_code,
- const struct pm8921_adc_properties *adc_properties,
- const struct pm8921_adc_chan_properties *chan_properties,
- struct pm8921_adc_chan_result *adc_chan_result)
-{
- bool negative_rawfromoffset = 0;
- int32_t rawfromoffset = 0;
-
- if (!chan_properties || !chan_properties->offset_gain_numerator ||
- !chan_properties->offset_gain_denominator || !adc_properties
- || !adc_chan_result)
- return -EINVAL;
-
- rawfromoffset = adc_code -
- chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].offset;
-
- adc_chan_result->adc_code = adc_code;
- if (rawfromoffset < 0) {
- if (adc_properties->bipolar) {
- rawfromoffset = -rawfromoffset;
- negative_rawfromoffset = 1;
- } else {
- rawfromoffset = 0;
- }
- }
-
- if (rawfromoffset >= 1 << adc_properties->bitresolution)
- rawfromoffset = (1 << adc_properties->bitresolution) - 1;
-
- adc_chan_result->measurement = (int64_t)rawfromoffset *
- chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].dx *
- chan_properties->offset_gain_denominator;
-
- /* do_div only perform positive integer division! */
- do_div(adc_chan_result->measurement,
- chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].dy *
- chan_properties->offset_gain_numerator);
-
- if (negative_rawfromoffset)
- adc_chan_result->measurement = -adc_chan_result->measurement;
-
- /* Note: adc_chan_result->measurement is in the unit of
- * adc_properties.adc_reference. For generic channel processing,
- * channel measurement is a scale/ratio relative to the adc
- * reference input */
- adc_chan_result->physical = (int32_t) adc_chan_result->measurement;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(pm8921_adc_scale_default);
-
-int32_t pm8921_adc_scale_batt_therm(int32_t adc_code,
- const struct pm8921_adc_properties *adc_properties,
- const struct pm8921_adc_chan_properties *chan_properties,
- struct pm8921_adc_chan_result *adc_chan_result)
-{
- /* convert mV ---> degC using the table */
- return pm8921_adc_map_linear(
- adcmap_batttherm,
- ARRAY_SIZE(adcmap_batttherm),
- adc_code,
- &adc_chan_result->physical);
-}
-EXPORT_SYMBOL_GPL(pm8921_adc_scale_batt_therm);
-
-int32_t pm8921_adc_scale_pa_therm(int32_t adc_code,
- const struct pm8921_adc_properties *adc_properties,
- const struct pm8921_adc_chan_properties *chan_properties,
- struct pm8921_adc_chan_result *adc_chan_result)
-{
- /* convert mV ---> degC using the table */
- return pm8921_adc_map_linear(
- adcmap_pa_therm,
- ARRAY_SIZE(adcmap_pa_therm),
- adc_code,
- &adc_chan_result->physical);
-}
-EXPORT_SYMBOL_GPL(pm8921_adc_scale_pa_therm);
-
-int32_t pm8921_adc_scale_pmic_therm(int32_t adc_code,
- const struct pm8921_adc_properties *adc_properties,
- const struct pm8921_adc_chan_properties *chan_properties,
- struct pm8921_adc_chan_result *adc_chan_result)
-{
- int32_t rawfromoffset;
-
- if (!chan_properties || !chan_properties->offset_gain_numerator ||
- !chan_properties->offset_gain_denominator || !adc_properties
- || !adc_chan_result)
- return -EINVAL;
-
- adc_chan_result->adc_code = adc_code;
- rawfromoffset = adc_code -
- chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].offset;
- if (rawfromoffset > 0) {
- if (rawfromoffset >= 1 << adc_properties->bitresolution)
- rawfromoffset = (1 << adc_properties->bitresolution)
- - 1;
- /* 2mV/K */
- adc_chan_result->measurement = (int64_t)rawfromoffset*
- chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].dx *
- chan_properties->offset_gain_denominator * 1000;
-
- do_div(adc_chan_result->measurement,
- chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].dy *
- chan_properties->offset_gain_numerator*2);
- } else {
- adc_chan_result->measurement = 0;
- }
- /* Note: adc_chan_result->measurement is in the unit of
- adc_properties.adc_reference */
- adc_chan_result->physical = (int32_t)adc_chan_result->measurement;
- /* Change to .001 deg C */
- adc_chan_result->physical -= KELVINMIL_DEGMIL;
- adc_chan_result->measurement <<= 1;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(pm8921_adc_scale_pmic_therm);
-
-/* Scales the ADC code to 0.001 degrees C using the map
- * table for the XO thermistor.
- */
-int32_t pm8921_adc_tdkntcg_therm(int32_t adc_code,
- const struct pm8921_adc_properties *adc_properties,
- const struct pm8921_adc_chan_properties *chan_properties,
- struct pm8921_adc_chan_result *adc_chan_result)
-{
- int32_t rt_r25;
- int32_t offset = chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].offset;
-
- rt_r25 = adc_code - offset;
-
- pm8921_adc_map_linear(adcmap_ntcg_104ef_104fb,
- ARRAY_SIZE(adcmap_ntcg_104ef_104fb),
- rt_r25, &adc_chan_result->physical);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(pm8921_adc_tdkntcg_therm);
-
-int32_t pm8921_adc_batt_scaler(struct pm8921_adc_arb_btm_param *btm_param,
- const struct pm8921_adc_properties *adc_properties,
- const struct pm8921_adc_chan_properties *chan_properties)
-{
- int rc;
-
- rc = pm8921_adc_map_linear(
- adcmap_btm_threshold,
- ARRAY_SIZE(adcmap_btm_threshold),
- btm_param->low_thr_temp,
- &btm_param->low_thr_voltage);
- if (rc)
- return rc;
-
- btm_param->low_thr_voltage *=
- chan_properties->adc_graph[ADC_CALIB_RATIOMETRIC].dy;
- do_div(btm_param->low_thr_voltage, adc_properties->adc_vdd_reference);
- btm_param->low_thr_voltage +=
- chan_properties->adc_graph[ADC_CALIB_RATIOMETRIC].adc_gnd;
-
- rc = pm8921_adc_map_linear(
- adcmap_btm_threshold,
- ARRAY_SIZE(adcmap_btm_threshold),
- btm_param->high_thr_temp,
- &btm_param->high_thr_voltage);
- if (rc)
- return rc;
-
- btm_param->high_thr_voltage *=
- chan_properties->adc_graph[ADC_CALIB_RATIOMETRIC].dy;
- do_div(btm_param->high_thr_voltage, adc_properties->adc_vdd_reference);
- btm_param->high_thr_voltage +=
- chan_properties->adc_graph[ADC_CALIB_RATIOMETRIC].adc_gnd;
-
- return rc;
-}
-EXPORT_SYMBOL_GPL(pm8921_adc_batt_scaler);
diff --git a/drivers/hwmon/pm8921-adc.c b/drivers/hwmon/pm8921-adc.c
deleted file mode 100644
index 38e18de..0000000
--- a/drivers/hwmon/pm8921-adc.c
+++ /dev/null
@@ -1,1359 +0,0 @@
-/*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * 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.
- *
- * Qualcomm's PM8921 ADC Arbiter driver
- */
-#define pr_fmt(fmt) "%s: " fmt, __func__
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mutex.h>
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/completion.h>
-#include <linux/platform_device.h>
-#include <linux/mfd/pm8xxx/core.h>
-#include <linux/mfd/pm8xxx/mpp.h>
-#include <linux/debugfs.h>
-#include <linux/regulator/consumer.h>
-#include <linux/mfd/pm8xxx/pm8921-adc.h>
-#include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
-#include <linux/wakelock.h>
-
-/* User Bank register set */
-#define PM8921_ADC_ARB_USRP_CNTRL1 0x197
-#define PM8921_ADC_ARB_USRP_CNTRL1_EN_ARB BIT(0)
-#define PM8921_ADC_ARB_USRP_CNTRL1_RSV1 BIT(1)
-#define PM8921_ADC_ARB_USRP_CNTRL1_RSV2 BIT(2)
-#define PM8921_ADC_ARB_USRP_CNTRL1_RSV3 BIT(3)
-#define PM8921_ADC_ARB_USRP_CNTRL1_RSV4 BIT(4)
-#define PM8921_ADC_ARB_USRP_CNTRL1_RSV5 BIT(5)
-#define PM8921_ADC_ARB_USRP_CNTRL1_EOC BIT(6)
-#define PM8921_ADC_ARB_USRP_CNTRL1_REQ BIT(7)
-
-#define PM8921_ADC_ARB_USRP_AMUX_CNTRL 0x198
-#define PM8921_ADC_ARB_USRP_AMUX_CNTRL_RSV0 BIT(0)
-#define PM8921_ADC_ARB_USRP_AMUX_CNTRL_RSV1 BIT(1)
-#define PM8921_ADC_ARB_USRP_AMUX_CNTRL_PREMUX0 BIT(2)
-#define PM8921_ADC_ARB_USRP_AMUX_CNTRL_PREMUX1 BIT(3)
-#define PM8921_ADC_ARB_USRP_AMUX_CNTRL_SEL0 BIT(4)
-#define PM8921_ADC_ARB_USRP_AMUX_CNTRL_SEL1 BIT(5)
-#define PM8921_ADC_ARB_USRP_AMUX_CNTRL_SEL2 BIT(6)
-#define PM8921_ADC_ARB_USRP_AMUX_CNTRL_SEL3 BIT(7)
-
-#define PM8921_ADC_ARB_USRP_ANA_PARAM 0x199
-#define PM8921_ADC_ARB_USRP_DIG_PARAM 0x19A
-#define PM8921_ADC_ARB_USRP_DIG_PARAM_SEL_SHIFT0 BIT(0)
-#define PM8921_ADC_ARB_USRP_DIG_PARAM_SEL_SHIFT1 BIT(1)
-#define PM8921_ADC_ARB_USRP_DIG_PARAM_CLK_RATE0 BIT(2)
-#define PM8921_ADC_ARB_USRP_DIG_PARAM_CLK_RATE1 BIT(3)
-#define PM8921_ADC_ARB_USRP_DIG_PARAM_EOC BIT(4)
-#define PM8921_ADC_ARB_USRP_DIG_PARAM_DEC_RATE0 BIT(5)
-#define PM8921_ADC_ARB_USRP_DIG_PARAM_DEC_RATE1 BIT(6)
-#define PM8921_ADC_ARB_USRP_DIG_PARAM_EN BIT(7)
-
-#define PM8921_ADC_ARB_USRP_RSV 0x19B
-#define PM8921_ADC_ARB_USRP_RSV_RST BIT(0)
-#define PM8921_ADC_ARB_USRP_RSV_DTEST0 BIT(1)
-#define PM8921_ADC_ARB_USRP_RSV_DTEST1 BIT(2)
-#define PM8921_ADC_ARB_USRP_RSV_OP BIT(3)
-#define PM8921_ADC_ARB_USRP_RSV_IP_SEL0 BIT(4)
-#define PM8921_ADC_ARB_USRP_RSV_IP_SEL1 BIT(5)
-#define PM8921_ADC_ARB_USRP_RSV_IP_SEL2 BIT(6)
-#define PM8921_ADC_ARB_USRP_RSV_TRM BIT(7)
-
-#define PM8921_ADC_ARB_USRP_DATA0 0x19D
-#define PM8921_ADC_ARB_USRP_DATA1 0x19C
-
-#define PM8921_ADC_ARB_BTM_CNTRL1 0x17e
-#define PM8921_ADC_ARB_BTM_CNTRL1_EN_BTM BIT(0)
-#define PM8921_ADC_ARB_BTM_CNTRL1_SEL_OP_MODE BIT(1)
-#define PM8921_ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL1 BIT(2)
-#define PM8921_ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL2 BIT(3)
-#define PM8921_ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL3 BIT(4)
-#define PM8921_ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL4 BIT(5)
-#define PM8921_ADC_ARB_BTM_CNTRL1_EOC BIT(6)
-#define PM8921_ADC_ARB_BTM_CNTRL1_REQ BIT(7)
-
-#define PM8921_ADC_ARB_BTM_CNTRL2 0x18c
-#define PM8921_ADC_ARB_BTM_AMUX_CNTRL 0x17f
-#define PM8921_ADC_ARB_BTM_ANA_PARAM 0x180
-#define PM8921_ADC_ARB_BTM_DIG_PARAM 0x181
-#define PM8921_ADC_ARB_BTM_RSV 0x182
-#define PM8921_ADC_ARB_BTM_DATA1 0x183
-#define PM8921_ADC_ARB_BTM_DATA0 0x184
-#define PM8921_ADC_ARB_BTM_BAT_COOL_THR1 0x185
-#define PM8921_ADC_ARB_BTM_BAT_COOL_THR0 0x186
-#define PM8921_ADC_ARB_BTM_BAT_WARM_THR1 0x187
-#define PM8921_ADC_ARB_BTM_BAT_WARM_THR0 0x188
-
-#define PM8921_ADC_ARB_ANA_DIG 0xa0
-#define PM8921_ADC_BTM_RSV 0x10
-#define PM8921_ADC_AMUX_MPP_SEL 2
-#define PM8921_ADC_AMUX_SEL 4
-#define PM8921_ADC_RSV_IP_SEL 4
-#define PM8921_ADC_BTM_CHANNEL_SEL 4
-#define PM8921_MAX_CHANNEL_PROPERTIES 2
-#define PM8921_ADC_IRQ_0 0
-#define PM8921_ADC_IRQ_1 1
-#define PM8921_ADC_IRQ_2 2
-#define PM8921_ADC_BTM_INTERVAL_SEL_MASK 0xF
-#define PM8921_ADC_BTM_INTERVAL_SEL_SHIFT 2
-#define PM8921_ADC_BTM_DECIMATION_SEL 5
-#define PM8921_ADC_MUL 10
-#define PM8921_ADC_CONV_TIME_MIN 2000
-#define PM8921_ADC_CONV_TIME_MAX 2100
-#define PM8921_ADC_MPP_SETTLE_TIME_MIN 200
-#define PM8921_ADC_MPP_SETTLE_TIME_MAX 200
-#define PM8921_ADC_PA_THERM_VREG_UV_MIN 1800000
-#define PM8921_ADC_PA_THERM_VREG_UV_MAX 1800000
-#define PM8921_ADC_PA_THERM_VREG_UA_LOAD 100000
-
-struct pm8921_adc {
- struct device *dev;
- struct pm8921_adc_properties *adc_prop;
- int adc_irq;
- struct mutex adc_lock;
- struct mutex mpp_adc_lock;
- spinlock_t btm_lock;
- uint32_t adc_num_channel;
- uint32_t adc_num_board_channel;
- struct completion adc_rslt_completion;
- struct pm8921_adc_amux *adc_channel;
- struct pm8921_adc_amux_properties *conv;
- struct pm8921_adc_arb_btm_param *batt;
- int btm_warm_irq;
- int btm_cool_irq;
- struct dentry *dent;
- struct work_struct warm_work;
- struct work_struct cool_work;
- uint32_t mpp_base;
- struct sensor_device_attribute *sens_attr;
- struct device *hwmon;
- struct wake_lock adc_wakelock;
- int msm_suspend_check;
-};
-
-struct pm8921_adc_amux_properties {
- uint32_t amux_channel;
- uint32_t decimation;
- uint32_t amux_ip_rsv;
- uint32_t amux_mpp_channel;
- struct pm8921_adc_chan_properties *chan_prop;
-};
-
-static const struct pm8921_adc_scaling_ratio pm8921_amux_scaling_ratio[] = {
- {1, 1},
- {1, 3},
- {1, 4},
- {1, 6}
-};
-
-static struct pm8921_adc *pmic_adc;
-
-static struct pm8921_adc_scale_fn adc_scale_fn[] = {
- [ADC_SCALE_DEFAULT] = {pm8921_adc_scale_default},
- [ADC_SCALE_BATT_THERM] = {pm8921_adc_scale_batt_therm},
- [ADC_SCALE_PA_THERM] = {pm8921_adc_scale_pa_therm},
- [ADC_SCALE_PMIC_THERM] = {pm8921_adc_scale_pmic_therm},
- [ADC_SCALE_XOTHERM] = {pm8921_adc_tdkntcg_therm},
-};
-
-/* MPP 8 is mapped to AMUX8 and is common between remote processor's */
-
-static struct pm8xxx_mpp_config_data pm8921_adc_mpp_config = {
- .type = PM8XXX_MPP_TYPE_A_INPUT,
- /* AMUX6 is dedicated to be used for apps processor */
- .level = PM8XXX_MPP_AIN_AMUX_CH6,
- .control = PM8XXX_MPP_AOUT_CTRL_DISABLE,
-};
-
-/* MPP Configuration for default settings */
-static struct pm8xxx_mpp_config_data pm8921_adc_mpp_unconfig = {
- .type = PM8XXX_MPP_TYPE_SINK,
- .level = PM8XXX_MPP_AIN_AMUX_CH5,
- .control = PM8XXX_MPP_AOUT_CTRL_DISABLE,
-};
-
-static bool pm8921_adc_calib_first_adc;
-static bool pm8921_adc_initialized, pm8921_adc_calib_device_init;
-
-static int32_t pm8921_adc_arb_cntrl(uint32_t arb_cntrl, uint32_t channel)
-{
- struct pm8921_adc *adc_pmic = pmic_adc;
- int i, rc;
- u8 data_arb_cntrl = 0;
-
- if (arb_cntrl) {
- if (adc_pmic->msm_suspend_check)
- pr_err("PM8921 ADC request being made after suspend "
- "irq with channel id:%d\n", channel);
- data_arb_cntrl |= PM8921_ADC_ARB_USRP_CNTRL1_EN_ARB;
- }
-
- /* Write twice to the CNTRL register for the arbiter settings
- to take into effect */
- for (i = 0; i < 2; i++) {
- rc = pm8xxx_writeb(adc_pmic->dev->parent,
- PM8921_ADC_ARB_USRP_CNTRL1, data_arb_cntrl);
- if (rc < 0) {
- pr_err("PM8921 arb cntrl write failed with %d\n", rc);
- return rc;
- }
- }
-
- if (arb_cntrl) {
- data_arb_cntrl |= PM8921_ADC_ARB_USRP_CNTRL1_REQ;
- rc = pm8xxx_writeb(adc_pmic->dev->parent,
- PM8921_ADC_ARB_USRP_CNTRL1, data_arb_cntrl);
- if (rc < 0) {
- pr_err("PM8921 arb cntrl write failed with %d\n", rc);
- return rc;
- }
- wake_lock(&adc_pmic->adc_wakelock);
- } else {
- wake_unlock(&adc_pmic->adc_wakelock);
- }
-
- return 0;
-}
-
-static int32_t pm8921_adc_patherm_power(bool on)
-{
- static struct regulator *pa_therm;
- struct pm8921_adc *adc_pmic = pmic_adc;
- int rc = 0;
- if (on) {
- pa_therm = regulator_get(adc_pmic->dev,
- "pa_therm");
- if (IS_ERR(pa_therm)) {
- rc = PTR_ERR(pa_therm);
- pr_err("failed to request pa_therm vreg "
- "with error %d\n", rc);
- return rc;
- }
-
- rc = regulator_set_voltage(pa_therm,
- PM8921_ADC_PA_THERM_VREG_UV_MIN,
- PM8921_ADC_PA_THERM_VREG_UV_MAX);
- if (rc < 0) {
- pr_err("failed to set the voltage for "
- "pa_therm with error %d\n", rc);
- goto fail;
- }
-
- rc = regulator_set_optimum_mode(pa_therm,
- PM8921_ADC_PA_THERM_VREG_UA_LOAD);
- if (rc < 0) {
- pr_err("failed to set optimum mode for "
- "pa_therm with error %d\n", rc);
- goto fail;
- }
-
- if (regulator_enable(pa_therm)) {
- pr_err("failed to enable pa_therm vreg with "
- "error %d\n", rc);
- goto fail;
- }
- } else {
- if (pa_therm != NULL) {
- regulator_disable(pa_therm);
- regulator_put(pa_therm);
- }
- }
-
- return rc;
-fail:
- regulator_put(pa_therm);
- return rc;
-}
-
-static int32_t pm8921_adc_channel_power_enable(uint32_t channel,
- bool power_cntrl)
-{
- int rc = 0;
-
- switch (channel)
- case ADC_MPP_1_AMUX8:
- pm8921_adc_patherm_power(power_cntrl);
-
- return rc;
-}
-
-
-static uint32_t pm8921_adc_read_reg(uint32_t reg, u8 *data)
-{
- struct pm8921_adc *adc_pmic = pmic_adc;
- int rc;
-
- rc = pm8xxx_readb(adc_pmic->dev->parent, reg, data);
- if (rc < 0) {
- pr_err("PM8921 adc read reg %d failed with %d\n", reg, rc);
- return rc;
- }
-
- return 0;
-}
-
-static uint32_t pm8921_adc_write_reg(uint32_t reg, u8 data)
-{
- struct pm8921_adc *adc_pmic = pmic_adc;
- int rc;
-
- rc = pm8xxx_writeb(adc_pmic->dev->parent, reg, data);
- if (rc < 0) {
- pr_err("PM8921 adc write reg %d failed with %d\n", reg, rc);
- return rc;
- }
-
- return 0;
-}
-
-static int32_t pm8921_adc_configure(
- struct pm8921_adc_amux_properties *chan_prop)
-{
- struct pm8921_adc *adc_pmic = pmic_adc;
- u8 data_amux_chan = 0, data_arb_rsv = 0, data_dig_param = 0;
- int rc;
-
- data_amux_chan |= chan_prop->amux_channel << PM8921_ADC_AMUX_SEL;
-
- if (chan_prop->amux_mpp_channel)
- data_amux_chan |= chan_prop->amux_mpp_channel <<
- PM8921_ADC_AMUX_MPP_SEL;
-
- rc = pm8921_adc_write_reg(PM8921_ADC_ARB_USRP_AMUX_CNTRL,
- data_amux_chan);
- if (rc < 0)
- return rc;
-
- data_arb_rsv &= (PM8921_ADC_ARB_USRP_RSV_RST |
- PM8921_ADC_ARB_USRP_RSV_DTEST0 |
- PM8921_ADC_ARB_USRP_RSV_DTEST1 |
- PM8921_ADC_ARB_USRP_RSV_OP |
- PM8921_ADC_ARB_USRP_RSV_TRM);
- data_arb_rsv |= chan_prop->amux_ip_rsv << PM8921_ADC_RSV_IP_SEL;
-
- rc = pm8921_adc_write_reg(PM8921_ADC_ARB_USRP_RSV, data_arb_rsv);
- if (rc < 0)
- return rc;
-
- rc = pm8921_adc_read_reg(PM8921_ADC_ARB_USRP_DIG_PARAM,
- &data_dig_param);
- if (rc < 0)
- return rc;
-
- /* Default 2.4Mhz clock rate */
- /* Client chooses the decimation */
- switch (chan_prop->decimation) {
- case ADC_DECIMATION_TYPE1:
- data_dig_param |= PM8921_ADC_ARB_USRP_DIG_PARAM_DEC_RATE0;
- break;
- case ADC_DECIMATION_TYPE2:
- data_dig_param |= (PM8921_ADC_ARB_USRP_DIG_PARAM_DEC_RATE0
- | PM8921_ADC_ARB_USRP_DIG_PARAM_DEC_RATE1);
- break;
- default:
- data_dig_param |= PM8921_ADC_ARB_USRP_DIG_PARAM_DEC_RATE0;
- break;
- }
- rc = pm8921_adc_write_reg(PM8921_ADC_ARB_USRP_DIG_PARAM,
- PM8921_ADC_ARB_ANA_DIG);
- if (rc < 0)
- return rc;
-
- rc = pm8921_adc_write_reg(PM8921_ADC_ARB_USRP_ANA_PARAM,
- PM8921_ADC_ARB_ANA_DIG);
- if (rc < 0)
- return rc;
-
- if (!pm8921_adc_calib_first_adc)
- enable_irq(adc_pmic->adc_irq);
-
- rc = pm8921_adc_arb_cntrl(1, chan_prop->amux_mpp_channel);
- if (rc < 0) {
- pr_err("Configuring ADC Arbiter"
- "enable failed with %d\n", rc);
- return rc;
- }
-
- return 0;
-}
-
-static uint32_t pm8921_adc_read_adc_code(int32_t *data)
-{
- struct pm8921_adc *adc_pmic = pmic_adc;
- uint8_t rslt_lsb, rslt_msb;
- int32_t rc, max_ideal_adc_code = 1 << adc_pmic->adc_prop->bitresolution;
-
- rc = pm8xxx_readb(adc_pmic->dev->parent,
- PM8921_ADC_ARB_USRP_DATA0, &rslt_lsb);
- if (rc < 0) {
- pr_err("PM8921 adc result read failed with %d\n", rc);
- return rc;
- }
-
- rc = pm8xxx_readb(adc_pmic->dev->parent,
- PM8921_ADC_ARB_USRP_DATA1, &rslt_msb);
- if (rc < 0) {
- pr_err("PM8921 adc result read failed with %d\n", rc);
- return rc;
- }
-
- *data = (rslt_msb << 8) | rslt_lsb;
-
- /* Use the midpoint to determine underflow or overflow */
- if (*data > max_ideal_adc_code + (max_ideal_adc_code >> 1))
- *data |= ((1 << (8 * sizeof(*data) -
- adc_pmic->adc_prop->bitresolution)) - 1) <<
- adc_pmic->adc_prop->bitresolution;
-
- /* Default value for switching off the arbiter after reading
- the ADC value. Bit 0 set to 0. */
- rc = pm8921_adc_arb_cntrl(0, CHANNEL_MUXOFF);
- if (rc < 0) {
- pr_err("%s: Configuring ADC Arbiter disable"
- "failed\n", __func__);
- return rc;
- }
-
- return 0;
-}
-
-static void pm8921_adc_btm_warm_scheduler_fn(struct work_struct *work)
-{
- struct pm8921_adc *adc_pmic = container_of(work, struct pm8921_adc,
- warm_work);
- unsigned long flags = 0;
- bool warm_status;
-
- spin_lock_irqsave(&adc_pmic->btm_lock, flags);
- warm_status = irq_read_line(adc_pmic->btm_warm_irq);
- if (adc_pmic->batt->btm_warm_fn != NULL)
- adc_pmic->batt->btm_warm_fn(warm_status);
- spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
-}
-
-static void pm8921_adc_btm_cool_scheduler_fn(struct work_struct *work)
-{
- struct pm8921_adc *adc_pmic = container_of(work, struct pm8921_adc,
- cool_work);
- unsigned long flags = 0;
- bool cool_status;
-
- spin_lock_irqsave(&adc_pmic->btm_lock, flags);
- cool_status = irq_read_line(adc_pmic->btm_cool_irq);
- if (adc_pmic->batt->btm_cool_fn != NULL)
- adc_pmic->batt->btm_cool_fn(cool_status);
- spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
-}
-
-static irqreturn_t pm8921_adc_isr(int irq, void *dev_id)
-{
- struct pm8921_adc *adc_8921 = dev_id;
-
- disable_irq_nosync(adc_8921->adc_irq);
-
- if (pm8921_adc_calib_first_adc)
- return IRQ_HANDLED;
- /* TODO Handle spurius interrupt condition */
- complete(&adc_8921->adc_rslt_completion);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t pm8921_btm_warm_isr(int irq, void *dev_id)
-{
- struct pm8921_adc *btm_8921 = dev_id;
-
- schedule_work(&btm_8921->warm_work);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t pm8921_btm_cool_isr(int irq, void *dev_id)
-{
- struct pm8921_adc *btm_8921 = dev_id;
-
- schedule_work(&btm_8921->cool_work);
-
- return IRQ_HANDLED;
-}
-
-static uint32_t pm8921_adc_calib_device(void)
-{
- struct pm8921_adc *adc_pmic = pmic_adc;
- struct pm8921_adc_amux_properties conv;
- int rc, offset_adc, slope_adc, calib_read_1, calib_read_2;
- u8 data_arb_usrp_cntrl1 = 0;
-
- conv.amux_channel = CHANNEL_125V;
- conv.decimation = ADC_DECIMATION_TYPE2;
- conv.amux_ip_rsv = AMUX_RSV1;
- conv.amux_mpp_channel = PREMUX_MPP_SCALE_0;
- pm8921_adc_calib_first_adc = true;
- rc = pm8921_adc_configure(&conv);
- if (rc) {
- pr_err("pm8921_adc configure failed with %d\n", rc);
- goto calib_fail;
- }
-
- while (data_arb_usrp_cntrl1 != (PM8921_ADC_ARB_USRP_CNTRL1_EOC |
- PM8921_ADC_ARB_USRP_CNTRL1_EN_ARB)) {
- rc = pm8921_adc_read_reg(PM8921_ADC_ARB_USRP_CNTRL1,
- &data_arb_usrp_cntrl1);
- if (rc < 0)
- return rc;
- usleep_range(PM8921_ADC_CONV_TIME_MIN,
- PM8921_ADC_CONV_TIME_MAX);
- }
- data_arb_usrp_cntrl1 = 0;
-
- rc = pm8921_adc_read_adc_code(&calib_read_1);
- if (rc) {
- pr_err("pm8921_adc read adc failed with %d\n", rc);
- pm8921_adc_calib_first_adc = false;
- goto calib_fail;
- }
- pm8921_adc_calib_first_adc = false;
-
- conv.amux_channel = CHANNEL_625MV;
- conv.decimation = ADC_DECIMATION_TYPE2;
- conv.amux_ip_rsv = AMUX_RSV1;
- conv.amux_mpp_channel = PREMUX_MPP_SCALE_0;
- pm8921_adc_calib_first_adc = true;
- rc = pm8921_adc_configure(&conv);
- if (rc) {
- pr_err("pm8921_adc configure failed with %d\n", rc);
- goto calib_fail;
- }
-
- while (data_arb_usrp_cntrl1 != (PM8921_ADC_ARB_USRP_CNTRL1_EOC |
- PM8921_ADC_ARB_USRP_CNTRL1_EN_ARB)) {
- rc = pm8921_adc_read_reg(PM8921_ADC_ARB_USRP_CNTRL1,
- &data_arb_usrp_cntrl1);
- if (rc < 0)
- return rc;
- usleep_range(PM8921_ADC_CONV_TIME_MIN,
- PM8921_ADC_CONV_TIME_MAX);
- }
- data_arb_usrp_cntrl1 = 0;
-
- rc = pm8921_adc_read_adc_code(&calib_read_2);
- if (rc) {
- pr_err("pm8921_adc read adc failed with %d\n", rc);
- pm8921_adc_calib_first_adc = false;
- goto calib_fail;
- }
- pm8921_adc_calib_first_adc = false;
-
- slope_adc = (((calib_read_1 - calib_read_2) << PM8921_ADC_MUL)/
- PM8921_CHANNEL_ADC_625_MV);
- offset_adc = calib_read_2 -
- ((slope_adc * PM8921_CHANNEL_ADC_625_MV) >>
- PM8921_ADC_MUL);
-
- adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_ABSOLUTE].offset
- = offset_adc;
- adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_ABSOLUTE].dy =
- (calib_read_1 - calib_read_2);
- adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_ABSOLUTE].dx
- = PM8921_CHANNEL_ADC_625_MV;
- rc = pm8921_adc_arb_cntrl(0, CHANNEL_MUXOFF);
- if (rc < 0) {
- pr_err("%s: Configuring ADC Arbiter disable"
- "failed\n", __func__);
- return rc;
- }
- /* Ratiometric Calibration */
- conv.amux_channel = CHANNEL_MUXOFF;
- conv.decimation = ADC_DECIMATION_TYPE2;
- conv.amux_ip_rsv = AMUX_RSV5;
- conv.amux_mpp_channel = PREMUX_MPP_SCALE_0;
- pm8921_adc_calib_first_adc = true;
- rc = pm8921_adc_configure(&conv);
- if (rc) {
- pr_err("pm8921_adc configure failed with %d\n", rc);
- goto calib_fail;
- }
-
- while (data_arb_usrp_cntrl1 != (PM8921_ADC_ARB_USRP_CNTRL1_EOC |
- PM8921_ADC_ARB_USRP_CNTRL1_EN_ARB)) {
- rc = pm8921_adc_read_reg(PM8921_ADC_ARB_USRP_CNTRL1,
- &data_arb_usrp_cntrl1);
- if (rc < 0)
- return rc;
- usleep_range(PM8921_ADC_CONV_TIME_MIN,
- PM8921_ADC_CONV_TIME_MAX);
- }
- data_arb_usrp_cntrl1 = 0;
-
- rc = pm8921_adc_read_adc_code(&calib_read_1);
- if (rc) {
- pr_err("pm8921_adc read adc failed with %d\n", rc);
- pm8921_adc_calib_first_adc = false;
- goto calib_fail;
- }
- pm8921_adc_calib_first_adc = false;
-
- conv.amux_channel = CHANNEL_MUXOFF;
- conv.decimation = ADC_DECIMATION_TYPE2;
- conv.amux_ip_rsv = AMUX_RSV4;
- conv.amux_mpp_channel = PREMUX_MPP_SCALE_0;
- pm8921_adc_calib_first_adc = true;
- rc = pm8921_adc_configure(&conv);
- if (rc) {
- pr_err("pm8921_adc configure failed with %d\n", rc);
- goto calib_fail;
- }
-
- while (data_arb_usrp_cntrl1 != (PM8921_ADC_ARB_USRP_CNTRL1_EOC |
- PM8921_ADC_ARB_USRP_CNTRL1_EN_ARB)) {
- rc = pm8921_adc_read_reg(PM8921_ADC_ARB_USRP_CNTRL1,
- &data_arb_usrp_cntrl1);
- if (rc < 0)
- return rc;
- usleep_range(PM8921_ADC_CONV_TIME_MIN,
- PM8921_ADC_CONV_TIME_MAX);
- }
- data_arb_usrp_cntrl1 = 0;
-
- rc = pm8921_adc_read_adc_code(&calib_read_2);
- if (rc) {
- pr_err("pm8921_adc read adc failed with %d\n", rc);
- pm8921_adc_calib_first_adc = false;
- goto calib_fail;
- }
- pm8921_adc_calib_first_adc = false;
-
- slope_adc = (((calib_read_1 - calib_read_2) << PM8921_ADC_MUL)/
- adc_pmic->adc_prop->adc_vdd_reference);
- offset_adc = calib_read_2 -
- ((slope_adc * adc_pmic->adc_prop->adc_vdd_reference)
- >> PM8921_ADC_MUL);
- adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_RATIOMETRIC].offset
- = offset_adc;
- adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_RATIOMETRIC].dy =
- (calib_read_1 - calib_read_2);
- adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_RATIOMETRIC].dx =
- adc_pmic->adc_prop->adc_vdd_reference;
- adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_RATIOMETRIC].adc_vref =
- calib_read_1;
- adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_RATIOMETRIC].adc_gnd =
- calib_read_2;
-calib_fail:
- rc = pm8921_adc_arb_cntrl(0, CHANNEL_MUXOFF);
- if (rc < 0) {
- pr_err("%s: Configuring ADC Arbiter disable"
- "failed\n", __func__);
- }
-
- return rc;
-}
-
-uint32_t pm8921_adc_read(enum pm8921_adc_channels channel,
- struct pm8921_adc_chan_result *result)
-{
- struct pm8921_adc *adc_pmic = pmic_adc;
- int i = 0, rc = 0, rc_fail, amux_prescaling, scale_type;
- enum pm8921_adc_premux_mpp_scale_type mpp_scale;
-
- if (!pm8921_adc_initialized)
- return -ENODEV;
-
- if (!pm8921_adc_calib_device_init) {
- if (pm8921_adc_calib_device() == 0)
- pm8921_adc_calib_device_init = true;
- }
-
- mutex_lock(&adc_pmic->adc_lock);
-
- for (i = 0; i < adc_pmic->adc_num_channel; i++) {
- if (channel == adc_pmic->adc_channel[i].channel_name)
- break;
- }
-
- if (i == adc_pmic->adc_num_channel) {
- rc = -EBADF;
- goto fail_unlock;
- }
-
- if (channel < PM8921_CHANNEL_MPP_SCALE1_IDX) {
- mpp_scale = PREMUX_MPP_SCALE_0;
- adc_pmic->conv->amux_channel = channel;
- } else if (channel >= PM8921_CHANNEL_MPP_SCALE1_IDX) {
- mpp_scale = PREMUX_MPP_SCALE_1;
- adc_pmic->conv->amux_channel = channel %
- PM8921_CHANNEL_MPP_SCALE1_IDX;
- } else if (channel >= PM8921_CHANNEL_MPP_SCALE3_IDX) {
- mpp_scale = PREMUX_MPP_SCALE_1_DIV3;
- adc_pmic->conv->amux_channel = channel %
- PM8921_CHANNEL_MPP_SCALE3_IDX;
- }
-
- adc_pmic->conv->amux_mpp_channel = mpp_scale;
- adc_pmic->conv->amux_ip_rsv = adc_pmic->adc_channel[i].adc_rsv;
- adc_pmic->conv->decimation = adc_pmic->adc_channel[i].adc_decimation;
- amux_prescaling = adc_pmic->adc_channel[i].chan_path_prescaling;
-
- adc_pmic->conv->chan_prop->offset_gain_numerator =
- pm8921_amux_scaling_ratio[amux_prescaling].num;
- adc_pmic->conv->chan_prop->offset_gain_denominator =
- pm8921_amux_scaling_ratio[amux_prescaling].den;
-
- rc = pm8921_adc_channel_power_enable(channel, true);
- if (rc) {
- rc = -EINVAL;
- goto fail_unlock;
- }
-
- rc = pm8921_adc_configure(adc_pmic->conv);
- if (rc) {
- rc = -EINVAL;
- goto fail;
- }
-
- wait_for_completion(&adc_pmic->adc_rslt_completion);
-
- rc = pm8921_adc_read_adc_code(&result->adc_code);
- if (rc) {
- rc = -EINVAL;
- goto fail;
- }
-
- scale_type = adc_pmic->adc_channel[i].adc_scale_fn;
- if (scale_type >= ADC_SCALE_NONE) {
- rc = -EBADF;
- goto fail;
- }
-
- adc_scale_fn[scale_type].chan(result->adc_code,
- adc_pmic->adc_prop, adc_pmic->conv->chan_prop, result);
-
- rc = pm8921_adc_channel_power_enable(channel, false);
- if (rc) {
- rc = -EINVAL;
- goto fail_unlock;
- }
-
- mutex_unlock(&adc_pmic->adc_lock);
-
- return 0;
-fail:
- rc_fail = pm8921_adc_channel_power_enable(channel, false);
- if (rc_fail)
- pr_err("pm8921 adc power disable failed\n");
-fail_unlock:
- mutex_unlock(&adc_pmic->adc_lock);
- pr_err("pm8921 adc error with %d\n", rc);
- return rc;
-}
-EXPORT_SYMBOL_GPL(pm8921_adc_read);
-
-uint32_t pm8921_adc_mpp_config_read(uint32_t mpp_num,
- enum pm8921_adc_channels channel,
- struct pm8921_adc_chan_result *result)
-{
- struct pm8921_adc *adc_pmic = pmic_adc;
- int rc = 0;
-
- if (!adc_pmic->mpp_base) {
- rc = -EINVAL;
- pr_info("PM8921 MPP base invalid with error %d\n", rc);
- return rc;
- }
-
- if (mpp_num == PM8921_AMUX_MPP_8) {
- rc = -EINVAL;
- pr_info("PM8921 MPP8 is already configured "
- "to AMUX8. Use pm8921_adc_read() instead.\n");
- return rc;
- }
-
- mutex_lock(&adc_pmic->mpp_adc_lock);
-
- rc = pm8xxx_mpp_config(((mpp_num - 1) + adc_pmic->mpp_base),
- &pm8921_adc_mpp_config);
- if (rc < 0) {
- pr_err("pm8921 adc mpp config error with %d\n", rc);
- goto fail;
- }
-
- usleep_range(PM8921_ADC_MPP_SETTLE_TIME_MIN,
- PM8921_ADC_MPP_SETTLE_TIME_MAX);
-
- rc = pm8921_adc_read(channel, result);
- if (rc < 0)
- pr_err("pm8921 adc read error with %d\n", rc);
-
- rc = pm8xxx_mpp_config(((mpp_num - 1) + adc_pmic->mpp_base),
- &pm8921_adc_mpp_unconfig);
- if (rc < 0)
- pr_err("pm8921 adc mpp config error with %d\n", rc);
-fail:
- mutex_unlock(&adc_pmic->mpp_adc_lock);
-
- return rc;
-}
-EXPORT_SYMBOL_GPL(pm8921_adc_mpp_config_read);
-
-uint32_t pm8921_adc_btm_configure(struct pm8921_adc_arb_btm_param *btm_param)
-{
- struct pm8921_adc *adc_pmic = pmic_adc;
- u8 data_btm_cool_thr0, data_btm_cool_thr1;
- u8 data_btm_warm_thr0, data_btm_warm_thr1;
- u8 arb_btm_cntrl1;
- unsigned long flags = 0;
- int rc;
-
- if (adc_pmic == NULL) {
- pr_err("PMIC ADC not valid\n");
- return -EINVAL;
- }
-
- if ((btm_param->btm_cool_fn == NULL) &&
- (btm_param->btm_warm_fn == NULL)) {
- pr_err("No BTM warm/cool notification??\n");
- return -EINVAL;
- }
-
- rc = pm8921_adc_batt_scaler(btm_param, adc_pmic->adc_prop,
- adc_pmic->conv->chan_prop);
- if (rc < 0) {
- pr_err("Failed to lookup the BTM thresholds\n");
- return rc;
- }
-
- spin_lock_irqsave(&adc_pmic->btm_lock, flags);
-
- data_btm_cool_thr0 = ((btm_param->low_thr_voltage << 24) >> 24);
- data_btm_cool_thr1 = ((btm_param->low_thr_voltage << 16) >> 24);
- data_btm_warm_thr0 = ((btm_param->high_thr_voltage << 24) >> 24);
- data_btm_warm_thr1 = ((btm_param->high_thr_voltage << 16) >> 24);
-
- if (btm_param->btm_cool_fn != NULL) {
- rc = pm8921_adc_write_reg(PM8921_ADC_ARB_BTM_BAT_COOL_THR0,
- data_btm_cool_thr0);
- if (rc < 0)
- goto write_err;
-
- rc = pm8921_adc_write_reg(PM8921_ADC_ARB_BTM_BAT_COOL_THR1,
- data_btm_cool_thr1);
- if (rc < 0)
- goto write_err;
-
- adc_pmic->batt->btm_cool_fn = btm_param->btm_cool_fn;
- }
-
- if (btm_param->btm_warm_fn != NULL) {
- rc = pm8921_adc_write_reg(PM8921_ADC_ARB_BTM_BAT_WARM_THR0,
- data_btm_warm_thr0);
- if (rc < 0)
- goto write_err;
-
- rc = pm8921_adc_write_reg(PM8921_ADC_ARB_BTM_BAT_WARM_THR1,
- data_btm_warm_thr1);
- if (rc < 0)
- goto write_err;
-
- adc_pmic->batt->btm_warm_fn = btm_param->btm_warm_fn;
- }
-
- rc = pm8921_adc_read_reg(PM8921_ADC_ARB_BTM_CNTRL1, &arb_btm_cntrl1);
- if (rc < 0)
- goto bail_out;
-
- btm_param->interval &= PM8921_ADC_BTM_INTERVAL_SEL_MASK;
- arb_btm_cntrl1 |=
- btm_param->interval << PM8921_ADC_BTM_INTERVAL_SEL_SHIFT;
-
- rc = pm8921_adc_write_reg(PM8921_ADC_ARB_BTM_CNTRL1, arb_btm_cntrl1);
- if (rc < 0)
- goto write_err;
-
- spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
-
- return rc;
-bail_out:
-write_err:
- spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
- pr_debug("%s: with error code %d\n", __func__, rc);
- return rc;
-}
-EXPORT_SYMBOL_GPL(pm8921_adc_btm_configure);
-
-static uint32_t pm8921_adc_btm_read(uint32_t channel)
-{
- struct pm8921_adc *adc_pmic = pmic_adc;
- int rc, i;
- u8 arb_btm_dig_param, arb_btm_ana_param, arb_btm_rsv;
- u8 arb_btm_amux_cntrl, data_arb_btm_cntrl = 0;
- unsigned long flags;
-
- arb_btm_amux_cntrl = channel << PM8921_ADC_BTM_CHANNEL_SEL;
- arb_btm_rsv = adc_pmic->adc_channel[channel].adc_rsv;
- arb_btm_dig_param = arb_btm_ana_param = PM8921_ADC_ARB_ANA_DIG;
-
- spin_lock_irqsave(&adc_pmic->btm_lock, flags);
-
- rc = pm8921_adc_write_reg(PM8921_ADC_ARB_BTM_AMUX_CNTRL,
- arb_btm_amux_cntrl);
- if (rc < 0)
- goto write_err;
-
- arb_btm_rsv = PM8921_ADC_BTM_RSV;
-
- rc = pm8921_adc_write_reg(PM8921_ADC_ARB_BTM_RSV, arb_btm_rsv);
- if (rc < 0)
- goto write_err;
-
- rc = pm8921_adc_write_reg(PM8921_ADC_ARB_BTM_DIG_PARAM,
- arb_btm_dig_param);
- if (rc < 0)
- goto write_err;
-
- rc = pm8921_adc_write_reg(PM8921_ADC_ARB_BTM_ANA_PARAM,
- arb_btm_ana_param);
- if (rc < 0)
- goto write_err;
-
- data_arb_btm_cntrl |= PM8921_ADC_ARB_BTM_CNTRL1_EN_BTM;
-
- for (i = 0; i < 2; i++) {
- rc = pm8921_adc_write_reg(PM8921_ADC_ARB_BTM_CNTRL1,
- data_arb_btm_cntrl);
- if (rc < 0)
- goto write_err;
- }
-
- data_arb_btm_cntrl |= PM8921_ADC_ARB_BTM_CNTRL1_REQ
- | PM8921_ADC_ARB_BTM_CNTRL1_SEL_OP_MODE;
-
- rc = pm8921_adc_write_reg(PM8921_ADC_ARB_BTM_CNTRL1,
- data_arb_btm_cntrl);
- if (rc < 0)
- goto write_err;
-
- if (pmic_adc->batt->btm_warm_fn != NULL)
- enable_irq(adc_pmic->btm_warm_irq);
-
- if (pmic_adc->batt->btm_cool_fn != NULL)
- enable_irq(adc_pmic->btm_cool_irq);
-
-write_err:
- spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
- return rc;
-}
-
-uint32_t pm8921_adc_btm_start(void)
-{
- return pm8921_adc_btm_read(CHANNEL_BATT_THERM);
-}
-EXPORT_SYMBOL_GPL(pm8921_adc_btm_start);
-
-uint32_t pm8921_adc_btm_end(void)
-{
- struct pm8921_adc *adc_pmic = pmic_adc;
- int i, rc;
- u8 data_arb_btm_cntrl;
- unsigned long flags;
-
- disable_irq_nosync(adc_pmic->btm_warm_irq);
- disable_irq_nosync(adc_pmic->btm_cool_irq);
-
- spin_lock_irqsave(&adc_pmic->btm_lock, flags);
- /* Set BTM registers to Disable mode */
- rc = pm8921_adc_read_reg(PM8921_ADC_ARB_BTM_CNTRL1,
- &data_arb_btm_cntrl);
- if (rc < 0) {
- spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
- return rc;
- }
-
- data_arb_btm_cntrl |= ~PM8921_ADC_ARB_BTM_CNTRL1_EN_BTM;
- /* Write twice to the CNTRL register for the arbiter settings
- to take into effect */
- for (i = 0; i < 2; i++) {
- rc = pm8921_adc_write_reg(PM8921_ADC_ARB_BTM_CNTRL1,
- data_arb_btm_cntrl);
- if (rc < 0) {
- spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
- return rc;
- }
- }
-
- spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
-
- return rc;
-}
-EXPORT_SYMBOL_GPL(pm8921_adc_btm_end);
-
-static ssize_t pm8921_adc_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct pm8921_adc *adc_pmic = pmic_adc;
- struct pm8921_adc_chan_result result;
- int rc = -1;
-
- if (attr->index < adc_pmic->adc_num_channel)
- rc = pm8921_adc_read(attr->index, &result);
-
- if (rc)
- return 0;
-
- return snprintf(buf, sizeof(struct pm8921_adc_chan_result),
- "Result:%lld Raw:%d\n",
- result.physical, result.adc_code);
-}
-
-static int get_adc(void *data, u64 *val)
-{
- struct pm8921_adc_chan_result result;
- int i = (int)data;
- int rc;
-
- rc = pm8921_adc_read(i, &result);
- if (!rc)
- pr_info("ADC value raw:%x physical:%lld\n",
- result.adc_code, result.physical);
- *val = result.physical;
-
- return 0;
-}
-DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_adc, NULL, "%llu\n");
-
-static int get_mpp_adc(void *data, u64 *val)
-{
- struct pm8921_adc_chan_result result;
- int i = (int)data;
- int rc;
-
- rc = pm8921_adc_mpp_config_read(i,
- ADC_MPP_1_AMUX6, &result);
- if (!rc)
- pr_info("ADC MPP value raw:%x physical:%lld\n",
- result.adc_code, result.physical);
- *val = result.physical;
-
- return 0;
-}
-DEFINE_SIMPLE_ATTRIBUTE(reg_mpp_fops, get_mpp_adc, NULL, "%llu\n");
-
-#ifdef CONFIG_DEBUG_FS
-static void create_debugfs_entries(void)
-{
- pmic_adc->dent = debugfs_create_dir("pm8921_adc", NULL);
-
- if (IS_ERR(pmic_adc->dent)) {
- pr_err("pmic adc debugfs dir not created\n");
- return;
- }
-
- debugfs_create_file("vbat", 0644, pmic_adc->dent,
- (void *)CHANNEL_VBAT, ®_fops);
- debugfs_create_file("625mv", 0644, pmic_adc->dent,
- (void *)CHANNEL_625MV, ®_fops);
- debugfs_create_file("125v", 0644, pmic_adc->dent,
- (void *)CHANNEL_125V, ®_fops);
- debugfs_create_file("die_temp", 0644, pmic_adc->dent,
- (void *)CHANNEL_DIE_TEMP, ®_fops);
- debugfs_create_file("vcoin", 0644, pmic_adc->dent,
- (void *)CHANNEL_VCOIN, ®_fops);
- debugfs_create_file("dc_in", 0644, pmic_adc->dent,
- (void *)CHANNEL_DCIN, ®_fops);
- debugfs_create_file("vph_pwr", 0644, pmic_adc->dent,
- (void *)CHANNEL_VPH_PWR, ®_fops);
- debugfs_create_file("usb_in", 0644, pmic_adc->dent,
- (void *)CHANNEL_USBIN, ®_fops);
- debugfs_create_file("batt_therm", 0644, pmic_adc->dent,
- (void *)CHANNEL_BATT_THERM, ®_fops);
- debugfs_create_file("batt_id", 0644, pmic_adc->dent,
- (void *)CHANNEL_BATT_ID, ®_fops);
- debugfs_create_file("chg_temp", 0644, pmic_adc->dent,
- (void *)CHANNEL_CHG_TEMP, ®_fops);
- debugfs_create_file("charger_current", 0644, pmic_adc->dent,
- (void *)CHANNEL_ICHG, ®_fops);
- debugfs_create_file("ibat", 0644, pmic_adc->dent,
- (void *)CHANNEL_IBAT, ®_fops);
- debugfs_create_file("pa_therm1", 0644, pmic_adc->dent,
- (void *)ADC_MPP_1_AMUX8, ®_fops);
- debugfs_create_file("xo_therm", 0644, pmic_adc->dent,
- (void *)CHANNEL_MUXOFF, ®_fops);
- debugfs_create_file("pa_therm0", 0644, pmic_adc->dent,
- (void *)ADC_MPP_1_AMUX3, ®_fops);
-}
-#else
-static inline void create_debugfs_entries(void)
-{
-}
-#endif
-static struct sensor_device_attribute pm8921_adc_attr =
- SENSOR_ATTR(NULL, S_IRUGO, pm8921_adc_show, NULL, 0);
-
-static int32_t pm8921_adc_init_hwmon(struct platform_device *pdev)
-{
- struct pm8921_adc *adc_pmic = pmic_adc;
- int rc = 0, i;
-
- adc_pmic->sens_attr = kzalloc(pmic_adc->adc_num_board_channel *
- sizeof(struct sensor_device_attribute), GFP_KERNEL);
-
- if (!adc_pmic->sens_attr) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
- rc = -ENOMEM;
- goto hwmon_err_sens;
- }
-
- for (i = 0; i < pmic_adc->adc_num_board_channel; i++) {
- pm8921_adc_attr.index = adc_pmic->adc_channel[i].channel_name;
- pm8921_adc_attr.dev_attr.attr.name =
- adc_pmic->adc_channel[i].name;
- memcpy(&adc_pmic->sens_attr[i], &pm8921_adc_attr,
- sizeof(pm8921_adc_attr));
- rc = device_create_file(&pdev->dev,
- &adc_pmic->sens_attr[i].dev_attr);
- if (rc) {
- dev_err(&pdev->dev, "device_create_file failed for "
- "dev %s\n",
- adc_pmic->adc_channel[i].name);
- goto hwmon_err_sens;
- }
- }
- return 0;
-
-hwmon_err_sens:
- pr_info("Init HWMON failed for pm8921_adc with %d\n", rc);
- return rc;
-}
-
-#ifdef CONFIG_PM
-static int pm8921_adc_suspend_noirq(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct pm8921_adc *adc_pmic = platform_get_drvdata(pdev);
-
- adc_pmic->msm_suspend_check = 1;
-
- return 0;
-}
-
-static int pm8921_adc_resume_noirq(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct pm8921_adc *adc_pmic = platform_get_drvdata(pdev);
-
- adc_pmic->msm_suspend_check = 0;
-
- return 0;
-}
-
-static const struct dev_pm_ops pm8921_adc_dev_pm_ops = {
- .suspend_noirq = pm8921_adc_suspend_noirq,
- .resume_noirq = pm8921_adc_resume_noirq,
-};
-
-#define PM8921_ADC_DEV_PM_OPS (&pm8921_adc_dev_pm_ops)
-#else
-#define PM8921_ADC_DEV_PM_OPS NULL
-#endif
-
-static int __devexit pm8921_adc_teardown(struct platform_device *pdev)
-{
- struct pm8921_adc *adc_pmic = pmic_adc;
- int i;
-
- wake_lock_destroy(&adc_pmic->adc_wakelock);
- free_irq(adc_pmic->adc_irq, adc_pmic);
- free_irq(adc_pmic->btm_warm_irq, adc_pmic);
- free_irq(adc_pmic->btm_cool_irq, adc_pmic);
- platform_set_drvdata(pdev, NULL);
- pmic_adc = NULL;
- kfree(adc_pmic->conv->chan_prop);
- kfree(adc_pmic->adc_channel);
- kfree(adc_pmic->batt);
- for (i = 0; i < adc_pmic->adc_num_board_channel; i++)
- device_remove_file(adc_pmic->dev,
- &adc_pmic->sens_attr[i].dev_attr);
- kfree(adc_pmic->sens_attr);
- kfree(adc_pmic);
- pm8921_adc_initialized = false;
-
- return 0;
-}
-
-static int __devinit pm8921_adc_probe(struct platform_device *pdev)
-{
- const struct pm8921_adc_platform_data *pdata = pdev->dev.platform_data;
- struct pm8921_adc *adc_pmic;
- struct pm8921_adc_amux_properties *adc_amux_prop;
- struct pm8921_adc_chan_properties *adc_pmic_chanprop;
- struct pm8921_adc_arb_btm_param *adc_btm;
- int rc = 0;
-
- if (!pdata) {
- dev_err(&pdev->dev, "no platform data?\n");
- return -EINVAL;
- }
-
- adc_pmic = kzalloc(sizeof(struct pm8921_adc),
- GFP_KERNEL);
- if (!adc_pmic) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
- return -ENOMEM;
- }
-
- adc_amux_prop = kzalloc(sizeof(struct pm8921_adc_amux_properties),
- GFP_KERNEL);
- if (!adc_amux_prop) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
- return -ENOMEM;
- }
-
- adc_pmic_chanprop = kzalloc(sizeof(struct pm8921_adc_chan_properties),
- GFP_KERNEL);
- if (!adc_pmic_chanprop) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
- return -ENOMEM;
- }
-
- adc_btm = kzalloc(sizeof(struct pm8921_adc_arb_btm_param),
- GFP_KERNEL);
- if (!adc_btm) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
- return -ENOMEM;
- }
-
- adc_pmic->dev = &pdev->dev;
- adc_pmic->adc_prop = pdata->adc_prop;
- adc_pmic->conv = adc_amux_prop;
- adc_pmic->conv->chan_prop = adc_pmic_chanprop;
- adc_pmic->batt = adc_btm;
-
- init_completion(&adc_pmic->adc_rslt_completion);
- adc_pmic->adc_channel = pdata->adc_channel;
- adc_pmic->adc_num_board_channel = pdata->adc_num_board_channel;
- adc_pmic->adc_num_channel = ADC_MPP_2_CHANNEL_NONE;
- adc_pmic->mpp_base = pdata->adc_mpp_base;
-
- mutex_init(&adc_pmic->adc_lock);
- mutex_init(&adc_pmic->mpp_adc_lock);
- spin_lock_init(&adc_pmic->btm_lock);
-
- adc_pmic->adc_irq = platform_get_irq(pdev, PM8921_ADC_IRQ_0);
- if (adc_pmic->adc_irq < 0) {
- rc = -ENXIO;
- goto err_cleanup;
- }
-
- rc = request_irq(adc_pmic->adc_irq,
- pm8921_adc_isr,
- IRQF_TRIGGER_RISING, "pm8921_adc_interrupt", adc_pmic);
- if (rc) {
- dev_err(&pdev->dev, "failed to request adc irq "
- "with error %d\n", rc);
- goto err_cleanup;
- }
-
- disable_irq_nosync(adc_pmic->adc_irq);
-
- adc_pmic->btm_warm_irq = platform_get_irq(pdev, PM8921_ADC_IRQ_1);
- if (adc_pmic->btm_warm_irq < 0) {
- rc = -ENXIO;
- goto err_cleanup;
- }
-
- rc = request_irq(adc_pmic->btm_warm_irq,
- pm8921_btm_warm_isr,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "pm8921_btm_warm_interrupt", adc_pmic);
- if (rc) {
- pr_err("btm warm irq failed %d with interrupt number %d\n",
- rc, adc_pmic->btm_warm_irq);
- dev_err(&pdev->dev, "failed to request btm irq\n");
- goto err_cleanup;
- }
-
- disable_irq_nosync(adc_pmic->btm_warm_irq);
-
- adc_pmic->btm_cool_irq = platform_get_irq(pdev, PM8921_ADC_IRQ_2);
- if (adc_pmic->btm_cool_irq < 0) {
- rc = -ENXIO;
- goto err_cleanup;
- }
-
- rc = request_irq(adc_pmic->btm_cool_irq,
- pm8921_btm_cool_isr,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "pm8921_btm_cool_interrupt", adc_pmic);
- if (rc) {
- pr_err("btm cool irq failed with return %d and number %d\n",
- rc, adc_pmic->btm_cool_irq);
- dev_err(&pdev->dev, "failed to request btm irq\n");
- goto err_cleanup;
- }
-
- disable_irq_nosync(adc_pmic->btm_cool_irq);
- platform_set_drvdata(pdev, adc_pmic);
- pmic_adc = adc_pmic;
-
- INIT_WORK(&adc_pmic->warm_work, pm8921_adc_btm_warm_scheduler_fn);
- INIT_WORK(&adc_pmic->cool_work, pm8921_adc_btm_cool_scheduler_fn);
- wake_lock_init(&adc_pmic->adc_wakelock, WAKE_LOCK_SUSPEND,
- "pm8921_adc_wakelock");
- create_debugfs_entries();
- pm8921_adc_calib_first_adc = false;
- pm8921_adc_calib_device_init = false;
- pm8921_adc_initialized = true;
-
- rc = pm8921_adc_init_hwmon(pdev);
- if (rc) {
- pr_err("pm8921 adc init hwmon failed with %d\n", rc);
- goto err_cleanup;
- }
- adc_pmic->hwmon = hwmon_device_register(adc_pmic->dev);
- return 0;
-
-err_cleanup:
- pm8921_adc_teardown(pdev);
- return rc;
-}
-
-static struct platform_driver pm8921_adc_driver = {
- .probe = pm8921_adc_probe,
- .remove = __devexit_p(pm8921_adc_teardown),
- .driver = {
- .name = PM8921_ADC_DEV_NAME,
- .owner = THIS_MODULE,
- .pm = PM8921_ADC_DEV_PM_OPS,
- },
-};
-
-static int __init pm8921_adc_init(void)
-{
- return platform_driver_register(&pm8921_adc_driver);
-}
-module_init(pm8921_adc_init);
-
-static void __exit pm8921_adc_exit(void)
-{
- platform_driver_unregister(&pm8921_adc_driver);
-}
-module_exit(pm8921_adc_exit);
-
-MODULE_ALIAS("platform:" PM8921_ADC_DEV_NAME);
-MODULE_DESCRIPTION("PMIC8921 ADC driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index f2b377c..36d7f27 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -390,7 +390,7 @@
{
if (is_word_sized(reg))
return LM75_TEMP_FROM_REG(regval);
- return regval * 1000;
+ return ((s8)regval) * 1000;
}
static inline u16
@@ -398,7 +398,8 @@
{
if (is_word_sized(reg))
return LM75_TEMP_TO_REG(temp);
- return DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, -127000, 128000), 1000);
+ return (s8)DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, -127000, 128000),
+ 1000);
}
/* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */
@@ -1715,7 +1716,8 @@
}
/* Get the monitoring functions started */
-static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
+static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data,
+ enum kinds kind)
{
int i;
u8 tmp, diode;
@@ -1746,10 +1748,16 @@
w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01);
/* Get thermal sensor types */
- diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
+ switch (kind) {
+ case w83627ehf:
+ diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
+ break;
+ default:
+ diode = 0x70;
+ }
for (i = 0; i < 3; i++) {
if ((tmp & (0x02 << i)))
- data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 2;
+ data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 3;
else
data->temp_type[i] = 4; /* thermistor */
}
@@ -2016,7 +2024,7 @@
}
/* Initialize the chip */
- w83627ehf_init_device(data);
+ w83627ehf_init_device(data, sio_data->kind);
data->vrm = vid_which_vrm();
superio_enter(sio_data->sioreg);
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 2747980..16f69be 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -435,7 +435,12 @@
if (!(rq->cmd_flags & REQ_FLUSH))
return BLKPREP_OK;
- cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
+ if (rq->special) {
+ cmd = rq->special;
+ memset(cmd, 0, sizeof(*cmd));
+ } else {
+ cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
+ }
/* FIXME: map struct ide_taskfile on rq->cmd[] */
BUG_ON(cmd == NULL);
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index 0a5008f..2332dc2 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -287,7 +287,7 @@
if (test_bit(RELEASE_RESOURCES, &ep->com.flags)) {
cxgb3_remove_tid(ep->com.tdev, (void *)ep, ep->hwtid);
dst_release(ep->dst);
- l2t_release(L2DATA(ep->com.tdev), ep->l2t);
+ l2t_release(ep->com.tdev, ep->l2t);
}
kfree(ep);
}
@@ -1178,7 +1178,7 @@
release_tid(ep->com.tdev, GET_TID(rpl), NULL);
cxgb3_free_atid(ep->com.tdev, ep->atid);
dst_release(ep->dst);
- l2t_release(L2DATA(ep->com.tdev), ep->l2t);
+ l2t_release(ep->com.tdev, ep->l2t);
put_ep(&ep->com);
return CPL_RET_BUF_DONE;
}
@@ -1375,7 +1375,7 @@
if (!child_ep) {
printk(KERN_ERR MOD "%s - failed to allocate ep entry!\n",
__func__);
- l2t_release(L2DATA(tdev), l2t);
+ l2t_release(tdev, l2t);
dst_release(dst);
goto reject;
}
@@ -1952,7 +1952,7 @@
if (!err)
goto out;
- l2t_release(L2DATA(h->rdev.t3cdev_p), ep->l2t);
+ l2t_release(h->rdev.t3cdev_p, ep->l2t);
fail4:
dst_release(ep->dst);
fail3:
@@ -2123,7 +2123,7 @@
PDBG("%s ep %p redirect to dst %p l2t %p\n", __func__, ep, new,
l2t);
dst_hold(new);
- l2t_release(L2DATA(ep->com.tdev), ep->l2t);
+ l2t_release(ep->com.tdev, ep->l2t);
ep->l2t = l2t;
dst_release(old);
ep->dst = new;
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 07b6c81..6e7dd68 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -381,7 +381,7 @@
spin_lock_irq(&client->buffer_lock);
- have_event = client->head != client->tail;
+ have_event = client->packet_head != client->tail;
if (have_event) {
*event = client->buffer[client->tail++];
client->tail &= client->bufsize - 1;
@@ -400,19 +400,17 @@
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
struct input_event event;
- int retval;
+ int retval = 0;
if (count < input_event_size())
return -EINVAL;
- if (client->packet_head == client->tail && evdev->exist &&
- (file->f_flags & O_NONBLOCK))
- return -EAGAIN;
-
- retval = wait_event_interruptible(evdev->wait,
- client->packet_head != client->tail || !evdev->exist);
- if (retval)
- return retval;
+ if (!(file->f_flags & O_NONBLOCK)) {
+ retval = wait_event_interruptible(evdev->wait,
+ client->packet_head != client->tail || !evdev->exist);
+ if (retval)
+ return retval;
+ }
if (!evdev->exist)
return -ENODEV;
@@ -426,6 +424,8 @@
retval += input_event_size();
}
+ if (retval == 0 && file->f_flags & O_NONBLOCK)
+ retval = -EAGAIN;
return retval;
}
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 0822866..6db0da1 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -401,17 +401,6 @@
Say Y here to enable the driver for the keypad matrix interface
on the Qualcomm PM8058 power management I/C device.
-config KEYBOARD_PMIC8XXX
- tristate "Qualcomm PMIC8XXX keypad support"
- depends on MFD_PM8XXX
- help
- Say Y here if you want to enable the driver for the PMIC8XXX
- keypad provided as a reference design from Qualcomm. This is intended
- to support upto 18x8 matrix based keypad design.
-
- To compile this driver as a module, choose M here: the module will
- be called pmic8xxx-keypad.
-
config KEYBOARD_PXA27x
tristate "PXA27x/PXA3xx keypad support"
depends on PXA27x || PXA3xx || ARCH_MMP
diff --git a/drivers/input/misc/gpio_input.c b/drivers/input/misc/gpio_input.c
index 98d204f..6a0c315 100644
--- a/drivers/input/misc/gpio_input.c
+++ b/drivers/input/misc/gpio_input.c
@@ -82,10 +82,11 @@
if (key_state->debounce & DEBOUNCE_UNSTABLE) {
debounce = key_state->debounce = DEBOUNCE_UNKNOWN;
enable_irq(gpio_to_irq(key_entry->gpio));
- pr_info("gpio_keys_scan_keys: key %x-%x, %d "
- "(%d) continue debounce\n",
- ds->info->type, key_entry->code,
- i, key_entry->gpio);
+ if (gpio_flags & GPIOEDF_PRINT_KEY_UNSTABLE)
+ pr_info("gpio_keys_scan_keys: key %x-%x, %d "
+ "(%d) continue debounce\n",
+ ds->info->type, key_entry->code,
+ i, key_entry->gpio);
}
npolarity = !(gpio_flags & GPIOEDF_ACTIVE_HIGH);
pressed = gpio_get_value(key_entry->gpio) ^ npolarity;
@@ -227,13 +228,25 @@
ds->info->keymap[i].gpio, irq);
goto err_request_irq_failed;
}
- enable_irq_wake(irq);
+ if (ds->info->info.no_suspend) {
+ err = enable_irq_wake(irq);
+ if (err) {
+ pr_err("gpio_event_input_request_irqs: "
+ "enable_irq_wake failed for input %d, "
+ "irq %d\n",
+ ds->info->keymap[i].gpio, irq);
+ goto err_enable_irq_wake_failed;
+ }
+ }
}
return 0;
for (i = ds->info->keymap_size - 1; i >= 0; i--) {
- free_irq(gpio_to_irq(ds->info->keymap[i].gpio),
- &ds->key_state[i]);
+ irq = gpio_to_irq(ds->info->keymap[i].gpio);
+ if (ds->info->info.no_suspend)
+ disable_irq_wake(irq);
+err_enable_irq_wake_failed:
+ free_irq(irq, &ds->key_state[i]);
err_request_irq_failed:
err_gpio_get_irq_num_failed:
;
@@ -341,8 +354,10 @@
hrtimer_cancel(&ds->timer);
if (ds->use_irq) {
for (i = di->keymap_size - 1; i >= 0; i--) {
- free_irq(gpio_to_irq(di->keymap[i].gpio),
- &ds->key_state[i]);
+ int irq = gpio_to_irq(di->keymap[i].gpio);
+ if (ds->info->info.no_suspend)
+ disable_irq_wake(irq);
+ free_irq(irq, &ds->key_state[i]);
}
}
spin_unlock_irqrestore(&ds->irq_lock, irqflags);
diff --git a/drivers/input/misc/pmic8058-othc.c b/drivers/input/misc/pmic8058-othc.c
index c6be119..cac748a 100644
--- a/drivers/input/misc/pmic8058-othc.c
+++ b/drivers/input/misc/pmic8058-othc.c
@@ -27,7 +27,7 @@
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
-#include <linux/mfd/pmic8058.h>
+#include <linux/mfd/pm8xxx/core.h>
#include <linux/pmic8058-othc.h>
#include <linux/msm_adc.h>
@@ -68,6 +68,7 @@
void *adc_handle;
void *accessory_adc_handle;
spinlock_t lock;
+ struct device *dev;
struct regulator *othc_vreg;
struct input_dev *othc_ipd;
struct switch_dev othc_sdev;
@@ -75,7 +76,6 @@
struct othc_accessory_info *accessory_info;
struct hrtimer timer;
struct othc_n_switch_config *switch_config;
- struct pm8058_chip *pm_chip;
struct work_struct switch_work;
struct delayed_work detect_work;
struct delayed_work hs_work;
@@ -149,7 +149,7 @@
return -EINVAL;
}
- rc = pm8058_read(dd->pm_chip, dd->othc_base + 1, ®, 1);
+ rc = pm8xxx_readb(dd->dev->parent, dd->othc_base + 1, ®);
if (rc < 0) {
pr_err("PM8058 read failed\n");
return rc;
@@ -158,7 +158,7 @@
reg &= PM8058_OTHC_EN_SIG_MASK;
reg |= (enable << PM8058_OTHC_EN_SIG_SHIFT);
- rc = pm8058_write(dd->pm_chip, dd->othc_base + 1, ®, 1);
+ rc = pm8xxx_writeb(dd->dev->parent, dd->othc_base + 1, reg);
if (rc < 0) {
pr_err("PM8058 write failed\n");
return rc;
@@ -446,7 +446,7 @@
if (dd->ir_gpio < 0) {
/* Check the MIC_BIAS status */
- rc = pm8058_irq_get_rt_status(dd->pm_chip, dd->othc_irq_ir);
+ rc = pm8xxx_read_irq_stat(dd->dev->parent, dd->othc_irq_ir);
if (rc < 0) {
pr_err("Unable to read IR status from PMIC\n");
goto fail_ir_accessory;
@@ -462,7 +462,7 @@
}
/* Check the switch status */
- rc = pm8058_irq_get_rt_status(dd->pm_chip, dd->othc_irq_sw);
+ rc = pm8xxx_read_irq_stat(dd->dev->parent, dd->othc_irq_sw);
if (rc < 0) {
pr_err("Unable to read SWITCH status\n");
goto fail_ir_accessory;
@@ -536,19 +536,11 @@
struct pm8058_othc *dd =
container_of(work, struct pm8058_othc, detect_work.work);
- if (dd->othc_ir_state) {
- /* inserted */
- rc = pm8058_accessory_report(dd, 1);
- if (rc)
- pr_err("Accessory could not be detected\n");
- } else {
- /* removed */
- rc = pm8058_accessory_report(dd, 0);
- if (rc)
- pr_err("Accessory could not be detected\n");
- /* Clear existing switch state */
- dd->othc_sw_state = false;
- }
+ /* Accessory has been inserted */
+ rc = pm8058_accessory_report(dd, 1);
+ if (rc)
+ pr_err("Accessory insertion could not be detected\n");
+
enable_irq(dd->othc_irq_ir);
}
@@ -576,7 +568,7 @@
}
spin_unlock_irqrestore(&dd->lock, flags);
- level = pm8058_irq_get_rt_status(dd->pm_chip, dd->othc_irq_sw);
+ level = pm8xxx_read_irq_stat(dd->dev->parent, dd->othc_irq_sw);
if (level < 0) {
pr_err("Unable to read IRQ status register\n");
return IRQ_HANDLED;
@@ -637,19 +629,29 @@
ktime_set((dd->switch_debounce_ms / 1000),
(dd->switch_debounce_ms % 1000) * 1000000), HRTIMER_MODE_REL);
- /* disable irq, this gets enabled in the workqueue */
- disable_irq_nosync(dd->othc_irq_ir);
/* Check the MIC_BIAS status, to check if inserted or removed */
- rc = pm8058_irq_get_rt_status(dd->pm_chip, dd->othc_irq_ir);
+ rc = pm8xxx_read_irq_stat(dd->dev->parent, dd->othc_irq_ir);
if (rc < 0) {
pr_err("Unable to read IR status\n");
goto fail_ir;
}
dd->othc_ir_state = rc;
- schedule_delayed_work(&dd->detect_work,
+ if (dd->othc_ir_state) {
+ /* disable irq, this gets enabled in the workqueue */
+ disable_irq_nosync(dd->othc_irq_ir);
+ /* Accessory has been inserted, report with detection delay */
+ schedule_delayed_work(&dd->detect_work,
msecs_to_jiffies(dd->detection_delay_ms));
+ } else {
+ /* Accessory has been removed, report removal immediately */
+ rc = pm8058_accessory_report(dd, 0);
+ if (rc)
+ pr_err("Accessory removal could not be detected\n");
+ /* Clear existing switch state */
+ dd->othc_sw_state = false;
+ }
fail_ir:
return IRQ_HANDLED;
@@ -666,7 +668,7 @@
/* Intialize the OTHC module */
/* Control Register 1*/
- rc = pm8058_read(dd->pm_chip, base_addr, ®, 1);
+ rc = pm8xxx_readb(dd->dev->parent, base_addr, ®);
if (rc < 0) {
pr_err("PM8058 read failed\n");
return rc;
@@ -676,14 +678,14 @@
value = (hsed_config->othc_highcurr_thresh_uA / 100) - 2;
reg = (reg & PM8058_OTHC_HIGH_CURR_MASK) | value;
- rc = pm8058_write(dd->pm_chip, base_addr, ®, 1);
+ rc = pm8xxx_writeb(dd->dev->parent, base_addr, reg);
if (rc < 0) {
pr_err("PM8058 read failed\n");
return rc;
}
/* Control register 2*/
- rc = pm8058_read(dd->pm_chip, base_addr + 1, ®, 1);
+ rc = pm8xxx_readb(dd->dev->parent, base_addr + 1, ®);
if (rc < 0) {
pr_err("PM8058 read failed\n");
return rc;
@@ -718,14 +720,14 @@
}
reg = (reg & PM8058_OTHC_CLK_PREDIV_MASK) | (value - 1);
- rc = pm8058_write(dd->pm_chip, base_addr + 1, ®, 1);
+ rc = pm8xxx_writeb(dd->dev->parent, base_addr + 1, reg);
if (rc < 0) {
pr_err("PM8058 read failed\n");
return rc;
}
/* Control register 3 */
- rc = pm8058_read(dd->pm_chip, base_addr + 2 , ®, 1);
+ rc = pm8xxx_readb(dd->dev->parent, base_addr + 2 , ®);
if (rc < 0) {
pr_err("PM8058 read failed\n");
return rc;
@@ -748,7 +750,7 @@
}
reg = (reg & PM8058_OTHC_PERIOD_CLK_MASK) | value;
- rc = pm8058_write(dd->pm_chip, base_addr + 2, ®, 1);
+ rc = pm8xxx_writeb(dd->dev->parent, base_addr + 2, reg);
if (rc < 0) {
pr_err("PM8058 read failed\n");
return rc;
@@ -1006,7 +1008,7 @@
/* Check if the accessory is already inserted during boot up */
if (dd->ir_gpio < 0) {
- rc = pm8058_irq_get_rt_status(dd->pm_chip, dd->othc_irq_ir);
+ rc = pm8xxx_read_irq_stat(dd->dev->parent, dd->othc_irq_ir);
if (rc < 0) {
pr_err("Unable to get accessory status at boot\n");
goto fail_ir_status;
@@ -1061,22 +1063,9 @@
{
int rc;
struct pm8058_othc *dd;
- struct pm8058_chip *chip;
struct resource *res;
struct pmic8058_othc_config_pdata *pdata = pd->dev.platform_data;
- chip = dev_get_drvdata(pd->dev.parent);
- if (chip == NULL) {
- pr_err("Invalid driver information\n");
- return -EINVAL;
- }
-
- /* Check PMIC8058 version. A0 version is not supported */
- if (pm8058_rev(chip) == PM_8058_REV_1p0) {
- pr_err("PMIC8058 version not supported\n");
- return -ENODEV;
- }
-
if (pdata == NULL) {
pr_err("Platform data not present\n");
return -EINVAL;
@@ -1101,8 +1090,8 @@
goto fail_get_res;
}
+ dd->dev = &pd->dev;
dd->othc_pdata = pdata;
- dd->pm_chip = chip;
dd->othc_base = res->start;
if (pdata->micbias_regulator == NULL) {
pr_err("OTHC regulator not specified\n");
diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c
index 2225b7a..f0da3e8 100644
--- a/drivers/input/misc/pmic8xxx-pwrkey.c
+++ b/drivers/input/misc/pmic8xxx-pwrkey.c
@@ -100,7 +100,9 @@
return -EINVAL;
}
- if (pdata->kpd_trigger_delay_us > 62500) {
+ /* Valid range of pwr key trigger delay is 1/64 sec to 2 seconds. */
+ if (pdata->kpd_trigger_delay_us > USEC_PER_SEC * 2 ||
+ pdata->kpd_trigger_delay_us < USEC_PER_SEC / 64) {
dev_err(&pdev->dev, "invalid power key trigger delay\n");
return -EINVAL;
}
@@ -124,8 +126,8 @@
pwr->phys = "pmic8xxx_pwrkey/input0";
pwr->dev.parent = &pdev->dev;
- delay = (pdata->kpd_trigger_delay_us << 10) / USEC_PER_SEC;
- delay = 1 + ilog2(delay);
+ delay = (pdata->kpd_trigger_delay_us << 6) / USEC_PER_SEC;
+ delay = ilog2(delay);
err = pm8xxx_readb(pdev->dev.parent, PON_CNTL_1, &pon_cntl);
if (err < 0) {
diff --git a/drivers/input/touchscreen/atmel_maxtouch.c b/drivers/input/touchscreen/atmel_maxtouch.c
index d2bd4df..e397774 100644
--- a/drivers/input/touchscreen/atmel_maxtouch.c
+++ b/drivers/input/touchscreen/atmel_maxtouch.c
@@ -939,6 +939,7 @@
input_mt_sync(mxt->input);
}
}
+ input_report_key(mxt->input, BTN_TOUCH, !!active_touches);
if (active_touches == 0)
input_mt_sync(mxt->input);
input_sync(mxt->input);
@@ -1877,7 +1878,7 @@
const struct i2c_device_id *id)
{
struct mxt_data *mxt;
- struct mxt_platform_data *pdata;
+ struct maxtouch_platform_data *pdata;
struct input_dev *input;
u8 *id_data;
u8 *t38_data;
diff --git a/drivers/input/touchscreen/cy8c_ts.c b/drivers/input/touchscreen/cy8c_ts.c
index ac4138e..f708582 100644
--- a/drivers/input/touchscreen/cy8c_ts.c
+++ b/drivers/input/touchscreen/cy8c_ts.c
@@ -197,8 +197,7 @@
input_report_abs(ts->input, ABS_MT_TRACKING_ID, id);
input_report_abs(ts->input, ABS_MT_POSITION_X, x);
input_report_abs(ts->input, ABS_MT_POSITION_Y, y);
- input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, pressure);
- input_report_abs(ts->input, ABS_MT_WIDTH_MAJOR, ts->dd->finger_size);
+ input_report_abs(ts->input, ABS_MT_PRESSURE, pressure);
input_mt_sync(ts->input);
}
@@ -227,8 +226,7 @@
}
for (i = 0; i < ts->prev_touches - touches; i++) {
- input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, 0);
- input_report_abs(ts->input, ABS_MT_WIDTH_MAJOR, 0);
+ input_report_abs(ts->input, ABS_MT_PRESSURE, 0);
input_mt_sync(ts->input);
}
@@ -263,8 +261,7 @@
}
} else {
for (i = 0; i < ts->prev_touches; i++) {
- input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, 0);
- input_report_abs(ts->input, ABS_MT_WIDTH_MAJOR, 0);
+ input_report_abs(ts->input, ABS_MT_PRESSURE, 0);
input_mt_sync(ts->input);
}
}
@@ -402,10 +399,8 @@
ts->pdata->dis_min_x, ts->pdata->dis_max_x, 0, 0);
input_set_abs_params(input_device, ABS_MT_POSITION_Y,
ts->pdata->dis_min_y, ts->pdata->dis_max_y, 0, 0);
- input_set_abs_params(input_device, ABS_MT_TOUCH_MAJOR,
+ input_set_abs_params(input_device, ABS_MT_PRESSURE,
ts->pdata->min_touch, ts->pdata->max_touch, 0, 0);
- input_set_abs_params(input_device, ABS_MT_WIDTH_MAJOR,
- ts->pdata->min_width, ts->pdata->max_width, 0, 0);
input_set_abs_params(input_device, ABS_MT_TRACKING_ID,
ts->pdata->min_tid, ts->pdata->max_tid, 0, 0);
diff --git a/drivers/input/touchscreen/cyttsp-i2c.c b/drivers/input/touchscreen/cyttsp-i2c.c
index 4aa4796..9df1189 100644
--- a/drivers/input/touchscreen/cyttsp-i2c.c
+++ b/drivers/input/touchscreen/cyttsp-i2c.c
@@ -935,6 +935,7 @@
u16 st_x2, st_y2;
u8 st_z2;
s32 retval;
+ int val;
cyttsp_xdebug("TTSP handler start 1:\n");
@@ -1239,16 +1240,20 @@
FLIP_XY(g_xy_data.x4, g_xy_data.y4);
if (rev_x) {
- g_xy_data.x4 = INVERT_X(g_xy_data.x4,
- ts->platform_data->panel_maxx);
- if (g_xy_data.x4 < 0)
+ val = INVERT_X(g_xy_data.x4,
+ ts->platform_data->panel_maxx);
+ if (val >= 0)
+ g_xy_data.x4 = val;
+ else
pr_debug("X value is negative. Please configure"
" maxx in platform data structure\n");
}
if (rev_y) {
- g_xy_data.y4 = INVERT_X(g_xy_data.y4,
- ts->platform_data->panel_maxy);
- if (g_xy_data.y4 < 0)
+ val = INVERT_X(g_xy_data.y4,
+ ts->platform_data->panel_maxy);
+ if (val >= 0)
+ g_xy_data.y4 = val;
+ else
pr_debug("Y value is negative. Please configure"
" maxy in platform data structure\n");
@@ -1293,17 +1298,21 @@
FLIP_XY(g_xy_data.x3, g_xy_data.y3);
if (rev_x) {
- g_xy_data.x3 = INVERT_X(g_xy_data.x3,
- ts->platform_data->panel_maxx);
- if (g_xy_data.x3 < 0)
+ val = INVERT_X(g_xy_data.x3,
+ ts->platform_data->panel_maxx);
+ if (val >= 0)
+ g_xy_data.x3 = val;
+ else
pr_debug("X value is negative. Please configure"
" maxx in platform data structure\n");
}
if (rev_y) {
- g_xy_data.y3 = INVERT_X(g_xy_data.y3,
- ts->platform_data->panel_maxy);
- if (g_xy_data.y3 < 0)
+ val = INVERT_X(g_xy_data.y3,
+ ts->platform_data->panel_maxy);
+ if (val >= 0)
+ g_xy_data.y3 = val;
+ else
pr_debug("Y value is negative. Please configure"
" maxy in platform data structure\n");
@@ -1348,16 +1357,20 @@
FLIP_XY(g_xy_data.x2, g_xy_data.y2);
if (rev_x) {
- g_xy_data.x2 = INVERT_X(g_xy_data.x2,
- ts->platform_data->panel_maxx);
- if (g_xy_data.x2 < 0)
+ val = INVERT_X(g_xy_data.x2,
+ ts->platform_data->panel_maxx);
+ if (val >= 0)
+ g_xy_data.x2 = val;
+ else
pr_debug("X value is negative. Please configure"
" maxx in platform data structure\n");
}
if (rev_y) {
- g_xy_data.y2 = INVERT_X(g_xy_data.y2,
- ts->platform_data->panel_maxy);
- if (g_xy_data.y2 < 0)
+ val = INVERT_X(g_xy_data.y2,
+ ts->platform_data->panel_maxy);
+ if (val >= 0)
+ g_xy_data.y2 = val;
+ else
pr_debug("Y value is negative. Please configure"
" maxy in platform data structure\n");
}
@@ -1401,16 +1414,20 @@
FLIP_XY(g_xy_data.x1, g_xy_data.y1);
if (rev_x) {
- g_xy_data.x1 = INVERT_X(g_xy_data.x1,
- ts->platform_data->panel_maxx);
- if (g_xy_data.x1 < 0)
+ val = INVERT_X(g_xy_data.x1,
+ ts->platform_data->panel_maxx);
+ if (val >= 0)
+ g_xy_data.x1 = val;
+ else
pr_debug("X value is negative. Please configure"
" maxx in platform data structure\n");
}
if (rev_y) {
- g_xy_data.y1 = INVERT_X(g_xy_data.y1,
- ts->platform_data->panel_maxy);
- if (g_xy_data.y1 < 0)
+ val = INVERT_X(g_xy_data.y1,
+ ts->platform_data->panel_maxy);
+ if (val >= 0)
+ g_xy_data.y1 = val;
+ else
pr_debug("Y value is negative. Please configure"
" maxy in platform data structure");
}
@@ -2744,7 +2761,7 @@
ts = kzalloc(sizeof(struct cyttsp), GFP_KERNEL);
if (ts == NULL) {
cyttsp_xdebug1("err kzalloc for cyttsp\n");
- retval = -ENOMEM;
+ return -ENOMEM;
}
/* Enable runtime PM ops, start in ACTIVE mode */
@@ -2779,10 +2796,8 @@
error = cyttsp_initialize(client, ts);
if (error) {
cyttsp_xdebug1("err cyttsp_initialize\n");
- if (ts != NULL) {
- /* deallocate memory */
- kfree(ts);
- }
+ /* deallocate memory */
+ kfree(ts);
/*
i2c_del_driver(&cyttsp_driver);
*/
@@ -3054,8 +3069,7 @@
gpio_free(ts->platform_data->irq_gpio);
/* housekeeping */
- if (ts != NULL)
- kfree(ts);
+ kfree(ts);
cyttsp_alert("Leaving\n");
diff --git a/drivers/input/touchscreen/cyttsp_fw.h b/drivers/input/touchscreen/cyttsp_fw.h
old mode 100755
new mode 100644
diff --git a/drivers/input/touchscreen/synaptics/rmi_f11.c b/drivers/input/touchscreen/synaptics/rmi_f11.c
index 9a23776..4caaf92 100644
--- a/drivers/input/touchscreen/synaptics/rmi_f11.c
+++ b/drivers/input/touchscreen/synaptics/rmi_f11.c
@@ -188,11 +188,7 @@
}
}
input_report_key(function_device->input,
- BTN_TOUCH, fingerDownCount);
- for (finger = 0; finger < (instanceData->sensorInfo->numberOfFingers - 1); finger++) {
- input_report_key(function_device->input,
- BTN_2 + finger, fingerDownCount >= (finger + 2));
- }
+ BTN_TOUCH, !!fingerDownCount);
for (finger = 0; finger < instanceData->sensorInfo->numberOfFingers; finger++) {
int reg;
@@ -269,14 +265,8 @@
}
#ifdef CONFIG_SYNA_MULTI_TOUCH
/* Report Multi-Touch events for each finger */
- /* major axis of touch area ellipse */
- input_report_abs(function_device->input, ABS_MT_TOUCH_MAJOR, Z);
- /* minor axis of touch area ellipse */
- input_report_abs(function_device->input, ABS_MT_WIDTH_MAJOR,
- max(Wx, Wy));
- /* Currently only 2 supported - 1 or 0 */
- input_report_abs(function_device->input, ABS_MT_ORIENTATION,
- (Wx > Wy ? 1 : 0));
+ input_report_abs(function_device->input,
+ ABS_MT_PRESSURE, Z);
input_report_abs(function_device->input, ABS_MT_POSITION_X, X);
input_report_abs(function_device->input, ABS_MT_POSITION_Y, Y);
@@ -284,7 +274,7 @@
/* Could be formed by keeping an id per position and assiging */
/* a new id when fingerStatus changes for that position.*/
input_report_abs(function_device->input, ABS_MT_TRACKING_ID,
- finger+1);
+ finger);
/* MT sync between fingers */
input_mt_sync(function_device->input);
#endif
@@ -297,17 +287,10 @@
instanceData->wasdown = false;
#ifdef CONFIG_SYNA_MULTI_TOUCH
- input_report_abs(function_device->input, ABS_MT_TOUCH_MAJOR, 0);
- input_report_abs(function_device->input, ABS_MT_WIDTH_MAJOR, 0);
- input_report_abs(function_device->input, ABS_MT_POSITION_X, instanceData->oldX);
- input_report_abs(function_device->input, ABS_MT_POSITION_Y, instanceData->oldY);
- input_report_abs(function_device->input, ABS_MT_TRACKING_ID, 1);
+ input_report_abs(function_device->input, ABS_MT_PRESSURE, 0);
+ input_report_key(function_device->input, BTN_TOUCH, 0);
input_mt_sync(function_device->input);
#endif
-
- input_report_abs(function_device->input, ABS_X, instanceData->oldX);
- input_report_abs(function_device->input, ABS_Y, instanceData->oldY);
- instanceData->oldX = instanceData->oldY = 0;
}
FN_11_relreport(rmifninfo);
@@ -468,10 +451,11 @@
input_set_abs_params(function_device->input, ABS_TOOL_WIDTH, 0, 15, 0, 0);
#ifdef CONFIG_SYNA_MULTI_TOUCH
- input_set_abs_params(function_device->input, ABS_MT_TOUCH_MAJOR, 0, 15, 0, 0);
- input_set_abs_params(function_device->input, ABS_MT_TOUCH_MINOR, 0, 15, 0, 0);
+ input_set_abs_params(function_device->input, ABS_MT_PRESSURE,
+ 0, 15, 0, 0);
input_set_abs_params(function_device->input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
- input_set_abs_params(function_device->input, ABS_MT_TRACKING_ID, 1, 10, 0, 0);
+ input_set_abs_params(function_device->input, ABS_MT_TRACKING_ID,
+ 0, 10, 0, 0);
input_set_abs_params(function_device->input, ABS_MT_POSITION_X, xMin, xMax,
0, 0);
input_set_abs_params(function_device->input, ABS_MT_POSITION_Y, yMin, yMax,
@@ -536,8 +520,8 @@
set_bit(EV_ABS, function_device->input->evbit);
set_bit(EV_SYN, function_device->input->evbit);
set_bit(EV_KEY, function_device->input->evbit);
- set_bit(BTN_MISC, function_device->input->keybit);
- set_bit(KEY_OK, function_device->input->keybit);
+ set_bit(BTN_TOUCH, function_device->input->keybit);
+ set_bit(KEY_OK, function_device->input->keybit);
f11_set_abs_params(function_device);
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index 9798811..b145b5a 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -2531,6 +2531,9 @@
/* Setup the generic properties */
dev->flags = IFF_NOARP|IFF_POINTOPOINT;
+
+ /* isdn prepends a header in the tx path, can't share skbs */
+ dev->priv_flags &= ~IFF_TX_SKB_SHARING;
dev->header_ops = NULL;
dev->netdev_ops = &isdn_netdev_ops;
diff --git a/drivers/leds/leds-pmic8058.c b/drivers/leds/leds-pmic8058.c
index d1aed3f..3b3a24a 100644
--- a/drivers/leds/leds-pmic8058.c
+++ b/drivers/leds/leds-pmic8058.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010, 2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -15,7 +15,7 @@
#include <linux/leds.h>
#include <linux/workqueue.h>
#include <linux/spinlock.h>
-#include <linux/mfd/pmic8058.h>
+#include <linux/mfd/pm8xxx/core.h>
#include <linux/leds-pmic8058.h>
#define SSBI_REG_ADDR_DRV_KEYPAD 0x48
@@ -41,11 +41,11 @@
#define PMIC8058_LED_OFFSET(id) ((id) - PMIC8058_ID_LED_0)
struct pmic8058_led_data {
+ struct device *dev;
struct led_classdev cdev;
int id;
enum led_brightness brightness;
u8 flags;
- struct pm8058_chip *pm_chip;
struct work_struct work;
struct mutex lock;
spinlock_t value_lock;
@@ -72,8 +72,8 @@
led->reg_kp |= level;
spin_unlock_irqrestore(&led->value_lock, flags);
- rc = pm8058_write(led->pm_chip, SSBI_REG_ADDR_DRV_KEYPAD,
- &led->reg_kp, 1);
+ rc = pm8xxx_writeb(led->dev->parent, SSBI_REG_ADDR_DRV_KEYPAD,
+ led->reg_kp);
if (rc)
pr_err("%s: can't set keypad backlight level\n", __func__);
}
@@ -105,8 +105,8 @@
tmp |= level;
spin_unlock_irqrestore(&led->value_lock, flags);
- rc = pm8058_write(led->pm_chip, SSBI_REG_ADDR_LED_CTRL(offset),
- &tmp, 1);
+ rc = pm8xxx_writeb(led->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset),
+ tmp);
if (rc) {
dev_err(led->cdev.dev, "can't set (%d) led value\n",
led->id);
@@ -159,7 +159,7 @@
}
spin_unlock_irqrestore(&led->value_lock, flags);
- rc = pm8058_write(led->pm_chip, reg_addr, ®_flash_led, 1);
+ rc = pm8xxx_writeb(led->dev->parent, reg_addr, reg_flash_led);
if (rc)
pr_err("%s: can't set flash led%d level %d\n", __func__,
led->id, rc);
@@ -294,46 +294,38 @@
struct pmic8058_led_data *led_dat;
struct pmic8058_led *curr_led;
int rc, i = 0;
- struct pm8058_chip *pm_chip;
u8 reg_kp;
u8 reg_led_ctrl[3];
u8 reg_flash_led0;
u8 reg_flash_led1;
- pm_chip = dev_get_drvdata(pdev->dev.parent);
- if (pm_chip == NULL) {
- dev_err(&pdev->dev, "no parent data passed in\n");
- return -EFAULT;
- }
-
if (pdata == NULL) {
dev_err(&pdev->dev, "platform data not supplied\n");
return -EINVAL;
}
- rc = pm8058_read(pm_chip, SSBI_REG_ADDR_DRV_KEYPAD, ®_kp,
- 1);
+ rc = pm8xxx_readb(pdev->dev.parent, SSBI_REG_ADDR_DRV_KEYPAD, ®_kp);
if (rc) {
dev_err(&pdev->dev, "can't get keypad backlight level\n");
goto err_reg_read;
}
- rc = pm8058_read(pm_chip, SSBI_REG_ADDR_LED_CTRL_BASE,
- reg_led_ctrl, 3);
+ rc = pm8xxx_read_buf(pdev->dev.parent, SSBI_REG_ADDR_LED_CTRL_BASE,
+ reg_led_ctrl, 3);
if (rc) {
dev_err(&pdev->dev, "can't get led levels\n");
goto err_reg_read;
}
- rc = pm8058_read(pm_chip, SSBI_REG_ADDR_FLASH_DRV0,
- ®_flash_led0, 1);
+ rc = pm8xxx_readb(pdev->dev.parent, SSBI_REG_ADDR_FLASH_DRV0,
+ ®_flash_led0);
if (rc) {
dev_err(&pdev->dev, "can't read flash led0\n");
goto err_reg_read;
}
- rc = pm8058_read(pm_chip, SSBI_REG_ADDR_FLASH_DRV1,
- ®_flash_led1, 1);
+ rc = pm8xxx_readb(pdev->dev.parent, SSBI_REG_ADDR_FLASH_DRV1,
+ ®_flash_led1);
if (rc) {
dev_err(&pdev->dev, "can't get flash led1\n");
goto err_reg_read;
@@ -366,7 +358,7 @@
goto fail_id_check;
}
- led_dat->pm_chip = pm_chip;
+ led_dat->dev = &pdev->dev;
mutex_init(&led_dat->lock);
spin_lock_init(&led_dat->value_lock);
diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
index d87c9d0..328c64c 100644
--- a/drivers/leds/ledtrig-timer.c
+++ b/drivers/leds/ledtrig-timer.c
@@ -41,6 +41,7 @@
if (count == size) {
led_blink_set(led_cdev, &state, &led_cdev->blink_delay_off);
+ led_cdev->blink_delay_on = state;
ret = count;
}
@@ -69,6 +70,7 @@
if (count == size) {
led_blink_set(led_cdev, &led_cdev->blink_delay_on, &state);
+ led_cdev->blink_delay_off = state;
ret = count;
}
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 451c3bb..ebdae6e 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -1184,14 +1184,15 @@
return;
template_disk = dm_table_get_integrity_disk(t, true);
- if (!template_disk &&
- blk_integrity_is_initialized(dm_disk(t->md))) {
+ if (template_disk)
+ blk_integrity_register(dm_disk(t->md),
+ blk_get_integrity(template_disk));
+ else if (blk_integrity_is_initialized(dm_disk(t->md)))
DMWARN("%s: device no longer has a valid integrity profile",
dm_device_name(t->md));
- return;
- }
- blk_integrity_register(dm_disk(t->md),
- blk_get_integrity(template_disk));
+ else
+ DMWARN("%s: unable to establish an integrity profile",
+ dm_device_name(t->md));
}
void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
diff --git a/drivers/md/linear.h b/drivers/md/linear.h
index 0ce29b6..2f2da05 100644
--- a/drivers/md/linear.h
+++ b/drivers/md/linear.h
@@ -10,9 +10,9 @@
struct linear_private_data
{
+ struct rcu_head rcu;
sector_t array_sectors;
dev_info_t disks[0];
- struct rcu_head rcu;
};
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 91e31e2..bc83428 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -61,6 +61,11 @@
static void autostart_arrays(int part);
#endif
+/* pers_list is a list of registered personalities protected
+ * by pers_lock.
+ * pers_lock does extra service to protect accesses to
+ * mddev->thread when the mutex cannot be held.
+ */
static LIST_HEAD(pers_list);
static DEFINE_SPINLOCK(pers_lock);
@@ -690,7 +695,12 @@
} else
mutex_unlock(&mddev->reconfig_mutex);
+ /* was we've dropped the mutex we need a spinlock to
+ * make sur the thread doesn't disappear
+ */
+ spin_lock(&pers_lock);
md_wakeup_thread(mddev->thread);
+ spin_unlock(&pers_lock);
}
static mdk_rdev_t * find_rdev_nr(mddev_t *mddev, int nr)
@@ -1084,8 +1094,11 @@
ret = 0;
}
rdev->sectors = rdev->sb_start;
+ /* Limit to 4TB as metadata cannot record more than that */
+ if (rdev->sectors >= (2ULL << 32))
+ rdev->sectors = (2ULL << 32) - 2;
- if (rdev->sectors < sb->size * 2 && sb->level > 1)
+ if (rdev->sectors < ((sector_t)sb->size) * 2 && sb->level >= 1)
/* "this cannot possibly happen" ... */
ret = -EINVAL;
@@ -1119,7 +1132,7 @@
mddev->clevel[0] = 0;
mddev->layout = sb->layout;
mddev->raid_disks = sb->raid_disks;
- mddev->dev_sectors = sb->size * 2;
+ mddev->dev_sectors = ((sector_t)sb->size) * 2;
mddev->events = ev1;
mddev->bitmap_info.offset = 0;
mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9;
@@ -1361,6 +1374,11 @@
rdev->sb_start = calc_dev_sboffset(rdev);
if (!num_sectors || num_sectors > rdev->sb_start)
num_sectors = rdev->sb_start;
+ /* Limit to 4TB as metadata cannot record more than that.
+ * 4TB == 2^32 KB, or 2*2^32 sectors.
+ */
+ if (num_sectors >= (2ULL << 32))
+ num_sectors = (2ULL << 32) - 2;
md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size,
rdev->sb_page);
md_super_wait(rdev->mddev);
@@ -6178,11 +6196,18 @@
return thread;
}
-void md_unregister_thread(mdk_thread_t *thread)
+void md_unregister_thread(mdk_thread_t **threadp)
{
+ mdk_thread_t *thread = *threadp;
if (!thread)
return;
dprintk("interrupting MD-thread pid %d\n", task_pid_nr(thread->tsk));
+ /* Locking ensures that mddev_unlock does not wake_up a
+ * non-existent thread
+ */
+ spin_lock(&pers_lock);
+ *threadp = NULL;
+ spin_unlock(&pers_lock);
kthread_stop(thread->tsk);
kfree(thread);
@@ -7117,8 +7142,7 @@
mdk_rdev_t *rdev;
/* resync has finished, collect result */
- md_unregister_thread(mddev->sync_thread);
- mddev->sync_thread = NULL;
+ md_unregister_thread(&mddev->sync_thread);
if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery) &&
!test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
/* success...*/
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 1c26c7a..ce4e328 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -475,7 +475,7 @@
extern int unregister_md_personality(struct mdk_personality *p);
extern mdk_thread_t * md_register_thread(void (*run) (mddev_t *mddev),
mddev_t *mddev, const char *name);
-extern void md_unregister_thread(mdk_thread_t *thread);
+extern void md_unregister_thread(mdk_thread_t **threadp);
extern void md_wakeup_thread(mdk_thread_t *thread);
extern void md_check_recovery(mddev_t *mddev);
extern void md_write_start(mddev_t *mddev, struct bio *bi);
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index 3535c23..d5b5fb3 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -514,8 +514,7 @@
{
multipath_conf_t *conf = mddev->private;
- md_unregister_thread(mddev->thread);
- mddev->thread = NULL;
+ md_unregister_thread(&mddev->thread);
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
mempool_destroy(conf->pool);
kfree(conf->multipaths);
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index f7431b6..3a9e59f 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -2045,8 +2045,7 @@
raise_barrier(conf);
lower_barrier(conf);
- md_unregister_thread(mddev->thread);
- mddev->thread = NULL;
+ md_unregister_thread(&mddev->thread);
if (conf->r1bio_pool)
mempool_destroy(conf->r1bio_pool);
kfree(conf->mirrors);
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 6e84668..17cb6ab 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -2331,7 +2331,7 @@
return 0;
out_free_conf:
- md_unregister_thread(mddev->thread);
+ md_unregister_thread(&mddev->thread);
if (conf->r10bio_pool)
mempool_destroy(conf->r10bio_pool);
safe_put_page(conf->tmppage);
@@ -2349,8 +2349,7 @@
raise_barrier(conf, 0);
lower_barrier(conf);
- md_unregister_thread(mddev->thread);
- mddev->thread = NULL;
+ md_unregister_thread(&mddev->thread);
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
if (conf->r10bio_pool)
mempool_destroy(conf->r10bio_pool);
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index b72edf3..2581ba1 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -5162,8 +5162,7 @@
return 0;
abort:
- md_unregister_thread(mddev->thread);
- mddev->thread = NULL;
+ md_unregister_thread(&mddev->thread);
if (conf) {
print_raid5_conf(conf);
free_conf(conf);
@@ -5177,8 +5176,7 @@
{
raid5_conf_t *conf = mddev->private;
- md_unregister_thread(mddev->thread);
- mddev->thread = NULL;
+ md_unregister_thread(&mddev->thread);
if (mddev->queue)
mddev->queue->backing_dev_info.congested_fn = NULL;
free_conf(conf);
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
index 3db89e3..536c16c 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ b/drivers/media/dvb/dvb-usb/vp7045.c
@@ -224,26 +224,8 @@
static int vp7045_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- struct dvb_usb_device *d;
- int ret = dvb_usb_device_init(intf, &vp7045_properties,
- THIS_MODULE, &d, adapter_nr);
- if (ret)
- return ret;
-
- d->priv = kmalloc(20, GFP_KERNEL);
- if (!d->priv) {
- dvb_usb_device_exit(intf);
- return -ENOMEM;
- }
-
- return ret;
-}
-
-static void vp7045_usb_disconnect(struct usb_interface *intf)
-{
- struct dvb_usb_device *d = usb_get_intfdata(intf);
- kfree(d->priv);
- dvb_usb_device_exit(intf);
+ return dvb_usb_device_init(intf, &vp7045_properties,
+ THIS_MODULE, NULL, adapter_nr);
}
static struct usb_device_id vp7045_usb_table [] = {
@@ -258,7 +240,7 @@
static struct dvb_usb_device_properties vp7045_properties = {
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-vp7045-01.fw",
- .size_of_priv = sizeof(u8 *),
+ .size_of_priv = 20,
.num_adapters = 1,
.adapter = {
@@ -305,7 +287,7 @@
static struct usb_driver vp7045_usb_driver = {
.name = "dvb_usb_vp7045",
.probe = vp7045_usb_probe,
- .disconnect = vp7045_usb_disconnect,
+ .disconnect = dvb_usb_device_exit,
.id_table = vp7045_usb_table,
};
diff --git a/drivers/media/radio/radio-iris-transport.c b/drivers/media/radio/radio-iris-transport.c
index 50ca58c..57b11c9 100644
--- a/drivers/media/radio/radio-iris-transport.c
+++ b/drivers/media/radio/radio-iris-transport.c
@@ -64,7 +64,7 @@
return;
}
- rc = smd_read_from_cb(hsmd->fm_channel, (void *)buf, len);
+ rc = smd_read(hsmd->fm_channel, (void *)buf, len);
memcpy(skb_put(skb, len), buf, len);
@@ -85,8 +85,10 @@
len = smd_write(hs.fm_channel, skb->data, skb->len);
if (len < skb->len) {
FMDERR("Failed to write Data %d", len);
+ kfree_skb(skb);
return -ENODEV;
}
+ kfree_skb(skb);
return 0;
}
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 2d42e17..8b983d0 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -648,6 +648,15 @@
return radio_hci_send_cmd(hdev, opcode, 0, NULL);
}
+static int hci_get_fm_trans_conf_req(struct radio_hci_dev *hdev,
+ unsigned long param)
+{
+ u16 opcode = 0;
+
+ opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
+ HCI_OCF_FM_GET_TRANS_CONF_REQ);
+ return radio_hci_send_cmd(hdev, opcode, 0, NULL);
+}
static int hci_set_fm_recv_conf_req(struct radio_hci_dev *hdev,
unsigned long param)
{
@@ -1352,18 +1361,30 @@
return ret;
}
-static int hci_fm_set_cal_req(struct radio_hci_dev *hdev,
+static int hci_fm_set_cal_req_proc(struct radio_hci_dev *hdev,
unsigned long param)
{
u16 opcode = 0;
- struct hci_fm_set_cal_req *cal_req =
- (struct hci_fm_set_cal_req *)param;
+ struct hci_fm_set_cal_req_proc *cal_req =
+ (struct hci_fm_set_cal_req_proc *)param;
opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
HCI_OCF_FM_SET_CALIBRATION);
- return radio_hci_send_cmd(hdev, opcode, sizeof((*hci_fm_set_cal_req)),
+ return radio_hci_send_cmd(hdev, opcode, sizeof(*cal_req),
cal_req);
+}
+static int hci_fm_set_cal_req_dc(struct radio_hci_dev *hdev,
+ unsigned long param)
+{
+ u16 opcode = 0;
+ struct hci_fm_set_cal_req_dc *cal_req =
+ (struct hci_fm_set_cal_req_dc *)param;
+
+ opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
+ HCI_OCF_FM_SET_CALIBRATION);
+ return radio_hci_send_cmd(hdev, opcode, sizeof(*cal_req),
+ cal_req);
}
static int hci_fm_do_cal_req(struct radio_hci_dev *hdev,
@@ -1462,6 +1483,10 @@
msecs_to_jiffies(RADIO_HCI_TIMEOUT));
break;
+ case HCI_FM_GET_TX_CONFIG:
+ ret = radio_hci_request(hdev, hci_get_fm_trans_conf_req, arg,
+ msecs_to_jiffies(RADIO_HCI_TIMEOUT));
+ break;
default:
ret = -EINVAL;
break;
@@ -1490,6 +1515,7 @@
if (status)
return;
+
radio_hci_req_complete(hdev, status);
}
@@ -1519,6 +1545,19 @@
radio_hci_req_complete(hdev, rsp->status);
}
+static void hci_cc_fm_trans_get_conf_rsp(struct radio_hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_fm_get_trans_conf_rsp *rsp = (void *)skb->data;
+ struct iris_device *radio = video_get_drvdata(video_get_dev());
+
+ if (rsp->status)
+ return;
+ memcpy((void *)&radio->trans_conf, (void*)&rsp->trans_conf_rsp,
+ sizeof(rsp->trans_conf_rsp));
+ radio_hci_req_complete(hdev, rsp->status);
+}
+
static void hci_cc_fm_enable_rsp(struct radio_hci_dev *hdev,
struct sk_buff *skb)
{
@@ -1851,6 +1890,9 @@
hci_cc_do_calibration_rsp(hdev, skb);
break;
+ case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_GET_TRANS_CONF_REQ):
+ hci_cc_fm_trans_get_conf_rsp(hdev, skb);
+ break;
default:
FMDERR("%s opcode 0x%x", hdev->name, opcode);
break;
@@ -1869,17 +1911,10 @@
struct sk_buff *skb)
{
int i;
- int len;
-
struct iris_device *radio = video_get_drvdata(video_get_dev());
- struct hci_fm_station_rsp *rsp;
- len = sizeof(struct hci_fm_station_rsp);
- rsp = (struct hci_fm_station_rsp *)skb_pull(skb, len);
- if (rsp == NULL)
- return;
- memcpy(&radio->fm_st_rsp.station_rsp, rsp, len);
-
+ memcpy(&radio->fm_st_rsp.station_rsp, &skb->data[0],
+ sizeof(struct hci_ev_tune_status));
iris_q_event(radio, IRIS_EVT_TUNE_SUCC);
for (i = 0; i < IRIS_BUF_MAX; i++) {
@@ -2525,7 +2560,8 @@
struct hci_fm_tx_ps tx_ps;
struct hci_fm_tx_rt tx_rt;
struct hci_fm_def_data_wr_req default_data;
- struct hci_fm_set_cal_req cal_req;
+ struct hci_fm_set_cal_req_proc proc_cal_req;
+ struct hci_fm_set_cal_req_dc dc_cal_req;
struct iris_device *radio = video_get_drvdata(video_devdata(file));
char *data = NULL;
@@ -2579,24 +2615,33 @@
retval = hci_def_data_write(&default_data, radio->fm_hdev);
break;
case V4L2_CID_PRIVATE_IRIS_SET_CALIBRATION:
- FMDERR("In Set Calibration");
data = (ctrl->controls[0]).string;
bytes_to_copy = (ctrl->controls[0]).size;
- memset(cal_req.data, 0, MAX_CALIB_SIZE);
- cal_req.mode = PROCS_CALIB_MODE;
- if (copy_from_user(&cal_req.data[0],
- data, PROCS_CALIB_SIZE))
+ if (bytes_to_copy < (PROCS_CALIB_SIZE + DC_CALIB_SIZE)) {
+ FMDERR("data is less than required size");
+ return -EFAULT;
+ }
+ memset(proc_cal_req.data, 0, PROCS_CALIB_SIZE);
+ proc_cal_req.mode = PROCS_CALIB_MODE;
+ if (copy_from_user(&proc_cal_req.data[0],
+ data, sizeof(proc_cal_req.data)))
return -EFAULT;
- retval = radio_hci_request(radio->fm_hdev, hci_fm_set_cal_req,
- (unsigned long)&cal_req, RADIO_HCI_TIMEOUT);
- if (retval < 0)
+ retval = radio_hci_request(radio->fm_hdev,
+ hci_fm_set_cal_req_proc,
+ (unsigned long)&proc_cal_req,
+ RADIO_HCI_TIMEOUT);
+ if (retval < 0) {
FMDERR("Set Process calibration failed %d", retval);
- if (copy_from_user(&cal_req.data[PROCS_CALIB_SIZE],
- data, DC_CALIB_SIZE))
+ return retval;
+ }
+ memset(dc_cal_req.data, 0, DC_CALIB_SIZE);
+ if (copy_from_user(&dc_cal_req.data[0], &data[PROCS_CALIB_SIZE],
+ sizeof(dc_cal_req.data)))
return -EFAULT;
- cal_req.mode = DC_CALIB_MODE;
- retval = radio_hci_request(radio->fm_hdev, hci_fm_set_cal_req,
- (unsigned long)&cal_req, RADIO_HCI_TIMEOUT);
+ dc_cal_req.mode = DC_CALIB_MODE;
+ retval = radio_hci_request(radio->fm_hdev,
+ hci_fm_set_cal_req_dc,
+ (unsigned long)&dc_cal_req, RADIO_HCI_TIMEOUT);
if (retval < 0)
FMDERR("Set DC calibration failed %d", retval);
break;
@@ -2624,6 +2669,8 @@
retval = radio_hci_request(radio->fm_hdev,
hci_fm_tone_generator, arg,
msecs_to_jiffies(RADIO_HCI_TIMEOUT));
+ if (retval < 0)
+ FMDERR("Error while setting the tone %d", retval);
break;
case V4L2_CID_AUDIO_VOLUME:
break;
@@ -2651,12 +2698,12 @@
case FM_RECV:
retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
radio->fm_hdev);
-
- radio->mode = FM_RECV;
-
- if (retval < 0)
+ if (retval < 0) {
FMDERR("Error while enabling RECV FM"
" %d\n", retval);
+ return retval;
+ }
+ radio->mode = FM_RECV;
radio->mute_mode.soft_mute = CTRL_ON;
retval = hci_set_fm_mute_mode(
&radio->mute_mode,
@@ -2676,6 +2723,14 @@
FMDERR("Failed to set stereo mode\n");
return retval;
}
+ radio->event_mask = SIG_LEVEL_INTR |
+ RDS_SYNC_INTR | AUDIO_CTRL_INTR;
+ retval = hci_conf_event_mask(&radio->event_mask,
+ radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("Enable Async events failed");
+ return retval;
+ }
retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
radio->fm_hdev);
if (retval < 0)
@@ -2685,10 +2740,14 @@
retval = hci_cmd(HCI_FM_ENABLE_TRANS_CMD,
radio->fm_hdev);
radio->mode = FM_TRANS;
-
- if (retval < 0)
+ if (retval < 0) {
FMDERR("Error while enabling TRANS FM"
" %d\n", retval);
+ return retval;
+ }
+ retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
+ if (retval < 0)
+ FMDERR("get frequency failed %d\n", retval);
break;
case FM_OFF:
switch (radio->mode) {
@@ -2746,7 +2805,14 @@
case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
break;
case V4L2_CID_PRIVATE_IRIS_SPACING:
- radio->recv_conf.ch_spacing = ctrl->value;
+ if (radio->mode == FM_RECV) {
+ radio->recv_conf.ch_spacing = ctrl->value;
+ retval = hci_set_fm_recv_conf(
+ &radio->recv_conf,
+ radio->fm_hdev);
+ if (retval < 0)
+ FMDERR("Error in setting channel spacing");
+ }
break;
case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
switch (radio->mode) {
@@ -2926,7 +2992,14 @@
temp_val = ctrl->value;
retval = hci_set_notch_filter(&temp_val, radio->fm_hdev);
break;
-
+ case V4L2_CID_PRIVATE_IRIS_SRCH_ALGORITHM:
+ /*
+ This private control is a place holder to keep the
+ driver compatible with changes done in the frameworks
+ which are specific to TAVARUA.
+ */
+ retval = 0;
+ break;
default:
retval = -EINVAL;
}
@@ -2941,19 +3014,37 @@
if (tuner->index > 0)
return -EINVAL;
- retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
- if (retval < 0)
- return retval;
+ if (radio->mode == FM_RECV) {
+ retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("Failed to Get station params");
+ return retval;
+ }
+ tuner->type = V4L2_TUNER_RADIO;
+ tuner->rangelow =
+ radio->recv_conf.band_low_limit * TUNE_PARAM;
+ tuner->rangehigh =
+ radio->recv_conf.band_high_limit * TUNE_PARAM;
+ tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+ tuner->capability = V4L2_TUNER_CAP_LOW;
+ tuner->signal = radio->fm_st_rsp.station_rsp.rssi;
+ tuner->audmode = radio->fm_st_rsp.station_rsp.stereo_prg;
+ tuner->afc = 0;
+ } else if (radio->mode == FM_TRANS) {
+ retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("get Tx config failed %d\n", retval);
+ return retval;
+ } else {
+ tuner->type = V4L2_TUNER_RADIO;
+ tuner->rangelow =
+ radio->trans_conf.band_low_limit * TUNE_PARAM;
+ tuner->rangehigh =
+ radio->trans_conf.band_high_limit * TUNE_PARAM;
+ }
- tuner->type = V4L2_TUNER_RADIO;
- tuner->rangelow = radio->recv_conf.band_low_limit * TUNE_PARAM;
- tuner->rangehigh = radio->recv_conf.band_high_limit * TUNE_PARAM;
- tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
- tuner->capability = V4L2_TUNER_CAP_LOW;
- tuner->signal = radio->fm_st_rsp.station_rsp.rssi;
- tuner->audmode = radio->fm_st_rsp.station_rsp.stereo_prg;
- tuner->afc = 0;
-
+ } else
+ return -EINVAL;
return 0;
}
@@ -2983,16 +3074,13 @@
if (retval < 0)
FMDERR(": set tuner failed with %d\n", retval);
return retval;
- } else {
- if (radio->mode == FM_TRANS) {
+ } else if (radio->mode == FM_TRANS) {
radio->trans_conf.band_low_limit =
tuner->rangelow / TUNE_PARAM;
radio->trans_conf.band_high_limit =
tuner->rangehigh / TUNE_PARAM;
- } else {
- return -EINVAL;
- }
- }
+ } else
+ return -EINVAL;
return retval;
}
@@ -3180,6 +3268,9 @@
if ((i == IRIS_BUF_RAW_RDS) || (i == IRIS_BUF_PEEK))
kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
rds_buf*3, GFP_KERNEL);
+ else if (i == IRIS_BUF_CAL_DATA)
+ kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
+ STD_BUF_SIZE*2, GFP_KERNEL);
else
kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
STD_BUF_SIZE, GFP_KERNEL);
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index 49bc46c..d09f89f 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -118,6 +118,7 @@
int pi;
/*PS repeatcount for PS Tx */
int ps_repeatcount;
+ int enable_optimized_srch_alg;
};
/**************************************************************************
@@ -1162,6 +1163,169 @@
return 0;
}
+static int optimized_search_algorithm(struct tavarua_device *radio,
+ int region)
+{
+ unsigned char adie_type_bahma;
+ int retval = 0;
+ unsigned int rdsMask = 0;
+ unsigned char value;
+
+ adie_type_bahma = is_bahama();
+
+ switch (region) {
+ case TAVARUA_REGION_US:
+ /*
+ Radio band for all the 200KHz channel-spaced regions
+ coming under EUROPE too, have been set as TAVARUA_REGION_US.
+ */
+ FMDBG("%s: The region selected from APP is"
+ " : TAVARUA_REGION_US", __func__);
+ break;
+ case TAVARUA_REGION_EU:
+ /*
+ Radio band for all the 50KHz channel-spaced regions
+ coming under EUROPE, have been set as TAVARUA_REGION_EU.
+ */
+ FMDBG("%s: The region selected from APP is : "
+ "TAVARUA_REGION_EU", __func__);
+ break;
+ case TAVARUA_REGION_JAPAN:
+ /*
+ Radio band for the 100KHz channel-spaced JAPAN region
+ has been set as TAVARUA_REGION_JAPAN.
+ */
+ FMDBG("%s: The region selected from APP is"
+ " : TAVARUA_REGION_JAPAN", __func__);
+ break;
+ case TAVARUA_REGION_JAPAN_WIDE:
+ /*
+ Radio band for the 50KHz channel-spaced JAPAN WIDE region
+ has been set as TAVARUA_REGION_JAPAN_WIDE.
+ */
+ FMDBG("%s: The region selected from APP is"
+ " : TAVARUA_REGION_JAPAN_WIDE", __func__);
+ break;
+ case TAVARUA_REGION_OTHER:
+ /*
+ Radio band for all the 100KHz channel-spaced regions
+ including those coming under EUROPE have been set as
+ TAVARUA_REGION_OTHER.
+ */
+ FMDBG("%s: The region selected from APP is"
+ " : TAVARUA_REGION_OTHER", __func__);
+ break;
+ default:
+ pr_err("%s: Should not reach here.", __func__);
+ break;
+
+ }
+
+ /* Enable or Disable the 200KHz enforcer */
+ switch (region) {
+ case TAVARUA_REGION_US:
+ case TAVARUA_REGION_JAPAN:
+ case TAVARUA_REGION_OTHER:
+ /*
+ These are the 3 bands for which we need to enable the
+ 200KHz enforcer in ADVCTL reg.
+ */
+ if (adie_type_bahma) {
+ FMDBG("Adie type : Bahama\n");
+ FMDBG("%s: Enabling the 200KHz enforcer for"
+ " Region : %d", __func__, region);
+ /*Enable the 200KHz enforcer*/
+ retval = tavarua_read_registers(radio,
+ ADVCTRL, 1);
+ if (retval >= 0) {
+ rdsMask = radio->registers[ADVCTRL];
+ SET_REG_FIELD(rdsMask, ENF_SRCH200khz,
+ SRCH200KHZ_OFFSET, SRCH_MASK);
+ retval = tavarua_write_register(radio,
+ ADVCTRL, rdsMask);
+ } else
+ return retval;
+ } /* if Marimba do nothing */
+ break;
+ case TAVARUA_REGION_EU:
+ case TAVARUA_REGION_JAPAN_WIDE:
+ /*
+ These are the 2 bands for which we need to disable the
+ 200KHz enforcer in ADVCTL reg.
+ Radio band for all the 50KHz channel-spaced regions
+ coming under EUROPE have been set as TAVARUA_REGION_EU.
+ */
+ if (adie_type_bahma) {
+ FMDBG("Adie type : Bahama\n");
+ FMDBG("%s: Disabling the 200KHz enforcer for"
+ " Region : %d", __func__, region);
+ /*
+ Disable 200KHz enforcer for all 50 KHz
+ spaced regions.
+ */
+ retval = tavarua_read_registers(radio,
+ ADVCTRL, 1);
+ if (retval >= 0) {
+ rdsMask = radio->registers[ADVCTRL];
+ SET_REG_FIELD(rdsMask, NO_SRCH200khz,
+ SRCH200KHZ_OFFSET, SRCH_MASK);
+ retval = tavarua_write_register(radio,
+ ADVCTRL, rdsMask);
+ } else
+ return retval;
+ } /* if Marimba do nothing */
+ break;
+ default:
+ FMDBG("%s: Defaulting in case of Enabling/Disabling"
+ "the 200KHz Enforcer", __func__);
+ break;
+ }
+
+ /* Set channel spacing */
+ switch (region) {
+ case TAVARUA_REGION_US:
+ if (adie_type_bahma) {
+ FMDBG("Adie type : Bahama\n");
+ /*
+ Configuring all 200KHZ spaced regions as 100KHz due to
+ change in the new Bahma FM SoC search algorithm.
+ */
+ value = FM_CH_SPACE_100KHZ;
+ } else {
+ FMDBG("Adie type : Marimba\n");
+ value = FM_CH_SPACE_200KHZ;
+ }
+ break;
+ case TAVARUA_REGION_JAPAN:
+ case TAVARUA_REGION_OTHER:
+ if (adie_type_bahma) {
+ FMDBG("Adie type : Bahama\n");
+ FMDBG("%s: Configuring the channel-spacing as 50KHz"
+ "for the Region : %d", __func__, region);
+ /*
+ Configuring all 100KHZ spaced regions as 50KHz due to
+ change in the new Bahma FM SoC search algorithm.
+ */
+ value = FM_CH_SPACE_50KHZ;
+ } else {
+ FMDBG("Adie type : Marimba\n");
+ value = FM_CH_SPACE_100KHZ;
+ }
+ break;
+ case TAVARUA_REGION_EU:
+ case TAVARUA_REGION_JAPAN_WIDE:
+ value = FM_CH_SPACE_50KHZ;
+ break;
+ default:
+ FMDBG("%s: Defualting in case of Channel-Spacing", __func__);
+ break;
+ }
+
+ SET_REG_FIELD(radio->registers[RDCTRL], value,
+ RDCTRL_CHSPACE_OFFSET, RDCTRL_CHSPACE_MASK);
+
+ return retval;
+}
/*************************************************************************
* fops/IOCTL helper functions
************************************************************************/
@@ -1255,14 +1419,11 @@
switch (region) {
case TAVARUA_REGION_US:
case TAVARUA_REGION_EU:
- case TAVARUA_REGION_JAPAN_WIDE:
SET_REG_FIELD(radio->registers[RDCTRL], 0,
RDCTRL_BAND_OFFSET, RDCTRL_BAND_MASK);
break;
+ case TAVARUA_REGION_JAPAN_WIDE:
case TAVARUA_REGION_JAPAN:
- SET_REG_FIELD(radio->registers[RDCTRL], 1,
- RDCTRL_BAND_OFFSET, RDCTRL_BAND_MASK);
- break;
default:
retval = sync_read_xfr(radio, RADIO_CONFIG, xfr_buf);
if (retval < 0) {
@@ -1286,85 +1447,6 @@
break;
}
- /* Enable/Disable the 200KHz enforcer for respectiver regions */
- switch (region) {
- case TAVARUA_REGION_US:
- if (adie_type_bahma) {
- FMDBG("Adie type : Bahama\n");
- /*Enable the 200KHz enforcer*/
- retval = tavarua_read_registers(radio,
- ADVCTRL, 1);
- if (retval >= 0) {
- rdsMask = radio->registers[ADVCTRL];
- SET_REG_FIELD(rdsMask, ENF_SRCH200khz,
- SRCH200KHZ_OFFSET, SRCH_MASK);
- msleep(TAVARUA_DELAY);
- retval = tavarua_write_register(radio,
- ADVCTRL, rdsMask);
- } else
- return retval;
- } /* if Marimba do nothing */
- break;
- case TAVARUA_REGION_EU:
- case TAVARUA_REGION_JAPAN:
- case TAVARUA_REGION_JAPAN_WIDE:
- default:
- if (adie_type_bahma) {
- FMDBG("Adie type : Bahama\n");
- /*
- Disable 200KHz enforcer for all 100/50 KHz
- spaced regions.
- */
- retval = tavarua_read_registers(radio,
- ADVCTRL, 1);
- if (retval >= 0) {
- rdsMask = radio->registers[ADVCTRL];
- SET_REG_FIELD(rdsMask, NO_SRCH200khz,
- SRCH200KHZ_OFFSET, SRCH_MASK);
- msleep(TAVARUA_DELAY);
- retval = tavarua_write_register(radio,
- ADVCTRL, rdsMask);
- } else
- return retval;
- } /* if Marimba do nothing */
- break;
- }
-
- /* Set channel spacing */
- switch (region) {
- case TAVARUA_REGION_US:
- if (adie_type_bahma) {
- FMDBG("Adie type : Bahama\n");
- /*
- Configuring all 200KHZ spaced regions as
- 100KHz due to change in the new Bahma
- FM SoC search algorithm.
- */
- value = FM_CH_SPACE_100KHZ;
- } else {
- FMDBG("Adie type : Marimba\n");
- value = FM_CH_SPACE_200KHZ;
- }
- break;
- case TAVARUA_REGION_EU:
- case TAVARUA_REGION_JAPAN:
- value = FM_CH_SPACE_100KHZ;
- break;
- case TAVARUA_REGION_JAPAN_WIDE:
- value = FM_CH_SPACE_50KHZ;
- break;
- default:
- /*
- Set the channel spacing as configured from
- the upper layers.
- */
- value = radio->region_params.spacing;
- break;
- }
-
- SET_REG_FIELD(radio->registers[RDCTRL], value,
- RDCTRL_CHSPACE_OFFSET, RDCTRL_CHSPACE_MASK);
-
/* Set De-emphasis and soft band range*/
switch (region) {
case TAVARUA_REGION_US:
@@ -1403,13 +1485,6 @@
if (retval < 0)
return retval;
- FMDBG("RDCTRL: %x\n", radio->registers[RDCTRL]);
- retval = tavarua_write_register(radio, RDCTRL,
- radio->registers[RDCTRL]);
- if (retval < 0) {
- FMDERR("Could not set region in rdctrl\n");
- return retval;
- }
/* setting soft band */
switch (region) {
@@ -1430,6 +1505,101 @@
break;
}
radio->region_params.region = region;
+
+ /* Check for the FM Algorithm used */
+ if (radio->enable_optimized_srch_alg) {
+ FMDBG("Optimized Srch Algorithm!!!");
+ optimized_search_algorithm(radio, region);
+ } else {
+ FMDBG("Native Srch Algorithm!!!");
+ /* Enable/Disable the 200KHz enforcer */
+ switch (region) {
+ case TAVARUA_REGION_US:
+ if (adie_type_bahma) {
+ FMDBG("Adie type : Bahama\n");
+ /*Enable the 200KHz enforcer*/
+ retval = tavarua_read_registers(radio,
+ ADVCTRL, 1);
+ if (retval >= 0) {
+ rdsMask = radio->registers[ADVCTRL];
+ SET_REG_FIELD(rdsMask, ENF_SRCH200khz,
+ SRCH200KHZ_OFFSET, SRCH_MASK);
+ retval = tavarua_write_register(radio,
+ ADVCTRL, rdsMask);
+ } else
+ return retval;
+ } /* if Marimba do nothing */
+ break;
+ case TAVARUA_REGION_EU:
+ case TAVARUA_REGION_JAPAN:
+ case TAVARUA_REGION_JAPAN_WIDE:
+ default:
+ if (adie_type_bahma) {
+ FMDBG("Adie type : Bahama\n");
+ /*
+ Disable 200KHz enforcer for all 100/50 KHz
+ spaced regions.
+ */
+ retval = tavarua_read_registers(radio,
+ ADVCTRL, 1);
+ if (retval >= 0) {
+ rdsMask = radio->registers[ADVCTRL];
+ SET_REG_FIELD(rdsMask, NO_SRCH200khz,
+ SRCH200KHZ_OFFSET, SRCH_MASK);
+ retval = tavarua_write_register(radio,
+ ADVCTRL, rdsMask);
+ } else
+ return retval;
+ } /* if Marimba do nothing */
+ break;
+ }
+
+ /* Set channel spacing */
+ switch (region) {
+ case TAVARUA_REGION_US:
+ if (adie_type_bahma) {
+ FMDBG("Adie type : Bahama\n");
+ /*
+ Configuring all 200KHZ spaced regions as
+ 100KHz due to change in the new Bahma
+ FM SoC search algorithm.
+ */
+ value = FM_CH_SPACE_100KHZ;
+ } else {
+ FMDBG("Adie type : Marimba\n");
+ value = FM_CH_SPACE_200KHZ;
+ }
+ break;
+ case TAVARUA_REGION_JAPAN:
+ value = FM_CH_SPACE_100KHZ;
+ break;
+ case TAVARUA_REGION_EU:
+ case TAVARUA_REGION_JAPAN_WIDE:
+ value = FM_CH_SPACE_50KHZ;
+ break;
+ default:
+ /*
+ Set the channel spacing as configured from
+ the upper layers.
+ */
+ value = radio->region_params.spacing;
+ break;
+ }
+
+ SET_REG_FIELD(radio->registers[RDCTRL], value,
+ RDCTRL_CHSPACE_OFFSET, RDCTRL_CHSPACE_MASK);
+
+ }
+
+ /* Write the config values into RDCTL register */
+ FMDBG("RDCTRL: %x\n", radio->registers[RDCTRL]);
+ retval = tavarua_write_register(radio, RDCTRL,
+ radio->registers[RDCTRL]);
+ if (retval < 0) {
+ FMDERR("Could not set region in rdctrl\n");
+ return retval;
+ }
+
return retval;
}
@@ -2745,6 +2915,7 @@
{
struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
int retval = 0;
+ int size = 0, cnt = 0;
unsigned char value;
unsigned char xfr_buf[XFR_REG_NUM];
unsigned char tx_data[XFR_REG_NUM];
@@ -2838,6 +3009,11 @@
}
}
break;
+ case V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM:
+ radio->enable_optimized_srch_alg = ctrl->value;
+ FMDBG("V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM : %d",
+ radio->enable_optimized_srch_alg);
+ break;
case V4L2_CID_PRIVATE_TAVARUA_REGION:
retval = tavarua_set_region(radio, ctrl->value);
break;
@@ -2961,6 +3137,110 @@
SET_REG_FIELD(radio->registers[IOCTRL], ctrl->value,
IOC_ANTENNA_OFFSET, IOC_ANTENNA_MASK);
break;
+ case V4L2_CID_PRIVATE_TAVARUA_ON_CHANNEL_THRESHOLD:
+ size = 0x04;
+ /* Poking the value of ON Channel Threshold value */
+ xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
+ xfr_buf[1] = ON_CHANNEL_TH_MSB;
+ xfr_buf[2] = ON_CHANNEL_TH_LSB;
+ /* Data to be poked into the register */
+ xfr_buf[3] = (ctrl->value & 0xFF000000) >> 24;
+ xfr_buf[4] = (ctrl->value & 0x00FF0000) >> 16;
+ xfr_buf[5] = (ctrl->value & 0x0000FF00) >> 8;
+ xfr_buf[6] = (ctrl->value & 0x000000FF);
+
+ for (cnt = 3; cnt < 7; cnt++) {
+ FMDBG("On-channel data to be poked is : %d",
+ (int)xfr_buf[cnt]);
+ }
+
+ retval = tavarua_write_registers(radio, XFRCTRL,
+ xfr_buf, size+3);
+ if (retval < 0) {
+ FMDBG("Failed to write\n");
+ return retval;
+ }
+ /*Wait for the XFR interrupt */
+ msleep(TAVARUA_DELAY*15);
+
+ for (cnt = 0; cnt < 5; cnt++) {
+ xfr_buf[cnt] = 0;
+ radio->registers[XFRDAT0+cnt] = 0x0;
+ }
+
+ /* Peeking Regs 0x88C2-0x88C4 */
+ size = 0x04;
+ xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
+ xfr_buf[1] = ON_CHANNEL_TH_MSB;
+ xfr_buf[2] = ON_CHANNEL_TH_LSB;
+ retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
+ if (retval < 0) {
+ pr_err("%s: Failed to write\n", __func__);
+ return retval;
+ }
+ /*Wait for the XFR interrupt */
+ msleep(TAVARUA_DELAY*10);
+ retval = tavarua_read_registers(radio, XFRDAT0, 4);
+ if (retval < 0) {
+ pr_err("%s: On Ch. DET: Read failure\n", __func__);
+ return retval;
+ }
+ for (cnt = 0; cnt < 4; cnt++)
+ FMDBG("On-Channel data set is : 0x%x\t",
+ (int)radio->registers[XFRDAT0+cnt]);
+ break;
+ case V4L2_CID_PRIVATE_TAVARUA_OFF_CHANNEL_THRESHOLD:
+ size = 0x04;
+ /* Poking the value of OFF Channel Threshold value */
+ xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
+ xfr_buf[1] = OFF_CHANNEL_TH_MSB;
+ xfr_buf[2] = OFF_CHANNEL_TH_LSB;
+ /* Data to be poked into the register */
+ xfr_buf[3] = (ctrl->value & 0xFF000000) >> 24;
+ xfr_buf[4] = (ctrl->value & 0x00FF0000) >> 16;
+ xfr_buf[5] = (ctrl->value & 0x0000FF00) >> 8;
+ xfr_buf[6] = (ctrl->value & 0x000000FF);
+
+ for (cnt = 3; cnt < 7; cnt++) {
+ FMDBG("Off-channel data to be poked is : %d",
+ (int)xfr_buf[cnt]);
+ }
+
+ retval = tavarua_write_registers(radio, XFRCTRL,
+ xfr_buf, size+3);
+ if (retval < 0) {
+ pr_err("%s: Failed to write\n", __func__);
+ return retval;
+ }
+ /*Wait for the XFR interrupt */
+ msleep(TAVARUA_DELAY*10);
+
+ for (cnt = 0; cnt < 5; cnt++) {
+ xfr_buf[cnt] = 0;
+ radio->registers[XFRDAT0+cnt] = 0x0;
+ }
+
+ /* Peeking Regs 0x88C2-0x88C4 */
+ size = 0x04;
+ xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
+ xfr_buf[1] = OFF_CHANNEL_TH_MSB;
+ xfr_buf[2] = OFF_CHANNEL_TH_LSB;
+ retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
+ if (retval < 0) {
+ pr_err("%s: Failed to write\n", __func__);
+ return retval;
+ }
+ /*Wait for the XFR interrupt */
+ msleep(TAVARUA_DELAY*10);
+ retval = tavarua_read_registers(radio, XFRDAT0, 4);
+ if (retval < 0) {
+ pr_err("%s: Off Ch. DET: Read failure\n", __func__);
+ return retval;
+ }
+ for (cnt = 0; cnt < 4; cnt++)
+ FMDBG("Off-channel data set is : 0x%x\t",
+ (int)radio->registers[XFRDAT0+cnt]);
+ break;
/* TX Controls */
case V4L2_CID_RDS_TX_PTY: {
@@ -3553,7 +3833,7 @@
printk(KERN_INFO DRIVER_NAME "%s: radio suspend\n\n", __func__);
if (radio) {
users = atomic_read(&radio->users);
- if (users) {
+ if (!users) {
retval = tavarua_disable_interrupts(radio);
if (retval < 0) {
printk(KERN_INFO DRIVER_NAME
@@ -3585,7 +3865,7 @@
if (radio) {
users = atomic_read(&radio->users);
- if (users) {
+ if (!users) {
retval = tavarua_setup_interrupts(radio,
(radio->registers[RDCTRL] & 0x03));
if (retval < 0) {
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index ce595f9..9fd019e 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -624,7 +624,6 @@
static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
{
DEFINE_IR_RAW_EVENT(rawir);
- unsigned int count;
u32 carrier;
u8 sample;
int i;
@@ -637,65 +636,38 @@
if (nvt->carrier_detect_enabled)
carrier = nvt_rx_carrier_detect(nvt);
- count = nvt->pkts;
- nvt_dbg_verbose("Processing buffer of len %d", count);
+ nvt_dbg_verbose("Processing buffer of len %d", nvt->pkts);
init_ir_raw_event(&rawir);
- for (i = 0; i < count; i++) {
- nvt->pkts--;
+ for (i = 0; i < nvt->pkts; i++) {
sample = nvt->buf[i];
rawir.pulse = ((sample & BUF_PULSE_BIT) != 0);
rawir.duration = US_TO_NS((sample & BUF_LEN_MASK)
* SAMPLE_PERIOD);
- if ((sample & BUF_LEN_MASK) == BUF_LEN_MASK) {
- if (nvt->rawir.pulse == rawir.pulse)
- nvt->rawir.duration += rawir.duration;
- else {
- nvt->rawir.duration = rawir.duration;
- nvt->rawir.pulse = rawir.pulse;
- }
- continue;
- }
+ nvt_dbg("Storing %s with duration %d",
+ rawir.pulse ? "pulse" : "space", rawir.duration);
- rawir.duration += nvt->rawir.duration;
-
- init_ir_raw_event(&nvt->rawir);
- nvt->rawir.duration = 0;
- nvt->rawir.pulse = rawir.pulse;
-
- if (sample == BUF_PULSE_BIT)
- rawir.pulse = false;
-
- if (rawir.duration) {
- nvt_dbg("Storing %s with duration %d",
- rawir.pulse ? "pulse" : "space",
- rawir.duration);
-
- ir_raw_event_store_with_filter(nvt->rdev, &rawir);
- }
+ ir_raw_event_store_with_filter(nvt->rdev, &rawir);
/*
* BUF_PULSE_BIT indicates end of IR data, BUF_REPEAT_BYTE
* indicates end of IR signal, but new data incoming. In both
* cases, it means we're ready to call ir_raw_event_handle
*/
- if ((sample == BUF_PULSE_BIT) && nvt->pkts) {
+ if ((sample == BUF_PULSE_BIT) && (i + 1 < nvt->pkts)) {
nvt_dbg("Calling ir_raw_event_handle (signal end)\n");
ir_raw_event_handle(nvt->rdev);
}
}
+ nvt->pkts = 0;
+
nvt_dbg("Calling ir_raw_event_handle (buffer empty)\n");
ir_raw_event_handle(nvt->rdev);
- if (nvt->pkts) {
- nvt_dbg("Odd, pkts should be 0 now... (its %u)", nvt->pkts);
- nvt->pkts = 0;
- }
-
nvt_dbg_verbose("%s done", __func__);
}
@@ -1054,7 +1026,6 @@
spin_lock_init(&nvt->nvt_lock);
spin_lock_init(&nvt->tx.lock);
- init_ir_raw_event(&nvt->rawir);
ret = -EBUSY;
/* now claim resources */
diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h
index 1241fc8..0d5e087 100644
--- a/drivers/media/rc/nuvoton-cir.h
+++ b/drivers/media/rc/nuvoton-cir.h
@@ -67,7 +67,6 @@
struct nvt_dev {
struct pnp_dev *pdev;
struct rc_dev *rdev;
- struct ir_raw_event rawir;
spinlock_t nvt_lock;
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index 9361f5a9..0d822bb 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -168,12 +168,6 @@
depends on MSM_CAMERA && ARCH_MSM8960
default y
-config QS_MT9P017
- bool "Sensor qs_mt9p017 (Aptina 3D 5M)"
- depends on MSM_CAMERA
- ---help---
- Aptina 3D 5M with Autofocus
-
config VB6801
bool "Sensor vb6801"
depends on MSM_CAMERA && !ARCH_MSM8X60 && !MSM_CAMERA_V4L2
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index a6b7f48..6f39576 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -35,7 +35,6 @@
obj-$(CONFIG_IMX074) += imx074.o imx074_reg.o
endif
obj-$(CONFIG_QS_S5K4E1) += qs_s5k4e1.o qs_s5k4e1_reg.o
-obj-$(CONFIG_QS_MT9P017) += qs_mt9p017.o qs_mt9p017_reg.o
obj-$(CONFIG_VB6801) += vb6801.o
obj-$(CONFIG_IMX072) += imx072.o imx072_reg.o
obj-$(CONFIG_WEBCAM_OV9726) += ov9726.o ov9726_reg.o
diff --git a/drivers/media/video/msm/actuators/imx074_act.c b/drivers/media/video/msm/actuators/imx074_act.c
index f267f80..e01d2c7 100644
--- a/drivers/media/video/msm/actuators/imx074_act.c
+++ b/drivers/media/video/msm/actuators/imx074_act.c
@@ -12,7 +12,6 @@
*/
#include "msm_actuator.h"
-#include "msm_logging.h"
#include "msm_camera_i2c.h"
#define IMX074_TOTAL_STEPS_NEAR_TO_FAR 41
diff --git a/drivers/media/video/msm/actuators/msm_actuator.c b/drivers/media/video/msm/actuators/msm_actuator.c
index 7f570e6..f0023d7 100644
--- a/drivers/media/video/msm/actuators/msm_actuator.c
+++ b/drivers/media/video/msm/actuators/msm_actuator.c
@@ -11,10 +11,6 @@
*/
#include "msm_actuator.h"
-#include "msm_logging.h"
-
-LDECVAR(a_profstarttime);
-LDECVAR(a_profendtime);
int32_t msm_actuator_write_focus(
struct msm_actuator_ctrl_t *a_ctrl,
diff --git a/drivers/media/video/msm/actuators/msm_actuator.h b/drivers/media/video/msm/actuators/msm_actuator.h
index d612dad..6fad8dd 100644
--- a/drivers/media/video/msm/actuators/msm_actuator.h
+++ b/drivers/media/video/msm/actuators/msm_actuator.h
@@ -18,6 +18,24 @@
#include <media/msm_camera.h>
#include "msm_camera_i2c.h"
+#ifdef LERROR
+#undef LERROR
+#endif
+
+#ifdef LINFO
+#undef LINFO
+#endif
+
+#define LERROR(fmt, args...) pr_err(fmt, ##args)
+
+#define CONFIG_MSM_CAMERA_ACT_DBG 0
+
+#if CONFIG_MSM_CAMERA_ACT_DBG
+#define LINFO(fmt, args...) printk(fmt, ##args)
+#else
+#define LINFO(fmt, args...) CDBG(fmt, ##args)
+#endif
+
struct msm_actuator_ctrl_t;
struct region_params_t {
diff --git a/drivers/media/video/msm/csi/msm_csid.c b/drivers/media/video/msm/csi/msm_csid.c
index fb809c9..7a0ee4d 100644
--- a/drivers/media/video/msm/csi/msm_csid.c
+++ b/drivers/media/video/msm/csi/msm_csid.c
@@ -97,6 +97,7 @@
val |= 0x1 << 10;
val |= 0x1 << 11;
val |= 0x1 << 12;
+ val |= 0x1 << 13;
val |= 0x1 << 28;
msm_io_w(val, csidbase + CSID_CORE_CTRL_ADDR);
diff --git a/drivers/media/video/msm/csi/msm_csiphy.c b/drivers/media/video/msm/csi/msm_csiphy.c
index b62ec84..109b3dd 100644
--- a/drivers/media/video/msm/csi/msm_csiphy.c
+++ b/drivers/media/video/msm/csi/msm_csiphy.c
@@ -79,7 +79,7 @@
msm_io_w(0x1, csiphybase + MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR);
for (i = 0; i < csiphy_params->lane_cnt; i++) {
- msm_io_w(0x10, csiphybase + MIPI_CSIPHY_LNn_CFG1_ADDR + 0x40*i);
+ msm_io_w(0x00, csiphybase + MIPI_CSIPHY_LNn_CFG1_ADDR + 0x40*i);
msm_io_w(0x5F, csiphybase + MIPI_CSIPHY_LNn_CFG2_ADDR + 0x40*i);
msm_io_w(csiphy_params->settle_cnt,
csiphybase + MIPI_CSIPHY_LNn_CFG3_ADDR + 0x40*i);
diff --git a/drivers/media/video/msm/flash.c b/drivers/media/video/msm/flash.c
index f1a24cc..6985f3c 100644
--- a/drivers/media/video/msm/flash.c
+++ b/drivers/media/video/msm/flash.c
@@ -293,6 +293,7 @@
if (sc628a_client) {
gpio_set_value_cansleep(external->led_en, 1);
gpio_set_value_cansleep(external->led_flash_en, 1);
+ usleep_range(2000, 3000);
}
rc = sc628a_i2c_write_b_flash(0x02, 0x06);
break;
@@ -301,6 +302,7 @@
if (sc628a_client) {
gpio_set_value_cansleep(external->led_en, 1);
gpio_set_value_cansleep(external->led_flash_en, 1);
+ usleep_range(2000, 3000);
}
rc = sc628a_i2c_write_b_flash(0x02, 0x49);
break;
diff --git a/drivers/media/video/msm/io/msm_camera_i2c.c b/drivers/media/video/msm/io/msm_camera_i2c.c
index 019d6e1..23db5f6b 100644
--- a/drivers/media/video/msm/io/msm_camera_i2c.c
+++ b/drivers/media/video/msm/io/msm_camera_i2c.c
@@ -138,34 +138,155 @@
return rc;
}
+int32_t msm_camera_i2c_set_mask(struct msm_camera_i2c_client *client,
+ uint16_t addr, uint16_t mask,
+ enum msm_camera_i2c_data_type data_type, uint16_t set_mask)
+{
+ int32_t rc;
+ uint16_t reg_data;
+
+ rc = msm_camera_i2c_read(client, addr, ®_data, data_type);
+ if (rc < 0) {
+ S_I2C_DBG("%s read fail\n", __func__);
+ return rc;
+ }
+ S_I2C_DBG("%s addr: 0x%x data: 0x%x setmask: 0x%x\n",
+ __func__, addr, reg_data, mask);
+
+ if (set_mask)
+ reg_data |= mask;
+ else
+ reg_data &= ~mask;
+ S_I2C_DBG("%s write: 0x%x\n", __func__, reg_data);
+
+ rc = msm_camera_i2c_write(client, addr, reg_data, data_type);
+ if (rc < 0)
+ S_I2C_DBG("%s write fail\n", __func__);
+
+ return rc;
+}
+
+int32_t msm_camera_i2c_compare(struct msm_camera_i2c_client *client,
+ uint16_t addr, uint16_t data,
+ enum msm_camera_i2c_data_type data_type)
+{
+ int32_t rc = -EIO;
+ uint16_t reg_data = 0;
+ int data_len = 0;
+ switch (data_type) {
+ case MSM_CAMERA_I2C_BYTE_DATA:
+ case MSM_CAMERA_I2C_WORD_DATA:
+ data_len = data_type;
+ break;
+ case MSM_CAMERA_I2C_SET_BYTE_MASK:
+ case MSM_CAMERA_I2C_UNSET_BYTE_MASK:
+ data_len = MSM_CAMERA_I2C_BYTE_DATA;
+ break;
+ case MSM_CAMERA_I2C_SET_WORD_MASK:
+ case MSM_CAMERA_I2C_UNSET_WORD_MASK:
+ data_len = MSM_CAMERA_I2C_WORD_DATA;
+ break;
+ default:
+ pr_err("%s: Unsupport data type: %d\n", __func__, data_type);
+ break;
+ }
+
+ rc = msm_camera_i2c_read(client,
+ addr, ®_data, data_len);
+ if (rc < 0)
+ return rc;
+
+ rc = 0;
+ switch (data_type) {
+ case MSM_CAMERA_I2C_BYTE_DATA:
+ case MSM_CAMERA_I2C_WORD_DATA:
+ if (data == reg_data)
+ return rc;
+ break;
+ case MSM_CAMERA_I2C_SET_BYTE_MASK:
+ case MSM_CAMERA_I2C_SET_WORD_MASK:
+ if ((reg_data & data) == data)
+ return rc;
+ break;
+ case MSM_CAMERA_I2C_UNSET_BYTE_MASK:
+ case MSM_CAMERA_I2C_UNSET_WORD_MASK:
+ if (!(reg_data & data))
+ return rc;
+ break;
+ default:
+ pr_err("%s: Unsupport data type: %d\n", __func__, data_type);
+ break;
+ }
+
+ S_I2C_DBG("%s: Register and data does not match\n", __func__);
+ rc = 1;
+ return rc;
+}
+
+int32_t msm_camera_i2c_poll(struct msm_camera_i2c_client *client,
+ uint16_t addr, uint16_t data,
+ enum msm_camera_i2c_data_type data_type)
+{
+ int32_t rc = -EIO;
+ int i;
+ S_I2C_DBG("%s: addr: 0x%x data: 0x%x dt: %d\n",
+ __func__, addr, data, data_type);
+
+ for (i = 0; i < 20; i++) {
+ rc = msm_camera_i2c_compare(client,
+ addr, data, data_type);
+ if (rc == 0 || rc < 0)
+ break;
+ usleep_range(10000, 11000);
+ }
+ return rc;
+}
+
int32_t msm_camera_i2c_write_tbl(struct msm_camera_i2c_client *client,
- struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint8_t size,
+ struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size,
enum msm_camera_i2c_data_type data_type)
{
int i;
int32_t rc = -EFAULT;
for (i = 0; i < size; i++) {
- rc = msm_camera_i2c_write(
- client,
- reg_conf_tbl->reg_addr,
- reg_conf_tbl->reg_data, data_type);
- if (rc < 0)
- break;
- reg_conf_tbl++;
- }
- return rc;
-}
+ enum msm_camera_i2c_data_type dt;
+ if (reg_conf_tbl->dt == 0)
+ dt = data_type;
+ else
+ dt = reg_conf_tbl->dt;
-int32_t msm_camera_i2c_write_dt_tbl(struct msm_camera_i2c_client *client,
- struct msm_camera_i2c_reg_dt_conf *reg_conf_tbl, uint16_t size)
-{
- int i;
- int32_t rc = -EFAULT;
- for (i = 0; i < size; i++) {
- rc = msm_camera_i2c_write(
- client,
- reg_conf_tbl->reg_addr,
- reg_conf_tbl->reg_data, reg_conf_tbl->dt);
+ switch (dt) {
+ case MSM_CAMERA_I2C_BYTE_DATA:
+ case MSM_CAMERA_I2C_WORD_DATA:
+ rc = msm_camera_i2c_write(
+ client,
+ reg_conf_tbl->reg_addr,
+ reg_conf_tbl->reg_data, dt);
+ break;
+ case MSM_CAMERA_I2C_SET_BYTE_MASK:
+ rc = msm_camera_i2c_set_mask(client,
+ reg_conf_tbl->reg_addr, reg_conf_tbl->reg_data,
+ MSM_CAMERA_I2C_BYTE_DATA, 1);
+ break;
+ case MSM_CAMERA_I2C_UNSET_BYTE_MASK:
+ rc = msm_camera_i2c_set_mask(client,
+ reg_conf_tbl->reg_addr, reg_conf_tbl->reg_data,
+ MSM_CAMERA_I2C_BYTE_DATA, 0);
+ break;
+ case MSM_CAMERA_I2C_SET_WORD_MASK:
+ rc = msm_camera_i2c_set_mask(client,
+ reg_conf_tbl->reg_addr, reg_conf_tbl->reg_data,
+ MSM_CAMERA_I2C_WORD_DATA, 1);
+ break;
+ case MSM_CAMERA_I2C_UNSET_WORD_MASK:
+ rc = msm_camera_i2c_set_mask(client,
+ reg_conf_tbl->reg_addr, reg_conf_tbl->reg_data,
+ MSM_CAMERA_I2C_WORD_DATA, 0);
+ break;
+ default:
+ pr_err("%s: Unsupport data type: %d\n", __func__, dt);
+ break;
+ }
if (rc < 0)
break;
reg_conf_tbl++;
@@ -202,7 +323,7 @@
else
*data = buf[0] << 8 | buf[1];
- S_I2C_DBG("%s addr = 0x%x data: 0x%x", __func__, addr, *data);
+ S_I2C_DBG("%s addr = 0x%x data: 0x%x\n", __func__, addr, *data);
return rc;
}
@@ -243,15 +364,16 @@
struct msm_camera_i2c_conf_array *array, uint16_t index)
{
int32_t rc;
- if (array[index].data_type != MSM_CAMERA_I2C_HYBRID_DATA) {
- rc = msm_camera_i2c_write_tbl(client,
- (struct msm_camera_i2c_reg_conf *) array[index].conf,
- array[index].size, array[index].data_type);
- } else {
- rc = msm_camera_i2c_write_dt_tbl(client,
- (struct msm_camera_i2c_reg_dt_conf *) array[index].conf,
- array[index].size);
- }
+ if (array[index].pre_process != NULL)
+ array[index].pre_process();
+
+ rc = msm_camera_i2c_write_tbl(client,
+ (struct msm_camera_i2c_reg_conf *) array[index].conf,
+ array[index].size, array[index].data_type);
+
+ if (array[index].post_process != NULL)
+ array[index].post_process();
+
if (array[index].delay > 20)
msleep(array[index].delay);
else
diff --git a/drivers/media/video/msm/io/msm_camera_i2c.h b/drivers/media/video/msm/io/msm_camera_i2c.h
index 201cd03..05b3960 100644
--- a/drivers/media/video/msm/io/msm_camera_i2c.h
+++ b/drivers/media/video/msm/io/msm_camera_i2c.h
@@ -35,28 +35,28 @@
enum msm_camera_i2c_reg_addr_type addr_type;
};
-struct msm_camera_i2c_reg_conf {
- uint16_t reg_addr;
- uint16_t reg_data;
-};
-
enum msm_camera_i2c_data_type {
MSM_CAMERA_I2C_BYTE_DATA = 1,
MSM_CAMERA_I2C_WORD_DATA,
- MSM_CAMERA_I2C_HYBRID_DATA,
+ MSM_CAMERA_I2C_SET_BYTE_MASK,
+ MSM_CAMERA_I2C_UNSET_BYTE_MASK,
+ MSM_CAMERA_I2C_SET_WORD_MASK,
+ MSM_CAMERA_I2C_UNSET_WORD_MASK,
};
-struct msm_camera_i2c_reg_dt_conf {
+struct msm_camera_i2c_reg_conf {
uint16_t reg_addr;
uint16_t reg_data;
enum msm_camera_i2c_data_type dt;
};
struct msm_camera_i2c_conf_array {
- void *conf;
+ struct msm_camera_i2c_reg_conf *conf;
uint16_t size;
uint16_t delay;
enum msm_camera_i2c_data_type data_type;
+ int (*pre_process) (void);
+ int (*post_process) (void);
};
int32_t msm_camera_i2c_rxdata(struct msm_camera_i2c_client *client,
@@ -79,12 +79,21 @@
int32_t msm_camera_i2c_write_seq(struct msm_camera_i2c_client *client,
uint16_t addr, uint8_t *data, uint16_t num_byte);
-int32_t msm_camera_i2c_write_tbl(struct msm_camera_i2c_client *client,
- struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint8_t size,
+int32_t msm_camera_i2c_set_mask(struct msm_camera_i2c_client *client,
+ uint16_t addr, uint16_t mask,
+ enum msm_camera_i2c_data_type data_type, uint16_t flag);
+
+int32_t msm_camera_i2c_compare(struct msm_camera_i2c_client *client,
+ uint16_t addr, uint16_t data,
enum msm_camera_i2c_data_type data_type);
-int32_t msm_camera_i2c_write_dt_tbl(struct msm_camera_i2c_client *client,
- struct msm_camera_i2c_reg_dt_conf *reg_conf_tbl, uint16_t size);
+int32_t msm_camera_i2c_poll(struct msm_camera_i2c_client *client,
+ uint16_t addr, uint16_t data,
+ enum msm_camera_i2c_data_type data_type);
+
+int32_t msm_camera_i2c_write_tbl(struct msm_camera_i2c_client *client,
+ struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size,
+ enum msm_camera_i2c_data_type data_type);
int32_t msm_sensor_write_conf_array(struct msm_camera_i2c_client *client,
struct msm_camera_i2c_conf_array *array, uint16_t index);
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index f7a1fa8..251f12d 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -1497,12 +1497,7 @@
}
}
pcam_inst->vbqueue_initialized = 0;
- /* Initialize the video queue */
- rc = pcam->mctl.mctl_buf_init(pcam_inst);
- if (rc < 0) {
- mutex_unlock(&pcam->vid_lock);
- return rc;
- }
+ rc = 0;
f->private_data = &pcam_inst->eventHandle;
@@ -1630,7 +1625,6 @@
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
ion_client_destroy(pcam->mctl.client);
#endif
- dma_release_declared_memory(&pcam->pdev->dev);
}
mutex_unlock(&pcam->vid_lock);
return rc;
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index f11e43f..3e3b9c8 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -485,6 +485,10 @@
int msm_mctl_pp_done(
struct msm_cam_media_controller *p_mctl,
void __user *arg);
+int msm_mctl_pp_divert_done(
+ struct msm_cam_media_controller *p_mctl,
+ void __user *arg);
+
#endif /* __KERNEL__ */
#endif /* _MSM_H */
diff --git a/drivers/media/video/msm/msm_camera.c b/drivers/media/video/msm/msm_camera.c
index 7f43136..e401a7a 100644
--- a/drivers/media/video/msm/msm_camera.c
+++ b/drivers/media/video/msm/msm_camera.c
@@ -3815,6 +3815,14 @@
return rc;
}
+static int msm_open_frame(struct inode *inode, struct file *filep)
+{
+ struct msm_cam_device *pmsm =
+ container_of(inode->i_cdev, struct msm_cam_device, cdev);
+ msm_queue_drain(&pmsm->sync->frame_q, list_frame);
+ return msm_open_common(inode, filep, 1, 0);
+}
+
static int msm_open(struct inode *inode, struct file *filep)
{
return msm_open_common(inode, filep, 1, 0);
@@ -3863,7 +3871,7 @@
static const struct file_operations msm_fops_frame = {
.owner = THIS_MODULE,
- .open = msm_open,
+ .open = msm_open_frame,
.unlocked_ioctl = msm_ioctl_frame,
.release = msm_release_frame,
.poll = msm_poll_frame,
diff --git a/drivers/media/video/msm/msm_io_7x27a.c b/drivers/media/video/msm/msm_io_7x27a.c
index b1f9532..7a83721 100644
--- a/drivers/media/video/msm/msm_io_7x27a.c
+++ b/drivers/media/video/msm/msm_io_7x27a.c
@@ -288,11 +288,6 @@
clk_set_rate(clk, rate);
}
-void msm_camio_clk_set_min_rate(struct clk *clk, int rate)
-{
- clk_set_min_rate(clk, rate);
-}
-
static irqreturn_t msm_io_csi_irq(int irq_num, void *data)
{
uint32_t irq;
diff --git a/drivers/media/video/msm/msm_io_8960.c b/drivers/media/video/msm/msm_io_8960.c
index 1293c7b..ec18a93 100644
--- a/drivers/media/video/msm/msm_io_8960.c
+++ b/drivers/media/video/msm/msm_io_8960.c
@@ -346,7 +346,7 @@
case CAMIO_JPEG_CLK:
camio_jpeg_clk =
clk = clk_get(NULL, "ijpeg_clk");
- clk_set_min_rate(clk, 144000000);
+ clk_set_rate(clk, 153600000);
break;
case CAMIO_JPEG_PCLK:
@@ -414,11 +414,6 @@
clk_set_rate(clk, rate);
}
-void msm_camio_clk_set_min_rate(struct clk *clk, int rate)
-{
- clk_set_min_rate(clk, rate);
-}
-
int msm_camio_jpeg_clk_disable(void)
{
int rc = 0;
diff --git a/drivers/media/video/msm/msm_io_8x60.c b/drivers/media/video/msm/msm_io_8x60.c
index 2262aa4..9620d8b 100644
--- a/drivers/media/video/msm/msm_io_8x60.c
+++ b/drivers/media/video/msm/msm_io_8x60.c
@@ -344,7 +344,8 @@
case CAMIO_VPE_CLK:
camio_vpe_clk =
clk = clk_get(NULL, "vpe_clk");
- msm_camio_clk_set_min_rate(camio_vpe_clk, vpe_clk_rate);
+ vpe_clk_rate = clk_round_rate(camio_vpe_clk, vpe_clk_rate);
+ clk_set_rate(camio_vpe_clk, vpe_clk_rate);
break;
case CAMIO_VPE_PCLK:
@@ -457,11 +458,6 @@
clk_set_rate(clk, rate);
}
-void msm_camio_clk_set_min_rate(struct clk *clk, int rate)
-{
- clk_set_min_rate(clk, rate);
-}
-
static irqreturn_t msm_io_csi_irq(int irq_num, void *data)
{
uint32_t irq;
diff --git a/drivers/media/video/msm/msm_io_vfe31.c b/drivers/media/video/msm/msm_io_vfe31.c
index 1cd731c..91dbc8f 100644
--- a/drivers/media/video/msm/msm_io_vfe31.c
+++ b/drivers/media/video/msm/msm_io_vfe31.c
@@ -111,17 +111,24 @@
static struct clk *camio_jpeg_clk;
static struct clk *camio_jpeg_pclk;
static struct clk *camio_vpe_clk;
-static struct vreg *vreg_gp2;
-static struct vreg *vreg_lvsw1;
-static struct vreg *vreg_gp6;
-static struct vreg *vreg_gp16;
-static struct regulator *fs_vfe;
static struct regulator *fs_vpe;
static struct msm_camera_io_ext camio_ext;
static struct msm_camera_io_clk camio_clk;
static struct resource *camifpadio, *csiio;
void __iomem *camifpadbase, *csibase;
static uint32_t vpe_clk_rate;
+static uint32_t jpeg_clk_rate;
+
+static struct regulator_bulk_data regs[] = {
+ { .supply = "gp2", .min_uV = 2600000, .max_uV = 2600000 },
+ { .supply = "lvsw1" },
+ { .supply = "fs_vfe" },
+ /* sn12m0pz regulators */
+ { .supply = "gp6", .min_uV = 3050000, .max_uV = 3100000 },
+ { .supply = "gp16", .min_uV = 1200000, .max_uV = 1200000 },
+};
+
+static int reg_count;
void msm_io_w(u32 data, void __iomem *addr)
{
@@ -201,135 +208,54 @@
static void msm_camera_vreg_enable(struct platform_device *pdev)
{
- vreg_gp2 = vreg_get(NULL, "gp2");
- if (IS_ERR(vreg_gp2)) {
- pr_err("%s: VREG GP2 get failed %ld\n", __func__,
- PTR_ERR(vreg_gp2));
- vreg_gp2 = NULL;
+ int count, rc;
+
+ struct device *dev = &pdev->dev;
+
+ /* Use gp6 and gp16 if and only if dev name matches. */
+ if (!strncmp(pdev->name, "msm_camera_sn12m0pz", 20))
+ count = ARRAY_SIZE(regs);
+ else
+ count = ARRAY_SIZE(regs) - 2;
+
+ rc = regulator_bulk_get(dev, count, regs);
+
+ if (rc) {
+ dev_err(dev, "%s: could not get regulators: %d\n",
+ __func__, rc);
return;
}
- if (vreg_set_level(vreg_gp2, 2600)) {
- pr_err("%s: VREG GP2 set failed\n", __func__);
- goto gp2_put;
+ rc = regulator_bulk_set_voltage(count, regs);
+
+ if (rc) {
+ dev_err(dev, "%s: could not set voltages: %d\n",
+ __func__, rc);
+ goto reg_free;
}
- if (vreg_enable(vreg_gp2)) {
- pr_err("%s: VREG GP2 enable failed\n", __func__);
- goto gp2_put;
+ rc = regulator_bulk_enable(count, regs);
+
+ if (rc) {
+ dev_err(dev, "%s: could not enable regulators: %d\n",
+ __func__, rc);
+ goto reg_free;
}
- vreg_lvsw1 = vreg_get(NULL, "lvsw1");
- if (IS_ERR(vreg_lvsw1)) {
- pr_err("%s: VREG LVSW1 get failed %ld\n", __func__,
- PTR_ERR(vreg_lvsw1));
- vreg_lvsw1 = NULL;
- goto gp2_disable;
- }
- if (vreg_set_level(vreg_lvsw1, 1800)) {
- pr_err("%s: VREG LVSW1 set failed\n", __func__);
- goto lvsw1_put;
- }
- if (vreg_enable(vreg_lvsw1)) {
- pr_err("%s: VREG LVSW1 enable failed\n", __func__);
- goto lvsw1_put;
- }
-
- if (!strcmp(pdev->name, "msm_camera_sn12m0pz")) {
- vreg_gp6 = vreg_get(NULL, "gp6");
- if (IS_ERR(vreg_gp6)) {
- pr_err("%s: VREG GP6 get failed %ld\n", __func__,
- PTR_ERR(vreg_gp6));
- vreg_gp6 = NULL;
- goto lvsw1_disable;
- }
-
- if (vreg_set_level(vreg_gp6, 3050)) {
- pr_err("%s: VREG GP6 set failed\n", __func__);
- goto gp6_put;
- }
-
- if (vreg_enable(vreg_gp6)) {
- pr_err("%s: VREG GP6 enable failed\n", __func__);
- goto gp6_put;
- }
- vreg_gp16 = vreg_get(NULL, "gp16");
- if (IS_ERR(vreg_gp16)) {
- pr_err("%s: VREG GP16 get failed %ld\n", __func__,
- PTR_ERR(vreg_gp16));
- vreg_gp16 = NULL;
- goto gp6_disable;
- }
-
- if (vreg_set_level(vreg_gp16, 1200)) {
- pr_err("%s: VREG GP16 set failed\n", __func__);
- goto gp16_put;
- }
-
- if (vreg_enable(vreg_gp16)) {
- pr_err("%s: VREG GP16 enable failed\n", __func__);
- goto gp16_put;
- }
- }
-
- fs_vfe = regulator_get(NULL, "fs_vfe");
- if (IS_ERR(fs_vfe)) {
- pr_err("%s: Regulator FS_VFE get failed %ld\n", __func__,
- PTR_ERR(fs_vfe));
- fs_vfe = NULL;
- } else if (regulator_enable(fs_vfe)) {
- pr_err("%s: Regulator FS_VFE enable failed\n", __func__);
- regulator_put(fs_vfe);
- }
-
+ reg_count = count;
return;
-gp16_put:
- vreg_put(vreg_gp16);
- vreg_gp16 = NULL;
-gp6_disable:
- vreg_disable(vreg_gp6);
-gp6_put:
- vreg_put(vreg_gp6);
- vreg_gp6 = NULL;
-lvsw1_disable:
- vreg_disable(vreg_lvsw1);
-lvsw1_put:
- vreg_put(vreg_lvsw1);
- vreg_lvsw1 = NULL;
-gp2_disable:
- vreg_disable(vreg_gp2);
-gp2_put:
- vreg_put(vreg_gp2);
- vreg_gp2 = NULL;
+reg_free:
+ regulator_bulk_free(count, regs);
+ return;
}
+
static void msm_camera_vreg_disable(void)
{
- if (vreg_gp2) {
- vreg_disable(vreg_gp2);
- vreg_put(vreg_gp2);
- vreg_gp2 = NULL;
- }
- if (vreg_lvsw1) {
- vreg_disable(vreg_lvsw1);
- vreg_put(vreg_lvsw1);
- vreg_lvsw1 = NULL;
- }
- if (vreg_gp6) {
- vreg_disable(vreg_gp6);
- vreg_put(vreg_gp6);
- vreg_gp6 = NULL;
- }
- if (vreg_gp16) {
- vreg_disable(vreg_gp16);
- vreg_put(vreg_gp16);
- vreg_gp16 = NULL;
- }
- if (fs_vfe) {
- regulator_disable(fs_vfe);
- regulator_put(fs_vfe);
- }
+ regulator_bulk_disable(reg_count, regs);
+ regulator_bulk_free(reg_count, regs);
+ reg_count = 0;
}
int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
@@ -392,7 +318,8 @@
case CAMIO_JPEG_CLK:
camio_jpeg_clk =
clk = clk_get(NULL, "jpeg_clk");
- clk_set_min_rate(clk, 144000000);
+ jpeg_clk_rate = clk_round_rate(clk, 144000000);
+ clk_set_rate(clk, jpeg_clk_rate);
break;
case CAMIO_JPEG_PCLK:
camio_jpeg_pclk =
@@ -401,7 +328,8 @@
case CAMIO_VPE_CLK:
camio_vpe_clk =
clk = clk_get(NULL, "vpe_clk");
- msm_camio_clk_set_min_rate(clk, vpe_clk_rate);
+ vpe_clk_rate = clk_round_rate(clk, vpe_clk_rate);
+ clk_set_rate(clk, vpe_clk_rate);
break;
default:
break;
@@ -495,11 +423,6 @@
clk_set_rate(clk, rate);
}
-void msm_camio_clk_set_min_rate(struct clk *clk, int rate)
-{
- clk_set_min_rate(clk, rate);
-}
-
static irqreturn_t msm_io_csi_irq(int irq_num, void *data)
{
uint32_t irq;
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index e4d4f27..0a1516b 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -268,6 +268,10 @@
struct msm_sync *sync =
(struct msm_sync *)v4l2_get_subdev_hostdata(sd);
struct msm_vpe_resp *vdata = (struct msm_vpe_resp *)arg;
+ if (sync == NULL) {
+ pr_err("%s: VPE subdev hostdata not set\n", __func__);
+ return -EINVAL;
+ }
msm_mctl_pp_notify(&sync->pcam_sync->mctl,
(struct msm_mctl_pp_frame_info *)vdata->extdata);
diff --git a/drivers/media/video/msm/msm_logging.h b/drivers/media/video/msm/msm_logging.h
deleted file mode 100644
index 5e1547c..0000000
--- a/drivers/media/video/msm/msm_logging.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * 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 __MSM_LOGGING_H
-#define __MSM_LOGGING_H
-
-#include <linux/time.h>
-
-#ifdef MSM_LOG_LEVEL_ERROR
-#undef MSM_LOG_LEVEL_ERROR
-#endif
-
-#ifdef MSM_LOG_LEVEL_PROFILE
-#undef MSM_LOG_LEVEL_PROFILE
-#endif
-
-#ifdef MSM_LOG_LEVEL_ALL
-#undef MSM_LOG_LEVEL_ALL
-#endif
-
-/* MSM_LOG_LEVEL_ERROR - prints only error logs
- * MSM_LOG_LEVEL_PROFILE - prints all profile and error logs
- * MSM_LOG_LEVEL_ALL - prints all logs */
-
-#define MSM_LOG_LEVEL_ERROR
-/* #define MSM_LOG_LEVEL_PROFILE */
-/* #define MSM_LOG_LEVEL_ALL */
-
-#ifdef LINFO
-#undef LINFO
-#endif
-
-#ifdef LERROR
-#undef LERROR
-#endif
-
-#ifdef LPROFSTART
-#undef LPROFSTART
-#endif
-
-#ifdef LPROFEND
-#undef LPROFEND
-#endif
-
-#if defined(MSM_LOG_LEVEL_ERROR)
-#define LDECVAR(VAR)
-#define LINFO(fmt, args...) pr_debug(fmt, ##args)
-#define LERROR(fmt, args...) pr_err(fmt, ##args)
-#define LPROFSTART(START) do {} while (0)
-#define LPROFEND(START, END) do {} while (0)
-#elif defined(MSM_LOG_LEVEL_PROFILE)
-#define LDECVAR(VAR) \
- static struct timespec VAR
-#define LINFO(fmt, args...) do {} while (0)
-#define LERROR(fmt, args...) pr_err(fmt, ##args)
-#define LPROFSTART(START) \
- START = current_kernel_time()
-#define LPROFEND(START, END) \
- do { \
- END = current_kernel_time(); \
- pr_info("profile start time in ns: %lu\n", \
- (START.tv_sec * NSEC_PER_SEC) + \
- START.tv_nsec); \
- pr_info("profile end time in ns: %lu\n", \
- (END.tv_sec * NSEC_PER_SEC) + \
- END.tv_nsec); \
- pr_info("profile diff time in ns: %lu\n", \
- ((END.tv_sec - START.tv_sec) * NSEC_PER_SEC) + \
- (END.tv_nsec - START.tv_nsec)); \
- START = END; \
- } while (0)
-
-#elif defined(MSM_LOG_LEVEL_ALL)
-#define LDECVAR(VAR) \
- static struct timespec VAR
-#define LINFO(fmt, args...) pr_debug(fmt, ##args)
-#define LERROR(fmt, args...) pr_err(fmt, ##args)
-#define LPROFSTART(START) \
- START = current_kernel_time()
-#define LPROFEND(START, END) \
- do { \
- END = current_kernel_time(); \
- pr_info("profile start time in ns: %lu\n", \
- (START.tv_sec * NSEC_PER_SEC) + \
- START.tv_nsec); \
- pr_info("profile end time in ns: %lu\n", \
- (END.tv_sec * NSEC_PER_SEC) + \
- END.tv_nsec); \
- pr_info("profile diff time in ns: %lu\n", \
- ((END.tv_sec - START.tv_sec) * NSEC_PER_SEC) + \
- (END.tv_nsec - START.tv_nsec)); \
- START = END; \
- } while (0)
-#else
-#define LDECVAR(VAR)
-#define LINFO(fmt, args...) do {} while (0)
-#define LERROR(fmt, args...) do {} while (0)
-#define LPROFSTART(START) do {} while (0)
-#define LPROFEND(START, END) do {} while (0)
-#endif
-#endif
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index a3cf004..73fd383 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -299,6 +299,9 @@
case MSM_CAM_IOCTL_PICT_PP:
rc = msm_mctl_set_pp_key(p_mctl, (void __user *)arg);
break;
+ case MSM_CAM_IOCTL_PICT_PP_DIVERT_DONE:
+ rc = msm_mctl_pp_divert_done(p_mctl, (void __user *)arg);
+ break;
case MSM_CAM_IOCTL_PICT_PP_DONE:
rc = msm_mctl_pp_done(p_mctl, (void __user *)arg);
break;
diff --git a/drivers/media/video/msm/msm_mctl_buf.c b/drivers/media/video/msm/msm_mctl_buf.c
index aed70bc..7a0cc02 100644
--- a/drivers/media/video/msm/msm_mctl_buf.c
+++ b/drivers/media/video/msm/msm_mctl_buf.c
@@ -97,8 +97,15 @@
if (buf->state == MSM_BUFFER_STATE_INITIALIZED)
return rc;
- buf_type = (vb->num_planes == 1) ? VIDEOBUF2_SINGLE_PLANE
- : VIDEOBUF2_MULTIPLE_PLANES;
+ if (pcam_inst->plane_info.buffer_type ==
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ buf_type = VIDEOBUF2_MULTIPLE_PLANES;
+ else if (pcam_inst->plane_info.buffer_type ==
+ V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ buf_type = VIDEOBUF2_SINGLE_PLANE;
+ else
+ return -EINVAL;
+
if (buf_type == VIDEOBUF2_SINGLE_PLANE) {
offset.sp_off.y_off = pcam_inst->plane_info.sp_y_offset;
offset.sp_off.cbcr_off =
@@ -319,52 +326,6 @@
return 0;
}
-static int msm_buf_init(struct msm_cam_v4l2_dev_inst *pcam_inst)
-{
- int rc = 0;
- struct resource *res;
- struct platform_device *pdev = NULL;
- struct msm_cam_v4l2_device *pcam = NULL;
-
- D("%s\n", __func__);
- pcam = pcam_inst->pcam;
- if (!pcam) {
- pr_err("%s error : input is NULL\n", __func__);
- return -EINVAL;
- } else
- pdev = pcam->mctl.sync.pdev;
-
- if (!pdev) {
- pr_err("%s error : pdev is NULL\n", __func__);
- return -EINVAL;
- }
- if (pcam->use_count == 1) {
- /* first check if we have resources */
- res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (res) {
- D("res->start = 0x%x\n", (u32)res->start);
- D("res->size = 0x%x\n", (u32)resource_size(res));
- D("res->end = 0x%x\n", (u32)res->end);
- rc = dma_declare_coherent_memory(&pdev->dev, res->start,
- res->start,
- resource_size(res),
- DMA_MEMORY_MAP |
- DMA_MEMORY_EXCLUSIVE);
- if (!rc) {
- pr_err("%s: Unable to declare coherent memory.\n",
- __func__);
- rc = -ENXIO;
- return rc;
- }
- D("%s: found DMA capable resource\n", __func__);
- } else {
- pr_err("%s: no DMA capable resource\n", __func__);
- return -ENOMEM;
- }
- }
- return 0;
-}
-
int msm_mctl_out_type_to_inst_index(struct msm_cam_v4l2_device *pcam,
int out_type)
{
@@ -502,7 +463,6 @@
int msm_mctl_buf_init(struct msm_cam_v4l2_device *pcam)
{
- pcam->mctl.mctl_buf_init = msm_buf_init;
pcam->mctl.mctl_vbqueue_init = msm_vbqueue_init;
return 0;
}
diff --git a/drivers/media/video/msm/msm_mctl_pp.c b/drivers/media/video/msm/msm_mctl_pp.c
index 8236dae..77f963c 100644
--- a/drivers/media/video/msm/msm_mctl_pp.c
+++ b/drivers/media/video/msm/msm_mctl_pp.c
@@ -49,7 +49,7 @@
return -ENOMEM;
}
D("%s: msm_cam_evt_divert_frame=%d",
- __func__, sizeof(struct msm_cam_evt_divert_frame));
+ __func__, sizeof(struct msm_cam_evt_divert_frame));
memset(&v4l2_evt, 0, sizeof(v4l2_evt));
v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
MSM_CAM_RESP_DIV_FRAME_EVT_MSG;
@@ -82,7 +82,7 @@
image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW;
if (p_mctl->pp_info.pp_key & pp_key)
*pp_divert_type = OUTPUT_TYPE_P;
- if (p_mctl->pp_info.pp_ctrl.pp_msg_type == OUTPUT_TYPE_P)
+ if (p_mctl->pp_info.pp_ctrl.pp_msg_type & OUTPUT_TYPE_P)
*pp_type = OUTPUT_TYPE_P;
break;
case VFE_MSG_OUTPUT_S:
@@ -90,15 +90,15 @@
image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
if (p_mctl->pp_info.pp_key & pp_key)
*pp_divert_type = OUTPUT_TYPE_S;
- if (p_mctl->pp_info.pp_ctrl.pp_msg_type == OUTPUT_TYPE_S)
+ if (p_mctl->pp_info.pp_ctrl.pp_msg_type & OUTPUT_TYPE_S)
*pp_type = OUTPUT_TYPE_P;
break;
case VFE_MSG_OUTPUT_V:
- if (p_mctl->pp_info.pp_ctrl.pp_msg_type == OUTPUT_TYPE_V)
+ if (p_mctl->pp_info.pp_ctrl.pp_msg_type & OUTPUT_TYPE_V)
*pp_type = OUTPUT_TYPE_V;
break;
case VFE_MSG_OUTPUT_T:
- if (p_mctl->pp_info.pp_ctrl.pp_msg_type == OUTPUT_TYPE_T)
+ if (p_mctl->pp_info.pp_ctrl.pp_msg_type & OUTPUT_TYPE_T)
*pp_type = OUTPUT_TYPE_T;
break;
default:
@@ -142,10 +142,8 @@
div.op_mode = pcam_inst->pcam->op_mode;
div.inst_idx = pcam_inst->my_index;
div.node_idx = pcam_inst->pcam->vnode_id;
- p_mctl->pp_info.cur_frame_id[pcam_inst->image_mode]++;
- if (p_mctl->pp_info.cur_frame_id[pcam_inst->image_mode] == 0)
- p_mctl->pp_info.cur_frame_id[pcam_inst->image_mode]++;
- div.frame.frame_id =
+ p_mctl->pp_info.cur_frame_id[pcam_inst->image_mode] = frame_id;
+ div.frame.frame_id =
p_mctl->pp_info.cur_frame_id[pcam_inst->image_mode];
div.frame.handle = (uint32_t)vb;
msm_mctl_gettimeofday(&div.frame.timestamp);
@@ -160,7 +158,7 @@
/* This buffer contains only 1 plane. Use the
* single planar structure to store the info.*/
div.frame.num_planes = 1;
- div.frame.sp.phy_addr =
+ div.frame.sp.phy_addr =
videobuf2_to_pmem_contig(&vb->vidbuf, 0);
div.frame.sp.addr_offset = mem->addr_offset;
div.frame.sp.y_off = 0;
@@ -582,28 +580,17 @@
sizeof(divert_pp)))
return -EFAULT;
D("%s: PP_PATH, path=%d",
- __func__, divert_pp.path);
+ __func__, divert_pp.path);
spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
- p_mctl->pp_info.pp_ctrl.pp_msg_type = divert_pp.path;
+ if (divert_pp.enable)
+ p_mctl->pp_info.pp_ctrl.pp_msg_type |= divert_pp.path;
+ else
+ p_mctl->pp_info.pp_ctrl.pp_msg_type &= ~divert_pp.path;
spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
- D("%s: pp path = %d", __func__,
- p_mctl->pp_info.pp_ctrl.pp_msg_type);
+ D("%s: pp path = 0x%x", __func__,
+ p_mctl->pp_info.pp_ctrl.pp_msg_type);
break;
}
- case MCTL_CMD_DIVERT_FRAME_PP_DONE: {
- struct msm_frame_buffer *buf = NULL;
- if (copy_from_user(&pp_buffer, pp_cmd->value,
- sizeof(pp_buffer)))
- return -EFAULT;
- buf = (struct msm_frame_buffer *)pp_buffer.buf_handle;
- msg_type = msm_mctl_pp_path_to_msg_type(
- pp_buffer.path);
- if (msm_mctl_buf_del(p_mctl, msg_type, buf) == 0) {
- vb2_buffer_done(&buf->vidbuf,
- VB2_BUF_STATE_DONE);
- }
- }
- break;
default:
rc = -EPERM;
break;
@@ -843,7 +830,7 @@
memset(&p_mctl->pp_info.div_frame[image_mode],
0, sizeof(buf));
if (p_mctl->pp_info.cur_frame_id[image_mode] !=
- frame.frame_id) {
+ frame.frame_id) {
/* dirty frame. should not pass to app */
dirty = 1;
}
@@ -862,3 +849,49 @@
return rc;
}
+int msm_mctl_pp_divert_done(
+ struct msm_cam_media_controller *p_mctl,
+ void __user *arg)
+{
+ struct msm_pp_frame frame;
+ int msg_type, image_mode, rc = 0;
+ int dirty = 0;
+ struct msm_free_buf buf;
+ unsigned long flags;
+
+ if (copy_from_user(&frame, arg, sizeof(frame)))
+ return -EFAULT;
+
+ spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
+ switch (frame.path) {
+ case OUTPUT_TYPE_P:
+ msg_type = VFE_MSG_OUTPUT_P;
+ image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW;
+ break;
+ case OUTPUT_TYPE_S:
+ msg_type = VFE_MSG_OUTPUT_S;
+ image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
+ break;
+ case OUTPUT_TYPE_V:
+ msg_type = VFE_MSG_OUTPUT_V;
+ image_mode = MSM_V4L2_EXT_CAPTURE_MODE_VIDEO;
+ break;
+ case OUTPUT_TYPE_T:
+ default:
+ rc = -EFAULT;
+ goto err;
+ }
+ if (frame.num_planes > 1)
+ buf.ch_paddr[0] = frame.mp[0].phy_addr;
+ else
+ buf.ch_paddr[0] = frame.sp.phy_addr;
+ spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
+ /* here buf.addr is phy_addr */
+ rc = msm_mctl_buf_done_pp(p_mctl, msg_type, &buf, dirty);
+ return rc;
+err:
+ spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
+ return rc;
+}
+
+
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index e8904e2..d34d5b1 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -1461,6 +1461,45 @@
cmdp_local, (vfe32_cmd[cmd->id].length));
}
break;
+ case VFE_CMD_CHROMA_SUP_UPDATE:
+ case VFE_CMD_CHROMA_SUP_CFG:{
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ msm_io_memcpy(vfe32_ctrl->vfebase + V32_CHROMA_SUP_OFF,
+ cmdp_local, 4);
+
+ cmdp_local += 1;
+ new_val = *cmdp_local;
+ /* Incrementing with 4 so as to point to the 2nd Register as
+ * the 2nd register has the mce_enable bit
+ */
+ old_val = msm_io_r(vfe32_ctrl->vfebase +
+ V32_CHROMA_SUP_OFF + 4);
+ old_val &= ~MCE_EN_MASK;
+ new_val = new_val | old_val;
+ msm_io_memcpy(vfe32_ctrl->vfebase + V32_CHROMA_SUP_OFF + 4,
+ &new_val, 4);
+ cmdp_local += 1;
+
+ old_val = msm_io_r(vfe32_ctrl->vfebase +
+ V32_CHROMA_SUP_OFF + 8);
+ new_val = *cmdp_local;
+ old_val &= ~MCE_Q_K_MASK;
+ new_val = new_val | old_val;
+ msm_io_memcpy(vfe32_ctrl->vfebase + V32_CHROMA_SUP_OFF + 8,
+ &new_val, 4);
+ }
+ break;
case VFE_CMD_BLACK_LEVEL_CFG:
rc = -EFAULT;
goto proc_general_done;
@@ -2092,6 +2131,9 @@
}
msm_io_memcpy(vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
cmdp, (vfe32_cmd[cmd->id].length));
+ cmdp_local = cmdp + V32_ASF_LEN/4;
+ msm_io_memcpy(vfe32_ctrl->vfebase + V32_ASF_SPECIAL_EFX_CFG_OFF,
+ cmdp_local, V32_ASF_SPECIAL_EFX_CFG_LEN);
break;
case VFE_CMD_PCA_ROLL_OFF_CFG:
@@ -2220,17 +2262,17 @@
CDBG("%s: PCA Rolloff Ram0\n", __func__);
for (i = 0 ; i < V33_PCA_ROLL_OFF_TABLE_SIZE * 2; i++) {
- temp2 = (i == (V33_PCA_ROLL_OFF_TABLE_SIZE - 1));
+ temp2 = (i == (V33_PCA_ROLL_OFF_TABLE_SIZE));
if (old_val && temp2)
vfe32_program_dmi_cfg(ROLLOFF_RAM1_BANK1);
else if (!old_val && temp2)
vfe32_program_dmi_cfg(ROLLOFF_RAM1_BANK0);
+ *cmdp_local = msm_io_r(vfe32_ctrl->vfebase +
+ VFE33_DMI_DATA_LO);
*(cmdp_local + 1) =
msm_io_r(vfe32_ctrl->vfebase +
VFE33_DMI_DATA_HI);
- *cmdp_local = msm_io_r(vfe32_ctrl->vfebase +
- VFE33_DMI_DATA_LO);
CDBG("%s: %08x%08x\n", __func__,
*(cmdp_local + 1), *cmdp_local);
cmdp_local += 2;
diff --git a/drivers/media/video/msm/msm_vfe32.h b/drivers/media/video/msm/msm_vfe32.h
index e41a544..ecb8608 100644
--- a/drivers/media/video/msm/msm_vfe32.h
+++ b/drivers/media/video/msm/msm_vfe32.h
@@ -349,6 +349,9 @@
#define V32_MODULE_CFG_OFF 0x00000010
#define V32_MODULE_CFG_LEN 4
+#define V32_ASF_SPECIAL_EFX_CFG_OFF 0x000005FC
+#define V32_ASF_SPECIAL_EFX_CFG_LEN 4
+
#define V32_CLF_CFG_OFF 0x000006B0
#define V32_CLF_CFG_LEN 72
diff --git a/drivers/media/video/msm/msm_vpe.c b/drivers/media/video/msm/msm_vpe.c
index 658f911..2f693ea 100644
--- a/drivers/media/video/msm/msm_vpe.c
+++ b/drivers/media/video/msm/msm_vpe.c
@@ -668,6 +668,7 @@
atomic_set(&vpe_init_done, 0);
return rc;
}
+ v4l2_set_subdev_hostdata(sd, data);
spin_lock_init(&vpe_ctrl->lock);
CDBG("%s:end", __func__);
return rc;
diff --git a/drivers/media/video/msm/qs_mt9p017.c b/drivers/media/video/msm/qs_mt9p017.c
deleted file mode 100644
index d160af8..0000000
--- a/drivers/media/video/msm/qs_mt9p017.c
+++ /dev/null
@@ -1,1255 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * 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/delay.h>
-#include <linux/debugfs.h>
-#include <linux/types.h>
-#include <linux/i2c.h>
-#include <linux/uaccess.h>
-#include <linux/miscdevice.h>
-#include <linux/slab.h>
-#include <media/msm_camera.h>
-#include <media/v4l2-subdev.h>
-#include <mach/gpio.h>
-#include <mach/camera.h>
-#include "qs_mt9p017.h"
-#include "msm.h"
-/*
-* =============================================================
-* SENSOR REGISTER DEFINES
-* ==============================================================
-*/
-#define REG_GROUPED_PARAMETER_HOLD 0x0104
-#define GROUPED_PARAMETER_HOLD_OFF 0x00
-#define GROUPED_PARAMETER_HOLD 0x01
-/* Integration Time */
-#define REG_COARSE_INTEGRATION_TIME 0x3012
-/* Gain */
-#define REG_GLOBAL_GAIN 0x305E
-#define REG_GR_GAIN 0x3056
-#define REG_R_GAIN 0x3058
-#define REG_B_GAIN 0x305A
-#define REG_GB_GAIN 0x305C
-
-/* PLL registers */
-#define REG_FRAME_LENGTH_LINES 0x300A
-#define REG_LINE_LENGTH_PCK 0x300C
-/* Test Pattern */
-#define REG_TEST_PATTERN_MODE 0x0601
-#define REG_VCM_NEW_CODE 0x30F2
-#define AF_ADDR 0x18
-#define BRIDGE_ADDR 0x80
-/*
-* ============================================================================
-* TYPE DECLARATIONS
-* ============================================================================
-*/
-
-/* 16bit address - 8 bit context register structure */
-#define Q8 0x00000100
-#define Q10 0x00000400
-#define QS_MT9P017_MASTER_CLK_RATE 24000000
-#define QS_MT9P017_OFFSET 8
-
-/* AF Total steps parameters */
-#define QS_MT9P017_TOTAL_STEPS_NEAR_TO_FAR 32
-#define QS_MT9P017_NL_REGION_BOUNDARY 3
-#define QS_MT9P017_NL_REGION_CODE_PER_STEP 30
-#define QS_MT9P017_L_REGION_CODE_PER_STEP 4
-
-#define QS_MT9P017_BRIDGE_DBG 0
-
-static struct i2c_client *qs_mt9p017_client;
-
-struct qs_mt9p017_format {
- enum v4l2_mbus_pixelcode code;
- enum v4l2_colorspace colorspace;
- u16 fmt;
- u16 order;
-};
-
-struct qs_mt9p017_ctrl_t {
- const struct msm_camera_sensor_info *sensordata;
-
- uint32_t sensormode;
- uint32_t fps_divider;/* init to 1 * 0x00000400 */
- uint32_t pict_fps_divider;/* init to 1 * 0x00000400 */
- uint16_t fps;
-
- uint16_t curr_lens_pos;
- uint16_t curr_step_pos;
- uint16_t my_reg_gain;
- uint32_t my_reg_line_count;
- uint16_t total_lines_per_frame;
-
- enum qs_mt9p017_resolution_t prev_res;
- enum qs_mt9p017_resolution_t pict_res;
- enum qs_mt9p017_resolution_t curr_res;
- enum qs_mt9p017_cam_mode_t cam_mode;
- struct v4l2_subdev *sensor_dev;
- struct qs_mt9p017_format *fmt;
- uint16_t qs_mt9p017_step_position_table
- [QS_MT9P017_TOTAL_STEPS_NEAR_TO_FAR+1];
- uint16_t prev_line_length_pck;
- uint16_t prev_frame_length_lines;
- uint16_t snap_line_length_pck;
- uint16_t snap_frame_length_lines;
-};
-
-static bool CSI_CONFIG;
-static struct qs_mt9p017_ctrl_t *qs_mt9p017_ctrl;
-DEFINE_MUTEX(qs_mt9p017_mut);
-/*=============================================================*/
-
-static int qs_mt9p017_i2c_rxdata(unsigned short saddr,
- unsigned char *rxdata, int length)
-{
- struct i2c_msg msgs[] = {
- {
- .addr = saddr,
- .flags = 0,
- .len = length,
- .buf = rxdata,
- },
- {
- .addr = saddr,
- .flags = I2C_M_RD,
- .len = length,
- .buf = rxdata,
- },
- };
- if (i2c_transfer(qs_mt9p017_client->adapter, msgs, 2) < 0) {
- CDBG("qs_mt9p017_i2c_rxdata faild 0x%x\n", saddr);
- return -EIO;
- }
- return 0;
-}
-
-static int32_t qs_mt9p017_i2c_txdata(unsigned short saddr,
- unsigned char *txdata, int length)
-{
- struct i2c_msg msg[] = {
- {
- .addr = saddr,
- .flags = 0,
- .len = length,
- .buf = txdata,
- },
- };
- if (i2c_transfer(qs_mt9p017_client->adapter, msg, 1) < 0) {
- CDBG("qs_mt9p017_i2c_txdata faild 0x%x\n", saddr);
- return -EIO;
- }
-
- return 0;
-}
-
-static int32_t qs_mt9p017_i2c_read(unsigned short raddr,
- unsigned short *rdata, int rlen)
-{
- int32_t rc = 0;
- unsigned char buf[] = {
- raddr >> BITS_PER_BYTE,
- raddr,
- };
- if (!rdata)
- return -EIO;
- rc = qs_mt9p017_i2c_rxdata(qs_mt9p017_client->addr, buf, rlen);
- if (rc < 0) {
- CDBG("qs_mt9p017_i2c_read 0x%x failed!\n", raddr);
- return rc;
- }
- *rdata = (rlen == 2 ? buf[0] << BITS_PER_BYTE | buf[1] : buf[0]);
- CDBG("qs_mt9p017_i2c_read 0x%x val = 0x%x!\n", raddr, *rdata);
- return rc;
-}
-
-static int32_t qs_mt9p017_i2c_write_w_sensor(unsigned short waddr,
- uint16_t wdata)
-{
- int32_t rc = -EFAULT;
- unsigned char buf[] = {
- waddr >> BITS_PER_BYTE,
- waddr,
- wdata >> BITS_PER_BYTE,
- wdata,
- };
- CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, wdata);
- rc = qs_mt9p017_i2c_txdata(qs_mt9p017_client->addr, buf, 4);
- if (rc < 0) {
- CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
- waddr, wdata);
- }
- return rc;
-}
-
-static int32_t qs_mt9p017_i2c_write_b_sensor(unsigned short waddr,
- uint8_t bdata)
-{
- int32_t rc = -EFAULT;
- unsigned char buf[] = {
- waddr >> BITS_PER_BYTE,
- waddr,
- bdata,
- };
- CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata);
- rc = qs_mt9p017_i2c_txdata(qs_mt9p017_client->addr, buf, 3);
- if (rc < 0) {
- CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
- waddr, bdata);
- }
- return rc;
-}
-
-static int32_t qs_mt9p017_i2c_write_seq_sensor(unsigned short waddr,
- unsigned char *seq_data, int len)
-{
- int32_t rc = -EFAULT;
- unsigned char buf[len+2];
- int i = 0;
- buf[0] = waddr >> BITS_PER_BYTE;
- buf[1] = waddr;
- for (i = 0; i < len; i++)
- buf[i+2] = seq_data[i];
- rc = qs_mt9p017_i2c_txdata(qs_mt9p017_client->addr, buf, len+2);
- return rc;
-}
-
-static int32_t qs_mt9p017_i2c_write_w_table(struct qs_mt9p017_i2c_reg_conf const
- *reg_conf_tbl, int num)
-{
- int i;
- int32_t rc = -EIO;
- for (i = 0; i < num; i++) {
- rc = qs_mt9p017_i2c_write_w_sensor(reg_conf_tbl->waddr,
- reg_conf_tbl->wdata);
- if (rc < 0)
- break;
- reg_conf_tbl++;
- }
- return rc;
-}
-
-static int32_t bridge_i2c_write_w(unsigned short waddr, uint16_t wdata)
-{
- int32_t rc = -EFAULT;
- unsigned char buf[] = {
- waddr >> BITS_PER_BYTE,
- waddr,
- wdata >> BITS_PER_BYTE,
- wdata,
- };
- CDBG("bridge_i2c_write_w addr = 0x%x, val = 0x%x\n", waddr, wdata);
- rc = qs_mt9p017_i2c_txdata(BRIDGE_ADDR>>1, buf, 4);
- if (rc < 0) {
- CDBG("bridge_i2c_write_w failed, addr = 0x%x, val = 0x%x!\n",
- waddr, wdata);
- }
- return rc;
-}
-
-static int32_t bridge_i2c_read(unsigned short raddr,
- unsigned short *rdata, int rlen)
-{
- int32_t rc = 0;
- unsigned char buf[] = {
- raddr >> BITS_PER_BYTE,
- raddr,
- };
- if (!rdata)
- return -EIO;
- rc = qs_mt9p017_i2c_rxdata(BRIDGE_ADDR>>1, buf, rlen);
- if (rc < 0) {
- CDBG("bridge_i2c_read 0x%x failed!\n", raddr);
- return rc;
- }
- *rdata = (rlen == 2 ? buf[0] << BITS_PER_BYTE | buf[1] : buf[0]);
- CDBG("bridge_i2c_read 0x%x val = 0x%x!\n", raddr, *rdata);
- return rc;
-}
-
-static int32_t qs_mt9p017_eeprom_i2c_read(unsigned short raddr,
- unsigned char *rdata, int rlen)
-{
- int32_t rc = 0;
- unsigned short i2caddr = 0xA0 >> 1;
- uint8_t block_num = 0;
- unsigned char buf[rlen+2];
- int i = 0;
- if (!rdata)
- return -EIO;
-
- block_num = raddr >> BITS_PER_BYTE;
- i2caddr |= block_num;
-
- buf[0] = raddr >> BITS_PER_BYTE;
- buf[1] = raddr;
- rc = qs_mt9p017_i2c_rxdata(i2caddr, buf, rlen);
- if (rc < 0) {
- CDBG("qs_mt9p017_eeprom_i2c_read 0x%x failed!\n", raddr);
- return rc;
- }
- for (i = 0; i < rlen; i++) {
- rdata[i] = buf[i];
- CDBG("qs_mt9p017_eeprom_i2c_read 0x%x index: %d val = 0x%x!\n",
- raddr, i, buf[i]);
- }
- return rc;
-}
-
-static int32_t qs_mt9p017_eeprom_i2c_read_b(unsigned short raddr,
- unsigned short *rdata, int rlen)
-{
- int32_t rc = 0;
- unsigned char buf[2];
- rc = qs_mt9p017_eeprom_i2c_read(raddr, &buf[0], rlen);
- *rdata = (rlen == 2 ? buf[0] << BITS_PER_BYTE | buf[1] : buf[0]);
- CDBG("qs_mt9p017_eeprom_i2c_read 0x%x val = 0x%x!\n", raddr, *rdata);
- return rc;
-}
-
-static int32_t qs_mt9p017_get_calibration_data(
- struct sensor_3d_cali_data_t *cdata)
-{
- struct qs_mt9p017_i2c_read_seq_t eeprom_read_seq_tbl[] = {
- {0x0, &(cdata->left_p_matrix[0][0][0]), 96},
- {0x60, &(cdata->right_p_matrix[0][0][0]), 96},
- {0xC0, &(cdata->square_len[0]), 8},
- {0xC8, &(cdata->focal_len[0]), 8},
- {0xD0, &(cdata->pixel_pitch[0]), 8},
- };
-
- struct qs_mt9p017_i2c_read_t eeprom_read_tbl[] = {
- {0x100, &(cdata->left_r), 1},
- {0x101, &(cdata->right_r), 1},
- {0x102, &(cdata->left_b), 1},
- {0x103, &(cdata->right_b), 1},
- {0x104, &(cdata->left_gb), 1},
- {0x105, &(cdata->right_gb), 1},
- {0x110, &(cdata->left_af_far), 2},
- {0x112, &(cdata->right_af_far), 2},
- {0x114, &(cdata->left_af_mid), 2},
- {0x116, &(cdata->right_af_mid), 2},
- {0x118, &(cdata->left_af_short), 2},
- {0x11A, &(cdata->right_af_short), 2},
- {0x11C, &(cdata->left_af_5um), 2},
- {0x11E, &(cdata->right_af_5um), 2},
- {0x120, &(cdata->left_af_50up), 2},
- {0x122, &(cdata->right_af_50up), 2},
- {0x124, &(cdata->left_af_50down), 2},
- {0x126, &(cdata->right_af_50down), 2},
- };
-
- int i;
- for (i = 0; i < ARRAY_SIZE(eeprom_read_seq_tbl); i++) {
- qs_mt9p017_eeprom_i2c_read(
- eeprom_read_seq_tbl[i].raddr,
- eeprom_read_seq_tbl[i].rdata,
- eeprom_read_seq_tbl[i].rlen);
- }
-
- for (i = 0; i < ARRAY_SIZE(eeprom_read_tbl); i++) {
- qs_mt9p017_eeprom_i2c_read_b(
- eeprom_read_tbl[i].raddr,
- eeprom_read_tbl[i].rdata,
- eeprom_read_tbl[i].rlen);
- }
- return 0;
-}
-
-static int32_t qs_mt9p017_load_left_lsc(void)
-{
- int i;
- unsigned char left_lsc1[210];
- unsigned short left_origin_c, left_origin_r;
- struct qs_mt9p017_i2c_reg_conf lsc_conf[] = {
- {0x37C0, 0x0000},
- {0x37C2, 0x0000},
- {0x37C4, 0x0000},
- {0x37C6, 0x0000},
- {0x3780, 0x8000},
- };
- qs_mt9p017_eeprom_i2c_read(0x200, &left_lsc1[0], 126);
- qs_mt9p017_eeprom_i2c_read_b(0x27E, &left_origin_c, 2);
- qs_mt9p017_eeprom_i2c_read_b(0x280, &left_origin_r, 2);
- bridge_i2c_write_w(0x06, 0x01);
- qs_mt9p017_i2c_write_seq_sensor(0x3600, left_lsc1, 126);
- qs_mt9p017_i2c_write_w_sensor(0x3782, left_origin_c);
- qs_mt9p017_i2c_write_w_sensor(0x3784, left_origin_r);
- for (i = 0; i < ARRAY_SIZE(lsc_conf); i++) {
- qs_mt9p017_i2c_write_w_sensor(
- lsc_conf[i].waddr, lsc_conf[i].wdata);
- }
- return 0;
-}
-
-static int32_t qs_mt9p017_load_right_lsc(void)
-{
- int i;
- unsigned char right_lsc1[210];
- unsigned short right_origin_c, right_origin_r;
- struct qs_mt9p017_i2c_reg_conf lsc_conf[] = {
- {0x37C0, 0x0000},
- {0x37C2, 0x0000},
- {0x37C4, 0x0000},
- {0x37C6, 0x0000},
- {0x3780, 0x8000},
- };
- qs_mt9p017_eeprom_i2c_read(0x2D2, &right_lsc1[0], 126);
- qs_mt9p017_eeprom_i2c_read_b(0x350, &right_origin_c, 2);
- qs_mt9p017_eeprom_i2c_read_b(0x352, &right_origin_r, 2);
- bridge_i2c_write_w(0x06, 0x02);
- qs_mt9p017_i2c_write_seq_sensor(0x3600, right_lsc1, 126);
- qs_mt9p017_i2c_write_w_sensor(0x3782, right_origin_c);
- qs_mt9p017_i2c_write_w_sensor(0x3784, right_origin_r);
-
- for (i = 0; i < ARRAY_SIZE(lsc_conf); i++) {
- qs_mt9p017_i2c_write_w_sensor(
- lsc_conf[i].waddr, lsc_conf[i].wdata);
- }
- return 0;
-}
-
-static int32_t qs_mt9p017_load_lsc(void)
-{
- qs_mt9p017_load_left_lsc();
- qs_mt9p017_load_right_lsc();
- return 0;
-}
-
-static int32_t af_i2c_write_b_sensor(unsigned short baddr, uint8_t bdata)
-{
- int32_t rc = -EFAULT;
- unsigned char buf[2];
- buf[0] = baddr;
- buf[1] = bdata;
- CDBG("af i2c_write_b addr = 0x%x, val = 0x%x\n", baddr, bdata);
- rc = qs_mt9p017_i2c_txdata(AF_ADDR>>1, buf, 2);
- if (rc < 0) {
- CDBG("af i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
- baddr, bdata);
- }
- return rc;
-}
-
-static void qs_mt9p017_bridge_reset(void){
- unsigned short rstl_state = 0, gpio_state = 0;
- bridge_i2c_write_w(0x50, 0x00);
- bridge_i2c_write_w(0x53, 0x00);
- msleep(30);
- bridge_i2c_write_w(0x53, 0x01);
- msleep(30);
- bridge_i2c_write_w(0x14, 0x0C);
- bridge_i2c_write_w(0x0E, 0xFFFF);
-
- bridge_i2c_read(0x54, &rstl_state, 2);
- bridge_i2c_write_w(0x54, (rstl_state | 0x1));
- msleep(30);
- bridge_i2c_write_w(0x54, (rstl_state | 0x3));
- bridge_i2c_read(0x54, &rstl_state, 2);
- bridge_i2c_write_w(0x54, (rstl_state | 0x4));
- bridge_i2c_write_w(0x54, (rstl_state | 0xC));
-
- bridge_i2c_read(0x55, &gpio_state, 2);
- bridge_i2c_write_w(0x55, (gpio_state | 0x1));
- msleep(30);
- bridge_i2c_write_w(0x55, (gpio_state | 0x3));
-
- bridge_i2c_read(0x55, &gpio_state, 2);
- bridge_i2c_write_w(0x55, (gpio_state | 0x4));
- msleep(30);
- bridge_i2c_write_w(0x55, (gpio_state | 0xC));
- bridge_i2c_read(0x55, &gpio_state, 2);
-}
-
-static void qs_mt9p017_bridge_config(int mode, int rt)
-{
- if (mode == MODE_3D) {
- bridge_i2c_write_w(0x16, 0x00);
- bridge_i2c_write_w(0x51, 0x3);
- bridge_i2c_write_w(0x52, 0x1);
- bridge_i2c_write_w(0x06, 0x03);
- bridge_i2c_write_w(0x04, 0x6C18);
- bridge_i2c_write_w(0x50, 0x00);
- } else if (mode == MODE_2D_LEFT) {
- bridge_i2c_write_w(0x06, 0x01);
- bridge_i2c_write_w(0x04, 0x6C18);
- bridge_i2c_write_w(0x50, 0x01);
- } else if (mode == MODE_2D_RIGHT) {
- bridge_i2c_write_w(0x06, 0x02);
- bridge_i2c_write_w(0x04, 0x6C18);
- bridge_i2c_write_w(0x50, 0x02);
- }
-}
-
-static void qs_mt9p017_group_hold_on(void)
-{
- qs_mt9p017_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
- GROUPED_PARAMETER_HOLD);
-}
-
-static void qs_mt9p017_group_hold_off(void)
-{
- qs_mt9p017_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
- GROUPED_PARAMETER_HOLD_OFF);
-}
-
-static void qs_mt9p017_start_stream(void)
-{
- qs_mt9p017_i2c_write_w_sensor(0x301A, 0x065C|0x2);
-}
-
-static void qs_mt9p017_stop_stream(void)
-{
- qs_mt9p017_i2c_write_b_sensor(0x0100, 0x00);
-}
-
-static void qs_mt9p017_get_pict_fps(uint16_t fps, uint16_t *pfps)
-{
- /* input fps is preview fps in Q8 format */
- uint32_t divider, d1, d2;
-
- d1 = qs_mt9p017_ctrl->prev_frame_length_lines * 0x400
- / qs_mt9p017_ctrl->snap_frame_length_lines;
- d2 = qs_mt9p017_ctrl->prev_line_length_pck * 0x400
- / qs_mt9p017_ctrl->snap_line_length_pck;
- divider = d1 * d2 / 0x400;
-
- /*Verify PCLK settings and frame sizes.*/
- *pfps = (uint16_t) (fps * divider / 0x400);
- /* 2 is the ratio of no.of snapshot channels
- to number of preview channels */
-}
-
-static int32_t qs_mt9p017_set_fps(struct fps_cfg *fps)
-{
- uint16_t total_lines_per_frame;
- int32_t rc = 0;
- total_lines_per_frame = (uint16_t)
- ((qs_mt9p017_ctrl->prev_frame_length_lines) *
- qs_mt9p017_ctrl->fps_divider/0x400);
- qs_mt9p017_ctrl->fps_divider = fps->fps_div;
- qs_mt9p017_ctrl->pict_fps_divider = fps->pict_fps_div;
-
- qs_mt9p017_group_hold_on();
- rc = qs_mt9p017_i2c_write_w_sensor(REG_FRAME_LENGTH_LINES,
- total_lines_per_frame);
- qs_mt9p017_group_hold_off();
- return rc;
-}
-
-static int32_t qs_mt9p017_write_exp_gain(struct sensor_3d_exp_cfg exp_cfg)
-{
- uint16_t max_legal_gain = 0xE7F;
- uint16_t gain = exp_cfg.gain;
- uint32_t line = exp_cfg.line;
- int32_t rc = 0;
- if (gain > max_legal_gain) {
- CDBG("Max legal gain Line:%d\n", __LINE__);
- gain = max_legal_gain;
- }
- qs_mt9p017_group_hold_on();
- rc = qs_mt9p017_i2c_write_w_sensor(REG_GLOBAL_GAIN, gain|0x1000);
- rc = qs_mt9p017_i2c_write_w_sensor(REG_COARSE_INTEGRATION_TIME, line);
- if (qs_mt9p017_ctrl->cam_mode == MODE_3D) {
- bridge_i2c_write_w(0x06, 0x02);
- rc = qs_mt9p017_i2c_write_w_sensor(REG_GR_GAIN, gain|0x1000);
- rc = qs_mt9p017_i2c_write_w_sensor(REG_R_GAIN,
- exp_cfg.r_gain|0x1000);
- rc = qs_mt9p017_i2c_write_w_sensor(REG_B_GAIN,
- exp_cfg.b_gain|0x1000);
- rc = qs_mt9p017_i2c_write_w_sensor(REG_GB_GAIN,
- exp_cfg.gb_gain|0x1000);
- bridge_i2c_write_w(0x06, 0x03);
- }
- qs_mt9p017_group_hold_off();
- return rc;
-}
-
-static int32_t qs_mt9p017_set_pict_exp_gain(struct sensor_3d_exp_cfg exp_cfg)
-{
- int32_t rc = 0;
- rc = qs_mt9p017_write_exp_gain(exp_cfg);
- qs_mt9p017_i2c_write_w_sensor(0x301A, 0x065C|0x2);
- return rc;
-}
-
-static int32_t qs_mt9p017_move_focus(int direction,
- int32_t num_steps)
-{
- int16_t step_direction, actual_step, next_position;
- uint8_t code_val_msb, code_val_lsb;
- if (direction == MOVE_NEAR)
- step_direction = 16;
- else
- step_direction = -16;
-
- actual_step = (int16_t) (step_direction * (int16_t) num_steps);
- next_position = (int16_t) (qs_mt9p017_ctrl->curr_lens_pos+actual_step);
-
- if (next_position > 1023)
- next_position = 1023;
- else if (next_position < 0)
- next_position = 0;
-
- code_val_msb = next_position >> 8;
- code_val_lsb = (next_position & 0x00FF);
- af_i2c_write_b_sensor(0x4, code_val_msb);
- af_i2c_write_b_sensor(0x5, code_val_lsb);
-
- qs_mt9p017_ctrl->curr_lens_pos = next_position;
- return 0;
-}
-
-static int32_t qs_mt9p017_set_default_focus(uint8_t af_step)
-{
- int32_t rc = 0;
- if (qs_mt9p017_ctrl->curr_step_pos != 0) {
- rc = qs_mt9p017_move_focus(MOVE_FAR,
- qs_mt9p017_ctrl->curr_step_pos);
- } else {
- af_i2c_write_b_sensor(0x4, 0);
- af_i2c_write_b_sensor(0x5, 0);
- }
-
- qs_mt9p017_ctrl->curr_lens_pos = 0;
- qs_mt9p017_ctrl->curr_step_pos = 0;
-
- return rc;
-}
-
-static void qs_mt9p017_init_focus(void)
-{
- uint8_t i;
- qs_mt9p017_ctrl->qs_mt9p017_step_position_table[0] = 0;
- for (i = 1; i <= QS_MT9P017_TOTAL_STEPS_NEAR_TO_FAR; i++) {
- if (i <= QS_MT9P017_NL_REGION_BOUNDARY) {
- qs_mt9p017_ctrl->qs_mt9p017_step_position_table[i] =
- qs_mt9p017_ctrl->qs_mt9p017_step_position_table[i-1]
- + QS_MT9P017_NL_REGION_CODE_PER_STEP;
- } else {
- qs_mt9p017_ctrl->qs_mt9p017_step_position_table[i] =
- qs_mt9p017_ctrl->qs_mt9p017_step_position_table[i-1]
- + QS_MT9P017_L_REGION_CODE_PER_STEP;
- }
-
- if (qs_mt9p017_ctrl->qs_mt9p017_step_position_table[i] > 255)
- qs_mt9p017_ctrl->
- qs_mt9p017_step_position_table[i] = 255;
- }
-}
-
-static int32_t qs_mt9p017_sensor_setting(int update_type, int rt)
-{
-
- int32_t rc = 0, i;
- uint16_t read_data;
- struct msm_camera_csid_params qs_mt9p017_csid_params;
- struct msm_camera_csiphy_params qs_mt9p017_csiphy_params;
- qs_mt9p017_stop_stream();
- msleep(30);
- bridge_i2c_write_w(0x53, 0x00);
- msleep(30);
- if (update_type == REG_INIT) {
- CSI_CONFIG = 0;
- qs_mt9p017_bridge_config(qs_mt9p017_ctrl->cam_mode, rt);
- qs_mt9p017_i2c_write_w_table(qs_mt9p017_regs.rec_settings,
- qs_mt9p017_regs.rec_size);
- if (qs_mt9p017_ctrl->cam_mode == MODE_3D)
- qs_mt9p017_i2c_write_w_table(qs_mt9p017_regs.reg_3d_pll,
- qs_mt9p017_regs.reg_3d_pll_size);
- else
- qs_mt9p017_i2c_write_w_table(qs_mt9p017_regs.reg_pll,
- qs_mt9p017_regs.reg_pll_size);
- qs_mt9p017_i2c_write_w_table(qs_mt9p017_regs.reg_lens,
- qs_mt9p017_regs.reg_lens_size);
- qs_mt9p017_i2c_read(0x31BE, &read_data, 2);
- qs_mt9p017_i2c_write_w_sensor(0x31BE, read_data | 0x4);
- } else if (update_type == UPDATE_PERIODIC) {
- qs_mt9p017_i2c_write_w_table(
- qs_mt9p017_regs.conf_array[rt].conf,
- qs_mt9p017_regs.conf_array[rt].size);
-
- msleep(20);
- bridge_i2c_write_w(0x53, 0x01);
- msleep(30);
- if (!CSI_CONFIG) {
- if (qs_mt9p017_ctrl->cam_mode == MODE_3D) {
- struct msm_camera_csid_vc_cfg
- qs_mt9p017_vccfg[] = {
- {0, CSI_RAW10, CSI_DECODE_10BIT},
- {1, CSI_EMBED_DATA, CSI_DECODE_8BIT},
- };
- qs_mt9p017_csid_params.lane_cnt = 4;
- qs_mt9p017_csiphy_params.lane_cnt = 4;
- qs_mt9p017_csid_params.lut_params.num_cid =
- ARRAY_SIZE(qs_mt9p017_vccfg);
- qs_mt9p017_csid_params.lut_params.vc_cfg =
- &qs_mt9p017_vccfg[0];
- } else {
- struct msm_camera_csid_vc_cfg
- qs_mt9p017_vccfg[] = {
- {0, CSI_RAW10, CSI_DECODE_10BIT},
- {1, CSI_EMBED_DATA, CSI_DECODE_8BIT},
- };
- qs_mt9p017_csid_params.lane_cnt = 2;
- qs_mt9p017_csiphy_params.lane_cnt = 2;
- qs_mt9p017_csid_params.lut_params.num_cid =
- ARRAY_SIZE(qs_mt9p017_vccfg);
- qs_mt9p017_csid_params.lut_params.vc_cfg =
- &qs_mt9p017_vccfg[0];
- }
- qs_mt9p017_csid_params.lane_assign = 0xe4;
- qs_mt9p017_csiphy_params.settle_cnt = 0x18;
- rc = msm_camio_csid_config(&qs_mt9p017_csid_params);
- rc = msm_camio_csiphy_config
- (&qs_mt9p017_csiphy_params);
- v4l2_subdev_notify(qs_mt9p017_ctrl->sensor_dev,
- NOTIFY_CID_CHANGE, NULL);
- msleep(100);
- CSI_CONFIG = 1;
- }
- qs_mt9p017_start_stream();
- msleep(30);
-
- for (i = 0; i < QS_MT9P017_BRIDGE_DBG; i++) {
- bridge_i2c_read(0x10, &read_data, 2);
- CDBG("IRQ Status: 0x%x\n", read_data);
- bridge_i2c_read(0x0A, &read_data, 2);
- CDBG("Skew Value: 0x%x\n", read_data);
- }
- }
- return rc;
-}
-
-static int32_t qs_mt9p017_video_config(int mode)
-{
-
- int32_t rc = 0;
- /* change sensor resolution if needed */
- rc = qs_mt9p017_sensor_setting(UPDATE_PERIODIC,
- qs_mt9p017_ctrl->prev_res);
- if (rc < 0)
- return rc;
-
- qs_mt9p017_ctrl->curr_res = qs_mt9p017_ctrl->prev_res;
- qs_mt9p017_ctrl->sensormode = mode;
- return rc;
-}
-
-static int32_t qs_mt9p017_snapshot_config(int mode)
-{
- int32_t rc = 0;
- /*change sensor resolution if needed */
- if (qs_mt9p017_ctrl->curr_res != qs_mt9p017_ctrl->pict_res) {
- rc = qs_mt9p017_sensor_setting(UPDATE_PERIODIC,
- qs_mt9p017_ctrl->pict_res);
- if (rc < 0)
- return rc;
- }
-
- qs_mt9p017_ctrl->curr_res = qs_mt9p017_ctrl->pict_res;
- qs_mt9p017_ctrl->sensormode = mode;
- return rc;
-} /*end of qs_mt9p017_snapshot_config*/
-
-static int32_t qs_mt9p017_raw_snapshot_config(int mode)
-{
- int32_t rc = 0;
- /* change sensor resolution if needed */
- if (qs_mt9p017_ctrl->curr_res != qs_mt9p017_ctrl->pict_res) {
- rc = qs_mt9p017_sensor_setting(UPDATE_PERIODIC,
- qs_mt9p017_ctrl->pict_res);
- if (rc < 0)
- return rc;
- }
-
- qs_mt9p017_ctrl->curr_res = qs_mt9p017_ctrl->pict_res;
- qs_mt9p017_ctrl->sensormode = mode;
- return rc;
-} /*end of qs_mt9p017_raw_snapshot_config*/
-
-static int32_t qs_mt9p017_mode_init(int mode, struct sensor_init_cfg init_info)
-{
- int32_t rc = 0;
- if (mode == qs_mt9p017_ctrl->cam_mode)
- return rc;
-
- qs_mt9p017_ctrl->prev_res = init_info.prev_res;
- qs_mt9p017_ctrl->pict_res = init_info.pict_res;
- qs_mt9p017_ctrl->cam_mode = mode;
-
- qs_mt9p017_ctrl->prev_frame_length_lines =
- qs_mt9p017_regs.conf_array[qs_mt9p017_ctrl->prev_res].
- conf[QS_MT9P017_FRAME_LENGTH_LINES].wdata;
- qs_mt9p017_ctrl->prev_line_length_pck =
- qs_mt9p017_regs.conf_array[qs_mt9p017_ctrl->prev_res].
- conf[QS_MT9P017_LINE_LENGTH_PCK].wdata;
- qs_mt9p017_ctrl->snap_frame_length_lines =
- qs_mt9p017_regs.conf_array[qs_mt9p017_ctrl->pict_res].
- conf[QS_MT9P017_FRAME_LENGTH_LINES].wdata;
- qs_mt9p017_ctrl->snap_line_length_pck =
- qs_mt9p017_regs.conf_array[qs_mt9p017_ctrl->pict_res].
- conf[QS_MT9P017_LINE_LENGTH_PCK].wdata;
-
- if (mode == MODE_2D_LEFT)
- qs_mt9p017_load_left_lsc();
- else if (mode == MODE_2D_RIGHT)
- qs_mt9p017_load_right_lsc();
- else
- qs_mt9p017_load_lsc();
-
- rc = qs_mt9p017_sensor_setting(REG_INIT,
- qs_mt9p017_ctrl->prev_res);
- return rc;
-}
-
-static int32_t qs_mt9p017_set_sensor_mode(int mode, int res)
-{
- int32_t rc = 0;
-
- switch (mode) {
- case SENSOR_PREVIEW_MODE:
- qs_mt9p017_ctrl->prev_res = res;
- rc = qs_mt9p017_video_config(mode);
- break;
- case SENSOR_SNAPSHOT_MODE:
- qs_mt9p017_ctrl->pict_res = res;
- rc = qs_mt9p017_snapshot_config(mode);
- break;
- case SENSOR_RAW_SNAPSHOT_MODE:
- qs_mt9p017_ctrl->pict_res = res;
- rc = qs_mt9p017_raw_snapshot_config(mode);
- break;
- default:
- rc = -EINVAL;
- break;
- }
- return rc;
-}
-
-static int32_t qs_mt9p017_check_id(void){
- int rc;
- uint16_t chipid = 0x0;
-
- rc = qs_mt9p017_i2c_read(0x0000, &chipid, 2);
- if (rc < 0)
- return rc;
-
- CDBG(KERN_ERR "qs_mt9p017 model_id = 0x%x\n", chipid);
- if (chipid != 0x4800) {
- rc = -ENODEV;
- CDBG("qs_mt9p017 fail chip id doesnot match\n");
- }
- return rc;
-}
-
-static int32_t qs_mt9p017_power_up(const struct msm_camera_sensor_info *data)
-{
- int32_t rc = 0;
- rc = gpio_request(data->sensor_platform_info->sensor_reset,
- "qs_mt9p017");
- CDBG("%s\n", __func__);
- if (!rc) {
- CDBG("sensor_reset = %d\n", rc);
- gpio_direction_output(data->sensor_platform_info->sensor_reset
- , 0);
- msleep(50);
- gpio_set_value_cansleep(data->sensor_platform_info->
- sensor_reset, 1);
- msleep(20);
- } else {
- CDBG("sensor reset fail");
- }
- qs_mt9p017_bridge_reset();
- qs_mt9p017_bridge_config(MODE_3D, RES_PREVIEW);
- msleep(30);
- return rc;
-}
-
-static int32_t qs_mt9p017_power_down(const struct msm_camera_sensor_info *data)
-{
- gpio_set_value_cansleep(data->sensor_platform_info->sensor_reset, 0);
- gpio_free(data->sensor_platform_info->sensor_reset);
- return 0;
-}
-
-static int qs_mt9p017_sensor_open_init
- (const struct msm_camera_sensor_info *data)
-{
- int32_t rc = 0;
- CDBG("%s: %d\n", __func__, __LINE__);
- qs_mt9p017_ctrl->fps_divider = 1 * 0x00000400;
- qs_mt9p017_ctrl->pict_fps_divider = 1 * 0x00000400;
- qs_mt9p017_ctrl->cam_mode = MODE_INVALID;
- qs_mt9p017_ctrl->fps = 30*Q8;
-
- if (data)
- qs_mt9p017_ctrl->sensordata = data;
-
- msm_camio_clk_rate_set(QS_MT9P017_MASTER_CLK_RATE);
- msleep(20);
-
- rc = qs_mt9p017_power_up(data);
- if (rc < 0) {
- CDBG("Calling qs_mt9p017_sensor_open_init fail\n");
- return rc;
- }
-
- qs_mt9p017_init_focus();
- return rc;
-}
-
-static const struct i2c_device_id qs_mt9p017_i2c_id[] = {
- {"qs_mt9p017", 0},
- { }
-};
-
-static int qs_mt9p017_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- int rc = 0;
- CDBG("qs_mt9p017_probe called!\n");
-
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
- CDBG("i2c_check_functionality failed\n");
- rc = -1;
- goto probe_failure;
- }
-
- qs_mt9p017_client = client;
- CDBG("qs_mt9p017_probe successed! rc = %d\n", rc);
- return rc;
-
-probe_failure:
- CDBG("qs_mt9p017_probe failed! rc = %d\n", rc);
- return rc;
-}
-
-static int __exit qs_mt9p017_i2c_remove(struct i2c_client *client)
-{
- qs_mt9p017_client = NULL;
- return 0;
-}
-
-static struct i2c_driver qs_mt9p017_i2c_driver = {
- .id_table = qs_mt9p017_i2c_id,
- .probe = qs_mt9p017_i2c_probe,
- .remove = __exit_p(qs_mt9p017_i2c_remove),
- .driver = {
- .name = "qs_mt9p017",
- },
-};
-
-static int qs_mt9p017_3D_sensor_config(void __user *argp)
-{
- struct sensor_large_data cdata;
- int rc;
- if (copy_from_user(&cdata,
- (void *)argp,
- sizeof(struct sensor_large_data)))
- return -EFAULT;
- mutex_lock(&qs_mt9p017_mut);
- rc = qs_mt9p017_get_calibration_data
- (&cdata.data.sensor_3d_cali_data);
- if (copy_to_user((void *)argp,
- &cdata,
- sizeof(struct sensor_large_data)))
- rc = -EFAULT;
- mutex_unlock(&qs_mt9p017_mut);
- return rc;
-}
-
-static int qs_mt9p017_2D_sensor_config(void __user *argp)
-{
- struct sensor_cfg_data cdata;
- long rc = 0;
- if (copy_from_user(&cdata,
- (void *)argp,
- sizeof(struct sensor_cfg_data)))
- return -EFAULT;
- mutex_lock(&qs_mt9p017_mut);
- CDBG("qs_mt9p017_sensor_config: cfgtype = %d\n",
- cdata.cfgtype);
- switch (cdata.cfgtype) {
- case CFG_GET_PICT_FPS:
- qs_mt9p017_get_pict_fps(
- cdata.cfg.gfps.prevfps,
- &(cdata.cfg.gfps.pictfps));
-
- if (copy_to_user((void *)argp,
- &cdata,
- sizeof(struct sensor_cfg_data)))
- rc = -EFAULT;
- break;
-
- case CFG_GET_PREV_L_PF:
- cdata.cfg.prevl_pf =
- qs_mt9p017_ctrl->prev_frame_length_lines;
-
- if (copy_to_user((void *)argp,
- &cdata,
- sizeof(struct sensor_cfg_data)))
- rc = -EFAULT;
- break;
-
- case CFG_GET_PREV_P_PL:
- cdata.cfg.prevp_pl =
- qs_mt9p017_ctrl->prev_line_length_pck;
-
- if (copy_to_user((void *)argp,
- &cdata,
- sizeof(struct sensor_cfg_data)))
- rc = -EFAULT;
- break;
-
- case CFG_GET_PICT_L_PF:
- cdata.cfg.pictl_pf =
- qs_mt9p017_ctrl->snap_frame_length_lines;
-
- if (copy_to_user((void *)argp,
- &cdata,
- sizeof(struct sensor_cfg_data)))
- rc = -EFAULT;
- break;
-
- case CFG_GET_PICT_P_PL:
- cdata.cfg.pictp_pl =
- qs_mt9p017_ctrl->snap_line_length_pck;
-
- if (copy_to_user((void *)argp,
- &cdata,
- sizeof(struct sensor_cfg_data)))
- rc = -EFAULT;
- break;
-
- case CFG_GET_PICT_MAX_EXP_LC:
- cdata.cfg.pict_max_exp_lc =
- qs_mt9p017_ctrl->snap_frame_length_lines * 24;
-
- if (copy_to_user((void *)argp,
- &cdata,
- sizeof(struct sensor_cfg_data)))
- rc = -EFAULT;
- break;
-
- case CFG_SET_FPS:
- case CFG_SET_PICT_FPS:
- rc = qs_mt9p017_set_fps(&(cdata.cfg.fps));
- break;
-
- case CFG_SET_EXP_GAIN:
- rc =
- qs_mt9p017_write_exp_gain(
- cdata.cfg.sensor_3d_exp);
- break;
-
- case CFG_SET_PICT_EXP_GAIN:
- rc =
- qs_mt9p017_set_pict_exp_gain(
- cdata.cfg.sensor_3d_exp);
- break;
-
- case CFG_SET_MODE:
- rc = qs_mt9p017_set_sensor_mode(cdata.mode,
- cdata.rs);
- break;
-
- case CFG_PWR_DOWN:
- rc = qs_mt9p017_power_down(qs_mt9p017_ctrl->sensordata);
- break;
-
- case CFG_MOVE_FOCUS:
- rc =
- qs_mt9p017_move_focus(
- cdata.cfg.focus.dir,
- cdata.cfg.focus.steps);
- break;
-
- case CFG_SET_DEFAULT_FOCUS:
- rc =
- qs_mt9p017_set_default_focus(
- cdata.cfg.focus.steps);
- break;
-
- case CFG_GET_AF_MAX_STEPS:
- cdata.max_steps = QS_MT9P017_TOTAL_STEPS_NEAR_TO_FAR;
- if (copy_to_user((void *)argp,
- &cdata,
- sizeof(struct sensor_cfg_data)))
- rc = -EFAULT;
- break;
-
- case CFG_SET_EFFECT:
- rc = qs_mt9p017_set_default_focus(
- cdata.cfg.effect);
- break;
-
- case CFG_SENSOR_INIT:
- rc = qs_mt9p017_mode_init(cdata.mode,
- cdata.cfg.init_info);
- break;
-
- default:
- rc = -EFAULT;
- break;
- }
-
- mutex_unlock(&qs_mt9p017_mut);
-
- return rc;
-}
-
-static int qs_mt9p017_sensor_config(void __user *argp)
-{
- int cfgtype;
- if (copy_from_user(&cfgtype,
- (void *)argp,
- sizeof(int)))
- return -EFAULT;
- if (cfgtype != CFG_GET_3D_CALI_DATA)
- qs_mt9p017_2D_sensor_config(argp);
- else
- qs_mt9p017_3D_sensor_config(argp);
- return 0;
-}
-
-static int qs_mt9p017_sensor_release(void)
-{
- int rc = -EBADF;
- mutex_lock(&qs_mt9p017_mut);
- qs_mt9p017_power_down(qs_mt9p017_ctrl->sensordata);
- mutex_unlock(&qs_mt9p017_mut);
- return rc;
-}
-
-static int qs_mt9p017_sensor_probe(const struct msm_camera_sensor_info *info,
- struct msm_sensor_ctrl *s)
-{
- int rc = 0;
- rc = i2c_add_driver(&qs_mt9p017_i2c_driver);
- if (rc < 0 || qs_mt9p017_client == NULL) {
- rc = -ENOTSUPP;
- CDBG("I2C add driver failed");
- goto i2c_probe_fail;
- }
- msm_camio_clk_rate_set(QS_MT9P017_MASTER_CLK_RATE);
- rc = qs_mt9p017_power_up(info);
- if (rc < 0)
- goto gpio_request_fail;
-
- rc = qs_mt9p017_check_id();
- if (rc < 0) {
- qs_mt9p017_power_down(info);
- goto i2c_probe_fail;
- }
- s->s_init = qs_mt9p017_sensor_open_init;
- s->s_release = qs_mt9p017_sensor_release;
- s->s_config = qs_mt9p017_sensor_config;
- s->s_mount_angle = 270;
- s->s_camera_type = info->camera_type;
- qs_mt9p017_power_down(info);
- return rc;
-
-gpio_request_fail:
- pr_err("%s: gpio request fail\n", __func__);
-i2c_probe_fail:
- CDBG("qs_mt9p017_sensor_probe: probe failed!\n");
- i2c_del_driver(&qs_mt9p017_i2c_driver);
- return rc;
-}
-
-static struct qs_mt9p017_format qs_mt9p017_subdev_info[] = {
- {
- .code = V4L2_MBUS_FMT_YUYV8_2X8,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .fmt = 1,
- .order = 0,
- },
-};
-
-static int qs_mt9p017_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
-{
- CDBG(KERN_DEBUG "Index is %d\n", index);
- if (index >= ARRAY_SIZE(qs_mt9p017_subdev_info))
- return -EINVAL;
-
- *code = qs_mt9p017_subdev_info[index].code;
- return 0;
-}
-
-static struct v4l2_subdev_core_ops qs_mt9p017_subdev_core_ops;
-static struct v4l2_subdev_video_ops qs_mt9p017_subdev_video_ops = {
- .enum_mbus_fmt = qs_mt9p017_enum_fmt,
-};
-
-static struct v4l2_subdev_ops qs_mt9p017_subdev_ops = {
- .core = &qs_mt9p017_subdev_core_ops,
- .video = &qs_mt9p017_subdev_video_ops,
-};
-
-
-static int qs_mt9p017_sensor_probe_cb(const struct msm_camera_sensor_info *info,
- struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s)
-{
- int rc = 0;
- qs_mt9p017_ctrl = kzalloc(sizeof(struct qs_mt9p017_ctrl_t), GFP_KERNEL);
- if (!qs_mt9p017_ctrl) {
- CDBG("qs_mt9p017_sensor_probe failed!\n");
- return -ENOMEM;
- }
-
- rc = qs_mt9p017_sensor_probe(info, s);
- if (rc < 0) {
- kfree(qs_mt9p017_ctrl);
- return rc;
- }
-
- /* probe is successful, init a v4l2 subdevice */
- CDBG(KERN_DEBUG "going into v4l2_i2c_subdev_init\n");
- if (sdev) {
- v4l2_i2c_subdev_init(sdev, qs_mt9p017_client,
- &qs_mt9p017_subdev_ops);
- qs_mt9p017_ctrl->sensor_dev = sdev;
- }
- return rc;
-}
-
-static int __qs_mt9p017_probe(struct platform_device *pdev)
-{
- return msm_sensor_register(pdev, qs_mt9p017_sensor_probe_cb);
-}
-
-static struct platform_driver msm_camera_driver = {
- .probe = __qs_mt9p017_probe,
- .driver = {
- .name = "msm_camera_qs_mt9p017",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init qs_mt9p017_init(void)
-{
- return platform_driver_register(&msm_camera_driver);
-}
-
-static void __exit qs_mt9p017_exit(void)
-{
- platform_driver_unregister(&msm_camera_driver);
-}
-module_init(qs_mt9p017_init);
-module_exit(qs_mt9p017_exit);
-MODULE_DESCRIPTION("Aptina 8 MP Bayer sensor driver");
-MODULE_LICENSE("GPL v2");
-
diff --git a/drivers/media/video/msm/qs_mt9p017.h b/drivers/media/video/msm/qs_mt9p017.h
deleted file mode 100644
index 8ac1cc1..0000000
--- a/drivers/media/video/msm/qs_mt9p017.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * 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 QS_MT9P017_H
-#define QS_MT9P017_H
-#include <linux/types.h>
-#include <linux/kernel.h>
-extern struct qs_mt9p017_reg qs_mt9p017_regs;
-
-struct qs_mt9p017_i2c_reg_conf {
- unsigned short waddr;
- unsigned short wdata;
-};
-
-struct qs_mt9p017_i2c_conf_array {
- struct qs_mt9p017_i2c_reg_conf *conf;
- unsigned short size;
-};
-
-struct qs_mt9p017_i2c_read_t {
- unsigned short raddr;
- unsigned short *rdata;
- int rlen;
-};
-
-struct qs_mt9p017_i2c_read_seq_t {
- unsigned short raddr;
- unsigned char *rdata;
- int rlen;
-};
-
-enum qs_mt9p017_test_mode_t {
- TEST_OFF,
- TEST_1,
- TEST_2,
- TEST_3
-};
-
-enum qs_mt9p017_resolution_t {
- QTR_2D_SIZE,
- FULL_2D_SIZE,
- QTR_3D_SIZE,
- FULL_3D_SIZE,
- INVALID_SIZE
-};
-enum qs_mt9p017_setting {
- RES_PREVIEW,
- RES_CAPTURE,
- RES_3D_PREVIEW,
- RES_3D_CAPTURE
-};
-enum qs_mt9p017_cam_mode_t {
- MODE_2D_RIGHT,
- MODE_2D_LEFT,
- MODE_3D,
- MODE_INVALID
-};
-enum qs_mt9p017_reg_update {
- /* Sensor egisters that need to be updated during initialization */
- REG_INIT,
- /* Sensor egisters that needs periodic I2C writes */
- UPDATE_PERIODIC,
- /* All the sensor Registers will be updated */
- UPDATE_ALL,
- /* Not valid update */
- UPDATE_INVALID
-};
-
-enum qs_mt9p017_reg_mode {
- QS_MT9P017_LINE_LENGTH_PCK = 7,
- QS_MT9P017_FRAME_LENGTH_LINES,
-};
-
-struct qs_mt9p017_reg {
- const struct qs_mt9p017_i2c_reg_conf *rec_settings;
- const unsigned short rec_size;
- const struct qs_mt9p017_i2c_reg_conf *reg_pll;
- const unsigned short reg_pll_size;
- const struct qs_mt9p017_i2c_reg_conf *reg_3d_pll;
- const unsigned short reg_3d_pll_size;
- const struct qs_mt9p017_i2c_reg_conf *reg_lens;
- const unsigned short reg_lens_size;
- const struct qs_mt9p017_i2c_conf_array *conf_array;
-};
-#endif /* QS_MT9P017_H */
diff --git a/drivers/media/video/msm/qs_mt9p017_reg.c b/drivers/media/video/msm/qs_mt9p017_reg.c
deleted file mode 100644
index 04715a2..0000000
--- a/drivers/media/video/msm/qs_mt9p017_reg.c
+++ /dev/null
@@ -1,352 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * 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 "qs_mt9p017.h"
-
-struct qs_mt9p017_i2c_reg_conf qs_mt9p017_pll_settings[] = {
- {0x301A, 0x0018},/*reset_register*/
- {0x3064, 0x7800},/*smia_test_2lane_mipi*/
- {0x31AE, 0x0202},/*dual_lane_MIPI_interface*/
- {0x0300, 0x0005},/*vt_pix_clk_div*/
- {0x0302, 0x0001},/*vt_sys_clk_div*/
- {0x0304, 0x0002},/*pre_pll_clk_div*/
- {0x0306, 0x002C},/*pll_multipler*/
- {0x0308, 0x000A},/*op_pix_clk_div*/
- {0x030A, 0x0001} /*op_sys_clk_div*/
-};
-
-struct qs_mt9p017_i2c_reg_conf qs_mt9p017_3d_pll_settings[] = {
- {0x301A, 0x0018},/*reset_register*/
- {0x3064, 0x7800},/*smia_test_2lane_mipi*/
- {0x31AE, 0x0202},/*dual_lane_MIPI_interface*/
- {0x0300, 0x0005},/*vt_pix_clk_div*/
- {0x0302, 0x0001},/*vt_sys_clk_div*/
- {0x0304, 0x0002},/*pre_pll_clk_div*/
- {0x0306, 0x0018},/*pll_multipler*/
- {0x0308, 0x000A},/*op_pix_clk_div*/
- {0x030A, 0x0001},/*op_sys_clk_div*/
-};
-
-struct qs_mt9p017_i2c_reg_conf qs_mt9p017_recommend_settings[] = {
- {0x316A, 0x8200},
- {0x3ED2, 0xD965},
- {0x3ED8, 0x7F1B},
- {0x3EDA, 0xAF11},
- {0x3EDE, 0xCA00},
- {0x3EE2, 0x0068},
- {0x3EF2, 0xD965},
- {0x3EF8, 0x797F},
- {0x3EFC, 0xAFEF},
- {0x3EFE, 0x1308},
- {0x31E0, 0x1F01},
- {0x3e00, 0x0429},/*[REV3_pixel_timing]*/
- {0x3e02, 0xFFFF},
- {0x3e04, 0xFFFF},
- {0x3e06, 0xFFFF},
- {0x3e08, 0x8080},
- {0x3e0a, 0x7180},
- {0x3e0c, 0x7200},
- {0x3e0e, 0x4353},
- {0x3e10, 0x1300},
- {0x3e12, 0x8710},
- {0x3e14, 0x6085},
- {0x3e16, 0x40A2},
- {0x3e18, 0x0018},
- {0x3e1a, 0x9057},
- {0x3e1c, 0xA049},
- {0x3e1e, 0xA649},
- {0x3e20, 0x8846},
- {0x3e22, 0x8142},
- {0x3e24, 0x0082},
- {0x3e26, 0x8B49},
- {0x3e28, 0x9C49},
- {0x3e2a, 0x8E47},
- {0x3e2c, 0x884D},
- {0x3e2e, 0x8010},
- {0x3e30, 0x0C04},
- {0x3e32, 0x0691},
- {0x3e34, 0x100C},
- {0x3e36, 0x8C4D},
- {0x3e38, 0xB94A},
- {0x3e3a, 0x4283},
- {0x3e3c, 0x4181},
- {0x3e3e, 0x4BB2},
- {0x3e40, 0x4B80},
- {0x3e42, 0x5680},
- {0x3e44, 0x001C},
- {0x3e46, 0x8110},
- {0x3e48, 0xE080},
- {0x3e4a, 0x1300},
- {0x3e4c, 0x1C00},
- {0x3e4e, 0x827C},
- {0x3e50, 0x0970},
- {0x3e52, 0x8082},
- {0x3e54, 0x7281},
- {0x3e56, 0x4C40},
- {0x3e58, 0x8E4D},
- {0x3e5a, 0x8110},
- {0x3e5c, 0x0CAF},
- {0x3e5e, 0x4D80},
- {0x3e60, 0x100C},
- {0x3e62, 0x8440},
- {0x3e64, 0x4C81},
- {0x3e66, 0x7C53},
- {0x3e68, 0x7000},
- {0x3e6a, 0x0000},
- {0x3e6c, 0x0000},
- {0x3e6e, 0x0000},
- {0x3e70, 0x0000},
- {0x3e72, 0x0000},
- {0x3e74, 0x0000},
- {0x3e76, 0x0000},
- {0x3e78, 0x7000},
- {0x3e7a, 0x0000},
- {0x3e7c, 0x0000},
- {0x3e7e, 0x0000},
- {0x3e80, 0x0000},
- {0x3e82, 0x0000},
- {0x3e84, 0x0000},
- {0x3e86, 0x0000},
- {0x3e88, 0x0000},
- {0x3e8a, 0x0000},
- {0x3e8c, 0x0000},
- {0x3e8e, 0x0000},
- {0x3e90, 0x0000},
- {0x3e92, 0x0000},
- {0x3e94, 0x0000},
- {0x3e96, 0x0000},
- {0x3e98, 0x0000},
- {0x3e9a, 0x0000},
- {0x3e9c, 0x0000},
- {0x3e9e, 0x0000},
- {0x3ea0, 0x0000},
- {0x3ea2, 0x0000},
- {0x3ea4, 0x0000},
- {0x3ea6, 0x0000},
- {0x3ea8, 0x0000},
- {0x3eaa, 0x0000},
- {0x3eac, 0x0000},
- {0x3eae, 0x0000},
- {0x3eb0, 0x0000},
- {0x3eb2, 0x0000},
- {0x3eb4, 0x0000},
- {0x3eb6, 0x0000},
- {0x3eb8, 0x0000},
- {0x3eba, 0x0000},
- {0x3ebc, 0x0000},
- {0x3ebe, 0x0000},
- {0x3ec0, 0x0000},
- {0x3ec2, 0x0000},
- {0x3ec4, 0x0000},
- {0x3ec6, 0x0000},
- {0x3ec8, 0x0000},
- {0x3eca, 0x0000},
- {0x3ec0, 0x0000},
- {0x3ec2, 0x0000},
- {0x3ec4, 0x0000},
- {0x3ec6, 0x0000},
- {0x3ec8, 0x0000},
- {0x3eca, 0x0000}
-
-};
-
-struct qs_mt9p017_i2c_reg_conf qs_mt9p017_prev_settings[] = {
- {0x3004, 0x0008},/*x_addr_start*/
- {0x3008, 0x0A25},/*x_addr_end*/
- {0x3002, 0x0008},/*y_start_addr*/
- {0x3006, 0x079D},/*y_addr_end*/
- {0x3040, 0x04C3},/*read_mode*/
- {0x034C, 0x0510},/*x_output_size*/
- {0x034E, 0x03CC},/*y_output_size*/
- {0x300C, 0x0D66},/*line_length_pck*/
- {0x300A, 0x0415},/*frame_length_lines*/
- {0x3012, 0x0414},/*coarse_integration_time*/
- {0x3014, 0x0A22},/*fine_integration_time*/
- {0x3010, 0x0184} /*fine_correction*/
-};
-
-struct qs_mt9p017_i2c_reg_conf qs_mt9p017_snap_settings[] = {
- {0x3004, 0x0000},/*x_addr_start*/
- {0x3008, 0x0A2F},/*x_addr_end*/
- {0x3002, 0x0000},/*y_start_addr*/
- {0x3006, 0x07A7},/*y_addr_end*/
- {0x3040, 0x0041},/*read_mode*/
- {0x034C, 0x0A30},/*x_output_size*/
- {0x034E, 0x07A8},/*y_output_size*/
- {0x300C, 0x0E7E},/*line_length_pck*/
- {0x300A, 0x07F5},/*frame_length_lines*/
- {0x3012, 0x07F4},/*coarse_integration_time*/
- {0x3014, 0x0C9C},/*fine_integration_time*/
- {0x3010, 0x00A0},/*fine_correction*/
-};
-
-struct qs_mt9p017_i2c_reg_conf qs_mt9p017_3d_prev_settings[] = {
- {0x3004, 0x0008},/*x_addr_start*/
- {0x3008, 0x0785},/*x_addr_end*/
- {0x3002, 0x0008},/*y_start_addr*/
- {0x3006, 0x043F},/*y_addr_end*/
- {0x3040, 0x00C1},/*read_mode*/
- {0x034C, 0x03C0},/*x_output_size*/
- {0x034E, 0x0438},/*y_output_size*/
- {0x300C, 0x0BCE},/*line_length_pck*/
- {0x300A, 0x04A6},/*frame_length_lines*/
- {0x3012, 0x04A5},/*coarse_integration_time*/
- {0x3014, 0x062C},/*fine_integration_time*/
- {0x3010, 0x00A0} /*fine_correction*/
-};
-
-struct qs_mt9p017_i2c_reg_conf qs_mt9p017_3d_snap_settings[] = {
- {0x3004, 0x0008},/*x_addr_start*/
- {0x3008, 0x0787},/*x_addr_end*/
- {0x3002, 0x0008},/*y_start_addr*/
- {0x3006, 0x043F},/*y_addr_end*/
- {0x3040, 0x0041},/*read_mode*/
- {0x034C, 0x0780},/*x_output_size*/
- {0x034E, 0x0438},/*y_output_size*/
- {0x300C, 0x0BCE},/*line_length_pck*/
- {0x300A, 0x04A6},/*frame_length_lines*/
- {0x3012, 0x04A5},/*coarse_integration_time*/
- {0x3014, 0x09EC},/*fine_integration_time*/
- {0x3010, 0x00A0} /*fine_correction*/
-};
-
-struct qs_mt9p017_i2c_reg_conf qs_mt9p017_lens_settings[] = {
- {0x3600, 0x0650},
- {0x3602, 0x564D},
- {0x3604, 0x6730},
- {0x3606, 0x49CC},
- {0x3608, 0xC790},
- {0x360A, 0x0350},
- {0x360C, 0xF7ED},
- {0x360E, 0x5970},
- {0x3610, 0x378F},
- {0x3612, 0xDCD0},
- {0x3614, 0x0290},
- {0x3616, 0x4C2D},
- {0x3618, 0x35AF},
- {0x361A, 0xA5ED},
- {0x361C, 0xC1CE},
- {0x361E, 0x0310},
- {0x3620, 0x83EE},
- {0x3622, 0x79B0},
- {0x3624, 0x0F2F},
- {0x3626, 0xEEF0},
- {0x3640, 0x86AD},
- {0x3642, 0xAE8D},
- {0x3644, 0x9D4E},
- {0x3646, 0x782B},
- {0x3648, 0x216F},
- {0x364A, 0xAC6C},
- {0x364C, 0x33CD},
- {0x364E, 0x922C},
- {0x3650, 0xA12D},
- {0x3652, 0x3DCB},
- {0x3654, 0x506C},
- {0x3656, 0x306D},
- {0x3658, 0x934B},
- {0x365A, 0xC5CD},
- {0x365C, 0x6568},
- {0x365E, 0x0CEC},
- {0x3660, 0xEE8D},
- {0x3662, 0x0A8E},
- {0x3664, 0x104E},
- {0x3666, 0xECCE},
- {0x3680, 0x0FF1},
- {0x3682, 0x1B8F},
- {0x3684, 0x92D3},
- {0x3686, 0x8910},
- {0x3688, 0x1FF4},
- {0x368A, 0x1BD1},
- {0x368C, 0x5A0D},
- {0x368E, 0x89B3},
- {0x3690, 0xFF10},
- {0x3692, 0x1994},
- {0x3694, 0x2DD0},
- {0x3696, 0x796C},
- {0x3698, 0xC912},
- {0x369A, 0x194F},
- {0x369C, 0x7633},
- {0x369E, 0x06B1},
- {0x36A0, 0x018E},
- {0x36A2, 0x8F13},
- {0x36A4, 0xF110},
- {0x36A6, 0x2014},
- {0x36C0, 0xA089},
- {0x36C2, 0x44AD},
- {0x36C4, 0x3C4B},
- {0x36C6, 0x658C},
- {0x36C8, 0xDF10},
- {0x36CA, 0x2D2E},
- {0x36CC, 0xAC8A},
- {0x36CE, 0xD450},
- {0x36D0, 0x742E},
- {0x36D2, 0x4E4F},
- {0x36D4, 0xE86D},
- {0x36D6, 0xE1AD},
- {0x36D8, 0x6CAF},
- {0x36DA, 0x2D8F},
- {0x36DC, 0x9B71},
- {0x36DE, 0x9C8D},
- {0x36E0, 0x55CE},
- {0x36E2, 0xC28F},
- {0x36E4, 0xED4F},
- {0x36E6, 0x23F0},
- {0x3700, 0xECF1},
- {0x3702, 0x9130},
- {0x3704, 0x31F4},
- {0x3706, 0xED2F},
- {0x3708, 0xB8B4},
- {0x370A, 0xE4D1},
- {0x370C, 0x220B},
- {0x370E, 0x2394},
- {0x3710, 0xEED1},
- {0x3712, 0xD4B3},
- {0x3714, 0x9431},
- {0x3716, 0x428E},
- {0x3718, 0x1894},
- {0x371A, 0xBCF2},
- {0x371C, 0x9C94},
- {0x371E, 0xD271},
- {0x3720, 0xE56B},
- {0x3722, 0x1E54},
- {0x3724, 0xEA10},
- {0x3726, 0x8EF4},
- {0x3782, 0x04A4},
- {0x3784, 0x03B4},
- {0x37C0, 0x0000},
- {0x37C2, 0x0000},
- {0x37C4, 0x0000},
- {0x37C6, 0x0000},
- {0x3780, 0x8000}
-};
-
-struct qs_mt9p017_i2c_conf_array qs_mt9p017_confs[] = {
- {&qs_mt9p017_prev_settings[0], ARRAY_SIZE(qs_mt9p017_prev_settings)},
- {&qs_mt9p017_snap_settings[0], ARRAY_SIZE(qs_mt9p017_snap_settings)},
- {&qs_mt9p017_3d_prev_settings[0],
- ARRAY_SIZE(qs_mt9p017_3d_prev_settings)},
- {&qs_mt9p017_3d_snap_settings[0],
- ARRAY_SIZE(qs_mt9p017_3d_snap_settings)},
-};
-
-struct qs_mt9p017_reg qs_mt9p017_regs = {
- .rec_settings = &qs_mt9p017_recommend_settings[0],
- .rec_size = ARRAY_SIZE(qs_mt9p017_recommend_settings),
- .reg_pll = &qs_mt9p017_pll_settings[0],
- .reg_pll_size = ARRAY_SIZE(qs_mt9p017_pll_settings),
- .reg_3d_pll = &qs_mt9p017_3d_pll_settings[0],
- .reg_3d_pll_size = ARRAY_SIZE(qs_mt9p017_3d_pll_settings),
- .reg_lens = &qs_mt9p017_lens_settings[0],
- .reg_lens_size = ARRAY_SIZE(qs_mt9p017_lens_settings),
- .conf_array = &qs_mt9p017_confs[0],
-};
diff --git a/drivers/media/video/msm/sensors/imx074_v4l2.c b/drivers/media/video/msm/sensors/imx074_v4l2.c
index 99cc2d4..f721441 100644
--- a/drivers/media/video/msm/sensors/imx074_v4l2.c
+++ b/drivers/media/video/msm/sensors/imx074_v4l2.c
@@ -51,8 +51,8 @@
{0x0383, 0x03}, /*x_odd_inc*/
{0x0385, 0x01}, /*y_even_inc*/
{0x0387, 0x03}, /*y_odd_inc*/
- {0x3001, 0x00}, /*hmodeadd*/
- {0x3016, 0x06}, /*vmodeadd*/
+ {0x3001, 0x80}, /*hmodeadd*/
+ {0x3016, 0x16}, /*vmodeadd*/
{0x3069, 0x24}, /*vapplinepos_start*/
{0x306b, 0x53}, /*vapplinepos_end*/
{0x3086, 0x00}, /*shutter*/
@@ -164,7 +164,7 @@
.frame_length_lines = 0x62D,
.vt_pixel_clk = 216000000,
.op_pixel_clk = 216000000,
- .binning_factor = 1,
+ .binning_factor = 2,
},
};
@@ -315,12 +315,6 @@
.sensor_stop_stream = msm_sensor_stop_stream,
.sensor_group_hold_on = msm_sensor_group_hold_on,
.sensor_group_hold_off = msm_sensor_group_hold_off,
- .sensor_get_prev_lines_pf = msm_sensor_get_prev_lines_pf,
- .sensor_get_prev_pixels_pl = msm_sensor_get_prev_pixels_pl,
- .sensor_get_pict_lines_pf = msm_sensor_get_pict_lines_pf,
- .sensor_get_pict_pixels_pl = msm_sensor_get_pict_pixels_pl,
- .sensor_get_pict_max_exp_lc = msm_sensor_get_pict_max_exp_lc,
- .sensor_get_pict_fps = msm_sensor_get_pict_fps,
.sensor_set_fps = msm_sensor_set_fps,
.sensor_write_exp_gain = msm_sensor_write_exp_gain1,
.sensor_write_snapshot_exp_gain = msm_sensor_write_exp_gain1,
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index 76ade6c..7eb3160 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -100,54 +100,6 @@
s_ctrl->msm_sensor_reg->default_data_type);
}
-uint16_t msm_sensor_get_prev_lines_pf(struct msm_sensor_ctrl_t *s_ctrl)
-{
- return s_ctrl->msm_sensor_reg->
- output_settings[s_ctrl->prev_res].frame_length_lines;
-}
-
-uint16_t msm_sensor_get_prev_pixels_pl(struct msm_sensor_ctrl_t *s_ctrl)
-{
- return s_ctrl->msm_sensor_reg->
- output_settings[s_ctrl->prev_res].line_length_pclk;
-}
-
-uint16_t msm_sensor_get_pict_lines_pf(struct msm_sensor_ctrl_t *s_ctrl)
-{
- return s_ctrl->msm_sensor_reg->
- output_settings[s_ctrl->pict_res].frame_length_lines;
-}
-
-uint16_t msm_sensor_get_pict_pixels_pl(struct msm_sensor_ctrl_t *s_ctrl)
-{
- return s_ctrl->msm_sensor_reg->
- output_settings[s_ctrl->pict_res].line_length_pclk;
-}
-
-uint32_t msm_sensor_get_pict_max_exp_lc(struct msm_sensor_ctrl_t *s_ctrl)
-{
- return s_ctrl->msm_sensor_reg->
- output_settings[s_ctrl->prev_res].frame_length_lines * 24;
-}
-
-void msm_sensor_get_pict_fps(struct msm_sensor_ctrl_t *s_ctrl,
- uint16_t fps, uint16_t *pfps)
-{
- uint32_t divider, d1, d2;
- d1 = s_ctrl->msm_sensor_reg->
- output_settings[s_ctrl->prev_res].frame_length_lines * Q10 /
- s_ctrl->msm_sensor_reg->
- output_settings[s_ctrl->pict_res].frame_length_lines;
-
- d2 = s_ctrl->msm_sensor_reg->
- output_settings[s_ctrl->prev_res].line_length_pclk * Q10 /
- s_ctrl->msm_sensor_reg->
- output_settings[s_ctrl->pict_res].line_length_pclk;
-
- divider = d1 * d2 / Q10;
- *pfps = (uint16_t) (fps * divider / Q10);
-}
-
int32_t msm_sensor_set_fps(struct msm_sensor_ctrl_t *s_ctrl,
struct fps_cfg *fps)
{
@@ -268,15 +220,6 @@
{
int32_t rc = 0;
if (s_ctrl->curr_res != res) {
- switch (mode) {
- case SENSOR_PREVIEW_MODE:
- s_ctrl->prev_res = res;
- break;
- case SENSOR_SNAPSHOT_MODE:
- case SENSOR_RAW_SNAPSHOT_MODE:
- s_ctrl->pict_res = res;
- break;
- }
s_ctrl->curr_frame_length_lines =
s_ctrl->msm_sensor_reg->
output_settings[res].frame_length_lines;
@@ -298,27 +241,16 @@
int mode, struct sensor_init_cfg *init_info)
{
int32_t rc = 0;
- s_ctrl->fps = 30*Q8;
s_ctrl->fps_divider = Q10;
s_ctrl->cam_mode = MSM_SENSOR_MODE_INVALID;
CDBG("%s: %d\n", __func__, __LINE__);
if (mode != s_ctrl->cam_mode) {
- if (init_info->prev_res >=
- s_ctrl->msm_sensor_reg->num_conf ||
- init_info->pict_res >=
- s_ctrl->msm_sensor_reg->num_conf) {
- CDBG("Resolution does not exist");
- return -EINVAL;
- }
-
- s_ctrl->prev_res = init_info->prev_res;
- s_ctrl->pict_res = init_info->pict_res;
s_ctrl->curr_res = MSM_SENSOR_INVALID_RES;
s_ctrl->cam_mode = mode;
rc = s_ctrl->func_tbl->sensor_setting(s_ctrl,
- MSM_SENSOR_REG_INIT, s_ctrl->prev_res);
+ MSM_SENSOR_REG_INIT, 0);
}
return rc;
}
@@ -349,109 +281,6 @@
CDBG("msm_sensor_config: cfgtype = %d\n",
cdata.cfgtype);
switch (cdata.cfgtype) {
- case CFG_GET_PICT_FPS:
- if (s_ctrl->func_tbl->
- sensor_get_pict_fps == NULL) {
- rc = -EFAULT;
- break;
- }
- s_ctrl->func_tbl->
- sensor_get_pict_fps(
- s_ctrl,
- cdata.cfg.gfps.prevfps,
- &(cdata.cfg.gfps.pictfps));
-
- if (copy_to_user((void *)argp,
- &cdata,
- sizeof(struct sensor_cfg_data)))
- rc = -EFAULT;
- break;
-
- case CFG_GET_PREV_L_PF:
- if (s_ctrl->func_tbl->
- sensor_get_prev_lines_pf == NULL) {
- rc = -EFAULT;
- break;
- }
- cdata.cfg.prevl_pf =
- s_ctrl->func_tbl->
- sensor_get_prev_lines_pf
- (s_ctrl);
-
- if (copy_to_user((void *)argp,
- &cdata,
- sizeof(struct sensor_cfg_data)))
- rc = -EFAULT;
- break;
-
- case CFG_GET_PREV_P_PL:
- if (s_ctrl->func_tbl->
- sensor_get_prev_pixels_pl == NULL) {
- rc = -EFAULT;
- break;
- }
- cdata.cfg.prevp_pl =
- s_ctrl->func_tbl->
- sensor_get_prev_pixels_pl
- (s_ctrl);
-
- if (copy_to_user((void *)argp,
- &cdata,
- sizeof(struct sensor_cfg_data)))
- rc = -EFAULT;
- break;
-
- case CFG_GET_PICT_L_PF:
- if (s_ctrl->func_tbl->
- sensor_get_pict_lines_pf == NULL) {
- rc = -EFAULT;
- break;
- }
- cdata.cfg.pictl_pf =
- s_ctrl->func_tbl->
- sensor_get_pict_lines_pf
- (s_ctrl);
-
- if (copy_to_user((void *)argp,
- &cdata,
- sizeof(struct sensor_cfg_data)))
- rc = -EFAULT;
- break;
-
- case CFG_GET_PICT_P_PL:
- if (s_ctrl->func_tbl->
- sensor_get_pict_pixels_pl == NULL) {
- rc = -EFAULT;
- break;
- }
- cdata.cfg.pictp_pl =
- s_ctrl->func_tbl->
- sensor_get_pict_pixels_pl
- (s_ctrl);
-
- if (copy_to_user((void *)argp,
- &cdata,
- sizeof(struct sensor_cfg_data)))
- rc = -EFAULT;
- break;
-
- case CFG_GET_PICT_MAX_EXP_LC:
- if (s_ctrl->func_tbl->
- sensor_get_pict_max_exp_lc == NULL) {
- rc = -EFAULT;
- break;
- }
- cdata.cfg.pict_max_exp_lc =
- s_ctrl->func_tbl->
- sensor_get_pict_max_exp_lc
- (s_ctrl);
-
- if (copy_to_user((void *)argp,
- &cdata,
- sizeof(struct sensor_cfg_data)))
- rc = -EFAULT;
- break;
-
case CFG_SET_FPS:
case CFG_SET_PICT_FPS:
if (s_ctrl->func_tbl->
@@ -506,30 +335,9 @@
cdata.rs);
break;
- case CFG_PWR_DOWN:
- break;
-
- case CFG_MOVE_FOCUS:
- break;
-
- case CFG_SET_DEFAULT_FOCUS:
- break;
-
- case CFG_GET_AF_MAX_STEPS:
- cdata.max_steps = 32;
- if (copy_to_user((void *)argp,
- &cdata,
- sizeof(struct sensor_cfg_data)))
- rc = -EFAULT;
- break;
-
case CFG_SET_EFFECT:
break;
-
- case CFG_SEND_WB_INFO:
- break;
-
case CFG_SENSOR_INIT:
if (s_ctrl->func_tbl->
sensor_mode_init == NULL) {
diff --git a/drivers/media/video/msm/sensors/msm_sensor.h b/drivers/media/video/msm/sensors/msm_sensor.h
index 1121170..e4dc34f 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.h
+++ b/drivers/media/video/msm/sensors/msm_sensor.h
@@ -99,18 +99,6 @@
void (*sensor_group_hold_on) (struct msm_sensor_ctrl_t *);
void (*sensor_group_hold_off) (struct msm_sensor_ctrl_t *);
- uint16_t (*sensor_get_prev_lines_pf)
- (struct msm_sensor_ctrl_t *);
- uint16_t (*sensor_get_prev_pixels_pl)
- (struct msm_sensor_ctrl_t *);
- uint16_t (*sensor_get_pict_lines_pf)
- (struct msm_sensor_ctrl_t *);
- uint16_t (*sensor_get_pict_pixels_pl)
- (struct msm_sensor_ctrl_t *);
- uint32_t (*sensor_get_pict_max_exp_lc)
- (struct msm_sensor_ctrl_t *);
- void (*sensor_get_pict_fps) (struct msm_sensor_ctrl_t *,
- uint16_t, uint16_t *);
int32_t (*sensor_set_fps) (struct msm_sensor_ctrl_t *,
struct fps_cfg *);
int32_t (*sensor_write_exp_gain) (struct msm_sensor_ctrl_t *,
@@ -153,10 +141,7 @@
uint16_t curr_line_length_pclk;
uint16_t curr_frame_length_lines;
- uint16_t fps;
uint32_t fps_divider;
- enum msm_sensor_resolution_t prev_res;
- enum msm_sensor_resolution_t pict_res;
enum msm_sensor_resolution_t curr_res;
enum msm_sensor_cam_mode_t cam_mode;
@@ -176,13 +161,6 @@
void msm_sensor_group_hold_on(struct msm_sensor_ctrl_t *s_ctrl);
void msm_sensor_group_hold_off(struct msm_sensor_ctrl_t *s_ctrl);
-uint16_t msm_sensor_get_prev_lines_pf(struct msm_sensor_ctrl_t *s_ctrl);
-uint16_t msm_sensor_get_prev_pixels_pl(struct msm_sensor_ctrl_t *s_ctrl);
-uint16_t msm_sensor_get_pict_lines_pf(struct msm_sensor_ctrl_t *s_ctrl);
-uint16_t msm_sensor_get_pict_pixels_pl(struct msm_sensor_ctrl_t *s_ctrl);
-uint32_t msm_sensor_get_pict_max_exp_lc(struct msm_sensor_ctrl_t *s_ctrl);
-void msm_sensor_get_pict_fps(struct msm_sensor_ctrl_t *s_ctrl,
- uint16_t fps, uint16_t *pfps);
int32_t msm_sensor_set_fps(struct msm_sensor_ctrl_t *s_ctrl,
struct fps_cfg *fps);
int32_t msm_sensor_write_exp_gain1(struct msm_sensor_ctrl_t *s_ctrl,
diff --git a/drivers/media/video/msm/sensors/ov2720.c b/drivers/media/video/msm/sensors/ov2720.c
index bdad57c..5938406 100644
--- a/drivers/media/video/msm/sensors/ov2720.c
+++ b/drivers/media/video/msm/sensors/ov2720.c
@@ -477,12 +477,6 @@
.sensor_stop_stream = msm_sensor_stop_stream,
.sensor_group_hold_on = msm_sensor_group_hold_on,
.sensor_group_hold_off = msm_sensor_group_hold_off,
- .sensor_get_prev_lines_pf = msm_sensor_get_prev_lines_pf,
- .sensor_get_prev_pixels_pl = msm_sensor_get_prev_pixels_pl,
- .sensor_get_pict_lines_pf = msm_sensor_get_pict_lines_pf,
- .sensor_get_pict_pixels_pl = msm_sensor_get_pict_pixels_pl,
- .sensor_get_pict_max_exp_lc = msm_sensor_get_pict_max_exp_lc,
- .sensor_get_pict_fps = msm_sensor_get_pict_fps,
.sensor_set_fps = msm_sensor_set_fps,
.sensor_write_exp_gain = ov2720_write_exp_gain,
.sensor_write_snapshot_exp_gain = ov2720_write_exp_gain,
diff --git a/drivers/media/video/uvc/uvc_entity.c b/drivers/media/video/uvc/uvc_entity.c
index 48fea37..29e2399 100644
--- a/drivers/media/video/uvc/uvc_entity.c
+++ b/drivers/media/video/uvc/uvc_entity.c
@@ -49,7 +49,7 @@
if (remote == NULL)
return -EINVAL;
- source = (UVC_ENTITY_TYPE(remote) != UVC_TT_STREAMING)
+ source = (UVC_ENTITY_TYPE(remote) == UVC_TT_STREAMING)
? (remote->vdev ? &remote->vdev->entity : NULL)
: &remote->subdev.entity;
if (source == NULL)
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index a4feb838..9e9bb23 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -157,15 +157,16 @@
tristate "PMIC8058 Power Management chip"
depends on MSM_SSBI
select MFD_CORE
+ select MFD_PM8XXX
select MSM_SHOW_RESUME_IRQ
help
Say yes here for Qualcomm PM8058 chip.
config PMIC8901
tristate "PMIC8901 Power Management chip"
- depends on I2C_SSBI && ARCH_MSM8X60
- default y if I2C_SSBI && ARCH_MSM8X60
+ depends on MSM_SSBI
select MFD_CORE
+ select MFD_PM8XXX
help
Say yes here for Qualcomm PM8901 chip.
@@ -804,6 +805,21 @@
Say M here if you want to include support for PM8018 chip as a module.
This will build a module called "pm8018-core".
+config MFD_PM8038_CORE
+ tristate "Qualcomm PM8038 PMIC chip"
+ depends on MSM_SSBI
+ select MFD_CORE
+ select MFD_PM8XXX
+ help
+ If you say yes to this option, support will be included for the
+ built-in PM8038 PMIC chip.
+
+ This is required if your board has a PM8038 and uses its features,
+ such as: MPPs, GPIOs, regulators, interrupts, and PWM.
+
+ Say M here if you want to include support for PM8038 chip as a module.
+ This will build a module called "pm8038-core".
+
config MFD_PM8XXX_IRQ
bool "Support for Qualcomm PM8xxx IRQ features"
depends on MFD_PM8XXX
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 5813b86..30192d9 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -117,6 +117,7 @@
obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o
obj-$(CONFIG_MFD_PM8821_CORE) += pm8821-core.o
obj-$(CONFIG_MFD_PM8018_CORE) += pm8018-core.o
+obj-$(CONFIG_MFD_PM8038_CORE) += pm8038-core.o
obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
obj-$(CONFIG_MFD_PM8XXX_DEBUG) += pm8xxx-debug.o
obj-$(CONFIG_MFD_PM8XXX_PWM) += pm8xxx-pwm.o
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
index 1717144..e67c3d3 100644
--- a/drivers/mfd/omap-usb-host.c
+++ b/drivers/mfd/omap-usb-host.c
@@ -676,7 +676,6 @@
| OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF
| OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE);
- reg |= (1 << (i + 1));
} else
continue;
diff --git a/drivers/mfd/pm8018-core.c b/drivers/mfd/pm8018-core.c
index 528f232..8d89568 100644
--- a/drivers/mfd/pm8018-core.c
+++ b/drivers/mfd/pm8018-core.c
@@ -29,6 +29,7 @@
#define REG_HWREV_2 0x0E8 /* PMIC4 revision 2 */
#define REG_MPP_BASE 0x050
+#define REG_IRQ_BASE 0x1BB
#define REG_RTC_BASE 0x11D
@@ -237,6 +238,7 @@
if (pdata->irq_pdata) {
pdata->irq_pdata->irq_cdata.nirqs = PM8018_NR_IRQS;
+ pdata->irq_pdata->irq_cdata.base_addr = REG_IRQ_BASE;
irq_base = pdata->irq_pdata->irq_base;
irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
diff --git a/drivers/mfd/pm8038-core.c b/drivers/mfd/pm8038-core.c
new file mode 100644
index 0000000..9123067
--- /dev/null
+++ b/drivers/mfd/pm8038-core.c
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/msm_ssbi.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/pm8xxx/pm8038.h>
+#include <linux/mfd/pm8xxx/core.h>
+
+#define REG_HWREV 0x002 /* PMIC4 revision */
+#define REG_HWREV_2 0x0E8 /* PMIC4 revision 2 */
+
+#define REG_MPP_BASE 0x050
+#define REG_RTC_BASE 0x11D
+#define REG_IRQ_BASE 0x1BB
+
+#define PM8038_VERSION_MASK 0xFFF0
+#define PM8038_VERSION_VALUE 0x09F0
+#define PM8038_REVISION_MASK 0x000F
+
+#define REG_PM8038_PON_CNTRL_3 0x01D
+#define PM8038_RESTART_REASON_MASK 0x07
+
+#define SINGLE_IRQ_RESOURCE(_name, _irq) \
+{ \
+ .name = _name, \
+ .start = _irq, \
+ .end = _irq, \
+ .flags = IORESOURCE_IRQ, \
+}
+
+struct pm8038 {
+ struct device *dev;
+ struct pm_irq_chip *irq_chip;
+ u32 rev_registers;
+};
+
+static int pm8038_readb(const struct device *dev, u16 addr, u8 *val)
+{
+ const struct pm8xxx_drvdata *pm8038_drvdata = dev_get_drvdata(dev);
+ const struct pm8038 *pmic = pm8038_drvdata->pm_chip_data;
+
+ return msm_ssbi_read(pmic->dev->parent, addr, val, 1);
+}
+
+static int pm8038_writeb(const struct device *dev, u16 addr, u8 val)
+{
+ const struct pm8xxx_drvdata *pm8038_drvdata = dev_get_drvdata(dev);
+ const struct pm8038 *pmic = pm8038_drvdata->pm_chip_data;
+
+ return msm_ssbi_write(pmic->dev->parent, addr, &val, 1);
+}
+
+static int pm8038_read_buf(const struct device *dev, u16 addr, u8 *buf,
+ int cnt)
+{
+ const struct pm8xxx_drvdata *pm8038_drvdata = dev_get_drvdata(dev);
+ const struct pm8038 *pmic = pm8038_drvdata->pm_chip_data;
+
+ return msm_ssbi_read(pmic->dev->parent, addr, buf, cnt);
+}
+
+static int pm8038_write_buf(const struct device *dev, u16 addr, u8 *buf,
+ int cnt)
+{
+ const struct pm8xxx_drvdata *pm8038_drvdata = dev_get_drvdata(dev);
+ const struct pm8038 *pmic = pm8038_drvdata->pm_chip_data;
+
+ return msm_ssbi_write(pmic->dev->parent, addr, buf, cnt);
+}
+
+static int pm8038_read_irq_stat(const struct device *dev, int irq)
+{
+ const struct pm8xxx_drvdata *pm8038_drvdata = dev_get_drvdata(dev);
+ const struct pm8038 *pmic = pm8038_drvdata->pm_chip_data;
+
+ return pm8xxx_get_irq_stat(pmic->irq_chip, irq);
+}
+
+static enum pm8xxx_version pm8038_get_version(const struct device *dev)
+{
+ const struct pm8xxx_drvdata *pm8038_drvdata = dev_get_drvdata(dev);
+ const struct pm8038 *pmic = pm8038_drvdata->pm_chip_data;
+ enum pm8xxx_version version = -ENODEV;
+
+ if ((pmic->rev_registers & PM8038_VERSION_MASK) == PM8038_VERSION_VALUE)
+ version = PM8XXX_VERSION_8038;
+
+ return version;
+}
+
+static int pm8038_get_revision(const struct device *dev)
+{
+ const struct pm8xxx_drvdata *pm8038_drvdata = dev_get_drvdata(dev);
+ const struct pm8038 *pmic = pm8038_drvdata->pm_chip_data;
+
+ return pmic->rev_registers & PM8038_REVISION_MASK;
+}
+
+static struct pm8xxx_drvdata pm8038_drvdata = {
+ .pmic_readb = pm8038_readb,
+ .pmic_writeb = pm8038_writeb,
+ .pmic_read_buf = pm8038_read_buf,
+ .pmic_write_buf = pm8038_write_buf,
+ .pmic_read_irq_stat = pm8038_read_irq_stat,
+ .pmic_get_version = pm8038_get_version,
+ .pmic_get_revision = pm8038_get_revision,
+};
+
+static const struct resource gpio_cell_resources[] __devinitconst = {
+ [0] = {
+ .start = PM8038_IRQ_BLOCK_BIT(PM8038_GPIO_BLOCK_START, 0),
+ .end = PM8038_IRQ_BLOCK_BIT(PM8038_GPIO_BLOCK_START, 0)
+ + PM8038_NR_GPIOS - 1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mfd_cell gpio_cell __devinitdata = {
+ .name = PM8XXX_GPIO_DEV_NAME,
+ .id = -1,
+ .resources = gpio_cell_resources,
+ .num_resources = ARRAY_SIZE(gpio_cell_resources),
+};
+
+static const struct resource mpp_cell_resources[] __devinitconst = {
+ {
+ .start = PM8038_IRQ_BLOCK_BIT(PM8038_MPP_BLOCK_START, 0),
+ .end = PM8038_IRQ_BLOCK_BIT(PM8038_MPP_BLOCK_START, 0)
+ + PM8038_NR_MPPS - 1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mfd_cell mpp_cell __devinitdata = {
+ .name = PM8XXX_MPP_DEV_NAME,
+ .id = 1,
+ .resources = mpp_cell_resources,
+ .num_resources = ARRAY_SIZE(mpp_cell_resources),
+};
+
+static const struct resource rtc_cell_resources[] __devinitconst = {
+ [0] = SINGLE_IRQ_RESOURCE(NULL, PM8038_RTC_ALARM_IRQ),
+ [1] = {
+ .name = "pmic_rtc_base",
+ .start = REG_RTC_BASE,
+ .end = REG_RTC_BASE,
+ .flags = IORESOURCE_IO,
+ },
+};
+
+static struct mfd_cell rtc_cell __devinitdata = {
+ .name = PM8XXX_RTC_DEV_NAME,
+ .id = -1,
+ .resources = rtc_cell_resources,
+ .num_resources = ARRAY_SIZE(rtc_cell_resources),
+};
+
+static const struct resource resources_pwrkey[] __devinitconst = {
+ SINGLE_IRQ_RESOURCE(NULL, PM8038_PWRKEY_REL_IRQ),
+ SINGLE_IRQ_RESOURCE(NULL, PM8038_PWRKEY_PRESS_IRQ),
+};
+
+static struct mfd_cell pwrkey_cell __devinitdata = {
+ .name = PM8XXX_PWRKEY_DEV_NAME,
+ .id = -1,
+ .num_resources = ARRAY_SIZE(resources_pwrkey),
+ .resources = resources_pwrkey,
+};
+
+static struct mfd_cell pwm_cell __devinitdata = {
+ .name = PM8XXX_PWM_DEV_NAME,
+ .id = -1,
+};
+
+static struct mfd_cell misc_cell __devinitdata = {
+ .name = PM8XXX_MISC_DEV_NAME,
+ .id = -1,
+};
+
+static struct mfd_cell debugfs_cell __devinitdata = {
+ .name = "pm8xxx-debug",
+ .id = 0,
+ .platform_data = "pm8038-dbg",
+ .pdata_size = sizeof("pm8038-dbg"),
+};
+
+
+static int __devinit
+pm8038_add_subdevices(const struct pm8038_platform_data *pdata,
+ struct pm8038 *pmic)
+{
+ int ret = 0, irq_base = 0;
+ struct pm_irq_chip *irq_chip;
+
+ if (pdata->irq_pdata) {
+ pdata->irq_pdata->irq_cdata.nirqs = PM8038_NR_IRQS;
+ pdata->irq_pdata->irq_cdata.base_addr = REG_IRQ_BASE;
+ irq_base = pdata->irq_pdata->irq_base;
+ irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
+
+ if (IS_ERR(irq_chip)) {
+ pr_err("Failed to init interrupts ret=%ld\n",
+ PTR_ERR(irq_chip));
+ return PTR_ERR(irq_chip);
+ }
+ pmic->irq_chip = irq_chip;
+ }
+
+ if (pdata->gpio_pdata) {
+ pdata->gpio_pdata->gpio_cdata.ngpios = PM8038_NR_GPIOS;
+ gpio_cell.platform_data = pdata->gpio_pdata;
+ gpio_cell.pdata_size = sizeof(struct pm8xxx_gpio_platform_data);
+ ret = mfd_add_devices(pmic->dev, 0, &gpio_cell, 1,
+ NULL, irq_base);
+ if (ret) {
+ pr_err("Failed to add gpio subdevice ret=%d\n", ret);
+ goto bail;
+ }
+ }
+
+ if (pdata->mpp_pdata) {
+ pdata->mpp_pdata->core_data.nmpps = PM8038_NR_MPPS;
+ pdata->mpp_pdata->core_data.base_addr = REG_MPP_BASE;
+ mpp_cell.platform_data = pdata->mpp_pdata;
+ mpp_cell.pdata_size = sizeof(struct pm8xxx_mpp_platform_data);
+ ret = mfd_add_devices(pmic->dev, 0, &mpp_cell, 1, NULL,
+ irq_base);
+ if (ret) {
+ pr_err("Failed to add mpp subdevice ret=%d\n", ret);
+ goto bail;
+ }
+ }
+
+ if (pdata->rtc_pdata) {
+ rtc_cell.platform_data = pdata->rtc_pdata;
+ rtc_cell.pdata_size = sizeof(struct pm8xxx_rtc_platform_data);
+ ret = mfd_add_devices(pmic->dev, 0, &rtc_cell, 1, NULL,
+ irq_base);
+ if (ret) {
+ pr_err("Failed to add rtc subdevice ret=%d\n", ret);
+ goto bail;
+ }
+ }
+
+ if (pdata->pwrkey_pdata) {
+ pwrkey_cell.platform_data = pdata->pwrkey_pdata;
+ pwrkey_cell.pdata_size =
+ sizeof(struct pm8xxx_pwrkey_platform_data);
+ ret = mfd_add_devices(pmic->dev, 0, &pwrkey_cell, 1, NULL,
+ irq_base);
+ if (ret) {
+ pr_err("Failed to add pwrkey subdevice ret=%d\n", ret);
+ goto bail;
+ }
+ }
+
+ ret = mfd_add_devices(pmic->dev, 0, &pwm_cell, 1, NULL, 0);
+ if (ret) {
+ pr_err("Failed to add pwm subdevice ret=%d\n", ret);
+ goto bail;
+ }
+
+ if (pdata->misc_pdata) {
+ misc_cell.platform_data = pdata->misc_pdata;
+ misc_cell.pdata_size = sizeof(struct pm8xxx_misc_platform_data);
+ ret = mfd_add_devices(pmic->dev, 0, &misc_cell, 1, NULL,
+ irq_base);
+ if (ret) {
+ pr_err("Failed to add misc subdevice ret=%d\n", ret);
+ goto bail;
+ }
+ }
+
+ ret = mfd_add_devices(pmic->dev, 0, &debugfs_cell, 1, NULL, irq_base);
+ if (ret) {
+ pr_err("Failed to add debugfs subdevice ret=%d\n", ret);
+ goto bail;
+ }
+
+ return 0;
+bail:
+ if (pmic->irq_chip) {
+ pm8xxx_irq_exit(pmic->irq_chip);
+ pmic->irq_chip = NULL;
+ }
+ return ret;
+}
+
+static const char * const pm8038_restart_reason[] = {
+ [0] = "Unknown",
+ [1] = "Triggered from CBL (external charger)",
+ [2] = "Triggered from KPD (power key press)",
+ [3] = "Triggered from CHG (usb charger insertion)",
+ [4] = "Triggered from SMPL (sudden momentary power loss)",
+ [5] = "Triggered from RTC (real time clock)",
+ [6] = "Triggered by Hard Reset",
+ [7] = "Triggered by General Purpose Trigger",
+};
+
+static const char * const pm8038_rev_names[] = {
+ [PM8XXX_REVISION_8038_TEST] = "test",
+ [PM8XXX_REVISION_8038_1p0] = "1.0",
+ [PM8XXX_REVISION_8038_2p0] = "2.0",
+ [PM8XXX_REVISION_8038_2p1] = "2.1",
+};
+
+static int __devinit pm8038_probe(struct platform_device *pdev)
+{
+ const struct pm8038_platform_data *pdata = pdev->dev.platform_data;
+ const char *revision_name = "unknown";
+ struct pm8038 *pmic;
+ enum pm8xxx_version version;
+ int revision;
+ int rc;
+ u8 val;
+
+ if (!pdata) {
+ pr_err("missing platform data\n");
+ return -EINVAL;
+ }
+
+ pmic = kzalloc(sizeof(struct pm8038), GFP_KERNEL);
+ if (!pmic) {
+ pr_err("Cannot alloc pm8038 struct\n");
+ return -ENOMEM;
+ }
+
+ /* Read PMIC chip revision */
+ rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val));
+ if (rc) {
+ pr_err("Failed to read hw rev reg %d:rc=%d\n", REG_HWREV, rc);
+ goto err_read_rev;
+ }
+ pr_info("PMIC revision 1: PM8038 rev %02X\n", val);
+ pmic->rev_registers = val;
+
+ /* Read PMIC chip revision 2 */
+ rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV_2, &val, sizeof(val));
+ if (rc) {
+ pr_err("Failed to read hw rev 2 reg %d:rc=%d\n",
+ REG_HWREV_2, rc);
+ goto err_read_rev;
+ }
+ pr_info("PMIC revision 2: PM8038 rev %02X\n", val);
+ pmic->rev_registers |= val << BITS_PER_BYTE;
+
+ pmic->dev = &pdev->dev;
+ pm8038_drvdata.pm_chip_data = pmic;
+ platform_set_drvdata(pdev, &pm8038_drvdata);
+
+ /* Print out human readable version and revision names. */
+ version = pm8xxx_get_version(pmic->dev);
+ if (version == PM8XXX_VERSION_8038) {
+ revision = pm8xxx_get_revision(pmic->dev);
+ if (revision >= 0 && revision < ARRAY_SIZE(pm8038_rev_names))
+ revision_name = pm8038_rev_names[revision];
+ pr_info("PMIC version: PM8038 ver %s\n", revision_name);
+ } else {
+ WARN_ON(version != PM8XXX_VERSION_8038);
+ }
+
+ /* Log human readable restart reason */
+ rc = msm_ssbi_read(pdev->dev.parent, REG_PM8038_PON_CNTRL_3, &val, 1);
+ if (rc) {
+ pr_err("Cannot read restart reason rc=%d\n", rc);
+ goto err_read_rev;
+ }
+ val &= PM8038_RESTART_REASON_MASK;
+ pr_info("PMIC Restart Reason: %s\n", pm8038_restart_reason[val]);
+
+ rc = pm8038_add_subdevices(pdata, pmic);
+ if (rc) {
+ pr_err("Cannot add subdevices rc=%d\n", rc);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ mfd_remove_devices(pmic->dev);
+ platform_set_drvdata(pdev, NULL);
+err_read_rev:
+ kfree(pmic);
+ return rc;
+}
+
+static int __devexit pm8038_remove(struct platform_device *pdev)
+{
+ struct pm8xxx_drvdata *drvdata;
+ struct pm8038 *pmic = NULL;
+
+ drvdata = platform_get_drvdata(pdev);
+
+ if (drvdata)
+ pmic = drvdata->pm_chip_data;
+
+ if (pmic) {
+ if (pmic->dev)
+ mfd_remove_devices(pmic->dev);
+
+ if (pmic->irq_chip) {
+ pm8xxx_irq_exit(pmic->irq_chip);
+ pmic->irq_chip = NULL;
+ }
+
+ kfree(pmic);
+ }
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver pm8038_driver = {
+ .probe = pm8038_probe,
+ .remove = __devexit_p(pm8038_remove),
+ .driver = {
+ .name = PM8038_CORE_DEV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pm8038_init(void)
+{
+ return platform_driver_register(&pm8038_driver);
+}
+postcore_initcall(pm8038_init);
+
+static void __exit pm8038_exit(void)
+{
+ platform_driver_unregister(&pm8038_driver);
+}
+module_exit(pm8038_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PMIC 8038 core driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:pm8038-core");
diff --git a/drivers/mfd/pm8821-core.c b/drivers/mfd/pm8821-core.c
index ed29785..8a556bd 100644
--- a/drivers/mfd/pm8821-core.c
+++ b/drivers/mfd/pm8821-core.c
@@ -26,6 +26,7 @@
#define REG_HWREV_2 0x0E8 /* PMIC4 revision 2 */
#define REG_MPP_BASE 0x050
+#define REG_IRQ_BASE 0x1BB
#define PM8821_VERSION_MASK 0xFFF0
#define PM8821_VERSION_VALUE 0x07F0
@@ -150,6 +151,7 @@
if (pdata->irq_pdata) {
pdata->irq_pdata->irq_cdata.nirqs = PM8821_NR_IRQS;
+ pdata->irq_pdata->irq_cdata.base_addr = REG_IRQ_BASE;
irq_base = pdata->irq_pdata->irq_base;
irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
index 742d8dd..373aaf7 100644
--- a/drivers/mfd/pm8921-core.c
+++ b/drivers/mfd/pm8921-core.c
@@ -27,6 +27,7 @@
#define REG_HWREV_2 0x0E8 /* PMIC4 revision 2 */
#define REG_MPP_BASE 0x050
+#define REG_IRQ_BASE 0x1BB
#define REG_TEMP_ALARM_CTRL 0x1B
#define REG_TEMP_ALARM_PWM 0x9B
@@ -38,9 +39,11 @@
#define PM8921_VERSION_MASK 0xFFF0
#define PM8921_VERSION_VALUE 0x06F0
+#define PM8922_VERSION_VALUE 0x0AF0
#define PM8921_REVISION_MASK 0x000F
#define REG_PM8921_PON_CNTRL_3 0x01D
+#define REG_PM8921_PON_CNTRL_4 0x01E
#define PM8921_RESTART_REASON_MASK 0x07
#define SINGLE_IRQ_RESOURCE(_name, _irq) \
@@ -108,6 +111,9 @@
if ((pmic->rev_registers & PM8921_VERSION_MASK) == PM8921_VERSION_VALUE)
version = PM8XXX_VERSION_8921;
+ else if ((pmic->rev_registers & PM8921_VERSION_MASK)
+ == PM8922_VERSION_VALUE)
+ version = PM8XXX_VERSION_8922;
return version;
}
@@ -153,7 +159,7 @@
};
static struct mfd_cell adc_cell __devinitdata = {
- .name = PM8921_ADC_DEV_NAME,
+ .name = PM8XXX_ADC_DEV_NAME,
.id = -1,
.resources = adc_cell_resources,
.num_resources = ARRAY_SIZE(adc_cell_resources),
@@ -270,7 +276,6 @@
SINGLE_IRQ_RESOURCE("PM8921_BMS_OCV_FOR_R", PM8921_BMS_OCV_FOR_R),
SINGLE_IRQ_RESOURCE("PM8921_BMS_GOOD_OCV", PM8921_BMS_GOOD_OCV),
SINGLE_IRQ_RESOURCE("PM8921_BMS_VSENSE_AVG", PM8921_BMS_VSENSE_AVG),
- SINGLE_IRQ_RESOURCE("PM8921_BMS_CCADC_EOC", PM8921_BMS_CCADC_EOC),
};
static struct mfd_cell charger_cell __devinitdata = {
@@ -304,7 +309,7 @@
static struct pm8xxx_tm_core_data thermal_alarm_cdata = {
.adc_channel = CHANNEL_DIE_TEMP,
- .adc_type = PM8XXX_TM_ADC_PM8921_ADC,
+ .adc_type = PM8XXX_TM_ADC_PM8XXX_ADC,
.reg_addr_temp_alarm_ctrl = REG_TEMP_ALARM_CTRL,
.reg_addr_temp_alarm_pwm = REG_TEMP_ALARM_PWM,
.tm_name = "pm8921_tz",
@@ -342,6 +347,17 @@
.pdata_size = sizeof(struct pm8xxx_batt_alarm_core_data),
};
+static const struct resource ccadc_cell_resources[] __devinitconst = {
+ SINGLE_IRQ_RESOURCE("PM8921_BMS_CCADC_EOC", PM8921_BMS_CCADC_EOC),
+};
+
+static struct mfd_cell ccadc_cell __devinitdata = {
+ .name = PM8XXX_CCADC_DEV_NAME,
+ .id = -1,
+ .resources = ccadc_cell_resources,
+ .num_resources = ARRAY_SIZE(ccadc_cell_resources),
+};
+
static struct mfd_cell vibrator_cell __devinitdata = {
.name = PM8XXX_VIBRATOR_DEV_NAME,
.id = -1,
@@ -354,10 +370,14 @@
int ret = 0, irq_base = 0;
struct pm_irq_chip *irq_chip;
static struct mfd_cell *mfd_regulators;
+ enum pm8xxx_version version;
int i;
+ version = pm8xxx_get_version(pmic->dev);
+
if (pdata->irq_pdata) {
pdata->irq_pdata->irq_cdata.nirqs = PM8921_NR_IRQS;
+ pdata->irq_pdata->irq_cdata.base_addr = REG_IRQ_BASE;
irq_base = pdata->irq_pdata->irq_base;
irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
@@ -449,7 +469,7 @@
if (pdata->adc_pdata) {
adc_cell.platform_data = pdata->adc_pdata;
adc_cell.pdata_size =
- sizeof(struct pm8921_adc_platform_data);
+ sizeof(struct pm8xxx_adc_platform_data);
ret = mfd_add_devices(pmic->dev, 0, &adc_cell, 1, NULL,
irq_base);
if (ret) {
@@ -566,6 +586,19 @@
}
}
+ if (pdata->ccadc_pdata) {
+ ccadc_cell.platform_data = pdata->ccadc_pdata;
+ ccadc_cell.pdata_size =
+ sizeof(struct pm8xxx_ccadc_platform_data);
+
+ ret = mfd_add_devices(pmic->dev, 0, &ccadc_cell, 1, NULL,
+ irq_base);
+ if (ret) {
+ pr_err("Failed to add ccadc subdevice ret=%d\n", ret);
+ goto bail;
+ }
+ }
+
return 0;
bail:
if (pmic->irq_chip) {
@@ -591,6 +624,14 @@
[PM8XXX_REVISION_8921_1p0] = "1.0",
[PM8XXX_REVISION_8921_1p1] = "1.1",
[PM8XXX_REVISION_8921_2p0] = "2.0",
+ [PM8XXX_REVISION_8921_3p0] = "3.0",
+};
+
+static const char * const pm8922_rev_names[] = {
+ [PM8XXX_REVISION_8922_TEST] = "test",
+ [PM8XXX_REVISION_8922_1p0] = "1.0",
+ [PM8XXX_REVISION_8922_1p1] = "1.1",
+ [PM8XXX_REVISION_8922_2p0] = "2.0",
};
static int __devinit pm8921_probe(struct platform_device *pdev)
@@ -639,13 +680,18 @@
/* Print out human readable version and revision names. */
version = pm8xxx_get_version(pmic->dev);
+ revision = pm8xxx_get_revision(pmic->dev);
if (version == PM8XXX_VERSION_8921) {
- revision = pm8xxx_get_revision(pmic->dev);
if (revision >= 0 && revision < ARRAY_SIZE(pm8921_rev_names))
revision_name = pm8921_rev_names[revision];
pr_info("PMIC version: PM8921 rev %s\n", revision_name);
+ } else if (version == PM8XXX_VERSION_8922) {
+ if (revision >= 0 && revision < ARRAY_SIZE(pm8922_rev_names))
+ revision_name = pm8922_rev_names[revision];
+ pr_info("PMIC version: PM8922 rev %s\n", revision_name);
} else {
- WARN_ON(version != PM8XXX_VERSION_8921);
+ WARN_ON(version != PM8XXX_VERSION_8921
+ && version != PM8XXX_VERSION_8922);
}
/* Log human readable restart reason */
@@ -657,6 +703,14 @@
val &= PM8921_RESTART_REASON_MASK;
pr_info("PMIC Restart Reason: %s\n", pm8921_restart_reason[val]);
+ /* Set power-on-reset to 3 seconds */
+ val = 0xBB;
+ rc = msm_ssbi_write(pdev->dev.parent, REG_PM8921_PON_CNTRL_4, &val, 1);
+ if (rc) {
+ pr_err("Cannot write power-on-reset rc=%d\n", rc);
+ goto err;
+ }
+
rc = pm8921_add_subdevices(pdata, pmic);
if (rc) {
pr_err("Cannot add subdevices rc=%d\n", rc);
diff --git a/drivers/mfd/pm8xxx-irq.c b/drivers/mfd/pm8xxx-irq.c
index c6221b8..5864b85 100644
--- a/drivers/mfd/pm8xxx-irq.c
+++ b/drivers/mfd/pm8xxx-irq.c
@@ -24,17 +24,15 @@
/* PMIC8xxx IRQ */
-#define SSBI_REG_ADDR_IRQ_BASE 0x1BB
-
-#define SSBI_REG_ADDR_IRQ_ROOT (SSBI_REG_ADDR_IRQ_BASE + 0)
-#define SSBI_REG_ADDR_IRQ_M_STATUS1 (SSBI_REG_ADDR_IRQ_BASE + 1)
-#define SSBI_REG_ADDR_IRQ_M_STATUS2 (SSBI_REG_ADDR_IRQ_BASE + 2)
-#define SSBI_REG_ADDR_IRQ_M_STATUS3 (SSBI_REG_ADDR_IRQ_BASE + 3)
-#define SSBI_REG_ADDR_IRQ_M_STATUS4 (SSBI_REG_ADDR_IRQ_BASE + 4)
-#define SSBI_REG_ADDR_IRQ_BLK_SEL (SSBI_REG_ADDR_IRQ_BASE + 5)
-#define SSBI_REG_ADDR_IRQ_IT_STATUS (SSBI_REG_ADDR_IRQ_BASE + 6)
-#define SSBI_REG_ADDR_IRQ_CONFIG (SSBI_REG_ADDR_IRQ_BASE + 7)
-#define SSBI_REG_ADDR_IRQ_RT_STATUS (SSBI_REG_ADDR_IRQ_BASE + 8)
+#define SSBI_REG_ADDR_IRQ_ROOT(base) (base + 0)
+#define SSBI_REG_ADDR_IRQ_M_STATUS1(base) (base + 1)
+#define SSBI_REG_ADDR_IRQ_M_STATUS2(base) (base + 2)
+#define SSBI_REG_ADDR_IRQ_M_STATUS3(base) (base + 3)
+#define SSBI_REG_ADDR_IRQ_M_STATUS4(base) (base + 4)
+#define SSBI_REG_ADDR_IRQ_BLK_SEL(base) (base + 5)
+#define SSBI_REG_ADDR_IRQ_IT_STATUS(base) (base + 6)
+#define SSBI_REG_ADDR_IRQ_CONFIG(base) (base + 7)
+#define SSBI_REG_ADDR_IRQ_RT_STATUS(base) (base + 8)
#define PM_IRQF_LVL_SEL 0x01 /* level select */
#define PM_IRQF_MASK_FE 0x02 /* mask falling edge */
@@ -50,6 +48,7 @@
struct pm_irq_chip {
struct device *dev;
spinlock_t pm_irq_lock;
+ unsigned int base_addr;
unsigned int devirq;
unsigned int irq_base;
unsigned int num_irqs;
@@ -60,13 +59,14 @@
static int pm8xxx_read_root_irq(const struct pm_irq_chip *chip, u8 *rp)
{
- return pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_ROOT, rp);
+ return pm8xxx_readb(chip->dev,
+ SSBI_REG_ADDR_IRQ_ROOT(chip->base_addr), rp);
}
static int pm8xxx_read_master_irq(const struct pm_irq_chip *chip, u8 m, u8 *bp)
{
return pm8xxx_readb(chip->dev,
- SSBI_REG_ADDR_IRQ_M_STATUS1 + m, bp);
+ SSBI_REG_ADDR_IRQ_M_STATUS1(chip->base_addr) + m, bp);
}
static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, u8 bp, u8 *ip)
@@ -74,13 +74,15 @@
int rc;
spin_lock(&chip->pm_irq_lock);
- rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
+ rc = pm8xxx_writeb(chip->dev,
+ SSBI_REG_ADDR_IRQ_BLK_SEL(chip->base_addr), bp);
if (rc) {
pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
goto bail;
}
- rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_IT_STATUS, ip);
+ rc = pm8xxx_readb(chip->dev,
+ SSBI_REG_ADDR_IRQ_IT_STATUS(chip->base_addr), ip);
if (rc)
pr_err("Failed Reading Status rc=%d\n", rc);
bail:
@@ -93,17 +95,20 @@
int rc;
spin_lock(&chip->pm_irq_lock);
- rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
+ rc = pm8xxx_writeb(chip->dev,
+ SSBI_REG_ADDR_IRQ_BLK_SEL(chip->base_addr), bp);
if (rc) {
pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
goto bail;
}
- rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_CONFIG, cp);
+ rc = pm8xxx_writeb(chip->dev,
+ SSBI_REG_ADDR_IRQ_CONFIG(chip->base_addr), cp);
if (rc)
pr_err("Failed Configuring IRQ rc=%d\n", rc);
- rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_CONFIG, r);
+ rc = pm8xxx_readb(chip->dev,
+ SSBI_REG_ADDR_IRQ_CONFIG(chip->base_addr), r);
if (rc)
pr_err("Failed reading IRQ rc=%d\n", rc);
bail:
@@ -116,14 +121,16 @@
int rc;
spin_lock(&chip->pm_irq_lock);
- rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
+ rc = pm8xxx_writeb(chip->dev,
+ SSBI_REG_ADDR_IRQ_BLK_SEL(chip->base_addr), bp);
if (rc) {
pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
goto bail;
}
cp |= PM_IRQF_WRITE;
- rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_CONFIG, cp);
+ rc = pm8xxx_writeb(chip->dev,
+ SSBI_REG_ADDR_IRQ_CONFIG(chip->base_addr), cp);
if (rc)
pr_err("Failed Configuring IRQ rc=%d\n", rc);
bail:
@@ -335,14 +342,16 @@
spin_lock_irqsave(&chip->pm_irq_lock, flags);
- rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, block);
+ rc = pm8xxx_writeb(chip->dev,
+ SSBI_REG_ADDR_IRQ_BLK_SEL(chip->base_addr), block);
if (rc) {
pr_err("Failed Selecting block irq=%d pmirq=%d blk=%d rc=%d\n",
irq, pmirq, block, rc);
goto bail_out;
}
- rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_RT_STATUS, &bits);
+ rc = pm8xxx_readb(chip->dev,
+ SSBI_REG_ADDR_IRQ_RT_STATUS(chip->base_addr), &bits);
if (rc) {
pr_err("Failed Configuring irq=%d pmirq=%d blk=%d rc=%d\n",
irq, pmirq, block, rc);
@@ -388,6 +397,7 @@
chip->devirq = devirq;
chip->irq_base = pdata->irq_base;
chip->num_irqs = pdata->irq_cdata.nirqs;
+ chip->base_addr = pdata->irq_cdata.base_addr;
chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8);
chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8);
spin_lock_init(&chip->pm_irq_lock);
diff --git a/drivers/mfd/pm8xxx-pwm.c b/drivers/mfd/pm8xxx-pwm.c
index 5b4f7e3..f65a183 100644
--- a/drivers/mfd/pm8xxx-pwm.c
+++ b/drivers/mfd/pm8xxx-pwm.c
@@ -1360,7 +1360,8 @@
version = pm8xxx_get_version(chip->dev->parent);
if (version == PM8XXX_VERSION_8921 ||
- version == PM8XXX_VERSION_8058) {
+ version == PM8XXX_VERSION_8058 ||
+ version == PM8XXX_VERSION_8922) {
chip->is_lpg_supported = 1;
}
if (chip->is_lpg_supported) {
diff --git a/drivers/mfd/pmic8058.c b/drivers/mfd/pmic8058.c
index 85c8a9d..ae721e4 100644
--- a/drivers/mfd/pmic8058.c
+++ b/drivers/mfd/pmic8058.c
@@ -14,55 +14,33 @@
* Qualcomm PMIC8058 driver
*
*/
-#include <linux/interrupt.h>
-#include <linux/i2c.h>
-#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
-#include <linux/ratelimit.h>
-#include <linux/kthread.h>
+#include <linux/irq.h>
#include <linux/msm_ssbi.h>
#include <linux/mfd/core.h>
#include <linux/mfd/pmic8058.h>
-#include <linux/platform_device.h>
-#include <linux/ratelimit.h>
-#include <linux/slab.h>
-#include <linux/debugfs.h>
-#include <linux/irq.h>
-#include <linux/syscore_ops.h>
-#include <linux/gpio.h>
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/msm_adc.h>
+
+#define REG_MPP_BASE 0x50
+#define REG_IRQ_BASE 0x1BB
/* PMIC8058 Revision */
-#define SSBI_REG_REV 0x002 /* PMIC4 revision */
+#define PM8058_REG_REV 0x002 /* PMIC4 revision */
+#define PM8058_VERSION_MASK 0xF0
+#define PM8058_REVISION_MASK 0x0F
+#define PM8058_VERSION_VALUE 0xE0
-/* PMIC8058 IRQ */
-#define SSBI_REG_ADDR_IRQ_BASE 0x1BB
+/* PMIC 8058 Battery Alarm SSBI registers */
+#define REG_BATT_ALARM_THRESH 0x023
+#define REG_BATT_ALARM_CTRL1 0x024
+#define REG_BATT_ALARM_CTRL2 0x0AA
+#define REG_BATT_ALARM_PWM_CTRL 0x0A3
-#define SSBI_REG_ADDR_IRQ_ROOT (SSBI_REG_ADDR_IRQ_BASE + 0)
-#define SSBI_REG_ADDR_IRQ_M_STATUS1 (SSBI_REG_ADDR_IRQ_BASE + 1)
-#define SSBI_REG_ADDR_IRQ_M_STATUS2 (SSBI_REG_ADDR_IRQ_BASE + 2)
-#define SSBI_REG_ADDR_IRQ_M_STATUS3 (SSBI_REG_ADDR_IRQ_BASE + 3)
-#define SSBI_REG_ADDR_IRQ_M_STATUS4 (SSBI_REG_ADDR_IRQ_BASE + 4)
-#define SSBI_REG_ADDR_IRQ_BLK_SEL (SSBI_REG_ADDR_IRQ_BASE + 5)
-#define SSBI_REG_ADDR_IRQ_IT_STATUS (SSBI_REG_ADDR_IRQ_BASE + 6)
-#define SSBI_REG_ADDR_IRQ_CONFIG (SSBI_REG_ADDR_IRQ_BASE + 7)
-#define SSBI_REG_ADDR_IRQ_RT_STATUS (SSBI_REG_ADDR_IRQ_BASE + 8)
-
-#define PM8058_IRQF_LVL_SEL 0x01 /* level select */
-#define PM8058_IRQF_MASK_FE 0x02 /* mask falling edge */
-#define PM8058_IRQF_MASK_RE 0x04 /* mask rising edge */
-#define PM8058_IRQF_CLR 0x08 /* clear interrupt */
-#define PM8058_IRQF_BITS_MASK 0x70
-#define PM8058_IRQF_BITS_SHIFT 4
-#define PM8058_IRQF_WRITE 0x80
-
-#define PM8058_IRQF_MASK_ALL (PM8058_IRQF_MASK_FE | \
- PM8058_IRQF_MASK_RE)
-#define PM8058_IRQF_W_C_M (PM8058_IRQF_WRITE | \
- PM8058_IRQF_CLR | \
- PM8058_IRQF_MASK_ALL)
-
-/* MISC register */
-#define SSBI_REG_ADDR_MISC 0x1CC
+#define REG_TEMP_ALRM_CTRL 0x1B
+#define REG_TEMP_ALRM_PWM 0x9B
/* PON CNTL 1 register */
#define SSBI_REG_ADDR_PON_CNTL_1 0x01C
@@ -138,53 +116,32 @@
/* GP_TEST1 register */
#define SSBI_REG_ADDR_GP_TEST_1 0x07A
-/* IRQ */
-#define MAX_PM_IRQ 256
-#define MAX_PM_BLOCKS (MAX_PM_IRQ / 8 + 1)
-#define MAX_PM_MASTERS (MAX_PM_BLOCKS / 8 + 1)
+#define PM8058_RTC_BASE 0x1E8
+#define PM8058_OTHC_CNTR_BASE0 0xA0
+#define PM8058_OTHC_CNTR_BASE1 0x134
+#define PM8058_OTHC_CNTR_BASE2 0x137
+
+#define SINGLE_IRQ_RESOURCE(_name, _irq) \
+{ \
+ .name = _name, \
+ .start = _irq, \
+ .end = _irq, \
+ .flags = IORESOURCE_IRQ, \
+}
struct pm8058_chip {
struct pm8058_platform_data pdata;
struct device *dev;
+ struct pm_irq_chip *irq_chip;
+ struct mfd_cell *mfd_regulators, *mfd_xo_buffers;
- u8 irqs_allowed[MAX_PM_BLOCKS];
- u8 blocks_allowed[MAX_PM_MASTERS];
- u8 masters_allowed;
- int pm_max_irq;
- int pm_max_blocks;
- int pm_max_masters;
-
- u8 config[MAX_PM_IRQ];
- u8 bus_unlock_config[MAX_PM_IRQ];
- u8 wake_enable[MAX_PM_IRQ];
- u16 count_wakeable;
-
- u8 revision;
+ u8 revision;
struct mutex pm_lock;
};
-#if defined(CONFIG_DEBUG_FS)
-struct pm8058_dbg_device {
- struct mutex dbg_mutex;
- struct pm8058_chip *pm_chip;
- struct dentry *dent;
- int addr;
-};
-
-static struct pm8058_dbg_device *pmic_dbg_device;
-#endif
-
static struct pm8058_chip *pmic_chip;
-/* Helper Functions */
-DEFINE_RATELIMIT_STATE(pm8058_msg_ratelimit, 60 * HZ, 10);
-
-static inline int pm8058_can_print(void)
-{
- return __ratelimit(&pm8058_msg_ratelimit);
-}
-
static inline int
ssbi_read(struct device *dev, u16 addr, u8 *buf, size_t len)
{
@@ -223,111 +180,6 @@
return rc;
}
-/* External APIs */
-int pm8058_rev(struct pm8058_chip *chip)
-{
- if (chip == NULL)
- return -EINVAL;
-
- return chip->revision;
-}
-EXPORT_SYMBOL(pm8058_rev);
-
-int pm8058_irq_get_rt_status(struct pm8058_chip *chip, int irq)
-{
- int rc;
- u8 block, bits, bit;
-
- if (chip == NULL || irq < chip->pdata.irq_base ||
- irq >= chip->pdata.irq_base + MAX_PM_IRQ)
- return -EINVAL;
-
- irq -= chip->pdata.irq_base;
-
- block = irq / 8;
- bit = irq % 8;
-
- mutex_lock(&chip->pm_lock);
-
- rc = ssbi_write(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, &block, 1);
- if (rc) {
- pr_err("%s: FAIL ssbi_write(): rc=%d (Select Block)\n",
- __func__, rc);
- goto bail_out;
- }
-
- rc = ssbi_read(chip->dev, SSBI_REG_ADDR_IRQ_RT_STATUS, &bits, 1);
- if (rc) {
- pr_err("%s: FAIL ssbi_read(): rc=%d (Read RT Status)\n",
- __func__, rc);
- goto bail_out;
- }
-
- rc = (bits & (1 << bit)) ? 1 : 0;
-
-bail_out:
- mutex_unlock(&chip->pm_lock);
-
- return rc;
-}
-EXPORT_SYMBOL(pm8058_irq_get_rt_status);
-
-int pm8058_read(struct pm8058_chip *chip, u16 addr, u8 *values,
- unsigned int len)
-{
- if (chip == NULL)
- return -EINVAL;
-
- return ssbi_read(chip->dev, addr, values, len);
-}
-EXPORT_SYMBOL(pm8058_read);
-
-int pm8058_write(struct pm8058_chip *chip, u16 addr, u8 *values,
- unsigned int len)
-{
- if (chip == NULL)
- return -EINVAL;
-
- return ssbi_write(chip->dev, addr, values, len);
-}
-EXPORT_SYMBOL(pm8058_write);
-
-int pm8058_misc_control(struct pm8058_chip *chip, int mask, int flag)
-{
- int rc;
- u8 misc;
-
- if (chip == NULL)
- chip = pmic_chip; /* for calls from non child */
- if (chip == NULL)
- return -ENODEV;
-
- mutex_lock(&chip->pm_lock);
-
- rc = ssbi_read(chip->dev, SSBI_REG_ADDR_MISC, &misc, 1);
- if (rc) {
- pr_err("%s: FAIL ssbi_read(0x%x): rc=%d\n",
- __func__, SSBI_REG_ADDR_MISC, rc);
- goto get_out;
- }
-
- misc &= ~mask;
- misc |= flag;
-
- rc = ssbi_write(chip->dev, SSBI_REG_ADDR_MISC, &misc, 1);
- if (rc) {
- pr_err("%s: FAIL ssbi_write(0x%x)=0x%x: rc=%d\n",
- __func__, SSBI_REG_ADDR_MISC, misc, rc);
- goto get_out;
- }
-
-get_out:
- mutex_unlock(&chip->pm_lock);
-
- return rc;
-}
-EXPORT_SYMBOL(pm8058_misc_control);
-
/**
* pm8058_smpl_control - enables/disables SMPL detection
* @enable: 0 = shutdown PMIC on power loss, 1 = reset PMIC on power loss
@@ -713,765 +565,695 @@
}
EXPORT_SYMBOL(pm8058_hard_reset_config);
-/* Internal functions */
-static inline int
-pm8058_config_irq(struct pm8058_chip *chip, u8 *bp, u8 *cp)
+static int pm8058_readb(const struct device *dev, u16 addr, u8 *val)
{
- int rc;
+ const struct pm8xxx_drvdata *pm8058_drvdata = dev_get_drvdata(dev);
+ const struct pm8058_chip *pmic = pm8058_drvdata->pm_chip_data;
- rc = ssbi_write(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp, 1);
- if (rc) {
- pr_err("%s: ssbi_write: rc=%d (Select block)\n",
- __func__, rc);
- goto bail_out;
- }
-
- rc = ssbi_write(chip->dev, SSBI_REG_ADDR_IRQ_CONFIG, cp, 1);
- if (rc)
- pr_err("%s: ssbi_write: rc=%d (Configure IRQ)\n",
- __func__, rc);
-
-bail_out:
- return rc;
+ return msm_ssbi_read(pmic->dev->parent, addr, val, 1);
}
-static void pm8058_irq_mask(struct irq_data *data)
+static int pm8058_writeb(const struct device *dev, u16 addr, u8 val)
{
- int master, irq_bit;
- struct pm8058_chip *chip = irq_data_get_irq_chip_data(data);
- u8 block, config;
- unsigned int irq = data->irq;
+ const struct pm8xxx_drvdata *pm8058_drvdata = dev_get_drvdata(dev);
+ const struct pm8058_chip *pmic = pm8058_drvdata->pm_chip_data;
- irq -= chip->pdata.irq_base;
- block = irq / 8;
- master = block / 8;
- irq_bit = irq % 8;
-
- chip->irqs_allowed[block] &= ~(1 << irq_bit);
- if (!chip->irqs_allowed[block]) {
- chip->blocks_allowed[master] &= ~(1 << (block % 8));
-
- if (!chip->blocks_allowed[master])
- chip->masters_allowed &= ~(1 << master);
- }
-
- config = PM8058_IRQF_WRITE | chip->config[irq] |
- PM8058_IRQF_MASK_FE | PM8058_IRQF_MASK_RE;
- chip->bus_unlock_config[irq] = config;
+ return msm_ssbi_write(pmic->dev->parent, addr, &val, 1);
}
-static void pm8058_irq_unmask(struct irq_data *data)
+static int pm8058_read_buf(const struct device *dev, u16 addr, u8 *buf,
+ int cnt)
{
- int master, irq_bit;
- struct pm8058_chip *chip = irq_data_get_irq_chip_data(data);
- u8 block, config, old_irqs_allowed, old_blocks_allowed;
- unsigned int irq = data->irq;
+ const struct pm8xxx_drvdata *pm8058_drvdata = dev_get_drvdata(dev);
+ const struct pm8058_chip *pmic = pm8058_drvdata->pm_chip_data;
- irq -= chip->pdata.irq_base;
- block = irq / 8;
- master = block / 8;
- irq_bit = irq % 8;
-
- old_irqs_allowed = chip->irqs_allowed[block];
- if (old_irqs_allowed & (1 << irq_bit)) {
- pr_debug("%s: no need to enable an already enabled irq=%d\n",
- __func__, irq + chip->pdata.irq_base);
- return;
- }
-
- chip->irqs_allowed[block] |= 1 << irq_bit;
- if (!old_irqs_allowed) {
- master = block / 8;
-
- old_blocks_allowed = chip->blocks_allowed[master];
- chip->blocks_allowed[master] |= 1 << (block % 8);
-
- if (!old_blocks_allowed)
- chip->masters_allowed |= 1 << master;
- }
-
- config = PM8058_IRQF_WRITE | chip->config[irq];
- chip->bus_unlock_config[irq] = config;
+ return msm_ssbi_read(pmic->dev->parent, addr, buf, cnt);
}
-static void pm8058_irq_ack(struct irq_data *data)
+static int pm8058_write_buf(const struct device *dev, u16 addr, u8 *buf,
+ int cnt)
{
- struct pm8058_chip *chip = irq_data_get_irq_chip_data(data);
- u8 block, config;
- unsigned int irq = data->irq;
+ const struct pm8xxx_drvdata *pm8058_drvdata = dev_get_drvdata(dev);
+ const struct pm8058_chip *pmic = pm8058_drvdata->pm_chip_data;
- irq -= chip->pdata.irq_base;
- block = irq / 8;
-
- config = PM8058_IRQF_WRITE | chip->config[irq] | PM8058_IRQF_CLR;
- /* Keep the mask */
- if (!(chip->irqs_allowed[block] & (1 << (irq % 8))))
- config |= PM8058_IRQF_MASK_FE | PM8058_IRQF_MASK_RE;
- chip->bus_unlock_config[irq] = config;
+ return msm_ssbi_write(pmic->dev->parent, addr, buf, cnt);
}
-static int pm8058_irq_set_type(struct irq_data *data, unsigned int flow_type)
+static int pm8058_read_irq_stat(const struct device *dev, int irq)
{
- int master, irq_bit;
- struct pm8058_chip *chip = irq_data_get_irq_chip_data(data);
- u8 block, config;
- unsigned int irq = data->irq;
+ const struct pm8xxx_drvdata *pm8058_drvdata = dev_get_drvdata(dev);
+ const struct pm8058_chip *pmic = pm8058_drvdata->pm_chip_data;
- irq -= chip->pdata.irq_base;
- if (irq > chip->pm_max_irq) {
- chip->pm_max_irq = irq;
- chip->pm_max_blocks =
- chip->pm_max_irq / 8 + 1;
- chip->pm_max_masters =
- chip->pm_max_blocks / 8 + 1;
- }
- block = irq / 8;
- master = block / 8;
- irq_bit = irq % 8;
-
- chip->config[irq] = (irq_bit << PM8058_IRQF_BITS_SHIFT) |
- PM8058_IRQF_MASK_RE | PM8058_IRQF_MASK_FE;
- if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
- if (flow_type & IRQF_TRIGGER_RISING)
- chip->config[irq] &= ~PM8058_IRQF_MASK_RE;
- if (flow_type & IRQF_TRIGGER_FALLING)
- chip->config[irq] &= ~PM8058_IRQF_MASK_FE;
- } else {
- chip->config[irq] |= PM8058_IRQF_LVL_SEL;
-
- if (flow_type & IRQF_TRIGGER_HIGH)
- chip->config[irq] &= ~PM8058_IRQF_MASK_RE;
- else
- chip->config[irq] &= ~PM8058_IRQF_MASK_FE;
- }
-
- config = PM8058_IRQF_WRITE | chip->config[irq] | PM8058_IRQF_CLR;
- chip->bus_unlock_config[irq] = config;
- return 0;
-}
-
-static int pm8058_irq_set_wake(struct irq_data *data, unsigned int on)
-{
- struct pm8058_chip *chip = irq_data_get_irq_chip_data(data);
- unsigned int irq = data->irq;
-
- irq -= chip->pdata.irq_base;
- if (on) {
- if (!chip->wake_enable[irq]) {
- chip->wake_enable[irq] = 1;
- chip->count_wakeable++;
- }
- } else {
- if (chip->wake_enable[irq]) {
- chip->wake_enable[irq] = 0;
- chip->count_wakeable--;
- }
- }
+ return pm8xxx_get_irq_stat(pmic->irq_chip, irq);
return 0;
}
-static void pm8058_irq_bus_lock(struct irq_data *data)
+static enum pm8xxx_version pm8058_get_version(const struct device *dev)
{
- u8 block;
- struct pm8058_chip *chip = irq_data_get_irq_chip_data(data);
- unsigned int irq = data->irq;
+ const struct pm8xxx_drvdata *pm8058_drvdata = dev_get_drvdata(dev);
+ const struct pm8058_chip *pmic = pm8058_drvdata->pm_chip_data;
+ enum pm8xxx_version version = -ENODEV;
- irq -= chip->pdata.irq_base;
- block = irq / 8;
- chip->bus_unlock_config[irq] = 0;
+ if ((pmic->revision & PM8058_VERSION_MASK) == PM8058_VERSION_VALUE)
+ version = PM8XXX_VERSION_8058;
- mutex_lock(&chip->pm_lock);
+ return version;
}
-static void pm8058_irq_bus_sync_unlock(struct irq_data *data)
+static int pm8058_get_revision(const struct device *dev)
{
- u8 block, config;
- struct pm8058_chip *chip = irq_data_get_irq_chip_data(data);
- unsigned int irq = data->irq;
+ const struct pm8xxx_drvdata *pm8058_drvdata = dev_get_drvdata(dev);
+ const struct pm8058_chip *pmic = pm8058_drvdata->pm_chip_data;
- irq -= chip->pdata.irq_base;
- block = irq / 8;
- config = chip->bus_unlock_config[irq];
- /* dont waste cpu cycles if we dont have data to write */
- if (config)
- pm8058_config_irq(chip, &block, &config);
- mutex_unlock(&chip->pm_lock);
+ return pmic->revision & PM8058_REVISION_MASK;
}
-static inline int
-pm8058_read_root(struct pm8058_chip *chip, u8 *rp)
-{
- int rc;
-
- rc = ssbi_read(chip->dev, SSBI_REG_ADDR_IRQ_ROOT, rp, 1);
- if (rc) {
- pr_err("%s: FAIL ssbi_read(): rc=%d (Read Root)\n",
- __func__, rc);
- *rp = 0;
- }
-
- return rc;
-}
-
-static inline int
-pm8058_read_master(struct pm8058_chip *chip, u8 m, u8 *bp)
-{
- int rc;
-
- rc = ssbi_read(chip->dev, SSBI_REG_ADDR_IRQ_M_STATUS1 + m, bp, 1);
- if (rc) {
- pr_err("%s: FAIL ssbi_read(): rc=%d (Read Master)\n",
- __func__, rc);
- *bp = 0;
- }
-
- return rc;
-}
-
-static inline int
-pm8058_read_block(struct pm8058_chip *chip, u8 *bp, u8 *ip)
-{
- int rc;
-
- rc = ssbi_write(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp, 1);
- if (rc) {
- pr_err("%s: FAIL ssbi_write(): rc=%d (Select Block)\n",
- __func__, rc);
- *bp = 0;
- goto bail_out;
- }
-
- rc = ssbi_read(chip->dev, SSBI_REG_ADDR_IRQ_IT_STATUS, ip, 1);
- if (rc)
- pr_err("%s: FAIL ssbi_read(): rc=%d (Read Status)\n",
- __func__, rc);
-
-bail_out:
- return rc;
-}
-
-static irqreturn_t pm8058_isr_thread(int irq_requested, void *data)
-{
- struct pm8058_chip *chip = data;
- int i, j, k;
- u8 root, block, config, bits;
- u8 blocks[MAX_PM_MASTERS];
- int masters = 0, irq, handled = 0, spurious = 0;
- u16 irqs_to_handle[MAX_PM_IRQ];
-
- mutex_lock(&chip->pm_lock);
-
- /* Read root for masters */
- if (pm8058_read_root(chip, &root))
- goto bail_out;
-
- masters = root >> 1;
-
- if (!(masters & chip->masters_allowed) ||
- (masters & ~chip->masters_allowed)) {
- spurious = 1000000;
- }
-
- /* Read allowed masters for blocks. */
- for (i = 0; i < chip->pm_max_masters; i++) {
- if (masters & (1 << i)) {
- if (pm8058_read_master(chip, i, &blocks[i]))
- goto bail_out;
-
- if (!blocks[i]) {
- if (pm8058_can_print())
- pr_err("%s: Spurious master: %d "
- "(blocks=0)", __func__, i);
- spurious += 10000;
- }
- } else
- blocks[i] = 0;
- }
-
- /* Select block, read status and call isr */
- for (i = 0; i < chip->pm_max_masters; i++) {
- if (!blocks[i])
- continue;
-
- for (j = 0; j < 8; j++) {
- if (!(blocks[i] & (1 << j)))
- continue;
-
- block = i * 8 + j; /* block # */
- if (pm8058_read_block(chip, &block, &bits))
- goto bail_out;
-
- if (!bits) {
- if (pm8058_can_print())
- pr_err("%s: Spurious block: "
- "[master, block]=[%d, %d] "
- "(bits=0)\n", __func__, i, j);
- spurious += 100;
- continue;
- }
-
- /* Check IRQ bits */
- for (k = 0; k < 8; k++) {
- if (!(bits & (1 << k)))
- continue;
-
- /* Check spurious interrupts */
- if (((1 << i) & chip->masters_allowed) &&
- (blocks[i] & chip->blocks_allowed[i]) &&
- (bits & chip->irqs_allowed[block])) {
-
- /* Found one */
- irq = block * 8 + k;
- irqs_to_handle[handled] = irq +
- chip->pdata.irq_base;
- handled++;
- } else {
- /* Clear and mask wrong one */
- config = PM8058_IRQF_W_C_M |
- (k << PM8058_IRQF_BITS_SHIFT);
-
- pm8058_config_irq(chip,
- &block, &config);
-
- if (pm8058_can_print())
- pr_err("%s: Spurious IRQ: "
- "[master, block, bit]="
- "[%d, %d (%d), %d]\n",
- __func__,
- i, j, block, k);
- spurious++;
- }
- }
- }
-
- }
-
-bail_out:
-
- mutex_unlock(&chip->pm_lock);
-
- for (i = 0; i < handled; i++) {
- int pmic_irq = irqs_to_handle[i] - chip->pdata.irq_base;
-
- /* ack the interrupt first */
- block = pmic_irq / 8 ;
- config = PM8058_IRQF_WRITE | chip->config[pmic_irq]
- | PM8058_IRQF_CLR;
- pm8058_config_irq(chip, &block, &config);
-
- /* calle the action handler */
- handle_nested_irq(irqs_to_handle[i]);
- }
-
- if (spurious) {
- if (!pm8058_can_print())
- return IRQ_HANDLED;
-
- pr_err("%s: spurious = %d (handled = %d)\n",
- __func__, spurious, handled);
- pr_err(" root = 0x%x (masters_allowed<<1 = 0x%x)\n",
- root, chip->masters_allowed << 1);
- for (i = 0; i < chip->pm_max_masters; i++) {
- if (masters & (1 << i))
- pr_err(" blocks[%d]=0x%x, "
- "allowed[%d]=0x%x\n",
- i, blocks[i],
- i, chip->blocks_allowed[i]);
- }
- }
-
- return IRQ_HANDLED;
-}
-
-#if defined(CONFIG_DEBUG_FS)
-
-static int check_addr(int addr, const char *func_name)
-{
- if (addr < 0 || addr > 0x3FF) {
- pr_err("%s: PMIC 8058 register address is invalid: %d\n",
- func_name, addr);
- return -EINVAL;
- }
- return 0;
-}
-
-static int data_set(void *data, u64 val)
-{
- struct pm8058_dbg_device *dbgdev = data;
- u8 reg = val;
- int rc;
-
- mutex_lock(&dbgdev->dbg_mutex);
-
- rc = check_addr(dbgdev->addr, __func__);
- if (rc)
- goto done;
-
- rc = pm8058_write(dbgdev->pm_chip, dbgdev->addr, ®, 1);
-
- if (rc)
- pr_err("%s: FAIL pm8058_write(0x%03X)=0x%02X: rc=%d\n",
- __func__, dbgdev->addr, reg, rc);
-done:
- mutex_unlock(&dbgdev->dbg_mutex);
- return rc;
-}
-
-static int data_get(void *data, u64 *val)
-{
- struct pm8058_dbg_device *dbgdev = data;
- int rc;
- u8 reg;
-
- mutex_lock(&dbgdev->dbg_mutex);
-
- rc = check_addr(dbgdev->addr, __func__);
- if (rc)
- goto done;
-
- rc = pm8058_read(dbgdev->pm_chip, dbgdev->addr, ®, 1);
-
- if (rc) {
- pr_err("%s: FAIL pm8058_read(0x%03X)=0x%02X: rc=%d\n",
- __func__, dbgdev->addr, reg, rc);
- goto done;
- }
-
- *val = reg;
-done:
- mutex_unlock(&dbgdev->dbg_mutex);
- return rc;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(dbg_data_fops, data_get, data_set, "0x%02llX\n");
-
-static int addr_set(void *data, u64 val)
-{
- struct pm8058_dbg_device *dbgdev = data;
- int rc;
-
- rc = check_addr(val, __func__);
- if (rc)
- return rc;
-
- mutex_lock(&dbgdev->dbg_mutex);
- dbgdev->addr = val;
- mutex_unlock(&dbgdev->dbg_mutex);
-
- return 0;
-}
-
-static int addr_get(void *data, u64 *val)
-{
- struct pm8058_dbg_device *dbgdev = data;
- int rc;
-
- mutex_lock(&dbgdev->dbg_mutex);
-
- rc = check_addr(dbgdev->addr, __func__);
- if (rc) {
- mutex_unlock(&dbgdev->dbg_mutex);
- return rc;
- }
- *val = dbgdev->addr;
-
- mutex_unlock(&dbgdev->dbg_mutex);
-
- return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(dbg_addr_fops, addr_get, addr_set, "0x%03llX\n");
-
-static int __devinit pmic8058_dbg_probe(struct pm8058_chip *chip)
-{
- struct pm8058_dbg_device *dbgdev;
- struct dentry *dent;
- struct dentry *temp;
- int rc;
-
- if (chip == NULL) {
- pr_err("%s: no parent data passed in.\n", __func__);
- return -EINVAL;
- }
-
- dbgdev = kzalloc(sizeof *dbgdev, GFP_KERNEL);
- if (dbgdev == NULL) {
- pr_err("%s: kzalloc() failed.\n", __func__);
- return -ENOMEM;
- }
-
- dbgdev->pm_chip = chip;
- dbgdev->addr = -1;
-
- dent = debugfs_create_dir("pm8058-dbg", NULL);
- if (dent == NULL || IS_ERR(dent)) {
- pr_err("%s: ERR debugfs_create_dir: dent=0x%X\n",
- __func__, (unsigned)dent);
- rc = PTR_ERR(dent);
- goto dir_error;
- }
-
- temp = debugfs_create_file("addr", S_IRUSR | S_IWUSR, dent,
- dbgdev, &dbg_addr_fops);
- if (temp == NULL || IS_ERR(temp)) {
- pr_err("%s: ERR debugfs_create_file: dent=0x%X\n",
- __func__, (unsigned)temp);
- rc = PTR_ERR(temp);
- goto debug_error;
- }
-
- temp = debugfs_create_file("data", S_IRUSR | S_IWUSR, dent,
- dbgdev, &dbg_data_fops);
- if (temp == NULL || IS_ERR(temp)) {
- pr_err("%s: ERR debugfs_create_file: dent=0x%X\n",
- __func__, (unsigned)temp);
- rc = PTR_ERR(temp);
- goto debug_error;
- }
-
- mutex_init(&dbgdev->dbg_mutex);
-
- dbgdev->dent = dent;
-
- pmic_dbg_device = dbgdev;
-
- return 0;
-
-debug_error:
- debugfs_remove_recursive(dent);
-dir_error:
- kfree(dbgdev);
-
- return rc;
-}
-
-static int __devexit pmic8058_dbg_remove(void)
-{
- if (pmic_dbg_device) {
- debugfs_remove_recursive(pmic_dbg_device->dent);
- mutex_destroy(&pmic_dbg_device->dbg_mutex);
- kfree(pmic_dbg_device);
- }
- return 0;
-}
-
-#else
-
-static int __devinit pmic8058_dbg_probe(struct pm8058_chip *chip)
-{
- return 0;
-}
-
-static int __devexit pmic8058_dbg_remove(void)
-{
- return 0;
-}
-
-#endif
-
-static struct irq_chip pm8058_irq_chip = {
- .name = "pm8058",
- .irq_ack = pm8058_irq_ack,
- .irq_mask = pm8058_irq_mask,
- .irq_unmask = pm8058_irq_unmask,
- .irq_set_type = pm8058_irq_set_type,
- .irq_set_wake = pm8058_irq_set_wake,
- .irq_bus_lock = pm8058_irq_bus_lock,
- .irq_bus_sync_unlock = pm8058_irq_bus_sync_unlock,
+static struct pm8xxx_drvdata pm8058_drvdata = {
+ .pmic_readb = pm8058_readb,
+ .pmic_writeb = pm8058_writeb,
+ .pmic_read_buf = pm8058_read_buf,
+ .pmic_write_buf = pm8058_write_buf,
+ .pmic_read_irq_stat = pm8058_read_irq_stat,
+ .pmic_get_version = pm8058_get_version,
+ .pmic_get_revision = pm8058_get_revision,
};
-static int pm8058_suspend(void)
-{
- struct pm8058_chip *chip = pmic_chip;
- struct irq_data *data;
- int i;
-
- for (i = 0; i < MAX_PM_IRQ; i++) {
- if (chip->config[i] && !chip->wake_enable[i]) {
- if (!((chip->config[i] & PM8058_IRQF_MASK_ALL)
- == PM8058_IRQF_MASK_ALL)) {
- data = irq_get_irq_data(i +
- chip->pdata.irq_base);
- pm8058_irq_bus_lock(data);
- pm8058_irq_mask(data);
- pm8058_irq_bus_sync_unlock(data);
- }
- }
- }
-
- if (!chip->count_wakeable)
- disable_irq(chip->pdata.irq);
-
- return 0;
-}
-
-extern int msm_show_resume_irq_mask;
-
-static void pm8058_show_resume_irq(void)
-{
- u8 block, bits;
- int i;
- struct pm8058_chip *chip = pmic_chip;
-
- if (!msm_show_resume_irq_mask)
- return;
-
- for (i = 0; i < MAX_PM_IRQ; i++) {
- if (chip->wake_enable[i]) {
- block = i / 8;
- if (!pm8058_read_block(chip, &block, &bits)) {
- if (bits & (1 << (i & 0x7)))
- pr_warning("%s:%d triggered\n",
- __func__, i + chip->pdata.irq_base);
- }
- }
- }
-}
-
-static void pm8058_resume(void)
-{
- struct pm8058_chip *chip = pmic_chip;
- struct irq_data *data;
- int i;
-
- pm8058_show_resume_irq();
-
- for (i = 0; i < MAX_PM_IRQ; i++) {
- if (chip->config[i] && !chip->wake_enable[i]) {
- if (!((chip->config[i] & PM8058_IRQF_MASK_ALL)
- == PM8058_IRQF_MASK_ALL)) {
- data = irq_get_irq_data(i +
- chip->pdata.irq_base);
- pm8058_irq_bus_lock(data);
- pm8058_irq_unmask(data);
- pm8058_irq_bus_sync_unlock(data);
- }
- }
- }
-
- if (!chip->count_wakeable)
- enable_irq(chip->pdata.irq);
-}
-
-static struct syscore_ops pm8058_pm = {
- .suspend = pm8058_suspend,
- .resume = pm8058_resume,
+static const struct resource pm8058_charger_resources[] __devinitconst = {
+ SINGLE_IRQ_RESOURCE("CHGVAL", PM8058_CHGVAL_IRQ),
+ SINGLE_IRQ_RESOURCE("CHGINVAL", PM8058_CHGINVAL_IRQ),
+ SINGLE_IRQ_RESOURCE("CHGILIM", PM8058_CHGILIM_IRQ),
+ SINGLE_IRQ_RESOURCE("VCP", PM8058_VCP_IRQ),
+ SINGLE_IRQ_RESOURCE("ATC_DONE", PM8058_ATC_DONE_IRQ),
+ SINGLE_IRQ_RESOURCE("ATCFAIL", PM8058_ATCFAIL_IRQ),
+ SINGLE_IRQ_RESOURCE("AUTO_CHGDONE", PM8058_AUTO_CHGDONE_IRQ),
+ SINGLE_IRQ_RESOURCE("AUTO_CHGFAIL", PM8058_AUTO_CHGFAIL_IRQ),
+ SINGLE_IRQ_RESOURCE("CHGSTATE", PM8058_CHGSTATE_IRQ),
+ SINGLE_IRQ_RESOURCE("FASTCHG", PM8058_FASTCHG_IRQ),
+ SINGLE_IRQ_RESOURCE("CHG_END", PM8058_CHG_END_IRQ),
+ SINGLE_IRQ_RESOURCE("BATTTEMP", PM8058_BATTTEMP_IRQ),
+ SINGLE_IRQ_RESOURCE("CHGHOT", PM8058_CHGHOT_IRQ),
+ SINGLE_IRQ_RESOURCE("CHGTLIMIT", PM8058_CHGTLIMIT_IRQ),
+ SINGLE_IRQ_RESOURCE("CHG_GONE", PM8058_CHG_GONE_IRQ),
+ SINGLE_IRQ_RESOURCE("VCPMAJOR", PM8058_VCPMAJOR_IRQ),
+ SINGLE_IRQ_RESOURCE("VBATDET", PM8058_VBATDET_IRQ),
+ SINGLE_IRQ_RESOURCE("BATFET", PM8058_BATFET_IRQ),
+ SINGLE_IRQ_RESOURCE("BATT_REPLACE", PM8058_BATT_REPLACE_IRQ),
+ SINGLE_IRQ_RESOURCE("BATTCONNECT", PM8058_BATTCONNECT_IRQ),
+ SINGLE_IRQ_RESOURCE("VBATDET_LOW", PM8058_VBATDET_LOW_IRQ),
};
+static struct mfd_cell pm8058_charger_cell __devinitdata = {
+ .name = "pm8058-charger",
+ .id = -1,
+ .resources = pm8058_charger_resources,
+ .num_resources = ARRAY_SIZE(pm8058_charger_resources),
+};
+
+static const struct resource misc_cell_resources[] __devinitconst = {
+ SINGLE_IRQ_RESOURCE("pm8xxx_osc_halt_irq", PM8058_OSCHALT_IRQ),
+};
+
+static struct mfd_cell misc_cell __devinitdata = {
+ .name = PM8XXX_MISC_DEV_NAME,
+ .id = -1,
+ .resources = misc_cell_resources,
+ .num_resources = ARRAY_SIZE(misc_cell_resources),
+};
+
+static struct mfd_cell pm8058_pwm_cell __devinitdata = {
+ .name = "pm8058-pwm",
+ .id = -1,
+};
+
+static struct resource xoadc_resources[] = {
+ SINGLE_IRQ_RESOURCE(NULL, PM8058_ADC_IRQ),
+};
+
+static struct mfd_cell xoadc_cell __devinitdata = {
+ .name = "pm8058-xoadc",
+ .id = -1,
+ .resources = xoadc_resources,
+ .num_resources = ARRAY_SIZE(xoadc_resources),
+};
+
+static const struct resource thermal_alarm_cell_resources[] __devinitconst = {
+ SINGLE_IRQ_RESOURCE("pm8058_tempstat_irq", PM8058_TEMPSTAT_IRQ),
+ SINGLE_IRQ_RESOURCE("pm8058_overtemp_irq", PM8058_OVERTEMP_IRQ),
+};
+
+static struct pm8xxx_tm_core_data thermal_alarm_cdata = {
+ .adc_channel = CHANNEL_ADC_DIE_TEMP,
+ .adc_type = PM8XXX_TM_ADC_PM8058_ADC,
+ .reg_addr_temp_alarm_ctrl = REG_TEMP_ALRM_CTRL,
+ .reg_addr_temp_alarm_pwm = REG_TEMP_ALRM_PWM,
+ .tm_name = "pm8058_tz",
+ .irq_name_temp_stat = "pm8058_tempstat_irq",
+ .irq_name_over_temp = "pm8058_overtemp_irq",
+};
+
+static struct mfd_cell thermal_alarm_cell __devinitdata = {
+ .name = PM8XXX_TM_DEV_NAME,
+ .id = -1,
+ .resources = thermal_alarm_cell_resources,
+ .num_resources = ARRAY_SIZE(thermal_alarm_cell_resources),
+ .platform_data = &thermal_alarm_cdata,
+ .pdata_size = sizeof(struct pm8xxx_tm_core_data),
+};
+
+static struct mfd_cell debugfs_cell __devinitdata = {
+ .name = "pm8xxx-debug",
+ .id = -1,
+ .platform_data = "pm8058-dbg",
+ .pdata_size = sizeof("pm8058-dbg"),
+};
+
+static const struct resource othc0_cell_resources[] __devinitconst = {
+ {
+ .name = "othc_base",
+ .start = PM8058_OTHC_CNTR_BASE0,
+ .end = PM8058_OTHC_CNTR_BASE0,
+ .flags = IORESOURCE_IO,
+ },
+};
+
+static const struct resource othc1_cell_resources[] __devinitconst = {
+ SINGLE_IRQ_RESOURCE(NULL, PM8058_SW_1_IRQ),
+ SINGLE_IRQ_RESOURCE(NULL, PM8058_IR_1_IRQ),
+ {
+ .name = "othc_base",
+ .start = PM8058_OTHC_CNTR_BASE1,
+ .end = PM8058_OTHC_CNTR_BASE1,
+ .flags = IORESOURCE_IO,
+ },
+};
+
+static const struct resource othc2_cell_resources[] __devinitconst = {
+ {
+ .name = "othc_base",
+ .start = PM8058_OTHC_CNTR_BASE2,
+ .end = PM8058_OTHC_CNTR_BASE2,
+ .flags = IORESOURCE_IO,
+ },
+};
+
+static const struct resource batt_alarm_cell_resources[] __devinitconst = {
+ SINGLE_IRQ_RESOURCE("pm8058_batt_alarm_irq", PM8058_BATT_ALARM_IRQ),
+};
+
+static struct mfd_cell leds_cell __devinitdata = {
+ .name = "pm8058-led",
+ .id = -1,
+};
+
+static struct mfd_cell othc0_cell __devinitdata = {
+ .name = "pm8058-othc",
+ .id = 0,
+ .resources = othc0_cell_resources,
+ .num_resources = ARRAY_SIZE(othc0_cell_resources),
+};
+
+static struct mfd_cell othc1_cell __devinitdata = {
+ .name = "pm8058-othc",
+ .id = 1,
+ .resources = othc1_cell_resources,
+ .num_resources = ARRAY_SIZE(othc1_cell_resources),
+};
+
+static struct mfd_cell othc2_cell __devinitdata = {
+ .name = "pm8058-othc",
+ .id = 2,
+ .resources = othc2_cell_resources,
+ .num_resources = ARRAY_SIZE(othc2_cell_resources),
+};
+
+static struct pm8xxx_batt_alarm_core_data batt_alarm_cdata = {
+ .irq_name = "pm8058_batt_alarm_irq",
+ .reg_addr_threshold = REG_BATT_ALARM_THRESH,
+ .reg_addr_ctrl1 = REG_BATT_ALARM_CTRL1,
+ .reg_addr_ctrl2 = REG_BATT_ALARM_CTRL2,
+ .reg_addr_pwm_ctrl = REG_BATT_ALARM_PWM_CTRL,
+};
+
+static struct mfd_cell batt_alarm_cell __devinitdata = {
+ .name = PM8XXX_BATT_ALARM_DEV_NAME,
+ .id = -1,
+ .resources = batt_alarm_cell_resources,
+ .num_resources = ARRAY_SIZE(batt_alarm_cell_resources),
+ .platform_data = &batt_alarm_cdata,
+ .pdata_size = sizeof(struct pm8xxx_batt_alarm_core_data),
+};
+
+static struct mfd_cell upl_cell __devinitdata = {
+ .name = PM8XXX_UPL_DEV_NAME,
+ .id = -1,
+};
+
+static struct mfd_cell nfc_cell __devinitdata = {
+ .name = PM8XXX_NFC_DEV_NAME,
+ .id = -1,
+};
+
+static const struct resource rtc_cell_resources[] __devinitconst = {
+ [0] = SINGLE_IRQ_RESOURCE(NULL, PM8058_RTC_ALARM_IRQ),
+ [1] = {
+ .name = "pmic_rtc_base",
+ .start = PM8058_RTC_BASE,
+ .end = PM8058_RTC_BASE,
+ .flags = IORESOURCE_IO,
+ },
+};
+
+static struct mfd_cell rtc_cell __devinitdata = {
+ .name = PM8XXX_RTC_DEV_NAME,
+ .id = -1,
+ .resources = rtc_cell_resources,
+ .num_resources = ARRAY_SIZE(rtc_cell_resources),
+};
+
+static const struct resource resources_pwrkey[] __devinitconst = {
+ SINGLE_IRQ_RESOURCE(NULL, PM8058_PWRKEY_REL_IRQ),
+ SINGLE_IRQ_RESOURCE(NULL, PM8058_PWRKEY_PRESS_IRQ),
+};
+
+static struct mfd_cell vibrator_cell __devinitdata = {
+ .name = PM8XXX_VIBRATOR_DEV_NAME,
+ .id = -1,
+};
+
+static struct mfd_cell pwrkey_cell __devinitdata = {
+ .name = PM8XXX_PWRKEY_DEV_NAME,
+ .id = -1,
+ .num_resources = ARRAY_SIZE(resources_pwrkey),
+ .resources = resources_pwrkey,
+};
+
+static const struct resource resources_keypad[] = {
+ SINGLE_IRQ_RESOURCE(NULL, PM8058_KEYPAD_IRQ),
+ SINGLE_IRQ_RESOURCE(NULL, PM8058_KEYSTUCK_IRQ),
+};
+
+static struct mfd_cell keypad_cell __devinitdata = {
+ .name = PM8XXX_KEYPAD_DEV_NAME,
+ .id = -1,
+ .num_resources = ARRAY_SIZE(resources_keypad),
+ .resources = resources_keypad,
+};
+
+static const struct resource mpp_cell_resources[] __devinitconst = {
+ {
+ .start = PM8058_IRQ_BLOCK_BIT(PM8058_MPP_BLOCK_START, 0),
+ .end = PM8058_IRQ_BLOCK_BIT(PM8058_MPP_BLOCK_START, 0)
+ + PM8058_MPPS - 1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mfd_cell mpp_cell __devinitdata = {
+ .name = PM8XXX_MPP_DEV_NAME,
+ .id = 0,
+ .resources = mpp_cell_resources,
+ .num_resources = ARRAY_SIZE(mpp_cell_resources),
+};
+
+static const struct resource gpio_cell_resources[] __devinitconst = {
+ [0] = {
+ .start = PM8058_IRQ_BLOCK_BIT(PM8058_GPIO_BLOCK_START, 0),
+ .end = PM8058_IRQ_BLOCK_BIT(PM8058_GPIO_BLOCK_START, 0)
+ + PM8058_GPIOS - 1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mfd_cell gpio_cell __devinitdata = {
+ .name = PM8XXX_GPIO_DEV_NAME,
+ .id = -1,
+ .resources = gpio_cell_resources,
+ .num_resources = ARRAY_SIZE(gpio_cell_resources),
+};
+
+static int __devinit
+pm8058_add_subdevices(const struct pm8058_platform_data *pdata,
+ struct pm8058_chip *pmic)
+{
+ int rc = 0, irq_base = 0, i;
+ struct pm_irq_chip *irq_chip;
+ static struct mfd_cell *mfd_regulators, *mfd_xo_buffers;
+
+ if (pdata->irq_pdata) {
+ pdata->irq_pdata->irq_cdata.nirqs = PM8058_NR_IRQS;
+ pdata->irq_pdata->irq_cdata.base_addr = REG_IRQ_BASE;
+ irq_base = pdata->irq_pdata->irq_base;
+ irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
+
+ if (IS_ERR(irq_chip)) {
+ pr_err("Failed to init interrupts ret=%ld\n",
+ PTR_ERR(irq_chip));
+ return PTR_ERR(irq_chip);
+ }
+ pmic->irq_chip = irq_chip;
+ }
+
+ if (pdata->gpio_pdata) {
+ pdata->gpio_pdata->gpio_cdata.ngpios = PM8058_GPIOS;
+ gpio_cell.platform_data = pdata->gpio_pdata;
+ gpio_cell.pdata_size = sizeof(struct pm8xxx_gpio_platform_data);
+ rc = mfd_add_devices(pmic->dev, 0, &gpio_cell, 1,
+ NULL, irq_base);
+ if (rc) {
+ pr_err("Failed to add gpio subdevice ret=%d\n", rc);
+ goto bail;
+ }
+ }
+
+ if (pdata->mpp_pdata) {
+ pdata->mpp_pdata->core_data.nmpps = PM8058_MPPS;
+ pdata->mpp_pdata->core_data.base_addr = REG_MPP_BASE;
+ mpp_cell.platform_data = pdata->mpp_pdata;
+ mpp_cell.pdata_size = sizeof(struct pm8xxx_mpp_platform_data);
+ rc = mfd_add_devices(pmic->dev, 0, &mpp_cell, 1, NULL,
+ irq_base);
+ if (rc) {
+ pr_err("Failed to add mpp subdevice ret=%d\n", rc);
+ goto bail;
+ }
+ }
+
+ if (pdata->num_regulators > 0 && pdata->regulator_pdatas) {
+ mfd_regulators = kzalloc(sizeof(struct mfd_cell)
+ * (pdata->num_regulators), GFP_KERNEL);
+ if (!mfd_regulators) {
+ pr_err("Cannot allocate %d bytes for pm8058 regulator "
+ "mfd cells\n", sizeof(struct mfd_cell)
+ * (pdata->num_regulators));
+ rc = -ENOMEM;
+ goto bail;
+ }
+ for (i = 0; i < pdata->num_regulators; i++) {
+ mfd_regulators[i].name = "pm8058-regulator";
+ mfd_regulators[i].id = pdata->regulator_pdatas[i].id;
+ mfd_regulators[i].platform_data =
+ &(pdata->regulator_pdatas[i]);
+ mfd_regulators[i].pdata_size =
+ sizeof(struct pm8058_vreg_pdata);
+ }
+ rc = mfd_add_devices(pmic->dev, 0, mfd_regulators,
+ pdata->num_regulators, NULL, irq_base);
+ if (rc) {
+ pr_err("Failed to add regulator subdevices ret=%d\n",
+ rc);
+ kfree(mfd_regulators);
+ goto bail;
+ }
+ pmic->mfd_regulators = mfd_regulators;
+ }
+
+ if (pdata->num_xo_buffers > 0 && pdata->xo_buffer_pdata) {
+ mfd_xo_buffers = kzalloc(sizeof(struct mfd_cell)
+ * (pdata->num_xo_buffers), GFP_KERNEL);
+ if (!mfd_xo_buffers) {
+ pr_err("Cannot allocate %d bytes for pm8058 XO buffer "
+ "mfd cells\n", sizeof(struct mfd_cell)
+ * (pdata->num_xo_buffers));
+ rc = -ENOMEM;
+ goto bail;
+ }
+ for (i = 0; i < pdata->num_xo_buffers; i++) {
+ mfd_xo_buffers[i].name = PM8058_XO_BUFFER_DEV_NAME;
+ mfd_xo_buffers[i].id = pdata->xo_buffer_pdata[i].id;
+ mfd_xo_buffers[i].platform_data =
+ &(pdata->xo_buffer_pdata[i]);
+ mfd_xo_buffers[i].pdata_size =
+ sizeof(struct pm8058_xo_pdata);
+ }
+ rc = mfd_add_devices(pmic->dev, 0, mfd_xo_buffers,
+ pdata->num_xo_buffers, NULL, irq_base);
+ if (rc) {
+ pr_err("Failed to add XO buffer subdevices ret=%d\n",
+ rc);
+ kfree(mfd_xo_buffers);
+ goto bail;
+ }
+ pmic->mfd_xo_buffers = mfd_xo_buffers;
+ }
+
+ if (pdata->keypad_pdata) {
+ keypad_cell.platform_data = pdata->keypad_pdata;
+ keypad_cell.pdata_size =
+ sizeof(struct pm8xxx_keypad_platform_data);
+ rc = mfd_add_devices(pmic->dev, 0, &keypad_cell, 1, NULL,
+ irq_base);
+ if (rc) {
+ pr_err("Failed to add keypad subdevice ret=%d\n", rc);
+ goto bail;
+ }
+ }
+
+ if (pdata->rtc_pdata) {
+ rtc_cell.platform_data = pdata->rtc_pdata;
+ rtc_cell.pdata_size = sizeof(struct pm8xxx_rtc_platform_data);
+ rc = mfd_add_devices(pmic->dev, 0, &rtc_cell, 1, NULL,
+ irq_base);
+ if (rc) {
+ pr_err("Failed to add rtc subdevice ret=%d\n", rc);
+ goto bail;
+ }
+ }
+
+ if (pdata->pwrkey_pdata) {
+ pwrkey_cell.platform_data = pdata->pwrkey_pdata;
+ pwrkey_cell.pdata_size =
+ sizeof(struct pm8xxx_pwrkey_platform_data);
+ rc = mfd_add_devices(pmic->dev, 0, &pwrkey_cell, 1, NULL,
+ irq_base);
+ if (rc) {
+ pr_err("Failed to add pwrkey subdevice ret=%d\n", rc);
+ goto bail;
+ }
+ }
+
+ if (pdata->vibrator_pdata) {
+ vibrator_cell.platform_data = pdata->vibrator_pdata;
+ vibrator_cell.pdata_size =
+ sizeof(struct pm8xxx_vibrator_platform_data);
+ rc = mfd_add_devices(pmic->dev, 0, &vibrator_cell, 1, NULL,
+ irq_base);
+ if (rc) {
+ pr_err("Failed to add vibrator subdevice ret=%d\n",
+ rc);
+ goto bail;
+ }
+ }
+
+ if (pdata->leds_pdata) {
+ leds_cell.platform_data = pdata->leds_pdata;
+ leds_cell.pdata_size =
+ sizeof(struct pmic8058_leds_platform_data);
+ rc = mfd_add_devices(pmic->dev, 0, &leds_cell, 1, NULL,
+ irq_base);
+ if (rc) {
+ pr_err("Failed to add leds subdevice ret=%d\n", rc);
+ goto bail;
+ }
+ }
+
+ if (pdata->xoadc_pdata) {
+ xoadc_cell.platform_data = pdata->xoadc_pdata;
+ xoadc_cell.pdata_size =
+ sizeof(struct xoadc_platform_data);
+ rc = mfd_add_devices(pmic->dev, 0, &xoadc_cell, 1, NULL,
+ irq_base);
+ if (rc) {
+ pr_err("Failed to add leds subdevice ret=%d\n", rc);
+ goto bail;
+ }
+ }
+
+ if (pdata->othc0_pdata) {
+ othc0_cell.platform_data = pdata->othc0_pdata;
+ othc0_cell.pdata_size =
+ sizeof(struct pmic8058_othc_config_pdata);
+ rc = mfd_add_devices(pmic->dev, 0, &othc0_cell, 1, NULL, 0);
+ if (rc) {
+ pr_err("Failed to add othc0 subdevice ret=%d\n", rc);
+ goto bail;
+ }
+ }
+
+ if (pdata->othc1_pdata) {
+ othc1_cell.platform_data = pdata->othc1_pdata;
+ othc1_cell.pdata_size =
+ sizeof(struct pmic8058_othc_config_pdata);
+ rc = mfd_add_devices(pmic->dev, 0, &othc1_cell, 1, NULL,
+ irq_base);
+ if (rc) {
+ pr_err("Failed to add othc1 subdevice ret=%d\n", rc);
+ goto bail;
+ }
+ }
+
+ if (pdata->othc2_pdata) {
+ othc2_cell.platform_data = pdata->othc2_pdata;
+ othc2_cell.pdata_size =
+ sizeof(struct pmic8058_othc_config_pdata);
+ rc = mfd_add_devices(pmic->dev, 0, &othc2_cell, 1, NULL, 0);
+ if (rc) {
+ pr_err("Failed to add othc2 subdevice ret=%d\n", rc);
+ goto bail;
+ }
+ }
+
+ if (pdata->pwm_pdata) {
+ pm8058_pwm_cell.platform_data = pdata->pwm_pdata;
+ pm8058_pwm_cell.pdata_size = sizeof(struct pm8058_pwm_pdata);
+ rc = mfd_add_devices(pmic->dev, 0, &pm8058_pwm_cell, 1, NULL,
+ irq_base);
+ if (rc) {
+ pr_err("Failed to add pwm subdevice ret=%d\n", rc);
+ goto bail;
+ }
+ }
+
+ if (pdata->misc_pdata) {
+ misc_cell.platform_data = pdata->misc_pdata;
+ misc_cell.pdata_size = sizeof(struct pm8xxx_misc_platform_data);
+ rc = mfd_add_devices(pmic->dev, 0, &misc_cell, 1, NULL,
+ irq_base);
+ if (rc) {
+ pr_err("Failed to add misc subdevice ret=%d\n", rc);
+ goto bail;
+ }
+ }
+
+ rc = mfd_add_devices(pmic->dev, 0, &thermal_alarm_cell, 1, NULL,
+ irq_base);
+ if (rc) {
+ pr_err("Failed to add thermal alarm subdevice ret=%d\n",
+ rc);
+ goto bail;
+ }
+
+ rc = mfd_add_devices(pmic->dev, 0, &batt_alarm_cell, 1, NULL,
+ irq_base);
+ if (rc) {
+ pr_err("Failed to add battery alarm subdevice ret=%d\n",
+ rc);
+ goto bail;
+ }
+
+ rc = mfd_add_devices(pmic->dev, 0, &upl_cell, 1, NULL, 0);
+ if (rc) {
+ pr_err("Failed to add upl subdevice ret=%d\n", rc);
+ goto bail;
+ }
+
+ rc = mfd_add_devices(pmic->dev, 0, &nfc_cell, 1, NULL, 0);
+ if (rc) {
+ pr_err("Failed to add upl subdevice ret=%d\n", rc);
+ goto bail;
+ }
+
+ if (pdata->charger_pdata) {
+ pm8058_charger_cell.platform_data = pdata->charger_pdata;
+ pm8058_charger_cell.pdata_size = sizeof(struct
+ pmic8058_charger_data);
+ rc = mfd_add_devices(pmic->dev, 0, &pm8058_charger_cell,
+ 1, NULL, irq_base);
+ if (rc) {
+ pr_err("Failed to add charger subdevice ret=%d\n", rc);
+ goto bail;
+ }
+ }
+
+ rc = mfd_add_devices(pmic->dev, 0, &debugfs_cell, 1, NULL, irq_base);
+ if (rc) {
+ pr_err("Failed to add debugfs subdevice ret=%d\n", rc);
+ goto bail;
+ }
+
+ return rc;
+bail:
+ if (pmic->irq_chip) {
+ pm8xxx_irq_exit(pmic->irq_chip);
+ pmic->irq_chip = NULL;
+ }
+ return rc;
+}
+
static int __devinit pm8058_probe(struct platform_device *pdev)
{
- int i, rc;
- struct pm8058_platform_data *pdata = pdev->dev.platform_data;
- struct pm8058_chip *chip;
+ int rc;
+ struct pm8058_platform_data *pdata = pdev->dev.platform_data;
+ struct pm8058_chip *pmic;
- if (pdata == NULL || !gpio_is_valid(pdata->irq)) {
+ if (pdata == NULL) {
pr_err("%s: No platform_data or IRQ.\n", __func__);
return -ENODEV;
}
- if (pdata->num_subdevs == 0) {
- pr_err("%s: No sub devices to support.\n", __func__);
- return -ENODEV;
- }
-
- chip = kzalloc(sizeof *chip, GFP_KERNEL);
- if (chip == NULL) {
+ pmic = kzalloc(sizeof *pmic, GFP_KERNEL);
+ if (pmic == NULL) {
pr_err("%s: kzalloc() failed.\n", __func__);
return -ENOMEM;
}
- chip->dev = &pdev->dev;
+ pmic->dev = &pdev->dev;
+
+ pm8058_drvdata.pm_chip_data = pmic;
+ platform_set_drvdata(pdev, &pm8058_drvdata);
+
+ mutex_init(&pmic->pm_lock);
+ pmic_chip = pmic;
/* Read PMIC chip revision */
- rc = ssbi_read(chip->dev, SSBI_REG_REV, &chip->revision, 1);
+ rc = pm8058_readb(pmic->dev, PM8058_REG_REV, &pmic->revision);
if (rc)
- pr_err("%s: Failed on ssbi_read for revision: rc=%d.\n",
+ pr_err("%s: Failed on pm8058_readb for revision: rc=%d.\n",
__func__, rc);
- pr_info("%s: PMIC revision: %X\n", __func__, chip->revision);
- (void) memcpy((void *)&chip->pdata, (const void *)pdata,
- sizeof(chip->pdata));
+ pr_info("%s: PMIC revision: %X\n", __func__, pmic->revision);
- mutex_init(&chip->pm_lock);
- irq_set_handler_data(pdata->irq, (void *)chip);
- irq_set_irq_wake(pdata->irq, 1);
+ (void) memcpy((void *)&pmic->pdata, (const void *)pdata,
+ sizeof(pmic->pdata));
- chip->pm_max_irq = 0;
- chip->pm_max_blocks = 0;
- chip->pm_max_masters = 0;
-
- platform_set_drvdata(pdev, chip);
-
- pmic_chip = chip;
-
- /* Register for all reserved IRQs */
- for (i = pdata->irq_base; i < (pdata->irq_base + MAX_PM_IRQ); i++) {
- irq_set_chip(i, &pm8058_irq_chip);
- irq_set_chip_data(i, (void *)chip);
- irq_set_handler(i, handle_edge_irq);
- set_irq_flags(i, IRQF_VALID);
- irq_set_nested_thread(i, 1);
+ rc = pm8058_add_subdevices(pdata, pmic);
+ if (rc) {
+ pr_err("Cannot add subdevices rc=%d\n", rc);
+ goto err;
}
- rc = mfd_add_devices(chip->dev, 0, pdata->sub_devices,
- pdata->num_subdevs, NULL, 0);
-
- /* Add charger sub device with the chip parameter as driver data */
- if (pdata->charger_sub_device) {
- rc = mfd_add_devices(chip->dev, 0,
- pdata->charger_sub_device,
- 1, NULL, 0);
- }
-
- if (pdata->init) {
- rc = pdata->init(chip);
- if (rc != 0) {
- pr_err("%s: board init failed\n", __func__);
- chip->dev = NULL;
- kfree(chip);
- return -ENODEV;
- }
- }
-
- rc = request_threaded_irq(pdata->irq, NULL, pm8058_isr_thread,
- IRQF_ONESHOT | IRQF_DISABLED | pdata->irq_trigger_flags,
- "pm8058-irq", chip);
- if (rc < 0)
- pr_err("%s: could not request irq %d: %d\n", __func__,
- pdata->irq, rc);
-
- rc = pmic8058_dbg_probe(chip);
- if (rc < 0)
- pr_err("%s: could not set up debugfs: %d\n", __func__, rc);
-
rc = pm8058_hard_reset_config(SHUTDOWN_ON_HARD_RESET);
if (rc < 0)
pr_err("%s: failed to config shutdown on hard reset: %d\n",
__func__, rc);
- register_syscore_ops(&pm8058_pm);
-
return 0;
+
+err:
+ mfd_remove_devices(pmic->dev);
+ platform_set_drvdata(pdev, NULL);
+ kfree(pmic);
+ return rc;
}
static int __devexit pm8058_remove(struct platform_device *pdev)
{
- struct pm8058_chip *chip;
+ struct pm8xxx_drvdata *drvdata;
+ struct pm8058_chip *pmic = NULL;
- chip = platform_get_drvdata(pdev);
- if (chip) {
- if (chip->pm_max_irq) {
- irq_set_irq_wake(chip->pdata.irq, 0);
- free_irq(chip->pdata.irq, chip);
- }
- mutex_destroy(&chip->pm_lock);
- chip->dev = NULL;
-
- kfree(chip);
+ drvdata = platform_get_drvdata(pdev);
+ if (drvdata)
+ pmic = drvdata->pm_chip_data;
+ if (pmic) {
+ if (pmic->dev)
+ mfd_remove_devices(pmic->dev);
+ if (pmic->irq_chip)
+ pm8xxx_irq_exit(pmic->irq_chip);
+ mutex_destroy(&pmic->pm_lock);
+ kfree(pmic->mfd_regulators);
+ kfree(pmic);
}
-
- pmic8058_dbg_remove();
+ platform_set_drvdata(pdev, NULL);
return 0;
}
@@ -1489,7 +1271,7 @@
{
return platform_driver_register(&pm8058_driver);
}
-arch_initcall(pm8058_init);
+postcore_initcall(pm8058_init);
static void __exit pm8058_exit(void)
{
diff --git a/drivers/mfd/pmic8901.c b/drivers/mfd/pmic8901.c
index 390de33..3d87f0b 100644
--- a/drivers/mfd/pmic8901.c
+++ b/drivers/mfd/pmic8901.c
@@ -11,13 +11,15 @@
*/
#include <linux/interrupt.h>
-#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/ratelimit.h>
+#include <linux/gpio.h>
#include <linux/mfd/core.h>
+#include <linux/msm_ssbi.h>
#include <linux/mfd/pmic8901.h>
#include <linux/platform_device.h>
#include <linux/debugfs.h>
+#include <linux/delay.h>
/* PMIC8901 Revision */
#define SSBI_REG_REV 0x002 /* PMIC4 revision */
@@ -64,10 +66,13 @@
#define REGULATOR_PMR_STATE_MASK 0x60
#define REGULATOR_PMR_STATE_OFF 0x20
+/* Shutdown/restart delays to allow for LDO 7/dVdd regulator load settling. */
+#define DELAY_AFTER_REG_DISABLE_MS 4
+#define DELAY_BEFORE_SHUTDOWN_MS 8
+
struct pm8901_chip {
struct pm8901_platform_data pdata;
-
- struct i2c_client *dev;
+ struct device *dev;
u8 irqs_allowed[MAX_PM_BLOCKS];
u8 blocks_allowed[MAX_PM_MASTERS];
@@ -107,33 +112,15 @@
}
static inline int
-ssbi_write(struct i2c_client *client, u16 addr, const u8 *buf, size_t len)
+ssbi_read(struct device *dev, u16 addr, u8 *buf, size_t len)
{
- int rc;
- struct i2c_msg msg = {
- .addr = addr,
- .flags = 0x0,
- .buf = (u8 *)buf,
- .len = len,
- };
-
- rc = i2c_transfer(client->adapter, &msg, 1);
- return (rc == 1) ? 0 : rc;
+ return msm_ssbi_read(dev->parent, addr, buf, len);
}
static inline int
-ssbi_read(struct i2c_client *client, u16 addr, u8 *buf, size_t len)
+ssbi_write(struct device *dev, u16 addr, u8 *buf, size_t len)
{
- int rc;
- struct i2c_msg msg = {
- .addr = addr,
- .flags = I2C_M_RD,
- .buf = buf,
- .len = len,
- };
-
- rc = i2c_transfer(client->adapter, &msg, 1);
- return (rc == 1) ? 0 : rc;
+ return msm_ssbi_write(dev->parent, addr, buf, len);
}
/* External APIs */
@@ -243,10 +230,12 @@
"\n", __func__, pmr_addr[i], pmr, rc);
goto get_out;
}
+ mdelay(DELAY_AFTER_REG_DISABLE_MS);
}
}
get_out:
+ mdelay(DELAY_BEFORE_SHUTDOWN_MS);
return rc;
}
EXPORT_SYMBOL(pm8901_reset_pwr_off);
@@ -770,30 +759,24 @@
.irq_set_wake = pm8901_irq_set_wake,
};
-static int pm8901_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int pm8901_probe(struct platform_device *pdev)
{
- int i, rc;
- struct pm8901_platform_data *pdata = client->dev.platform_data;
- struct pm8901_chip *chip;
+ int i, rc;
+ struct pm8901_platform_data *pdata = pdev->dev.platform_data;
+ struct pm8901_chip *chip;
- if (pdata == NULL || !client->irq) {
+ if (pdata == NULL || pdata->irq <= 0) {
pr_err("%s: No platform_data or IRQ.\n", __func__);
return -ENODEV;
}
- if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
- pr_err("%s: i2c_check_functionality failed.\n", __func__);
- return -ENODEV;
- }
-
chip = kzalloc(sizeof *chip, GFP_KERNEL);
if (chip == NULL) {
pr_err("%s: kzalloc() failed.\n", __func__);
return -ENOMEM;
}
- chip->dev = client;
+ chip->dev = &pdev->dev;
/* Read PMIC chip revision */
rc = ssbi_read(chip->dev, SSBI_REG_REV, &chip->revision, 1);
@@ -805,14 +788,14 @@
(void) memcpy((void *)&chip->pdata, (const void *)pdata,
sizeof(chip->pdata));
- irq_set_handler_data(chip->dev->irq, (void *)chip);
- irq_set_irq_wake(chip->dev->irq, 1);
+ irq_set_handler_data(pdata->irq, (void *)chip);
+ irq_set_irq_wake(pdata->irq, 1);
chip->pm_max_irq = 0;
chip->pm_max_blocks = 0;
chip->pm_max_masters = 0;
- i2c_set_clientdata(client, chip);
+ platform_set_drvdata(pdev, chip);
pmic_chip = chip;
spin_lock_init(&chip->pm_lock);
@@ -825,19 +808,19 @@
irq_set_handler_data(i, (void *)chip);
}
- rc = mfd_add_devices(&chip->dev->dev, 0, pdata->sub_devices,
+ rc = mfd_add_devices(chip->dev, 0, pdata->sub_devices,
pdata->num_subdevs, NULL, 0);
if (rc) {
pr_err("%s: could not add devices %d\n", __func__, rc);
return rc;
}
- rc = request_threaded_irq(chip->dev->irq, NULL, pm8901_isr_thread,
+ rc = request_threaded_irq(pdata->irq, NULL, pm8901_isr_thread,
IRQF_ONESHOT | IRQF_DISABLED | pdata->irq_trigger_flags,
"pm8901-irq", chip);
if (rc)
pr_err("%s: could not request irq %d: %d\n", __func__,
- chip->dev->irq, rc);
+ pdata->irq, rc);
rc = pmic8901_dbg_probe(chip);
if (rc < 0)
@@ -846,18 +829,18 @@
return rc;
}
-static int __devexit pm8901_remove(struct i2c_client *client)
+static int __devexit pm8901_remove(struct platform_device *pdev)
{
struct pm8901_chip *chip;
- chip = i2c_get_clientdata(client);
+ chip = platform_get_drvdata(pdev);
if (chip) {
if (chip->pm_max_irq) {
- irq_set_irq_wake(chip->dev->irq, 0);
- free_irq(chip->dev->irq, chip);
+ irq_set_irq_wake(chip->pdata.irq, 0);
+ free_irq(chip->pdata.irq, chip);
}
- mfd_remove_devices(&chip->dev->dev);
+ mfd_remove_devices(chip->dev);
chip->dev = NULL;
@@ -870,13 +853,13 @@
}
#ifdef CONFIG_PM
-static int pm8901_suspend(struct i2c_client *client, pm_message_t mesg)
+static int pm8901_suspend(struct platform_device *pdev, pm_message_t mesg)
{
struct pm8901_chip *chip;
int i;
unsigned long irqsave;
- chip = i2c_get_clientdata(client);
+ chip = platform_get_drvdata(pdev);
for (i = 0; i < MAX_PM_IRQ; i++) {
spin_lock_irqsave(&chip->pm_lock, irqsave);
@@ -890,18 +873,18 @@
}
if (!chip->count_wakeable)
- disable_irq(chip->dev->irq);
+ disable_irq(chip->pdata.irq);
return 0;
}
-static int pm8901_resume(struct i2c_client *client)
+static int pm8901_resume(struct platform_device *pdev)
{
struct pm8901_chip *chip;
int i;
unsigned long irqsave;
- chip = i2c_get_clientdata(client);
+ chip = platform_get_drvdata(pdev);
for (i = 0; i < MAX_PM_IRQ; i++) {
spin_lock_irqsave(&chip->pm_lock, irqsave);
@@ -915,7 +898,7 @@
}
if (!chip->count_wakeable)
- enable_irq(chip->dev->irq);
+ enable_irq(chip->pdata.irq);
return 0;
}
@@ -924,35 +907,27 @@
#define pm8901_resume NULL
#endif
-static const struct i2c_device_id pm8901_ids[] = {
- { "pm8901-core", 0 },
- { },
-};
-MODULE_DEVICE_TABLE(i2c, pm8901_ids);
-
-static struct i2c_driver pm8901_driver = {
- .driver.name = "pm8901-core",
- .id_table = pm8901_ids,
+static struct platform_driver pm8901_driver = {
.probe = pm8901_probe,
.remove = __devexit_p(pm8901_remove),
+ .driver = {
+ .name = "pm8901-core",
+ .owner = THIS_MODULE,
+ },
.suspend = pm8901_suspend,
.resume = pm8901_resume,
};
static int __init pm8901_init(void)
{
- int rc = i2c_add_driver(&pm8901_driver);
- pr_notice("%s: i2c_add_driver: rc = %d\n", __func__, rc);
-
- return rc;
+ return platform_driver_register(&pm8901_driver);
}
+arch_initcall(pm8901_init);
static void __exit pm8901_exit(void)
{
- i2c_del_driver(&pm8901_driver);
+ platform_driver_unregister(&pm8901_driver);
}
-
-arch_initcall(pm8901_init);
module_exit(pm8901_exit);
MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/tps65910-irq.c b/drivers/mfd/tps65910-irq.c
index 2bfad5c..a56be93 100644
--- a/drivers/mfd/tps65910-irq.c
+++ b/drivers/mfd/tps65910-irq.c
@@ -178,8 +178,10 @@
switch (tps65910_chip_id(tps65910)) {
case TPS65910:
tps65910->irq_num = TPS65910_NUM_IRQ;
+ break;
case TPS65911:
tps65910->irq_num = TPS65911_NUM_IRQ;
+ break;
}
/* Register with genirq */
diff --git a/drivers/mfd/wcd9310-core.c b/drivers/mfd/wcd9310-core.c
index 8eca7aa..aabc2cc 100644
--- a/drivers/mfd/wcd9310-core.c
+++ b/drivers/mfd/wcd9310-core.c
@@ -22,10 +22,25 @@
#include <linux/gpio.h>
#include <linux/debugfs.h>
#include <linux/regulator/consumer.h>
+#include <linux/i2c.h>
#include <sound/soc.h>
#define TABLA_SLIM_GLA_MAX_RETRIES 5
#define TABLA_REGISTER_START_OFFSET 0x800
+
+#define MAX_TABLA_DEVICE 4
+#define TABLA_I2C_MODE 0x03
+
+struct tabla_i2c {
+ struct i2c_client *client;
+ struct i2c_msg xfer_msg[2];
+ struct mutex xfer_lock;
+ int mod_id;
+};
+
+struct tabla_i2c tabla_modules[MAX_TABLA_DEVICE];
+static int tabla_intf;
+
static int tabla_read(struct tabla *tabla, unsigned short reg,
int bytes, void *dest, bool interface_reg)
{
@@ -566,6 +581,214 @@
kfree(tabla->supplies);
}
+int tabla_get_intf_type(void)
+{
+ return tabla_intf;
+}
+EXPORT_SYMBOL_GPL(tabla_get_intf_type);
+
+struct tabla_i2c *get_i2c_tabla_device_info(u16 reg)
+{
+ u16 mask = 0x0f00;
+ int value = 0;
+ struct tabla_i2c *tabla = NULL;
+ value = ((reg & mask) >> 8) & 0x000f;
+ switch (value) {
+ case 0:
+ tabla = &tabla_modules[0];
+ break;
+ case 1:
+ tabla = &tabla_modules[1];
+ break;
+ case 2:
+ tabla = &tabla_modules[2];
+ break;
+ case 3:
+ tabla = &tabla_modules[3];
+ break;
+ default:
+ break;
+ }
+ return tabla;
+}
+
+int tabla_i2c_write_device(u16 reg, u8 *value,
+ u32 bytes)
+{
+
+ struct i2c_msg *msg;
+ int ret = 0;
+ u8 reg_addr = 0;
+ u8 data[bytes + 1];
+ struct tabla_i2c *tabla;
+
+ tabla = get_i2c_tabla_device_info(reg);
+ if (tabla->client == NULL) {
+ pr_err("failed to get device info\n");
+ return -ENODEV;
+ }
+ reg_addr = (u8)reg;
+ msg = &tabla->xfer_msg[0];
+ msg->addr = tabla->client->addr;
+ msg->len = bytes + 1;
+ msg->flags = 0;
+ data[0] = reg;
+ data[1] = *value;
+ msg->buf = data;
+ ret = i2c_transfer(tabla->client->adapter, tabla->xfer_msg, 1);
+ /* Try again if the write fails */
+ if (ret != 1) {
+ ret = i2c_transfer(tabla->client->adapter,
+ tabla->xfer_msg, 1);
+ if (ret != 1) {
+ pr_err("failed to write the device\n");
+ return ret;
+ }
+ }
+ pr_debug("write sucess register = %x val = %x\n", reg, data[1]);
+ return 0;
+}
+
+
+int tabla_i2c_read_device(unsigned short reg,
+ int bytes, unsigned char *dest)
+{
+ struct i2c_msg *msg;
+ int ret = 0;
+ u8 reg_addr = 0;
+ struct tabla_i2c *tabla;
+ u8 i = 0;
+
+ tabla = get_i2c_tabla_device_info(reg);
+ if (tabla->client == NULL) {
+ pr_err("failed to get device info\n");
+ return -ENODEV;
+ }
+ for (i = 0; i < bytes; i++) {
+ reg_addr = (u8)reg++;
+ msg = &tabla->xfer_msg[0];
+ msg->addr = tabla->client->addr;
+ msg->len = 1;
+ msg->flags = 0;
+ msg->buf = ®_addr;
+
+ msg = &tabla->xfer_msg[1];
+ msg->addr = tabla->client->addr;
+ msg->len = 1;
+ msg->flags = I2C_M_RD;
+ msg->buf = dest++;
+ ret = i2c_transfer(tabla->client->adapter, tabla->xfer_msg, 2);
+
+ /* Try again if read fails first time */
+ if (ret != 2) {
+ ret = i2c_transfer(tabla->client->adapter,
+ tabla->xfer_msg, 2);
+ if (ret != 2) {
+ pr_err("failed to read tabla register\n");
+ return ret;
+ }
+ }
+ }
+ return 0;
+}
+
+int tabla_i2c_read(struct tabla *tabla, unsigned short reg,
+ int bytes, void *dest, bool interface_reg)
+{
+ return tabla_i2c_read_device(reg, bytes, dest);
+}
+
+int tabla_i2c_write(struct tabla *tabla, unsigned short reg,
+ int bytes, void *src, bool interface_reg)
+{
+ return tabla_i2c_write_device(reg, src, bytes);
+}
+
+static int __devinit tabla_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct tabla *tabla;
+ struct tabla_pdata *pdata = client->dev.platform_data;
+ int val = 0;
+ int ret = 0;
+ static int device_id;
+
+ if (device_id > 0) {
+ tabla_modules[device_id++].client = client;
+ pr_info("probe for other slaves devices of tabla\n");
+ return ret;
+ }
+
+ tabla = kzalloc(sizeof(struct tabla), GFP_KERNEL);
+ if (tabla == NULL) {
+ pr_err("%s: error, allocation failed\n", __func__);
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ if (!pdata) {
+ dev_dbg(&client->dev, "no platform data?\n");
+ ret = -EINVAL;
+ goto fail;
+ }
+ if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
+ dev_dbg(&client->dev, "can't talk I2C?\n");
+ ret = -EIO;
+ goto fail;
+ }
+ tabla->dev = &client->dev;
+ tabla->reset_gpio = pdata->reset_gpio;
+
+ ret = tabla_enable_supplies(tabla);
+ if (ret) {
+ pr_err("%s: Fail to enable Tabla supplies\n", __func__);
+ goto err_tabla;
+ }
+
+ usleep_range(5, 5);
+ ret = tabla_reset(tabla);
+ if (ret) {
+ pr_err("%s: Resetting Tabla failed\n", __func__);
+ goto err_supplies;
+ }
+ tabla_modules[device_id++].client = client;
+
+ tabla->read_dev = tabla_i2c_read;
+ tabla->write_dev = tabla_i2c_write;
+ tabla->irq = pdata->irq;
+ tabla->irq_base = pdata->irq_base;
+
+ /*read the tabla status before initializing the device type*/
+ ret = tabla_read(tabla, TABLA_A_CHIP_STATUS, 1, &val, 0);
+ if ((ret < 0) || (val != TABLA_I2C_MODE)) {
+ pr_err("failed to read the tabla status\n");
+ goto err_device_init;
+ }
+
+ ret = tabla_device_init(tabla, tabla->irq);
+ if (ret) {
+ pr_err("%s: error, initializing device failed\n", __func__);
+ goto err_device_init;
+ }
+ tabla_intf = TABLA_INTERFACE_TYPE_I2C;
+
+ return ret;
+err_device_init:
+ tabla_free_reset(tabla);
+err_supplies:
+ tabla_disable_supplies(tabla);
+err_tabla:
+ kfree(tabla);
+fail:
+ return ret;
+}
+
+static int __devexit tabla_i2c_remove(struct i2c_client *client)
+{
+ pr_debug("exit\n");
+ return 0;
+}
+
static int tabla_slim_probe(struct slim_device *slim)
{
struct tabla *tabla;
@@ -600,7 +823,7 @@
ret = tabla_enable_supplies(tabla);
if (ret) {
- pr_info("%s: Fail to enable Tabla supplies\n", __func__);
+ pr_err("%s: Fail to enable Tabla supplies\n", __func__);
goto err_tabla;
}
usleep_range(5, 5);
@@ -661,6 +884,7 @@
break;
}
tabla_inf_la = tabla->slim_slave->laddr;
+ tabla_intf = TABLA_INTERFACE_TYPE_SLIMBUS;
ret = tabla_device_init(tabla, tabla->irq);
if (ret) {
@@ -744,9 +968,33 @@
.id_table = slimtest2x_id,
};
+#define TABLA_I2C_TOP_LEVEL 0
+#define TABLA_I2C_ANALOG 1
+#define TABLA_I2C_DIGITAL_1 2
+#define TABLA_I2C_DIGITAL_2 3
+
+static struct i2c_device_id tabla_id_table[] = {
+ {"tabla top level", TABLA_I2C_TOP_LEVEL},
+ {"tabla analog", TABLA_I2C_TOP_LEVEL},
+ {"tabla digital1", TABLA_I2C_TOP_LEVEL},
+ {"tabla digital2", TABLA_I2C_TOP_LEVEL},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, tabla_id_table);
+
+static struct i2c_driver tabla_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "tabla-i2c-core",
+ },
+ .id_table = tabla_id_table,
+ .probe = tabla_i2c_probe,
+ .remove = __devexit_p(tabla_i2c_remove),
+};
+
static int __init tabla_init(void)
{
- int ret1, ret2;
+ int ret1, ret2, ret3;
ret1 = slim_driver_register(&tabla_slim_driver);
if (ret1 != 0)
@@ -756,7 +1004,11 @@
if (ret2 != 0)
pr_err("Failed to register tabla2x SB driver: %d\n", ret2);
- return (ret1 && ret2) ? -1 : 0;
+ ret3 = i2c_add_driver(&tabla_i2c_driver);
+ if (ret3 != 0)
+ pr_err("failed to add the I2C driver\n");
+
+ return (ret1 && ret2 && ret3) ? -1 : 0;
}
module_init(tabla_init);
diff --git a/drivers/mfd/wcd9310-irq.c b/drivers/mfd/wcd9310-irq.c
index bc7841e..9cc4761 100644
--- a/drivers/mfd/wcd9310-irq.c
+++ b/drivers/mfd/wcd9310-irq.c
@@ -110,11 +110,19 @@
(i >= TABLA_IRQ_MBHC_REMOVAL)) {
tabla_reg_write(tabla, TABLA_A_INTR_CLEAR0 +
BIT_BYTE(i), BYTE_BIT_MASK(i));
+ if (tabla_get_intf_type() ==
+ TABLA_INTERFACE_TYPE_I2C)
+ tabla_reg_write(tabla,
+ TABLA_A_INTR_MODE, 0x02);
handle_nested_irq(tabla->irq_base + i);
} else {
handle_nested_irq(tabla->irq_base + i);
tabla_reg_write(tabla, TABLA_A_INTR_CLEAR0 +
BIT_BYTE(i), BYTE_BIT_MASK(i));
+ if (tabla_get_intf_type() ==
+ TABLA_INTERFACE_TYPE_I2C)
+ tabla_reg_write(tabla,
+ TABLA_A_INTR_MODE, 0x02);
}
break;
}
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index dfbf345..0c579e2 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -233,13 +233,6 @@
driver (SCSI/ATA) which supports enclosures
or a SCSI enclosure device (SES) to use these services.
-config KERNEL_DEBUGGER_CORE
- bool "Kernel Debugger Core"
- default n
- ---help---
- Generic kernel debugging command processor used by low level
- (interrupt context) platform-specific debuggers.
-
config SGI_XP
tristate "Support communication between SGI SSIs"
depends on NET
@@ -601,21 +594,19 @@
on the PM8XXX chips. The vibrator is controlled using the
timed output class.
-config PMIC8058_NFC
- tristate "Qualcomm PM8058 support for Near Field Communication"
- depends on PMIC8058
- default y
+config PMIC8XXX_NFC
+ tristate "Qualcomm PM8XXX support for Near Field Communication"
+ depends on MFD_PM8XXX
help
- Qualcomm PM8058 chip has a module to support NFC (Near Field
+ Qualcomm PM8XXX chips have a module to support NFC (Near Field
Communication). This option enables the driver to support it.
-config PMIC8058_UPL
- tristate "Qualcomm PM8058 support for User Programmable Logic"
- depends on PMIC8058
- default n
+config PMIC8XXX_UPL
+ tristate "Qualcomm PM8XXX support for User Programmable Logic"
+ depends on MFD_PM8XXX
help
This option enables device driver support for User Programmable Logic
- on Qualcomm PM8058 chip. The UPL module provides a means to implement
+ on Qualcomm PM8XXX chips. The UPL module provides a means to implement
simple truth table based logic via a set of control registers. I/O may
be routed in and out of the UPL module via GPIO or DTEST pins.
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index a38ccfd..385f8ff 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -22,7 +22,6 @@
obj-$(CONFIG_ANDROID_PMEM) += pmem.o
obj-$(CONFIG_SGI_IOC4) += ioc4.o
obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
-obj-$(CONFIG_KERNEL_DEBUGGER_CORE) += kernel_debugger.o
obj-$(CONFIG_KGDB_TESTS) += kgdbts.o
obj-$(CONFIG_SGI_XP) += sgi-xp/
obj-$(CONFIG_SGI_GRU) += sgi-gru/
@@ -59,11 +58,12 @@
obj-$(CONFIG_PMIC8058_PWM) += pmic8058-pwm.o
obj-$(CONFIG_PMIC8058_VIBRATOR) += pmic8058-vibrator.o
obj-$(CONFIG_PMIC8XXX_VIBRATOR) += pm8xxx-vibrator.o
-obj-$(CONFIG_PMIC8058_NFC) += pmic8058-nfc.o
-obj-$(CONFIG_PMIC8058_UPL) += pmic8058-upl.o
+obj-$(CONFIG_PMIC8XXX_NFC) += pm8xxx-nfc.o
+obj-$(CONFIG_PMIC8XXX_UPL) += pm8xxx-upl.o
obj-$(CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN) \
+= msm_migrate_pages.o
obj-$(CONFIG_PMIC8058_XOADC) += pmic8058-xoadc.o
obj-$(CONFIG_PMIC8058_MISC) += pmic8058-misc.o
obj-$(CONFIG_PMIC8058_BATTALARM) += pmic8058-batt-alarm.o
obj-$(CONFIG_TZCOM) += tzcom.o
+obj-$(CONFIG_QFP_FUSE) += qfp_fuse.o
diff --git a/drivers/misc/isa1200.c b/drivers/misc/isa1200.c
index a58c7d6..31c79a0 100644
--- a/drivers/misc/isa1200.c
+++ b/drivers/misc/isa1200.c
@@ -187,7 +187,7 @@
rc = isa1200_write_reg(client, ISA1200_HCTRL1, value);
if (rc < 0) {
pr_err("%s: i2c write failure\n", __func__);
- return rc;
+ goto reset_gpios;
}
if (haptic->pdata->mode_ctrl == PWM_GEN_MODE) {
@@ -224,6 +224,10 @@
reset_hctrl1:
i2c_smbus_write_byte_data(client, ISA1200_HCTRL1,
ISA1200_HCTRL1_RESET);
+reset_gpios:
+ gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 0);
+ if (haptic->is_len_gpio_valid == true)
+ gpio_set_value_cansleep(haptic->pdata->hap_len_gpio, 0);
return rc;
}
@@ -449,6 +453,11 @@
return 0;
reset_hctrl0:
+ gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 0);
+ if (haptic->is_len_gpio_valid == true)
+ gpio_set_value_cansleep(haptic->pdata->hap_len_gpio, 0);
+ i2c_smbus_write_byte_data(client, ISA1200_HCTRL1,
+ ISA1200_HCTRL1_RESET);
i2c_smbus_write_byte_data(client, ISA1200_HCTRL0,
ISA1200_HCTRL0_RESET);
setup_fail:
@@ -490,6 +499,10 @@
timed_output_dev_unregister(&haptic->dev);
+ gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 0);
+ if (haptic->is_len_gpio_valid == true)
+ gpio_set_value_cansleep(haptic->pdata->hap_len_gpio, 0);
+
gpio_free(haptic->pdata->hap_en_gpio);
if (haptic->is_len_gpio_valid == true)
gpio_free(haptic->pdata->hap_len_gpio);
diff --git a/drivers/misc/kernel_debugger.c b/drivers/misc/kernel_debugger.c
deleted file mode 100644
index 4a9fef6..0000000
--- a/drivers/misc/kernel_debugger.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/* drivers/android/kernel_debugger.c
- *
- * Guts of the kernel debugger.
- * Needs something to actually push commands to it.
- *
- * Copyright (C) 2007-2008 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/ctype.h>
-#include <linux/device.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/sysrq.h>
-#include <linux/kernel_debugger.h>
-
-#define dprintf(fmt...) (ctxt->printf(ctxt->cookie, fmt))
-
-static void do_ps(struct kdbg_ctxt *ctxt)
-{
- struct task_struct *g, *p;
- unsigned state;
- static const char stat_nam[] = "RSDTtZX";
-
- dprintf("pid ppid prio task pc\n");
- read_lock(&tasklist_lock);
- do_each_thread(g, p) {
- state = p->state ? __ffs(p->state) + 1 : 0;
- dprintf("%5d %5d %4d ", p->pid, p->parent->pid, p->prio);
- dprintf("%-13.13s %c", p->comm,
- state >= sizeof(stat_nam) ? '?' : stat_nam[state]);
- if (state == TASK_RUNNING)
- dprintf(" running\n");
- else
- dprintf(" %08lx\n", thread_saved_pc(p));
- } while_each_thread(g, p);
- read_unlock(&tasklist_lock);
-}
-
-int log_buf_copy(char *dest, int idx, int len);
-extern int do_syslog(int type, char __user *bug, int count);
-static void do_sysrq(struct kdbg_ctxt *ctxt, char rq)
-{
- char buf[128];
- int ret;
- int idx = 0;
- do_syslog(5 /* clear */, NULL, 0);
- handle_sysrq(rq);
- while (1) {
- ret = log_buf_copy(buf, idx, sizeof(buf) - 1);
- if (ret <= 0)
- break;
- buf[ret] = 0;
- dprintf("%s", buf);
- idx += ret;
- }
-}
-
-static void do_help(struct kdbg_ctxt *ctxt)
-{
- dprintf("Kernel Debugger commands:\n");
- dprintf(" ps Process list\n");
- dprintf(" sysrq sysrq options\n");
- dprintf(" sysrq <param> Execute sysrq with <param>\n");
-}
-
-int kernel_debugger(struct kdbg_ctxt *ctxt, char *cmd)
-{
- if (!strcmp(cmd, "ps"))
- do_ps(ctxt);
- if (!strcmp(cmd, "sysrq"))
- do_sysrq(ctxt, 'h');
- if (!strncmp(cmd, "sysrq ", 6))
- do_sysrq(ctxt, cmd[6]);
- if (!strcmp(cmd, "help"))
- do_help(ctxt);
-
- return 0;
-}
-
diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c
index b928bc1..8b51cd6 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d.c
@@ -375,12 +375,14 @@
* both have been read. So the value read will always be correct.
* Set BOOT bit to refresh factory tuning values.
*/
- lis3->read(lis3, CTRL_REG2, ®);
- if (lis3->whoami == WAI_12B)
- reg |= CTRL2_BDU | CTRL2_BOOT;
- else
- reg |= CTRL2_BOOT_8B;
- lis3->write(lis3, CTRL_REG2, reg);
+ if (lis3->pdata) {
+ lis3->read(lis3, CTRL_REG2, ®);
+ if (lis3->whoami == WAI_12B)
+ reg |= CTRL2_BDU | CTRL2_BOOT;
+ else
+ reg |= CTRL2_BOOT_8B;
+ lis3->write(lis3, CTRL_REG2, reg);
+ }
/* LIS3 power on delay is quite long */
msleep(lis3->pwron_delay / lis3lv02d_get_odr());
diff --git a/drivers/misc/pm8xxx-nfc.c b/drivers/misc/pm8xxx-nfc.c
new file mode 100644
index 0000000..1aaa3e3
--- /dev/null
+++ b/drivers/misc/pm8xxx-nfc.c
@@ -0,0 +1,311 @@
+/* Copyright (c) 2010,2011 Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ *
+ */
+/*
+ * Qualcomm PMIC8XXX NFC driver
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/nfc.h>
+
+/* PM8XXX NFC */
+#define SSBI_REG_NFC_CTRL 0x14D
+#define SSBI_REG_NFC_TEST 0x14E
+
+/* NFC_CTRL */
+#define PM8XXX_NFC_SUPPORT_EN 0x80
+#define PM8XXX_NFC_LDO_EN 0x40
+#define PM8XXX_NFC_EN 0x20
+#define PM8XXX_NFC_EXT_VDDLDO_EN 0x10
+#define PM8XXX_NFC_VPH_PWR_EN 0x08
+#define PM8XXX_NFC_RESERVED 0x04
+#define PM8XXX_NFC_VDDLDO_LEVEL 0x03
+
+/* NFC_TEST */
+#define PM8XXX_NFC_VDDLDO_MON_EN 0x80
+#define PM8XXX_NFC_ATEST_EN 0x40
+#define PM8XXX_NFC_DTEST1_EN 0x20
+#define PM8XXX_NFC_RESERVED2 0x18
+#define PM8XXX_NFC_VDDLDO_OK_S 0x04
+#define PM8XXX_NFC_MBG_EN_S 0x02
+#define PM8XXX_NFC_EXT_EN_S 0x01
+
+struct pm8xxx_nfc_device {
+ struct device *dev;
+ struct mutex nfc_mutex;
+#if defined(CONFIG_DEBUG_FS)
+ struct dentry *dent;
+#endif
+};
+static struct pm8xxx_nfc_device *nfc_dev;
+
+/* APIs */
+/*
+ * pm8xxx_nfc_request - request a handle to access NFC device
+ */
+struct pm8xxx_nfc_device *pm8xxx_nfc_request(void)
+{
+ return nfc_dev;
+}
+EXPORT_SYMBOL(pm8xxx_nfc_request);
+
+/*
+ * pm8xxx_nfc_config - configure NFC signals
+ *
+ * @nfcdev: the NFC device
+ * @mask: signal mask to configure
+ * @flags: control flags
+ */
+int pm8xxx_nfc_config(struct pm8xxx_nfc_device *nfcdev, u32 mask, u32 flags)
+{
+ u8 nfc_ctrl, nfc_test, m, f;
+ int rc;
+
+ if (nfcdev == NULL || IS_ERR(nfcdev) || !mask)
+ return -EINVAL;
+
+ mutex_lock(&nfcdev->nfc_mutex);
+
+ if (!(mask & PM_NFC_CTRL_REQ))
+ goto config_test;
+
+ rc = pm8xxx_readb(nfcdev->dev->parent, SSBI_REG_NFC_CTRL, &nfc_ctrl);
+ if (rc) {
+ pr_err("%s: FAIL pm8xxx_readb(): rc=%d (nfc_ctrl=0x%x)\n",
+ __func__, rc, nfc_ctrl);
+ goto config_done;
+ }
+
+ m = mask & 0x00ff;
+ f = flags & 0x00ff;
+ nfc_ctrl &= ~m;
+ nfc_ctrl |= m & f;
+
+ rc = pm8xxx_writeb(nfcdev->dev->parent, SSBI_REG_NFC_CTRL, nfc_ctrl);
+ if (rc) {
+ pr_err("%s: FAIL pm8xxx_writeb(): rc=%d (nfc_ctrl=0x%x)\n",
+ __func__, rc, nfc_ctrl);
+ goto config_done;
+ }
+
+config_test:
+ if (!(mask & PM_NFC_TEST_REQ))
+ goto config_done;
+
+ rc = pm8xxx_readb(nfcdev->dev->parent, SSBI_REG_NFC_TEST, &nfc_test);
+ if (rc) {
+ pr_err("%s: FAIL pm8xxx_readb(): rc=%d (nfc_test=0x%x)\n",
+ __func__, rc, nfc_test);
+ goto config_done;
+ }
+
+ m = (mask >> 8) & 0x00ff;
+ f = (flags >> 8) & 0x00ff;
+ nfc_test &= ~m;
+ nfc_test |= m & f;
+
+ rc = pm8xxx_writeb(nfcdev->dev->parent, SSBI_REG_NFC_TEST, nfc_test);
+ if (rc) {
+ pr_err("%s: FAIL pm8xxx_writeb(): rc=%d (nfc_test=0x%x)\n",
+ __func__, rc, nfc_test);
+ goto config_done;
+ }
+
+config_done:
+ mutex_unlock(&nfcdev->nfc_mutex);
+ return 0;
+}
+EXPORT_SYMBOL(pm8xxx_nfc_config);
+
+/*
+ * pm8xxx_nfc_get_status - get NFC status
+ *
+ * @nfcdev: the NFC device
+ * @mask: of status mask to read
+ * @status: pointer to the status variable
+ */
+int pm8xxx_nfc_get_status(struct pm8xxx_nfc_device *nfcdev,
+ u32 mask, u32 *status)
+{
+ u8 nfc_ctrl, nfc_test;
+ u32 st;
+ int rc;
+
+ if (nfcdev == NULL || IS_ERR(nfcdev) || status == NULL)
+ return -EINVAL;
+
+ st = 0;
+ mutex_lock(&nfcdev->nfc_mutex);
+
+ if (!(mask & PM_NFC_CTRL_REQ))
+ goto read_test;
+
+ rc = pm8xxx_readb(nfcdev->dev->parent, SSBI_REG_NFC_CTRL, &nfc_ctrl);
+ if (rc) {
+ pr_err("%s: FAIL pm8xxx_readb(): rc=%d (nfc_ctrl=0x%x)\n",
+ __func__, rc, nfc_ctrl);
+ goto get_status_done;
+ }
+
+read_test:
+ if (!(mask & (PM_NFC_TEST_REQ | PM_NFC_TEST_STATUS)))
+ goto get_status_done;
+
+ rc = pm8xxx_readb(nfcdev->dev->parent, SSBI_REG_NFC_TEST, &nfc_test);
+ if (rc)
+ pr_err("%s: FAIL pm8xxx_readb(): rc=%d (nfc_test=0x%x)\n",
+ __func__, rc, nfc_test);
+
+get_status_done:
+ st = nfc_ctrl;
+ st |= nfc_test << 8;
+ *status = st;
+
+ mutex_unlock(&nfcdev->nfc_mutex);
+ return 0;
+}
+EXPORT_SYMBOL(pm8xxx_nfc_get_status);
+
+/*
+ * pm8xxx_nfc_free - free the NFC device
+ */
+void pm8xxx_nfc_free(struct pm8xxx_nfc_device *nfcdev)
+{
+ /* Disable all signals */
+ pm8xxx_nfc_config(nfcdev, PM_NFC_CTRL_REQ, 0);
+}
+EXPORT_SYMBOL(pm8xxx_nfc_free);
+
+#if defined(CONFIG_DEBUG_FS)
+static int pm8xxx_nfc_debug_set(void *data, u64 val)
+{
+ struct pm8xxx_nfc_device *nfcdev;
+ u32 mask, control;
+ int rc;
+
+ nfcdev = (struct pm8xxx_nfc_device *)data;
+ control = (u32)val & 0xffff;
+ mask = ((u32)val >> 16) & 0xffff;
+ rc = pm8xxx_nfc_config(nfcdev, mask, control);
+ if (rc)
+ pr_err("%s: ERR pm8xxx_nfc_config: rc=%d, "
+ "[mask, control]=[0x%x, 0x%x]\n",
+ __func__, rc, mask, control);
+
+ return 0;
+}
+
+static int pm8xxx_nfc_debug_get(void *data, u64 *val)
+{
+ struct pm8xxx_nfc_device *nfcdev;
+ u32 status;
+ int rc;
+
+ nfcdev = (struct pm8xxx_nfc_device *)data;
+ rc = pm8xxx_nfc_get_status(nfcdev, (u32)-1, &status);
+ if (rc)
+ pr_err("%s: ERR pm8xxx_nfc_get_status: rc=%d, status=0x%x\n",
+ __func__, rc, status);
+
+ if (val)
+ *val = (u64)status;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(pm8xxx_nfc_fops, pm8xxx_nfc_debug_get,
+ pm8xxx_nfc_debug_set, "%llu\n");
+
+static int pm8xxx_nfc_debug_init(struct pm8xxx_nfc_device *nfcdev)
+{
+ struct dentry *dent;
+
+ dent = debugfs_create_file("pm8xxx-nfc", 0644, NULL,
+ (void *)nfcdev, &pm8xxx_nfc_fops);
+
+ if (dent == NULL || IS_ERR(dent))
+ pr_err("%s: ERR debugfs_create_file: dent=0x%x\n",
+ __func__, (unsigned)dent);
+
+ nfcdev->dent = dent;
+ return 0;
+}
+#endif
+
+static int __devinit pm8xxx_nfc_probe(struct platform_device *pdev)
+{
+ struct pm8xxx_nfc_device *nfcdev;
+
+ nfcdev = kzalloc(sizeof *nfcdev, GFP_KERNEL);
+ if (nfcdev == NULL) {
+ pr_err("%s: kzalloc() failed.\n", __func__);
+ return -ENOMEM;
+ }
+
+ mutex_init(&nfcdev->nfc_mutex);
+
+ nfcdev->dev = &pdev->dev;
+ nfc_dev = nfcdev;
+ platform_set_drvdata(pdev, nfcdev);
+
+#if defined(CONFIG_DEBUG_FS)
+ pm8xxx_nfc_debug_init(nfc_dev);
+#endif
+
+ pr_notice("%s: OK\n", __func__);
+ return 0;
+}
+
+static int __devexit pm8xxx_nfc_remove(struct platform_device *pdev)
+{
+ struct pm8xxx_nfc_device *nfcdev = platform_get_drvdata(pdev);
+
+#if defined(CONFIG_DEBUG_FS)
+ debugfs_remove(nfcdev->dent);
+#endif
+
+ platform_set_drvdata(pdev, NULL);
+ kfree(nfcdev);
+ return 0;
+}
+
+static struct platform_driver pm8xxx_nfc_driver = {
+ .probe = pm8xxx_nfc_probe,
+ .remove = __devexit_p(pm8xxx_nfc_remove),
+ .driver = {
+ .name = PM8XXX_NFC_DEV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pm8xxx_nfc_init(void)
+{
+ return platform_driver_register(&pm8xxx_nfc_driver);
+}
+
+static void __exit pm8xxx_nfc_exit(void)
+{
+ platform_driver_unregister(&pm8xxx_nfc_driver);
+}
+
+module_init(pm8xxx_nfc_init);
+module_exit(pm8xxx_nfc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PM8XXX NFC driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:" PM8XXX_NFC_DEV_NAME);
diff --git a/drivers/misc/pm8xxx-upl.c b/drivers/misc/pm8xxx-upl.c
new file mode 100644
index 0000000..d3d9746f
--- /dev/null
+++ b/drivers/misc/pm8xxx-upl.c
@@ -0,0 +1,350 @@
+/* Copyright (c) 2010,2011 Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ *
+ */
+/*
+ * Qualcomm PM8XXX UPL driver
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/upl.h>
+
+/* PMIC8XXX UPL registers */
+#define SSBI_REG_UPL_CTRL 0x17B
+#define SSBI_REG_UPL_TRUTHTABLE1 0x17C
+#define SSBI_REG_UPL_TRUTHTABLE2 0x17D
+
+struct pm8xxx_upl_device {
+ struct device *dev;
+ struct mutex upl_mutex;
+#if defined(CONFIG_DEBUG_FS)
+ struct dentry *dent;
+#endif
+};
+static struct pm8xxx_upl_device *upl_dev;
+
+/* APIs */
+
+/*
+ * pm8xxx_upl_request - request a handle to access UPL device
+ */
+struct pm8xxx_upl_device *pm8xxx_upl_request(void)
+{
+ return upl_dev;
+}
+EXPORT_SYMBOL(pm8xxx_upl_request);
+
+/*
+ * pm8xxx_upl_read_truthtable - read value currently stored in UPL truth table
+ *
+ * @upldev: the UPL device
+ * @truthtable: value read from UPL truth table
+ */
+int pm8xxx_upl_read_truthtable(struct pm8xxx_upl_device *upldev,
+ u16 *truthtable)
+{
+ int rc = 0;
+ u8 table[2];
+
+ if (upldev == NULL || IS_ERR(upldev))
+ return -EINVAL;
+
+ mutex_lock(&upldev->upl_mutex);
+
+ rc = pm8xxx_readb(upldev->dev->parent, SSBI_REG_UPL_TRUTHTABLE1,
+ &(table[0]));
+ if (rc) {
+ pr_err("%s: FAIL pm8xxx_readb(0x%X)=0x%02X: rc=%d\n",
+ __func__, SSBI_REG_UPL_TRUTHTABLE1, table[0], rc);
+ goto upl_read_done;
+ }
+
+ rc = pm8xxx_readb(upldev->dev->parent, SSBI_REG_UPL_TRUTHTABLE2,
+ &(table[1]));
+ if (rc)
+ pr_err("%s: FAIL pm8xxx_readb(0x%X)=0x%02X: rc=%d\n",
+ __func__, SSBI_REG_UPL_TRUTHTABLE2, table[1], rc);
+upl_read_done:
+ mutex_unlock(&upldev->upl_mutex);
+ *truthtable = (((u16)table[1]) << 8) | table[0];
+ return rc;
+}
+EXPORT_SYMBOL(pm8xxx_upl_read_truthtable);
+
+/*
+ * pm8xxx_upl_writes_truthtable - write value into UPL truth table
+ *
+ * @upldev: the UPL device
+ * @truthtable: value written to UPL truth table
+ *
+ * Each bit in parameter "truthtable" corresponds to the UPL output for a given
+ * set of input pin values. For example, if the input pins have the following
+ * values: A=1, B=1, C=1, D=0, then the UPL would output the value of bit 14
+ * (0b1110) in parameter "truthtable".
+ */
+int pm8xxx_upl_write_truthtable(struct pm8xxx_upl_device *upldev,
+ u16 truthtable)
+{
+ int rc = 0;
+ u8 table[2];
+
+ if (upldev == NULL || IS_ERR(upldev))
+ return -EINVAL;
+
+ table[0] = truthtable & 0xFF;
+ table[1] = (truthtable >> 8) & 0xFF;
+
+ mutex_lock(&upldev->upl_mutex);
+
+ rc = pm8xxx_writeb(upldev->dev->parent, SSBI_REG_UPL_TRUTHTABLE1,
+ table[0]);
+ if (rc) {
+ pr_err("%s: FAIL pm8xxx_writeb(0x%X)=0x%04X: rc=%d\n",
+ __func__, SSBI_REG_UPL_TRUTHTABLE1, table[0], rc);
+ goto upl_write_done;
+ }
+
+ rc = pm8xxx_writeb(upldev->dev->parent, SSBI_REG_UPL_TRUTHTABLE2,
+ table[1]);
+ if (rc)
+ pr_err("%s: FAIL pm8xxx_writeb(0x%X)=0x%04X: rc=%d\n",
+ __func__, SSBI_REG_UPL_TRUTHTABLE2, table[1], rc);
+upl_write_done:
+ mutex_unlock(&upldev->upl_mutex);
+ return rc;
+}
+EXPORT_SYMBOL(pm8xxx_upl_write_truthtable);
+
+/*
+ * pm8xxx_upl_config - configure UPL I/O settings and UPL enable/disable
+ *
+ * @upldev: the UPL device
+ * @mask: setting mask to configure
+ * @flags: setting flags
+ */
+int pm8xxx_upl_config(struct pm8xxx_upl_device *upldev, u32 mask, u32 flags)
+{
+ int rc;
+ u8 upl_ctrl, m, f;
+
+ if (upldev == NULL || IS_ERR(upldev))
+ return -EINVAL;
+
+ mutex_lock(&upldev->upl_mutex);
+
+ rc = pm8xxx_readb(upldev->dev->parent, SSBI_REG_UPL_CTRL, &upl_ctrl);
+ if (rc) {
+ pr_err("%s: FAIL pm8xxx_readb(0x%X)=0x%02X: rc=%d\n",
+ __func__, SSBI_REG_UPL_CTRL, upl_ctrl, rc);
+ goto upl_config_done;
+ }
+
+ m = mask & 0x00ff;
+ f = flags & 0x00ff;
+ upl_ctrl &= ~m;
+ upl_ctrl |= m & f;
+
+ rc = pm8xxx_writeb(upldev->dev->parent, SSBI_REG_UPL_CTRL, upl_ctrl);
+ if (rc)
+ pr_err("%s: FAIL pm8xxx_writeb(0x%X)=0x%02X: rc=%d\n",
+ __func__, SSBI_REG_UPL_CTRL, upl_ctrl, rc);
+upl_config_done:
+ mutex_unlock(&upldev->upl_mutex);
+ return rc;
+}
+EXPORT_SYMBOL(pm8xxx_upl_config);
+
+#if defined(CONFIG_DEBUG_FS)
+
+static int truthtable_set(void *data, u64 val)
+{
+ int rc;
+
+ rc = pm8xxx_upl_write_truthtable(data, val);
+ if (rc)
+ pr_err("%s: pm8xxx_upl_write_truthtable: rc=%d, "
+ "truthtable=0x%llX\n", __func__, rc, val);
+ return rc;
+}
+
+static int truthtable_get(void *data, u64 *val)
+{
+ int rc;
+ u16 truthtable;
+
+ rc = pm8xxx_upl_read_truthtable(data, &truthtable);
+ if (rc)
+ pr_err("%s: pm8xxx_upl_read_truthtable: rc=%d, "
+ "truthtable=0x%X\n", __func__, rc, truthtable);
+ if (val)
+ *val = truthtable;
+
+ return rc;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(upl_truthtable_fops, truthtable_get,
+ truthtable_set, "0x%04llX\n");
+
+/* enter values as 0xMMMMFFFF where MMMM is the mask and FFFF is the flags */
+static int control_set(void *data, u64 val)
+{
+ u8 mask, flags;
+ int rc;
+
+ flags = val & 0xFFFF;
+ mask = (val >> 16) & 0xFFFF;
+
+ rc = pm8xxx_upl_config(data, mask, flags);
+ if (rc)
+ pr_err("%s: pm8xxx_upl_config: rc=%d, mask = 0x%X, "
+ "flags = 0x%X\n", __func__, rc, mask, flags);
+ return rc;
+}
+
+static int control_get(void *data, u64 *val)
+{
+ struct pm8xxx_upl_device *upldev;
+ int rc = 0;
+ u8 ctrl;
+
+ upldev = data;
+
+ mutex_lock(&upldev->upl_mutex);
+
+ rc = pm8xxx_readb(upldev->dev->parent, SSBI_REG_UPL_CTRL, &ctrl);
+ if (rc)
+ pr_err("%s: FAIL pm8xxx_readb(): rc=%d (ctrl=0x%02X)\n",
+ __func__, rc, ctrl);
+
+ mutex_unlock(&upldev->upl_mutex);
+
+ *val = ctrl;
+
+ return rc;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(upl_control_fops, control_get,
+ control_set, "0x%02llX\n");
+
+static int pm8xxx_upl_debug_init(struct pm8xxx_upl_device *upldev)
+{
+ struct dentry *dent;
+ struct dentry *temp;
+
+ dent = debugfs_create_dir("pm8xxx-upl", NULL);
+ if (dent == NULL || IS_ERR(dent)) {
+ pr_err("%s: ERR debugfs_create_dir: dent=0x%X\n",
+ __func__, (unsigned)dent);
+ return -ENOMEM;
+ }
+
+ temp = debugfs_create_file("truthtable", S_IRUSR | S_IWUSR, dent,
+ upldev, &upl_truthtable_fops);
+ if (temp == NULL || IS_ERR(temp)) {
+ pr_err("%s: ERR debugfs_create_file: dent=0x%X\n",
+ __func__, (unsigned)dent);
+ goto debug_error;
+ }
+
+ temp = debugfs_create_file("control", S_IRUSR | S_IWUSR, dent,
+ upldev, &upl_control_fops);
+ if (temp == NULL || IS_ERR(temp)) {
+ pr_err("%s: ERR debugfs_create_file: dent=0x%X\n",
+ __func__, (unsigned)dent);
+ goto debug_error;
+ }
+
+ upldev->dent = dent;
+ return 0;
+
+debug_error:
+ debugfs_remove_recursive(dent);
+ return -ENOMEM;
+}
+
+static int __devexit pm8xxx_upl_debug_remove(struct pm8xxx_upl_device *upldev)
+{
+ debugfs_remove_recursive(upldev->dent);
+ return 0;
+}
+
+#endif /* CONFIG_DEBUG_FS */
+
+static int __devinit pm8xxx_upl_probe(struct platform_device *pdev)
+{
+ struct pm8xxx_upl_device *upldev;
+
+ upldev = kzalloc(sizeof *upldev, GFP_KERNEL);
+ if (upldev == NULL) {
+ pr_err("%s: kzalloc() failed.\n", __func__);
+ return -ENOMEM;
+ }
+
+ mutex_init(&upldev->upl_mutex);
+
+ upl_dev = upldev;
+ upldev->dev = &pdev->dev;
+ platform_set_drvdata(pdev, upldev);
+
+#if defined(CONFIG_DEBUG_FS)
+ pm8xxx_upl_debug_init(upl_dev);
+#endif
+ pr_notice("%s: OK\n", __func__);
+ return 0;
+}
+
+static int __devexit pm8xxx_upl_remove(struct platform_device *pdev)
+{
+ struct pm8xxx_upl_device *upldev = platform_get_drvdata(pdev);
+
+#if defined(CONFIG_DEBUG_FS)
+ pm8xxx_upl_debug_remove(upldev);
+#endif
+
+ platform_set_drvdata(pdev, NULL);
+ kfree(upldev);
+ pr_notice("%s: OK\n", __func__);
+
+ return 0;
+}
+
+static struct platform_driver pm8xxx_upl_driver = {
+ .probe = pm8xxx_upl_probe,
+ .remove = __devexit_p(pm8xxx_upl_remove),
+ .driver = {
+ .name = PM8XXX_UPL_DEV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pm8xxx_upl_init(void)
+{
+ return platform_driver_register(&pm8xxx_upl_driver);
+}
+
+static void __exit pm8xxx_upl_exit(void)
+{
+ platform_driver_unregister(&pm8xxx_upl_driver);
+}
+
+module_init(pm8xxx_upl_init);
+module_exit(pm8xxx_upl_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PM8XXX UPL driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:" PM8XXX_UPL_DEV_NAME);
diff --git a/drivers/misc/pm8xxx-vibrator.c b/drivers/misc/pm8xxx-vibrator.c
index 8aa7f72..62e7b45 100644
--- a/drivers/misc/pm8xxx-vibrator.c
+++ b/drivers/misc/pm8xxx-vibrator.c
@@ -27,6 +27,7 @@
#define VIB_DRV_SEL_MASK 0xf8
#define VIB_DRV_SEL_SHIFT 0x03
#define VIB_DRV_EN_MANUAL_MASK 0xfc
+#define VIB_DRV_LOGIC_SHIFT 0x2
#define VIB_MAX_LEVEL_mV 3100
#define VIB_MIN_LEVEL_mV 1200
@@ -43,6 +44,40 @@
u8 reg_vib_drv;
};
+static struct pm8xxx_vib *vib_dev;
+
+int pm8xxx_vibrator_config(struct pm8xxx_vib_config *vib_config)
+{
+ u8 reg = 0;
+ int rc;
+
+ if (vib_dev == NULL) {
+ pr_err("%s: vib_dev is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ if (vib_config->drive_mV) {
+ if ((vib_config->drive_mV < VIB_MIN_LEVEL_mV) ||
+ (vib_config->drive_mV > VIB_MAX_LEVEL_mV)) {
+ pr_err("Invalid vibrator drive strength\n");
+ return -EINVAL;
+ }
+ }
+
+ reg = (vib_config->drive_mV / 100) << VIB_DRV_SEL_SHIFT;
+
+ reg |= (!!vib_config->active_low) << VIB_DRV_LOGIC_SHIFT;
+
+ reg |= vib_config->enable_mode;
+
+ rc = pm8xxx_writeb(vib_dev->dev->parent, VIB_DRV, reg);
+ if (rc)
+ pr_err("%s: pm8xxx write failed: rc=%d\n", __func__, rc);
+
+ return rc;
+}
+EXPORT_SYMBOL(pm8xxx_vibrator_config);
+
/* REVISIT: just for debugging, will be removed in final working version */
static void __dump_vib_regs(struct pm8xxx_vib *vib, char *msg)
{
@@ -110,9 +145,8 @@
timed_dev);
unsigned long flags;
- spin_lock_irqsave(&vib->lock, flags);
-
retry:
+ spin_lock_irqsave(&vib->lock, flags);
if (hrtimer_try_to_cancel(&vib->vib_timer) < 0) {
spin_unlock_irqrestore(&vib->lock, flags);
cpu_relax();
@@ -240,6 +274,8 @@
platform_set_drvdata(pdev, vib);
+ vib_dev = vib;
+
return 0;
err_read_vib:
diff --git a/drivers/misc/pmem.c b/drivers/misc/pmem.c
index b94de48..692849a 100644
--- a/drivers/misc/pmem.c
+++ b/drivers/misc/pmem.c
@@ -1970,6 +1970,13 @@
if (!file)
return -EBADF;
+ /*
+ * check that the vaddr passed for flushing is valid
+ * so that you don't crash the kernel
+ */
+ if (!pmem_addr->vaddr)
+ return -EINVAL;
+
data = file->private_data;
id = get_id(file);
diff --git a/drivers/misc/pmic8058-nfc.c b/drivers/misc/pmic8058-nfc.c
deleted file mode 100644
index 76a19f4..0000000
--- a/drivers/misc/pmic8058-nfc.c
+++ /dev/null
@@ -1,322 +0,0 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * 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.
- *
- */
-/*
- * Qualcomm PMIC8058 NFC driver
- *
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/mfd/pmic8058.h>
-#include <linux/pmic8058-nfc.h>
-#include <linux/debugfs.h>
-#include <linux/slab.h>
-
-/* PMIC8058 NFC */
-#define SSBI_REG_NFC_CTRL 0x14D
-#define SSBI_REG_NFC_TEST 0x14E
-
-/* NFC_CTRL */
-#define PM8058_NFC_SUPPORT_EN 0x80
-#define PM8058_NFC_LDO_EN 0x40
-#define PM8058_NFC_EN 0x20
-#define PM8058_NFC_EXT_VDDLDO_EN 0x10
-#define PM8058_NFC_VPH_PWR_EN 0x08
-#define PM8058_NFC_RESERVED 0x04
-#define PM8058_NFC_VDDLDO_LEVEL 0x03
-
-/* NFC_TEST */
-#define PM8058_NFC_VDDLDO_MON_EN 0x80
-#define PM8058_NFC_ATEST_EN 0x40
-#define PM8058_NFC_DTEST1_EN 0x20
-#define PM8058_NFC_RESERVED2 0x18
-#define PM8058_NFC_VDDLDO_OK_S 0x04
-#define PM8058_NFC_MBG_EN_S 0x02
-#define PM8058_NFC_EXT_EN_S 0x01
-
-struct pm8058_nfc_device {
- struct mutex nfc_mutex;
- struct pm8058_chip *pm_chip;
-#if defined(CONFIG_DEBUG_FS)
- struct dentry *dent;
-#endif
-};
-static struct pm8058_nfc_device *nfc_dev;
-
-/* APIs */
-/*
- * pm8058_nfc_request - request a handle to access NFC device
- */
-struct pm8058_nfc_device *pm8058_nfc_request(void)
-{
- return nfc_dev;
-}
-EXPORT_SYMBOL(pm8058_nfc_request);
-
-/*
- * pm8058_nfc_config - configure NFC signals
- *
- * @nfcdev: the NFC device
- * @mask: signal mask to configure
- * @flags: control flags
- */
-int pm8058_nfc_config(struct pm8058_nfc_device *nfcdev, u32 mask, u32 flags)
-{
- u8 nfc_ctrl, nfc_test, m, f;
- int rc;
-
- if (nfcdev == NULL || IS_ERR(nfcdev) || !mask)
- return -EINVAL;
- if (nfcdev->pm_chip == NULL)
- return -ENODEV;
-
- mutex_lock(&nfcdev->nfc_mutex);
-
- if (!(mask & PM_NFC_CTRL_REQ))
- goto config_test;
-
- rc = pm8058_read(nfcdev->pm_chip, SSBI_REG_NFC_CTRL, &nfc_ctrl, 1);
- if (rc) {
- pr_err("%s: FAIL pm8058_read(): rc=%d (nfc_ctrl=0x%x)\n",
- __func__, rc, nfc_ctrl);
- goto config_done;
- }
-
- m = mask & 0x00ff;
- f = flags & 0x00ff;
- nfc_ctrl &= ~m;
- nfc_ctrl |= m & f;
-
- rc = pm8058_write(nfcdev->pm_chip, SSBI_REG_NFC_CTRL, &nfc_ctrl, 1);
- if (rc) {
- pr_err("%s: FAIL pm8058_write(): rc=%d (nfc_ctrl=0x%x)\n",
- __func__, rc, nfc_ctrl);
- goto config_done;
- }
-
-config_test:
- if (!(mask & PM_NFC_TEST_REQ))
- goto config_done;
-
- rc = pm8058_read(nfcdev->pm_chip, SSBI_REG_NFC_TEST, &nfc_test, 1);
- if (rc) {
- pr_err("%s: FAIL pm8058_read(): rc=%d (nfc_test=0x%x)\n",
- __func__, rc, nfc_test);
- goto config_done;
- }
-
- m = (mask >> 8) & 0x00ff;
- f = (flags >> 8) & 0x00ff;
- nfc_test &= ~m;
- nfc_test |= m & f;
-
- rc = pm8058_write(nfcdev->pm_chip, SSBI_REG_NFC_TEST, &nfc_test, 1);
- if (rc) {
- pr_err("%s: FAIL pm8058_write(): rc=%d (nfc_test=0x%x)\n",
- __func__, rc, nfc_test);
- goto config_done;
- }
-
-config_done:
- mutex_unlock(&nfcdev->nfc_mutex);
- return 0;
-}
-EXPORT_SYMBOL(pm8058_nfc_config);
-
-/*
- * pm8058_nfc_get_status - get NFC status
- *
- * @nfcdev: the NFC device
- * @mask: of status mask to read
- * @status: pointer to the status variable
- */
-int pm8058_nfc_get_status(struct pm8058_nfc_device *nfcdev,
- u32 mask, u32 *status)
-{
- u8 nfc_ctrl, nfc_test;
- u32 st;
- int rc;
-
- if (nfcdev == NULL || IS_ERR(nfcdev) || status == NULL)
- return -EINVAL;
- if (nfcdev->pm_chip == NULL)
- return -ENODEV;
-
- st = 0;
- mutex_lock(&nfcdev->nfc_mutex);
-
- if (!(mask & PM_NFC_CTRL_REQ))
- goto read_test;
-
- rc = pm8058_read(nfcdev->pm_chip, SSBI_REG_NFC_CTRL, &nfc_ctrl, 1);
- if (rc) {
- pr_err("%s: FAIL pm8058_read(): rc=%d (nfc_ctrl=0x%x)\n",
- __func__, rc, nfc_ctrl);
- goto get_status_done;
- }
-
-read_test:
- if (!(mask & (PM_NFC_TEST_REQ | PM_NFC_TEST_STATUS)))
- goto get_status_done;
-
- rc = pm8058_read(nfcdev->pm_chip, SSBI_REG_NFC_TEST, &nfc_test, 1);
- if (rc)
- pr_err("%s: FAIL pm8058_read(): rc=%d (nfc_test=0x%x)\n",
- __func__, rc, nfc_test);
-
-get_status_done:
- st = nfc_ctrl;
- st |= nfc_test << 8;
- *status = st;
-
- mutex_unlock(&nfcdev->nfc_mutex);
- return 0;
-}
-EXPORT_SYMBOL(pm8058_nfc_get_status);
-
-/*
- * pm8058_nfc_free - free the NFC device
- */
-void pm8058_nfc_free(struct pm8058_nfc_device *nfcdev)
-{
- /* Disable all signals */
- pm8058_nfc_config(nfcdev, PM_NFC_CTRL_REQ, 0);
-}
-EXPORT_SYMBOL(pm8058_nfc_free);
-
-#if defined(CONFIG_DEBUG_FS)
-static int pm8058_nfc_debug_set(void *data, u64 val)
-{
- struct pm8058_nfc_device *nfcdev;
- u32 mask, control;
- int rc;
-
- nfcdev = (struct pm8058_nfc_device *)data;
- control = (u32)val & 0xffff;
- mask = ((u32)val >> 16) & 0xffff;
- rc = pm8058_nfc_config(nfcdev, mask, control);
- if (rc)
- pr_err("%s: ERR pm8058_nfc_config: rc=%d, "
- "[mask, control]=[0x%x, 0x%x]\n",
- __func__, rc, mask, control);
-
- return 0;
-}
-
-static int pm8058_nfc_debug_get(void *data, u64 *val)
-{
- struct pm8058_nfc_device *nfcdev;
- u32 status;
- int rc;
-
- nfcdev = (struct pm8058_nfc_device *)data;
- rc = pm8058_nfc_get_status(nfcdev, (u32)-1, &status);
- if (rc)
- pr_err("%s: ERR pm8058_nfc_get_status: rc=%d, status=0x%x\n",
- __func__, rc, status);
-
- if (val)
- *val = (u64)status;
- return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(pm8058_nfc_fops, pm8058_nfc_debug_get,
- pm8058_nfc_debug_set, "%llu\n");
-
-static int pm8058_nfc_debug_init(struct pm8058_nfc_device *nfcdev)
-{
- struct dentry *dent;
-
- dent = debugfs_create_file("pm8058-nfc", 0644, NULL,
- (void *)nfcdev, &pm8058_nfc_fops);
-
- if (dent == NULL || IS_ERR(dent))
- pr_err("%s: ERR debugfs_create_file: dent=0x%x\n",
- __func__, (unsigned)dent);
-
- nfcdev->dent = dent;
- return 0;
-}
-#endif
-
-static int __devinit pmic8058_nfc_probe(struct platform_device *pdev)
-{
- struct pm8058_chip *pm_chip;
- struct pm8058_nfc_device *nfcdev;
-
- pm_chip = dev_get_drvdata(pdev->dev.parent);
- if (pm_chip == NULL) {
- pr_err("%s: no parent data passed in.\n", __func__);
- return -EFAULT;
- }
-
- nfcdev = kzalloc(sizeof *nfcdev, GFP_KERNEL);
- if (nfcdev == NULL) {
- pr_err("%s: kzalloc() failed.\n", __func__);
- return -ENOMEM;
- }
-
- mutex_init(&nfcdev->nfc_mutex);
-
- nfcdev->pm_chip = pm_chip;
- nfc_dev = nfcdev;
- platform_set_drvdata(pdev, nfcdev);
-
-#if defined(CONFIG_DEBUG_FS)
- pm8058_nfc_debug_init(nfc_dev);
-#endif
-
- pr_notice("%s: OK\n", __func__);
- return 0;
-}
-
-static int __devexit pmic8058_nfc_remove(struct platform_device *pdev)
-{
- struct pm8058_nfc_device *nfcdev = platform_get_drvdata(pdev);
-
-#if defined(CONFIG_DEBUG_FS)
- debugfs_remove(nfcdev->dent);
-#endif
-
- platform_set_drvdata(pdev, nfcdev->pm_chip);
- kfree(nfcdev);
- return 0;
-}
-
-static struct platform_driver pmic8058_nfc_driver = {
- .probe = pmic8058_nfc_probe,
- .remove = __devexit_p(pmic8058_nfc_remove),
- .driver = {
- .name = "pm8058-nfc",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init pm8058_nfc_init(void)
-{
- return platform_driver_register(&pmic8058_nfc_driver);
-}
-
-static void __exit pm8058_nfc_exit(void)
-{
- platform_driver_unregister(&pmic8058_nfc_driver);
-}
-
-module_init(pm8058_nfc_init);
-module_exit(pm8058_nfc_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PMIC8058 NFC driver");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:pmic8058-nfc");
diff --git a/drivers/misc/pmic8058-pwm.c b/drivers/misc/pmic8058-pwm.c
index ad03b88..33407b7 100644
--- a/drivers/misc/pmic8058-pwm.c
+++ b/drivers/misc/pmic8058-pwm.c
@@ -19,11 +19,11 @@
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <linux/err.h>
#include <linux/pwm.h>
-#include <linux/mfd/pmic8058.h>
+#include <linux/mfd/pm8xxx/core.h>
#include <linux/pmic8058-pwm.h>
-#include <linux/slab.h>
#define PM8058_LPG_BANKS 8
#define PM8058_PWM_CHANNELS PM8058_LPG_BANKS /* MAX=8 */
@@ -179,6 +179,7 @@
struct pm8058_pwm_chip;
struct pwm_device {
+ struct device *dev;
int pwm_id; /* = bank/channel id */
int in_use;
const char *label;
@@ -188,14 +189,13 @@
int use_lut; /* Use LUT to output PWM */
u8 pwm_ctl[PM8058_LPG_CTL_REGS];
int irq;
- struct pm8058_pwm_chip *chip;
+ struct pm8058_pwm_chip *chip;
};
struct pm8058_pwm_chip {
struct pwm_device pwm_dev[PM8058_PWM_CHANNELS];
u8 bank_mask;
struct mutex pwm_mutex;
- struct pm8058_chip *pm_chip;
struct pm8058_pwm_pdata *pdata;
};
@@ -244,9 +244,10 @@
else
reg = chip->bank_mask & ~(1 << pwm->pwm_id);
- rc = pm8058_write(chip->pm_chip, SSBI_REG_ADDR_LPG_BANK_EN, ®, 1);
+ rc = pm8xxx_writeb(pwm->dev->parent,
+ SSBI_REG_ADDR_LPG_BANK_EN, reg);
if (rc) {
- pr_err("pm8058_write(): rc=%d (Enable LPG Bank)\n", rc);
+ pr_err("pm8xxx_write(): rc=%d (Enable LPG Bank)\n", rc);
goto bail_out;
}
chip->bank_mask = reg;
@@ -261,10 +262,10 @@
u8 reg;
reg = pwm->pwm_id;
- rc = pm8058_write(pwm->chip->pm_chip, SSBI_REG_ADDR_LPG_BANK_SEL,
- ®, 1);
+ rc = pm8xxx_writeb(pwm->dev->parent,
+ SSBI_REG_ADDR_LPG_BANK_SEL, reg);
if (rc)
- pr_err("pm8058_write(): rc=%d (Select PWM Bank)\n", rc);
+ pr_err("pm8xxx_write(): rc=%d (Select PWM Bank)\n", rc);
return rc;
}
@@ -284,10 +285,10 @@
reg &= ~PM8058_PWM_RAMP_GEN_START;
}
- rc = pm8058_write(pwm->chip->pm_chip, SSBI_REG_ADDR_LPG_CTL(0),
- ®, 1);
+ rc = pm8xxx_writeb(pwm->dev->parent, SSBI_REG_ADDR_LPG_CTL(0),
+ reg);
if (rc)
- pr_err("pm8058_write(): rc=%d (Enable PWM Ctl 0)\n", rc);
+ pr_err("pm8xxx_write(): rc=%d (Enable PWM Ctl 0)\n", rc);
else
pwm->pwm_ctl[0] = reg;
return rc;
@@ -415,15 +416,13 @@
cfg1 = (pwm_value >> 1) & 0x80;
cfg1 |= start_idx + i;
- rc = pm8058_write(pwm->chip->pm_chip,
- SSBI_REG_ADDR_LPG_LUT_CFG0,
- &cfg0, 1);
+ rc = pm8xxx_writeb(pwm->dev->parent,
+ SSBI_REG_ADDR_LPG_LUT_CFG0, cfg0);
if (rc)
break;
- rc = pm8058_write(pwm->chip->pm_chip,
- SSBI_REG_ADDR_LPG_LUT_CFG1,
- &cfg1, 1);
+ rc = pm8xxx_writeb(pwm->dev->parent,
+ SSBI_REG_ADDR_LPG_LUT_CFG1, cfg1);
if (rc)
break;
}
@@ -539,11 +538,11 @@
/* Write in reverse way so 0 would be the last */
for (i = end - 1; i >= start; i--) {
- rc = pm8058_write(pwm->chip->pm_chip,
+ rc = pm8xxx_writeb(pwm->dev->parent,
SSBI_REG_ADDR_LPG_CTL(i),
- &pwm->pwm_ctl[i], 1);
+ pwm->pwm_ctl[i]);
if (rc) {
- pr_err("pm8058_write(): rc=%d (PWM Ctl[%d])\n", rc, i);
+ pr_err("pm8xxx_write(): rc=%d (PWM Ctl[%d])\n", rc, i);
return rc;
}
}
@@ -957,8 +956,8 @@
case PM_PWM_LED_2:
conf = mode & PM8058_LED_MODE_MASK;
conf |= (max_current / 2) << PM8058_LED_CURRENT_SHIFT;
- rc = pm8058_write(pwm->chip->pm_chip,
- SSBI_REG_ADDR_LED(id), &conf, 1);
+ rc = pm8xxx_writeb(pwm->dev->parent,
+ SSBI_REG_ADDR_LED(id), conf);
break;
case PM_PWM_LED_KPD:
@@ -982,8 +981,8 @@
}
conf |= (max_current / 20) << PM8058_FLASH_CURRENT_SHIFT;
id -= PM_PWM_LED_KPD;
- rc = pm8058_write(pwm->chip->pm_chip,
- SSBI_REG_ADDR_FLASH(id), &conf, 1);
+ rc = pm8xxx_writeb(pwm->dev->parent,
+ SSBI_REG_ADDR_FLASH(id), conf);
break;
default:
rc = -EINVAL;
@@ -1012,10 +1011,10 @@
/* Only Test 1 available */
reg |= (1 << PM8058_PWM_DTEST_SHIFT) &
PM8058_PWM_DTEST_MASK;
- rc = pm8058_write(pwm->chip->pm_chip, SSBI_REG_ADDR_LPG_TEST,
- ®, 1);
+ rc = pm8xxx_writeb(pwm->dev->parent,
+ SSBI_REG_ADDR_LPG_TEST, reg);
if (rc)
- pr_err("pm8058_write(DTEST=0x%x): rc=%d\n", reg, rc);
+ pr_err("pm8xxx_write(DTEST=0x%x): rc=%d\n", reg, rc);
}
return rc;
@@ -1024,16 +1023,9 @@
static int __devinit pmic8058_pwm_probe(struct platform_device *pdev)
{
- struct pm8058_chip *pm_chip;
struct pm8058_pwm_chip *chip;
int i;
- pm_chip = dev_get_drvdata(pdev->dev.parent);
- if (pm_chip == NULL) {
- pr_err("no parent data passed in.\n");
- return -EFAULT;
- }
-
chip = kzalloc(sizeof *chip, GFP_KERNEL);
if (chip == NULL) {
pr_err("kzalloc() failed.\n");
@@ -1043,12 +1035,12 @@
for (i = 0; i < PM8058_PWM_CHANNELS; i++) {
chip->pwm_dev[i].pwm_id = i;
chip->pwm_dev[i].chip = chip;
+ chip->pwm_dev[i].dev = &pdev->dev;
}
mutex_init(&chip->pwm_mutex);
chip->pdata = pdev->dev.platform_data;
- chip->pm_chip = pm_chip;
pwm_chip = chip;
platform_set_drvdata(pdev, chip);
diff --git a/drivers/misc/pmic8058-upl.c b/drivers/misc/pmic8058-upl.c
deleted file mode 100644
index ae0abd8..0000000
--- a/drivers/misc/pmic8058-upl.c
+++ /dev/null
@@ -1,363 +0,0 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * 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.
- *
- */
-/*
- * Qualcomm PMIC8058 UPL driver
- *
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/mfd/pmic8058.h>
-#include <linux/pmic8058-upl.h>
-#include <linux/debugfs.h>
-#include <linux/slab.h>
-
-/* PMIC8058 UPL registers */
-#define SSBI_REG_UPL_CTRL 0x17B
-#define SSBI_REG_UPL_TRUTHTABLE1 0x17C
-#define SSBI_REG_UPL_TRUTHTABLE2 0x17D
-
-struct pm8058_upl_device {
- struct mutex upl_mutex;
- struct pm8058_chip *pm_chip;
-#if defined(CONFIG_DEBUG_FS)
- struct dentry *dent;
-#endif
-};
-static struct pm8058_upl_device *upl_dev;
-
-/* APIs */
-
-/*
- * pm8058_upl_request - request a handle to access UPL device
- */
-struct pm8058_upl_device *pm8058_upl_request(void)
-{
- return upl_dev;
-}
-EXPORT_SYMBOL(pm8058_upl_request);
-
-/*
- * pm8058_upl_read_truthtable - read value currently stored in UPL truth table
- *
- * @upldev: the UPL device
- * @truthtable: value read from UPL truth table
- */
-int pm8058_upl_read_truthtable(struct pm8058_upl_device *upldev,
- u16 *truthtable)
-{
- int rc = 0;
- u8 table[2];
-
- if (upldev == NULL || IS_ERR(upldev))
- return -EINVAL;
- if (upldev->pm_chip == NULL)
- return -ENODEV;
-
- mutex_lock(&upldev->upl_mutex);
-
- rc = pm8058_read(upldev->pm_chip, SSBI_REG_UPL_TRUTHTABLE1,
- &(table[0]), 1);
- if (rc) {
- pr_err("%s: FAIL pm8058_read(0x%X)=0x%02X: rc=%d\n",
- __func__, SSBI_REG_UPL_TRUTHTABLE1, table[0], rc);
- goto upl_read_done;
- }
-
- rc = pm8058_read(upldev->pm_chip, SSBI_REG_UPL_TRUTHTABLE2,
- &(table[1]), 1);
- if (rc)
- pr_err("%s: FAIL pm8058_read(0x%X)=0x%02X: rc=%d\n",
- __func__, SSBI_REG_UPL_TRUTHTABLE2, table[1], rc);
-upl_read_done:
- mutex_unlock(&upldev->upl_mutex);
- *truthtable = (((u16)table[1]) << 8) | table[0];
- return rc;
-}
-EXPORT_SYMBOL(pm8058_upl_read_truthtable);
-
-/*
- * pm8058_upl_writes_truthtable - write value into UPL truth table
- *
- * @upldev: the UPL device
- * @truthtable: value written to UPL truth table
- *
- * Each bit in parameter "truthtable" corresponds to the UPL output for a given
- * set of input pin values. For example, if the input pins have the following
- * values: A=1, B=1, C=1, D=0, then the UPL would output the value of bit 14
- * (0b1110) in parameter "truthtable".
- */
-int pm8058_upl_write_truthtable(struct pm8058_upl_device *upldev,
- u16 truthtable)
-{
- int rc = 0;
- u8 table[2];
-
- if (upldev == NULL || IS_ERR(upldev))
- return -EINVAL;
- if (upldev->pm_chip == NULL)
- return -ENODEV;
-
- table[0] = truthtable & 0xFF;
- table[1] = (truthtable >> 8) & 0xFF;
-
- mutex_lock(&upldev->upl_mutex);
-
- rc = pm8058_write(upldev->pm_chip, SSBI_REG_UPL_TRUTHTABLE1,
- &(table[0]), 1);
- if (rc) {
- pr_err("%s: FAIL pm8058_write(0x%X)=0x%04X: rc=%d\n",
- __func__, SSBI_REG_UPL_TRUTHTABLE1, table[0], rc);
- goto upl_write_done;
- }
-
- rc = pm8058_write(upldev->pm_chip, SSBI_REG_UPL_TRUTHTABLE2,
- &(table[1]), 1);
- if (rc)
- pr_err("%s: FAIL pm8058_write(0x%X)=0x%04X: rc=%d\n",
- __func__, SSBI_REG_UPL_TRUTHTABLE2, table[1], rc);
-upl_write_done:
- mutex_unlock(&upldev->upl_mutex);
- return rc;
-}
-EXPORT_SYMBOL(pm8058_upl_write_truthtable);
-
-/*
- * pm8058_upl_config - configure UPL I/O settings and UPL enable/disable
- *
- * @upldev: the UPL device
- * @mask: setting mask to configure
- * @flags: setting flags
- */
-int pm8058_upl_config(struct pm8058_upl_device *upldev, u32 mask, u32 flags)
-{
- int rc;
- u8 upl_ctrl, m, f;
-
- if (upldev == NULL || IS_ERR(upldev))
- return -EINVAL;
- if (upldev->pm_chip == NULL)
- return -ENODEV;
-
- mutex_lock(&upldev->upl_mutex);
-
- rc = pm8058_read(upldev->pm_chip, SSBI_REG_UPL_CTRL, &upl_ctrl, 1);
- if (rc) {
- pr_err("%s: FAIL pm8058_read(0x%X)=0x%02X: rc=%d\n",
- __func__, SSBI_REG_UPL_CTRL, upl_ctrl, rc);
- goto upl_config_done;
- }
-
- m = mask & 0x00ff;
- f = flags & 0x00ff;
- upl_ctrl &= ~m;
- upl_ctrl |= m & f;
-
- rc = pm8058_write(upldev->pm_chip, SSBI_REG_UPL_CTRL, &upl_ctrl, 1);
- if (rc)
- pr_err("%s: FAIL pm8058_write(0x%X)=0x%02X: rc=%d\n",
- __func__, SSBI_REG_UPL_CTRL, upl_ctrl, rc);
-upl_config_done:
- mutex_unlock(&upldev->upl_mutex);
- return rc;
-}
-EXPORT_SYMBOL(pm8058_upl_config);
-
-#if defined(CONFIG_DEBUG_FS)
-
-static int truthtable_set(void *data, u64 val)
-{
- int rc;
-
- rc = pm8058_upl_write_truthtable(data, val);
- if (rc)
- pr_err("%s: pm8058_upl_write_truthtable: rc=%d, "
- "truthtable=0x%llX\n", __func__, rc, val);
- return rc;
-}
-
-static int truthtable_get(void *data, u64 *val)
-{
- int rc;
- u16 truthtable;
-
- rc = pm8058_upl_read_truthtable(data, &truthtable);
- if (rc)
- pr_err("%s: pm8058_upl_read_truthtable: rc=%d, "
- "truthtable=0x%X\n", __func__, rc, truthtable);
- if (val)
- *val = truthtable;
-
- return rc;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(upl_truthtable_fops, truthtable_get,
- truthtable_set, "0x%04llX\n");
-
-/* enter values as 0xMMMMFFFF where MMMM is the mask and FFFF is the flags */
-static int control_set(void *data, u64 val)
-{
- u8 mask, flags;
- int rc;
-
- flags = val & 0xFFFF;
- mask = (val >> 16) & 0xFFFF;
-
- rc = pm8058_upl_config(data, mask, flags);
- if (rc)
- pr_err("%s: pm8058_upl_config: rc=%d, mask = 0x%X, "
- "flags = 0x%X\n", __func__, rc, mask, flags);
- return rc;
-}
-
-static int control_get(void *data, u64 *val)
-{
- struct pm8058_upl_device *upldev;
- int rc = 0;
- u8 ctrl;
-
- upldev = data;
-
- mutex_lock(&upldev->upl_mutex);
-
- rc = pm8058_read(upldev->pm_chip, SSBI_REG_UPL_CTRL, &ctrl, 1);
- if (rc)
- pr_err("%s: FAIL pm8058_read(): rc=%d (ctrl=0x%02X)\n",
- __func__, rc, ctrl);
-
- mutex_unlock(&upldev->upl_mutex);
-
- *val = ctrl;
-
- return rc;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(upl_control_fops, control_get,
- control_set, "0x%02llX\n");
-
-static int pm8058_upl_debug_init(struct pm8058_upl_device *upldev)
-{
- struct dentry *dent;
- struct dentry *temp;
-
- dent = debugfs_create_dir("pm8058-upl", NULL);
- if (dent == NULL || IS_ERR(dent)) {
- pr_err("%s: ERR debugfs_create_dir: dent=0x%X\n",
- __func__, (unsigned)dent);
- return -ENOMEM;
- }
-
- temp = debugfs_create_file("truthtable", S_IRUSR | S_IWUSR, dent,
- upldev, &upl_truthtable_fops);
- if (temp == NULL || IS_ERR(temp)) {
- pr_err("%s: ERR debugfs_create_file: dent=0x%X\n",
- __func__, (unsigned)dent);
- goto debug_error;
- }
-
- temp = debugfs_create_file("control", S_IRUSR | S_IWUSR, dent,
- upldev, &upl_control_fops);
- if (temp == NULL || IS_ERR(temp)) {
- pr_err("%s: ERR debugfs_create_file: dent=0x%X\n",
- __func__, (unsigned)dent);
- goto debug_error;
- }
-
- upldev->dent = dent;
- return 0;
-
-debug_error:
- debugfs_remove_recursive(dent);
- return -ENOMEM;
-}
-
-static int __devexit pm8058_upl_debug_remove(struct pm8058_upl_device *upldev)
-{
- debugfs_remove_recursive(upldev->dent);
- return 0;
-}
-
-#endif /* CONFIG_DEBUG_FS */
-
-static int __devinit pmic8058_upl_probe(struct platform_device *pdev)
-{
- struct pm8058_chip *pm_chip;
- struct pm8058_upl_device *upldev;
-
- pm_chip = dev_get_drvdata(pdev->dev.parent);
- if (pm_chip == NULL) {
- pr_err("%s: no parent data passed in.\n", __func__);
- return -EFAULT;
- }
-
- upldev = kzalloc(sizeof *upldev, GFP_KERNEL);
- if (upldev == NULL) {
- pr_err("%s: kzalloc() failed.\n", __func__);
- return -ENOMEM;
- }
-
- mutex_init(&upldev->upl_mutex);
-
- upldev->pm_chip = pm_chip;
- upl_dev = upldev;
- platform_set_drvdata(pdev, upldev);
-
-#if defined(CONFIG_DEBUG_FS)
- pm8058_upl_debug_init(upl_dev);
-#endif
- pr_notice("%s: OK\n", __func__);
- return 0;
-}
-
-static int __devexit pmic8058_upl_remove(struct platform_device *pdev)
-{
- struct pm8058_upl_device *upldev = platform_get_drvdata(pdev);
-
-#if defined(CONFIG_DEBUG_FS)
- pm8058_upl_debug_remove(upldev);
-#endif
-
- platform_set_drvdata(pdev, upldev->pm_chip);
- kfree(upldev);
- pr_notice("%s: OK\n", __func__);
-
- return 0;
-}
-
-static struct platform_driver pmic8058_upl_driver = {
- .probe = pmic8058_upl_probe,
- .remove = __devexit_p(pmic8058_upl_remove),
- .driver = {
- .name = "pm8058-upl",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init pm8058_upl_init(void)
-{
- return platform_driver_register(&pmic8058_upl_driver);
-}
-
-static void __exit pm8058_upl_exit(void)
-{
- platform_driver_unregister(&pmic8058_upl_driver);
-}
-
-module_init(pm8058_upl_init);
-module_exit(pm8058_upl_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PMIC8058 UPL driver");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:pmic8058-upl");
diff --git a/drivers/misc/pmic8058-xoadc.c b/drivers/misc/pmic8058-xoadc.c
index b63800c..14b790f 100644
--- a/drivers/misc/pmic8058-xoadc.c
+++ b/drivers/misc/pmic8058-xoadc.c
@@ -17,7 +17,7 @@
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/msm_adc.h>
-#include <linux/pmic8058-xoadc.h>
+#include <linux/mfd/pm8xxx/core.h>
#include <linux/mfd/pmic8058.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
@@ -54,8 +54,8 @@
#define ADC_ARB_USRP_DATA1 0x19C
struct pmic8058_adc {
+ struct device *dev;
struct xoadc_platform_data *pdata;
- struct pm8058_chip *pm_chip;
struct adc_properties *adc_prop;
struct xoadc_conv_state conv[2];
int xoadc_queue_count;
@@ -144,8 +144,8 @@
/* Write twice to the CNTRL register for the arbiter settings
to take into effect */
for (i = 0; i < 2; i++) {
- rc = pm8058_write(adc_pmic->pm_chip, ADC_ARB_USRP_CNTRL,
- &data_arb_cntrl, 1);
+ rc = pm8xxx_writeb(adc_pmic->dev->parent, ADC_ARB_USRP_CNTRL,
+ data_arb_cntrl);
if (rc < 0) {
pr_debug("%s: PM8058 write failed\n", __func__);
return rc;
@@ -165,8 +165,8 @@
{
struct pmic8058_adc *adc_pmic = pmic_adc[adc_instance];
- u8 data_arb_cntrl, data_amux_chan, data_arb_rsv, data_ana_param;
- u8 data_dig_param, data_ana_param2;
+ u8 data_arb_cntrl = 0, data_amux_chan = 0, data_arb_rsv = 0;
+ u8 data_dig_param = 0, data_ana_param2 = 0, data_ana_param = 0;
int rc;
rc = pm8058_xoadc_arb_cntrl(1, adc_instance, slot->chan_path);
@@ -307,15 +307,15 @@
break;
}
- rc = pm8058_write(adc_pmic->pm_chip,
- ADC_ARB_USRP_AMUX_CNTRL, &data_amux_chan, 1);
+ rc = pm8xxx_writeb(adc_pmic->dev->parent,
+ ADC_ARB_USRP_AMUX_CNTRL, data_amux_chan);
if (rc < 0) {
pr_debug("%s: PM8058 write failed\n", __func__);
return rc;
}
- rc = pm8058_write(adc_pmic->pm_chip,
- ADC_ARB_USRP_RSV, &data_arb_rsv, 1);
+ rc = pm8xxx_writeb(adc_pmic->dev->parent,
+ ADC_ARB_USRP_RSV, data_arb_rsv);
if (rc < 0) {
pr_debug("%s: PM8058 write failed\n", __func__);
return rc;
@@ -341,22 +341,22 @@
break;
}
- rc = pm8058_write(adc_pmic->pm_chip,
- ADC_ARB_USRP_ANA_PARAM, &data_ana_param, 1);
+ rc = pm8xxx_writeb(adc_pmic->dev->parent,
+ ADC_ARB_USRP_ANA_PARAM, data_ana_param);
if (rc < 0) {
pr_debug("%s: PM8058 write failed\n", __func__);
return rc;
}
- rc = pm8058_write(adc_pmic->pm_chip,
- ADC_ARB_USRP_DIG_PARAM, &data_dig_param, 1);
+ rc = pm8xxx_writeb(adc_pmic->dev->parent,
+ ADC_ARB_USRP_DIG_PARAM, data_dig_param);
if (rc < 0) {
pr_debug("%s: PM8058 write failed\n", __func__);
return rc;
}
- rc = pm8058_write(adc_pmic->pm_chip,
- ADC_ARB_USRP_ANA_PARAM, &data_ana_param2, 1);
+ rc = pm8xxx_writeb(adc_pmic->dev->parent,
+ ADC_ARB_USRP_ANA_PARAM, data_ana_param2);
if (rc < 0) {
pr_debug("%s: PM8058 write failed\n", __func__);
return rc;
@@ -364,8 +364,8 @@
enable_irq(adc_pmic->adc_irq);
- rc = pm8058_write(adc_pmic->pm_chip,
- ADC_ARB_USRP_CNTRL, &data_arb_cntrl, 1);
+ rc = pm8xxx_writeb(adc_pmic->dev->parent,
+ ADC_ARB_USRP_CNTRL, data_arb_cntrl);
if (rc < 0) {
pr_debug("%s: PM8058 write failed\n", __func__);
return rc;
@@ -434,13 +434,15 @@
if (!xoadc_initialized)
return -ENODEV;
- rc = pm8058_read(adc_pmic->pm_chip, ADC_ARB_USRP_DATA0, &rslt_lsb, 1);
+ rc = pm8xxx_readb(adc_pmic->dev->parent, ADC_ARB_USRP_DATA0,
+ &rslt_lsb);
if (rc < 0) {
pr_debug("%s: PM8058 read failed\n", __func__);
return rc;
}
- rc = pm8058_read(adc_pmic->pm_chip, ADC_ARB_USRP_DATA1, &rslt_msb, 1);
+ rc = pm8xxx_readb(adc_pmic->dev->parent, ADC_ARB_USRP_DATA1,
+ &rslt_msb);
if (rc < 0) {
pr_debug("%s: PM8058 read failed\n", __func__);
return rc;
@@ -657,7 +659,7 @@
wake_lock_destroy(&adc_pmic->adc_wakelock);
msm_xo_put(adc_pmic->adc_voter);
- platform_set_drvdata(pdev, adc_pmic->pm_chip);
+ platform_set_drvdata(pdev, NULL);
device_init_wakeup(&pdev->dev, 0);
kfree(adc_pmic);
xoadc_initialized = false;
@@ -668,16 +670,9 @@
static int __devinit pm8058_xoadc_probe(struct platform_device *pdev)
{
struct xoadc_platform_data *pdata = pdev->dev.platform_data;
- struct pm8058_chip *pm_chip;
struct pmic8058_adc *adc_pmic;
int i, rc = 0;
- pm_chip = dev_get_drvdata(pdev->dev.parent);
- if (pm_chip == NULL) {
- dev_err(&pdev->dev, "no parent data passed in\n");
- return -EFAULT;
- }
-
if (!pdata) {
dev_err(&pdev->dev, "no platform data?\n");
return -EINVAL;
@@ -689,7 +684,7 @@
return -ENOMEM;
}
- adc_pmic->pm_chip = pm_chip;
+ adc_pmic->dev = &pdev->dev;
adc_pmic->adc_prop = pdata->xoadc_prop;
adc_pmic->xoadc_num = pdata->xoadc_num;
adc_pmic->xoadc_queue_count = 0;
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 0c81fa4..1ee8538 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -521,7 +521,20 @@
return result;
}
-static u32 get_card_status(struct mmc_card *card, struct request *req)
+static int send_stop(struct mmc_card *card, u32 *status)
+{
+ struct mmc_command cmd = {0};
+ int err;
+
+ cmd.opcode = MMC_STOP_TRANSMISSION;
+ cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+ err = mmc_wait_for_cmd(card->host, &cmd, 5);
+ if (err == 0)
+ *status = cmd.resp[0];
+ return err;
+}
+
+static int get_card_status(struct mmc_card *card, u32 *status, int retries)
{
struct mmc_command cmd = {0};
int err;
@@ -530,11 +543,145 @@
if (!mmc_host_is_spi(card->host))
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
- err = mmc_wait_for_cmd(card->host, &cmd, 0);
+ err = mmc_wait_for_cmd(card->host, &cmd, retries);
+ if (err == 0)
+ *status = cmd.resp[0];
+ return err;
+}
+
+#define ERR_RETRY 2
+#define ERR_ABORT 1
+#define ERR_CONTINUE 0
+
+static int mmc_blk_cmd_error(struct request *req, const char *name, int error,
+ bool status_valid, u32 status)
+{
+ switch (error) {
+ case -EILSEQ:
+ /* response crc error, retry the r/w cmd */
+ pr_err("%s: %s sending %s command, card status %#x\n",
+ req->rq_disk->disk_name, "response CRC error",
+ name, status);
+ return ERR_RETRY;
+
+ case -ETIMEDOUT:
+ pr_err("%s: %s sending %s command, card status %#x\n",
+ req->rq_disk->disk_name, "timed out", name, status);
+
+ /* If the status cmd initially failed, retry the r/w cmd */
+ if (!status_valid) {
+ pr_err("%s: status not valid, retrying timeout\n", req->rq_disk->disk_name);
+ return ERR_RETRY;
+ }
+ /*
+ * If it was a r/w cmd crc error, or illegal command
+ * (eg, issued in wrong state) then retry - we should
+ * have corrected the state problem above.
+ */
+ if (status & (R1_COM_CRC_ERROR | R1_ILLEGAL_COMMAND)) {
+ pr_err("%s: command error, retrying timeout\n", req->rq_disk->disk_name);
+ return ERR_RETRY;
+ }
+
+ /* Otherwise abort the command */
+ pr_err("%s: not retrying timeout\n", req->rq_disk->disk_name);
+ return ERR_ABORT;
+
+ default:
+ /* We don't understand the error code the driver gave us */
+ pr_err("%s: unknown error %d sending read/write command, card status %#x\n",
+ req->rq_disk->disk_name, error, status);
+ return ERR_ABORT;
+ }
+}
+
+/*
+ * Initial r/w and stop cmd error recovery.
+ * We don't know whether the card received the r/w cmd or not, so try to
+ * restore things back to a sane state. Essentially, we do this as follows:
+ * - Obtain card status. If the first attempt to obtain card status fails,
+ * the status word will reflect the failed status cmd, not the failed
+ * r/w cmd. If we fail to obtain card status, it suggests we can no
+ * longer communicate with the card.
+ * - Check the card state. If the card received the cmd but there was a
+ * transient problem with the response, it might still be in a data transfer
+ * mode. Try to send it a stop command. If this fails, we can't recover.
+ * - If the r/w cmd failed due to a response CRC error, it was probably
+ * transient, so retry the cmd.
+ * - If the r/w cmd timed out, but we didn't get the r/w cmd status, retry.
+ * - If the r/w cmd timed out, and the r/w cmd failed due to CRC error or
+ * illegal cmd, retry.
+ * Otherwise we don't understand what happened, so abort.
+ */
+static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
+ struct mmc_blk_request *brq)
+{
+ bool prev_cmd_status_valid = true;
+ u32 status, stop_status = 0;
+ int err, retry;
+
+ /*
+ * Try to get card status which indicates both the card state
+ * and why there was no response. If the first attempt fails,
+ * we can't be sure the returned status is for the r/w command.
+ */
+ for (retry = 2; retry >= 0; retry--) {
+ err = get_card_status(card, &status, 0);
+ if (!err)
+ break;
+
+ prev_cmd_status_valid = false;
+ pr_err("%s: error %d sending status command, %sing\n",
+ req->rq_disk->disk_name, err, retry ? "retry" : "abort");
+ }
+
+ /* We couldn't get a response from the card. Give up. */
if (err)
- printk(KERN_ERR "%s: error %d sending status command",
- req->rq_disk->disk_name, err);
- return cmd.resp[0];
+ return ERR_ABORT;
+
+ /*
+ * Check the current card state. If it is in some data transfer
+ * mode, tell it to stop (and hopefully transition back to TRAN.)
+ */
+ if (R1_CURRENT_STATE(status) == R1_STATE_DATA ||
+ R1_CURRENT_STATE(status) == R1_STATE_RCV) {
+ err = send_stop(card, &stop_status);
+ if (err)
+ pr_err("%s: error %d sending stop command\n",
+ req->rq_disk->disk_name, err);
+
+ /*
+ * If the stop cmd also timed out, the card is probably
+ * not present, so abort. Other errors are bad news too.
+ */
+ if (err)
+ return ERR_ABORT;
+ }
+
+ /* Check for set block count errors */
+ if (brq->sbc.error)
+ return mmc_blk_cmd_error(req, "SET_BLOCK_COUNT", brq->sbc.error,
+ prev_cmd_status_valid, status);
+
+ /* Check for r/w command errors */
+ if (brq->cmd.error)
+ return mmc_blk_cmd_error(req, "r/w cmd", brq->cmd.error,
+ prev_cmd_status_valid, status);
+
+ /* Now for stop errors. These aren't fatal to the transfer. */
+ pr_err("%s: error %d sending stop command, original cmd response %#x, card status %#x\n",
+ req->rq_disk->disk_name, brq->stop.error,
+ brq->cmd.resp[0], status);
+
+ /*
+ * Subsitute in our own stop status as this will give the error
+ * state which happened during the execution of the r/w command.
+ */
+ if (stop_status) {
+ brq->stop.resp[0] = stop_status;
+ brq->stop.error = 0;
+ }
+ return ERR_CONTINUE;
}
static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
@@ -665,12 +812,20 @@
}
}
+#define CMD_ERRORS \
+ (R1_OUT_OF_RANGE | /* Command argument out of range */ \
+ R1_ADDRESS_ERROR | /* Misaligned address */ \
+ R1_BLOCK_LEN_ERROR | /* Transferred block length incorrect */\
+ R1_WP_VIOLATION | /* Tried to write to protected block */ \
+ R1_CC_ERROR | /* Card controller error */ \
+ R1_ERROR) /* General/unknown error */
+
static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
{
struct mmc_blk_data *md = mq->data;
struct mmc_card *card = md->queue.card;
struct mmc_blk_request brq;
- int ret = 1, disable_multi = 0;
+ int ret = 1, disable_multi = 0, retry = 0;
/*
* Reliable writes are used to implement Forced Unit Access and
@@ -682,8 +837,7 @@
(md->flags & MMC_BLK_REL_WR);
do {
- struct mmc_command cmd = {0};
- u32 readcmd, writecmd, status = 0;
+ u32 readcmd, writecmd;
memset(&brq, 0, sizeof(struct mmc_blk_request));
brq.mrq.cmd = &brq.cmd;
@@ -800,64 +954,47 @@
mmc_queue_bounce_post(mq);
/*
- * Check for errors here, but don't jump to cmd_err
- * until later as we need to wait for the card to leave
- * programming mode even when things go wrong.
+ * sbc.error indicates a problem with the set block count
+ * command. No data will have been transferred.
+ *
+ * cmd.error indicates a problem with the r/w command. No
+ * data will have been transferred.
+ *
+ * stop.error indicates a problem with the stop command. Data
+ * may have been transferred, or may still be transferring.
*/
- if (brq.sbc.error || brq.cmd.error ||
- brq.data.error || brq.stop.error) {
- if (brq.data.blocks > 1 && rq_data_dir(req) == READ) {
- /* Redo read one sector at a time */
- printk(KERN_WARNING "%s: retrying using single "
- "block read\n", req->rq_disk->disk_name);
- disable_multi = 1;
- continue;
+ if (brq.sbc.error || brq.cmd.error || brq.stop.error) {
+ switch (mmc_blk_cmd_recovery(card, req, &brq)) {
+ case ERR_RETRY:
+ if (retry++ < 5)
+ continue;
+ case ERR_ABORT:
+ goto cmd_abort;
+ case ERR_CONTINUE:
+ break;
}
- status = get_card_status(card, req);
- } else if (disable_multi == 1) {
- disable_multi = 0;
}
- if (brq.sbc.error) {
- printk(KERN_ERR "%s: error %d sending SET_BLOCK_COUNT "
- "command, response %#x, card status %#x\n",
- req->rq_disk->disk_name, brq.sbc.error,
- brq.sbc.resp[0], status);
+ /*
+ * Check for errors relating to the execution of the
+ * initial command - such as address errors. No data
+ * has been transferred.
+ */
+ if (brq.cmd.resp[0] & CMD_ERRORS) {
+ pr_err("%s: r/w command failed, status = %#x\n",
+ req->rq_disk->disk_name, brq.cmd.resp[0]);
+ goto cmd_abort;
}
- if (brq.cmd.error) {
- printk(KERN_ERR "%s: error %d sending read/write "
- "command, response %#x, card status %#x\n",
- req->rq_disk->disk_name, brq.cmd.error,
- brq.cmd.resp[0], status);
- }
-
- if (brq.data.error) {
- if (brq.data.error == -ETIMEDOUT && brq.mrq.stop)
- /* 'Stop' response contains card status */
- status = brq.mrq.stop->resp[0];
- printk(KERN_ERR "%s: error %d transferring data,"
- " sector %u, nr %u, card status %#x\n",
- req->rq_disk->disk_name, brq.data.error,
- (unsigned)blk_rq_pos(req),
- (unsigned)blk_rq_sectors(req), status);
- }
-
- if (brq.stop.error) {
- printk(KERN_ERR "%s: error %d sending stop command, "
- "response %#x, card status %#x\n",
- req->rq_disk->disk_name, brq.stop.error,
- brq.stop.resp[0], status);
- }
-
+ /*
+ * Everything else is either success, or a data error of some
+ * kind. If it was a write, we may have transitioned to
+ * program mode, which we have to wait for it to complete.
+ */
if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
+ u32 status;
do {
- int err;
-
- cmd.opcode = MMC_SEND_STATUS;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- err = mmc_wait_for_cmd(card->host, &cmd, 5);
+ int err = get_card_status(card, &status, 5);
if (err) {
printk(KERN_ERR "%s: error %d requesting status\n",
req->rq_disk->disk_name, err);
@@ -868,20 +1005,26 @@
* so make sure to check both the busy
* indication and the card state.
*/
- } while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
- (R1_CURRENT_STATE(cmd.resp[0]) == 7));
-
-#if 0
- if (cmd.resp[0] & ~0x00000900)
- printk(KERN_ERR "%s: status = %08x\n",
- req->rq_disk->disk_name, cmd.resp[0]);
- if (mmc_decode_status(cmd.resp))
- goto cmd_err;
-#endif
+ } while (!(status & R1_READY_FOR_DATA) ||
+ (R1_CURRENT_STATE(status) == R1_STATE_PRG));
}
- if (brq.cmd.error || brq.stop.error || brq.data.error) {
+ if (brq.data.error) {
+ pr_err("%s: error %d transferring data, sector %u, nr %u, cmd response %#x, card status %#x\n",
+ req->rq_disk->disk_name, brq.data.error,
+ (unsigned)blk_rq_pos(req),
+ (unsigned)blk_rq_sectors(req),
+ brq.cmd.resp[0], brq.stop.resp[0]);
+
if (rq_data_dir(req) == READ) {
+ if (brq.data.blocks > 1) {
+ /* Redo read one sector at a time */
+ pr_warning("%s: retrying using single block read\n",
+ req->rq_disk->disk_name);
+ disable_multi = 1;
+ continue;
+ }
+
/*
* After an error, we redo I/O one sector at a
* time, so we only reach here after trying to
@@ -891,8 +1034,9 @@
ret = __blk_end_request(req, -EIO, brq.data.blksz);
spin_unlock_irq(&md->lock);
continue;
+ } else {
+ goto cmd_err;
}
- goto cmd_err;
}
/*
@@ -929,6 +1073,7 @@
spin_unlock_irq(&md->lock);
}
+ cmd_abort:
spin_lock_irq(&md->lock);
while (ret)
ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 93e1ec6..1116ca8 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -41,7 +41,6 @@
#include "sdio_ops.h"
static struct workqueue_struct *workqueue;
-static struct wake_lock mmc_delayed_work_wake_lock;
/*
* Enabling software CRCs on the data blocks can be a significant (30%)
@@ -74,7 +73,6 @@
static int mmc_schedule_delayed_work(struct delayed_work *work,
unsigned long delay)
{
- wake_lock(&mmc_delayed_work_wake_lock);
return queue_delayed_work(workqueue, work, delay);
}
@@ -588,12 +586,9 @@
/* If the host is claimed then we do not want to disable it anymore */
if (!mmc_try_claim_host(host))
- goto out;
+ return;
mmc_host_do_disable(host, 1);
mmc_do_release_host(host);
-
-out:
- wake_unlock(&mmc_delayed_work_wake_lock);
}
/**
@@ -1254,6 +1249,7 @@
spin_unlock_irqrestore(&host->lock, flags);
#endif
+ wake_lock(&host->detect_wake_lock);
mmc_schedule_delayed_work(&host->detect, delay);
}
@@ -1716,11 +1712,13 @@
out:
if (extend_wakelock)
- wake_lock_timeout(&mmc_delayed_work_wake_lock, HZ / 2);
+ wake_lock_timeout(&host->detect_wake_lock, HZ / 2);
else
- wake_unlock(&mmc_delayed_work_wake_lock);
- if (host->caps & MMC_CAP_NEEDS_POLL)
+ wake_unlock(&host->detect_wake_lock);
+ if (host->caps & MMC_CAP_NEEDS_POLL) {
+ wake_lock(&host->detect_wake_lock);
mmc_schedule_delayed_work(&host->detect, HZ);
+ }
}
void mmc_start_host(struct mmc_host *host)
@@ -1740,7 +1738,8 @@
if (host->caps & MMC_CAP_DISABLE)
cancel_delayed_work(&host->disable);
- cancel_delayed_work_sync(&host->detect);
+ if (cancel_delayed_work_sync(&host->detect))
+ wake_unlock(&host->detect_wake_lock);
mmc_flush_scheduled_work();
/* clear pm flags now and let card drivers set them as needed */
@@ -1861,7 +1860,8 @@
if (host->caps & MMC_CAP_DISABLE)
cancel_delayed_work(&host->disable);
- cancel_delayed_work(&host->detect);
+ if (cancel_delayed_work(&host->detect))
+ wake_unlock(&host->detect_wake_lock);
mmc_flush_scheduled_work();
mmc_bus_get(host);
@@ -1963,7 +1963,8 @@
}
host->rescan_disable = 1;
spin_unlock_irqrestore(&host->lock, flags);
- cancel_delayed_work_sync(&host->detect);
+ if (cancel_delayed_work_sync(&host->detect))
+ wake_unlock(&host->detect_wake_lock);
if (!host->bus_ops || host->bus_ops->suspend)
break;
@@ -2021,9 +2022,6 @@
if (!workqueue)
return -ENOMEM;
- wake_lock_init(&mmc_delayed_work_wake_lock, WAKE_LOCK_SUSPEND,
- "mmc_delayed_work");
-
ret = mmc_register_bus();
if (ret)
goto destroy_workqueue;
@@ -2044,7 +2042,6 @@
mmc_unregister_bus();
destroy_workqueue:
destroy_workqueue(workqueue);
- wake_lock_destroy(&mmc_delayed_work_wake_lock);
return ret;
}
@@ -2055,7 +2052,6 @@
mmc_unregister_host_class();
mmc_unregister_bus();
destroy_workqueue(workqueue);
- wake_lock_destroy(&mmc_delayed_work_wake_lock);
}
subsys_initcall(mmc_init);
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index d9411ed..a4edb24 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -49,6 +49,8 @@
if (ms < 1000 / HZ) {
cond_resched();
mdelay(ms);
+ } else if (ms < jiffies_to_msecs(2)) {
+ usleep_range(ms * 1000, (ms + 1) * 1000);
} else {
msleep(ms);
}
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 5441006..1985745 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -331,6 +331,8 @@
spin_lock_init(&host->lock);
init_waitqueue_head(&host->wq);
+ wake_lock_init(&host->detect_wake_lock, WAKE_LOCK_SUSPEND,
+ kasprintf(GFP_KERNEL, "%s_detect", mmc_hostname(host)));
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable);
#ifdef CONFIG_PM
@@ -502,6 +504,7 @@
spin_lock(&mmc_host_lock);
idr_remove(&mmc_host_idr, host->index);
spin_unlock(&mmc_host_lock);
+ wake_lock_destroy(&host->detect_wake_lock);
put_device(&host->class_dev);
}
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 71d0fa6..918fc9e 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -831,7 +831,7 @@
*
* WARNING: eMMC rules are NOT the same as SD DDR
*/
- if (ddr == EXT_CSD_CARD_TYPE_DDR_1_2V) {
+ if (ddr == MMC_1_2V_DDR_MODE) {
err = mmc_set_signal_voltage(host,
MMC_SIGNAL_VOLTAGE_120, 0);
if (err)
diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c
old mode 100755
new mode 100644
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 1ce089d..b46bee6 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -19,6 +19,7 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/ioport.h>
+#include <linux/of.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
@@ -42,7 +43,6 @@
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
-#include <linux/mmc/mmc.h>
#include <asm/cacheflush.h>
#include <asm/div64.h>
@@ -68,8 +68,6 @@
#define SPS_SDCC_CONSUMER_PIPE_INDEX 2
#define SPS_CONS_PERIPHERAL 0
#define SPS_PROD_PERIPHERAL 1
-/* 16 KB */
-#define SPS_MAX_DESC_SIZE (16 * 1024)
#if defined(CONFIG_DEBUG_FS)
static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
@@ -78,6 +76,7 @@
static int msmsdcc_dbg_init(void);
#endif
+static u64 dma_mask = DMA_BIT_MASK(32);
static unsigned int msmsdcc_pwrsave = 1;
static struct mmc_command dummy52cmd;
@@ -134,6 +133,42 @@
u32 c);
static inline void msmsdcc_delay(struct msmsdcc_host *host);
+static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
+{
+ unsigned short ret = NR_SG;
+
+ if (host->is_sps_mode) {
+ if (NR_SG > MAX_NR_SG_SPS)
+ ret = MAX_NR_SG_SPS;
+ } else { /* DMA or PIO mode */
+ if (NR_SG > MAX_NR_SG_DMA_PIO)
+ ret = MAX_NR_SG_DMA_PIO;
+ }
+
+ return ret;
+}
+
+static inline unsigned int msmsdcc_get_max_seg_size(struct msmsdcc_host *host)
+{
+ unsigned int max_seg_size;
+
+ /*
+ * SPS BAM has limitation of max. number of descriptors.
+ * max. # of descriptors = SPS_MAX_DESCS
+ * each descriptor can point to SPS_MAX_DESC_SIZE (16KB)
+ * So (nr_sg * max_seg_size) should be limited to the
+ * max. size that all of the descriptors can point to.
+ * i.e., (nr_sg * max_seg_size) = (SPS_MAX_DESCS * SPS_MAX_DESC_SIZE).
+ */
+ if (host->is_sps_mode) {
+ max_seg_size = (SPS_MAX_DESCS * SPS_MAX_DESC_SIZE) /
+ msmsdcc_get_nr_sg(host);
+ } else { /* DMA or PIO mode */
+ max_seg_size = MMC_MAX_REQ_SIZE;
+ }
+
+ return max_seg_size;
+}
#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
@@ -717,8 +752,9 @@
dmov_box *box;
uint32_t rows;
unsigned int n;
- int i;
+ int i, err = 0, box_cmd_cnt = 0;
struct scatterlist *sg = data->sg;
+ unsigned int len, offset;
if ((host->dma.channel == -1) || (host->dma.crci == -1))
return -ENOENT;
@@ -728,7 +764,8 @@
host->dma.sg = data->sg;
host->dma.num_ents = data->sg_len;
- BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */
+ /* Prevent memory corruption */
+ BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
nc = host->dma.nc;
@@ -737,59 +774,8 @@
else
host->dma.dir = DMA_TO_DEVICE;
- /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
- host->curr.user_pages = 0;
- box = &nc->cmd[0];
- for (i = 0; i < host->dma.num_ents; i++) {
- box->cmd = CMD_MODE_BOX;
-
- /* Initialize sg dma address */
- sg->dma_address = pfn_to_dma(mmc_dev(host->mmc),
- page_to_pfn(sg_page(sg)))
- + sg->offset;
-
- if (i == (host->dma.num_ents - 1))
- box->cmd |= CMD_LC;
- rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ?
- (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 :
- (sg_dma_len(sg) / MCI_FIFOSIZE) ;
-
- if (data->flags & MMC_DATA_READ) {
- box->src_row_addr = msmsdcc_fifo_addr(host);
- box->dst_row_addr = sg_dma_address(sg);
-
- box->src_dst_len = (MCI_FIFOSIZE << 16) |
- (MCI_FIFOSIZE);
- box->row_offset = MCI_FIFOSIZE;
-
- box->num_rows = rows * ((1 << 16) + 1);
- box->cmd |= CMD_SRC_CRCI(host->dma.crci);
- } else {
- box->src_row_addr = sg_dma_address(sg);
- box->dst_row_addr = msmsdcc_fifo_addr(host);
-
- box->src_dst_len = (MCI_FIFOSIZE << 16) |
- (MCI_FIFOSIZE);
- box->row_offset = (MCI_FIFOSIZE << 16);
-
- box->num_rows = rows * ((1 << 16) + 1);
- box->cmd |= CMD_DST_CRCI(host->dma.crci);
- }
- box++;
- sg++;
- }
-
- /* location of command block must be 64 bit aligned */
- BUG_ON(host->dma.cmd_busaddr & 0x07);
-
- nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
- host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
- DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
- host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
-
n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
host->dma.num_ents, host->dma.dir);
- /* dsb inside dma_map_sg will write nc out to mem as well */
if (n != host->dma.num_ents) {
pr_err("%s: Unable to map in all sg elements\n",
@@ -799,7 +785,79 @@
return -ENOMEM;
}
- return 0;
+ /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
+ host->curr.user_pages = 0;
+ box = &nc->cmd[0];
+ for (i = 0; i < host->dma.num_ents; i++) {
+ len = sg_dma_len(sg);
+ offset = 0;
+
+ do {
+ /* Check if we can do DMA */
+ if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
+ err = -ENOTSUPP;
+ goto unmap;
+ }
+
+ box->cmd = CMD_MODE_BOX;
+
+ if (len >= MMC_MAX_DMA_BOX_LENGTH) {
+ len = MMC_MAX_DMA_BOX_LENGTH;
+ len -= len % data->blksz;
+ }
+ rows = (len % MCI_FIFOSIZE) ?
+ (len / MCI_FIFOSIZE) + 1 :
+ (len / MCI_FIFOSIZE);
+
+ if (data->flags & MMC_DATA_READ) {
+ box->src_row_addr = msmsdcc_fifo_addr(host);
+ box->dst_row_addr = sg_dma_address(sg) + offset;
+ box->src_dst_len = (MCI_FIFOSIZE << 16) |
+ (MCI_FIFOSIZE);
+ box->row_offset = MCI_FIFOSIZE;
+ box->num_rows = rows * ((1 << 16) + 1);
+ box->cmd |= CMD_SRC_CRCI(host->dma.crci);
+ } else {
+ box->src_row_addr = sg_dma_address(sg) + offset;
+ box->dst_row_addr = msmsdcc_fifo_addr(host);
+ box->src_dst_len = (MCI_FIFOSIZE << 16) |
+ (MCI_FIFOSIZE);
+ box->row_offset = (MCI_FIFOSIZE << 16);
+ box->num_rows = rows * ((1 << 16) + 1);
+ box->cmd |= CMD_DST_CRCI(host->dma.crci);
+ }
+
+ offset += len;
+ len = sg_dma_len(sg) - offset;
+ box++;
+ box_cmd_cnt++;
+ } while (len);
+ sg++;
+ }
+ /* Mark last command */
+ box--;
+ box->cmd |= CMD_LC;
+
+ /* location of command block must be 64 bit aligned */
+ BUG_ON(host->dma.cmd_busaddr & 0x07);
+
+ nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
+ host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
+ DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
+ host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
+
+ /* Flush all data to memory before starting dma */
+ mb();
+
+unmap:
+ if (err) {
+ dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
+ host->dma.num_ents, host->dma.dir);
+ pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
+ mmc_hostname(host->mmc), err);
+ }
+
+ return err;
}
#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
@@ -825,7 +883,8 @@
struct scatterlist *sg = data->sg;
struct sps_pipe *sps_pipe_handle;
- BUG_ON(data->sg_len > NR_SG); /* Prevent memory corruption */
+ /* Prevent memory corruption */
+ BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
host->sps.sg = data->sg;
host->sps.num_ents = data->sg_len;
@@ -920,9 +979,11 @@
if (/*interrupt*/0)
*c |= MCI_CPSM_INTERRUPT;
- if ((((cmd->opcode == 17) || (cmd->opcode == 18)) ||
- ((cmd->opcode == 24) || (cmd->opcode == 25))) ||
- (cmd->opcode == 53))
+ if (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
+ cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
+ cmd->opcode == MMC_WRITE_BLOCK ||
+ cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK ||
+ cmd->opcode == SD_IO_RW_EXTENDED)
*c |= MCI_CSPM_DATCMD;
/* Check if AUTO CMD19 is required or not? */
@@ -933,10 +994,12 @@
* For close ended block read operation (with CMD23),
* AUTO_CMD19 bit should be set while sending CMD23.
*/
- if ((cmd->opcode == 23 && (host->curr.mrq->cmd->opcode == 17 ||
- host->curr.mrq->cmd->opcode == 18)) ||
+ if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
+ host->curr.mrq->cmd->opcode ==
+ MMC_READ_MULTIPLE_BLOCK) ||
(!host->curr.mrq->sbc &&
- (cmd->opcode == 17 || cmd->opcode == 18))) {
+ (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
+ cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
msmsdcc_enable_cdr_cm_sdc4_dll(host);
*c |= MCI_CSPM_AUTO_CMD19;
}
@@ -966,6 +1029,9 @@
void __iomem *base = host->base;
unsigned int pio_irqmask = 0;
+ BUG_ON(!data->sg);
+ BUG_ON(!data->sg_len);
+
host->curr.data = data;
host->curr.xfer_size = data->blksz * data->blocks;
host->curr.xfer_remain = host->curr.xfer_size;
@@ -1464,7 +1530,7 @@
msmsdcc_do_cmdirq(host, status);
}
- if (data) {
+ if (host->curr.data) {
/* Check for data errors */
if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
@@ -1642,6 +1708,9 @@
* without the need of sending dummy CMD52.
*/
host->curr.wait_for_auto_prog_done = 1;
+ } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
+ host->sdcc_version) {
+ host->curr.wait_for_auto_prog_done = 1;
}
}
@@ -3018,17 +3087,10 @@
* transfer. It's ignored for BAM-to-System mode transfer.
*/
sps_config->event_thresh = 0x10;
- /*
- * Max. no of scatter/gather buffers that can
- * be passed by block layer = 32 (NR_SG).
- * Each BAM descritor needs 64 bits (8 bytes).
- * One BAM descriptor is required per buffer transfer.
- * So we would require total 256 (32 * 8) bytes of descriptor FIFO.
- * But due to HW limitation we need to allocate atleast one extra
- * descriptor memory (256 bytes + 8 bytes). But in order to be
- * in power of 2, we are allocating 512 bytes of memory.
- */
- sps_config->desc.size = 512;
+
+ /* Allocate maximum descriptor fifo size */
+ sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
+ (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
sps_config->desc.size,
&sps_config->desc.phys_base,
@@ -3505,10 +3567,112 @@
spin_unlock_irqrestore(&host->lock, flags);
}
+static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
+{
+ int i, ret;
+ struct mmc_platform_data *pdata;
+ struct device_node *np = dev->of_node;
+ u32 bus_width = 0;
+ u32 *clk_table;
+ int clk_table_len;
+ u32 *sup_voltages;
+ int sup_volt_len;
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(dev, "could not allocate memory for platform data\n");
+ goto err;
+ }
+
+ of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
+ if (bus_width == 8) {
+ pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
+ } else if (bus_width == 4) {
+ pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
+ } else {
+ dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
+ pdata->mmc_bus_width = 0;
+ }
+
+ if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
+ size_t sz;
+ sz = sup_volt_len / sizeof(*sup_voltages);
+ if (sz > 0) {
+ sup_voltages = devm_kzalloc(dev,
+ sz * sizeof(*sup_voltages), GFP_KERNEL);
+ if (!sup_voltages) {
+ dev_err(dev, "No memory for supported voltage\n");
+ goto err;
+ }
+
+ ret = of_property_read_u32_array(np,
+ "qcom,sdcc-sup-voltages", sup_voltages, sz);
+ if (ret < 0) {
+ dev_err(dev, "error while reading voltage"
+ "ranges %d\n", ret);
+ goto err;
+ }
+ } else {
+ dev_err(dev, "No supported voltages\n");
+ goto err;
+ }
+ for (i = 0; i < sz; i += 2) {
+ u32 mask;
+
+ mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
+ sup_voltages[i + 1]);
+ if (!mask)
+ dev_err(dev, "Invalide voltage range %d\n", i);
+ pdata->ocr_mask |= mask;
+ }
+ dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
+ } else {
+ dev_err(dev, "Supported voltage range not specified\n");
+ }
+
+ if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
+ size_t sz;
+ sz = clk_table_len / sizeof(*clk_table);
+
+ if (sz > 0) {
+ clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
+ GFP_KERNEL);
+ if (!clk_table) {
+ dev_err(dev, "No memory for clock table\n");
+ goto err;
+ }
+
+ ret = of_property_read_u32_array(np,
+ "qcom,sdcc-clk-rates", clk_table, sz);
+ if (ret < 0) {
+ dev_err(dev, "error while reading clk"
+ "table %d\n", ret);
+ goto err;
+ }
+ } else {
+ dev_err(dev, "clk_table not specified\n");
+ goto err;
+ }
+ pdata->sup_clk_table = clk_table;
+ pdata->sup_clk_cnt = sz;
+ } else {
+ dev_err(dev, "Supported clock rates not specified\n");
+ }
+
+ if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
+ pdata->nonremovable = true;
+ if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
+ pdata->disable_cmd23 = true;
+
+ return pdata;
+err:
+ return NULL;
+}
+
static int
msmsdcc_probe(struct platform_device *pdev)
{
- struct mmc_platform_data *plat = pdev->dev.platform_data;
+ struct mmc_platform_data *plat;
struct msmsdcc_host *host;
struct mmc_host *mmc;
unsigned long flags;
@@ -3522,6 +3686,14 @@
int ret = 0;
int i;
+ if (pdev->dev.of_node) {
+ plat = msmsdcc_populate_pdata(&pdev->dev);
+ of_property_read_u32((&pdev->dev)->of_node,
+ "cell-index", &pdev->id);
+ } else {
+ plat = pdev->dev.platform_data;
+ }
+
/* must have platform data */
if (!plat) {
pr_err("%s: Platform data not available\n", __func__);
@@ -3541,35 +3713,54 @@
pr_err("%s: Invalid resource\n", __func__);
return -ENXIO;
}
+ if (pdev->dev.of_node) {
+ /*
+ * Device tree iomem resources are only accessible by index.
+ * index = 0 -> SDCC register interface
+ * index = 1 -> DML register interface
+ * index = 2 -> BAM register interface
+ * IRQ resources:
+ * index = 0 -> SDCC IRQ
+ * index = 1 -> BAM IRQ
+ */
+ core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+ } else {
+ for (i = 0; i < pdev->num_resources; i++) {
+ if (pdev->resource[i].flags & IORESOURCE_MEM) {
+ if (!strncmp(pdev->resource[i].name,
+ "sdcc_dml_addr",
+ sizeof("sdcc_dml_addr")))
+ dml_memres = &pdev->resource[i];
+ else if (!strncmp(pdev->resource[i].name,
+ "sdcc_bam_addr",
+ sizeof("sdcc_bam_addr")))
+ bam_memres = &pdev->resource[i];
+ else
+ core_memres = &pdev->resource[i];
- for (i = 0; i < pdev->num_resources; i++) {
- if (pdev->resource[i].flags & IORESOURCE_MEM) {
- if (!strcmp(pdev->resource[i].name,
- "sdcc_dml_addr"))
- dml_memres = &pdev->resource[i];
- else if (!strcmp(pdev->resource[i].name,
- "sdcc_bam_addr"))
- bam_memres = &pdev->resource[i];
- else
- core_memres = &pdev->resource[i];
-
- }
- if (pdev->resource[i].flags & IORESOURCE_IRQ) {
- if (!strcmp(pdev->resource[i].name,
- "sdcc_bam_irq"))
- bam_irqres = &pdev->resource[i];
- else
- core_irqres = &pdev->resource[i];
- }
- if (pdev->resource[i].flags & IORESOURCE_DMA) {
- if (!strncmp(pdev->resource[i].name,
- "sdcc_dma_chnl",
- sizeof("sdcc_dma_chnl")))
- dmares = &pdev->resource[i];
- else if (!strncmp(pdev->resource[i].name,
- "sdcc_dma_crci",
- sizeof("sdcc_dma_crci")))
- dma_crci_res = &pdev->resource[i];
+ }
+ if (pdev->resource[i].flags & IORESOURCE_IRQ) {
+ if (!strncmp(pdev->resource[i].name,
+ "sdcc_bam_irq",
+ sizeof("sdcc_bam_irq")))
+ bam_irqres = &pdev->resource[i];
+ else
+ core_irqres = &pdev->resource[i];
+ }
+ if (pdev->resource[i].flags & IORESOURCE_DMA) {
+ if (!strncmp(pdev->resource[i].name,
+ "sdcc_dma_chnl",
+ sizeof("sdcc_dma_chnl")))
+ dmares = &pdev->resource[i];
+ else if (!strncmp(pdev->resource[i].name,
+ "sdcc_dma_crci",
+ sizeof("sdcc_dma_crci")))
+ dma_crci_res = &pdev->resource[i];
+ }
}
}
@@ -3739,6 +3930,7 @@
if (ret)
goto sps_exit;
}
+ mmc_dev(mmc)->dma_mask = &dma_mask;
/*
* Setup MMC host structure
@@ -3782,12 +3974,12 @@
if (plat->is_sdio_al_client)
mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
- mmc->max_segs = NR_SG;
- mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
- mmc->max_blk_count = 65535;
+ mmc->max_segs = msmsdcc_get_nr_sg(host);
+ mmc->max_blk_size = MMC_MAX_BLK_SIZE;
+ mmc->max_blk_count = MMC_MAX_BLK_CNT;
- mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
- mmc->max_seg_size = mmc->max_req_size;
+ mmc->max_req_size = MMC_MAX_REQ_SIZE;
+ mmc->max_seg_size = msmsdcc_get_max_seg_size(host);
writel_relaxed(0, host->base + MMCIMASK0);
writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
@@ -4153,7 +4345,6 @@
enable_irq(host->core_irqres->start);
host->sdcc_irq_disabled = 0;
}
- wake_lock_timeout(&host->sdio_wlock, 1);
}
spin_unlock_irqrestore(&host->lock, flags);
return 0;
@@ -4378,12 +4569,19 @@
.resume = msmsdcc_pm_resume,
};
+static const struct of_device_id msmsdcc_dt_match[] = {
+ {.compatible = "qcom,msm-sdcc"},
+
+};
+MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
+
static struct platform_driver msmsdcc_driver = {
.probe = msmsdcc_probe,
.remove = msmsdcc_remove,
.driver = {
.name = "msm_sdcc",
.pm = &msmsdcc_dev_pm_ops,
+ .of_match_table = msmsdcc_dt_match,
},
};
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 2019913..ca3eed8 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -207,7 +207,7 @@
#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2)
-#define NR_SG 32
+#define NR_SG 128
#define MSM_MMC_IDLE_TIMEOUT 5000 /* msecs */
@@ -217,10 +217,46 @@
*/
#define MSM_MMC_REQ_TIMEOUT 10000 /* msecs */
+/*
+ * Controller HW limitations
+ */
+#define MCI_DATALENGTH_BITS 25
+#define MMC_MAX_REQ_SIZE ((1 << MCI_DATALENGTH_BITS) - 1)
+/* MCI_DATA_CTL BLOCKSIZE up to 4096 */
+#define MMC_MAX_BLK_SIZE 4096
+#define MMC_MIN_BLK_SIZE 512
+#define MMC_MAX_BLK_CNT (MMC_MAX_REQ_SIZE / MMC_MIN_BLK_SIZE)
+
+/* 64KiB */
+#define MAX_SG_SIZE (64 * 1024)
+#define MAX_NR_SG_DMA_PIO (MMC_MAX_REQ_SIZE / MAX_SG_SIZE)
+
+/*
+ * BAM limitations
+ */
+/* upto 16 bits (64K - 1) */
+#define SPS_MAX_DESC_FIFO_SIZE 65535
+/* 16KiB */
+#define SPS_MAX_DESC_SIZE (16 * 1024)
+/* Each descriptor is of length 8 bytes */
+#define SPS_MAX_DESC_LENGTH 8
+#define SPS_MAX_DESCS (SPS_MAX_DESC_FIFO_SIZE / SPS_MAX_DESC_LENGTH)
+#define SPS_MAX_SG_DESCS (MAX_SG_SIZE / SPS_MAX_DESC_SIZE)
+#define MAX_NR_SG_SPS (SPS_MAX_DESCS / SPS_MAX_SG_DESCS)
+
+/*
+ * DMA limitations
+ */
+/* upto 16 bits (64K - 1) */
+#define MMC_MAX_DMA_ROWS (64 * 1024 - 1)
+#define MMC_MAX_DMA_BOX_LENGTH (MMC_MAX_DMA_ROWS * MCI_FIFOSIZE)
+#define MMC_MAX_DMA_CMDS (MAX_NR_SG_DMA_PIO * (MMC_MAX_REQ_SIZE / \
+ MMC_MAX_DMA_BOX_LENGTH))
+
struct clk;
struct msmsdcc_nc_dmadata {
- dmov_box cmd[NR_SG];
+ dmov_box cmd[MMC_MAX_DMA_CMDS];
uint32_t cmdptr;
};
@@ -374,7 +410,12 @@
static inline int msmsdcc_lpm_disable(struct mmc_host *mmc)
{
- return msmsdcc_sdio_al_lpm(mmc, false);
+ struct msmsdcc_host *host = mmc_priv(mmc);
+ int ret;
+
+ ret = msmsdcc_sdio_al_lpm(mmc, false);
+ wake_unlock(&host->sdio_wlock);
+ return ret;
}
#endif
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index 99d39a6..d513d47 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -564,40 +564,38 @@
static void mxs_mmc_set_clk_rate(struct mxs_mmc_host *host, unsigned int rate)
{
- unsigned int ssp_rate, bit_rate;
- u32 div1, div2;
+ unsigned int ssp_clk, ssp_sck;
+ u32 clock_divide, clock_rate;
u32 val;
- ssp_rate = clk_get_rate(host->clk);
+ ssp_clk = clk_get_rate(host->clk);
- for (div1 = 2; div1 < 254; div1 += 2) {
- div2 = ssp_rate / rate / div1;
- if (div2 < 0x100)
+ for (clock_divide = 2; clock_divide <= 254; clock_divide += 2) {
+ clock_rate = DIV_ROUND_UP(ssp_clk, rate * clock_divide);
+ clock_rate = (clock_rate > 0) ? clock_rate - 1 : 0;
+ if (clock_rate <= 255)
break;
}
- if (div1 >= 254) {
+ if (clock_divide > 254) {
dev_err(mmc_dev(host->mmc),
"%s: cannot set clock to %d\n", __func__, rate);
return;
}
- if (div2 == 0)
- bit_rate = ssp_rate / div1;
- else
- bit_rate = ssp_rate / div1 / div2;
+ ssp_sck = ssp_clk / clock_divide / (1 + clock_rate);
val = readl(host->base + HW_SSP_TIMING);
val &= ~(BM_SSP_TIMING_CLOCK_DIVIDE | BM_SSP_TIMING_CLOCK_RATE);
- val |= BF_SSP(div1, TIMING_CLOCK_DIVIDE);
- val |= BF_SSP(div2 - 1, TIMING_CLOCK_RATE);
+ val |= BF_SSP(clock_divide, TIMING_CLOCK_DIVIDE);
+ val |= BF_SSP(clock_rate, TIMING_CLOCK_RATE);
writel(val, host->base + HW_SSP_TIMING);
- host->clk_rate = bit_rate;
+ host->clk_rate = ssp_sck;
dev_dbg(mmc_dev(host->mmc),
- "%s: div1 %d, div2 %d, ssp %d, bit %d, rate %d\n",
- __func__, div1, div2, ssp_rate, bit_rate, rate);
+ "%s: clock_divide %d, clock_rate %d, ssp_clk %d, rate_actual %d, rate_requested %d\n",
+ __func__, clock_divide, clock_rate, ssp_clk, ssp_sck, rate);
}
static void mxs_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index 69e3ee3..8cd999f 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -301,6 +301,8 @@
ctrl &= ~SDHCI_CTRL_8BITBUS;
break;
default:
+ ctrl &= ~SDHCI_CTRL_4BITBUS;
+ ctrl &= ~SDHCI_CTRL_8BITBUS;
break;
}
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index c35a7c7..aad27c8 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1863,9 +1863,6 @@
del_timer(&host->timer);
- if (host->version >= SDHCI_SPEC_300)
- del_timer(&host->tuning_timer);
-
mrq = host->mrq;
/*
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 43079b3..7b3cd59 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -286,6 +286,7 @@
obj-$(CONFIG_USB_USBNET) += usb/
obj-$(CONFIG_USB_ZD1201) += usb/
obj-$(CONFIG_USB_IPHETH) += usb/
+obj-$(CONFIG_USB_CDC_PHONET) += usb/
obj-$(CONFIG_WLAN) += wireless/
obj-$(CONFIG_NET_TULIP) += tulip/
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 57d3293..74580bb 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -416,6 +416,9 @@
struct bnx2 *bp = netdev_priv(dev);
struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+ if (!cp->max_iscsi_conn)
+ return NULL;
+
cp->drv_owner = THIS_MODULE;
cp->chip_id = bp->chip_id;
cp->pdev = bp->pdev;
@@ -8177,6 +8180,10 @@
bp->timer.data = (unsigned long) bp;
bp->timer.function = bnx2_timer;
+#ifdef BCM_CNIC
+ bp->cnic_eth_dev.max_iscsi_conn =
+ bnx2_reg_rd_ind(bp, BNX2_FW_MAX_ISCSI_CONN);
+#endif
pci_save_state(pdev);
return 0;
diff --git a/drivers/net/bnx2x/bnx2x_dcb.c b/drivers/net/bnx2x/bnx2x_dcb.c
index 410a49e..d11af7c 100644
--- a/drivers/net/bnx2x/bnx2x_dcb.c
+++ b/drivers/net/bnx2x/bnx2x_dcb.c
@@ -1858,6 +1858,7 @@
break;
case DCB_CAP_ATTR_DCBX:
*cap = BNX2X_DCBX_CAPS;
+ break;
default:
rval = -EINVAL;
break;
diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c
index 74be989..04976db 100644
--- a/drivers/net/bnx2x/bnx2x_main.c
+++ b/drivers/net/bnx2x/bnx2x_main.c
@@ -4138,7 +4138,7 @@
int igu_seg_id;
int port = BP_PORT(bp);
int func = BP_FUNC(bp);
- int reg_offset;
+ int reg_offset, reg_offset_en5;
u64 section;
int index;
struct hc_sp_status_block_data sp_sb_data;
@@ -4161,6 +4161,8 @@
reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
+ reg_offset_en5 = (port ? MISC_REG_AEU_ENABLE5_FUNC_1_OUT_0 :
+ MISC_REG_AEU_ENABLE5_FUNC_0_OUT_0);
for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) {
int sindex;
/* take care of sig[0]..sig[4] */
@@ -4175,7 +4177,7 @@
* and not 16 between the different groups
*/
bp->attn_group[index].sig[4] = REG_RD(bp,
- reg_offset + 0x10 + 0x4*index);
+ reg_offset_en5 + 0x4*index);
else
bp->attn_group[index].sig[4] = 0;
}
diff --git a/drivers/net/bnx2x/bnx2x_reg.h b/drivers/net/bnx2x/bnx2x_reg.h
index 86bba25..0380b3a 100644
--- a/drivers/net/bnx2x/bnx2x_reg.h
+++ b/drivers/net/bnx2x/bnx2x_reg.h
@@ -1325,6 +1325,18 @@
Latched ump_tx_parity; [31] MCP Latched scpad_parity; */
#define MISC_REG_AEU_ENABLE4_PXP_0 0xa108
#define MISC_REG_AEU_ENABLE4_PXP_1 0xa1a8
+/* [RW 32] fifth 32b for enabling the output for function 0 output0. Mapped
+ * as follows: [0] PGLUE config_space; [1] PGLUE misc_flr; [2] PGLUE B RBC
+ * attention [3] PGLUE B RBC parity; [4] ATC attention; [5] ATC parity; [6]
+ * mstat0 attention; [7] mstat0 parity; [8] mstat1 attention; [9] mstat1
+ * parity; [31-10] Reserved; */
+#define MISC_REG_AEU_ENABLE5_FUNC_0_OUT_0 0xa688
+/* [RW 32] Fifth 32b for enabling the output for function 1 output0. Mapped
+ * as follows: [0] PGLUE config_space; [1] PGLUE misc_flr; [2] PGLUE B RBC
+ * attention [3] PGLUE B RBC parity; [4] ATC attention; [5] ATC parity; [6]
+ * mstat0 attention; [7] mstat0 parity; [8] mstat1 attention; [9] mstat1
+ * parity; [31-10] Reserved; */
+#define MISC_REG_AEU_ENABLE5_FUNC_1_OUT_0 0xa6b0
/* [RW 1] set/clr general attention 0; this will set/clr bit 94 in the aeu
128 bit vector */
#define MISC_REG_AEU_GENERAL_ATTN_0 0xa000
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 63c22b0..9ea2f21 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1625,8 +1625,10 @@
if (slave_dev->type != ARPHRD_ETHER)
bond_setup_by_slave(bond_dev, slave_dev);
- else
+ else {
ether_setup(bond_dev);
+ bond_dev->priv_flags &= ~IFF_TX_SKB_SHARING;
+ }
netdev_bonding_change(bond_dev,
NETDEV_POST_TYPE_CHANGE);
@@ -4398,7 +4400,7 @@
bond_dev->tx_queue_len = 0;
bond_dev->flags |= IFF_MASTER|IFF_MULTICAST;
bond_dev->priv_flags |= IFF_BONDING;
- bond_dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
+ bond_dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);
/* At first, we block adding VLANs. That's the only way to
* prevent problems that occur when adding VLANs over an
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 88fcb25..0624610 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -992,6 +992,7 @@
int i;
struct slave *slave;
struct bonding *bond = to_bond(d);
+ char ifname[IFNAMSIZ];
if (!rtnl_trylock())
return restart_syscall();
@@ -1002,32 +1003,33 @@
if (!USES_PRIMARY(bond->params.mode)) {
pr_info("%s: Unable to set primary slave; %s is in mode %d\n",
bond->dev->name, bond->dev->name, bond->params.mode);
- } else {
- bond_for_each_slave(bond, slave, i) {
- if (strnicmp
- (slave->dev->name, buf,
- strlen(slave->dev->name)) == 0) {
- pr_info("%s: Setting %s as primary slave.\n",
- bond->dev->name, slave->dev->name);
- bond->primary_slave = slave;
- strcpy(bond->params.primary, slave->dev->name);
- bond_select_active_slave(bond);
- goto out;
- }
- }
+ goto out;
+ }
- /* if we got here, then we didn't match the name of any slave */
+ sscanf(buf, "%16s", ifname); /* IFNAMSIZ */
- if (strlen(buf) == 0 || buf[0] == '\n') {
- pr_info("%s: Setting primary slave to None.\n",
- bond->dev->name);
- bond->primary_slave = NULL;
- bond_select_active_slave(bond);
- } else {
- pr_info("%s: Unable to set %.*s as primary slave as it is not a slave.\n",
- bond->dev->name, (int)strlen(buf) - 1, buf);
+ /* check to see if we are clearing primary */
+ if (!strlen(ifname) || buf[0] == '\n') {
+ pr_info("%s: Setting primary slave to None.\n",
+ bond->dev->name);
+ bond->primary_slave = NULL;
+ bond_select_active_slave(bond);
+ goto out;
+ }
+
+ bond_for_each_slave(bond, slave, i) {
+ if (strncmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
+ pr_info("%s: Setting %s as primary slave.\n",
+ bond->dev->name, slave->dev->name);
+ bond->primary_slave = slave;
+ strcpy(bond->params.primary, slave->dev->name);
+ bond_select_active_slave(bond);
+ goto out;
}
}
+
+ pr_info("%s: Unable to set %.*s as primary slave.\n",
+ bond->dev->name, (int)strlen(buf) - 1, buf);
out:
write_unlock_bh(&bond->curr_slave_lock);
read_unlock(&bond->lock);
@@ -1162,6 +1164,7 @@
struct slave *old_active = NULL;
struct slave *new_active = NULL;
struct bonding *bond = to_bond(d);
+ char ifname[IFNAMSIZ];
if (!rtnl_trylock())
return restart_syscall();
@@ -1170,56 +1173,62 @@
read_lock(&bond->lock);
write_lock_bh(&bond->curr_slave_lock);
- if (!USES_PRIMARY(bond->params.mode))
+ if (!USES_PRIMARY(bond->params.mode)) {
pr_info("%s: Unable to change active slave; %s is in mode %d\n",
bond->dev->name, bond->dev->name, bond->params.mode);
- else {
- bond_for_each_slave(bond, slave, i) {
- if (strnicmp
- (slave->dev->name, buf,
- strlen(slave->dev->name)) == 0) {
- old_active = bond->curr_active_slave;
- new_active = slave;
- if (new_active == old_active) {
- /* do nothing */
- pr_info("%s: %s is already the current active slave.\n",
+ goto out;
+ }
+
+ sscanf(buf, "%16s", ifname); /* IFNAMSIZ */
+
+ /* check to see if we are clearing active */
+ if (!strlen(ifname) || buf[0] == '\n') {
+ pr_info("%s: Clearing current active slave.\n",
+ bond->dev->name);
+ bond->curr_active_slave = NULL;
+ bond_select_active_slave(bond);
+ goto out;
+ }
+
+ bond_for_each_slave(bond, slave, i) {
+ if (strncmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
+ old_active = bond->curr_active_slave;
+ new_active = slave;
+ if (new_active == old_active) {
+ /* do nothing */
+ pr_info("%s: %s is already the current"
+ " active slave.\n",
+ bond->dev->name,
+ slave->dev->name);
+ goto out;
+ }
+ else {
+ if ((new_active) &&
+ (old_active) &&
+ (new_active->link == BOND_LINK_UP) &&
+ IS_UP(new_active->dev)) {
+ pr_info("%s: Setting %s as active"
+ " slave.\n",
bond->dev->name,
slave->dev->name);
- goto out;
+ bond_change_active_slave(bond,
+ new_active);
}
else {
- if ((new_active) &&
- (old_active) &&
- (new_active->link == BOND_LINK_UP) &&
- IS_UP(new_active->dev)) {
- pr_info("%s: Setting %s as active slave.\n",
- bond->dev->name,
- slave->dev->name);
- bond_change_active_slave(bond, new_active);
- }
- else {
- pr_info("%s: Could not set %s as active slave; either %s is down or the link is down.\n",
- bond->dev->name,
- slave->dev->name,
- slave->dev->name);
- }
- goto out;
+ pr_info("%s: Could not set %s as"
+ " active slave; either %s is"
+ " down or the link is down.\n",
+ bond->dev->name,
+ slave->dev->name,
+ slave->dev->name);
}
+ goto out;
}
}
-
- /* if we got here, then we didn't match the name of any slave */
-
- if (strlen(buf) == 0 || buf[0] == '\n') {
- pr_info("%s: Setting active slave to None.\n",
- bond->dev->name);
- bond->primary_slave = NULL;
- bond_select_active_slave(bond);
- } else {
- pr_info("%s: Unable to set %.*s as active slave as it is not a slave.\n",
- bond->dev->name, (int)strlen(buf) - 1, buf);
- }
}
+
+ pr_info("%s: Unable to set %.*s as active slave.\n",
+ bond->dev->name, (int)strlen(buf) - 1, buf);
out:
write_unlock_bh(&bond->curr_slave_lock);
read_unlock(&bond->lock);
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
index 11a92af..363c7f3 100644
--- a/drivers/net/cnic.c
+++ b/drivers/net/cnic.c
@@ -605,11 +605,12 @@
}
EXPORT_SYMBOL(cnic_unregister_driver);
-static int cnic_init_id_tbl(struct cnic_id_tbl *id_tbl, u32 size, u32 start_id)
+static int cnic_init_id_tbl(struct cnic_id_tbl *id_tbl, u32 size, u32 start_id,
+ u32 next)
{
id_tbl->start = start_id;
id_tbl->max = size;
- id_tbl->next = 0;
+ id_tbl->next = next;
spin_lock_init(&id_tbl->lock);
id_tbl->table = kzalloc(DIV_ROUND_UP(size, 32) * 4, GFP_KERNEL);
if (!id_tbl->table)
@@ -2778,13 +2779,10 @@
/* Tell compiler that status_blk fields can change. */
barrier();
- if (status_idx != *cp->kcq1.status_idx_ptr) {
- status_idx = (u16) *cp->kcq1.status_idx_ptr;
- /* status block index must be read first */
- rmb();
- cp->kwq_con_idx = *cp->kwq_con_idx_ptr;
- } else
- break;
+ status_idx = (u16) *cp->kcq1.status_idx_ptr;
+ /* status block index must be read first */
+ rmb();
+ cp->kwq_con_idx = *cp->kwq_con_idx_ptr;
}
CNIC_WR16(dev, cp->kcq1.io_addr, cp->kcq1.sw_prod_idx);
@@ -2908,8 +2906,6 @@
/* Tell compiler that sblk fields can change. */
barrier();
- if (last_status == *info->status_idx_ptr)
- break;
last_status = *info->status_idx_ptr;
/* status block index must be read before reading the KCQ */
@@ -3772,7 +3768,13 @@
break;
case L4_KCQE_OPCODE_VALUE_CLOSE_RECEIVED:
- cnic_cm_upcall(cp, csk, opcode);
+ /* after we already sent CLOSE_REQ */
+ if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags) &&
+ !test_bit(SK_F_OFFLD_COMPLETE, &csk->flags) &&
+ csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP)
+ cp->close_conn(csk, L4_KCQE_OPCODE_VALUE_RESET_COMP);
+ else
+ cnic_cm_upcall(cp, csk, opcode);
break;
}
csk_put(csk);
@@ -3803,14 +3805,17 @@
static int cnic_cm_alloc_mem(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
+ u32 port_id;
cp->csk_tbl = kzalloc(sizeof(struct cnic_sock) * MAX_CM_SK_TBL_SZ,
GFP_KERNEL);
if (!cp->csk_tbl)
return -ENOMEM;
+ get_random_bytes(&port_id, sizeof(port_id));
+ port_id %= CNIC_LOCAL_PORT_RANGE;
if (cnic_init_id_tbl(&cp->csk_port_tbl, CNIC_LOCAL_PORT_RANGE,
- CNIC_LOCAL_PORT_MIN)) {
+ CNIC_LOCAL_PORT_MIN, port_id)) {
cnic_cm_free_mem(dev);
return -ENOMEM;
}
@@ -3826,12 +3831,14 @@
}
/* 1. If event opcode matches the expected event in csk->state
- * 2. If the expected event is CLOSE_COMP, we accept any event
+ * 2. If the expected event is CLOSE_COMP or RESET_COMP, we accept any
+ * event
* 3. If the expected event is 0, meaning the connection was never
* never established, we accept the opcode from cm_abort.
*/
if (opcode == csk->state || csk->state == 0 ||
- csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP) {
+ csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP ||
+ csk->state == L4_KCQE_OPCODE_VALUE_RESET_COMP) {
if (!test_and_set_bit(SK_F_CLOSING, &csk->flags)) {
if (csk->state == 0)
csk->state = opcode;
@@ -4218,14 +4225,6 @@
BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | cp->last_status_idx);
}
-static void cnic_get_bnx2_iscsi_info(struct cnic_dev *dev)
-{
- u32 max_conn;
-
- max_conn = cnic_reg_rd_ind(dev, BNX2_FW_MAX_ISCSI_CONN);
- dev->max_iscsi_conn = max_conn;
-}
-
static void cnic_disable_bnx2_int_sync(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
@@ -4550,8 +4549,6 @@
return err;
}
- cnic_get_bnx2_iscsi_info(dev);
-
return 0;
}
@@ -4826,7 +4823,7 @@
pfid = cp->pfid;
ret = cnic_init_id_tbl(&cp->cid_tbl, MAX_ISCSI_TBL_SZ,
- cp->iscsi_start_cid);
+ cp->iscsi_start_cid, 0);
if (ret)
return -ENOMEM;
@@ -4834,7 +4831,7 @@
if (BNX2X_CHIP_IS_E2(cp->chip_id)) {
ret = cnic_init_id_tbl(&cp->fcoe_cid_tbl,
BNX2X_FCOE_NUM_CONNECTIONS,
- cp->fcoe_start_cid);
+ cp->fcoe_start_cid, 0);
if (ret)
return -ENOMEM;
@@ -5217,6 +5214,8 @@
cdev->pcidev = pdev;
cp->chip_id = ethdev->chip_id;
+ cdev->max_iscsi_conn = ethdev->max_iscsi_conn;
+
cp->cnic_ops = &cnic_bnx2_ops;
cp->start_hw = cnic_start_bnx2_hw;
cp->stop_hw = cnic_stop_bnx2_hw;
@@ -5335,7 +5334,7 @@
dev = cnic_from_netdev(netdev);
- if (!dev && (event == NETDEV_REGISTER || event == NETDEV_UP)) {
+ if (!dev && (event == NETDEV_REGISTER || netif_running(netdev))) {
/* Check for the hot-plug device */
dev = is_cnic_dev(netdev);
if (dev) {
@@ -5351,7 +5350,7 @@
else if (event == NETDEV_UNREGISTER)
cnic_ulp_exit(dev);
- if (event == NETDEV_UP) {
+ if (event == NETDEV_UP || (new_dev && netif_running(netdev))) {
if (cnic_register_netdev(dev) != 0) {
cnic_put(dev);
goto done;
diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c
index 862804f..3f2e12c 100644
--- a/drivers/net/cxgb3/cxgb3_offload.c
+++ b/drivers/net/cxgb3/cxgb3_offload.c
@@ -1149,12 +1149,14 @@
if (te && te->ctx && te->client && te->client->redirect) {
update_tcb = te->client->redirect(te->ctx, old, new, e);
if (update_tcb) {
+ rcu_read_lock();
l2t_hold(L2DATA(tdev), e);
+ rcu_read_unlock();
set_l2t_ix(tdev, tid, e);
}
}
}
- l2t_release(L2DATA(tdev), e);
+ l2t_release(tdev, e);
}
/*
@@ -1267,7 +1269,7 @@
goto out_free;
err = -ENOMEM;
- L2DATA(dev) = t3_init_l2t(l2t_capacity);
+ RCU_INIT_POINTER(dev->l2opt, t3_init_l2t(l2t_capacity));
if (!L2DATA(dev))
goto out_free;
@@ -1301,16 +1303,24 @@
out_free_l2t:
t3_free_l2t(L2DATA(dev));
- L2DATA(dev) = NULL;
+ rcu_assign_pointer(dev->l2opt, NULL);
out_free:
kfree(t);
return err;
}
+static void clean_l2_data(struct rcu_head *head)
+{
+ struct l2t_data *d = container_of(head, struct l2t_data, rcu_head);
+ t3_free_l2t(d);
+}
+
+
void cxgb3_offload_deactivate(struct adapter *adapter)
{
struct t3cdev *tdev = &adapter->tdev;
struct t3c_data *t = T3C_DATA(tdev);
+ struct l2t_data *d;
remove_adapter(adapter);
if (list_empty(&adapter_list))
@@ -1318,8 +1328,11 @@
free_tid_maps(&t->tid_maps);
T3C_DATA(tdev) = NULL;
- t3_free_l2t(L2DATA(tdev));
- L2DATA(tdev) = NULL;
+ rcu_read_lock();
+ d = L2DATA(tdev);
+ rcu_read_unlock();
+ rcu_assign_pointer(tdev->l2opt, NULL);
+ call_rcu(&d->rcu_head, clean_l2_data);
if (t->nofail_skb)
kfree_skb(t->nofail_skb);
kfree(t);
diff --git a/drivers/net/cxgb3/l2t.c b/drivers/net/cxgb3/l2t.c
index f452c40..4154097 100644
--- a/drivers/net/cxgb3/l2t.c
+++ b/drivers/net/cxgb3/l2t.c
@@ -300,14 +300,21 @@
struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh,
struct net_device *dev)
{
- struct l2t_entry *e;
- struct l2t_data *d = L2DATA(cdev);
+ struct l2t_entry *e = NULL;
+ struct l2t_data *d;
+ int hash;
u32 addr = *(u32 *) neigh->primary_key;
int ifidx = neigh->dev->ifindex;
- int hash = arp_hash(addr, ifidx, d);
struct port_info *p = netdev_priv(dev);
int smt_idx = p->port_id;
+ rcu_read_lock();
+ d = L2DATA(cdev);
+ if (!d)
+ goto done_rcu;
+
+ hash = arp_hash(addr, ifidx, d);
+
write_lock_bh(&d->lock);
for (e = d->l2tab[hash].first; e; e = e->next)
if (e->addr == addr && e->ifindex == ifidx &&
@@ -338,6 +345,8 @@
}
done:
write_unlock_bh(&d->lock);
+done_rcu:
+ rcu_read_unlock();
return e;
}
diff --git a/drivers/net/cxgb3/l2t.h b/drivers/net/cxgb3/l2t.h
index fd3eb07..c4dd066 100644
--- a/drivers/net/cxgb3/l2t.h
+++ b/drivers/net/cxgb3/l2t.h
@@ -76,6 +76,7 @@
atomic_t nfree; /* number of free entries */
rwlock_t lock;
struct l2t_entry l2tab[0];
+ struct rcu_head rcu_head; /* to handle rcu cleanup */
};
typedef void (*arp_failure_handler_func)(struct t3cdev * dev,
@@ -99,7 +100,7 @@
/*
* Getting to the L2 data from an offload device.
*/
-#define L2DATA(dev) ((dev)->l2opt)
+#define L2DATA(cdev) (rcu_dereference((cdev)->l2opt))
#define W_TCB_L2T_IX 0
#define S_TCB_L2T_IX 7
@@ -126,15 +127,22 @@
return t3_l2t_send_slow(dev, skb, e);
}
-static inline void l2t_release(struct l2t_data *d, struct l2t_entry *e)
+static inline void l2t_release(struct t3cdev *t, struct l2t_entry *e)
{
- if (atomic_dec_and_test(&e->refcnt))
+ struct l2t_data *d;
+
+ rcu_read_lock();
+ d = L2DATA(t);
+
+ if (atomic_dec_and_test(&e->refcnt) && d)
t3_l2e_free(d, e);
+
+ rcu_read_unlock();
}
static inline void l2t_hold(struct l2t_data *d, struct l2t_entry *e)
{
- if (atomic_add_return(1, &e->refcnt) == 1) /* 0 -> 1 transition */
+ if (d && atomic_add_return(1, &e->refcnt) == 1) /* 0 -> 1 transition */
atomic_dec(&d->nfree);
}
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 7501d97..f17aaa1 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -4028,6 +4028,12 @@
checksum += eeprom_data;
}
+#ifdef CONFIG_PARISC
+ /* This is a signature and not a checksum on HP c8000 */
+ if ((hw->subsystem_vendor_id == 0x103C) && (eeprom_data == 0x16d6))
+ return E1000_SUCCESS;
+
+#endif
if (checksum == (u16) EEPROM_SUM)
return E1000_SUCCESS;
else {
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
index 3369d1f..ee77b94 100644
--- a/drivers/net/e1000e/ich8lan.c
+++ b/drivers/net/e1000e/ich8lan.c
@@ -137,8 +137,9 @@
#define HV_PM_CTRL PHY_REG(770, 17)
/* PHY Low Power Idle Control */
-#define I82579_LPI_CTRL PHY_REG(772, 20)
-#define I82579_LPI_CTRL_ENABLE_MASK 0x6000
+#define I82579_LPI_CTRL PHY_REG(772, 20)
+#define I82579_LPI_CTRL_ENABLE_MASK 0x6000
+#define I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT 0x80
/* EMI Registers */
#define I82579_EMI_ADDR 0x10
@@ -1611,6 +1612,7 @@
s32 ret_val = 0;
u16 status_reg = 0;
u32 mac_reg;
+ u16 phy_reg;
if (hw->mac.type != e1000_pch2lan)
goto out;
@@ -1625,12 +1627,19 @@
mac_reg = er32(FEXTNVM4);
mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK;
- if (status_reg & HV_M_STATUS_SPEED_1000)
- mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_8USEC;
- else
- mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_16USEC;
+ ret_val = e1e_rphy(hw, I82579_LPI_CTRL, &phy_reg);
+ if (ret_val)
+ goto out;
+ if (status_reg & HV_M_STATUS_SPEED_1000) {
+ mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_8USEC;
+ phy_reg &= ~I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT;
+ } else {
+ mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_16USEC;
+ phy_reg |= I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT;
+ }
ew32(FEXTNVM4, mac_reg);
+ ret_val = e1e_wphy(hw, I82579_LPI_CTRL, phy_reg);
}
out:
diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c
index dd8ab05..8d28602 100644
--- a/drivers/net/e1000e/lib.c
+++ b/drivers/net/e1000e/lib.c
@@ -190,7 +190,8 @@
/* Check for LOM (vs. NIC) or one of two valid mezzanine cards */
if (!((nvm_data & NVM_COMPAT_LOM) ||
(hw->adapter->pdev->device == E1000_DEV_ID_82571EB_SERDES_DUAL) ||
- (hw->adapter->pdev->device == E1000_DEV_ID_82571EB_SERDES_QUAD)))
+ (hw->adapter->pdev->device == E1000_DEV_ID_82571EB_SERDES_QUAD) ||
+ (hw->adapter->pdev->device == E1000_DEV_ID_82571EB_SERDES)))
goto out;
ret_val = e1000_read_nvm(hw, NVM_ALT_MAC_ADDR_PTR, 1,
diff --git a/drivers/net/gianfar_ptp.c b/drivers/net/gianfar_ptp.c
index d8e1753..c413479 100644
--- a/drivers/net/gianfar_ptp.c
+++ b/drivers/net/gianfar_ptp.c
@@ -193,14 +193,9 @@
/* Caller must hold etsects->lock. */
static void set_fipers(struct etsects *etsects)
{
- u32 tmr_ctrl = gfar_read(&etsects->regs->tmr_ctrl);
-
- gfar_write(&etsects->regs->tmr_ctrl, tmr_ctrl & (~TE));
- gfar_write(&etsects->regs->tmr_prsc, etsects->tmr_prsc);
+ set_alarm(etsects);
gfar_write(&etsects->regs->tmr_fiper1, etsects->tmr_fiper1);
gfar_write(&etsects->regs->tmr_fiper2, etsects->tmr_fiper2);
- set_alarm(etsects);
- gfar_write(&etsects->regs->tmr_ctrl, tmr_ctrl|TE);
}
/*
@@ -511,7 +506,7 @@
gfar_write(&etsects->regs->tmr_fiper1, etsects->tmr_fiper1);
gfar_write(&etsects->regs->tmr_fiper2, etsects->tmr_fiper2);
set_alarm(etsects);
- gfar_write(&etsects->regs->tmr_ctrl, tmr_ctrl|FS|RTPE|TE);
+ gfar_write(&etsects->regs->tmr_ctrl, tmr_ctrl|FS|RTPE|TE|FRD);
spin_unlock_irqrestore(&etsects->lock, flags);
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index b388d78..145c924 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -394,7 +394,7 @@
}
/* recycle the current buffer on the rx queue */
-static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
+static int ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
{
u32 q_index = adapter->rx_queue.index;
u64 correlator = adapter->rx_queue.queue_addr[q_index].correlator;
@@ -402,6 +402,7 @@
unsigned int index = correlator & 0xffffffffUL;
union ibmveth_buf_desc desc;
unsigned long lpar_rc;
+ int ret = 1;
BUG_ON(pool >= IBMVETH_NUM_BUFF_POOLS);
BUG_ON(index >= adapter->rx_buff_pool[pool].size);
@@ -409,7 +410,7 @@
if (!adapter->rx_buff_pool[pool].active) {
ibmveth_rxq_harvest_buffer(adapter);
ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[pool]);
- return;
+ goto out;
}
desc.fields.flags_len = IBMVETH_BUF_VALID |
@@ -422,12 +423,16 @@
netdev_dbg(adapter->netdev, "h_add_logical_lan_buffer failed "
"during recycle rc=%ld", lpar_rc);
ibmveth_remove_buffer_from_pool(adapter, adapter->rx_queue.queue_addr[adapter->rx_queue.index].correlator);
+ ret = 0;
}
if (++adapter->rx_queue.index == adapter->rx_queue.num_slots) {
adapter->rx_queue.index = 0;
adapter->rx_queue.toggle = !adapter->rx_queue.toggle;
}
+
+out:
+ return ret;
}
static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter)
@@ -806,7 +811,7 @@
} else
adapter->fw_ipv6_csum_support = data;
- if (ret != H_SUCCESS || ret6 != H_SUCCESS)
+ if (ret == H_SUCCESS || ret6 == H_SUCCESS)
adapter->rx_csum = data;
else
rc1 = -EIO;
@@ -924,6 +929,7 @@
union ibmveth_buf_desc descs[6];
int last, i;
int force_bounce = 0;
+ dma_addr_t dma_addr;
/*
* veth handles a maximum of 6 segments including the header, so
@@ -988,17 +994,16 @@
}
/* Map the header */
- descs[0].fields.address = dma_map_single(&adapter->vdev->dev, skb->data,
- skb_headlen(skb),
- DMA_TO_DEVICE);
- if (dma_mapping_error(&adapter->vdev->dev, descs[0].fields.address))
+ dma_addr = dma_map_single(&adapter->vdev->dev, skb->data,
+ skb_headlen(skb), DMA_TO_DEVICE);
+ if (dma_mapping_error(&adapter->vdev->dev, dma_addr))
goto map_failed;
descs[0].fields.flags_len = desc_flags | skb_headlen(skb);
+ descs[0].fields.address = dma_addr;
/* Map the frags */
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- unsigned long dma_addr;
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
dma_addr = dma_map_page(&adapter->vdev->dev, frag->page,
@@ -1020,7 +1025,12 @@
netdev->stats.tx_bytes += skb->len;
}
- for (i = 0; i < skb_shinfo(skb)->nr_frags + 1; i++)
+ dma_unmap_single(&adapter->vdev->dev,
+ descs[0].fields.address,
+ descs[0].fields.flags_len & IBMVETH_BUF_LEN_MASK,
+ DMA_TO_DEVICE);
+
+ for (i = 1; i < skb_shinfo(skb)->nr_frags + 1; i++)
dma_unmap_page(&adapter->vdev->dev, descs[i].fields.address,
descs[i].fields.flags_len & IBMVETH_BUF_LEN_MASK,
DMA_TO_DEVICE);
@@ -1083,8 +1093,9 @@
if (rx_flush)
ibmveth_flush_buffer(skb->data,
length + offset);
+ if (!ibmveth_rxq_recycle_buffer(adapter))
+ kfree_skb(skb);
skb = new_skb;
- ibmveth_rxq_recycle_buffer(adapter);
} else {
ibmveth_rxq_harvest_buffer(adapter);
skb_reserve(skb, offset);
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index 4fecaed..2b98461 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -145,7 +145,7 @@
dev->flags |= IFF_NOARP;
dev->flags &= ~IFF_MULTICAST;
- dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
+ dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);
random_ether_addr(dev->dev_addr);
}
diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c
index 0f563c8..493e331 100644
--- a/drivers/net/igb/e1000_82575.c
+++ b/drivers/net/igb/e1000_82575.c
@@ -1735,6 +1735,7 @@
ctrl |= E1000_CTRL_RST;
wr32(E1000_CTRL, ctrl);
+ wrfl();
/* Add delay to insure DEV_RST has time to complete */
if (global_device_reset)
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index 2c28621..97f46ac 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -1985,7 +1985,7 @@
if (hw->bus.func == 0)
hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data);
- else if (hw->mac.type == e1000_82580)
+ else if (hw->mac.type >= e1000_82580)
hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A +
NVM_82580_LAN_FUNC_OFFSET(hw->bus.func), 1,
&eeprom_data);
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index 8800e1f..6a4826a 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -515,7 +515,7 @@
* Try to open driver instance
*
*/
-static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq)
+static int __devinit smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq)
{
struct smsc_ircc_cb *self;
struct net_device *dev;
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 08e8e25..83f197d 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -1366,8 +1366,8 @@
if (ring_is_rsc_enabled(rx_ring))
pkt_is_rsc = ixgbe_get_rsc_state(rx_desc);
- /* if this is a skb from previous receive DMA will be 0 */
- if (rx_buffer_info->dma) {
+ /* linear means we are building an skb from multiple pages */
+ if (!skb_is_nonlinear(skb)) {
u16 hlen;
if (pkt_is_rsc &&
!(staterr & IXGBE_RXD_STAT_EOP) &&
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index d6aeaa5..2f3c48d 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -547,7 +547,7 @@
{
ether_setup(dev);
- dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
+ dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);
dev->netdev_ops = &macvlan_netdev_ops;
dev->destructor = free_netdev;
dev->header_ops = &macvlan_hard_header_ops,
diff --git a/drivers/net/msm_rmnet_bam.c b/drivers/net/msm_rmnet_bam.c
index 3b3758e..e40edc3 100644
--- a/drivers/net/msm_rmnet_bam.c
+++ b/drivers/net/msm_rmnet_bam.c
@@ -308,15 +308,26 @@
}
dev->trans_start = jiffies;
+ /* if write() succeeds, skb access is unsafe in this process */
bam_ret = msm_bam_dmux_write(p->ch_id, skb);
if (bam_ret != 0) {
pr_err("[%s] %s: write returned error %d",
dev->name, __func__, bam_ret);
- goto xmit_out;
+ return -EAGAIN;
}
- if (count_this_packet(skb->data, skb->len)) {
+ return 0;
+}
+
+static void bam_write_done(void *dev, struct sk_buff *skb)
+{
+ struct rmnet_private *p = netdev_priv(dev);
+ u32 opmode = p->operation_mode;
+
+ DBG1("%s: write complete\n", __func__);
+ if (RMNET_IS_MODE_IP(opmode) ||
+ count_this_packet(skb->data, skb->len)) {
p->stats.tx_packets++;
p->stats.tx_bytes += skb->len;
#ifdef CONFIG_MSM_RMNET_DEBUG
@@ -324,20 +335,15 @@
#endif
}
DBG1("[%s] Tx packet #%lu len=%d mark=0x%x\n",
- dev->name, p->stats.tx_packets, skb->len, skb->mark);
-
- return 0;
-xmit_out:
- /* data xmited, safe to release skb */
+ ((struct net_device *)(dev))->name, p->stats.tx_packets,
+ skb->len, skb->mark);
dev_kfree_skb_any(skb);
- return 0;
-}
-
-static void bam_write_done(void *dev, struct sk_buff *skb)
-{
- DBG1("%s: write complete\n", __func__);
- dev_kfree_skb_any(skb);
- netif_wake_queue(dev);
+ if (netif_queue_stopped(dev) &&
+ msm_bam_dmux_is_ch_low(p->ch_id)) {
+ DBG0("%s: Low WM hit, waking queue=%p\n",
+ __func__, skb);
+ netif_wake_queue(dev);
+ }
}
static void bam_notify(void *dev, int event, unsigned long data)
@@ -440,6 +446,7 @@
static int rmnet_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct rmnet_private *p = netdev_priv(dev);
+ int ret = 0;
if (netif_queue_stopped(dev)) {
pr_err("[%s]fatal: rmnet_xmit called when "
@@ -447,13 +454,21 @@
return 0;
}
- netif_stop_queue(dev);
if (!ul_is_connected) {
p->waiting_for_ul = 1;
msm_bam_dmux_kickoff_ul_wakeup();
return NETDEV_TX_BUSY;
}
- _rmnet_xmit(skb, dev);
+ ret = _rmnet_xmit(skb, dev);
+ if (ret == -EAGAIN) {
+ netif_start_queue(dev);
+ return NETDEV_TX_BUSY;
+ }
+
+ if (msm_bam_dmux_is_ch_full(p->ch_id)) {
+ netif_stop_queue(dev);
+ DBG0("%s: High WM hit, stopping queue=%p\n", __func__, skb);
+ }
return 0;
}
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index cc25bff0..2f8c351 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -9196,7 +9196,7 @@
first_chan = 0;
for (i = 0; i < port; i++)
- first_chan += parent->rxchan_per_port[port];
+ first_chan += parent->rxchan_per_port[i];
num_chan = parent->rxchan_per_port[port];
for (i = first_chan; i < (first_chan + num_chan); i++) {
@@ -9212,7 +9212,7 @@
first_chan = 0;
for (i = 0; i < port; i++)
- first_chan += parent->txchan_per_port[port];
+ first_chan += parent->txchan_per_port[i];
num_chan = parent->txchan_per_port[port];
for (i = first_chan; i < (first_chan + num_chan); i++) {
err = niu_ldg_assign_ldn(np, parent,
diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c
index 2cd8dc5..cb6e0b4 100644
--- a/drivers/net/phy/dp83640.c
+++ b/drivers/net/phy/dp83640.c
@@ -34,8 +34,7 @@
#define PAGESEL 0x13
#define LAYER4 0x02
#define LAYER2 0x01
-#define MAX_RXTS 4
-#define MAX_TXTS 4
+#define MAX_RXTS 64
#define N_EXT_TS 1
#define PSF_PTPVER 2
#define PSF_EVNT 0x4000
@@ -218,7 +217,7 @@
rxts->seqid = p->seqid;
rxts->msgtype = (p->msgtype >> 12) & 0xf;
rxts->hash = p->msgtype & 0x0fff;
- rxts->tmo = jiffies + HZ;
+ rxts->tmo = jiffies + 2;
}
static u64 phy2txts(struct phy_txts *p)
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 5990621..5f838ef 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -236,6 +236,7 @@
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), 0, 0, RTL_CFG_1 },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), 0, 0, RTL_CFG_0 },
{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), 0, 0, RTL_CFG_0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4302), 0, 0, RTL_CFG_0 },
{ PCI_DEVICE(PCI_VENDOR_ID_AT, 0xc107), 0, 0, RTL_CFG_0 },
{ PCI_DEVICE(0x16ec, 0x0116), 0, 0, RTL_CFG_0 },
{ PCI_VENDOR_ID_LINKSYS, 0x1032,
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
index 5d3436d..ca4694e 100644
--- a/drivers/net/rionet.c
+++ b/drivers/net/rionet.c
@@ -80,13 +80,13 @@
*/
static struct rio_dev **rionet_active;
-#define is_rionet_capable(pef, src_ops, dst_ops) \
- ((pef & RIO_PEF_INB_MBOX) && \
- (pef & RIO_PEF_INB_DOORBELL) && \
+#define is_rionet_capable(src_ops, dst_ops) \
+ ((src_ops & RIO_SRC_OPS_DATA_MSG) && \
+ (dst_ops & RIO_DST_OPS_DATA_MSG) && \
(src_ops & RIO_SRC_OPS_DOORBELL) && \
(dst_ops & RIO_DST_OPS_DOORBELL))
#define dev_rionet_capable(dev) \
- is_rionet_capable(dev->pef, dev->src_ops, dev->dst_ops)
+ is_rionet_capable(dev->src_ops, dev->dst_ops)
#define RIONET_MAC_MATCH(x) (*(u32 *)x == 0x00010001)
#define RIONET_GET_DESTID(x) (*(u16 *)(x + 4))
@@ -282,7 +282,6 @@
{
int i, rc = 0;
struct rionet_peer *peer, *tmp;
- u32 pwdcsr;
struct rionet_private *rnet = netdev_priv(ndev);
if (netif_msg_ifup(rnet))
@@ -332,13 +331,8 @@
continue;
}
- /*
- * If device has initialized inbound doorbells,
- * send a join message
- */
- rio_read_config_32(peer->rdev, RIO_WRITE_PORT_CSR, &pwdcsr);
- if (pwdcsr & RIO_DOORBELL_AVAIL)
- rio_send_doorbell(peer->rdev, RIONET_DOORBELL_JOIN);
+ /* Send a join message */
+ rio_send_doorbell(peer->rdev, RIONET_DOORBELL_JOIN);
}
out:
@@ -492,7 +486,7 @@
static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id)
{
int rc = -ENODEV;
- u32 lpef, lsrc_ops, ldst_ops;
+ u32 lsrc_ops, ldst_ops;
struct rionet_peer *peer;
struct net_device *ndev = NULL;
@@ -515,12 +509,11 @@
* on later probes
*/
if (!rionet_check) {
- rio_local_read_config_32(rdev->net->hport, RIO_PEF_CAR, &lpef);
rio_local_read_config_32(rdev->net->hport, RIO_SRC_OPS_CAR,
&lsrc_ops);
rio_local_read_config_32(rdev->net->hport, RIO_DST_OPS_CAR,
&ldst_ops);
- if (!is_rionet_capable(lpef, lsrc_ops, ldst_ops)) {
+ if (!is_rionet_capable(lsrc_ops, ldst_ops)) {
printk(KERN_ERR
"%s: local device is not network capable\n",
DRV_NAME);
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index c914729..7d1651b 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1051,7 +1051,6 @@
{
struct pci_dev *pci_dev = efx->pci_dev;
dma_addr_t dma_mask = efx->type->max_dma_mask;
- bool use_wc;
int rc;
netif_dbg(efx, probe, efx->net_dev, "initialising I/O\n");
@@ -1102,21 +1101,8 @@
rc = -EIO;
goto fail3;
}
-
- /* bug22643: If SR-IOV is enabled then tx push over a write combined
- * mapping is unsafe. We need to disable write combining in this case.
- * MSI is unsupported when SR-IOV is enabled, and the firmware will
- * have removed the MSI capability. So write combining is safe if
- * there is an MSI capability.
- */
- use_wc = (!EFX_WORKAROUND_22643(efx) ||
- pci_find_capability(pci_dev, PCI_CAP_ID_MSI));
- if (use_wc)
- efx->membase = ioremap_wc(efx->membase_phys,
- efx->type->mem_map_size);
- else
- efx->membase = ioremap_nocache(efx->membase_phys,
- efx->type->mem_map_size);
+ efx->membase = ioremap_nocache(efx->membase_phys,
+ efx->type->mem_map_size);
if (!efx->membase) {
netif_err(efx, probe, efx->net_dev,
"could not map memory BAR at %llx+%x\n",
diff --git a/drivers/net/sfc/io.h b/drivers/net/sfc/io.h
index cc97880..dc45110 100644
--- a/drivers/net/sfc/io.h
+++ b/drivers/net/sfc/io.h
@@ -48,9 +48,9 @@
* replacing the low 96 bits with zero does not affect functionality.
* - If the host writes to the last dword address of such a register
* (i.e. the high 32 bits) the underlying register will always be
- * written. If the collector and the current write together do not
- * provide values for all 128 bits of the register, the low 96 bits
- * will be written as zero.
+ * written. If the collector does not hold values for the low 96
+ * bits of the register, they will be written as zero. Writing to
+ * the last qword does not have this effect and must not be done.
* - If the host writes to the address of any other part of such a
* register while the collector already holds values for some other
* register, the write is discarded and the collector maintains its
@@ -103,7 +103,6 @@
_efx_writed(efx, value->u32[2], reg + 8);
_efx_writed(efx, value->u32[3], reg + 12);
#endif
- wmb();
mmiowb();
spin_unlock_irqrestore(&efx->biu_lock, flags);
}
@@ -126,7 +125,6 @@
__raw_writel((__force u32)value->u32[0], membase + addr);
__raw_writel((__force u32)value->u32[1], membase + addr + 4);
#endif
- wmb();
mmiowb();
spin_unlock_irqrestore(&efx->biu_lock, flags);
}
@@ -141,7 +139,6 @@
/* No lock required */
_efx_writed(efx, value->u32[0], reg);
- wmb();
}
/* Read a 128-bit CSR, locking as appropriate. */
@@ -152,7 +149,6 @@
spin_lock_irqsave(&efx->biu_lock, flags);
value->u32[0] = _efx_readd(efx, reg + 0);
- rmb();
value->u32[1] = _efx_readd(efx, reg + 4);
value->u32[2] = _efx_readd(efx, reg + 8);
value->u32[3] = _efx_readd(efx, reg + 12);
@@ -175,7 +171,6 @@
value->u64[0] = (__force __le64)__raw_readq(membase + addr);
#else
value->u32[0] = (__force __le32)__raw_readl(membase + addr);
- rmb();
value->u32[1] = (__force __le32)__raw_readl(membase + addr + 4);
#endif
spin_unlock_irqrestore(&efx->biu_lock, flags);
@@ -242,14 +237,12 @@
#ifdef EFX_USE_QWORD_IO
_efx_writeq(efx, value->u64[0], reg + 0);
- _efx_writeq(efx, value->u64[1], reg + 8);
#else
_efx_writed(efx, value->u32[0], reg + 0);
_efx_writed(efx, value->u32[1], reg + 4);
+#endif
_efx_writed(efx, value->u32[2], reg + 8);
_efx_writed(efx, value->u32[3], reg + 12);
-#endif
- wmb();
}
#define efx_writeo_page(efx, value, reg, page) \
_efx_writeo_page(efx, value, \
diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c
index 3dd45ed..81a4253 100644
--- a/drivers/net/sfc/mcdi.c
+++ b/drivers/net/sfc/mcdi.c
@@ -50,20 +50,6 @@
return &nic_data->mcdi;
}
-static inline void
-efx_mcdi_readd(struct efx_nic *efx, efx_dword_t *value, unsigned reg)
-{
- struct siena_nic_data *nic_data = efx->nic_data;
- value->u32[0] = (__force __le32)__raw_readl(nic_data->mcdi_smem + reg);
-}
-
-static inline void
-efx_mcdi_writed(struct efx_nic *efx, const efx_dword_t *value, unsigned reg)
-{
- struct siena_nic_data *nic_data = efx->nic_data;
- __raw_writel((__force u32)value->u32[0], nic_data->mcdi_smem + reg);
-}
-
void efx_mcdi_init(struct efx_nic *efx)
{
struct efx_mcdi_iface *mcdi;
@@ -84,8 +70,8 @@
const u8 *inbuf, size_t inlen)
{
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
- unsigned pdu = MCDI_PDU(efx);
- unsigned doorbell = MCDI_DOORBELL(efx);
+ unsigned pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx);
+ unsigned doorbell = FR_CZ_MC_TREG_SMEM + MCDI_DOORBELL(efx);
unsigned int i;
efx_dword_t hdr;
u32 xflags, seqno;
@@ -106,28 +92,29 @@
MCDI_HEADER_SEQ, seqno,
MCDI_HEADER_XFLAGS, xflags);
- efx_mcdi_writed(efx, &hdr, pdu);
+ efx_writed(efx, &hdr, pdu);
for (i = 0; i < inlen; i += 4)
- efx_mcdi_writed(efx, (const efx_dword_t *)(inbuf + i),
- pdu + 4 + i);
+ _efx_writed(efx, *((__le32 *)(inbuf + i)), pdu + 4 + i);
+
+ /* Ensure the payload is written out before the header */
+ wmb();
/* ring the doorbell with a distinctive value */
- EFX_POPULATE_DWORD_1(hdr, EFX_DWORD_0, 0x45789abc);
- efx_mcdi_writed(efx, &hdr, doorbell);
+ _efx_writed(efx, (__force __le32) 0x45789abc, doorbell);
}
static void efx_mcdi_copyout(struct efx_nic *efx, u8 *outbuf, size_t outlen)
{
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
- unsigned int pdu = MCDI_PDU(efx);
+ unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx);
int i;
BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT);
BUG_ON(outlen & 3 || outlen >= 0x100);
for (i = 0; i < outlen; i += 4)
- efx_mcdi_readd(efx, (efx_dword_t *)(outbuf + i), pdu + 4 + i);
+ *((__le32 *)(outbuf + i)) = _efx_readd(efx, pdu + 4 + i);
}
static int efx_mcdi_poll(struct efx_nic *efx)
@@ -135,7 +122,7 @@
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
unsigned int time, finish;
unsigned int respseq, respcmd, error;
- unsigned int pdu = MCDI_PDU(efx);
+ unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx);
unsigned int rc, spins;
efx_dword_t reg;
@@ -161,7 +148,8 @@
time = get_seconds();
- efx_mcdi_readd(efx, ®, pdu);
+ rmb();
+ efx_readd(efx, ®, pdu);
/* All 1's indicates that shared memory is in reset (and is
* not a valid header). Wait for it to come out reset before
@@ -188,7 +176,7 @@
respseq, mcdi->seqno);
rc = EIO;
} else if (error) {
- efx_mcdi_readd(efx, ®, pdu + 4);
+ efx_readd(efx, ®, pdu + 4);
switch (EFX_DWORD_FIELD(reg, EFX_DWORD_0)) {
#define TRANSLATE_ERROR(name) \
case MC_CMD_ERR_ ## name: \
@@ -222,21 +210,21 @@
/* Test and clear MC-rebooted flag for this port/function */
int efx_mcdi_poll_reboot(struct efx_nic *efx)
{
- unsigned int addr = MCDI_REBOOT_FLAG(efx);
+ unsigned int addr = FR_CZ_MC_TREG_SMEM + MCDI_REBOOT_FLAG(efx);
efx_dword_t reg;
uint32_t value;
if (efx_nic_rev(efx) < EFX_REV_SIENA_A0)
return false;
- efx_mcdi_readd(efx, ®, addr);
+ efx_readd(efx, ®, addr);
value = EFX_DWORD_FIELD(reg, EFX_DWORD_0);
if (value == 0)
return 0;
EFX_ZERO_DWORD(reg);
- efx_mcdi_writed(efx, ®, addr);
+ efx_writed(efx, ®, addr);
if (value == MC_STATUS_DWORD_ASSERT)
return -EINTR;
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c
index f2a2b94..5ac9fa2 100644
--- a/drivers/net/sfc/nic.c
+++ b/drivers/net/sfc/nic.c
@@ -1935,13 +1935,6 @@
size = min_t(size_t, table->step, 16);
- if (table->offset >= efx->type->mem_map_size) {
- /* No longer mapped; return dummy data */
- memcpy(buf, "\xde\xc0\xad\xde", 4);
- buf += table->rows * size;
- continue;
- }
-
for (i = 0; i < table->rows; i++) {
switch (table->step) {
case 4: /* 32-bit register or SRAM */
diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h
index 4bd1f28..7443f99 100644
--- a/drivers/net/sfc/nic.h
+++ b/drivers/net/sfc/nic.h
@@ -143,12 +143,10 @@
/**
* struct siena_nic_data - Siena NIC state
* @mcdi: Management-Controller-to-Driver Interface
- * @mcdi_smem: MCDI shared memory mapping. The mapping is always uncacheable.
* @wol_filter_id: Wake-on-LAN packet filter id
*/
struct siena_nic_data {
struct efx_mcdi_iface mcdi;
- void __iomem *mcdi_smem;
int wol_filter_id;
};
diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c
index fb4721f..ceac1c9 100644
--- a/drivers/net/sfc/siena.c
+++ b/drivers/net/sfc/siena.c
@@ -220,26 +220,12 @@
efx_reado(efx, ®, FR_AZ_CS_DEBUG);
efx->net_dev->dev_id = EFX_OWORD_FIELD(reg, FRF_CZ_CS_PORT_NUM) - 1;
- /* Initialise MCDI */
- nic_data->mcdi_smem = ioremap_nocache(efx->membase_phys +
- FR_CZ_MC_TREG_SMEM,
- FR_CZ_MC_TREG_SMEM_STEP *
- FR_CZ_MC_TREG_SMEM_ROWS);
- if (!nic_data->mcdi_smem) {
- netif_err(efx, probe, efx->net_dev,
- "could not map MCDI at %llx+%x\n",
- (unsigned long long)efx->membase_phys +
- FR_CZ_MC_TREG_SMEM,
- FR_CZ_MC_TREG_SMEM_STEP * FR_CZ_MC_TREG_SMEM_ROWS);
- rc = -ENOMEM;
- goto fail1;
- }
efx_mcdi_init(efx);
/* Recover from a failed assertion before probing */
rc = efx_mcdi_handle_assertion(efx);
if (rc)
- goto fail2;
+ goto fail1;
/* Let the BMC know that the driver is now in charge of link and
* filter settings. We must do this before we reset the NIC */
@@ -294,7 +280,6 @@
fail3:
efx_mcdi_drv_attach(efx, false, NULL);
fail2:
- iounmap(nic_data->mcdi_smem);
fail1:
kfree(efx->nic_data);
return rc;
@@ -374,8 +359,6 @@
static void siena_remove_nic(struct efx_nic *efx)
{
- struct siena_nic_data *nic_data = efx->nic_data;
-
efx_nic_free_buffer(efx, &efx->irq_status);
siena_reset_hw(efx, RESET_TYPE_ALL);
@@ -385,8 +368,7 @@
efx_mcdi_drv_attach(efx, false, NULL);
/* Tear down the private nic state */
- iounmap(nic_data->mcdi_smem);
- kfree(nic_data);
+ kfree(efx->nic_data);
efx->nic_data = NULL;
}
@@ -624,7 +606,8 @@
.default_mac_ops = &efx_mcdi_mac_operations,
.revision = EFX_REV_SIENA_A0,
- .mem_map_size = FR_CZ_MC_TREG_SMEM, /* MC_TREG_SMEM mapped separately */
+ .mem_map_size = (FR_CZ_MC_TREG_SMEM +
+ FR_CZ_MC_TREG_SMEM_STEP * FR_CZ_MC_TREG_SMEM_ROWS),
.txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL,
.rxd_ptr_tbl_base = FR_BZ_RX_DESC_PTR_TBL,
.buf_tbl_base = FR_BZ_BUF_FULL_TBL,
diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h
index 99ff114..e4dd3a7 100644
--- a/drivers/net/sfc/workarounds.h
+++ b/drivers/net/sfc/workarounds.h
@@ -38,8 +38,6 @@
#define EFX_WORKAROUND_15783 EFX_WORKAROUND_ALWAYS
/* Legacy interrupt storm when interrupt fifo fills */
#define EFX_WORKAROUND_17213 EFX_WORKAROUND_SIENA
-/* Write combining and sriov=enabled are incompatible */
-#define EFX_WORKAROUND_22643 EFX_WORKAROUND_SIENA
/* Spurious parity errors in TSORT buffers */
#define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index b436e00..f6d26ab 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -1824,6 +1824,16 @@
generic_mii_ioctl(&tp->mii_if, if_mii(ifr), cmd, NULL);
}
+static int sis190_mac_addr(struct net_device *dev, void *p)
+{
+ int rc;
+
+ rc = eth_mac_addr(dev, p);
+ if (!rc)
+ sis190_init_rxfilter(dev);
+ return rc;
+}
+
static const struct net_device_ops sis190_netdev_ops = {
.ndo_open = sis190_open,
.ndo_stop = sis190_close,
@@ -1832,7 +1842,7 @@
.ndo_tx_timeout = sis190_tx_timeout,
.ndo_set_multicast_list = sis190_set_rx_mode,
.ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
+ .ndo_set_mac_address = sis190_mac_addr,
.ndo_validate_addr = eth_validate_addr,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = sis190_netpoll,
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index a1f9f9e..38f6859 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -7267,16 +7267,11 @@
tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
}
- if (tg3_flag(tp, ENABLE_APE))
- tp->mac_mode = MAC_MODE_APE_TX_EN |
- MAC_MODE_APE_RX_EN |
- MAC_MODE_TDE_ENABLE;
-
if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
- tp->mac_mode |= MAC_MODE_PORT_MODE_TBI;
+ tp->mac_mode = MAC_MODE_PORT_MODE_TBI;
val = tp->mac_mode;
} else if (tp->phy_flags & TG3_PHYFLG_MII_SERDES) {
- tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
+ tp->mac_mode = MAC_MODE_PORT_MODE_GMII;
val = tp->mac_mode;
} else
val = 0;
@@ -8408,12 +8403,11 @@
udelay(10);
}
- if (tg3_flag(tp, ENABLE_APE))
- tp->mac_mode = MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN;
- else
- tp->mac_mode = 0;
tp->mac_mode |= MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE |
- MAC_MODE_TDE_ENABLE | MAC_MODE_RDE_ENABLE | MAC_MODE_FHDE_ENABLE;
+ MAC_MODE_TDE_ENABLE | MAC_MODE_RDE_ENABLE |
+ MAC_MODE_FHDE_ENABLE;
+ if (tg3_flag(tp, ENABLE_APE))
+ tp->mac_mode |= MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN;
if (!tg3_flag(tp, 5705_PLUS) &&
!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700)
@@ -8988,7 +8982,7 @@
* Turn off MSI one shot mode. Otherwise this test has no
* observable way to know whether the interrupt was delivered.
*/
- if (tg3_flag(tp, 57765_PLUS) && tg3_flag(tp, USING_MSI)) {
+ if (tg3_flag(tp, 57765_PLUS)) {
val = tr32(MSGINT_MODE) | MSGINT_MODE_ONE_SHOT_DISABLE;
tw32(MSGINT_MODE, val);
}
@@ -9016,6 +9010,10 @@
break;
}
+ if (tg3_flag(tp, 57765_PLUS) &&
+ tnapi->hw_status->status_tag != tnapi->last_tag)
+ tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24);
+
msleep(10);
}
@@ -9030,7 +9028,7 @@
if (intr_ok) {
/* Reenable MSI one shot mode. */
- if (tg3_flag(tp, 57765_PLUS) && tg3_flag(tp, USING_MSI)) {
+ if (tg3_flag(tp, 57765_PLUS)) {
val = tr32(MSGINT_MODE) & ~MSGINT_MODE_ONE_SHOT_DISABLE;
tw32(MSGINT_MODE, val);
}
@@ -12947,7 +12945,9 @@
}
if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) &&
- ((tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 &&
+ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720 ||
+ (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 &&
tp->pci_chip_rev_id != CHIPREV_ID_5717_A0) ||
(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 &&
tp->pci_chip_rev_id != CHIPREV_ID_57765_A0)))
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 67e474f..76b8650 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -528,6 +528,7 @@
dev->netdev_ops = &tap_netdev_ops;
/* Ethernet TAP Device */
ether_setup(dev);
+ dev->priv_flags &= ~IFF_TX_SKB_SHARING;
random_ether_addr(dev->dev_addr);
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index 6998aa6..5250288 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -1502,6 +1502,10 @@
USB_DEVICE (0x04f1, 0x3008),
.driver_info = (unsigned long) &ax8817x_info,
}, {
+ // ASIX AX88772B 10/100
+ USB_DEVICE (0x0b95, 0x772b),
+ .driver_info = (unsigned long) &ax88772_info,
+}, {
// ASIX AX88772 10/100
USB_DEVICE (0x0b95, 0x7720),
.driver_info = (unsigned long) &ax88772_info,
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index f33ca6a..d3b9e95 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -54,7 +54,7 @@
#include <linux/usb/usbnet.h>
#include <linux/usb/cdc.h>
-#define DRIVER_VERSION "01-June-2011"
+#define DRIVER_VERSION "04-Aug-2011"
/* CDC NCM subclass 3.2.1 */
#define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10
@@ -164,35 +164,8 @@
usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info));
}
-static int
-cdc_ncm_do_request(struct cdc_ncm_ctx *ctx, struct usb_cdc_notification *req,
- void *data, u16 flags, u16 *actlen, u16 timeout)
-{
- int err;
-
- err = usb_control_msg(ctx->udev, (req->bmRequestType & USB_DIR_IN) ?
- usb_rcvctrlpipe(ctx->udev, 0) :
- usb_sndctrlpipe(ctx->udev, 0),
- req->bNotificationType, req->bmRequestType,
- req->wValue,
- req->wIndex, data,
- req->wLength, timeout);
-
- if (err < 0) {
- if (actlen)
- *actlen = 0;
- return err;
- }
-
- if (actlen)
- *actlen = err;
-
- return 0;
-}
-
static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx)
{
- struct usb_cdc_notification req;
u32 val;
u8 flags;
u8 iface_no;
@@ -201,14 +174,14 @@
iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber;
- req.bmRequestType = USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE;
- req.bNotificationType = USB_CDC_GET_NTB_PARAMETERS;
- req.wValue = 0;
- req.wIndex = cpu_to_le16(iface_no);
- req.wLength = cpu_to_le16(sizeof(ctx->ncm_parm));
-
- err = cdc_ncm_do_request(ctx, &req, &ctx->ncm_parm, 0, NULL, 1000);
- if (err) {
+ err = usb_control_msg(ctx->udev,
+ usb_rcvctrlpipe(ctx->udev, 0),
+ USB_CDC_GET_NTB_PARAMETERS,
+ USB_TYPE_CLASS | USB_DIR_IN
+ | USB_RECIP_INTERFACE,
+ 0, iface_no, &ctx->ncm_parm,
+ sizeof(ctx->ncm_parm), 10000);
+ if (err < 0) {
pr_debug("failed GET_NTB_PARAMETERS\n");
return 1;
}
@@ -254,31 +227,26 @@
/* inform device about NTB input size changes */
if (ctx->rx_max != le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize)) {
- req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT |
- USB_RECIP_INTERFACE;
- req.bNotificationType = USB_CDC_SET_NTB_INPUT_SIZE;
- req.wValue = 0;
- req.wIndex = cpu_to_le16(iface_no);
if (flags & USB_CDC_NCM_NCAP_NTB_INPUT_SIZE) {
struct usb_cdc_ncm_ndp_input_size ndp_in_sz;
-
- req.wLength = 8;
- ndp_in_sz.dwNtbInMaxSize = cpu_to_le32(ctx->rx_max);
- ndp_in_sz.wNtbInMaxDatagrams =
- cpu_to_le16(CDC_NCM_DPT_DATAGRAMS_MAX);
- ndp_in_sz.wReserved = 0;
- err = cdc_ncm_do_request(ctx, &req, &ndp_in_sz, 0, NULL,
- 1000);
+ err = usb_control_msg(ctx->udev,
+ usb_sndctrlpipe(ctx->udev, 0),
+ USB_CDC_SET_NTB_INPUT_SIZE,
+ USB_TYPE_CLASS | USB_DIR_OUT
+ | USB_RECIP_INTERFACE,
+ 0, iface_no, &ndp_in_sz, 8, 1000);
} else {
__le32 dwNtbInMaxSize = cpu_to_le32(ctx->rx_max);
-
- req.wLength = 4;
- err = cdc_ncm_do_request(ctx, &req, &dwNtbInMaxSize, 0,
- NULL, 1000);
+ err = usb_control_msg(ctx->udev,
+ usb_sndctrlpipe(ctx->udev, 0),
+ USB_CDC_SET_NTB_INPUT_SIZE,
+ USB_TYPE_CLASS | USB_DIR_OUT
+ | USB_RECIP_INTERFACE,
+ 0, iface_no, &dwNtbInMaxSize, 4, 1000);
}
- if (err)
+ if (err < 0)
pr_debug("Setting NTB Input Size failed\n");
}
@@ -333,29 +301,24 @@
/* set CRC Mode */
if (flags & USB_CDC_NCM_NCAP_CRC_MODE) {
- req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT |
- USB_RECIP_INTERFACE;
- req.bNotificationType = USB_CDC_SET_CRC_MODE;
- req.wValue = cpu_to_le16(USB_CDC_NCM_CRC_NOT_APPENDED);
- req.wIndex = cpu_to_le16(iface_no);
- req.wLength = 0;
-
- err = cdc_ncm_do_request(ctx, &req, NULL, 0, NULL, 1000);
- if (err)
+ err = usb_control_msg(ctx->udev, usb_sndctrlpipe(ctx->udev, 0),
+ USB_CDC_SET_CRC_MODE,
+ USB_TYPE_CLASS | USB_DIR_OUT
+ | USB_RECIP_INTERFACE,
+ USB_CDC_NCM_CRC_NOT_APPENDED,
+ iface_no, NULL, 0, 1000);
+ if (err < 0)
pr_debug("Setting CRC mode off failed\n");
}
/* set NTB format, if both formats are supported */
if (ntb_fmt_supported & USB_CDC_NCM_NTH32_SIGN) {
- req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT |
- USB_RECIP_INTERFACE;
- req.bNotificationType = USB_CDC_SET_NTB_FORMAT;
- req.wValue = cpu_to_le16(USB_CDC_NCM_NTB16_FORMAT);
- req.wIndex = cpu_to_le16(iface_no);
- req.wLength = 0;
-
- err = cdc_ncm_do_request(ctx, &req, NULL, 0, NULL, 1000);
- if (err)
+ err = usb_control_msg(ctx->udev, usb_sndctrlpipe(ctx->udev, 0),
+ USB_CDC_SET_NTB_FORMAT, USB_TYPE_CLASS
+ | USB_DIR_OUT | USB_RECIP_INTERFACE,
+ USB_CDC_NCM_NTB16_FORMAT,
+ iface_no, NULL, 0, 1000);
+ if (err < 0)
pr_debug("Setting NTB format to 16-bit failed\n");
}
@@ -365,17 +328,13 @@
if (flags & USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE) {
__le16 max_datagram_size;
u16 eth_max_sz = le16_to_cpu(ctx->ether_desc->wMaxSegmentSize);
-
- req.bmRequestType = USB_TYPE_CLASS | USB_DIR_IN |
- USB_RECIP_INTERFACE;
- req.bNotificationType = USB_CDC_GET_MAX_DATAGRAM_SIZE;
- req.wValue = 0;
- req.wIndex = cpu_to_le16(iface_no);
- req.wLength = cpu_to_le16(2);
-
- err = cdc_ncm_do_request(ctx, &req, &max_datagram_size, 0, NULL,
- 1000);
- if (err) {
+ err = usb_control_msg(ctx->udev, usb_rcvctrlpipe(ctx->udev, 0),
+ USB_CDC_GET_MAX_DATAGRAM_SIZE,
+ USB_TYPE_CLASS | USB_DIR_IN
+ | USB_RECIP_INTERFACE,
+ 0, iface_no, &max_datagram_size,
+ 2, 1000);
+ if (err < 0) {
pr_debug("GET_MAX_DATAGRAM_SIZE failed, use size=%u\n",
CDC_NCM_MIN_DATAGRAM_SIZE);
} else {
@@ -396,17 +355,15 @@
CDC_NCM_MIN_DATAGRAM_SIZE;
/* if value changed, update device */
- req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT |
- USB_RECIP_INTERFACE;
- req.bNotificationType = USB_CDC_SET_MAX_DATAGRAM_SIZE;
- req.wValue = 0;
- req.wIndex = cpu_to_le16(iface_no);
- req.wLength = 2;
- max_datagram_size = cpu_to_le16(ctx->max_datagram_size);
-
- err = cdc_ncm_do_request(ctx, &req, &max_datagram_size,
- 0, NULL, 1000);
- if (err)
+ err = usb_control_msg(ctx->udev,
+ usb_sndctrlpipe(ctx->udev, 0),
+ USB_CDC_SET_MAX_DATAGRAM_SIZE,
+ USB_TYPE_CLASS | USB_DIR_OUT
+ | USB_RECIP_INTERFACE,
+ 0,
+ iface_no, &max_datagram_size,
+ 2, 1000);
+ if (err < 0)
pr_debug("SET_MAX_DATAGRAM_SIZE failed\n");
}
@@ -672,7 +629,7 @@
u32 rem;
u32 offset;
u32 last_offset;
- u16 n = 0;
+ u16 n = 0, index;
u8 ready2send = 0;
/* if there is a remaining skb, it gets priority */
@@ -860,8 +817,8 @@
cpu_to_le16(sizeof(ctx->tx_ncm.nth16));
ctx->tx_ncm.nth16.wSequence = cpu_to_le16(ctx->tx_seq);
ctx->tx_ncm.nth16.wBlockLength = cpu_to_le16(last_offset);
- ctx->tx_ncm.nth16.wNdpIndex = ALIGN(sizeof(struct usb_cdc_ncm_nth16),
- ctx->tx_ndp_modulus);
+ index = ALIGN(sizeof(struct usb_cdc_ncm_nth16), ctx->tx_ndp_modulus);
+ ctx->tx_ncm.nth16.wNdpIndex = cpu_to_le16(index);
memcpy(skb_out->data, &(ctx->tx_ncm.nth16), sizeof(ctx->tx_ncm.nth16));
ctx->tx_seq++;
@@ -874,12 +831,11 @@
ctx->tx_ncm.ndp16.wLength = cpu_to_le16(rem);
ctx->tx_ncm.ndp16.wNextNdpIndex = 0; /* reserved */
- memcpy(((u8 *)skb_out->data) + ctx->tx_ncm.nth16.wNdpIndex,
+ memcpy(((u8 *)skb_out->data) + index,
&(ctx->tx_ncm.ndp16),
sizeof(ctx->tx_ncm.ndp16));
- memcpy(((u8 *)skb_out->data) + ctx->tx_ncm.nth16.wNdpIndex +
- sizeof(ctx->tx_ncm.ndp16),
+ memcpy(((u8 *)skb_out->data) + index + sizeof(ctx->tx_ncm.ndp16),
&(ctx->tx_ncm.dpe16),
(ctx->tx_curr_frame_num + 1) *
sizeof(struct usb_cdc_ncm_dpe16));
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 8461576..4bf7c6d 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -262,6 +262,8 @@
{
ether_setup(dev);
+ dev->priv_flags &= ~IFF_TX_SKB_SHARING;
+
dev->netdev_ops = &veth_netdev_ops;
dev->ethtool_ops = &veth_ethtool_ops;
dev->features |= NETIF_F_LLTX;
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index fc433f2..13f9997 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -1083,9 +1083,10 @@
used = pvc_is_used(pvc);
- if (type == ARPHRD_ETHER)
+ if (type == ARPHRD_ETHER) {
dev = alloc_netdev(0, "pvceth%d", ether_setup);
- else
+ dev->priv_flags &= ~IFF_TX_SKB_SHARING;
+ } else
dev = alloc_netdev(0, "pvc%d", pvc_setup);
if (!dev) {
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 55cf71f..e1b3e3c 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -2823,6 +2823,7 @@
dev->wireless_data = &ai->wireless_data;
dev->irq = irq;
dev->base_addr = port;
+ dev->priv_flags &= ~IFF_TX_SKB_SHARING;
SET_NETDEV_DEV(dev, dmdev);
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index b6c5d37..1ae8913 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -1748,6 +1748,8 @@
if (dma_mapping_error(sc->dev, bf->skbaddr)) {
ATH5K_ERR(sc, "beacon DMA mapping failed\n");
+ dev_kfree_skb_any(skb);
+ bf->skb = NULL;
return -EIO;
}
@@ -1832,8 +1834,6 @@
ath5k_txbuf_free_skb(sc, avf->bbuf);
avf->bbuf->skb = skb;
ret = ath5k_beacon_setup(sc, avf->bbuf);
- if (ret)
- avf->bbuf->skb = NULL;
out:
return ret;
}
@@ -1854,6 +1854,7 @@
struct ath5k_vif *avf;
struct ath5k_buf *bf;
struct sk_buff *skb;
+ int err;
ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n");
@@ -1902,11 +1903,6 @@
avf = (void *)vif->drv_priv;
bf = avf->bbuf;
- if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION ||
- sc->opmode == NL80211_IFTYPE_MONITOR)) {
- ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL);
- return;
- }
/*
* Stop any current dma and put the new frame on the queue.
@@ -1920,8 +1916,17 @@
/* refresh the beacon for AP or MESH mode */
if (sc->opmode == NL80211_IFTYPE_AP ||
- sc->opmode == NL80211_IFTYPE_MESH_POINT)
- ath5k_beacon_update(sc->hw, vif);
+ sc->opmode == NL80211_IFTYPE_MESH_POINT) {
+ err = ath5k_beacon_update(sc->hw, vif);
+ if (err)
+ return;
+ }
+
+ if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION ||
+ sc->opmode == NL80211_IFTYPE_MONITOR)) {
+ ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf->skb);
+ return;
+ }
trace_ath5k_tx(sc, bf->skb, &sc->txqs[sc->bhalq]);
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
index 2d4c091..2d394af 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
@@ -41,7 +41,8 @@
case ADC_DC_CAL:
/* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */
if (!IS_CHAN_B(chan) &&
- !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan)))
+ !((IS_CHAN_2GHZ(chan) || IS_CHAN_A_FAST_CLOCK(ah, chan)) &&
+ IS_CHAN_HT20(chan)))
supported = true;
break;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
index f344cc2..c32f9d1 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
@@ -309,11 +309,7 @@
u8 i;
u32 val;
- if (ah->is_pciexpress != true)
- return;
-
- /* Do not touch SerDes registers */
- if (ah->config.pcie_powersave_enable == 2)
+ if (ah->is_pciexpress != true || ah->aspm_enabled != true)
return;
/* Nothing to do on restore for 11N */
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
index e8ac70d..029773c 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
@@ -1516,7 +1516,7 @@
{0x00008258, 0x00000000},
{0x0000825c, 0x40000000},
{0x00008260, 0x00080922},
- {0x00008264, 0x9bc00010},
+ {0x00008264, 0x9d400010},
{0x00008268, 0xffffffff},
{0x0000826c, 0x0000ffff},
{0x00008270, 0x00000000},
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index ff8150e..417106b 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -68,7 +68,7 @@
static const struct ar9300_eeprom ar9300_default = {
.eepromVersion = 2,
.templateVersion = 2,
- .macAddr = {1, 2, 3, 4, 5, 6},
+ .macAddr = {0, 2, 3, 4, 5, 6},
.custData = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
.baseEepHeader = {
@@ -306,7 +306,7 @@
{ { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
{ { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
- { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
+ { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0) } },
{ { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
{ { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
@@ -883,7 +883,7 @@
{ { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
{ { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
- { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
+ { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0) } },
{ { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
{ { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
@@ -2039,7 +2039,7 @@
{ { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
{ { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
- { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
+ { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0) } },
{ { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
{ { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
index 392bf0f..7e02fb4 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
@@ -351,11 +351,7 @@
int restore,
int power_off)
{
- if (ah->is_pciexpress != true)
- return;
-
- /* Do not touch SerDes registers */
- if (ah->config.pcie_powersave_enable == 2)
+ if (ah->is_pciexpress != true || ah->aspm_enabled != true)
return;
/* Nothing to do on restore for 11N */
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
index 443090d..efdbe98 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -848,7 +848,7 @@
#define AR_PHY_TPC_11_B1 (AR_SM1_BASE + 0x220)
#define AR_PHY_PDADC_TAB_1 (AR_SM1_BASE + 0x240)
#define AR_PHY_TX_IQCAL_STATUS_B1 (AR_SM1_BASE + 0x48c)
-#define AR_PHY_TX_IQCAL_CORR_COEFF_B1(_i) (AR_SM_BASE + 0x450 + ((_i) << 2))
+#define AR_PHY_TX_IQCAL_CORR_COEFF_B1(_i) (AR_SM1_BASE + 0x450 + ((_i) << 2))
/*
* Channel 2 Register Map
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 82fb6ce..87b6109 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -299,6 +299,14 @@
REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
}
+static void ath9k_hw_aspm_init(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ if (common->bus_ops->aspm_init)
+ common->bus_ops->aspm_init(common);
+}
+
/* This should work for all families including legacy */
static bool ath9k_hw_chip_test(struct ath_hw *ah)
{
@@ -359,7 +367,6 @@
ah->config.additional_swba_backoff = 0;
ah->config.ack_6mb = 0x0;
ah->config.cwm_ignore_extcca = 0;
- ah->config.pcie_powersave_enable = 0;
ah->config.pcie_clock_req = 0;
ah->config.pcie_waen = 0;
ah->config.analog_shiftreg = 1;
@@ -588,7 +595,7 @@
if (ah->is_pciexpress)
- ath9k_hw_configpcipowersave(ah, 0, 0);
+ ath9k_hw_aspm_init(ah);
else
ath9k_hw_disablepcie(ah);
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 4b157c5..939cc9d 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -215,7 +215,6 @@
int additional_swba_backoff;
int ack_6mb;
u32 cwm_ignore_extcca;
- u8 pcie_powersave_enable;
bool pcieSerDesWrite;
u8 pcie_clock_req;
u32 pcie_waen;
@@ -671,6 +670,7 @@
bool sw_mgmt_crypto;
bool is_pciexpress;
+ bool aspm_enabled;
bool is_monitoring;
bool need_an_top2_fixup;
u16 tx_trig_level;
@@ -870,6 +870,7 @@
bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
void (*bt_coex_prep)(struct ath_common *common);
void (*extn_synch_en)(struct ath_common *common);
+ void (*aspm_init)(struct ath_common *common);
};
static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 45c585a..5a9fd21 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -665,8 +665,10 @@
static void ath9k_init_txpower_limits(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath9k_channel *curchan = ah->curchan;
+ ah->txchainmask = common->tx_chainmask;
if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
ath9k_init_band_txpower(sc, IEEE80211_BAND_2GHZ);
if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 2ca351f..5362306 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -2260,7 +2260,11 @@
mutex_lock(&sc->mutex);
ah->coverage_class = coverage_class;
+
+ ath9k_ps_wakeup(sc);
ath9k_hw_init_global_settings(ah);
+ ath9k_ps_restore(sc);
+
mutex_unlock(&sc->mutex);
}
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index 3bad0b2..be4ea13 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -16,6 +16,7 @@
#include <linux/nl80211.h>
#include <linux/pci.h>
+#include <linux/pci-aspm.h>
#include <linux/ath9k_platform.h>
#include "ath9k.h"
@@ -115,12 +116,38 @@
pci_write_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, lnkctl);
}
+static void ath_pci_aspm_init(struct ath_common *common)
+{
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
+ struct ath_hw *ah = sc->sc_ah;
+ struct pci_dev *pdev = to_pci_dev(sc->dev);
+ struct pci_dev *parent;
+ int pos;
+ u8 aspm;
+
+ if (!pci_is_pcie(pdev))
+ return;
+
+ parent = pdev->bus->self;
+ if (WARN_ON(!parent))
+ return;
+
+ pos = pci_pcie_cap(parent);
+ pci_read_config_byte(parent, pos + PCI_EXP_LNKCTL, &aspm);
+ if (aspm & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1)) {
+ ah->aspm_enabled = true;
+ /* Initialize PCIe PM and SERDES registers. */
+ ath9k_hw_configpcipowersave(ah, 0, 0);
+ }
+}
+
static const struct ath_bus_ops ath_pci_bus_ops = {
.ath_bus_type = ATH_PCI,
.read_cachesize = ath_pci_read_cachesize,
.eeprom_read = ath_pci_eeprom_read,
.bt_coex_prep = ath_pci_bt_coex_prep,
.extn_synch_en = ath_pci_extn_synch_enable,
+ .aspm_init = ath_pci_aspm_init,
};
static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index 54d093c..b54966c 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -1066,8 +1066,10 @@
* the high througput speed in 802.11n networks.
*/
- if (!is_main_vif(ar, vif))
+ if (!is_main_vif(ar, vif)) {
+ mutex_lock(&ar->mutex);
goto err_softw;
+ }
/*
* While the hardware supports *catch-all* key, for offloading
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index eb41596..b1fe4fe 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -1571,7 +1571,8 @@
u32 cmd, beacon0_valid, beacon1_valid;
if (!b43_is_mode(wl, NL80211_IFTYPE_AP) &&
- !b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT))
+ !b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT) &&
+ !b43_is_mode(wl, NL80211_IFTYPE_ADHOC))
return;
/* This is the bottom half of the asynchronous beacon update. */
diff --git a/drivers/net/wireless/bcm4329/dhd.h b/drivers/net/wireless/bcm4329/dhd.h
index 95b334f..0b2e9c2 100644
--- a/drivers/net/wireless/bcm4329/dhd.h
+++ b/drivers/net/wireless/bcm4329/dhd.h
@@ -144,7 +144,7 @@
ulong rx_readahead_cnt; /* Number of packets where header read-ahead was used. */
ulong tx_realloc; /* Number of tx packets we had to realloc for headroom */
- ulong fc_packets; /* Number of flow control pkts recvd */
+ ulong fc_packets; /* Number of flow control pkts recvd */
/* Last error return */
int bcmerror;
@@ -156,6 +156,7 @@
/* Suspend disable flag and "in suspend" flag */
int suspend_disable_flag; /* "1" to disable all extra powersaving during suspend */
int in_suspend; /* flag set to 1 when early suspend called */
+ int hang_was_sent; /* flag that message was send at least once */
#ifdef PNO_SUPPORT
int pno_enable; /* pno status : "1" is pno enable */
#endif /* PNO_SUPPORT */
diff --git a/drivers/net/wireless/bcm4329/dhd_cdc.c b/drivers/net/wireless/bcm4329/dhd_cdc.c
index 61f6a6f..4bec0b6 100644
--- a/drivers/net/wireless/bcm4329/dhd_cdc.c
+++ b/drivers/net/wireless/bcm4329/dhd_cdc.c
@@ -150,7 +150,8 @@
memcpy(prot->buf, buf, len);
if ((ret = dhdcdc_msg(dhd)) < 0) {
- DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret));
+ if (!dhd->hang_was_sent)
+ DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret));
goto done;
}
@@ -205,6 +206,18 @@
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len));
+ if (dhd->busstate == DHD_BUS_DOWN) {
+ DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
+ return -EIO;
+ }
+
+ /* don't talk to the dongle if fw is about to be reloaded */
+ if (dhd->hang_was_sent) {
+ DHD_ERROR(("%s: HANG was sent up earlier. Not talking to the chip\n",
+ __FUNCTION__));
+ return -EIO;
+ }
+
memset(msg, 0, sizeof(cdc_ioctl_t));
msg->cmd = htol32(cmd);
@@ -251,7 +264,7 @@
dhd_prot_t *prot = dhd->prot;
int ret = -1;
- if (dhd->busstate == DHD_BUS_DOWN) {
+ if ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent) {
DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
return ret;
}
diff --git a/drivers/net/wireless/bcm4329/dhd_linux.c b/drivers/net/wireless/bcm4329/dhd_linux.c
index 5c1384b..5f5b418 100644
--- a/drivers/net/wireless/bcm4329/dhd_linux.c
+++ b/drivers/net/wireless/bcm4329/dhd_linux.c
@@ -319,7 +319,6 @@
int wl_count;
int wl_packet;
- int hang_was_sent; /* flag that message was send at least once */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
struct mutex wl_start_lock; /* mutex when START called to prevent any other Linux calls */
#endif
@@ -1520,7 +1519,8 @@
dhd_os_wake_unlock(&dhd->pub);
}
} else {
- dhd_bus_stop(dhd->pub.bus, TRUE);
+ if (dhd->pub.up)
+ dhd_bus_stop(dhd->pub.bus, TRUE);
dhd_os_wake_unlock(&dhd->pub);
}
}
@@ -1778,6 +1778,14 @@
dhd_os_wake_lock(&dhd->pub);
+ /* send to dongle only if we are not waiting for reload already */
+ if (dhd->pub.hang_was_sent) {
+ DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__));
+ dhd_os_wake_lock_timeout_enable(&dhd->pub);
+ dhd_os_wake_unlock(&dhd->pub);
+ return OSL_ERROR(BCME_DONGLE_DOWN);
+ }
+
ifidx = dhd_net2idx(dhd, net);
DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd));
@@ -1921,7 +1929,7 @@
#else
DHD_ERROR(("BYPASS %s:due to BRCM compilation : under investigation ...\n", __FUNCTION__));
#endif /* !defined(IGNORE_ETH0_DOWN) */
-
+ dhd->pub.hang_was_sent = 0;
OLD_MOD_DEC_USE_COUNT;
return 0;
}
@@ -3187,8 +3195,8 @@
int ret = 0;
if (dhd) {
- if (!dhd->hang_was_sent) {
- dhd->hang_was_sent = 1;
+ if (!dhd->pub.hang_was_sent) {
+ dhd->pub.hang_was_sent = 1;
ret = wl_iw_send_priv_event(dev, "HANG");
}
}
diff --git a/drivers/net/wireless/bcm4329/dhd_sdio.c b/drivers/net/wireless/bcm4329/dhd_sdio.c
index 1380dd3..e9093e8 100644
--- a/drivers/net/wireless/bcm4329/dhd_sdio.c
+++ b/drivers/net/wireless/bcm4329/dhd_sdio.c
@@ -1281,7 +1281,8 @@
DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
ret = 0;
} else {
- DHD_INFO(("%s: ctrl_frame_stat == TRUE\n", __FUNCTION__));
+ if (!bus->dhd->hang_was_sent)
+ DHD_ERROR(("%s: ctrl_frame_stat == TRUE\n", __FUNCTION__));
ret = -1;
}
}
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh.c b/drivers/net/wireless/bcmdhd/bcmsdh.c
index fc68b64..918c8e6 100644
--- a/drivers/net/wireless/bcmdhd/bcmsdh.c
+++ b/drivers/net/wireless/bcmdhd/bcmsdh.c
@@ -22,8 +22,13 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmsdh.c,v 1.57.6.4 2010-12-23 01:13:15 Exp $
+ * $Id: bcmsdh.c 275784 2011-08-04 22:41:49Z $
*/
+
+/**
+ * @file bcmsdh.c
+ */
+
/* ****************** BCMSDH Interface Functions *************************** */
#include <typedefs.h>
@@ -36,14 +41,16 @@
#include <bcmsdh.h> /* BRCM API for SDIO clients (such as wl, dhd) */
#include <bcmsdbus.h> /* common SDIO/controller interface */
-#include <sbsdio.h> /* BRCM sdio device core */
+#include <sbsdio.h> /* SDIO device core hardware definitions. */
-#include <sdio.h> /* sdio spec */
+#include <sdio.h> /* SDIO Device and Protocol Specs */
#define SDIOH_API_ACCESS_RETRY_LIMIT 2
const uint bcmsdh_msglevel = BCMSDH_ERROR_VAL;
-
+/**
+ * BCMSDH API context
+ */
struct bcmsdh_info
{
bool init_success; /* underlying driver successfully attached */
@@ -67,6 +74,15 @@
}
#endif
+/* Attach BCMSDH layer to SDIO Host Controller Driver
+ *
+ * @param osh OSL Handle.
+ * @param cfghdl Configuration Handle.
+ * @param regsva Virtual address of controller registers.
+ * @param irq Interrupt number of SDIO controller.
+ *
+ * @return bcmsdh_info_t Handle to BCMSDH context.
+ */
bcmsdh_info_t *
bcmsdh_attach(osl_t *osh, void *cfghdl, void **regsva, uint irq)
{
@@ -201,6 +217,14 @@
return BCME_UNSUPPORTED;
}
+/**
+ * Read from SDIO Configuration Space
+ * @param sdh SDIO Host context.
+ * @param func_num Function number to read from.
+ * @param addr Address to read from.
+ * @param err Error return.
+ * @return value read from SDIO configuration space.
+ */
uint8
bcmsdh_cfg_read(void *sdh, uint fnc_num, uint32 addr, int *err)
{
@@ -349,20 +373,30 @@
}
-static int
-bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address)
+int
+bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address, bool force_set)
{
int err = 0;
+ uint bar0 = address & ~SBSDIO_SB_OFT_ADDR_MASK;
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
- bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
- (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
- if (!err)
- bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
- (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
- if (!err)
- bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
- (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err);
+ if (bar0 != bcmsdh->sbwad || force_set) {
+ bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
+ (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
+ if (!err)
+ bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
+ (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
+ if (!err)
+ bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
+ (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err);
+
+ if (!err)
+ bcmsdh->sbwad = bar0;
+ else
+ /* invalidate cached window var */
+ bcmsdh->sbwad = 0;
+
+ }
return err;
}
@@ -373,7 +407,6 @@
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
SDIOH_API_RC status;
uint32 word = 0;
- uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, ", __FUNCTION__, addr));
@@ -382,12 +415,8 @@
ASSERT(bcmsdh->init_success);
- if (bar0 != bcmsdh->sbwad) {
- if (bcmsdhsdio_set_sbaddr_window(bcmsdh, bar0))
- return 0xFFFFFFFF;
-
- bcmsdh->sbwad = bar0;
- }
+ if (bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))
+ return 0xFFFFFFFF;
addr &= SBSDIO_SB_OFT_ADDR_MASK;
if (size == 4)
@@ -425,7 +454,6 @@
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
SDIOH_API_RC status;
- uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
int err = 0;
BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, uint%ddata = 0x%x\n",
@@ -436,12 +464,8 @@
ASSERT(bcmsdh->init_success);
- if (bar0 != bcmsdh->sbwad) {
- if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, bar0)))
- return err;
-
- bcmsdh->sbwad = bar0;
- }
+ if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE)))
+ return err;
addr &= SBSDIO_SB_OFT_ADDR_MASK;
if (size == 4)
@@ -467,13 +491,12 @@
int
bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags,
uint8 *buf, uint nbytes, void *pkt,
- bcmsdh_cmplt_fn_t complete, void *handle)
+ bcmsdh_cmplt_fn_t complete_fn, void *handle)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
SDIOH_API_RC status;
uint incr_fix;
uint width;
- uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
int err = 0;
ASSERT(bcmsdh);
@@ -487,12 +510,8 @@
if (flags & SDIO_REQ_ASYNC)
return BCME_UNSUPPORTED;
- if (bar0 != bcmsdh->sbwad) {
- if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, bar0)))
- return err;
-
- bcmsdh->sbwad = bar0;
- }
+ if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE)))
+ return err;
addr &= SBSDIO_SB_OFT_ADDR_MASK;
@@ -510,13 +529,12 @@
int
bcmsdh_send_buf(void *sdh, uint32 addr, uint fn, uint flags,
uint8 *buf, uint nbytes, void *pkt,
- bcmsdh_cmplt_fn_t complete, void *handle)
+ bcmsdh_cmplt_fn_t complete_fn, void *handle)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
SDIOH_API_RC status;
uint incr_fix;
uint width;
- uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
int err = 0;
ASSERT(bcmsdh);
@@ -530,12 +548,8 @@
if (flags & SDIO_REQ_ASYNC)
return BCME_UNSUPPORTED;
- if (bar0 != bcmsdh->sbwad) {
- if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, bar0)))
- return err;
-
- bcmsdh->sbwad = bar0;
- }
+ if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE)))
+ return err;
addr &= SBSDIO_SB_OFT_ADDR_MASK;
@@ -660,3 +674,17 @@
{
return;
}
+
+
+int
+bcmsdh_sleep(void *sdh, bool enab)
+{
+#ifdef SDIOH_SLEEP_ENABLED
+ bcmsdh_info_t *p = (bcmsdh_info_t *)sdh;
+ sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh);
+
+ return sdioh_sleep(sd, enab);
+#else
+ return BCME_UNSUPPORTED;
+#endif
+}
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c
index a4dc6ff..04c43a3 100644
--- a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c
+++ b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c
@@ -611,6 +611,13 @@
return IRQ_HANDLED;
}
+void *bcmsdh_get_drvdata(void)
+{
+ if (!sdhcinfo)
+ return NULL;
+ return dev_get_drvdata(sdhcinfo->dev);
+}
+
int bcmsdh_register_oob_intr(void * dhdp)
{
int error = 0;
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
index 8c328b8..70bacbd3 100644
--- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
+++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmsdh_sdmmc.c,v 1.14.64.3 2010-12-23 01:13:15 Exp $
+ * $Id: bcmsdh_sdmmc.c 282820 2011-09-09 15:40:35Z $
*/
#include <typedefs.h>
@@ -30,7 +30,7 @@
#include <bcmutils.h>
#include <osl.h>
#include <sdio.h> /* SDIO Device and Protocol Specs */
-#include <sdioh.h> /* SDIO Host Controller Specification */
+#include <sdioh.h> /* Standard SDIO Host Controller Specification */
#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
#include <sdiovar.h> /* ioctl/iovars */
@@ -198,9 +198,14 @@
sdio_release_host(gInstance->func[2]);
/* Disable Function 1 */
- sdio_claim_host(gInstance->func[1]);
- sdio_disable_func(gInstance->func[1]);
- sdio_release_host(gInstance->func[1]);
+ if (gInstance->func[1]) {
+ sdio_claim_host(gInstance->func[1]);
+ sdio_disable_func(gInstance->func[1]);
+ sdio_release_host(gInstance->func[1]);
+ }
+
+ gInstance->func[1] = NULL;
+ gInstance->func[2] = NULL;
/* deregister irq */
sdioh_sdmmc_osfree(sd);
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c
index c73e04c..726b639 100644
--- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c
+++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c
@@ -26,7 +26,7 @@
#include <typedefs.h>
#include <bcmutils.h>
-#include <sdio.h> /* SDIO Specs */
+#include <sdio.h> /* SDIO Device and Protocol Specs */
#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
#include <sdiovar.h> /* to get msglevel bit values */
@@ -66,6 +66,9 @@
extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd);
extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd);
+extern int dhd_os_check_wakelock(void *dhdp);
+extern int dhd_os_check_if_up(void *dhdp);
+extern void *bcmsdh_get_drvdata(void);
int sdio_function_init(void);
void sdio_function_cleanup(void);
@@ -87,6 +90,8 @@
extern int bcmsdh_probe(struct device *dev);
extern int bcmsdh_remove(struct device *dev);
+extern volatile bool dhd_mmc_suspend;
+
static int bcmsdh_sdmmc_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
@@ -133,6 +138,11 @@
if (func->num == 2) {
sd_trace(("F2 found, calling bcmsdh_remove...\n"));
bcmsdh_remove(&func->dev);
+ } else if (func->num == 1) {
+ sdio_claim_host(func);
+ sdio_disable_func(func);
+ sdio_release_host(func);
+ gInstance->func[1] = NULL;
}
}
@@ -149,12 +159,56 @@
MODULE_DEVICE_TABLE(sdio, bcmsdh_sdmmc_ids);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM)
+static int bcmsdh_sdmmc_suspend(struct device *pdev)
+{
+ struct sdio_func *func = dev_to_sdio_func(pdev);
+
+ if (func->num != 2)
+ return 0;
+ if (dhd_os_check_wakelock(bcmsdh_get_drvdata()))
+ return -EBUSY;
+#if defined(OOB_INTR_ONLY)
+ bcmsdh_oob_intr_set(0);
+#endif
+ dhd_mmc_suspend = TRUE;
+ smp_mb();
+
+ return 0;
+}
+
+static int bcmsdh_sdmmc_resume(struct device *pdev)
+{
+ struct sdio_func *func = dev_to_sdio_func(pdev);
+
+ if (func->num != 2)
+ return 0;
+ dhd_mmc_suspend = FALSE;
+#if defined(OOB_INTR_ONLY)
+ if (dhd_os_check_if_up(bcmsdh_get_drvdata()))
+ bcmsdh_oob_intr_set(1);
+#endif
+ smp_mb();
+ return 0;
+}
+
+static const struct dev_pm_ops bcmsdh_sdmmc_pm_ops = {
+ .suspend = bcmsdh_sdmmc_suspend,
+ .resume = bcmsdh_sdmmc_resume,
+};
+#endif
+
static struct sdio_driver bcmsdh_sdmmc_driver = {
.probe = bcmsdh_sdmmc_probe,
.remove = bcmsdh_sdmmc_remove,
.name = "bcmsdh_sdmmc",
.id_table = bcmsdh_sdmmc_ids,
- };
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM)
+ .drv = {
+ .pm = &bcmsdh_sdmmc_pm_ops,
+ },
+#endif
+};
struct sdos_info {
sdioh_info_t *sd;
@@ -259,7 +313,6 @@
error = sdio_register_driver(&bcmsdh_sdmmc_driver);
-
return error;
}
diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h
index 281e047..c87f6cf 100644
--- a/drivers/net/wireless/bcmdhd/dhd.h
+++ b/drivers/net/wireless/bcmdhd/dhd.h
@@ -24,7 +24,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhd.h,v 1.60.4.17 2011-01-09 08:11:56 Exp $
+ * $Id: dhd.h 290844 2011-10-20 08:54:39Z $
*/
/****************
@@ -52,6 +52,9 @@
#include <linux/wakelock.h>
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */
/* The kernel threading is sdio-specific */
+struct task_struct;
+struct sched_param;
+int setScheduler(struct task_struct *p, int policy, struct sched_param *param);
#define ALL_INTERFACES 0xff
@@ -77,6 +80,9 @@
#define WFD_MASK 0x0004
#define SOFTAP_FW_MASK 0x0008
+/* max sequential rxcntl timeouts to set HANG event */
+#define MAX_CNTL_TIMEOUT 2
+
enum dhd_bus_wake_state {
WAKE_LOCK_OFF,
WAKE_LOCK_PRIV,
@@ -93,6 +99,7 @@
WAKE_LOCK_SOFTAP_THREAD,
WAKE_LOCK_MAX
};
+
enum dhd_prealloc_index {
DHD_PREALLOC_PROT = 0,
DHD_PREALLOC_RXBUF,
@@ -100,6 +107,15 @@
DHD_PREALLOC_OSL_BUF
};
+typedef enum {
+ DHD_IF_NONE = 0,
+ DHD_IF_ADD,
+ DHD_IF_DEL,
+ DHD_IF_CHANGE,
+ DHD_IF_DELETING
+} dhd_if_state_t;
+
+
#if defined(DHD_USE_STATIC_BUF)
uint8* dhd_os_prealloc(void *osh, int section, uint size);
@@ -114,6 +130,11 @@
#endif /* defined(DHD_USE_STATIC_BUF) */
+/* Packet alignment for most efficient SDIO (can change based on platform) */
+#ifndef DHD_SDALIGN
+#define DHD_SDALIGN 32
+#endif
+
/* Common structure for module and instance linkage */
typedef struct dhd_pub {
/* Linkage ponters */
@@ -195,7 +216,9 @@
void* wlfc_state;
#endif
bool dongle_isolation;
-
+ int hang_was_sent;
+ int rxcnt_timeout; /* counter rxcnt timeout to send HANG */
+ int txcnt_timeout; /* counter txcnt timeout to send HANG */
#ifdef WLMEDIA_HTSF
uint8 htsfdlystat_sz; /* Size of delay stats, max 255B */
#endif
@@ -212,11 +235,12 @@
#define DHD_PM_RESUME_WAIT_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a);
#define _DHD_PM_RESUME_WAIT(a, b) do {\
int retry = 0; \
- smp_mb(); \
+ SMP_RD_BARRIER_DEPENDS(); \
while (dhd_mmc_suspend && retry++ != b) { \
- wait_event_interruptible_timeout(a, FALSE, HZ/100); \
+ SMP_RD_BARRIER_DEPENDS(); \
+ wait_event_interruptible_timeout(a, !dhd_mmc_suspend, HZ/100); \
} \
- } while (0)
+ } while (0)
#define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 200)
#define DHD_PM_RESUME_WAIT_FOREVER(a) _DHD_PM_RESUME_WAIT(a, ~0)
#define DHD_PM_RESUME_RETURN_ERROR(a) do { if (dhd_mmc_suspend) return a; } while (0)
@@ -262,7 +286,7 @@
extern int dhd_os_wake_lock(dhd_pub_t *pub);
extern int dhd_os_wake_unlock(dhd_pub_t *pub);
extern int dhd_os_wake_lock_timeout(dhd_pub_t *pub);
-extern int dhd_os_wake_lock_timeout_enable(dhd_pub_t *pub);
+extern int dhd_os_wake_lock_timeout_enable(dhd_pub_t *pub, int val);
inline static void MUTEX_LOCK_SOFTAP_SET_INIT(dhd_pub_t * dhdp)
{
@@ -288,8 +312,10 @@
#define DHD_OS_WAKE_LOCK(pub) dhd_os_wake_lock(pub)
#define DHD_OS_WAKE_UNLOCK(pub) dhd_os_wake_unlock(pub)
#define DHD_OS_WAKE_LOCK_TIMEOUT(pub) dhd_os_wake_lock_timeout(pub)
-#define DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(pub) dhd_os_wake_lock_timeout_enable(pub)
+#define DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(pub, val) dhd_os_wake_lock_timeout_enable(pub, val)
+#define DHD_PACKET_TIMEOUT 1
+#define DHD_EVENT_TIMEOUT 2
/* interface operations (register, remove) should be atomic, use this lock to prevent race
* condition among wifi on/off and interface operation functions
@@ -381,7 +407,7 @@
extern void dhd_os_sdunlock_rxq(dhd_pub_t * pub);
extern void dhd_os_sdlock_sndup_rxq(dhd_pub_t * pub);
extern void dhd_customer_gpio_wlan_ctrl(int onoff);
-extern int dhd_custom_get_mac_address(unsigned char *buf);
+extern int dhd_custom_get_mac_address(unsigned char *buf);
extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub);
extern void dhd_os_sdlock_eventq(dhd_pub_t * pub);
extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub);
@@ -396,6 +422,8 @@
extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled);
extern int dhd_dev_get_pno_status(struct net_device *dev);
extern int dhd_get_dtim_skip(dhd_pub_t *dhd);
+extern bool dhd_check_ap_wfd_mode_set(dhd_pub_t *dhd);
+extern bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret);
#define DHD_UNICAST_FILTER_NUM 0
#define DHD_BROADCAST_FILTER_NUM 1
@@ -413,12 +441,6 @@
extern void dhd_os_sdtxlock(dhd_pub_t * pub);
extern void dhd_os_sdtxunlock(dhd_pub_t * pub);
-#if defined(DHDTHREAD)
-struct task_struct;
-struct sched_param;
-int setScheduler(struct task_struct *p, int policy, struct sched_param *param);
-#endif /* DHDTHREAD && DHD_GPL */
-
typedef struct {
uint32 limit; /* Expiration time (usec) */
uint32 increment; /* Current expiration increment (usec) */
@@ -466,6 +488,16 @@
extern int dhd_bus_start(dhd_pub_t *dhdp);
extern int dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size);
extern void dhd_print_buf(void *pbuf, int len, int bytes_per_line);
+extern bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf);
+
+#if defined(KEEP_ALIVE)
+extern int dhd_keep_alive_onoff(dhd_pub_t *dhd);
+#endif /* KEEP_ALIVE */
+
+#ifdef ARP_OFFLOAD_SUPPORT
+extern void dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode);
+extern void dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable);
+#endif /* ARP_OFFLOAD_SUPPORT */
typedef enum cust_gpio_modes {
@@ -697,4 +729,5 @@
int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen);
void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr);
#endif /* ARP_OFFLOAD_SUPPORT */
+
#endif /* _dhd_h_ */
diff --git a/drivers/net/wireless/bcmdhd/dhd_cdc.c b/drivers/net/wireless/bcmdhd/dhd_cdc.c
index 0f9893a..3a4de96 100644
--- a/drivers/net/wireless/bcmdhd/dhd_cdc.c
+++ b/drivers/net/wireless/bcmdhd/dhd_cdc.c
@@ -47,23 +47,28 @@
#include <dhd_wlfc.h>
#endif
-/* Packet alignment for most efficient SDIO (can change based on platform) */
-#ifndef DHD_SDALIGN
-#define DHD_SDALIGN 32
-#endif
-#if !ISPOWEROF2(DHD_SDALIGN)
-#error DHD_SDALIGN is not a power of 2!
-#endif
#define RETRIES 2 /* # of retries to retrieve matching ioctl response */
#define BUS_HEADER_LEN (16+DHD_SDALIGN) /* Must be at least SDPCM_RESERVE
* defined in dhd_sdio.c (amount of header tha might be added)
* plus any space that might be needed for alignment padding.
*/
-#define ROUND_UP_MARGIN 2048 /* Biggest SDIO block size possible for
+#define ROUND_UP_MARGIN 2048 /* Biggest SDIO block size possible for
* round off at the end of buffer
*/
+#define BUS_RETRIES 1 /* # of retries before aborting a bus tx operation */
+
+#ifdef PROP_TXSTATUS
+typedef struct dhd_wlfc_commit_info {
+ uint8 needs_hdr;
+ uint8 ac_fifo_credit_spent;
+ ewlfc_packet_state_t pkt_type;
+ wlfc_mac_descriptor_t* mac_entry;
+ void* p;
+} dhd_wlfc_commit_info_t;
+#endif /* PROP_TXSTATUS */
+
typedef struct dhd_prot {
uint16 reqid;
uint8 pending;
@@ -159,7 +164,8 @@
memcpy(prot->buf, buf, len);
if ((ret = dhdcdc_msg(dhd)) < 0) {
- DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret));
+ if (!dhd->hang_was_sent)
+ DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret));
goto done;
}
@@ -214,6 +220,18 @@
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len));
+ if (dhd->busstate == DHD_BUS_DOWN) {
+ DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
+ return -EIO;
+ }
+
+ /* don't talk to the dongle if fw is about to be reloaded */
+ if (dhd->hang_was_sent) {
+ DHD_ERROR(("%s: HANG was sent up earlier. Not talking to the chip\n",
+ __FUNCTION__));
+ return -EIO;
+ }
+
memset(msg, 0, sizeof(cdc_ioctl_t));
msg->cmd = htol32(cmd);
@@ -266,12 +284,11 @@
int ret = -1;
uint8 action;
- if (dhd->busstate == DHD_BUS_DOWN) {
+ if ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent) {
DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
goto done;
}
-
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
ASSERT(len <= WLC_IOCTL_MAXLEN);
@@ -587,7 +604,7 @@
return;
}
-/* Create a place to store all packet pointers submitted to the firmware until
+/* Create a place to store all packet pointers submitted to the firmware until
a status comes back, suppress or otherwise.
hang-er: noun, a contrivance on which things are hung, as a hook.
@@ -636,8 +653,8 @@
if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE)
return (uint16)i;
}
+ h->failed_slotfind++;
}
- h->failed_slotfind++;
return WLFC_HANGER_MAXITEMS;
}
@@ -1294,6 +1311,31 @@
}
int
+_dhd_wlfc_borrow_credit(athost_wl_status_info_t* ctx, uint8 available_credit_map, int borrower_ac)
+{
+ int lender_ac;
+ int rc = BCME_ERROR;
+
+ if (ctx == NULL || available_credit_map == 0) {
+ WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__));
+ return BCME_BADARG;
+ }
+
+ /* Borrow from lowest priority available AC (including BC/MC credits) */
+ for (lender_ac = 0; lender_ac <= AC_COUNT; lender_ac++) {
+ if ((available_credit_map && (1 << lender_ac)) &&
+ (ctx->FIFO_credit[lender_ac] > 0)) {
+ ctx->credits_borrowed[borrower_ac][lender_ac]++;
+ ctx->FIFO_credit[lender_ac]--;
+ rc = BCME_OK;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+int
dhd_wlfc_interface_entry_update(void* state,
ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea)
{
@@ -1320,6 +1362,7 @@
/* credit for bc/mc packets */
ctx->FIFO_credit[4] = credits[4];
/* credit for ATIM FIFO is not used yet. */
+ ctx->FIFO_credit[5] = 0;
return BCME_OK;
}
@@ -1352,17 +1395,69 @@
}
int
+_dhd_wlfc_handle_packet_commit(athost_wl_status_info_t* ctx, int ac,
+ dhd_wlfc_commit_info_t *commit_info, f_commitpkt_t fcommit, void* commit_ctx)
+{
+ uint32 hslot;
+ int rc;
+
+ /*
+ if ac_fifo_credit_spent = 0
+
+ This packet will not count against the FIFO credit.
+ To ensure the txstatus corresponding to this packet
+ does not provide an implied credit (default behavior)
+ mark the packet accordingly.
+
+ if ac_fifo_credit_spent = 1
+
+ This is a normal packet and it counts against the FIFO
+ credit count.
+ */
+ DHD_PKTTAG_SETCREDITCHECK(PKTTAG(commit_info->p), commit_info->ac_fifo_credit_spent);
+ rc = _dhd_wlfc_pretx_pktprocess(ctx, commit_info->mac_entry, commit_info->p,
+ commit_info->needs_hdr, &hslot);
+
+ if (rc == BCME_OK)
+ rc = fcommit(commit_ctx, commit_info->p);
+ else
+ ctx->stats.generic_error++;
+
+ if (rc == BCME_OK) {
+ ctx->stats.pkt2bus++;
+ if (commit_info->ac_fifo_credit_spent) {
+ ctx->stats.sendq_pkts[ac]++;
+ WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac);
+ }
+ }
+ else {
+ /*
+ bus commit has failed, rollback.
+ - remove wl-header for a delayed packet
+ - save wl-header header for suppressed packets
+ */
+ rc = _dhd_wlfc_rollback_packet_toq(ctx, commit_info->p,
+ (commit_info->pkt_type), hslot);
+ if (rc != BCME_OK)
+ ctx->stats.rollback_failed++;
+
+ rc = BCME_ERROR;
+ }
+
+ return rc;
+}
+
+int
dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx)
{
int ac;
int credit;
- uint8 ac_fifo_credit_spent;
- uint8 needs_hdr;
- uint32 hslot;
- void* p;
int rc;
+ dhd_wlfc_commit_info_t commit_info;
athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state;
- wlfc_mac_descriptor_t* mac_entry;
+ int credit_count = 0;
+ int bus_retry_count = 0;
+ uint8 ac_available = 0; /* Bitmask for 4 ACs + BC/MC */
if ((state == NULL) ||
(fcommit == NULL)) {
@@ -1370,8 +1465,12 @@
return BCME_BADARG;
}
- /*
+ memset(&commit_info, 0, sizeof(commit_info));
+
+ /*
Commit packets for regular AC traffic. Higher priority first.
+ First, use up FIFO credits available to each AC. Based on distribution
+ and credits left, borrow from other ACs as applicable
-NOTE:
If the bus between the host and firmware is overwhelmed by the
@@ -1380,96 +1479,189 @@
have to employ weighted round-robin or ucode scheme to avoid
low priority packet starvation.
*/
+
for (ac = AC_COUNT; ac >= 0; ac--) {
+
+ int initial_credit_count = ctx->FIFO_credit[ac];
+
for (credit = 0; credit < ctx->FIFO_credit[ac];) {
- p = _dhd_wlfc_deque_delayedq(ctx, ac, &ac_fifo_credit_spent, &needs_hdr,
- &mac_entry);
- if (p == NULL)
+ commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac,
+ &(commit_info.ac_fifo_credit_spent),
+ &(commit_info.needs_hdr),
+ &(commit_info.mac_entry));
+
+ if (commit_info.p == NULL)
break;
- /*
- if ac_fifo_credit_spent = 0
- This packet will not count against the FIFO credit.
- To ensure the txstatus corresponding to this packet
- does not provide an implied credit (default behavior)
- mark the packet accordingly.
+ commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED :
+ eWLFC_PKTTYPE_SUPPRESSED;
- if ac_fifo_credit_spent = 1
+ rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info,
+ fcommit, commit_ctx);
- This is a normal packet and it counts against the FIFO
- credit count.
- */
- DHD_PKTTAG_SETCREDITCHECK(PKTTAG(p), ac_fifo_credit_spent);
- rc = _dhd_wlfc_pretx_pktprocess(ctx, mac_entry, p, needs_hdr, &hslot);
-
- if (rc == BCME_OK)
- rc = fcommit(commit_ctx, p);
- else
- ctx->stats.generic_error++;
-
+ /* Bus commits may fail (e.g. flow control); abort after retries */
if (rc == BCME_OK) {
- ctx->stats.pkt2bus++;
- if (ac_fifo_credit_spent) {
- ctx->stats.sendq_pkts[ac]++;
- WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac);
- /*
- 1 FIFO credit has been spent by sending this packet
- to the device.
- */
+ if (commit_info.ac_fifo_credit_spent) {
credit++;
}
}
else {
- /* bus commit has failed, rollback. */
- rc = _dhd_wlfc_rollback_packet_toq(ctx,
- p,
- /*
- - remove wl-header for a delayed packet
- - save wl-header header for suppressed packets
- */
- (needs_hdr ? eWLFC_PKTTYPE_DELAYED :
- eWLFC_PKTTYPE_SUPPRESSED),
- hslot);
- if (rc != BCME_OK)
- ctx->stats.rollback_failed++;
+ bus_retry_count++;
+ if (bus_retry_count >= BUS_RETRIES) {
+ DHD_ERROR(("dhd_wlfc_commit_packets(): bus error\n"));
+ ctx->FIFO_credit[ac] -= credit;
+ return rc;
+ }
}
}
+
ctx->FIFO_credit[ac] -= credit;
- /* packets from SENDQ are fresh and they'd need header */
- needs_hdr = 1;
+
+ /* packets from SENDQ are fresh and they'd need header and have no MAC entry */
+ commit_info.needs_hdr = 1;
+ commit_info.mac_entry = NULL;
+ commit_info.pkt_type = eWLFC_PKTTYPE_NEW;
+
for (credit = 0; credit < ctx->FIFO_credit[ac];) {
- p = _dhd_wlfc_deque_sendq(ctx, ac, &ac_fifo_credit_spent);
- if (p == NULL)
+ commit_info.p = _dhd_wlfc_deque_sendq(ctx, ac,
+ &(commit_info.ac_fifo_credit_spent));
+ if (commit_info.p == NULL)
break;
- DHD_PKTTAG_SETCREDITCHECK(PKTTAG(p), ac_fifo_credit_spent);
- rc = _dhd_wlfc_pretx_pktprocess(ctx, NULL, p, needs_hdr, &hslot);
- if (rc == BCME_OK)
- rc = fcommit(commit_ctx, p);
- else
- ctx->stats.generic_error++;
+ rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info,
+ fcommit, commit_ctx);
+ /* Bus commits may fail (e.g. flow control); abort after retries */
if (rc == BCME_OK) {
- ctx->stats.pkt2bus++;
- if (ac_fifo_credit_spent) {
- WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac);
- ctx->stats.sendq_pkts[ac]++;
+ if (commit_info.ac_fifo_credit_spent) {
credit++;
}
}
else {
- /* bus commit has failed, rollback. */
- rc = _dhd_wlfc_rollback_packet_toq(ctx,
- p,
- /* remove wl-header while rolling back */
- eWLFC_PKTTYPE_NEW,
- hslot);
- if (rc != BCME_OK)
- ctx->stats.rollback_failed++;
+ bus_retry_count++;
+ if (bus_retry_count >= BUS_RETRIES) {
+ DHD_ERROR(("dhd_wlfc_commit_packets(): bus error\n"));
+ ctx->FIFO_credit[ac] -= credit;
+ return rc;
+ }
}
}
+
ctx->FIFO_credit[ac] -= credit;
+
+ /* If no credits were used, the queue is idle and can be re-used
+ Note that resv credits cannot be borrowed
+ */
+ if (initial_credit_count == ctx->FIFO_credit[ac]) {
+ ac_available |= (1 << ac);
+ credit_count += ctx->FIFO_credit[ac];
+ }
}
+
+ /* We borrow only for AC_BE and only if no other traffic seen for DEFER_PERIOD
+
+ Note that (ac_available & WLFC_AC_BE_TRAFFIC_ONLY) is done to:
+ a) ignore BC/MC for deferring borrow
+ b) ignore AC_BE being available along with other ACs
+ (this should happen only for pure BC/MC traffic)
+
+ i.e. AC_VI, AC_VO, AC_BK all MUST be available (i.e. no traffic) and
+ we do not care if AC_BE and BC/MC are available or not
+ */
+ if ((ac_available & WLFC_AC_BE_TRAFFIC_ONLY) == WLFC_AC_BE_TRAFFIC_ONLY) {
+
+ if (ctx->allow_credit_borrow) {
+ ac = 1; /* Set ac to AC_BE and borrow credits */
+ }
+ else {
+ int delta;
+ int curr_t = OSL_SYSUPTIME();
+
+ if (curr_t > ctx->borrow_defer_timestamp)
+ delta = curr_t - ctx->borrow_defer_timestamp;
+ else
+ delta = 0xffffffff + curr_t - ctx->borrow_defer_timestamp;
+
+ if (delta >= WLFC_BORROW_DEFER_PERIOD_MS) {
+ /* Reset borrow but defer to next iteration (defensive borrowing) */
+ ctx->allow_credit_borrow = TRUE;
+ ctx->borrow_defer_timestamp = 0;
+ }
+ return BCME_OK;
+ }
+ }
+ else {
+ /* If we have multiple AC traffic, turn off borrowing, mark time and bail out */
+ ctx->allow_credit_borrow = FALSE;
+ ctx->borrow_defer_timestamp = OSL_SYSUPTIME();
+ return BCME_OK;
+ }
+
+ /* At this point, borrow all credits only for "ac" (which should be set above to AC_BE)
+ Generically use "ac" only in case we extend to all ACs in future
+ */
+ for (; (credit_count > 0);) {
+
+ commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac,
+ &(commit_info.ac_fifo_credit_spent),
+ &(commit_info.needs_hdr),
+ &(commit_info.mac_entry));
+ if (commit_info.p == NULL)
+ break;
+
+ commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED :
+ eWLFC_PKTTYPE_SUPPRESSED;
+
+ rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info,
+ fcommit, commit_ctx);
+
+ /* Bus commits may fail (e.g. flow control); abort after retries */
+ if (rc == BCME_OK) {
+ if (commit_info.ac_fifo_credit_spent) {
+ (void) _dhd_wlfc_borrow_credit(ctx, ac_available, ac);
+ credit_count--;
+ }
+ }
+ else {
+ bus_retry_count++;
+ if (bus_retry_count >= BUS_RETRIES) {
+ DHD_ERROR(("dhd_wlfc_commit_packets(): bus error\n"));
+ return rc;
+ }
+ }
+ }
+
+ /* packets from SENDQ are fresh and they'd need header and have no MAC entry */
+ commit_info.needs_hdr = 1;
+ commit_info.mac_entry = NULL;
+ commit_info.pkt_type = eWLFC_PKTTYPE_NEW;
+
+ for (; (credit_count > 0);) {
+
+ commit_info.p = _dhd_wlfc_deque_sendq(ctx, ac,
+ &(commit_info.ac_fifo_credit_spent));
+ if (commit_info.p == NULL)
+ break;
+
+ rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info,
+ fcommit, commit_ctx);
+
+ /* Bus commits may fail (e.g. flow control); abort after retries */
+ if (rc == BCME_OK) {
+ if (commit_info.ac_fifo_credit_spent) {
+ (void) _dhd_wlfc_borrow_credit(ctx, ac_available, ac);
+ credit_count--;
+ }
+ }
+ else {
+ bus_retry_count++;
+ if (bus_retry_count >= BUS_RETRIES) {
+ DHD_ERROR(("dhd_wlfc_commit_packets(): bus error\n"));
+ return rc;
+ }
+ }
+ }
+
return BCME_OK;
}
@@ -1496,6 +1688,7 @@
athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
dhd->wlfc_state;
void* p;
+ int fifo_id;
if (DHD_PKTTAG_SIGNALONLY(PKTTAG(txp))) {
#ifdef PROP_TXSTATUS_DEBUG
@@ -1513,11 +1706,29 @@
/* indicate failure and free the packet */
dhd_txcomplete(dhd, txp, FALSE);
- PKTFREE(wlfc->osh, txp, TRUE);
/* return the credit, if necessary */
- if (DHD_PKTTAG_CREDITCHECK(PKTTAG(txp)))
- wlfc->FIFO_credit[DHD_PKTTAG_FIFO(PKTTAG(txp))]++;
+ if (DHD_PKTTAG_CREDITCHECK(PKTTAG(txp))) {
+ int lender, credit_returned = 0; /* Note that borrower is fifo_id */
+
+ fifo_id = DHD_PKTTAG_FIFO(PKTTAG(txp));
+
+ /* Return credits to highest priority lender first */
+ for (lender = AC_COUNT; lender >= 0; lender--) {
+ if (wlfc->credits_borrowed[fifo_id][lender] > 0) {
+ wlfc->FIFO_credit[lender]++;
+ wlfc->credits_borrowed[fifo_id][lender]--;
+ credit_returned = 1;
+ break;
+ }
+ }
+
+ if (!credit_returned) {
+ wlfc->FIFO_credit[fifo_id]++;
+ }
+ }
+
+ PKTFREE(wlfc->osh, txp, TRUE);
}
return;
}
@@ -1600,7 +1811,22 @@
/* pick up the implicit credit from this packet */
if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) {
if (wlfc->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) {
- wlfc->FIFO_credit[fifo_id]++;
+
+ int lender, credit_returned = 0; /* Note that borrower is fifo_id */
+
+ /* Return credits to highest priority lender first */
+ for (lender = AC_COUNT; lender >= 0; lender--) {
+ if (wlfc->credits_borrowed[fifo_id][lender] > 0) {
+ wlfc->FIFO_credit[lender]++;
+ wlfc->credits_borrowed[fifo_id][lender]--;
+ credit_returned = 1;
+ break;
+ }
+ }
+
+ if (!credit_returned) {
+ wlfc->FIFO_credit[fifo_id]++;
+ }
}
}
else {
@@ -1651,8 +1877,33 @@
#endif
/* update FIFO credits */
if (wlfc->proptxstatus_mode == WLFC_FCMODE_EXPLICIT_CREDIT)
- wlfc->FIFO_credit[i] += credits[i];
+ {
+ int lender; /* Note that borrower is i */
+
+ /* Return credits to highest priority lender first */
+ for (lender = AC_COUNT; (lender >= 0) && (credits[i] > 0); lender--) {
+ if (wlfc->credits_borrowed[i][lender] > 0) {
+ if (credits[i] >= wlfc->credits_borrowed[i][lender]) {
+ credits[i] -= wlfc->credits_borrowed[i][lender];
+ wlfc->FIFO_credit[lender] +=
+ wlfc->credits_borrowed[i][lender];
+ wlfc->credits_borrowed[i][lender] = 0;
+ }
+ else {
+ wlfc->credits_borrowed[i][lender] -= credits[i];
+ wlfc->FIFO_credit[lender] += credits[i];
+ credits[i] = 0;
+ }
+ }
+ }
+
+ /* If we have more credits left over, these must belong to the AC */
+ if (credits[i] > 0) {
+ wlfc->FIFO_credit[i] += credits[i];
+ }
+ }
}
+
return BCME_OK;
}
@@ -1980,7 +2231,7 @@
wlfc->hostif_flow_state[i] = OFF;
}
- /*
+ /*
create the SENDQ containing
sub-queues for all AC precedences + 1 for bc/mc traffic
*/
@@ -1993,6 +2244,9 @@
wlfc->proptxstatus_mode = WLFC_FCMODE_EXPLICIT_CREDIT;
+ wlfc->allow_credit_borrow = TRUE;
+ wlfc->borrow_defer_timestamp = 0;
+
return BCME_OK;
}
@@ -2172,7 +2426,7 @@
dhd_wlfc_parse_header_info(dhd, pktbuf, (h->dataOffset << 2));
((athost_wl_status_info_t*)dhd->wlfc_state)->stats.dhd_hdrpulls++;
dhd_wlfc_commit_packets(dhd->wlfc_state, (f_commitpkt_t)dhd_bus_txdata,
- dhd->bus);
+ (void *)dhd->bus);
dhd_os_wlfc_unblock(dhd);
}
#endif /* PROP_TXSTATUS */
@@ -2239,7 +2493,6 @@
return;
}
-
int
dhd_prot_init(dhd_pub_t *dhd)
{
@@ -2248,7 +2501,6 @@
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
/* Get the device rev info */
memset(&revinfo, 0, sizeof(revinfo));
ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), FALSE, 0);
@@ -2260,7 +2512,7 @@
ret = dhd_wlfc_init(dhd);
#endif
-#ifndef WL_CFG80211
+#if !defined(WL_CFG80211)
ret = dhd_preinit_ioctls(dhd);
#endif /* WL_CFG80211 */
diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c
index f6bb8e5..a29c2fa 100644
--- a/drivers/net/wireless/bcmdhd/dhd_common.c
+++ b/drivers/net/wireless/bcmdhd/dhd_common.c
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhd_common.c,v 1.57.2.22 2011-02-01 18:38:37 Exp $
+ * $Id: dhd_common.c 290546 2011-10-19 01:55:21Z $
*/
#include <typedefs.h>
#include <osl.h>
@@ -88,21 +88,9 @@
void dhd_iscan_lock(void);
void dhd_iscan_unlock(void);
extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx);
-
bool ap_cfg_running = FALSE;
bool ap_fw_loaded = FALSE;
-#if defined(KEEP_ALIVE)
-int dhd_keep_alive_onoff(dhd_pub_t *dhd);
-#endif /* KEEP_ALIVE */
-
-/* Packet alignment for most efficient SDIO (can change based on platform) */
-#ifndef DHD_SDALIGN
-#define DHD_SDALIGN 32
-#endif
-#if !ISPOWEROF2(DHD_SDALIGN)
-#error DHD_SDALIGN is not a power of 2!
-#endif
#ifdef DHD_DEBUG
const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR "\nCompiled on "
@@ -113,8 +101,6 @@
void dhd_set_timer(void *bus, uint wdtick);
-
-
/* IOVar table */
enum {
IOV_VERSION = 1,
@@ -314,7 +300,8 @@
dhd_os_proto_block(dhd_pub);
ret = dhd_prot_ioctl(dhd_pub, ifindex, ioc, buf, len);
-
+ if (!ret)
+ dhd_os_check_hang(dhd_pub, ifindex, ret);
dhd_os_proto_unblock(dhd_pub);
return ret;
@@ -496,7 +483,7 @@
#endif /* PROP_TXSTATUS */
case IOV_GVAL(IOV_BUS_TYPE):
- /* The dhd application query the driver to check if its usb or sdio. */
+ /* The dhd application queries the driver to check if its usb or sdio. */
#ifdef BCMDHDUSB
int_val = BUS_TYPE_USB;
#endif
@@ -973,7 +960,7 @@
{
/* check whether packet is a BRCM event pkt */
bcm_event_t *pvt_data = (bcm_event_t *)pktdata;
- char *event_data;
+ uint8 *event_data;
uint32 type, status, reason, datalen;
uint16 flags;
int evlen;
@@ -1016,27 +1003,27 @@
case WLC_E_IF:
{
- dhd_if_event_t *ifevent = (dhd_if_event_t *)event_data;
+ dhd_if_event_t *ifevent = (dhd_if_event_t *)event_data;
#ifdef PROP_TXSTATUS
-{
- uint8* ea = pvt_data->eth.ether_dhost;
- WLFC_DBGMESG(("WLC_E_IF: idx:%d, action:%s, iftype:%s, "
- "[%02x:%02x:%02x:%02x:%02x:%02x]\n",
- ifevent->ifidx,
- ((ifevent->action == WLC_E_IF_ADD) ? "ADD":"DEL"),
- ((ifevent->is_AP == 0) ? "STA":"AP "),
- ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]));
- (void)ea;
+ {
+ uint8* ea = pvt_data->eth.ether_dhost;
+ WLFC_DBGMESG(("WLC_E_IF: idx:%d, action:%s, iftype:%s, "
+ "[%02x:%02x:%02x:%02x:%02x:%02x]\n",
+ ifevent->ifidx,
+ ((ifevent->action == WLC_E_IF_ADD) ? "ADD":"DEL"),
+ ((ifevent->is_AP == 0) ? "STA":"AP "),
+ ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]));
+ (void)ea;
- dhd_wlfc_interface_event(dhd_pub->info,
- ((ifevent->action == WLC_E_IF_ADD) ?
- eWLFC_MAC_ENTRY_ACTION_ADD : eWLFC_MAC_ENTRY_ACTION_DEL),
- ifevent->ifidx, ifevent->is_AP, ea);
+ dhd_wlfc_interface_event(dhd_pub->info,
+ ((ifevent->action == WLC_E_IF_ADD) ?
+ eWLFC_MAC_ENTRY_ACTION_ADD : eWLFC_MAC_ENTRY_ACTION_DEL),
+ ifevent->ifidx, ifevent->is_AP, ea);
- /* dhd already has created an interface by default, for 0 */
- if (ifevent->ifidx == 0)
- break;
-}
+ /* dhd already has created an interface by default, for 0 */
+ if (ifevent->ifidx == 0)
+ break;
+ }
#endif /* PROP_TXSTATUS */
#ifdef WL_CFG80211
@@ -1044,7 +1031,7 @@
DHD_ERROR(("%s: ifidx %d for %s action %d\n",
__FUNCTION__, ifevent->ifidx,
event->ifname, ifevent->action));
- if (ifevent->action == WLC_E_IF_ADD)
+ if (ifevent->action == WLC_E_IF_ADD)
wl_cfg80211_notify_ifchange();
return (BCME_OK);
}
@@ -1444,7 +1431,8 @@
__FUNCTION__, arp_enable));
}
-void dhd_aoe_arp_clr(dhd_pub_t *dhd)
+void
+dhd_aoe_arp_clr(dhd_pub_t *dhd)
{
int ret = 0;
int iov_len = 0;
@@ -1457,7 +1445,8 @@
DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
}
-void dhd_aoe_hostip_clr(dhd_pub_t *dhd)
+void
+dhd_aoe_hostip_clr(dhd_pub_t *dhd)
{
int ret = 0;
int iov_len = 0;
@@ -1470,7 +1459,8 @@
DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
}
-void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr)
+void
+dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr)
{
int iov_len = 0;
char iovbuf[32];
@@ -1487,7 +1477,8 @@
__FUNCTION__));
}
-int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen)
+int
+dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen)
{
int retcode, i;
int iov_len = 0;
@@ -1522,331 +1513,6 @@
}
#endif /* ARP_OFFLOAD_SUPPORT */
-int
-dhd_preinit_ioctls(dhd_pub_t *dhd)
-{
- int ret = 0;
- char eventmask[WL_EVENTING_MASK_LEN];
- char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
-
- uint up = 0;
- uint power_mode = PM_FAST;
- uint32 dongle_align = DHD_SDALIGN;
- uint32 glom = 0;
- uint bcn_timeout = 4;
- uint retry_max = 3;
-#if defined(ARP_OFFLOAD_SUPPORT)
- int arpoe = 1;
-#endif
- int scan_assoc_time = 40;
- int scan_unassoc_time = 40;
- const char *str;
- wl_pkt_filter_t pkt_filter;
- wl_pkt_filter_t *pkt_filterp;
- int buf_len;
- int str_len;
- uint32 mask_size;
- uint32 pattern_size;
- char buf[WLC_IOCTL_SMLEN];
- char *ptr;
- uint filter_mode = 1;
- uint32 listen_interval = LISTEN_INTERVAL; /* Default Listen Interval in Beacons */
-#if defined(SOFTAP)
- uint dtim = 1;
-#endif
-#if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211))
- uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */
-#endif /* AP */
-#if defined(AP) || defined(WLP2P)
- uint32 apsta = 1; /* Enable APSTA mode */
-#endif /* defined(AP) || defined(WLP2P) */
-#ifdef GET_CUSTOM_MAC_ENABLE
- struct ether_addr ea_addr;
-#endif /* GET_CUSTOM_MAC_ENABLE */
-
- dhd->op_mode = 0;
-#ifdef GET_CUSTOM_MAC_ENABLE
- ret = dhd_custom_get_mac_address(ea_addr.octet);
- if (!ret) {
- memset(buf, 0, sizeof(buf));
- bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf));
- ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
- if (ret < 0) {
- DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
- return BCME_NOTUP;
- }
- } else {
-#endif /* GET_CUSTOM_MAC_ENABLE */
- /* Get the default device MAC address directly from firmware */
- memset(buf, 0, sizeof(buf));
- bcm_mkiovar("cur_etheraddr", 0, 0, buf, sizeof(buf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
- FALSE, 0)) < 0) {
- DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret));
- return BCME_NOTUP;
- }
- /* Update public MAC address after reading from Firmware */
- memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN);
-#ifdef GET_CUSTOM_MAC_ENABLE
- }
-#endif /* GET_CUSTOM_MAC_ENABLE */
-
-#ifdef SET_RANDOM_MAC_SOFTAP
- if (strstr(fw_path, "_apsta") != NULL) {
- uint rand_mac;
-
- srandom32((uint)jiffies);
- rand_mac = random32();
- iovbuf[0] = 0x02; /* locally administered bit */
- iovbuf[1] = 0x1A;
- iovbuf[2] = 0x11;
- iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0;
- iovbuf[4] = (unsigned char)(rand_mac >> 8);
- iovbuf[5] = (unsigned char)(rand_mac >> 16);
-
- bcm_mkiovar("cur_etheraddr", (void *)iovbuf, ETHER_ADDR_LEN, buf, sizeof(buf));
- ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
- if (ret < 0) {
- DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
- } else
- memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN);
- }
-#endif /* SET_RANDOM_MAC_SOFTAP */
-
- DHD_TRACE(("Firmware = %s\n", fw_path));
-#if !defined(AP) && defined(WLP2P)
- /* Check if firmware with WFD support used */
- if (strstr(fw_path, "_p2p") != NULL) {
- bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
- iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s APSTA for WFD failed ret= %d\n", __FUNCTION__, ret));
- } else {
- dhd->op_mode |= WFD_MASK;
-#if defined(ARP_OFFLOAD_SUPPORT)
- arpoe = 0;
-#endif /* (ARP_OFFLOAD_SUPPORT) */
- dhd_pkt_filter_enable = FALSE;
- }
- }
-#endif /* !defined(AP) && defined(WLP2P) */
-
-#if !defined(AP) && defined(WL_CFG80211)
- /* Check if firmware with HostAPD support used */
- if (strstr(fw_path, "_apsta") != NULL) {
- /* Turn off MPC in AP mode */
- bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
- sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s mpc for HostAPD failed %d\n", __FUNCTION__, ret));
- } else {
- dhd->op_mode |= HOSTAPD_MASK;
-#if defined(ARP_OFFLOAD_SUPPORT)
- arpoe = 0;
-#endif /* (ARP_OFFLOAD_SUPPORT) */
- dhd_pkt_filter_enable = FALSE;
- }
- }
-#endif /* !defined(AP) && defined(WL_CFG80211) */
-
- if ((dhd->op_mode != WFD_MASK) && (dhd->op_mode != HOSTAPD_MASK)) {
- /* STA only operation mode */
- dhd->op_mode |= STA_MASK;
- dhd_pkt_filter_enable = TRUE;
- }
- DHD_ERROR(("Firmware up: op_mode=%d, "
- "Broadcom Dongle Host Driver mac=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
- dhd->op_mode,
- dhd->mac.octet[0], dhd->mac.octet[1], dhd->mac.octet[2],
- dhd->mac.octet[3], dhd->mac.octet[4], dhd->mac.octet[5]));
-
- /* Set Country code */
- if (dhd->dhd_cspec.ccode[0] != 0) {
- bcm_mkiovar("country", (char *)&dhd->dhd_cspec,
- sizeof(wl_country_t), iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
- DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__));
- }
-
- /* Set Listen Interval */
- bcm_mkiovar("assoc_listen", (char *)&listen_interval, 4, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
- DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret));
-
- /* query for 'ver' to get version info from firmware */
- memset(buf, 0, sizeof(buf));
- ptr = buf;
- bcm_mkiovar("ver", (char *)&buf, 4, buf, sizeof(buf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0)) < 0)
- DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret));
- else {
- bcmstrtok(&ptr, "\n", 0);
- /* Print fw version info */
- DHD_ERROR(("Firmware version = %s\n", buf));
- }
- /* Set PowerSave mode */
- dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0);
-
- /* Match Host and Dongle rx alignment */
- bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
-
- /* disable glom option per default */
- bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
-
- /* Setup timeout if Beacons are lost and roam is off to report link down */
- bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
- /* Setup assoc_retry_max count to reconnect target AP in dongle */
- bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
-#if defined(AP) && !defined(WLP2P)
- /* Turn off MPC in AP mode */
- bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
- bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
-#endif /* defined(AP) && !defined(WLP2P) */
-#if defined(SOFTAP)
- if (ap_fw_loaded == TRUE) {
- dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0);
- }
-#endif
-
-#if defined(KEEP_ALIVE)
- {
- /* Set Keep Alive : be sure to use FW with -keepalive */
- int res;
-
-#if defined(SOFTAP)
- if (ap_fw_loaded == FALSE)
-#endif
- if ((res = dhd_keep_alive_onoff(dhd)) < 0)
- DHD_ERROR(("%s set keeplive failed %d\n",
- __FUNCTION__, res));
- }
-#endif /* defined(KEEP_ALIVE) */
-
- /* Force STA UP */
- ret = dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0);
- if (ret < 0)
- goto done;
-
- /* Setup event_msgs */
- bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0);
- if (ret < 0)
- goto done;
- bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN);
-
- /* Setup event_msgs */
- setbit(eventmask, WLC_E_SET_SSID);
- setbit(eventmask, WLC_E_PRUNE);
- setbit(eventmask, WLC_E_AUTH);
- setbit(eventmask, WLC_E_REASSOC);
- setbit(eventmask, WLC_E_REASSOC_IND);
- setbit(eventmask, WLC_E_DEAUTH_IND);
- setbit(eventmask, WLC_E_DISASSOC_IND);
- setbit(eventmask, WLC_E_DISASSOC);
- setbit(eventmask, WLC_E_JOIN);
- setbit(eventmask, WLC_E_ASSOC_IND);
- setbit(eventmask, WLC_E_PSK_SUP);
- setbit(eventmask, WLC_E_LINK);
- setbit(eventmask, WLC_E_NDIS_LINK);
- setbit(eventmask, WLC_E_MIC_ERROR);
- setbit(eventmask, WLC_E_PMKID_CACHE);
- setbit(eventmask, WLC_E_TXFAIL);
- setbit(eventmask, WLC_E_JOIN_START);
- setbit(eventmask, WLC_E_SCAN_COMPLETE);
-#ifdef WLMEDIA_HTSF
- setbit(eventmask, WLC_E_HTSFSYNC);
-#endif
- bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
-
- dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time,
- sizeof(scan_assoc_time), TRUE, 0);
- dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time,
- sizeof(scan_unassoc_time), TRUE, 0);
-
- /* add a default packet filter pattern */
- str = "pkt_filter_add";
- str_len = strlen(str);
- strncpy(buf, str, str_len);
- buf[ str_len ] = '\0';
- buf_len = str_len + 1;
-
- pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1);
-
- /* Parse packet filter id. */
- pkt_filter.id = htod32(100);
-
- /* Parse filter polarity. */
- pkt_filter.negate_match = htod32(0);
-
- /* Parse filter type. */
- pkt_filter.type = htod32(0);
-
- /* Parse pattern filter offset. */
- pkt_filter.u.pattern.offset = htod32(0);
-
- /* Parse pattern filter mask. */
- mask_size = htod32(wl_pattern_atoh("0x01",
- (char *) pkt_filterp->u.pattern.mask_and_pattern));
-
- /* Parse pattern filter pattern. */
- pattern_size = htod32(wl_pattern_atoh("0x00",
- (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size]));
-
- if (mask_size != pattern_size) {
- DHD_ERROR(("Mask and pattern not the same size\n"));
- return -EINVAL;
- }
-
- pkt_filter.u.pattern.size_bytes = mask_size;
- buf_len += WL_PKT_FILTER_FIXED_LEN;
- buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
-
- /* Keep-alive attributes are set in local variable (keep_alive_pkt), and
- ** then memcpy'ed into buffer (keep_alive_pktp) since there is no
- ** guarantee that the buffer is properly aligned.
- */
- memcpy((char *)pkt_filterp, &pkt_filter,
- WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
-
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
-
- /* set mode to allow pattern */
- bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
-
-#ifdef ARP_OFFLOAD_SUPPORT
- /* Set and enable ARP offload feature for STA only */
- if (arpoe && !ap_fw_loaded) {
- dhd_arp_offload_set(dhd, dhd_arp_mode);
- dhd_arp_offload_enable(dhd, arpoe);
- } else {
- dhd_arp_offload_set(dhd, 0);
- dhd_arp_offload_enable(dhd, FALSE);
- }
-#endif /* ARP_OFFLOAD_SUPPORT */
-
-#ifdef PKT_FILTER_SUPPORT
- if (ap_fw_loaded) {
- int i;
- for (i = 0; i < dhd->pktfilter_count; i++) {
- dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i],
- 0, dhd_master_mode);
- }
- }
-#endif /* PKT_FILTER_SUPPORT */
-
-
-done:
- return ret;
-}
-
/* send up locally generated event */
void
dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data)
@@ -1862,8 +1528,6 @@
dhd_sendup_event(dhdp, event, data);
}
-
-
#ifdef SIMPLE_ISCAN
uint iscan_thread_id = 0;
@@ -2050,13 +1714,48 @@
#endif /* SIMPLE_ISCAN */
+/*
+ * returns = TRUE if associated, FALSE if not associated
+ */
+bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf)
+{
+ char bssid[6], zbuf[6];
+ int ret = -1;
+
+ bzero(bssid, 6);
+ bzero(zbuf, 6);
+
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, (char *)&bssid, ETHER_ADDR_LEN, FALSE, 0);
+ DHD_TRACE((" %s WLC_GET_BSSID ioctl res = %d\n", __FUNCTION__, ret));
+
+ if (ret == BCME_NOTASSOCIATED) {
+ DHD_TRACE(("%s: not associated! res:%d\n", __FUNCTION__, ret));
+ }
+
+ if (ret < 0)
+ return FALSE;
+
+ if ((memcmp(bssid, zbuf, ETHER_ADDR_LEN) != 0)) {
+ /* STA is assocoated BSSID is non zero */
+
+ if (bss_buf) {
+ /* return bss if caller provided buf */
+ memcpy(bss_buf, bssid, ETHER_ADDR_LEN);
+ }
+ return TRUE;
+ } else {
+ DHD_TRACE(("%s: WLC_GET_BSSID ioctl returned zero bssid\n", __FUNCTION__));
+ return FALSE;
+ }
+}
+
+
/* Function to estimate possible DTIM_SKIP value */
int
dhd_get_dtim_skip(dhd_pub_t *dhd)
{
int bcn_li_dtim;
- int ret;
- uint8 bssid[6];
+ int ret = -1;
int dtim_assoc = 0;
if ((dhd->dtim_skip == 0) || (dhd->dtim_skip == 1))
@@ -2065,8 +1764,7 @@
bcn_li_dtim = dhd->dtim_skip;
/* Check if associated */
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID,
- (char *)&bssid, ETHER_ADDR_LEN, FALSE, 0)) == BCME_NOTASSOCIATED) {
+ if (dhd_is_associated(dhd, NULL) == FALSE) {
DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret));
goto exit;
}
@@ -2152,7 +1850,6 @@
dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled)
{
char iovbuf[128];
- uint8 bssid[6];
int ret = -1;
if ((!dhd) && ((pfn_enabled != 0) || (pfn_enabled != 1))) {
@@ -2162,28 +1859,25 @@
if (dhd_check_ap_wfd_mode_set(dhd) == TRUE)
return (ret);
+
memset(iovbuf, 0, sizeof(iovbuf));
- /* Check if disassoc to enable pno */
- if ((pfn_enabled) &&
- ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID,
- (char *)&bssid, ETHER_ADDR_LEN, TRUE, 0)) == BCME_NOTASSOCIATED)) {
- DHD_TRACE(("%s pno enable called in disassoc mode\n", __FUNCTION__));
+
+ if ((pfn_enabled) && (dhd_is_associated(dhd, NULL) == TRUE)) {
+ DHD_ERROR(("%s pno is NOT enable : called in assoc mode , ignore\n", __FUNCTION__));
+ return ret;
}
- else if (pfn_enabled) {
- DHD_ERROR(("%s pno enable called in assoc mode ret=%d\n",
- __FUNCTION__, ret));
- return ret;
- }
+
/* Enable/disable PNO */
if ((ret = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf))) > 0) {
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
- sizeof(iovbuf), TRUE, 0)) < 0) {
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
+ iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
DHD_ERROR(("%s failed for error=%d\n", __FUNCTION__, ret));
return ret;
}
else {
dhd->pno_enable = pfn_enabled;
- DHD_TRACE(("%s set pno as %d\n", __FUNCTION__, dhd->pno_enable));
+ DHD_TRACE(("%s set pno as %s\n",
+ __FUNCTION__, dhd->pno_enable ? "Enable" : "Disable"));
}
}
else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, ret));
@@ -2209,6 +1903,7 @@
DHD_ERROR(("%s error exit\n", __FUNCTION__));
err = -1;
}
+
if (dhd_check_ap_wfd_mode_set(dhd) == TRUE)
return (err);
@@ -2277,7 +1972,7 @@
pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY);
pfn_element.wsec = htod32(0);
pfn_element.infra = htod32(1);
-
+ pfn_element.flags = htod32(ENABLE << WL_PFN_HIDDEN_BIT);
memcpy((char *)pfn_element.ssid.SSID, ssids_local[i].SSID, ssids_local[i].SSID_len);
pfn_element.ssid.SSID_len = ssids_local[i].SSID_len;
@@ -2291,7 +1986,7 @@
return err;
}
else
- DHD_ERROR(("%s set OK with PNO time=%d repeat=%d max_adjust=%d\n",
+ DHD_TRACE(("%s set OK with PNO time=%d repeat=%d max_adjust=%d\n",
__FUNCTION__, pfn_param.scan_freq,
pfn_param.repeat, pfn_param.exp));
}
@@ -2319,13 +2014,13 @@
#if defined(KEEP_ALIVE)
int dhd_keep_alive_onoff(dhd_pub_t *dhd)
{
- char buf[256];
- const char *str;
+ char buf[256];
+ const char *str;
wl_mkeep_alive_pkt_t mkeep_alive_pkt;
wl_mkeep_alive_pkt_t *mkeep_alive_pktp;
- int buf_len;
- int str_len;
- int res = -1;
+ int buf_len;
+ int str_len;
+ int res = -1;
if (dhd_check_ap_wfd_mode_set(dhd) == TRUE)
return (res);
diff --git a/drivers/net/wireless/bcmdhd/dhd_dbg.h b/drivers/net/wireless/bcmdhd/dhd_dbg.h
index 10851c4..a195cbe 100644
--- a/drivers/net/wireless/bcmdhd/dhd_dbg.h
+++ b/drivers/net/wireless/bcmdhd/dhd_dbg.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhd_dbg.h,v 1.9.6.1 2010-12-22 23:47:24 Exp $
+ * $Id: dhd_dbg.h 285933 2011-09-23 21:45:31Z $
*/
#ifndef _dhd_dbg_
@@ -95,6 +95,7 @@
#define DHD_LOG(args)
+#define DHD_BLOG(cp, size)
#define DHD_NONE(args)
extern int dhd_msg_level;
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c
index 03ba34a..92cdc9b 100644
--- a/drivers/net/wireless/bcmdhd/dhd_linux.c
+++ b/drivers/net/wireless/bcmdhd/dhd_linux.c
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhd_linux.c,v 1.131.2.55 2011-02-09 05:31:56 Exp $
+ * $Id: dhd_linux.c 291449 2011-10-22 12:16:26Z $
*/
#include <typedefs.h>
@@ -86,6 +86,10 @@
uint32 bin[NUMBIN];
} histo_t;
+#if !ISPOWEROF2(DHD_SDALIGN)
+#error DHD_SDALIGN is not a power of 2!
+#endif
+
static histo_t vi_d1, vi_d2, vi_d3, vi_d4;
#endif /* WLMEDIA_HTSF */
@@ -129,7 +133,11 @@
#include <dhd_bus.h>
+#ifndef PROP_TXSTATUS
#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen)
+#else
+#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen + 128)
+#endif
#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15)
const char *
@@ -163,13 +171,14 @@
struct net_device *net;
struct net_device_stats stats;
int idx; /* iface idx in dongle */
- int state; /* interface state */
+ dhd_if_state_t state; /* interface state */
uint subunit; /* subunit */
uint8 mac_addr[ETHER_ADDR_LEN]; /* assigned MAC address */
bool attached; /* Delayed attachment when unset */
bool txflowcontrol; /* Per interface flow control indicator */
char name[IFNAMSIZ+1]; /* linux interface name */
uint8 bssidx; /* bsscfg index for the interface */
+ bool set_multicast;
} dhd_if_t;
#ifdef WLMEDIA_HTSF
@@ -214,7 +223,7 @@
struct semaphore proto_sem;
#ifdef PROP_TXSTATUS
spinlock_t wlfc_spinlock;
-#endif
+#endif /* PROP_TXSTATUS */
#ifdef WLMEDIA_HTSF
htsf_t htsf;
#endif
@@ -254,10 +263,7 @@
int wakelock_counter;
int wakelock_timeout_enable;
- int hang_was_sent;
-
/* Thread to issue ioctl for multicast */
- bool set_multicast;
bool set_macaddress;
struct ether_addr macvalue;
wait_queue_head_t ctrl_wait;
@@ -300,7 +306,7 @@
#if defined(DHD_DEBUG)
/* Console poll interval */
uint dhd_console_ms = 0;
-module_param(dhd_console_ms, uint, 0);
+module_param(dhd_console_ms, uint, 0644);
#endif /* defined(DHD_DEBUG) */
/* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */
@@ -321,7 +327,7 @@
/* Pkt filter mode control */
uint dhd_master_mode = TRUE;
-module_param(dhd_master_mode, uint, 1);
+module_param(dhd_master_mode, uint, 0);
#ifdef DHDTHREAD
/* Watchdog thread priority, -1 to use kernel timer */
@@ -343,7 +349,7 @@
uint dhd_radio_up = 1;
/* Network inteface name */
-char iface_name[IFNAMSIZ];
+char iface_name[IFNAMSIZ] = {'\0'};
module_param_string(iface_name, iface_name, IFNAMSIZ, 0);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
@@ -467,24 +473,26 @@
static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
wl_event_msg_t *event_ptr, void **data_ptr);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) && 1
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored)
{
int ret = NOTIFY_DONE;
- switch (action) {
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39))
+ switch (action) {
case PM_HIBERNATION_PREPARE:
case PM_SUSPEND_PREPARE:
dhd_mmc_suspend = TRUE;
- ret = NOTIFY_OK;
+ ret = NOTIFY_OK;
break;
case PM_POST_HIBERNATION:
case PM_POST_SUSPEND:
dhd_mmc_suspend = FALSE;
- ret = NOTIFY_OK;
+ ret = NOTIFY_OK;
break;
}
smp_mb();
+#endif
return ret;
}
@@ -495,7 +503,6 @@
extern int register_pm_notifier(struct notifier_block *nb);
extern int unregister_pm_notifier(struct notifier_block *nb);
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
- /* && defined(DHD_GPL) */
static void dhd_set_packet_filter(int value, dhd_pub_t *dhd)
{
@@ -586,7 +593,7 @@
DHD_OS_WAKE_LOCK(dhdp);
/* Set flag when early suspend was called */
dhdp->in_suspend = val;
- if (!dhdp->suspend_disable_flag)
+ if ((!dhdp->suspend_disable_flag) && (dhd_check_ap_wfd_mode_set(dhdp) == FALSE))
dhd_set_suspend(val, dhdp);
DHD_OS_WAKE_UNLOCK(dhdp);
}
@@ -946,7 +953,7 @@
#endif
switch (ifp->state) {
- case WLC_E_IF_ADD:
+ case DHD_IF_ADD:
/*
* Delete the existing interface before overwriting it
* in case we missed the WLC_E_IF_DEL event.
@@ -971,12 +978,10 @@
if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)
if (!wl_cfg80211_notify_ifadd(ifp->net, ifp->idx, ifp->bssidx,
dhd_net_attach)) {
- ifp->state = 0;
+ ifp->state = DHD_IF_NONE;
return;
- }
-
+ }
#endif
-
if ((err = dhd_net_attach(&dhd->pub, ifp->idx)) != 0) {
DHD_ERROR(("%s: dhd_net_attach failed, err %d\n",
__FUNCTION__, err));
@@ -996,21 +1001,28 @@
#endif
DHD_TRACE(("\n ==== pid:%x, net_device for if:%s created ===\n\n",
current->pid, ifp->net->name));
- ifp->state = 0;
+ ifp->state = DHD_IF_NONE;
}
}
break;
- case WLC_E_IF_DEL:
+ case DHD_IF_DEL:
+ /* Make sure that we don't enter again here if .. */
+ /* dhd_op_if is called again from some other context */
+ ifp->state = DHD_IF_DELETING;
if (ifp->net != NULL) {
- DHD_TRACE(("\n%s: got 'WLC_E_IF_DEL' state\n", __FUNCTION__));
+ DHD_TRACE(("\n%s: got 'DHD_IF_DEL' state\n", __FUNCTION__));
#ifdef WL_CFG80211
- wl_cfg80211_ifdel_ops(ifp->net);
+ if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) {
+ wl_cfg80211_notify_ifdel(ifp->net);
+ }
#endif
netif_stop_queue(ifp->net);
unregister_netdev(ifp->net);
ret = DHD_DEL_IF; /* Make sure the free_netdev() is called */
}
break;
+ case DHD_IF_DELETING:
+ break;
default:
DHD_ERROR(("%s: bad op %d\n", __FUNCTION__, ifp->state));
ASSERT(!ifp->state);
@@ -1018,22 +1030,18 @@
}
if (ret < 0) {
+ ifp->set_multicast = FALSE;
if (ifp->net) {
free_netdev(ifp->net);
}
dhd->iflist[ifp->idx] = NULL;
-#ifdef WL_CFG80211
- if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) {
- wl_cfg80211_notify_ifdel(ifp->net);
- }
-#endif
#ifdef SOFTAP
flags = dhd_os_spin_lock(&dhd->pub);
if (ifp->net == ap_net_dev)
ap_net_dev = NULL; /* NULL SOFTAP global wl0.1 as well */
dhd_os_spin_unlock(&dhd->pub, flags);
#endif /* SOFTAP */
- MFREE(dhd->pub.osh, ifp, sizeof(*ifp));
+ MFREE(dhd->pub.osh, ifp, sizeof(*ifp));
}
}
@@ -1072,15 +1080,15 @@
in_ap = (ap_net_dev != NULL);
dhd_os_spin_unlock(&dhd->pub, flags);
#endif /* SOFTAP */
- if (dhd->iflist[i]->state)
+ if (dhd->iflist[i] && dhd->iflist[i]->state)
dhd_op_if(dhd->iflist[i]);
-#ifdef SOFTAP
+
if (dhd->iflist[i] == NULL) {
DHD_TRACE(("\n\n %s: interface %d just been removed,"
"!\n\n", __FUNCTION__, i));
continue;
}
-
+#ifdef SOFTAP
if (in_ap && dhd->set_macaddress) {
DHD_TRACE(("attempt to set MAC for %s in AP Mode,"
"blocked. \n", dhd->iflist[i]->net->name));
@@ -1088,15 +1096,15 @@
continue;
}
- if (in_ap && dhd->set_multicast) {
+ if (in_ap && dhd->iflist[i]->set_multicast) {
DHD_TRACE(("attempt to set MULTICAST list for %s"
"in AP Mode, blocked. \n", dhd->iflist[i]->net->name));
- dhd->set_multicast = FALSE;
+ dhd->iflist[i]->set_multicast = FALSE;
continue;
}
#endif /* SOFTAP */
- if (dhd->set_multicast) {
- dhd->set_multicast = FALSE;
+ if (dhd->iflist[i]->set_multicast) {
+ dhd->iflist[i]->set_multicast = FALSE;
_dhd_set_multicast_list(dhd, i);
}
if (dhd->set_macaddress) {
@@ -1145,7 +1153,7 @@
return;
ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0);
- dhd->set_multicast = TRUE;
+ dhd->iflist[ifidx]->set_multicast = TRUE;
up(&dhd->thr_sysioc_ctl.sema);
}
@@ -1389,6 +1397,7 @@
int i;
dhd_if_t *ifp;
wl_event_msg_t event;
+ int tout = DHD_PACKET_TIMEOUT;
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
@@ -1399,9 +1408,16 @@
struct dot11_llc_snap_header *lsh;
ifp = dhd->iflist[ifidx];
+ if (ifp == NULL) {
+ DHD_ERROR(("%s: ifp is NULL. drop packet\n",
+ __FUNCTION__));
+ PKTFREE(dhdp->osh, pktbuf, TRUE);
+ continue;
+ }
/* Dropping packets before registering net device to avoid kernel panic */
- if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED) {
+ if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED ||
+ !dhd->pub.up) {
DHD_ERROR(("%s: net device is NOT registered yet. drop packet\n",
__FUNCTION__));
PKTFREE(dhdp->osh, pktbuf, TRUE);
@@ -1485,6 +1501,7 @@
if (event.event_type == WLC_E_BTA_HCI_EVENT) {
dhd_bta_doevt(dhdp, data, event.datalen);
}
+ tout = DHD_EVENT_TIMEOUT;
}
ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]);
@@ -1517,7 +1534,7 @@
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */
}
}
- DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(dhdp);
+ DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(dhdp, tout);
}
void
@@ -1605,14 +1622,12 @@
/* This thread doesn't need any user-level access,
* so get rid of all our resources
*/
-#ifdef DHD_SCHED
if (dhd_watchdog_prio > 0) {
struct sched_param param;
param.sched_priority = (dhd_watchdog_prio < MAX_RT_PRIO)?
dhd_watchdog_prio:(MAX_RT_PRIO-1);
setScheduler(current, SCHED_FIFO, ¶m);
}
-#endif /* DHD_SCHED */
DAEMONIZE("dhd_watchdog");
@@ -1698,14 +1713,12 @@
/* This thread doesn't need any user-level access,
* so get rid of all our resources
*/
-#ifdef DHD_SCHED
if (dhd_dpc_prio > 0)
{
struct sched_param param;
param.sched_priority = (dhd_dpc_prio < MAX_RT_PRIO)?dhd_dpc_prio:(MAX_RT_PRIO-1);
setScheduler(current, SCHED_FIFO, ¶m);
}
-#endif /* DHD_SCHED */
DAEMONIZE("dhd_dpc");
/* DHD_OS_WAKE_LOCK is called in dhd_sched_dpc[dhd_linux.c] down below */
@@ -1731,7 +1744,8 @@
DHD_OS_WAKE_UNLOCK(&dhd->pub);
}
} else {
- dhd_bus_stop(dhd->pub.bus, TRUE);
+ if (dhd->pub.up)
+ dhd_bus_stop(dhd->pub.bus, TRUE);
DHD_OS_WAKE_UNLOCK(&dhd->pub);
}
}
@@ -1984,6 +1998,20 @@
}
#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */
+static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error)
+{
+ if (!dhdp)
+ return FALSE;
+ if ((error == -ETIMEDOUT) || ((dhdp->busstate == DHD_BUS_DOWN) &&
+ (!dhdp->dongle_reset))) {
+ DHD_ERROR(("%s: Event HANG send up due to re=%d te=%d e=%d s=%d\n", __FUNCTION__,
+ dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate));
+ net_os_send_hang_message(net);
+ return TRUE;
+ }
+ return FALSE;
+}
+
static int
dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
{
@@ -1998,6 +2026,14 @@
DHD_OS_WAKE_LOCK(&dhd->pub);
+ /* send to dongle only if we are not waiting for reload already */
+ if (dhd->pub.hang_was_sent) {
+ DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__));
+ DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ return OSL_ERROR(BCME_DONGLE_DOWN);
+ }
+
ifidx = dhd_net2idx(dhd, net);
DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd));
@@ -2026,6 +2062,7 @@
if (cmd == SIOCDEVPRIVATE+1) {
ret = wl_android_priv_cmd(net, ifr, cmd);
+ dhd_check_hang(net, &dhd->pub, ret);
DHD_OS_WAKE_UNLOCK(&dhd->pub);
return ret;
}
@@ -2163,11 +2200,7 @@
bcmerror = dhd_wl_ioctl(&dhd->pub, ifidx, (wl_ioctl_t *)&ioc, buf, buflen);
done:
- if ((bcmerror == -ETIMEDOUT) || ((dhd->pub.busstate == DHD_BUS_DOWN) &&
- (!dhd->pub.dongle_reset))) {
- DHD_ERROR(("%s: Event HANG send up\n", __FUNCTION__));
- net_os_send_hang_message(net);
- }
+ dhd_check_hang(net, &dhd->pub, bcmerror);
if (!bcmerror && buf && ioc.buf) {
if (copy_to_user(ioc.buf, buf, buflen))
@@ -2182,21 +2215,71 @@
return OSL_ERROR(bcmerror);
}
+#ifdef WL_CFG80211
+static int
+dhd_cleanup_virt_ifaces(dhd_info_t *dhd)
+{
+ int i = 1; /* Leave ifidx 0 [Primary Interface] */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ int rollback_lock = FALSE;
+#endif
+
+ DHD_TRACE(("%s: Enter \n", __func__));
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ /* release lock for unregister_netdev */
+ if (rtnl_is_locked()) {
+ rtnl_unlock();
+ rollback_lock = TRUE;
+ }
+#endif
+
+ for (i = 1; i < DHD_MAX_IFS; i++) {
+ if (dhd->iflist[i]) {
+ DHD_TRACE(("Deleting IF: %d \n", i));
+ if ((dhd->iflist[i]->state != DHD_IF_DEL) &&
+ (dhd->iflist[i]->state != DHD_IF_DELETING)) {
+ dhd->iflist[i]->state = DHD_IF_DEL;
+ dhd->iflist[i]->idx = i;
+ dhd_op_if(dhd->iflist[i]);
+ }
+ }
+ }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ if (rollback_lock)
+ rtnl_lock();
+#endif
+
+ return 0;
+}
+#endif /* WL_CFG80211 */
+
static int
dhd_stop(struct net_device *net)
{
int ifidx;
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
-
+ DHD_OS_WAKE_LOCK(&dhd->pub);
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
if (dhd->pub.up == 0) {
- return 0;
+ goto exit;
}
ifidx = dhd_net2idx(dhd, net);
#ifdef WL_CFG80211
- if (ifidx == 0)
+ if (ifidx == 0) {
wl_cfg80211_down();
+
+ /*
+ * For CFG80211: Clean up all the left over virtual interfaces
+ * when the primary Interface is brought down. [ifconfig wlan0 down]
+ */
+ if ((dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) &&
+ (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) {
+ dhd_cleanup_virt_ifaces(dhd);
+ }
+ }
#endif
#ifdef PROP_TXSTATUS
@@ -2210,11 +2293,15 @@
dhd_prot_stop(&dhd->pub);
#if defined(WL_CFG80211)
- if (ifidx == 0)
+ if (ifidx == 0 && !dhd_download_fw_on_driverload)
wl_android_wifi_off(net);
#endif
-
+ dhd->pub.hang_was_sent = 0;
+ dhd->pub.rxcnt_timeout = 0;
+ dhd->pub.txcnt_timeout = 0;
OLD_MOD_DEC_USE_COUNT;
+exit:
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
return 0;
}
@@ -2229,6 +2316,7 @@
int ifidx;
int32 ret = 0;
+ DHD_OS_WAKE_LOCK(&dhd->pub);
/* Update FW path if it was changed */
if ((firmware_path != NULL) && (firmware_path[0] != '\0')) {
if (firmware_path[strlen(firmware_path)-1] == '\n')
@@ -2236,10 +2324,12 @@
strcpy(fw_path, firmware_path);
firmware_path[0] = '\0';
}
+
#if !defined(WL_CFG80211)
- /** Force start if ifconfig_up gets called before START command
- * We keep WEXT's wl_control_wl_start to provide backward compatibility
- * This should be removed in the future
+ /*
+ * Force start if ifconfig_up gets called before START command
+ * We keep WEXT's wl_control_wl_start to provide backward compatibility
+ * This should be removed in the future
*/
wl_control_wl_start(net);
#endif
@@ -2249,19 +2339,23 @@
if (ifidx < 0) {
DHD_ERROR(("%s: Error: called with invalid IF\n", __FUNCTION__));
- return -1;
+ ret = -1;
+ goto exit;
}
- if (!dhd->iflist[ifidx] || dhd->iflist[ifidx]->state == WLC_E_IF_DEL) {
+ if (!dhd->iflist[ifidx] || dhd->iflist[ifidx]->state == DHD_IF_DEL) {
DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__));
- return -1;
+ ret = -1;
+ goto exit;
}
if (ifidx == 0) {
atomic_set(&dhd->pend_8021x_cnt, 0);
#if defined(WL_CFG80211)
- wl_android_wifi_on(net);
-#endif
+ DHD_ERROR(("\n%s\n", dhd_version));
+ if (!dhd_download_fw_on_driverload)
+ wl_android_wifi_on(net);
+#endif /* defined(WL_CFG80211) */
if (dhd->pub.busstate != DHD_BUS_DATA) {
int ret;
@@ -2269,7 +2363,8 @@
/* try to bring up bus */
if ((ret = dhd_bus_start(&dhd->pub)) != 0) {
DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
- return -1;
+ ret = -1;
+ goto exit;
}
}
@@ -2288,7 +2383,8 @@
#if defined(WL_CFG80211)
if (unlikely(wl_cfg80211_up())) {
DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__));
- return -1;
+ ret = -1;
+ goto exit;
}
#endif /* WL_CFG80211 */
}
@@ -2302,6 +2398,8 @@
#endif
OLD_MOD_INC_USE_COUNT;
+exit:
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
return ret;
}
@@ -2318,7 +2416,7 @@
DHD_ERROR(("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh)));
}
osl_detach(osh);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
up(&dhd_registration_sem);
#endif
}
@@ -2355,7 +2453,7 @@
memcpy(&ifp->mac_addr, mac_addr, ETHER_ADDR_LEN);
if (handle == NULL) {
- ifp->state = WLC_E_IF_ADD;
+ ifp->state = DHD_IF_ADD;
ifp->idx = ifidx;
ifp->bssidx = bssidx;
ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0);
@@ -2380,7 +2478,7 @@
return;
}
- ifp->state = WLC_E_IF_DEL;
+ ifp->state = DHD_IF_DEL;
ifp->idx = ifidx;
ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0);
up(&dhd->thr_sysioc_ctl.sema);
@@ -2565,7 +2663,7 @@
*/
memcpy(netdev_priv(net), &dhd, sizeof(dhd));
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) && 1
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
register_pm_notifier(&dhd_sleep_pm_notifier);
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
@@ -2605,15 +2703,14 @@
int ret = -1;
dhd_info_t *dhd = (dhd_info_t*)dhdp->info;
unsigned long flags;
-#ifdef EMBEDDED_PLATFORM
- char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
-#endif /* EMBEDDED_PLATFORM */
ASSERT(dhd);
- DHD_TRACE(("%s: \n", __FUNCTION__));
+ DHD_TRACE(("Enter %s:\n", __FUNCTION__));
+#ifdef DHDTHREAD
dhd_os_sdlock(dhdp);
+#endif /* DHDTHREAD */
/* try to download image and nvram to the dongle */
if ((dhd->pub.busstate == DHD_BUS_DOWN) &&
@@ -2624,12 +2721,16 @@
fw_path, nv_path))) {
DHD_ERROR(("%s: dhdsdio_probe_download failed. firmware = %s nvram = %s\n",
__FUNCTION__, fw_path, nv_path));
+#ifdef DHDTHREAD
dhd_os_sdunlock(dhdp);
+#endif /* DHDTHREAD */
return -1;
}
}
if (dhd->pub.busstate != DHD_BUS_LOAD) {
+#ifdef DHDTHREAD
dhd_os_sdunlock(dhdp);
+#endif /* DHDTHREAD */
return -ENETDOWN;
}
@@ -2639,21 +2740,27 @@
/* Bring up the bus */
if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) {
+
DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret));
+#ifdef DHDTHREAD
dhd_os_sdunlock(dhdp);
+#endif /* DHDTHREAD */
return ret;
}
#if defined(OOB_INTR_ONLY)
/* Host registration for OOB interrupt */
if (bcmsdh_register_oob_intr(dhdp)) {
/* deactivate timer and wait for the handler to finish */
+
flags = dhd_os_spin_lock(&dhd->pub);
dhd->wd_timer_valid = FALSE;
dhd_os_spin_unlock(&dhd->pub, flags);
del_timer_sync(&dhd->timer);
DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__));
+#ifdef DHDTHREAD
dhd_os_sdunlock(dhdp);
+#endif /* DHDTHREAD */
return -ENODEV;
}
@@ -2668,55 +2775,15 @@
dhd_os_spin_unlock(&dhd->pub, flags);
del_timer_sync(&dhd->timer);
DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__));
+#ifdef DHDTHREAD
dhd_os_sdunlock(dhdp);
+#endif /* DHDTHREAD */
return -ENODEV;
}
+#ifdef DHDTHREAD
dhd_os_sdunlock(dhdp);
-
-#ifdef EMBEDDED_PLATFORM
- bcm_mkiovar("event_msgs", dhdp->eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0);
- bcopy(iovbuf, dhdp->eventmask, WL_EVENTING_MASK_LEN);
-
- setbit(dhdp->eventmask, WLC_E_SET_SSID);
- setbit(dhdp->eventmask, WLC_E_PRUNE);
- setbit(dhdp->eventmask, WLC_E_AUTH);
- setbit(dhdp->eventmask, WLC_E_REASSOC);
- setbit(dhdp->eventmask, WLC_E_REASSOC_IND);
- setbit(dhdp->eventmask, WLC_E_DEAUTH_IND);
- setbit(dhdp->eventmask, WLC_E_DISASSOC_IND);
- setbit(dhdp->eventmask, WLC_E_DISASSOC);
- setbit(dhdp->eventmask, WLC_E_JOIN);
- setbit(dhdp->eventmask, WLC_E_ASSOC_IND);
- setbit(dhdp->eventmask, WLC_E_PSK_SUP);
- setbit(dhdp->eventmask, WLC_E_LINK);
- setbit(dhdp->eventmask, WLC_E_NDIS_LINK);
- setbit(dhdp->eventmask, WLC_E_MIC_ERROR);
- setbit(dhdp->eventmask, WLC_E_PMKID_CACHE);
- setbit(dhdp->eventmask, WLC_E_TXFAIL);
- setbit(dhdp->eventmask, WLC_E_JOIN_START);
- setbit(dhdp->eventmask, WLC_E_SCAN_COMPLETE);
- setbit(dhdp->eventmask, WLC_E_ACTION_FRAME_RX);
- setbit(dhdp->eventmask, WLC_E_ACTION_FRAME_COMPLETE);
-#if defined(WLP2P)
- setbit(dhdp->eventmask, WLC_E_P2P_PROBREQ_MSG);
-#endif /* WLP2P */
-#ifdef PNO_SUPPORT
- setbit(dhdp->eventmask, WLC_E_PFN_NET_FOUND);
-#endif /* PNO_SUPPORT */
-
-/* enable dongle roaming event */
- setbit(dhdp->eventmask, WLC_E_ROAM);
-
-
- dhdp->pktfilter_count = 4;
- /* Setup filter to allow only unicast */
- dhdp->pktfilter[0] = "100 0 0 0 0x01 0x00";
- dhdp->pktfilter[1] = NULL;
- dhdp->pktfilter[2] = NULL;
- dhdp->pktfilter[3] = NULL;
-#endif /* EMBEDDED_PLATFORM */
+#endif /* DHDTHREAD */
#ifdef READ_MACADDR
dhd_read_macaddr(dhd);
@@ -2734,6 +2801,318 @@
}
int
+dhd_preinit_ioctls(dhd_pub_t *dhd)
+{
+ int ret = 0;
+ char eventmask[WL_EVENTING_MASK_LEN];
+ char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
+
+ uint up = 0;
+ uint power_mode = PM_FAST;
+ uint32 dongle_align = DHD_SDALIGN;
+ uint32 glom = 0;
+ uint bcn_timeout = 4;
+ uint retry_max = 3;
+#if defined(ARP_OFFLOAD_SUPPORT)
+ int arpoe = 1;
+#endif
+ int scan_assoc_time = 40;
+ int scan_unassoc_time = 40;
+ int scan_passive_time = 130;
+ char buf[WLC_IOCTL_SMLEN];
+ char *ptr;
+ uint32 listen_interval = LISTEN_INTERVAL; /* Default Listen Interval in Beacons */
+#if defined(SOFTAP)
+ uint dtim = 1;
+#endif
+#if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211))
+ uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */
+#endif
+
+#if defined(AP) || defined(WLP2P)
+ uint32 apsta = 1; /* Enable APSTA mode */
+#endif /* defined(AP) || defined(WLP2P) */
+#ifdef GET_CUSTOM_MAC_ENABLE
+ struct ether_addr ea_addr;
+#endif /* GET_CUSTOM_MAC_ENABLE */
+
+ DHD_TRACE(("Enter %s\n", __FUNCTION__));
+ dhd->op_mode = 0;
+#ifdef GET_CUSTOM_MAC_ENABLE
+ ret = dhd_custom_get_mac_address(ea_addr.octet);
+ if (!ret) {
+ memset(buf, 0, sizeof(buf));
+ bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf));
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
+ if (ret < 0) {
+ DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
+ return BCME_NOTUP;
+ }
+ } else {
+#endif /* GET_CUSTOM_MAC_ENABLE */
+ /* Get the default device MAC address directly from firmware */
+ memset(buf, 0, sizeof(buf));
+ bcm_mkiovar("cur_etheraddr", 0, 0, buf, sizeof(buf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
+ FALSE, 0)) < 0) {
+ DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret));
+ return BCME_NOTUP;
+ }
+ /* Update public MAC address after reading from Firmware */
+ memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN);
+#ifdef GET_CUSTOM_MAC_ENABLE
+ }
+#endif /* GET_CUSTOM_MAC_ENABLE */
+
+#ifdef SET_RANDOM_MAC_SOFTAP
+ if (strstr(fw_path, "_apsta") != NULL) {
+ uint rand_mac;
+
+ srandom32((uint)jiffies);
+ rand_mac = random32();
+ iovbuf[0] = 0x02; /* locally administered bit */
+ iovbuf[1] = 0x1A;
+ iovbuf[2] = 0x11;
+ iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0;
+ iovbuf[4] = (unsigned char)(rand_mac >> 8);
+ iovbuf[5] = (unsigned char)(rand_mac >> 16);
+
+ bcm_mkiovar("cur_etheraddr", (void *)iovbuf, ETHER_ADDR_LEN, buf, sizeof(buf));
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
+ if (ret < 0) {
+ DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
+ } else
+ memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN);
+ }
+#endif /* SET_RANDOM_MAC_SOFTAP */
+
+ DHD_TRACE(("Firmware = %s\n", fw_path));
+#if !defined(AP) && defined(WLP2P)
+ /* Check if firmware with WFD support used */
+ if (strstr(fw_path, "_p2p") != NULL) {
+ bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
+ iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s APSTA for WFD failed ret= %d\n", __FUNCTION__, ret));
+ } else {
+ dhd->op_mode |= WFD_MASK;
+#if defined(ARP_OFFLOAD_SUPPORT)
+ arpoe = 0;
+#endif /* (ARP_OFFLOAD_SUPPORT) */
+ dhd_pkt_filter_enable = FALSE;
+ }
+ }
+#endif
+
+#if !defined(AP) && defined(WL_CFG80211)
+ /* Check if firmware with HostAPD support used */
+ if (strstr(fw_path, "_apsta") != NULL) {
+ /* Turn off MPC in AP mode */
+ bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s mpc for HostAPD failed %d\n", __FUNCTION__, ret));
+ } else {
+ dhd->op_mode |= HOSTAPD_MASK;
+#if defined(ARP_OFFLOAD_SUPPORT)
+ arpoe = 0;
+#endif /* (ARP_OFFLOAD_SUPPORT) */
+ dhd_pkt_filter_enable = FALSE;
+ }
+ }
+#endif
+
+ if ((dhd->op_mode != WFD_MASK) && (dhd->op_mode != HOSTAPD_MASK)) {
+ /* STA only operation mode */
+ dhd->op_mode |= STA_MASK;
+ dhd_pkt_filter_enable = TRUE;
+ }
+
+ DHD_ERROR(("Firmware up: op_mode=%d, "
+ "Broadcom Dongle Host Driver mac=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+ dhd->op_mode,
+ dhd->mac.octet[0], dhd->mac.octet[1], dhd->mac.octet[2],
+ dhd->mac.octet[3], dhd->mac.octet[4], dhd->mac.octet[5]));
+
+ /* Set Country code */
+ if (dhd->dhd_cspec.ccode[0] != 0) {
+ bcm_mkiovar("country", (char *)&dhd->dhd_cspec,
+ sizeof(wl_country_t), iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__));
+ }
+
+ /* Set Listen Interval */
+ bcm_mkiovar("assoc_listen", (char *)&listen_interval, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret));
+
+ /* Set PowerSave mode */
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0);
+
+ /* Match Host and Dongle rx alignment */
+ bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+
+ /* disable glom option per default */
+ bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+
+ /* Setup timeout if Beacons are lost and roam is off to report link down */
+ bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ /* Setup assoc_retry_max count to reconnect target AP in dongle */
+ bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#if defined(AP) && !defined(WLP2P)
+ /* Turn off MPC in AP mode */
+ bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#endif /* defined(AP) && !defined(WLP2P) */
+
+#if defined(SOFTAP)
+ if (ap_fw_loaded == TRUE) {
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0);
+ }
+#endif
+
+#if defined(KEEP_ALIVE)
+ {
+ /* Set Keep Alive : be sure to use FW with -keepalive */
+ int res;
+
+#if defined(SOFTAP)
+ if (ap_fw_loaded == FALSE)
+#endif
+ if ((res = dhd_keep_alive_onoff(dhd)) < 0)
+ DHD_ERROR(("%s set keeplive failed %d\n",
+ __FUNCTION__, res));
+ }
+#endif /* defined(KEEP_ALIVE) */
+
+ /* Read event_msgs mask */
+ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 0) {
+ DHD_ERROR(("%s read Event mask failed %d\n", __FUNCTION__, ret));
+ goto done;
+ }
+ bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN);
+
+ /* Setup event_msgs */
+ setbit(eventmask, WLC_E_SET_SSID);
+ setbit(eventmask, WLC_E_PRUNE);
+ setbit(eventmask, WLC_E_AUTH);
+ setbit(eventmask, WLC_E_REASSOC);
+ setbit(eventmask, WLC_E_REASSOC_IND);
+ setbit(eventmask, WLC_E_DEAUTH);
+ setbit(eventmask, WLC_E_DEAUTH_IND);
+ setbit(eventmask, WLC_E_DISASSOC_IND);
+ setbit(eventmask, WLC_E_DISASSOC);
+ setbit(eventmask, WLC_E_JOIN);
+ setbit(eventmask, WLC_E_ASSOC_IND);
+ setbit(eventmask, WLC_E_PSK_SUP);
+ setbit(eventmask, WLC_E_LINK);
+ setbit(eventmask, WLC_E_NDIS_LINK);
+ setbit(eventmask, WLC_E_MIC_ERROR);
+ setbit(eventmask, WLC_E_PMKID_CACHE);
+ setbit(eventmask, WLC_E_TXFAIL);
+ setbit(eventmask, WLC_E_JOIN_START);
+ setbit(eventmask, WLC_E_SCAN_COMPLETE);
+#ifdef WLMEDIA_HTSF
+ setbit(eventmask, WLC_E_HTSFSYNC);
+#endif /* WLMEDIA_HTSF */
+#ifdef PNO_SUPPORT
+ setbit(eventmask, WLC_E_PFN_NET_FOUND);
+#endif /* PNO_SUPPORT */
+ /* enable dongle roaming event */
+ setbit(eventmask, WLC_E_ROAM);
+#ifdef WL_CFG80211
+ setbit(eventmask, WLC_E_ESCAN_RESULT);
+ if ((dhd->op_mode & WFD_MASK) == WFD_MASK) {
+ setbit(eventmask, WLC_E_ACTION_FRAME_RX);
+ setbit(eventmask, WLC_E_ACTION_FRAME_COMPLETE);
+ setbit(eventmask, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE);
+ setbit(eventmask, WLC_E_P2P_PROBREQ_MSG);
+ setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE);
+ }
+#endif /* WL_CFG80211 */
+
+ /* Write updated Event mask */
+ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s Set Event mask failed %d\n", __FUNCTION__, ret));
+ goto done;
+ }
+
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time,
+ sizeof(scan_assoc_time), TRUE, 0);
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time,
+ sizeof(scan_unassoc_time), TRUE, 0);
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_PASSIVE_TIME, (char *)&scan_passive_time,
+ sizeof(scan_passive_time), TRUE, 0);
+
+#ifdef ARP_OFFLOAD_SUPPORT
+ /* Set and enable ARP offload feature for STA only */
+#if defined(SOFTAP)
+ if (arpoe && !ap_fw_loaded) {
+#else
+ if (arpoe) {
+#endif
+ dhd_arp_offload_set(dhd, dhd_arp_mode);
+ dhd_arp_offload_enable(dhd, arpoe);
+ } else {
+ dhd_arp_offload_set(dhd, 0);
+ dhd_arp_offload_enable(dhd, FALSE);
+ }
+#endif /* ARP_OFFLOAD_SUPPORT */
+
+#ifdef PKT_FILTER_SUPPORT
+ /* Setup defintions for pktfilter , enable in suspend */
+ dhd->pktfilter_count = 4;
+ /* Setup filter to allow only unicast */
+ dhd->pktfilter[0] = "100 0 0 0 0x01 0x00";
+ dhd->pktfilter[1] = NULL;
+ dhd->pktfilter[2] = NULL;
+ dhd->pktfilter[3] = NULL;
+#if defined(SOFTAP)
+ if (ap_fw_loaded) {
+ int i;
+ for (i = 0; i < dhd->pktfilter_count; i++) {
+ dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i],
+ 0, dhd_master_mode);
+ }
+ }
+#endif /* defined(SOFTAP) */
+#endif /* PKT_FILTER_SUPPORT */
+
+ /* Force STA UP */
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s Setting WL UP failed %d\n", __FUNCTION__, ret));
+ goto done;
+ }
+
+ /* query for 'ver' to get version info from firmware */
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ bcm_mkiovar("ver", (char *)&buf, 4, buf, sizeof(buf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0)) < 0)
+ DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret));
+ else {
+ bcmstrtok(&ptr, "\n", 0);
+ /* Print fw version info */
+ DHD_ERROR(("Firmware version = %s\n", buf));
+ DHD_BLOG(buf, strlen(buf) + 1);
+ DHD_BLOG(dhd_version, strlen(dhd_version) + 1);
+ }
+
+done:
+ return ret;
+}
+
+
+int
dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set)
{
char buf[strlen(name) + 1 + cmd_len];
@@ -2805,7 +3184,8 @@
#ifdef ARP_OFFLOAD_SUPPORT
/* add or remove AOE host ip(s) (up to 8 IPs on the interface) */
-void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add)
+void
+aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add)
{
u32 ipv4_buf[MAX_IPV4_ENTRIES]; /* temp save for AOE host_ip table */
int i;
@@ -2828,14 +3208,11 @@
}
for (i = 0; i < MAX_IPV4_ENTRIES; i++) {
-
if (add && (ipv4_buf[i] == 0)) {
-
- ipv4_buf[i] = ipa;
+ ipv4_buf[i] = ipa;
add = FALSE; /* added ipa to local table */
DHD_ARPOE(("%s: Saved new IP in temp arp_hostip[%d]\n",
__FUNCTION__, i));
-
} else if (ipv4_buf[i] == ipa) {
ipv4_buf[i] = 0;
DHD_ARPOE(("%s: removed IP:%x from temp table %d\n",
@@ -2882,6 +3259,12 @@
DHD_ARPOE(("%s: [%s] Up IP: 0x%x\n",
__FUNCTION__, ifa->ifa_label, ifa->ifa_address));
+ /* firmware not downloaded, do nothing */
+ if (dhd->pub.busstate == DHD_BUS_DOWN) {
+ DHD_ERROR(("%s: bus is down, exit\n", __FUNCTION__));
+ break;
+ }
+
#ifdef AOE_IP_ALIAS_SUPPORT
if (ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a) {
DHD_ARPOE(("%s:add aliased IP to AOE hostip cache\n",
@@ -2900,14 +3283,14 @@
#ifdef AOE_IP_ALIAS_SUPPORT
if (!(ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a)) {
DHD_ARPOE(("%s: primary interface is down, AOE clr all\n",
- __FUNCTION__));
+ __FUNCTION__));
dhd_aoe_hostip_clr(&dhd->pub);
dhd_aoe_arp_clr(&dhd->pub);
} else
aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE);
#else
- dhd_aoe_hostip_clr(&dhd->pub);
- dhd_aoe_arp_clr(&dhd->pub);
+ dhd_aoe_hostip_clr(&dhd->pub);
+ dhd_aoe_arp_clr(&dhd->pub);
#endif
break;
@@ -2961,9 +3344,9 @@
net->netdev_ops = &dhd_ops_pri;
#endif
} else {
- /*
- * We have to use the primary MAC for virtual interfaces
- */
+ /*
+ * We have to use the primary MAC for virtual interfaces
+ */
memcpy(temp_addr, dhd->iflist[ifidx]->mac_addr, ETHER_ADDR_LEN);
/*
* Android sets the locally administered bit to indicate that this is a
@@ -3037,8 +3420,9 @@
dhd = (dhd_info_t *)dhdp->info;
if (dhd) {
- /** In case of Android cfg80211 driver, the bus is down in dhd_stop,
- * calling stop again will cuase SD read/write errors.
+ /*
+ * In case of Android cfg80211 driver, the bus is down in dhd_stop,
+ * calling stop again will cuase SD read/write errors.
*/
if (dhd->pub.busstate != DHD_BUS_DOWN) {
/* Stop the protocol module */
@@ -3105,9 +3489,10 @@
int i = 1;
dhd_if_t *ifp;
+ /* Cleanup virtual interfaces */
for (i = 1; i < DHD_MAX_IFS; i++)
if (dhd->iflist[i]) {
- dhd->iflist[i]->state = WLC_E_IF_DEL;
+ dhd->iflist[i]->state = DHD_IF_DEL;
dhd->iflist[i]->idx = i;
dhd_op_if(dhd->iflist[i]);
}
@@ -3168,8 +3553,8 @@
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
- unregister_pm_notifier(&dhd_sleep_pm_notifier);
-#endif
+ unregister_pm_notifier(&dhd_sleep_pm_notifier);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) {
#ifdef CONFIG_HAS_WAKELOCK
@@ -3177,7 +3562,6 @@
wake_lock_destroy(&dhd->wl_rxwake);
#endif
}
-
}
@@ -3249,7 +3633,6 @@
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
error = dhd_bus_register();
-
if (!error)
printf("\n%s\n", dhd_version);
else {
@@ -3425,8 +3808,6 @@
{
struct file *fp;
- /* wl_cfg80211_request_fw(filename); */
-
fp = filp_open(filename, O_RDONLY, 0);
/*
* 2.6.11 (FC4) supports filp_open() but later revs don't?
@@ -3446,8 +3827,6 @@
struct file *fp = (struct file *)image;
int rdlen;
- /* wl_cfg80211_read_fw(buf, len); */
-
if (!image)
return 0;
@@ -3461,8 +3840,6 @@
void
dhd_os_close_image(void *image)
{
- /* wl_cfg80211_release_fw(); */
-
if (image)
filp_close((struct file *)image, NULL);
}
@@ -3515,10 +3892,12 @@
dhd = (dhd_info_t *)(pub->info);
spin_unlock_bh(&dhd->txqlock);
}
+
void
dhd_os_sdlock_rxq(dhd_pub_t *pub)
{
}
+
void
dhd_os_sdunlock_rxq(dhd_pub_t *pub)
{
@@ -3896,11 +4275,14 @@
int ret = 0;
if (dhd) {
- if (!dhd->hang_was_sent) {
- dhd->hang_was_sent = 1;
+ if (!dhd->pub.hang_was_sent) {
+ dhd->pub.hang_was_sent = 1;
#if defined(CONFIG_WIRELESS_EXT)
ret = wl_iw_send_priv_event(dev, "HANG");
#endif
+#if defined(WL_CFG80211)
+ ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
+#endif
}
}
return ret;
@@ -4038,7 +4420,8 @@
ret = dhd->wakelock_timeout_enable;
#ifdef CONFIG_HAS_WAKELOCK
if (dhd->wakelock_timeout_enable)
- wake_lock_timeout(&dhd->wl_rxwake, HZ);
+ wake_lock_timeout(&dhd->wl_rxwake,
+ dhd->wakelock_timeout_enable * HZ);
#endif
dhd->wakelock_timeout_enable = 0;
spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
@@ -4056,26 +4439,27 @@
return ret;
}
-int dhd_os_wake_lock_timeout_enable(dhd_pub_t *pub)
+int dhd_os_wake_lock_timeout_enable(dhd_pub_t *pub, int val)
{
dhd_info_t *dhd = (dhd_info_t *)(pub->info);
unsigned long flags;
if (dhd) {
spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
- dhd->wakelock_timeout_enable = 1;
+ if (val > dhd->wakelock_timeout_enable)
+ dhd->wakelock_timeout_enable = val;
spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
}
return 0;
}
-int net_os_wake_lock_timeout_enable(struct net_device *dev)
+int net_os_wake_lock_timeout_enable(struct net_device *dev, int val)
{
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
int ret = 0;
if (dhd)
- ret = dhd_os_wake_lock_timeout_enable(&dhd->pub);
+ ret = dhd_os_wake_lock_timeout_enable(&dhd->pub, val);
return ret;
}
@@ -4130,6 +4514,31 @@
return ret;
}
+int dhd_os_check_wakelock(void *dhdp)
+{
+#ifdef CONFIG_HAS_WAKELOCK
+ dhd_pub_t *pub = (dhd_pub_t *)dhdp;
+ dhd_info_t *dhd;
+
+ if (!pub)
+ return 0;
+ dhd = (dhd_info_t *)(pub->info);
+
+ if (dhd && wake_lock_active(&dhd->wl_wifi))
+ return 1;
+#endif
+ return 0;
+}
+
+int dhd_os_check_if_up(void *dhdp)
+{
+ dhd_pub_t *pub = (dhd_pub_t *)dhdp;
+
+ if (!pub)
+ return 0;
+ return pub->up;
+}
+
int net_os_wake_unlock(struct net_device *dev)
{
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
@@ -4160,11 +4569,20 @@
DHD_OS_WAKE_LOCK(&dhd->pub);
ret = dhd_wl_ioctl(&dhd->pub, ifidx, ioc, ioc->buf, ioc->len);
+ dhd_check_hang(net, &dhd->pub, ret);
DHD_OS_WAKE_UNLOCK(&dhd->pub);
return ret;
}
+bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret)
+{
+ struct net_device *net;
+
+ net = dhd_idx2net(dhdp, ifidx);
+ return dhd_check_hang(net, dhdp, ret);
+}
+
#ifdef PROP_TXSTATUS
extern int dhd_wlfc_interface_entry_update(void* state, ewlfc_mac_entry_action_t action, uint8 ifid,
uint8 iftype, uint8* ea);
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_sched.c b/drivers/net/wireless/bcmdhd/dhd_linux_sched.c
index 72290b5..aadd122 100644
--- a/drivers/net/wireless/bcmdhd/dhd_linux_sched.c
+++ b/drivers/net/wireless/bcmdhd/dhd_linux_sched.c
@@ -26,6 +26,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
+#include <typedefs.h>
#include <linuxver.h>
int setScheduler(struct task_struct *p, int policy, struct sched_param *param)
diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c
index 6d89f6b..2930115 100644
--- a/drivers/net/wireless/bcmdhd/dhd_sdio.c
+++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhd_sdio.c,v 1.274.2.40 2011-02-09 22:42:44 Exp $
+ * $Id: dhd_sdio.c 288105 2011-10-06 01:58:02Z $
*/
#include <typedefs.h>
@@ -87,14 +87,6 @@
#define MAX_NVRAMBUF_SIZE 4096 /* max nvram buf size */
#define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold biggest possible glom */
-/* Packet alignment for most efficient SDIO (can change based on platform) */
-#ifndef DHD_SDALIGN
-#define DHD_SDALIGN 32
-#endif
-#if !ISPOWEROF2(DHD_SDALIGN)
-#error DHD_SDALIGN is not a power of 2!
-#endif
-
#ifndef DHD_FIRSTREAD
#define DHD_FIRSTREAD 32
#endif
@@ -155,6 +147,8 @@
#ifdef DHD_DEBUG
/* Device console log buffer state */
+#define CONSOLE_LINE_MAX 192
+#define CONSOLE_BUFFER_MAX 2024
typedef struct dhd_console {
uint count; /* Poll interval msec counter */
uint log_addr; /* Log struct address (fixed) */
@@ -357,7 +351,7 @@
static bool forcealign;
/* Flag to indicate if we should download firmware on driver load */
-uint dhd_download_fw_on_driverload = FALSE;
+uint dhd_download_fw_on_driverload = TRUE;
#define ALIGNMENT 4
@@ -386,10 +380,9 @@
/* Try doing readahead */
static bool dhd_readahead;
-
/* To check if there's window offered */
#define DATAOK(bus) \
- (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \
+ (((uint8)(bus->tx_max - bus->tx_seq) > 2) && \
(((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
/* To check if there's window offered for ctrl frame */
@@ -429,6 +422,11 @@
} \
} while (0)
+#define BUS_WAKE(bus) \
+ do { \
+ if ((bus)->sleeping) \
+ dhdsdio_bussleep((bus), FALSE); \
+ } while (0);
/*
* pktavail interrupts from dongle to host can be managed in 3 different ways
@@ -437,7 +435,7 @@
* Mode 0: Dongle writes the software host mailbox and host is interrupted.
* Mode 1: (sdiod core rev >= 4)
* Device sets a new bit in the intstatus whenever there is a packet
- * available in fifo. Host can't clear this specific status bit until all the
+ * available in fifo. Host can't clear this specific status bit until all the
* packets are read from the FIFO. No need to ack dongle intstatus.
* Mode 2: (sdiod core rev >= 4)
* Device sets a bit in the intstatus, and host acks this by writing
@@ -470,10 +468,10 @@
#endif
#ifdef DHD_DEBUG
-static int dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size);
-static int dhdsdio_mem_dump(dhd_bus_t *bus);
+static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size);
static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror);
#endif /* DHD_DEBUG */
+
static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh);
@@ -927,13 +925,6 @@
}
#endif /* defined(OOB_INTR_ONLY) */
-#define BUS_WAKE(bus) \
- do { \
- if ((bus)->sleeping) \
- dhdsdio_bussleep((bus), FALSE); \
- } while (0);
-
-
/* Writes a HW/SW header into the packet and sends it. */
/* Assumes: (a) header space already there, (b) caller holds lock */
static int
@@ -1382,13 +1373,18 @@
DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
ret = 0;
} else {
- DHD_ERROR(("%s: ctrl_frame_stat == TRUE\n", __FUNCTION__));
+ bus->dhd->txcnt_timeout++;
+ if (!bus->dhd->hang_was_sent)
+ DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n",
+ __FUNCTION__, bus->dhd->txcnt_timeout));
ret = -1;
bus->ctrl_frame_stat = FALSE;
goto done;
}
}
+ bus->dhd->txcnt_timeout = 0;
+
if (ret == -1) {
#ifdef DHD_DEBUG
if (DHD_BYTES_ON() && DHD_CTL_ON()) {
@@ -1446,6 +1442,9 @@
else
bus->dhd->tx_ctlpkts++;
+ if (bus->dhd->txcnt_timeout >= MAX_CNTL_TIMEOUT)
+ return -ETIMEDOUT;
+
return ret ? -EIO : 0;
}
@@ -1491,13 +1490,22 @@
dhd_os_sdunlock(bus->dhd);
#endif /* DHD_DEBUG */
}
+ if (timeleft == 0) {
+ bus->dhd->rxcnt_timeout++;
+ DHD_ERROR(("%s: rxcnt_timeout=%d\n", __FUNCTION__, bus->dhd->rxcnt_timeout));
+ }
+ else
+ bus->dhd->rxcnt_timeout = 0;
if (rxlen)
bus->dhd->rx_ctlpkts++;
else
bus->dhd->rx_ctlerrs++;
- return rxlen ? (int)rxlen : -ETIMEDOUT;
+ if (bus->dhd->rxcnt_timeout >= MAX_CNTL_TIMEOUT)
+ return -ETIMEDOUT;
+
+ return rxlen ? (int)rxlen : -EIO;
}
/* IOVar table */
@@ -1536,9 +1544,9 @@
IOV_SD1IDLE,
IOV_SLEEP,
IOV_DONGLEISOLATION,
- IOV_VARS
+ IOV_VARS,
#ifdef SOFTAP
- , IOV_FWPATH
+ IOV_FWPATH
#endif
};
@@ -1571,6 +1579,7 @@
{"cpu", IOV_CPU, 0, IOVT_BOOL, 0 },
#ifdef DHD_DEBUG
{"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 },
+ {"serial", IOV_SERIALCONS, 0, IOVT_UINT32, 0 },
#endif /* DHD_DEBUG */
#endif /* DHD_DEBUG */
#ifdef SDTEST
@@ -1844,6 +1853,7 @@
if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1)
return BCME_OK;
+
if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
DHD_ERROR(("%s: sdpcm_shared version %d in dhd "
"is different than sdpcm_shared version %d in dongle\n",
@@ -1855,7 +1865,6 @@
return BCME_OK;
}
-#define CONSOLE_LINE_MAX 192
static int
dhdsdio_readconsole(dhd_bus_t *bus)
@@ -1928,16 +1937,21 @@
}
static int
-dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size)
+dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size)
{
int bcmerror = 0;
uint msize = 512;
char *mbuffer = NULL;
+ char *console_buffer = NULL;
uint maxstrlen = 256;
char *str = NULL;
trap_t tr;
sdpcm_shared_t sdpcm_shared;
struct bcmstrbuf strbuf;
+ uint32 console_ptr, console_size, console_index;
+ uint8 line[CONSOLE_LINE_MAX], ch;
+ uint32 n, i, addr;
+ int rv;
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
@@ -2021,86 +2035,86 @@
bcm_bprintf(&strbuf,
"Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
"lp 0x%x, rpc 0x%x Trap offset 0x%x, "
- "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n",
+ "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, "
+ "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n",
ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr),
ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc),
ltoh32(sdpcm_shared.trap_addr),
ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3),
ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7));
+
+ addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log);
+ if ((rv = dhdsdio_membytes(bus, FALSE, addr,
+ (uint8 *)&console_ptr, sizeof(console_ptr))) < 0)
+ goto printbuf;
+
+ addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.buf_size);
+ if ((rv = dhdsdio_membytes(bus, FALSE, addr,
+ (uint8 *)&console_size, sizeof(console_size))) < 0)
+ goto printbuf;
+
+ addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.idx);
+ if ((rv = dhdsdio_membytes(bus, FALSE, addr,
+ (uint8 *)&console_index, sizeof(console_index))) < 0)
+ goto printbuf;
+
+ console_ptr = ltoh32(console_ptr);
+ console_size = ltoh32(console_size);
+ console_index = ltoh32(console_index);
+
+ if (console_size > CONSOLE_BUFFER_MAX ||
+ !(console_buffer = MALLOC(bus->dhd->osh, console_size)))
+ goto printbuf;
+
+ if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr,
+ (uint8 *)console_buffer, console_size)) < 0)
+ goto printbuf;
+
+ for (i = 0, n = 0; i < console_size; i += n + 1) {
+ for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
+ ch = console_buffer[(console_index + i + n) % console_size];
+ if (ch == '\n')
+ break;
+ line[n] = ch;
+ }
+
+
+ if (n > 0) {
+ if (line[n - 1] == '\r')
+ n--;
+ line[n] = 0;
+ /* Don't use DHD_ERROR macro since we print
+ * a lot of information quickly. The macro
+ * will truncate a lot of the printfs
+ */
+
+ if (dhd_msg_level & DHD_ERROR_VAL) {
+ printf("CONSOLE: %s\n", line);
+ DHD_BLOG(line, strlen(line) + 1);
+ }
+ }
+ }
}
}
+printbuf:
if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) {
DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
}
-#ifdef DHD_DEBUG
- if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
- /* Mem dump to a file on device */
- dhdsdio_mem_dump(bus);
- }
-#endif /* DHD_DEBUG */
done:
if (mbuffer)
MFREE(bus->dhd->osh, mbuffer, msize);
if (str)
MFREE(bus->dhd->osh, str, maxstrlen);
+ if (console_buffer)
+ MFREE(bus->dhd->osh, console_buffer, console_size);
return bcmerror;
}
+#endif /* #ifdef DHD_DEBUG */
-static int
-dhdsdio_mem_dump(dhd_bus_t *bus)
-{
- int ret = 0;
- int size; /* Full mem size */
- int start = 0; /* Start address */
- int read_size = 0; /* Read size of each iteration */
- uint8 *buf = NULL, *databuf = NULL;
-
- /* Get full mem size */
- size = bus->ramsize;
- buf = MALLOC(bus->dhd->osh, size);
- if (!buf) {
- printf("%s: Out of memory (%d bytes)\n", __FUNCTION__, size);
- return -1;
- }
-
- /* Read mem content */
- printf("Dump dongle memory");
- databuf = buf;
- while (size)
- {
- read_size = MIN(MEMBLOCK, size);
- if ((ret = dhdsdio_membytes(bus, FALSE, start, databuf, read_size)))
- {
- printf("%s: Error membytes %d\n", __FUNCTION__, ret);
- if (buf) {
- MFREE(bus->dhd->osh, buf, size);
- }
- return -1;
- }
- printf(".");
-
- /* Decrement size and increment start address */
- size -= read_size;
- start += read_size;
- databuf += read_size;
- }
- printf("Done\n");
-
- /* free buf before return !!! */
- if (write_to_file(bus->dhd, buf, bus->ramsize))
- {
- printf("%s: Error writing to files\n", __FUNCTION__);
- return -1;
- }
-
- /* buf free handled in write_to_file, not here */
- return 0;
-}
-#endif /* defined(DHD_DEBUG) */
int
dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
@@ -3048,6 +3062,7 @@
dhd_os_sdunlock(bus->dhd);
}
+
int
dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
{
@@ -3550,7 +3565,7 @@
if ((uint8)(txmax - bus->tx_seq) > 0x40) {
DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
__FUNCTION__, txmax, bus->tx_seq));
- txmax = bus->tx_seq + 2;
+ txmax = bus->tx_seq;
}
bus->tx_max = txmax;
@@ -3971,7 +3986,7 @@
if ((uint8)(txmax - bus->tx_seq) > 0x40) {
DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
__FUNCTION__, txmax, bus->tx_seq));
- txmax = bus->tx_seq + 2;
+ txmax = bus->tx_seq;
}
bus->tx_max = txmax;
@@ -4128,7 +4143,7 @@
if ((uint8)(txmax - bus->tx_seq) > 0x40) {
DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
__FUNCTION__, txmax, bus->tx_seq));
- txmax = bus->tx_seq + 2;
+ txmax = bus->tx_seq;
}
bus->tx_max = txmax;
@@ -4360,6 +4375,13 @@
bus->flowcontrol = fcbits;
}
+#ifdef DHD_DEBUG
+ /* At least print a message if FW halted */
+ if (hmb_data & HMB_DATA_FWHALT) {
+ DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED\n"));
+ dhdsdio_checkdied(bus, NULL, 0);
+ }
+#endif /* DHD_DEBUG */
/* Shouldn't be any others */
if (hmb_data & ~(HMB_DATA_DEVREADY |
@@ -5184,6 +5206,9 @@
#ifdef GET_CUSTOM_MAC_ENABLE
struct ether_addr ea_addr;
#endif /* GET_CUSTOM_MAC_ENABLE */
+#ifdef PROP_TXSTATUS
+ uint up = 0;
+#endif
/* Init global variables at run-time, not as part of the declaration.
* This is required to support init/de-init of the driver. Initialization
@@ -5350,6 +5375,10 @@
goto fail;
}
+#ifdef PROP_TXSTATUS
+ if (dhd_download_fw_on_driverload)
+ dhd_wl_ioctl_cmd(bus->dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0);
+#endif
return bus;
fail:
@@ -5924,7 +5953,7 @@
return bcmerror;
}
-/*
+/*
EXAMPLE: nvram_array
nvram_arry format:
name=value
@@ -6177,8 +6206,9 @@
if (bus->dhd->dongle_reset) {
/* Turn on WLAN */
+#ifdef DHDTHREAD
dhd_os_sdlock(dhdp);
-
+#endif /* DHDTHREAD */
/* Reset SD client */
bcmsdh_reset(bus->sdh);
@@ -6198,16 +6228,16 @@
dhd_enable_oob_intr(bus, TRUE);
#endif /* defined(OOB_INTR_ONLY) */
- bus->dhd->dongle_reset = FALSE;
- bus->dhd->up = TRUE;
+ bus->dhd->dongle_reset = FALSE;
+ bus->dhd->up = TRUE;
#if !defined(IGNORE_ETH0_DOWN)
- /* Restore flow control */
- dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
+ /* Restore flow control */
+ dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
#endif
- dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
+ dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
- DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
+ DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
} else {
dhd_bus_stop(bus, FALSE);
dhdsdio_release_dongle(bus, bus->dhd->osh,
@@ -6218,8 +6248,11 @@
} else
bcmerror = BCME_SDIO_ERROR;
+#ifdef DHDTHREAD
dhd_os_sdunlock(dhdp);
+#endif /* DHDTHREAD */
} else {
+ bcmerror = BCME_SDIO_ERROR;
DHD_INFO(("%s called when dongle is not in reset\n",
__FUNCTION__));
DHD_INFO(("Will call dhd_bus_start instead\n"));
diff --git a/drivers/net/wireless/bcmdhd/dhd_wlfc.h b/drivers/net/wireless/bcmdhd/dhd_wlfc.h
index 53db62c..59d018b 100644
--- a/drivers/net/wireless/bcmdhd/dhd_wlfc.h
+++ b/drivers/net/wireless/bcmdhd/dhd_wlfc.h
@@ -201,6 +201,14 @@
#define WLFC_FCMODE_IMPLIED_CREDIT 1
#define WLFC_FCMODE_EXPLICIT_CREDIT 2
+#define WLFC_BORROW_DEFER_PERIOD_MS 100
+
+/* Mask to represent available ACs (note: BC/MC is ignored */
+#define WLFC_AC_MASK 0xF
+
+/* Mask to check for only on-going AC_BE traffic */
+#define WLFC_AC_BE_TRAFFIC_ONLY 0xD
+
typedef struct athost_wl_status_info {
uint8 last_seqid_to_wlc;
@@ -213,7 +221,11 @@
athost_wl_stat_counters_t stats;
/* the additional ones are for bc/mc and ATIM FIFO */
- int FIFO_credit[AC_COUNT + 2];
+ int FIFO_credit[AC_COUNT + 2];
+
+ /* Credit borrow counts for each FIFO from each of the other FIFOs */
+ int credits_borrowed[AC_COUNT + 2][AC_COUNT + 2];
+
struct pktq SENDQ;
/* packet hanger and MAC->handle lookup table */
@@ -228,7 +240,7 @@
wlfc_mac_descriptor_t other;
} destination_entries;
/* token position for different priority packets */
- uint8 token_pos[AC_COUNT];
+ uint8 token_pos[AC_COUNT+1];
/* ON/OFF state for flow control to the host network interface */
uint8 hostif_flow_state[WLFC_MAX_IFNUM];
uint8 host_ifidx;
@@ -243,6 +255,12 @@
2 - Use explicit credit
*/
uint8 proptxstatus_mode;
+
+ /* To borrow credits */
+ uint8 allow_credit_borrow;
+
+ /* Timestamp to compute how long to defer borrowing for */
+ uint32 borrow_defer_timestamp;
} athost_wl_status_info_t;
#endif /* __wlfc_host_driver_definitions_h__ */
diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h
index f474dfa..ae1f975 100644
--- a/drivers/net/wireless/bcmdhd/include/epivers.h
+++ b/drivers/net/wireless/bcmdhd/include/epivers.h
@@ -19,7 +19,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: epivers.h.in,v 13.32.4.1 2010-09-17 00:39:18 Exp $
+ * $Id: epivers.h.in,v 13.32.4.1 2010-09-17 00:39:18 $
*
*/
@@ -33,17 +33,17 @@
#define EPI_RC_NUMBER 125
-#define EPI_INCREMENTAL_NUMBER 69
+#define EPI_INCREMENTAL_NUMBER 94
#define EPI_BUILD_NUMBER 0
-#define EPI_VERSION 5, 90, 125, 69
+#define EPI_VERSION 5, 90, 125, 94
-#define EPI_VERSION_NUM 0x055a7d45
+#define EPI_VERSION_NUM 0x055a7d5e
#define EPI_VERSION_DEV 5.90.125
-#define EPI_VERSION_STR "5.90.125.69"
+#define EPI_VERSION_STR "5.90.125.94"
#endif
diff --git a/drivers/net/wireless/bcmdhd/include/linuxver.h b/drivers/net/wireless/bcmdhd/include/linuxver.h
index e1c62b7..96844db 100644
--- a/drivers/net/wireless/bcmdhd/include/linuxver.h
+++ b/drivers/net/wireless/bcmdhd/include/linuxver.h
@@ -70,7 +70,9 @@
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
#include <linux/semaphore.h>
+#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28))
#undef IP_TOS
#endif
diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd/include/wlioctl.h
index 1059de1..9357552 100644
--- a/drivers/net/wireless/bcmdhd/include/wlioctl.h
+++ b/drivers/net/wireless/bcmdhd/include/wlioctl.h
@@ -657,6 +657,49 @@
#define WLC_ASSOC_REQ_IS_REASSOC 0x01
+typedef struct {
+ uint16 ver;
+ uint16 len;
+ uint16 cap;
+ uint32 flags;
+ uint32 idle;
+ struct ether_addr ea;
+ wl_rateset_t rateset;
+ uint32 in;
+ uint32 listen_interval_inms;
+ uint32 tx_pkts;
+ uint32 tx_failures;
+ uint32 rx_ucast_pkts;
+ uint32 rx_mcast_pkts;
+ uint32 tx_rate;
+ uint32 rx_rate;
+ uint32 rx_decrypt_succeeds;
+ uint32 rx_decrypt_failures;
+} sta_info_t;
+
+#define WL_OLD_STAINFO_SIZE OFFSETOF(sta_info_t, tx_pkts)
+
+#define WL_STA_VER 3
+
+
+#define WL_STA_BRCM 0x1
+#define WL_STA_WME 0x2
+#define WL_STA_ABCAP 0x4
+#define WL_STA_AUTHE 0x8
+#define WL_STA_ASSOC 0x10
+#define WL_STA_AUTHO 0x20
+#define WL_STA_WDS 0x40
+#define WL_STA_WDS_LINKUP 0x80
+#define WL_STA_PS 0x100
+#define WL_STA_APSD_BE 0x200
+#define WL_STA_APSD_BK 0x400
+#define WL_STA_APSD_VI 0x800
+#define WL_STA_APSD_VO 0x1000
+#define WL_STA_N_CAP 0x2000
+#define WL_STA_SCBSTATS 0x4000
+
+#define WL_WDS_LINKUP WL_STA_WDS_LINKUP
+
#define WLC_TXFILTER_OVERRIDE_DISABLED 0
#define WLC_TXFILTER_OVERRIDE_ENABLED 1
diff --git a/drivers/net/wireless/bcmdhd/linux_osl.c b/drivers/net/wireless/bcmdhd/linux_osl.c
index bbb2408..1a54437 100644
--- a/drivers/net/wireless/bcmdhd/linux_osl.c
+++ b/drivers/net/wireless/bcmdhd/linux_osl.c
@@ -48,24 +48,27 @@
#define BCM_MEM_FILENAME_LEN 24
#ifdef DHD_USE_STATIC_BUF
-#define MAX_STATIC_BUF_NUM 16
-#define STATIC_BUF_SIZE (PAGE_SIZE*2)
-#define STATIC_BUF_TOTAL_LEN (MAX_STATIC_BUF_NUM*STATIC_BUF_SIZE)
+#define STATIC_BUF_MAX_NUM 16
+#define STATIC_BUF_SIZE (PAGE_SIZE * 2)
+#define STATIC_BUF_TOTAL_LEN (STATIC_BUF_MAX_NUM * STATIC_BUF_SIZE)
+
typedef struct bcm_static_buf {
struct semaphore static_sem;
unsigned char *buf_ptr;
- unsigned char buf_use[MAX_STATIC_BUF_NUM];
+ unsigned char buf_use[STATIC_BUF_MAX_NUM];
} bcm_static_buf_t;
static bcm_static_buf_t *bcm_static_buf = 0;
-#define MAX_STATIC_PKT_NUM 8
+#define STATIC_PKT_MAX_NUM 8
+
typedef struct bcm_static_pkt {
- struct sk_buff *skb_4k[MAX_STATIC_PKT_NUM];
- struct sk_buff *skb_8k[MAX_STATIC_PKT_NUM];
+ struct sk_buff *skb_4k[STATIC_PKT_MAX_NUM];
+ struct sk_buff *skb_8k[STATIC_PKT_MAX_NUM];
struct semaphore osl_pkt_sem;
- unsigned char pkt_use[MAX_STATIC_PKT_NUM*2];
+ unsigned char pkt_use[STATIC_PKT_MAX_NUM * 2];
} bcm_static_pkt_t;
+
static bcm_static_pkt_t *bcm_static_skb = 0;
#endif
@@ -167,8 +170,14 @@
osl_attach(void *pdev, uint bustype, bool pkttag)
{
osl_t *osh;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
+ gfp_t flags;
+ flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
+ osh = kmalloc(sizeof(osl_t), flags);
+#else
osh = kmalloc(sizeof(osl_t), GFP_ATOMIC);
+#endif
ASSERT(osh);
bzero(osh, sizeof(osl_t));
@@ -214,20 +223,17 @@
sema_init(&bcm_static_buf->static_sem, 1);
-
bcm_static_buf->buf_ptr = (unsigned char *)bcm_static_buf + STATIC_BUF_SIZE;
-
}
- if (!bcm_static_skb)
- {
+ if (!bcm_static_skb) {
int i;
void *skb_buff_ptr = 0;
bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048);
skb_buff_ptr = dhd_os_prealloc(osh, 4, 0);
- bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *)*16);
- for (i = 0; i < MAX_STATIC_PKT_NUM*2; i++)
+ bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *) * 16);
+ for (i = 0; i < STATIC_PKT_MAX_NUM * 2; i++)
bcm_static_skb->pkt_use[i] = 0;
sema_init(&bcm_static_skb->osl_pkt_sem, 1);
@@ -247,7 +253,7 @@
kfree(osh);
}
-struct sk_buff *osl_alloc_skb(unsigned int len)
+static struct sk_buff *osl_alloc_skb(unsigned int len)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
gfp_t flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
@@ -321,7 +327,14 @@
int32
osl_ctfpool_init(osl_t *osh, uint numobj, uint size)
{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
+ gfp_t flags;
+
+ flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
+ osh->ctfpool = kmalloc(sizeof(ctfpool_t), flags);
+#else
osh->ctfpool = kmalloc(sizeof(ctfpool_t), GFP_ATOMIC);
+#endif
ASSERT(osh->ctfpool);
bzero(osh->ctfpool, sizeof(ctfpool_t));
@@ -536,93 +549,74 @@
}
#ifdef DHD_USE_STATIC_BUF
-void*
+void *
osl_pktget_static(osl_t *osh, uint len)
{
- int i = 0;
+ int i;
struct sk_buff *skb;
-
- if (len > (PAGE_SIZE*2))
- {
- printk("Do we really need this big skb??\n");
+ if (len > (PAGE_SIZE * 2)) {
+ printk("%s: attempt to allocate huge packet (0x%x)\n", __FUNCTION__, len);
return osl_pktget(osh, len);
}
-
down(&bcm_static_skb->osl_pkt_sem);
- if (len <= PAGE_SIZE)
- {
- for (i = 0; i < MAX_STATIC_PKT_NUM; i++)
- {
+ if (len <= PAGE_SIZE) {
+ for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
if (bcm_static_skb->pkt_use[i] == 0)
break;
}
- if (i != MAX_STATIC_PKT_NUM)
- {
+ if (i != STATIC_PKT_MAX_NUM) {
bcm_static_skb->pkt_use[i] = 1;
up(&bcm_static_skb->osl_pkt_sem);
-
skb = bcm_static_skb->skb_4k[i];
skb->tail = skb->data + len;
skb->len = len;
-
return skb;
}
}
- for (i = 0; i < MAX_STATIC_PKT_NUM; i++)
- {
- if (bcm_static_skb->pkt_use[i+MAX_STATIC_PKT_NUM] == 0)
+ for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
+ if (bcm_static_skb->pkt_use[i+STATIC_PKT_MAX_NUM] == 0)
break;
}
- if (i != MAX_STATIC_PKT_NUM)
- {
- bcm_static_skb->pkt_use[i+MAX_STATIC_PKT_NUM] = 1;
+ if (i != STATIC_PKT_MAX_NUM) {
+ bcm_static_skb->pkt_use[i+STATIC_PKT_MAX_NUM] = 1;
up(&bcm_static_skb->osl_pkt_sem);
skb = bcm_static_skb->skb_8k[i];
skb->tail = skb->data + len;
skb->len = len;
-
return skb;
}
-
up(&bcm_static_skb->osl_pkt_sem);
- printk("all static pkt in use!\n");
+ printk("%s: all static pkt in use!\n", __FUNCTION__);
return osl_pktget(osh, len);
}
-
void
osl_pktfree_static(osl_t *osh, void *p, bool send)
{
int i;
- for (i = 0; i < MAX_STATIC_PKT_NUM; i++)
- {
- if (p == bcm_static_skb->skb_4k[i])
- {
+ for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
+ if (p == bcm_static_skb->skb_4k[i]) {
down(&bcm_static_skb->osl_pkt_sem);
bcm_static_skb->pkt_use[i] = 0;
up(&bcm_static_skb->osl_pkt_sem);
-
return;
}
}
- for (i = 0; i < MAX_STATIC_PKT_NUM; i++)
- {
- if (p == bcm_static_skb->skb_8k[i])
- {
+ for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
+ if (p == bcm_static_skb->skb_8k[i]) {
down(&bcm_static_skb->osl_pkt_sem);
- bcm_static_skb->pkt_use[i + MAX_STATIC_PKT_NUM] = 0;
+ bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] = 0;
up(&bcm_static_skb->osl_pkt_sem);
-
return;
}
}
@@ -630,6 +624,7 @@
return osl_pktfree(osh, p, send);
}
#endif
+
uint32
osl_pci_read_config(osl_t *osh, uint offset, uint size)
{
@@ -710,12 +705,18 @@
osl_malloc(osl_t *osh, uint size)
{
void *addr;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
+ gfp_t flags;
if (osh)
ASSERT(osh->magic == OS_HANDLE_MAGIC);
+ flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
+ if ((addr = kmalloc(size, flags)) == NULL) {
+#else
if ((addr = kmalloc(size, GFP_ATOMIC)) == NULL) {
+#endif
if (osh)
osh->failed++;
return (NULL);
@@ -843,8 +844,14 @@
osl_pktdup(osl_t *osh, void *skb)
{
void * p;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
+ gfp_t flags;
+ flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
+ if ((p = skb_clone((struct sk_buff *)skb, flags)) == NULL)
+#else
if ((p = skb_clone((struct sk_buff*)skb, GFP_ATOMIC)) == NULL)
+#endif
return NULL;
#ifdef CTFPOOL
diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c
index d6471d9..9ca3d60 100644
--- a/drivers/net/wireless/bcmdhd/wl_android.c
+++ b/drivers/net/wireless/bcmdhd/wl_android.c
@@ -36,7 +36,9 @@
#include <dngl_stats.h>
#include <dhd.h>
#include <bcmsdbus.h>
-
+#ifdef WL_CFG80211
+#include <wl_cfg80211.h>
+#endif
#if defined(CONFIG_WIFI_CONTROL_FUNC)
#include <linux/platform_device.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
@@ -51,25 +53,30 @@
* so they can be updated easily in the future (if needed)
*/
-#define CMD_START "START"
-#define CMD_STOP "STOP"
-#define CMD_SCAN_ACTIVE "SCAN-ACTIVE"
-#define CMD_SCAN_PASSIVE "SCAN-PASSIVE"
-#define CMD_RSSI "RSSI"
-#define CMD_LINKSPEED "LINKSPEED"
-#define CMD_RXFILTER_START "RXFILTER-START"
-#define CMD_RXFILTER_STOP "RXFILTER-STOP"
-#define CMD_RXFILTER_ADD "RXFILTER-ADD"
-#define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE"
+#define CMD_START "START"
+#define CMD_STOP "STOP"
+#define CMD_SCAN_ACTIVE "SCAN-ACTIVE"
+#define CMD_SCAN_PASSIVE "SCAN-PASSIVE"
+#define CMD_RSSI "RSSI"
+#define CMD_LINKSPEED "LINKSPEED"
+#define CMD_RXFILTER_START "RXFILTER-START"
+#define CMD_RXFILTER_STOP "RXFILTER-STOP"
+#define CMD_RXFILTER_ADD "RXFILTER-ADD"
+#define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE"
#define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START"
-#define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP"
-#define CMD_BTCOEXMODE "BTCOEXMODE"
-#define CMD_SETSUSPENDOPT "SETSUSPENDOPT"
-#define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR"
-#define CMD_SETFWPATH "SETFWPATH"
-#define CMD_SETBAND "SETBAND"
-#define CMD_GETBAND "GETBAND"
-#define CMD_COUNTRY "COUNTRY"
+#define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP"
+#define CMD_BTCOEXMODE "BTCOEXMODE"
+#define CMD_SETSUSPENDOPT "SETSUSPENDOPT"
+#define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR"
+#define CMD_SETFWPATH "SETFWPATH"
+#define CMD_SETBAND "SETBAND"
+#define CMD_GETBAND "GETBAND"
+#define CMD_COUNTRY "COUNTRY"
+#define CMD_P2P_SET_NOA "P2P_SET_NOA"
+#define CMD_P2P_GET_NOA "P2P_GET_NOA"
+#define CMD_P2P_SET_PS "P2P_SET_PS"
+#define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE"
+
#ifdef PNO_SUPPORT
#define CMD_PNOSSIDCLR_SET "PNOSSIDCLR"
@@ -108,9 +115,19 @@
void dhd_dev_init_ioctl(struct net_device *dev);
#ifdef WL_CFG80211
int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
+int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command);
#else
-int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) { return 0; }
+int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
+{ return 0; }
+int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
+{ return 0; }
+int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
+{ return 0; }
+int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
+{ return 0; }
#endif
+extern int dhd_os_check_if_up(void *dhdp);
+extern void *bcmsdh_get_drvdata(void);
extern bool ap_fw_loaded;
#ifdef CUSTOMER_HW2
@@ -157,6 +174,7 @@
error = wldev_get_rssi(net, &rssi);
if (error)
return -1;
+
error = wldev_get_ssid(net, &ssid);
if (error)
return -1;
@@ -186,7 +204,7 @@
if (ret_now != suspend_flag) {
if (!(ret = net_os_set_suspend(dev, ret_now)))
DHD_INFO(("%s: Suspend Flag %d -> %d\n",
- __FUNCTION__, ret_now, suspend_flag));
+ __FUNCTION__, ret_now, suspend_flag));
else
DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
}
@@ -219,6 +237,27 @@
int pno_repeat = 0;
int pno_freq_expo_max = 0;
+#ifdef PNO_SET_DEBUG
+ int i;
+ char pno_in_example[] = {
+ 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
+ 'S', '1', '2', '0',
+ 'S',
+ 0x05,
+ 'd', 'l', 'i', 'n', 'k',
+ 'S',
+ 0x04,
+ 'G', 'O', 'O', 'G',
+ 'T',
+ '0', 'B',
+ 'R',
+ '2',
+ 'M',
+ '2',
+ 0x00
+ };
+#endif /* PNO_SET_DEBUG */
+
DHD_INFO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) {
@@ -226,6 +265,14 @@
goto exit_proc;
}
+#ifdef PNO_SET_DEBUG
+ memcpy(command, pno_in_example, sizeof(pno_in_example));
+ for (i = 0; i < sizeof(pno_in_example); i++)
+ printf("%02X ", command[i]);
+ printf("\n");
+ total_len = sizeof(pno_in_example);
+#endif
+
str_ptr = command + strlen(CMD_PNOSETUP_SET);
tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET);
@@ -317,7 +364,8 @@
sdioh_start(NULL, 0);
ret = dhd_dev_reset(dev, FALSE);
sdioh_start(NULL, 1);
- dhd_dev_init_ioctl(dev);
+ if (!ret)
+ dhd_dev_init_ioctl(dev);
g_wifi_on = 1;
}
dhd_net_if_unlock(dev);
@@ -337,10 +385,8 @@
dhd_net_if_lock(dev);
if (g_wifi_on) {
- dhd_dev_reset(dev, 1);
+ ret = dhd_dev_reset(dev, TRUE);
sdioh_stop(NULL);
- /* clean up dtim_skip setting */
- net_os_set_dtim_skip(dev, TRUE);
dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
g_wifi_on = 0;
}
@@ -447,7 +493,15 @@
/* TBD: BTCOEXSCAN-STOP */
}
else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) {
- /* TBD: BTCOEXMODE */
+ uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
+
+ if (mode == 1)
+ net_os_set_packet_filter(net, 0); /* DHCP starts */
+ else
+ net_os_set_packet_filter(net, 1); /* DHCP ends */
+#ifdef WL_CFG80211
+ bytes_written = wl_cfg80211_set_btcoex_dhcp(net, command);
+#endif
}
else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) {
bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len);
@@ -477,7 +531,29 @@
#endif
else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) {
bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
- } else {
+ }
+ else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) {
+ int skip = strlen(CMD_P2P_SET_NOA) + 1;
+ bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip,
+ priv_cmd.total_len - skip);
+ }
+ else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) {
+ bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
+ }
+ else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) {
+ int skip = strlen(CMD_P2P_SET_PS) + 1;
+ bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip,
+ priv_cmd.total_len - skip);
+ }
+#ifdef WL_CFG80211
+ else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE,
+ strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) {
+ int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3;
+ bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip,
+ priv_cmd.total_len - skip, *(command + skip - 2) - '0');
+ }
+#endif /* WL_CFG80211 */
+ else {
DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command));
snprintf(command, 3, "OK");
bytes_written = strlen("OK");
@@ -517,8 +593,10 @@
dhd_download_fw_on_driverload = FALSE;
#endif /* ENABLE_INSMOD_NO_FW_LOAD */
#ifdef CUSTOMER_HW2
- if (!iface_name[0])
+ if (!iface_name[0]) {
+ memset(iface_name, 0, IFNAMSIZ);
bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ);
+ }
#endif /* CUSTOMER_HW2 */
return ret;
}
@@ -532,12 +610,24 @@
int wl_android_post_init(void)
{
+ struct net_device *ndev;
int ret = 0;
+ char buf[IFNAMSIZ];
if (!dhd_download_fw_on_driverload) {
/* Call customer gpio to turn off power with WL_REG_ON signal */
dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
g_wifi_on = 0;
-
+ } else {
+ memset(buf, 0, IFNAMSIZ);
+#ifdef CUSTOMER_HW2
+ snprintf(buf, IFNAMSIZ, "%s%d", iface_name, 0);
+#else
+ snprintf(buf, IFNAMSIZ, "%s%d", "eth", 0);
+#endif
+ if ((ndev = dev_get_by_name (&init_net, buf)) != NULL) {
+ dhd_dev_init_ioctl(ndev);
+ dev_put(ndev);
+ }
}
return ret;
}
@@ -621,7 +711,7 @@
wifi_control_data->set_power(on);
}
if (msec)
- mdelay(msec);
+ msleep(msec);
return 0;
}
@@ -697,18 +787,19 @@
static int wifi_suspend(struct platform_device *pdev, pm_message_t state)
{
DHD_TRACE(("##> %s\n", __FUNCTION__));
-#if defined(OOB_INTR_ONLY)
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
bcmsdh_oob_intr_set(0);
-#endif /* (OOB_INTR_ONLY) */
+#endif
return 0;
}
static int wifi_resume(struct platform_device *pdev)
{
DHD_TRACE(("##> %s\n", __FUNCTION__));
-#if defined(OOB_INTR_ONLY)
- bcmsdh_oob_intr_set(1);
-#endif /* (OOB_INTR_ONLY) */
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
+ if (dhd_os_check_if_up(bcmsdh_get_drvdata()))
+ bcmsdh_oob_intr_set(1);
+#endif
return 0;
}
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
index 0952913..daa7d26 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
@@ -29,13 +29,6 @@
#include <osl.h>
#include <linux/kernel.h>
-/*
- * sys proc file will be REMOVED in next release
- */
-#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
-#include <linux/sysctl.h>
-#endif
-
#include <bcmutils.h>
#include <bcmwifi.h>
#include <bcmendian.h>
@@ -52,7 +45,6 @@
#include <proto/ethernet.h>
#include <dngl_stats.h>
#include <dhd.h>
-
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/netdevice.h>
@@ -80,48 +72,36 @@
#define WL_4329_FW_FILE "brcm/bcm4329-fullmac-4-218-248-5.bin"
#define WL_4329_NVRAM_FILE "brcm/bcm4329-fullmac-4-218-248-5.txt"
-#define WL_TRACE(a) printk("%s ", __FUNCTION__); printk a
#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
#define MAX_WAIT_TIME 1500
static s8 ioctlbuf[WLC_IOCTL_MAXLEN];
-#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
-#define MAC_STRING_LEN (sizeof(u8) * 17)
-u8 wl_sysctl_macstring[2][MAC_STRING_LEN];
+#define COEX_DHCP
-static ctl_table wl_sysctl_child[] = {
- {
- .procname = "p2p_dev_addr",
- .data = &wl_sysctl_macstring[0],
- .maxlen = MAC_STRING_LEN,
- .mode = 0444,
- .child = NULL,
- .proc_handler = proc_dostring,
- },
- {
- .procname = "p2p_int_addr",
- .data = &wl_sysctl_macstring[1],
- .maxlen = MAC_STRING_LEN,
- .mode = 0444,
- .child = NULL,
- .proc_handler = proc_dostring,
- },
- {0}
+#if defined(COEX_DHCP)
+#define BT_DHCP_eSCO_FIX /* use New SCO/eSCO smart YG
+ * suppression
+ */
+#define BT_DHCP_USE_FLAGS /* this flag boost wifi pkt priority
+ * to max, caution: -not fair to sco
+ */
+#define BT_DHCP_OPPR_WIN_TIME 2500 /* T1 start SCO/ESCo priority
+ * suppression
+ */
+#define BT_DHCP_FLAG_FORCE_TIME 5500 /* T2 turn off SCO/SCO supperesion
+ * is (timeout)
+ */
+enum wl_cfg80211_btcoex_status {
+ BT_DHCP_IDLE,
+ BT_DHCP_START,
+ BT_DHCP_OPPR_WIN,
+ BT_DHCP_FLAG_FORCE_TIMEOUT
};
-static ctl_table wl_sysctl_table[] = {
- {
- .procname = "wifi",
- .data = NULL,
- .maxlen = 0,
- .mode = 0555,
- .child = wl_sysctl_child,
- .proc_handler = NULL,
- },
- {0}
-};
-static struct ctl_table_header *wl_sysctl_hdr;
-#endif /* CONFIG_SYSCTL */
+
+static int wl_cfg80211_btcoex_init(struct wl_priv *wl);
+static void wl_cfg80211_btcoex_deinit(struct wl_priv *wl);
+#endif
/* This is to override regulatory domains defined in cfg80211 module (reg.c)
* By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN
@@ -253,8 +233,8 @@
static s32 wl_event_handler(void *data);
static void wl_init_eq(struct wl_priv *wl);
static void wl_flush_eq(struct wl_priv *wl);
-static void wl_lock_eq(struct wl_priv *wl);
-static void wl_unlock_eq(struct wl_priv *wl);
+static unsigned long wl_lock_eq(struct wl_priv *wl);
+static void wl_unlock_eq(struct wl_priv *wl, unsigned long flags);
static void wl_init_eq_lock(struct wl_priv *wl);
static void wl_init_event_handler(struct wl_priv *wl);
static struct wl_event_q *wl_deq_event(struct wl_priv *wl);
@@ -306,7 +286,7 @@
static s32 wl_update_prof(struct wl_priv *wl, const wl_event_msg_t *e,
void *data, s32 item);
static void *wl_read_prof(struct wl_priv *wl, s32 item);
-static void wl_init_prof(struct wl_profile *prof);
+static void wl_init_prof(struct wl_priv *wl);
/*
* cfg80211 connect utilites
@@ -380,7 +360,6 @@
static s32 wl_dongle_probecap(struct wl_priv *wl);
static void wl_init_conf(struct wl_conf *conf);
static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add);
-static s32 wl_dongle_eventmsg(struct net_device *ndev);
/*
* dongle configuration utilities
@@ -393,7 +372,6 @@
u32 dongle_align);
static s32 wl_dongle_roam(struct net_device *ndev, u32 roamvar,
u32 bcn_timeout);
-static s32 wl_dongle_eventmsg(struct net_device *ndev);
static s32 wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
s32 scan_unassoc_time);
static s32 wl_dongle_offload(struct net_device *ndev, s32 arpoe,
@@ -611,7 +589,7 @@
WLAN_CIPHER_SUITE_WEP104,
WLAN_CIPHER_SUITE_TKIP,
WLAN_CIPHER_SUITE_CCMP,
- WLAN_CIPHER_SUITE_AES_CMAC
+ WLAN_CIPHER_SUITE_AES_CMAC,
};
/* There isn't a lot of sense in it, but you can transmit anything you like */
@@ -787,6 +765,8 @@
struct net_device *_ndev;
dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
int (*net_attach)(dhd_pub_t *dhdp, int ifidx);
+ bool rollback_lock = false;
+
WL_DBG(("if name: %s, type: %d\n", name, type));
switch (type) {
case NL80211_IFTYPE_ADHOC:
@@ -819,11 +799,14 @@
return NULL;
}
if (wl->p2p_supported && (wlif_type != -1)) {
- if (wl_get_p2p_status(wl, IF_DELETING) == 1) {
+ if (wl_get_p2p_status(wl, IF_DELETING)) {
/* wait till IF_DEL is complete
* release the lock for the unregister to proceed
*/
- rtnl_unlock();
+ if (rtnl_is_locked()) {
+ rtnl_unlock();
+ rollback_lock = true;
+ }
WL_INFO(("%s: Released the lock and wait till IF_DEL is complete\n",
__func__));
timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
@@ -831,12 +814,15 @@
msecs_to_jiffies(MAX_WAIT_TIME));
/* put back the rtnl_lock again */
- rtnl_lock();
+ if (rollback_lock) {
+ rtnl_lock();
+ rollback_lock = false;
+ }
if (timeout > 0) {
WL_ERR(("IF DEL is Success\n"));
} else {
- WL_ERR(("%s: timeount < 0, return -EAGAIN\n", __func__));
+ WL_ERR(("timeount < 0, return -EAGAIN\n"));
return ERR_PTR(-EAGAIN);
}
}
@@ -845,7 +831,6 @@
wl_cfgp2p_set_firm_p2p(wl);
wl_cfgp2p_init_discovery(wl);
}
-
memset(wl->p2p->vir_ifname, 0, IFNAMSIZ);
strncpy(wl->p2p->vir_ifname, name, IFNAMSIZ - 1);
wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
@@ -889,15 +874,22 @@
wl->p2p->vif_created = true;
set_mode_by_netdev(wl, _ndev, mode);
net_attach = wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION);
- rtnl_unlock();
- if (net_attach && !net_attach(dhd, _ndev->ifindex))
+ if (rtnl_is_locked()) {
+ rtnl_unlock();
+ rollback_lock = true;
+ }
+ if (net_attach && !net_attach(dhd, _ndev->ifindex)) {
WL_DBG((" virtual interface(%s) is "
"created net attach done\n", wl->p2p->vir_ifname));
- else {
- rtnl_lock();
+ } else {
+ /* put back the rtnl_lock again */
+ if (rollback_lock)
+ rtnl_lock();
goto fail;
}
- rtnl_lock();
+ /* put back the rtnl_lock again */
+ if (rollback_lock)
+ rtnl_lock();
return _ndev;
} else {
@@ -911,7 +903,6 @@
return ERR_PTR(-ENODEV);
}
-
static s32
wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev)
{
@@ -926,28 +917,30 @@
if (wl_get_drv_status(wl, SCANNING)) {
wl_cfg80211_scan_abort(wl, dev);
}
-
- ret = wl_cfgp2p_ifdel(wl, &p2p_mac);
+ wldev_iovar_setint(dev, "mpc", 1);
wl_set_p2p_status(wl, IF_DELETING);
+ ret = wl_cfgp2p_ifdel(wl, &p2p_mac);
if (ret) {
- /* Firmware could not delete the interface so we will not get WLC_E_IF event for cleaning the dhd virtual nw interace
- * So lets do it here. Failures from fw will ensure the application to do ifconfig <inter> down and up sequnce, which will reload the fw
- * however we should cleanup the linux network virtual interfaces
- */
+ /* Firmware could not delete the interface so we will not get WLC_E_IF
+ * event for cleaning the dhd virtual nw interace
+ * So lets do it here. Failures from fw will ensure the application to do
+ * ifconfig <inter> down and up sequnce, which will reload the fw
+ * however we should cleanup the linux network virtual interfaces
+ */
dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
- WL_ERR(("Firmware returned an error from p2p_ifdel, try to remove linux virtual network interface dev->name %s\n", dev->name));
+ WL_ERR(("Firmware returned an error from p2p_ifdel\n"));
+ WL_ERR(("try to remove linux virtual interface %s\n", dev->name));
dhd_del_if(dhd->info, dhd_net2idx(dhd->info, dev));
}
/* Wait for any pending scan req to get aborted from the sysioc context */
timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
- (wl->scan_request == false),
+ (wl_get_p2p_status(wl, IF_DELETING) == false),
msecs_to_jiffies(MAX_WAIT_TIME));
-
- if (timeout > 0 && (!wl->scan_request)) {
- WL_DBG(("IFDEL Operations Done"));
+ if (timeout > 0 && !wl_get_p2p_status(wl, IF_DELETING)) {
+ WL_DBG(("IFDEL operation done\n"));
} else {
- WL_ERR(("IFDEL didn't complete properly"));
+ WL_ERR(("IFDEL didn't complete properly\n"));
}
ret = dhd_del_monitor(dev);
}
@@ -1033,24 +1026,24 @@
}
s32
-wl_cfg80211_notify_ifadd(struct net_device *net, s32 idx, s32 bssidx,
+wl_cfg80211_notify_ifadd(struct net_device *ndev, s32 idx, s32 bssidx,
int (*_net_attach)(dhd_pub_t *dhdp, int ifidx))
{
struct wl_priv *wl = wlcfg_drv_priv;
s32 ret = BCME_OK;
- if (!net) {
+ if (!ndev) {
WL_ERR(("net is NULL\n"));
return 0;
}
if (wl->p2p_supported) {
WL_DBG(("IF_ADD event called from dongle, old interface name: %s,"
- "new name: %s\n", net->name, wl->p2p->vir_ifname));
+ "new name: %s\n", ndev->name, wl->p2p->vir_ifname));
/* Assign the net device to CONNECT BSSCFG */
- strncpy(net->name, wl->p2p->vir_ifname, IFNAMSIZ - 1);
- wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = net;
+ strncpy(ndev->name, wl->p2p->vir_ifname, IFNAMSIZ - 1);
+ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = ndev;
wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = bssidx;
wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION) = _net_attach;
- net->ifindex = idx;
+ ndev->ifindex = idx;
wl_clr_p2p_status(wl, IF_ADD);
wake_up_interruptible(&wl->dongle_event_wait);
@@ -1059,60 +1052,44 @@
}
s32
-wl_cfg80211_ifdel_ops(struct net_device *net)
+wl_cfg80211_notify_ifdel(struct net_device *ndev)
{
struct wl_priv *wl = wlcfg_drv_priv;
+ bool rollback_lock = false;
+ s32 index = 0;
- if (!net || !net->name) {
- WL_DBG(("net is NULL\n"));
+ if (!ndev || !ndev->name) {
+ WL_ERR(("net is NULL\n"));
return 0;
}
- if ((wl->p2p->vif_created) && (wl->scan_request)) {
-
- /* Abort any pending scan requests */
- wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
- rtnl_lock();
- WL_INFO(("ESCAN COMPLETED\n"));
- wl_notify_escan_complete(wl, true);
- rtnl_unlock();
- }
-
- /* Wake up any waiting thread */
- wake_up_interruptible(&wl->dongle_event_wait);
-
- return 0;
-}
-
-s32
-wl_cfg80211_notify_ifdel(struct net_device *net)
-{
- struct wl_priv *wl = wlcfg_drv_priv;
-
-
- if (wl->p2p->vif_created) {
- s32 index = 0;
-
- WL_DBG(("IF_DEL event called from dongle, net %x, vif name: %s\n",
- (unsigned int)net, wl->p2p->vir_ifname));
+ if (p2p_is_on(wl) && wl->p2p->vif_created) {
+ if (wl->scan_request) {
+ /* Abort any pending scan requests */
+ wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
+ if (!rtnl_is_locked()) {
+ rtnl_lock();
+ rollback_lock = true;
+ }
+ WL_DBG(("ESCAN COMPLETED\n"));
+ wl_notify_escan_complete(wl, true);
+ if (rollback_lock)
+ rtnl_unlock();
+ }
+ WL_ERR(("IF_DEL event called from dongle, net %x, vif name: %s\n",
+ (unsigned int)ndev, wl->p2p->vir_ifname));
memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ);
- index = wl_cfgp2p_find_idx(wl, net);
+ index = wl_cfgp2p_find_idx(wl, ndev);
wl_to_p2p_bss_ndev(wl, index) = NULL;
wl_to_p2p_bss_bssidx(wl, index) = 0;
wl->p2p->vif_created = false;
- set_mode_by_netdev(wl, net, -1);
wl_cfgp2p_clear_management_ie(wl,
index);
- index = get_idx_vwdev_by_netdev(wl, net);
+ wl_clr_p2p_status(wl, IF_DELETING);
WL_DBG(("index : %d\n", index));
- if (index >= 0) {
- free_vwdev_by_index(wl, index);
- }
+
}
-
- wl_clr_p2p_status(wl, IF_DELETING);
-
/* Wake up any waiting thread */
wake_up_interruptible(&wl->dongle_event_wait);
@@ -1268,8 +1245,7 @@
}
params = (struct wl_iscan_params *)kzalloc(params_size, GFP_KERNEL);
if (!params) {
- err = -ENOMEM;
- goto done;
+ return -ENOMEM;
}
if (request != NULL)
@@ -1288,13 +1264,13 @@
iscan->ioctl_buf, WLC_IOCTL_MEDLEN);
if (unlikely(err)) {
if (err == -EBUSY) {
- WL_INFO(("system busy : iscan canceled\n"));
+ WL_ERR(("system busy : iscan canceled\n"));
} else {
WL_ERR(("error (%d)\n", err));
}
}
- kfree(params);
done:
+ kfree(params);
return err;
}
@@ -1336,6 +1312,7 @@
s32 search_state = WL_P2P_DISC_ST_SCAN;
u32 i;
u16 *default_chan_list = NULL;
+ struct net_device *dev = NULL;
WL_DBG(("Enter \n"));
@@ -1370,11 +1347,14 @@
params->sync_id = htod16(0x1234);
if (params_size + sizeof("escan") >= WLC_IOCTL_MEDLEN) {
WL_ERR(("ioctl buffer length not sufficient\n"));
+ kfree(params);
err = -ENOMEM;
goto exit;
}
- wldev_iovar_setbuf(ndev, "escan", params, params_size,
+ err = wldev_iovar_setbuf(ndev, "escan", params, params_size,
wl->escan_ioctl_buf, WLC_IOCTL_MEDLEN);
+ if (unlikely(err))
+ WL_ERR((" Escan set error (%d)\n", err));
kfree(params);
}
else if (p2p_on(wl) && p2p_scan(wl)) {
@@ -1402,6 +1382,11 @@
/* SOCIAL CHANNELS 1, 6, 11 */
search_state = WL_P2P_DISC_ST_SEARCH;
WL_INFO(("P2P SEARCH PHASE START \n"));
+ } else if ((dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION)) &&
+ (get_mode_by_netdev(wl, dev) == WL_MODE_AP)) {
+ /* If you are already a GO, then do SEARCH only */
+ WL_INFO(("Already a GO. Do SEARCH Only"));
+ search_state = WL_P2P_DISC_ST_SEARCH;
} else {
WL_INFO(("P2P SCAN STATE START \n"));
}
@@ -1413,6 +1398,9 @@
kfree(default_chan_list);
}
exit:
+ if (unlikely(err)) {
+ WL_ERR(("error (%d)\n", err));
+ }
return err;
}
@@ -1432,7 +1420,7 @@
err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN,
&passive_scan, sizeof(passive_scan), false);
if (unlikely(err)) {
- WL_DBG(("error (%d)\n", err));
+ WL_ERR(("error (%d)\n", err));
return err;
}
results = (wl_scan_results_t *) wl->escan_info.escan_buf;
@@ -1440,7 +1428,7 @@
results->count = 0;
results->buflen = WL_SCAN_RESULTS_FIXED_SIZE;
- wl_run_escan(wl, ndev, request, WL_SCAN_ACTION_START);
+ err = wl_run_escan(wl, ndev, request, WL_SCAN_ACTION_START);
return err;
}
@@ -1452,6 +1440,7 @@
struct wl_priv *wl = wiphy_priv(wiphy);
struct cfg80211_ssid *ssids;
struct wl_scan_req *sr = wl_to_sr(wl);
+ wpa_ie_fixed_t *wps_ie;
s32 passive_scan;
bool iscan_req;
bool escan_req;
@@ -1459,7 +1448,10 @@
bool p2p_ssid;
s32 err = 0;
s32 i;
+ u32 wpsie_len = 0;
+ u8 wpsie[IE_MAX_LEN];
+ WL_DBG(("Enter wiphy (%p)\n", wiphy));
if (unlikely(wl_get_drv_status(wl, SCANNING))) {
WL_ERR(("Scanning already : status (%d)\n", (int)wl->status));
return -EAGAIN;
@@ -1474,8 +1466,8 @@
return -EOPNOTSUPP;
}
- WL_DBG(("wiphy (%p)\n", wiphy));
-
+ /* Arm scan timeout timer */
+ mod_timer(&wl->scan_timeout, jiffies + WL_SCAN_TIMER_INTERVAL_MS * HZ / 1000);
iscan_req = false;
spec_scan = false;
if (request) { /* scan bss */
@@ -1524,6 +1516,26 @@
}
}
}
+ if (!wl->p2p_supported || !p2p_scan(wl)) {
+ if (ndev == wl_to_prmry_ndev(wl)) {
+ /* find the WPSIE */
+ memset(wpsie, 0, sizeof(wpsie));
+ if ((wps_ie = wl_cfgp2p_find_wpsie(
+ (u8 *)request->ie,
+ request->ie_len)) != NULL) {
+ wpsie_len =
+ wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN;
+ memcpy(wpsie, wps_ie, wpsie_len);
+ } else {
+ wpsie_len = 0;
+ }
+ err = wl_cfgp2p_set_management_ie(wl, ndev, -1,
+ VNDR_IE_PRBREQ_FLAG, wpsie, wpsie_len);
+ if (unlikely(err)) {
+ goto scan_out;
+ }
+ }
+ }
}
}
} else { /* scan in ibss */
@@ -1582,7 +1594,7 @@
sizeof(sr->ssid), false);
if (err) {
if (err == -EBUSY) {
- WL_INFO(("system busy : scan for \"%s\" "
+ WL_ERR(("system busy : scan for \"%s\" "
"canceled\n", sr->ssid.SSID));
} else {
WL_ERR(("WLC_SCAN error (%d)\n", err));
@@ -1608,6 +1620,7 @@
WL_DBG(("Enter \n"));
CHECK_SYS_UP(wl);
+
err = __wl_cfg80211_scan(wiphy, ndev, request, NULL);
if (unlikely(err)) {
WL_ERR(("scan error (%d)\n", err));
@@ -1747,6 +1760,7 @@
struct cfg80211_ssid ssid;
s32 scan_retry = 0;
s32 err = 0;
+ bool rollback_lock = false;
WL_TRACE(("In\n"));
CHECK_SYS_UP(wl);
@@ -1768,11 +1782,15 @@
}
} while (++scan_retry < WL_SCAN_RETRY_MAX);
/* to allow scan_inform to propagate to cfg80211 plane */
- rtnl_unlock();
+ if (rtnl_is_locked()) {
+ rtnl_unlock();
+ rollback_lock = true;
+ }
/* wait 4 secons till scan done.... */
schedule_timeout_interruptible(4 * HZ);
- rtnl_lock();
+ if (rollback_lock)
+ rtnl_lock();
bss = cfg80211_get_ibss(wiphy, NULL,
params->ssid, params->ssid_len);
}
@@ -1829,9 +1847,9 @@
s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
- val = WPA_AUTH_PSK; /* | WPA_AUTH_UNSPECIFIED; */
+ val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
- val = WPA2_AUTH_PSK; /* | WPA2_AUTH_UNSPECIFIED ; */
+ val = WPA2_AUTH_PSK| WPA2_AUTH_UNSPECIFIED;
else
val = WPA_AUTH_DISABLED;
@@ -1946,7 +1964,9 @@
if (is_wps_conn(sme)) {
err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx);
} else {
- err = wldev_iovar_setint_bsscfg(dev, "wsec", pval | gval, bssidx);
+ WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC"));
+ err = wldev_iovar_setint_bsscfg(dev, "wsec",
+ pval | gval, bssidx);
}
if (unlikely(err)) {
WL_ERR(("error (%d)\n", err));
@@ -2002,7 +2022,6 @@
return -EINVAL;
}
}
-
WL_DBG(("setting wpa_auth to %d\n", val));
err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
@@ -2089,13 +2108,20 @@
{
struct wl_priv *wl = wiphy_priv(wiphy);
struct ieee80211_channel *chan = sme->channel;
+ wl_extjoin_params_t *ext_join_params;
struct wl_join_params join_params;
size_t join_params_size;
s32 err = 0;
wpa_ie_fixed_t *wpa_ie;
+ wpa_ie_fixed_t *wps_ie;
bcm_tlv_t *wpa2_ie;
u8* wpaie = 0;
u32 wpaie_len = 0;
+ u32 wpsie_len = 0;
+ u32 chan_cnt = 0;
+ u8 wpsie[IE_MAX_LEN];
+ struct ether_addr bssid;
+
WL_DBG(("In\n"));
CHECK_SYS_UP(wl);
@@ -2105,11 +2131,15 @@
if (wl->scan_request) {
wl_cfg80211_scan_abort(wl, dev);
}
+ /* Clean BSSID */
+ bzero(&bssid, sizeof(bssid));
+ wl_update_prof(wl, NULL, (void *)&bssid, WL_PROF_BSSID);
if (IS_P2P_SSID(sme->ssid) && (dev != wl_to_prmry_ndev(wl))) {
/* we only allow to connect using virtual interface in case of P2P */
if (p2p_on(wl) && is_wps_conn(sme)) {
- WL_DBG(("p2p index : %d\n", wl_cfgp2p_find_idx(wl, dev)));
+ WL_DBG(("ASSOC1 p2p index : %d sme->ie_len %d\n",
+ wl_cfgp2p_find_idx(wl, dev), sme->ie_len));
/* Have to apply WPS IE + P2P IE in assoc req frame */
wl_cfgp2p_set_management_ie(wl, dev,
wl_cfgp2p_find_idx(wl, dev), VNDR_IE_PRBREQ_FLAG,
@@ -2119,12 +2149,14 @@
wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev),
VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
} else if (p2p_on(wl) && (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)) {
- /* This is the connect req after WPS is done [credentials exchanged]
+ /* This is the connect req after WPS is done [credentials exchanged]
* currently identified with WPA_VERSION_2 .
* Update the previously set IEs with
* the newly received IEs from Supplicant. This will remove the WPS IE from
* the Assoc Req.
*/
+ WL_DBG(("ASSOC2 p2p index : %d sme->ie_len %d\n",
+ wl_cfgp2p_find_idx(wl, dev), sme->ie_len));
wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev),
VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
}
@@ -2151,44 +2183,126 @@
ioctlbuf, sizeof(ioctlbuf));
}
+ /* find the WPSIE */
+ memset(wpsie, 0, sizeof(wpsie));
+ if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)sme->ie,
+ sme->ie_len)) != NULL) {
+ wpsie_len = wps_ie->length +WPA_RSN_IE_TAG_FIXED_LEN;
+ memcpy(wpsie, wps_ie, wpsie_len);
+ } else {
+ wpsie_len = 0;
+ }
+ err = wl_cfgp2p_set_management_ie(wl, dev, -1,
+ VNDR_IE_ASSOCREQ_FLAG, wpsie, wpsie_len);
+ if (unlikely(err)) {
+ return err;
+ }
}
-
if (unlikely(!sme->ssid)) {
WL_ERR(("Invalid ssid\n"));
return -EOPNOTSUPP;
}
if (chan) {
wl->channel = ieee80211_frequency_to_channel(chan->center_freq);
+ chan_cnt = 1;
WL_DBG(("channel (%d), center_req (%d)\n", wl->channel,
chan->center_freq));
} else
wl->channel = 0;
WL_DBG(("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len));
err = wl_set_wpa_version(dev, sme);
- if (unlikely(err))
+ if (unlikely(err)) {
+ WL_ERR(("Invalid wpa_version\n"));
return err;
+ }
err = wl_set_auth_type(dev, sme);
- if (unlikely(err))
+ if (unlikely(err)) {
+ WL_ERR(("Invalid auth type\n"));
return err;
+ }
err = wl_set_set_cipher(dev, sme);
- if (unlikely(err))
+ if (unlikely(err)) {
+ WL_ERR(("Invalid ciper\n"));
return err;
+ }
err = wl_set_key_mgmt(dev, sme);
- if (unlikely(err))
+ if (unlikely(err)) {
+ WL_ERR(("Invalid key mgmt\n"));
return err;
+ }
err = wl_set_set_sharedkey(dev, sme);
- if (unlikely(err))
+ if (unlikely(err)) {
+ WL_ERR(("Invalid shared key\n"));
return err;
+ }
- wl_update_prof(wl, NULL, sme->bssid, WL_PROF_BSSID);
/*
* Join with specific BSSID and cached SSID
* If SSID is zero join based on BSSID only
*/
+ join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE +
+ chan_cnt * sizeof(chanspec_t);
+ ext_join_params = (wl_extjoin_params_t*)kzalloc(join_params_size, GFP_KERNEL);
+ if (ext_join_params == NULL) {
+ err = -ENOMEM;
+ wl_clr_drv_status(wl, CONNECTING);
+ goto exit;
+ }
+ ext_join_params->ssid.SSID_len = min(sizeof(ext_join_params->ssid.SSID), sme->ssid_len);
+ memcpy(&ext_join_params->ssid.SSID, sme->ssid, ext_join_params->ssid.SSID_len);
+ ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len);
+ /* Set up join scan parameters */
+ ext_join_params->scan.scan_type = -1;
+ ext_join_params->scan.nprobes = 2;
+ /* increate dwell time to receive probe response
+ * from target AP at a noisy air
+ */
+ ext_join_params->scan.active_time = 150;
+ ext_join_params->scan.passive_time = 300;
+ ext_join_params->scan.home_time = -1;
+ if (sme->bssid)
+ memcpy(&ext_join_params->assoc.bssid, sme->bssid, ETH_ALEN);
+ else
+ memcpy(&ext_join_params->assoc.bssid, ðer_bcast, ETH_ALEN);
+ ext_join_params->assoc.chanspec_num = chan_cnt;
+ if (chan_cnt) {
+ u16 channel, band, bw, ctl_sb;
+ chanspec_t chspec;
+ channel = wl->channel;
+ band = (channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G
+ : WL_CHANSPEC_BAND_5G;
+ bw = WL_CHANSPEC_BW_20;
+ ctl_sb = WL_CHANSPEC_CTL_SB_NONE;
+ chspec = (channel | band | bw | ctl_sb);
+ ext_join_params->assoc.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
+ ext_join_params->assoc.chanspec_list[0] |= chspec;
+ ext_join_params->assoc.chanspec_list[0] =
+ htodchanspec(ext_join_params->assoc.chanspec_list[0]);
+ }
+ ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num);
+ if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
+ WL_INFO(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID,
+ ext_join_params->ssid.SSID_len));
+ }
+ wl_set_drv_status(wl, CONNECTING);
+ err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size, ioctlbuf,
+ sizeof(ioctlbuf), wl_cfgp2p_find_idx(wl, dev));
+ kfree(ext_join_params);
+ if (err) {
+ wl_clr_drv_status(wl, CONNECTING);
+ if (err == BCME_UNSUPPORTED) {
+ WL_DBG(("join iovar is not supported\n"));
+ goto set_ssid;
+ } else
+ WL_ERR(("error (%d)\n", err));
+ } else
+ goto exit;
+
+set_ssid:
memset(&join_params, 0, sizeof(join_params));
join_params_size = sizeof(join_params.ssid);
@@ -2209,12 +2323,12 @@
join_params.ssid.SSID_len));
}
wl_set_drv_status(wl, CONNECTING);
- err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, false);
- if (unlikely(err)) {
+ err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, true);
+ if (err) {
WL_ERR(("error (%d)\n", err));
wl_clr_drv_status(wl, CONNECTING);
- return err;
}
+exit:
return err;
}
@@ -2226,10 +2340,11 @@
scb_val_t scbval;
bool act = false;
s32 err = 0;
-
- WL_ERR(("Reason %d\n\n\n", reason_code));
+ u8 *curbssid;
+ WL_ERR(("Reason %d\n", reason_code));
CHECK_SYS_UP(wl);
act = *(bool *) wl_read_prof(wl, WL_PROF_ACT);
+ curbssid = wl_read_prof(wl, WL_PROF_BSSID);
if (likely(act)) {
/*
* Cancel ongoing scan to sync up with sme state machine of cfg80211.
@@ -2239,10 +2354,10 @@
}
wl_set_drv_status(wl, DISCONNECTING);
scbval.val = reason_code;
- memcpy(&scbval.ea, &wl->bssid, ETHER_ADDR_LEN);
+ memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
scbval.val = htod32(scbval.val);
err = wldev_ioctl(dev, WLC_DISASSOC, &scbval,
- sizeof(scb_val_t), false);
+ sizeof(scb_val_t), true);
if (unlikely(err)) {
wl_clr_drv_status(wl, DISCONNECTING);
WL_ERR(("error (%d)\n", err));
@@ -2284,7 +2399,7 @@
/* Make sure radio is off or on as far as software is concerned */
disable = WL_RADIO_SW_DISABLE << 16;
disable = htod32(disable);
- err = wldev_ioctl(ndev, WLC_SET_RADIO, &disable, sizeof(disable), false);
+ err = wldev_ioctl(ndev, WLC_SET_RADIO, &disable, sizeof(disable), true);
if (unlikely(err)) {
WL_ERR(("WLC_SET_RADIO error (%d)\n", err));
return err;
@@ -2347,7 +2462,7 @@
index = (u32) key_idx;
index = htod32(index);
err = wldev_ioctl(dev, WLC_SET_KEY_PRIMARY, &index,
- sizeof(index), false);
+ sizeof(index), true);
if (unlikely(err)) {
WL_ERR(("error (%d)\n", err));
}
@@ -2541,16 +2656,6 @@
return err;
}
-#ifdef NOT_YET
- /* TODO: Removed in P2P, check later --lm */
- val = 1; /* assume shared key. otherwise 0 */
- val = htod32(val);
- err = wldev_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val), false);
- if (unlikely(err)) {
- WL_ERR(("WLC_SET_AUTH error (%d)\n", err));
- return err;
- }
-#endif
return err;
}
@@ -2587,17 +2692,6 @@
}
return err;
}
-
-#ifdef NOT_YET
- /* TODO: Removed in P2P twig, check later --lin */
- val = 0; /* assume open key. otherwise 1 */
- val = htod32(val);
- err = wldev_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val), false);
- if (unlikely(err)) {
- WL_ERR(("WLC_SET_AUTH error (%d)\n", err));
- return err;
- }
-#endif
return err;
}
@@ -2670,51 +2764,88 @@
{
struct wl_priv *wl = wiphy_priv(wiphy);
scb_val_t scb_val;
- int rssi;
+ s32 rssi;
s32 rate;
s32 err = 0;
+ sta_info_t *sta;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
+ s8 eabuf[ETHER_ADDR_STR_LEN];
+#endif
+ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
CHECK_SYS_UP(wl);
- if (unlikely
- (memcmp(mac, wl_read_prof(wl, WL_PROF_BSSID), ETHER_ADDR_LEN))) {
- WL_ERR(("Wrong Mac address\n"));
- return -ENOENT;
- }
-
- /* Report the current tx rate */
- err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false);
- if (err) {
- WL_ERR(("Could not get rate (%d)\n", err));
- } else {
- rate = dtoh32(rate);
- sinfo->filled |= STATION_INFO_TX_BITRATE;
- sinfo->txrate.legacy = rate * 5;
- WL_DBG(("Rate %d Mbps\n", (rate / 2)));
- }
-
- if (wl_get_drv_status(wl, CONNECTED)) {
- memset(&scb_val, 0, sizeof(scb_val));
- scb_val.val = 0;
- err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val,
- sizeof(scb_val_t), false);
- if (unlikely(err)) {
- WL_ERR(("Could not get rssi (%d)\n", err));
+ if (get_mode_by_netdev(wl, dev) == WL_MODE_AP) {
+ err = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)mac,
+ ETHER_ADDR_LEN, ioctlbuf, sizeof(ioctlbuf));
+ if (err < 0) {
+ WL_ERR(("GET STA INFO failed, %d\n", err));
return err;
}
- rssi = dtoh32(scb_val.val);
- sinfo->filled |= STATION_INFO_SIGNAL;
- sinfo->signal = rssi;
- WL_DBG(("RSSI %d dBm\n", rssi));
- }
-
-#if defined(ANDROID_WIRELESS_PATCH)
- err = wldev_ioctl(dev, WLC_GET_RATE, &sinfo->link_speed, sizeof(sinfo->link_speed), false);
- sinfo->link_speed = sinfo->link_speed / 2; /* Convert internal 500Kbps to Mpbs */
- if (!err)
- sinfo->filled |= STATION_LINK_SPEED;
- else
- WL_ERR(("WLC_GET_RATE failed\n"));
+ sinfo->filled = STATION_INFO_INACTIVE_TIME;
+ sta = (sta_info_t *)ioctlbuf;
+ sta->len = dtoh16(sta->len);
+ sta->cap = dtoh16(sta->cap);
+ sta->flags = dtoh32(sta->flags);
+ sta->idle = dtoh32(sta->idle);
+ sta->in = dtoh32(sta->in);
+ sinfo->inactive_time = sta->idle * 1000;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
+ if (sta->flags & WL_STA_ASSOC) {
+ sinfo->filled |= STATION_INFO_CONNECTED_TIME;
+ sinfo->connected_time = sta->in;
+ }
+ WL_INFO(("STA %s : idle time : %d sec, connected time :%d ms\n",
+ bcm_ether_ntoa((const struct ether_addr *)mac, eabuf), sinfo->inactive_time,
+ sta->idle * 1000));
#endif
+ } else if (get_mode_by_netdev(wl, dev) == WL_MODE_BSS) {
+ u8 *curmacp = wl_read_prof(wl, WL_PROF_BSSID);
+
+ if (!wl_get_drv_status(wl, CONNECTED) ||
+ (dhd_is_associated(dhd, NULL) == FALSE)) {
+ WL_ERR(("NOT assoc\n"));
+ err = -ENODEV;
+ goto get_station_err;
+ }
+ if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
+ WL_ERR(("Wrong Mac address: "MACSTR" != "MACSTR"\n",
+ MAC2STR(mac), MAC2STR(curmacp)));
+ }
+
+ /* Report the current tx rate */
+ err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false);
+ if (err) {
+ WL_ERR(("Could not get rate (%d)\n", err));
+ } else {
+ rate = dtoh32(rate);
+ sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->txrate.legacy = rate * 5;
+ WL_DBG(("Rate %d Mbps\n", (rate / 2)));
+ }
+
+ memset(&scb_val, 0, sizeof(scb_val));
+ scb_val.val = 0;
+ err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val,
+ sizeof(scb_val_t), false);
+ if (err) {
+ WL_ERR(("Could not get rssi (%d)\n", err));
+ goto get_station_err;
+ }
+
+ rssi = dtoh32(scb_val.val);
+ sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->signal = rssi;
+ WL_DBG(("RSSI %d dBm\n", rssi));
+
+get_station_err:
+ if (err) {
+ /* Disconnect due to zero BSSID or error to get RSSI */
+ WL_ERR(("force cfg80211_disconnected\n"));
+ wl_clr_drv_status(wl, CONNECTED);
+ cfg80211_disconnected(dev, 0, NULL, 0, GFP_KERNEL);
+ wl_link_down(wl);
+ }
+ }
return err;
}
@@ -2736,7 +2867,7 @@
}
pm = htod32(pm);
WL_DBG(("power save %s\n", (pm ? "enabled" : "disabled")));
- err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), false);
+ err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), true);
if (unlikely(err)) {
if (err == -ENODEV)
WL_DBG(("net_device is not ready yet\n"));
@@ -2796,8 +2927,11 @@
static s32 wl_cfg80211_suspend(struct wiphy *wiphy)
#endif
{
+#ifdef DHD_CLEAR_ON_SUSPEND
struct wl_priv *wl = wiphy_priv(wiphy);
- s32 err = 0;
+ struct net_device *ndev = wl_to_prmry_ndev(wl);
+ unsigned long flags;
+
if (unlikely(!wl_get_drv_status(wl, READY))) {
WL_INFO(("device is not ready : status (%d)\n",
(int)wl->status));
@@ -2806,14 +2940,19 @@
wl_set_drv_status(wl, SCAN_ABORTING);
wl_term_iscan(wl);
+ flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
if (wl->scan_request) {
cfg80211_scan_done(wl->scan_request, true);
wl->scan_request = NULL;
}
wl_clr_drv_status(wl, SCANNING);
wl_clr_drv_status(wl, SCAN_ABORTING);
-
- return err;
+ dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+ if (wl_get_drv_status(wl, CONNECTING)) {
+ wl_bss_connect_done(wl, ndev, NULL, NULL, false);
+ }
+#endif
+ return 0;
}
static __used s32
@@ -2982,12 +3121,14 @@
*out_params_size = params_size; /* rtn size to the caller */
return params;
}
+
s32
wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev)
{
- wl_scan_params_t *params;
- s32 params_size;
+ wl_scan_params_t *params = NULL;
+ s32 params_size = 0;
s32 err = BCME_OK;
+ unsigned long flags;
WL_DBG(("Enter\n"));
@@ -2996,15 +3137,26 @@
if (params == NULL) {
WL_ERR(("scan params allocation failed \n"));
err = -ENOMEM;
+ } else {
+ /* Do a scan abort to stop the driver's scan engine */
+ err = wldev_ioctl(ndev, WLC_SCAN, params, params_size, true);
+ if (err < 0) {
+ WL_ERR(("scan abort failed \n"));
+ }
}
- /* Do a scan abort to stop the driver's scan engine */
- err = wldev_ioctl(ndev, WLC_SCAN, params, params_size, false);
- if (err < 0) {
- WL_ERR(("scan abort failed \n"));
+ del_timer_sync(&wl->scan_timeout);
+ flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+ if (wl->scan_request) {
+ cfg80211_scan_done(wl->scan_request, true);
+ wl->scan_request = NULL;
}
-
+ wl_clr_drv_status(wl, SCANNING);
+ dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+ if (params)
+ kfree(params);
return err;
}
+
static s32
wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel * channel,
@@ -3078,6 +3230,7 @@
u32 wpsie_len = 0;
u16 fc;
bool ack = false;
+ wifi_p2p_pub_act_frame_t *act_frm;
WL_DBG(("Enter \n"));
/* find bssidx based on ndev */
bssidx = wl_cfgp2p_find_idx(wl, dev);
@@ -3130,9 +3283,6 @@
wl_cfgp2p_set_management_ie(wl, dev, bssidx,
VNDR_IE_PRBRSP_FLAG,
(u8 *)wps_ie, wpsie_len + p2pie_len);
- /* remove WLC_E_PROBREQ_MSG event to prevent HOSTAPD
- * from responding many probe request
- */
}
}
cfg80211_mgmt_tx_status(dev, *cookie, buf, len, true, GFP_KERNEL);
@@ -3179,27 +3329,21 @@
memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len);
+ act_frm = (wifi_p2p_pub_act_frame_t *) (action_frame->data);
+ WL_DBG(("action_frame->len: %d chan %d category %d subtype %d\n",
+ action_frame->len, af_params->channel,
+ act_frm->category, act_frm->subtype));
if (wl->p2p->vif_created) {
- wifi_p2p_pub_act_frame_t *act_frm =
- (wifi_p2p_pub_act_frame_t *) (action_frame->data);
/*
- * Have to change intented address from GO REQ or GO RSP and INVITE REQ
- * because wpa-supplicant use eth0 primary address
+ * To make sure to send successfully action frame, we have to turn off mpc
*/
if ((act_frm->subtype == P2P_PAF_GON_REQ)||
- (act_frm->subtype == P2P_PAF_GON_RSP)||
- (act_frm->subtype == P2P_PAF_GON_CONF)||
- (act_frm->subtype == P2P_PAF_INVITE_REQ)) {
- p2p_ie = wl_cfgp2p_find_p2pie(act_frm->elts,
- action_frame->len - P2P_PUB_AF_FIXED_LEN);
- #ifdef ENABLE_DRIVER_CHANGE_IFADDR /* We are now doing this in supplicant */
- wl_cfg80211_change_ifaddr((u8 *)p2p_ie, &wl->p2p.int_addr,
- P2P_SEID_INTINTADDR);
- wl_cfg80211_change_ifaddr((u8 *)p2p_ie, &wl->p2p.dev_addr,
- P2P_SEID_DEV_INFO);
- wl_cfg80211_change_ifaddr((u8 *)p2p_ie, &wl->p2p.dev_addr,
- P2P_SEID_GROUP_ID);
- #endif
+ (act_frm->subtype == P2P_PAF_GON_RSP)) {
+ wldev_iovar_setint(dev, "mpc", 0);
+ } else if (act_frm->subtype == P2P_PAF_GON_CONF) {
+ wldev_iovar_setint(dev, "mpc", 1);
+ } else if (act_frm->subtype == P2P_PAF_DEVDIS_REQ) {
+ af_params->dwell_time = WL_LONG_DWELL_TIME;
}
}
@@ -3263,8 +3407,10 @@
channel = ieee80211_frequency_to_channel(chan->center_freq);
WL_DBG(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n",
dev->ifindex, channel_type, channel));
- wldev_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel), false);
-
+ err = wldev_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel), true);
+ if (err < 0) {
+ WL_ERR(("WLC_SET_CHANNEL error %d chip may not be supporting this channel\n", err));
+ }
return err;
}
@@ -3519,7 +3665,7 @@
}
static s32
-wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
+wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
struct beacon_parameters *info)
{
s32 err = BCME_OK;
@@ -3545,7 +3691,7 @@
WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n",
info->interval, info->dtim_period, info->head_len, info->tail_len));
if (wl->p2p_supported && p2p_on(wl) &&
- (bssidx >= wl_to_p2p_bss_bssidx(wl,
+ (bssidx == wl_to_p2p_bss_bssidx(wl,
P2PAPI_BSSCFG_CONNECTION))) {
memset(beacon_ie, 0, sizeof(beacon_ie));
/* We don't need to set beacon for P2P_GO,
@@ -3593,10 +3739,10 @@
} else {
WL_ERR(("No P2PIE in beacon \n"));
}
+ /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
+ wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG,
beacon_ie, wpsie_len + p2pie_len);
- wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_ASSOCRSP_FLAG,
- beacon_ie, wpsie_len + p2pie_len);
/* find the RSN_IE */
if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len,
@@ -3606,24 +3752,25 @@
is_bssup = wl_cfgp2p_bss_isup(dev, bssidx);
if (!is_bssup && (wpa2_ie != NULL)) {
+ wldev_iovar_setint(dev, "mpc", 0);
if ((err = wl_validate_wpa2ie(dev, wpa2_ie, bssidx)) < 0) {
- WL_ERR(("WPA2 IE parsing error"));
- return BCME_ERROR;
+ WL_ERR(("WPA2 IE parsing error"));
+ goto exit;
}
- err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), false);
+ err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true);
if (err < 0) {
WL_ERR(("SET INFRA error %d\n", err));
- return err;
+ goto exit;
}
err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &wl->p2p->ssid,
sizeof(wl->p2p->ssid), ioctlbuf, sizeof(ioctlbuf), bssidx);
if (err < 0) {
WL_ERR(("GO SSID setting error %d\n", err));
- return err;
+ goto exit;
}
if ((err = wl_cfgp2p_bss(dev, bssidx, 1)) < 0) {
WL_ERR(("GO Bring up error %d\n", err));
- return err;
+ goto exit;
}
}
} else if (wl_get_drv_status(wl, AP_CREATING)) {
@@ -3638,9 +3785,9 @@
WL_DBG(("SSID is (%s) in Head \n", ssid.SSID));
ssid.SSID_len = ssid_ie->len;
wldev_iovar_setint(dev, "mpc", 0);
- wldev_ioctl(dev, WLC_DOWN, &ap, sizeof(s32), false);
- wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), false);
- if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), false)) < 0) {
+ wldev_ioctl(dev, WLC_DOWN, &ap, sizeof(s32), true);
+ wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true);
+ if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) {
WL_ERR(("setting AP mode failed %d \n", err));
return err;
}
@@ -3661,9 +3808,18 @@
return BCME_ERROR;
}
wl->ap_info->security_mode = true;
- kfree(wl->ap_info->rsn_ie);
- kfree(wl->ap_info->wpa_ie);
- kfree(wl->ap_info->wps_ie);
+ if (wl->ap_info->rsn_ie) {
+ kfree(wl->ap_info->rsn_ie);
+ wl->ap_info->rsn_ie = NULL;
+ }
+ if (wl->ap_info->wpa_ie) {
+ kfree(wl->ap_info->wpa_ie);
+ wl->ap_info->wpa_ie = NULL;
+ }
+ if (wl->ap_info->wps_ie) {
+ kfree(wl->ap_info->wps_ie);
+ wl->ap_info->wps_ie = NULL;
+ }
if (wpa_ie != NULL) {
/* WPAIE */
wl->ap_info->rsn_ie = NULL;
@@ -3696,8 +3852,25 @@
} else {
WL_DBG(("No WPSIE in beacon \n"));
}
- wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), false);
-
+ if (info->interval) {
+ if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD,
+ &info->interval, sizeof(s32), true)) < 0) {
+ WL_ERR(("Beacon Interval Set Error, %d\n", err));
+ return err;
+ }
+ }
+ if (info->dtim_period) {
+ if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD,
+ &info->dtim_period, sizeof(s32), true)) < 0) {
+ WL_ERR(("DTIM Interval Set Error, %d\n", err));
+ return err;
+ }
+ }
+ err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true);
+ if (unlikely(err)) {
+ WL_ERR(("WLC_UP error (%d)\n", err));
+ return err;
+ }
memset(&join_params, 0, sizeof(join_params));
/* join parameters starts with ssid */
join_params_size = sizeof(join_params.ssid);
@@ -3705,7 +3878,7 @@
join_params.ssid.SSID_len = htod32(ssid.SSID_len);
/* create softap */
if ((err = wldev_ioctl(dev, WLC_SET_SSID, &join_params,
- join_params_size, false)) == 0) {
+ join_params_size, true)) == 0) {
wl_clr_drv_status(wl, AP_CREATING);
wl_set_drv_status(wl, AP_CREATED);
}
@@ -3811,29 +3984,12 @@
WL_ERR(("No WPSIE in beacon \n"));
}
}
- return 0;
-}
-
-#if defined(ANDROID_WIRELESS_PATCH)
-static s32
-wl_cfg80211_drv_start(struct wiphy *wiphy, struct net_device *dev)
-{
- s32 err = 0;
-
- printk("Android driver start command\n");
+exit:
+ if (err)
+ wldev_iovar_setint(dev, "mpc", 1);
return err;
}
-static s32
-wl_cfg80211_drv_stop(struct wiphy *wiphy, struct net_device *dev)
-{
- s32 err = 0;
-
- printk("Android driver stop command\n");
- return err;
-}
-#endif /* defined(ANDROID_WIRELESS_PATCH) */
-
static struct cfg80211_ops wl_cfg80211_ops = {
.add_virtual_intf = wl_cfg80211_add_virtual_iface,
.del_virtual_intf = wl_cfg80211_del_virtual_iface,
@@ -3864,11 +4020,8 @@
.mgmt_frame_register = wl_cfg80211_mgmt_frame_register,
.change_bss = wl_cfg80211_change_bss,
.set_channel = wl_cfg80211_set_channel,
- .set_beacon = wl_cfg80211_set_beacon,
-#if defined(ANDROID_WIRELESS_PATCH)
- .drv_start = wl_cfg80211_drv_start,
- .drv_stop = wl_cfg80211_drv_stop
-#endif
+ .set_beacon = wl_cfg80211_add_set_beacon,
+ .add_beacon = wl_cfg80211_add_set_beacon,
};
static s32 wl_mode_to_nl80211_iftype(s32 mode)
@@ -4003,7 +4156,7 @@
struct wl_scan_req *sr = wl_to_sr(wl);
struct beacon_proberesp *beacon_proberesp;
s32 mgmt_type;
- u32 signal;
+ s32 signal;
u32 freq;
s32 err = 0;
@@ -4025,7 +4178,7 @@
band = wiphy->bands[IEEE80211_BAND_2GHZ];
else
band = wiphy->bands[IEEE80211_BAND_5GHZ];
- notif_bss_info->rssi = bi->RSSI;
+ notif_bss_info->rssi = dtoh16(bi->RSSI);
memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN);
mgmt_type = wl->active_scan ?
IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON;
@@ -4039,15 +4192,7 @@
beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period);
beacon_proberesp->capab_info = cpu_to_le16(bi->capability);
wl_rst_ie(wl);
- /*
- * wl_add_ie is not necessary because it can only add duplicated
- * SSID, rate information to frame_buf
- */
- /*
- * wl_add_ie(wl, WLAN_EID_SSID, bi->SSID_len, bi->SSID);
- * wl_add_ie(wl, WLAN_EID_SUPP_RATES, bi->rateset.count,
- * bi->rateset.rates);
- */
+
wl_mrg_ie(wl, ((u8 *) bi) + bi->ie_offset, bi->ie_length);
wl_cp_ie(wl, beacon_proberesp->variable, WL_BSS_INFO_MAX -
offsetof(struct wl_cfg80211_bss_info, frame_buf));
@@ -4060,15 +4205,16 @@
#endif
channel = ieee80211_get_channel(wiphy, freq);
- WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM\n",
- bi->SSID,
- notif_bss_info->rssi, notif_bss_info->channel,
- mgmt->u.beacon.capab_info, &bi->BSSID));
+ WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM"
+ "mgmt_type %d frame_len %d\n", bi->SSID,
+ notif_bss_info->rssi, notif_bss_info->channel,
+ mgmt->u.beacon.capab_info, &bi->BSSID, mgmt_type,
+ notif_bss_info->frame_len));
signal = notif_bss_info->rssi * 100;
+
if (unlikely(!cfg80211_inform_bss_frame(wiphy, channel, mgmt,
- le16_to_cpu
- (notif_bss_info->frame_len),
+ le16_to_cpu(notif_bss_info->frame_len),
signal, GFP_KERNEL))) {
WL_ERR(("cfg80211_inform_bss_frame error\n"));
kfree(notif_bss_info);
@@ -4154,13 +4300,15 @@
channel_info_t ci;
memset(body, 0, sizeof(body));
+ memset(&bssid, 0, ETHER_ADDR_LEN);
WL_DBG(("Enter \n"));
if (get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
memcpy(body, data, len);
wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
- &da, sizeof(struct ether_addr), ioctlbuf, sizeof(ioctlbuf), bsscfgidx);
- wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
+ NULL, 0, ioctlbuf, sizeof(ioctlbuf), bsscfgidx);
+ memcpy(da.octet, ioctlbuf, ETHER_ADDR_LEN);
+ err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
switch (event) {
case WLC_E_ASSOC_IND:
fc = FC_ASSOC_REQ;
@@ -4172,10 +4320,10 @@
fc = FC_DISASSOC;
break;
case WLC_E_DEAUTH_IND:
- fc = FC_DEAUTH;
+ fc = FC_DISASSOC;
break;
case WLC_E_DEAUTH:
- fc = FC_DEAUTH;
+ fc = FC_DISASSOC;
break;
default:
fc = 0;
@@ -4203,28 +4351,30 @@
isfree = true;
if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) {
- cfg80211_send_rx_assoc(ndev, mgmt_frame, len);
+ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
} else if (event == WLC_E_DISASSOC_IND) {
- cfg80211_send_disassoc(ndev, mgmt_frame, len);
+ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
} else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
- cfg80211_send_deauth(ndev, mgmt_frame, len);
+ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
}
} else {
WL_DBG(("wl_notify_connect_status : event %d status : %d \n",
- ntoh32(e->event_type), ntoh32(e->status)));
+ ntoh32(e->event_type), ntoh32(e->status)));
if (wl_is_linkup(wl, e, ndev)) {
wl_link_up(wl);
act = true;
wl_update_prof(wl, e, &act, WL_PROF_ACT);
+ wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
if (wl_is_ibssmode(wl, ndev)) {
- printk("cfg80211_ibss_joined");
+ printk("cfg80211_ibss_joined\n");
cfg80211_ibss_joined(ndev, (s8 *)&e->addr,
GFP_KERNEL);
WL_DBG(("joined in IBSS network\n"));
} else {
if (!wl_get_drv_status(wl, DISCONNECTING)) {
- printk("wl_bss_connect_done succeeded");
+ printk("wl_bss_connect_done succeeded status=(0x%x)\n",
+ (int)wl->status);
wl_bss_connect_done(wl, ndev, e, data, true);
WL_DBG(("joined in BSS network \"%s\"\n",
((struct wlc_ssid *)
@@ -4234,31 +4384,51 @@
} else if (wl_is_linkdown(wl, e)) {
if (wl->scan_request) {
+ del_timer_sync(&wl->scan_timeout);
if (wl->escan_on) {
wl_notify_escan_complete(wl, true);
} else
wl_iscan_aborted(wl);
}
if (wl_get_drv_status(wl, CONNECTED)) {
- printk("link down, call cfg80211_disconnected ");
+ scb_val_t scbval;
+ u8 *curbssid = wl_read_prof(wl, WL_PROF_BSSID);
+ printk("link down, call cfg80211_disconnected\n");
wl_clr_drv_status(wl, CONNECTED);
+ /* To make sure disconnect, explictly send dissassoc
+ * for BSSID 00:00:00:00:00:00 issue
+ */
+ scbval.val = WLAN_REASON_DEAUTH_LEAVING;
+
+ memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
+ scbval.val = htod32(scbval.val);
+ wldev_ioctl(ndev, WLC_DISASSOC, &scbval,
+ sizeof(scb_val_t), true);
cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL);
wl_link_down(wl);
- wl_init_prof(wl->profile);
+ wl_init_prof(wl);
} else if (wl_get_drv_status(wl, CONNECTING)) {
- printk("link down, during connecting");
+ printk("link down, during connecting\n");
wl_bss_connect_done(wl, ndev, e, data, false);
}
wl_clr_drv_status(wl, DISCONNECTING);
} else if (wl_is_nonetwork(wl, e)) {
- printk("connect failed e->status 0x%x", (int)ntoh32(e->status));
+ printk("connect failed event=%d e->status 0x%x\n",
+ event, (int)ntoh32(e->status));
+ /* Clean up any pending scan request */
+ if (wl->scan_request) {
+ del_timer_sync(&wl->scan_timeout);
+ if (wl->escan_on) {
+ wl_notify_escan_complete(wl, true);
+ } else
+ wl_iscan_aborted(wl);
+ }
if (wl_get_drv_status(wl, CONNECTING))
wl_bss_connect_done(wl, ndev, e, data, false);
} else {
printk("%s nothing\n", __FUNCTION__);
}
- printk("\n");
}
exit:
if (isfree)
@@ -4282,6 +4452,7 @@
wl_bss_connect_done(wl, ndev, e, data, true);
act = true;
wl_update_prof(wl, e, &act, WL_PROF_ACT);
+ wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
}
return err;
}
@@ -4295,7 +4466,7 @@
buflen = bcm_mkiovar(name, buf, len, wl->ioctl_buf, WL_IOCTL_LEN_MAX);
BUG_ON(unlikely(!buflen));
- return wldev_ioctl(dev, WLC_SET_VAR, wl->ioctl_buf, buflen, false);
+ return wldev_ioctl(dev, WLC_SET_VAR, wl->ioctl_buf, buflen, true);
}
static s32
@@ -4398,7 +4569,7 @@
join_params->params.chanspec_num = 1;
join_params->params.chanspec_list[0] = ch;
- if (join_params->params.chanspec_list[0])
+ if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL)
chanspec |= WL_CHANSPEC_BAND_2G;
else
chanspec |= WL_CHANSPEC_BAND_5G;
@@ -4433,6 +4604,7 @@
u8 dtim_period;
size_t ie_len;
u8 *ie;
+ u8 *curbssid;
s32 err = 0;
struct wiphy *wiphy;
wiphy = wl_to_wiphy(wl);
@@ -4441,22 +4613,23 @@
return err;
ssid = (struct wlc_ssid *)wl_read_prof(wl, WL_PROF_SSID);
- bss = cfg80211_get_bss(wiphy, NULL, (s8 *)&wl->bssid,
+ curbssid = wl_read_prof(wl, WL_PROF_BSSID);
+ bss = cfg80211_get_bss(wiphy, NULL, curbssid,
ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_ESS,
WLAN_CAPABILITY_ESS);
- rtnl_lock();
+ mutex_lock(&wl->usr_sync);
if (unlikely(!bss)) {
WL_DBG(("Could not find the AP\n"));
*(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX);
- err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_BSS_INFO,
+ err = wldev_ioctl(ndev, WLC_GET_BSS_INFO,
wl->extra_buf, WL_EXTRA_BUF_MAX, false);
if (unlikely(err)) {
WL_ERR(("Could not get bss info %d\n", err));
goto update_bss_info_out;
}
bi = (struct wl_bss_info *)(wl->extra_buf + 4);
- if (unlikely(memcmp(&bi->BSSID, &wl->bssid, ETHER_ADDR_LEN))) {
+ if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) {
err = -EIO;
goto update_bss_info_out;
}
@@ -4484,7 +4657,7 @@
* information out of probe response.
* so we speficially query dtim information to dongle.
*/
- err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_DTIMPRD,
+ err = wldev_ioctl(ndev, WLC_GET_DTIMPRD,
&dtim_period, sizeof(dtim_period), false);
if (unlikely(err)) {
WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err));
@@ -4496,7 +4669,7 @@
wl_update_prof(wl, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
update_bss_info_out:
- rtnl_unlock();
+ mutex_unlock(&wl->usr_sync);
return err;
}
@@ -4506,16 +4679,18 @@
{
struct wl_connect_info *conn_info = wl_to_conn(wl);
s32 err = 0;
+ u8 *curbssid;
wl_get_assoc_ies(wl, ndev);
- memcpy(&wl->bssid, &e->addr, ETHER_ADDR_LEN);
+ wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
+ curbssid = wl_read_prof(wl, WL_PROF_BSSID);
wl_update_bss_info(wl, ndev);
wl_update_pmklist(ndev, wl->pmk_list, err);
cfg80211_roamed(ndev,
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)
NULL,
#endif
- (u8 *)&wl->bssid,
+ curbssid,
conn_info->req_ie, conn_info->req_ie_len,
conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
WL_DBG(("Report roaming result\n"));
@@ -4531,30 +4706,33 @@
{
struct wl_connect_info *conn_info = wl_to_conn(wl);
s32 err = 0;
-
+ u8 *curbssid = wl_read_prof(wl, WL_PROF_BSSID);
WL_DBG((" enter\n"));
if (wl->scan_request) {
- wl_cfg80211_scan_abort(wl, ndev);
+ wl_cfg80211_scan_abort(wl, ndev);
}
if (wl_get_drv_status(wl, CONNECTING)) {
wl_clr_drv_status(wl, CONNECTING);
if (completed) {
wl_get_assoc_ies(wl, ndev);
- memcpy(&wl->bssid, &e->addr, ETHER_ADDR_LEN);
+ wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
+ curbssid = wl_read_prof(wl, WL_PROF_BSSID);
wl_update_bss_info(wl, ndev);
wl_update_pmklist(ndev, wl->pmk_list, err);
wl_set_drv_status(wl, CONNECTED);
}
cfg80211_connect_result(ndev,
- (u8 *)&wl->bssid,
+ curbssid,
conn_info->req_ie,
conn_info->req_ie_len,
conn_info->resp_ie,
conn_info->resp_ie_len,
completed ? WLAN_STATUS_SUCCESS : WLAN_STATUS_AUTH_TIMEOUT,
GFP_KERNEL);
- WL_DBG(("Report connect result - connection %s\n",
- completed ? "succeeded" : "failed"));
+ if (completed)
+ WL_INFO(("Report connect result - connection succeeded\n"));
+ else
+ WL_ERR(("Report connect result - connection failed\n"));
}
return err;
}
@@ -4566,7 +4744,7 @@
u16 flags = ntoh16(e->flags);
enum nl80211_key_type key_type;
- rtnl_lock();
+ mutex_lock(&wl->usr_sync);
if (flags & WLC_EVENT_MSG_GROUP)
key_type = NL80211_KEYTYPE_GROUP;
else
@@ -4574,7 +4752,7 @@
cfg80211_michael_mic_failure(ndev, (u8 *)&e->addr, key_type, -1,
NULL, GFP_KERNEL);
- rtnl_unlock();
+ mutex_unlock(&wl->usr_sync);
return 0;
}
@@ -4587,18 +4765,14 @@
struct wl_scan_results *bss_list;
u32 len = WL_SCAN_BUF_MAX;
s32 err = 0;
+ unsigned long flags;
WL_DBG(("Enter \n"));
if (wl->iscan_on && wl->iscan_kickstart)
return wl_wakeup_iscan(wl_to_iscan(wl));
- if (unlikely(!wl_get_drv_status(wl, SCANNING))) {
- wl_clr_drv_status(wl, SCANNING);
- WL_DBG(("Scan complete while device not scanning\n"));
- return -EINVAL;
- }
+ mutex_lock(&wl->usr_sync);
wl_clr_drv_status(wl, SCANNING);
- rtnl_lock();
err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform,
sizeof(channel_inform), false);
if (unlikely(err)) {
@@ -4626,16 +4800,17 @@
bss_list->count = dtoh32(bss_list->count);
err = wl_inform_bss(wl);
- if (err)
- goto scan_done_out;
scan_done_out:
+ del_timer_sync(&wl->scan_timeout);
+ flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
if (wl->scan_request) {
WL_DBG(("cfg80211_scan_done\n"));
cfg80211_scan_done(wl->scan_request, false);
wl->scan_request = NULL;
}
- rtnl_unlock();
+ dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+ mutex_unlock(&wl->usr_sync);
return err;
}
static s32
@@ -4690,13 +4865,16 @@
bool isfree = false;
s32 err = 0;
s32 freq;
+ wifi_p2p_pub_act_frame_t *act_frm;
wl_event_rx_frame_data_t *rxframe =
(wl_event_rx_frame_data_t*)data;
u32 event = ntoh32(e->event_type);
u8 *mgmt_frame;
u8 bsscfgidx = e->bsscfgidx;
u32 mgmt_frame_len = ntoh32(e->datalen) - sizeof(wl_event_rx_frame_data_t);
- u16 channel = ((ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK) & 0x0f);
+ u16 channel = ((ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK));
+
+ memset(&bssid, 0, ETHER_ADDR_LEN);
if (channel <= CH_MAX_2G_CHANNEL)
band = wiphy->bands[IEEE80211_BAND_2GHZ];
else
@@ -4709,8 +4887,10 @@
#endif
if (event == WLC_E_ACTION_FRAME_RX) {
wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
- &da, sizeof(struct ether_addr), ioctlbuf, sizeof(ioctlbuf), bsscfgidx);
+ NULL, 0, ioctlbuf, sizeof(ioctlbuf), bsscfgidx);
+
wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
+ memcpy(da.octet, ioctlbuf, ETHER_ADDR_LEN);
err = wl_frame_get_mgmt(FC_ACTION, &da, &e->addr, &bssid,
&mgmt_frame, &mgmt_frame_len,
(u8 *)((wl_event_rx_frame_data_t *)rxframe + 1));
@@ -4720,6 +4900,14 @@
goto exit;
}
isfree = true;
+ act_frm =
+ (wifi_p2p_pub_act_frame_t *) (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
+ /*
+ * After complete GO Negotiation, roll back to mpc mode
+ */
+ if (act_frm->subtype == P2P_PAF_GON_CONF) {
+ wldev_iovar_setint(ndev, "mpc", 1);
+ }
} else {
mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1);
}
@@ -4750,9 +4938,13 @@
conf->tx_power = -1;
}
-static void wl_init_prof(struct wl_profile *prof)
+static void wl_init_prof(struct wl_priv *wl)
{
- memset(prof, 0, sizeof(*prof));
+ unsigned long flags;
+
+ flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+ memset(wl->profile, 0, sizeof(struct wl_profile));
+ dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
}
static void wl_init_event_handler(struct wl_priv *wl)
@@ -4760,7 +4952,6 @@
memset(wl->evt_handler, 0, sizeof(wl->evt_handler));
wl->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status;
- /* wl->evt_handler[WLC_E_JOIN] = wl_notify_connect_status; */
wl->evt_handler[WLC_E_LINK] = wl_notify_connect_status;
wl->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status;
wl->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status;
@@ -4838,7 +5029,11 @@
WL_ERR(("pmk list alloc failed\n"));
goto init_priv_mem_out;
}
-
+ wl->sta_info = (void *)kzalloc(sizeof(*wl->sta_info), GFP_KERNEL);
+ if (unlikely(!wl->sta_info)) {
+ WL_ERR(("sta info alloc failed\n"));
+ goto init_priv_mem_out;
+ }
return 0;
init_priv_mem_out:
@@ -4871,6 +5066,8 @@
wl->fw = NULL;
kfree(wl->pmk_list);
wl->pmk_list = NULL;
+ kfree(wl->sta_info);
+ wl->sta_info = NULL;
if (wl->ap_info) {
kfree(wl->ap_info->wpa_ie);
kfree(wl->ap_info->rsn_ie);
@@ -4915,6 +5112,7 @@
static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted)
{
struct wl_priv *wl = iscan_to_wl(iscan);
+ unsigned long flags;
WL_DBG(("Enter \n"));
if (unlikely(!wl_get_drv_status(wl, SCANNING))) {
@@ -4922,11 +5120,13 @@
WL_ERR(("Scan complete while device not scanning\n"));
return;
}
+ flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
wl_clr_drv_status(wl, SCANNING);
if (likely(wl->scan_request)) {
cfg80211_scan_done(wl->scan_request, aborted);
wl->scan_request = NULL;
}
+ dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
wl->iscan_kickstart = false;
}
@@ -4984,10 +5184,10 @@
s32 err = 0;
iscan->state = WL_ISCAN_STATE_IDLE;
- rtnl_lock();
+ mutex_lock(&wl->usr_sync);
wl_inform_bss(wl);
wl_notify_iscan_complete(iscan, false);
- rtnl_unlock();
+ mutex_unlock(&wl->usr_sync);
return err;
}
@@ -5009,10 +5209,10 @@
struct wl_iscan_ctrl *iscan = wl->iscan;
s32 err = 0;
- rtnl_lock();
+ mutex_lock(&wl->usr_sync);
wl_inform_bss(wl);
wl_run_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE);
- rtnl_unlock();
+ mutex_unlock(&wl->usr_sync);
/* Reschedule the timer */
mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
iscan->timer_on = 1;
@@ -5026,9 +5226,9 @@
s32 err = 0;
iscan->state = WL_ISCAN_STATE_IDLE;
- rtnl_lock();
+ mutex_lock(&wl->usr_sync);
wl_notify_iscan_complete(iscan, true);
- rtnl_unlock();
+ mutex_unlock(&wl->usr_sync);
return err;
}
@@ -5051,13 +5251,13 @@
del_timer_sync(&iscan->timer);
iscan->timer_on = 0;
}
- rtnl_lock();
+ mutex_lock(&wl->usr_sync);
err = wl_get_iscan_results(iscan, &status, &wl->bss_list);
if (unlikely(err)) {
status = WL_SCAN_RESULTS_ABORTED;
WL_ERR(("Abort iscan\n"));
}
- rtnl_unlock();
+ mutex_unlock(&wl->usr_sync);
iscan->iscan_handler[status] (wl);
}
if (iscan->timer_on) {
@@ -5069,6 +5269,19 @@
return 0;
}
+static void wl_scan_timeout(unsigned long data)
+{
+ struct wl_priv *wl = (struct wl_priv *)data;
+
+ if (wl->scan_request) {
+ WL_ERR(("timer expired\n"));
+ if (wl->escan_on)
+ wl_notify_escan_complete(wl, true);
+ else
+ wl_notify_iscan_complete(wl_to_iscan(wl), true);
+ }
+}
+
static void wl_iscan_timer(unsigned long data)
{
struct wl_iscan_ctrl *iscan = (struct wl_iscan_ctrl *)data;
@@ -5111,21 +5324,19 @@
static void wl_notify_escan_complete(struct wl_priv *wl, bool aborted)
{
+ unsigned long flags;
+
WL_DBG(("Enter \n"));
- if (unlikely(!wl_get_drv_status(wl, SCANNING))) {
- wl_clr_drv_status(wl, SCANNING);
- WL_ERR(("Scan complete while device not scanning\n"));
- wl->scan_request = NULL;
- return;
- }
wl_clr_drv_status(wl, SCANNING);
if (wl->p2p_supported && p2p_on(wl))
wl_clr_p2p_status(wl, SCANNING);
+ flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
if (likely(wl->scan_request)) {
cfg80211_scan_done(wl->scan_request, aborted);
wl->scan_request = NULL;
}
+ dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
}
static s32 wl_escan_handler(struct wl_priv *wl,
@@ -5210,23 +5421,37 @@
else if (status == WLC_E_STATUS_SUCCESS) {
wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
if (likely(wl->scan_request)) {
- rtnl_lock();
+ mutex_lock(&wl->usr_sync);
+ del_timer_sync(&wl->scan_timeout);
WL_INFO(("ESCAN COMPLETED\n"));
wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
wl_inform_bss(wl);
wl_notify_escan_complete(wl, false);
- rtnl_unlock();
+ mutex_unlock(&wl->usr_sync);
}
}
else if (status == WLC_E_STATUS_ABORT) {
wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
if (likely(wl->scan_request)) {
- rtnl_lock();
+ mutex_lock(&wl->usr_sync);
+ del_timer_sync(&wl->scan_timeout);
WL_INFO(("ESCAN ABORTED\n"));
wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
wl_inform_bss(wl);
wl_notify_escan_complete(wl, true);
- rtnl_unlock();
+ mutex_unlock(&wl->usr_sync);
+ }
+ }
+ else {
+ WL_ERR(("unexpected Escan Event %d : abort\n", status));
+ wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
+ if (likely(wl->scan_request)) {
+ mutex_lock(&wl->usr_sync);
+ del_timer_sync(&wl->scan_timeout);
+ wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
+ wl_inform_bss(wl);
+ wl_notify_escan_complete(wl, true);
+ mutex_unlock(&wl->usr_sync);
}
}
exit:
@@ -5258,6 +5483,10 @@
wl->evt_handler[WLC_E_ESCAN_RESULT] = wl_escan_handler;
wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
}
+ /* Init scan_timeout timer */
+ init_timer(&wl->scan_timeout);
+ wl->scan_timeout.data = (unsigned long) wl;
+ wl->scan_timeout.function = wl_scan_timeout;
return err;
}
@@ -5300,7 +5529,7 @@
return err;
wl_init_fw(wl->fw);
wl_init_conf(wl->conf);
- wl_init_prof(wl->profile);
+ wl_init_prof(wl);
wl_link_down(wl);
return err;
@@ -5312,6 +5541,7 @@
wl->dongle_up = false; /* dongle down */
wl_flush_eq(wl);
wl_link_down(wl);
+ del_timer_sync(&wl->scan_timeout);
wl_term_iscan(wl);
wl_deinit_priv_mem(wl);
}
@@ -5407,6 +5637,11 @@
goto cfg80211_attach_out;
}
#endif
+#if defined(COEX_DHCP)
+ if (wl_cfg80211_btcoex_init(wl))
+ goto cfg80211_attach_out;
+#endif /* COEX_DHCP */
+
wlcfg_drv_priv = wl;
return err;
@@ -5423,6 +5658,11 @@
wl = wlcfg_drv_priv;
WL_TRACE(("In\n"));
+
+#if defined(COEX_DHCP)
+ wl_cfg80211_btcoex_deinit(wl);
+#endif /* COEX_DHCP */
+
#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
if (wl_sysctl_hdr)
unregister_sysctl_table(wl_sysctl_hdr);
@@ -5438,8 +5678,10 @@
static void wl_wakeup_event(struct wl_priv *wl)
{
- if (wl->event_tsk.thr_pid >= 0)
+ if (wl->event_tsk.thr_pid >= 0) {
+ DHD_OS_WAKE_LOCK(wl->pub);
up(&wl->event_tsk.sema);
+ }
}
static s32 wl_event_handler(void *data)
@@ -5456,21 +5698,19 @@
SMP_RD_BARRIER_DEPENDS();
if (tsk->terminated)
break;
- e = wl_deq_event(wl);
- if (unlikely(!e)) {
- WL_ERR(("equeue empty..\n"));
- return 0;
+ while ((e = wl_deq_event(wl))) {
+ WL_DBG(("event type (%d), if idx: %d\n", e->etype, e->emsg.ifidx));
+ netdev = dhd_idx2net((struct dhd_pub *)(wl->pub), e->emsg.ifidx);
+ if (!netdev)
+ netdev = wl_to_prmry_ndev(wl);
+ if (e->etype < WLC_E_LAST && wl->evt_handler[e->etype]) {
+ wl->evt_handler[e->etype] (wl, netdev, &e->emsg, e->edata);
+ } else {
+ WL_DBG(("Unknown Event (%d): ignoring\n", e->etype));
+ }
+ wl_put_event(e);
}
- WL_DBG(("event type (%d), if idx: %d\n", e->etype, e->emsg.ifidx));
- netdev = dhd_idx2net((struct dhd_pub *)(wl->pub), e->emsg.ifidx);
- if (!netdev)
- netdev = wl_to_prmry_ndev(wl);
- if (e->etype < WLC_E_LAST && wl->evt_handler[e->etype]) {
- wl->evt_handler[e->etype] (wl, netdev, &e->emsg, e->edata);
- } else {
- WL_DBG(("Unknown Event (%d): ignoring\n", e->etype));
- }
- wl_put_event(e);
+ DHD_OS_WAKE_UNLOCK(wl->pub);
}
WL_DBG(("%s was terminated\n", __func__));
complete_and_exit(&tsk->completed, 0);
@@ -5489,6 +5729,9 @@
WL_DBG(("event_type (%d):" "WLC_E_" "%s\n", event_type, estr));
#endif /* (WL_DBG_LEVEL > 0) */
+ if (event_type == WLC_E_PFN_NET_FOUND)
+ WL_ERR((" PNO Event\n"));
+
if (likely(!wl_enq_event(wl, ndev, event_type, e, data)))
wl_wakeup_event(wl);
}
@@ -5502,14 +5745,15 @@
static void wl_flush_eq(struct wl_priv *wl)
{
struct wl_event_q *e;
+ unsigned long flags;
- wl_lock_eq(wl);
+ flags = wl_lock_eq(wl);
while (!list_empty(&wl->eq_list)) {
e = list_first_entry(&wl->eq_list, struct wl_event_q, eq_list);
list_del(&e->eq_list);
kfree(e);
}
- wl_unlock_eq(wl);
+ wl_unlock_eq(wl, flags);
}
/*
@@ -5519,13 +5763,14 @@
static struct wl_event_q *wl_deq_event(struct wl_priv *wl)
{
struct wl_event_q *e = NULL;
+ unsigned long flags;
- wl_lock_eq(wl);
+ flags = wl_lock_eq(wl);
if (likely(!list_empty(&wl->eq_list))) {
e = list_first_entry(&wl->eq_list, struct wl_event_q, eq_list);
list_del(&e->eq_list);
}
- wl_unlock_eq(wl);
+ wl_unlock_eq(wl, flags);
return e;
}
@@ -5542,12 +5787,15 @@
s32 err = 0;
uint32 evtq_size;
uint32 data_len;
+ unsigned long flags;
+ gfp_t aflags;
data_len = 0;
if (data)
data_len = ntoh32(msg->datalen);
evtq_size = sizeof(struct wl_event_q) + data_len;
- e = kzalloc(evtq_size, GFP_ATOMIC);
+ aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
+ e = kzalloc(evtq_size, aflags);
if (unlikely(!e)) {
WL_ERR(("event alloc failed\n"));
return -ENOMEM;
@@ -5556,9 +5804,9 @@
memcpy(&e->emsg, msg, sizeof(wl_event_msg_t));
if (data)
memcpy(e->edata, data, data_len);
- wl_lock_eq(wl);
+ flags = wl_lock_eq(wl);
list_add_tail(&e->eq_list, &wl->eq_list);
- wl_unlock_eq(wl);
+ wl_unlock_eq(wl, flags);
return err;
}
@@ -5614,7 +5862,7 @@
return err;
}
infra = htod32(infra);
- err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), false);
+ err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), true);
if (unlikely(err)) {
WL_ERR(("WLC_SET_INFRA error (%d)\n", err));
return err;
@@ -5632,7 +5880,7 @@
s32 err = 0;
/* Setup event_msgs */
- bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
+ bcm_mkiovar("event_msgs", NULL, 0, iovbuf,
sizeof(iovbuf));
err = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false);
if (unlikely(err)) {
@@ -5647,7 +5895,7 @@
}
bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), false);
+ err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
if (unlikely(err)) {
WL_ERR(("Set event_msgs error (%d)\n", err));
goto dongle_eventmsg_out;
@@ -5658,57 +5906,6 @@
}
-static s32 wl_dongle_eventmsg(struct net_device *ndev)
-{
- s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
-
- s8 eventmask[WL_EVENTING_MASK_LEN];
- s32 err = 0;
-
- /* Setup event_msgs */
- bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
- sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false);
- if (unlikely(err)) {
- WL_ERR(("Get event_msgs error (%d)\n", err));
- goto dongle_eventmsg_out;
- }
- memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
-
- setbit(eventmask, WLC_E_SET_SSID);
- setbit(eventmask, WLC_E_PRUNE);
- setbit(eventmask, WLC_E_AUTH);
- setbit(eventmask, WLC_E_REASSOC);
- setbit(eventmask, WLC_E_REASSOC_IND);
- setbit(eventmask, WLC_E_DEAUTH_IND);
- setbit(eventmask, WLC_E_DEAUTH);
- setbit(eventmask, WLC_E_DISASSOC_IND);
- setbit(eventmask, WLC_E_DISASSOC);
- setbit(eventmask, WLC_E_JOIN);
- setbit(eventmask, WLC_E_ROAM);
- setbit(eventmask, WLC_E_ASSOC_IND);
- setbit(eventmask, WLC_E_LINK);
- setbit(eventmask, WLC_E_MIC_ERROR);
- setbit(eventmask, WLC_E_PMKID_CACHE);
- setbit(eventmask, WLC_E_TXFAIL);
- setbit(eventmask, WLC_E_SCAN_COMPLETE);
- setbit(eventmask, WLC_E_ACTION_FRAME_RX);
- setbit(eventmask, WLC_E_ACTION_FRAME_COMPLETE);
- setbit(eventmask, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE);
- setbit(eventmask, WLC_E_P2P_PROBREQ_MSG);
- setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE);
- setbit(eventmask, WLC_E_ESCAN_RESULT);
- bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
- sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), false);
- if (unlikely(err)) {
- WL_ERR(("Set event_msgs error (%d)\n", err));
- goto dongle_eventmsg_out;
- }
-
-dongle_eventmsg_out:
- return err;
-}
#ifndef EMBEDDED_PLATFORM
static s32 wl_dongle_country(struct net_device *ndev, u8 ccode)
@@ -5723,7 +5920,7 @@
{
s32 err = 0;
- err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), false);
+ err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true);
if (unlikely(err)) {
WL_ERR(("WLC_UP error (%d)\n", err));
}
@@ -5735,7 +5932,7 @@
s32 err = 0;
WL_TRACE(("In\n"));
- err = wldev_ioctl(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode), false);
+ err = wldev_ioctl(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode), true);
if (unlikely(err)) {
WL_ERR(("WLC_SET_PM error (%d)\n", err));
}
@@ -5752,14 +5949,14 @@
/* Match Host and Dongle rx alignment */
bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf,
sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), false);
+ err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
if (unlikely(err)) {
WL_ERR(("txglomalign error (%d)\n", err));
goto dongle_glom_out;
}
/* disable glom option per default */
bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), false);
+ err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
if (unlikely(err)) {
WL_ERR(("txglom error (%d)\n", err));
goto dongle_glom_out;
@@ -5779,7 +5976,7 @@
if (roamvar) {
bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf,
sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), false);
+ err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
if (unlikely(err)) {
WL_ERR(("bcn_timeout error (%d)\n", err));
goto dongle_rom_out;
@@ -5787,7 +5984,7 @@
}
/* Enable/Disable built-in roaming to allow supplicant to take care of roaming */
bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), false);
+ err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
if (unlikely(err)) {
WL_ERR(("roam_off error (%d)\n", err));
goto dongle_rom_out;
@@ -5803,7 +6000,7 @@
s32 err = 0;
err = wldev_ioctl(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time,
- sizeof(scan_assoc_time), false);
+ sizeof(scan_assoc_time), true);
if (err) {
if (err == -EOPNOTSUPP) {
WL_INFO(("Scan assoc time is not supported\n"));
@@ -5813,7 +6010,7 @@
goto dongle_scantime_out;
}
err = wldev_ioctl(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time,
- sizeof(scan_unassoc_time), false);
+ sizeof(scan_unassoc_time), true);
if (err) {
if (err == -EOPNOTSUPP) {
WL_INFO(("Scan unassoc time is not supported\n"));
@@ -5837,7 +6034,7 @@
/* Set ARP offload */
bcm_mkiovar("arpoe", (char *)&arpoe, 4, iovbuf, sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), false);
+ err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
if (err) {
if (err == -EOPNOTSUPP)
WL_INFO(("arpoe is not supported\n"));
@@ -5847,7 +6044,7 @@
goto dongle_offload_out;
}
bcm_mkiovar("arp_ol", (char *)&arp_ol, 4, iovbuf, sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), false);
+ err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
if (err) {
if (err == -EOPNOTSUPP)
WL_INFO(("arp_ol is not supported\n"));
@@ -5946,7 +6143,7 @@
memcpy((char *)pkt_filterp, &pkt_filter,
WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
- err = wldev_ioctl(ndev, WLC_SET_VAR, buf, buf_len, false);
+ err = wldev_ioctl(ndev, WLC_SET_VAR, buf, buf_len, true);
if (err) {
if (err == -EOPNOTSUPP) {
WL_INFO(("filter not supported\n"));
@@ -5959,7 +6156,7 @@
/* set mode to allow pattern */
bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf,
sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), false);
+ err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
if (err) {
if (err == -EOPNOTSUPP) {
WL_INFO(("filter_mode not supported\n"));
@@ -5993,11 +6190,6 @@
wdev = ndev->ieee80211_ptr;
if (need_lock)
rtnl_lock();
- err = wl_dongle_eventmsg(ndev);
- if (unlikely(err)) {
- WL_ERR(("wl_dongle_eventmsg failed\n"));
- goto default_conf_out;
- }
#ifndef EMBEDDED_PLATFORM
err = wl_dongle_up(ndev, 0);
if (unlikely(err)) {
@@ -6024,12 +6216,6 @@
WL_ERR(("wl_dongle_roam failed\n"));
goto default_conf_out;
}
- err = wl_dongle_eventmsg(ndev);
- if (unlikely(err)) {
- WL_ERR(("wl_dongle_eventmsg failed\n"));
- goto default_conf_out;
- }
-
wl_dongle_scantime(ndev, 40, 80);
wl_dongle_offload(ndev, 1, 0xf);
wl_dongle_filter(ndev, 1);
@@ -6101,6 +6287,7 @@
static s32 __wl_cfg80211_down(struct wl_priv *wl)
{
s32 err = 0;
+ unsigned long flags;
WL_TRACE(("In\n"));
/* Check if cfg80211 interface is already down */
@@ -6110,6 +6297,7 @@
wl_set_drv_status(wl, SCAN_ABORTING);
wl_term_iscan(wl);
+ flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
if (wl->scan_request) {
cfg80211_scan_done(wl->scan_request, true);
wl->scan_request = NULL;
@@ -6123,9 +6311,11 @@
if (wl_get_drv_status(wl, AP_CREATED)) {
wl_clr_drv_status(wl, AP_CREATED);
wl_clr_drv_status(wl, AP_CREATING);
- wl_to_prmry_ndev(wl)->ieee80211_ptr->iftype =
- NL80211_IFTYPE_STATION;
}
+ wl_to_prmry_ndev(wl)->ieee80211_ptr->iftype =
+ NL80211_IFTYPE_STATION;
+ dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+
wl->dongle_up = false;
wl_flush_eq(wl);
wl_link_down(wl);
@@ -6155,6 +6345,20 @@
return err;
}
+/* Private Event to Supplicant with indication that FW hangs */
+int wl_cfg80211_hang(struct net_device *dev, u16 reason)
+{
+ struct wl_priv *wl;
+ wl = wlcfg_drv_priv;
+
+ WL_ERR(("In : FW crash Eventing\n"));
+ cfg80211_disconnected(dev, reason, NULL, 0, GFP_KERNEL);
+ if (wl != NULL) {
+ wl_link_down(wl);
+ }
+ return 0;
+}
+
s32 wl_cfg80211_down(void)
{
struct wl_priv *wl;
@@ -6168,6 +6372,7 @@
return err;
}
+
static s32 wl_dongle_probecap(struct wl_priv *wl)
{
s32 err = 0;
@@ -6181,18 +6386,28 @@
static void *wl_read_prof(struct wl_priv *wl, s32 item)
{
+ unsigned long flags;
+ void *rptr = NULL;
+
+ flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
switch (item) {
case WL_PROF_SEC:
- return &wl->profile->sec;
+ rptr = &wl->profile->sec;
+ break;
case WL_PROF_ACT:
- return &wl->profile->active;
+ rptr = &wl->profile->active;
+ break;
case WL_PROF_BSSID:
- return &wl->profile->bssid;
+ rptr = &wl->profile->bssid;
+ break;
case WL_PROF_SSID:
- return &wl->profile->ssid;
+ rptr = &wl->profile->ssid;
+ break;
}
- WL_ERR(("invalid item (%d)\n", item));
- return NULL;
+ dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+ if (!rptr)
+ WL_ERR(("invalid item (%d)\n", item));
+ return rptr;
}
static s32
@@ -6201,7 +6416,9 @@
{
s32 err = 0;
struct wlc_ssid *ssid;
+ unsigned long flags;
+ flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
switch (item) {
case WL_PROF_SSID:
ssid = (wlc_ssid_t *) data;
@@ -6233,7 +6450,7 @@
err = -EOPNOTSUPP;
break;
}
-
+ dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
return err;
}
@@ -6333,14 +6550,17 @@
conn_info->resp_ie_len = 0;
}
-static void wl_lock_eq(struct wl_priv *wl)
+static unsigned long wl_lock_eq(struct wl_priv *wl)
{
- spin_lock_irq(&wl->eq_lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&wl->eq_lock, flags);
+ return flags;
}
-static void wl_unlock_eq(struct wl_priv *wl)
+static void wl_unlock_eq(struct wl_priv *wl, unsigned long flags)
{
- spin_unlock_irq(&wl->eq_lock);
+ spin_unlock_irqrestore(&wl->eq_lock, flags);
}
static void wl_init_eq_lock(struct wl_priv *wl)
@@ -6463,10 +6683,68 @@
return 0;
}
+s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
+{
+ struct wl_priv *wl;
+ wl = wlcfg_drv_priv;
+
+ return wl_cfgp2p_set_p2p_noa(wl, net, buf, len);
+}
+
+s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
+{
+ struct wl_priv *wl;
+ wl = wlcfg_drv_priv;
+
+ return wl_cfgp2p_get_p2p_noa(wl, net, buf, len);
+}
+
+s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
+{
+ struct wl_priv *wl;
+ wl = wlcfg_drv_priv;
+
+ return wl_cfgp2p_set_p2p_ps(wl, net, buf, len);
+}
+
+s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len,
+ enum wl_management_type type)
+{
+ struct wl_priv *wl;
+ struct net_device *ndev = NULL;
+ s32 ret = 0;
+ s32 bssidx = 0;
+ s32 pktflag = 0;
+ wl = wlcfg_drv_priv;
+ if (wl->p2p && wl->p2p->vif_created) {
+ ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION);
+ bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION);
+ } else if (wl_get_drv_status(wl, AP_CREATING) ||
+ wl_get_drv_status(wl, AP_CREATED)) {
+ ndev = net;
+ bssidx = 0;
+ }
+ if (ndev != NULL) {
+ switch (type) {
+ case WL_BEACON:
+ pktflag = VNDR_IE_BEACON_FLAG;
+ break;
+ case WL_PROBE_RESP:
+ pktflag = VNDR_IE_PRBRSP_FLAG;
+ break;
+ case WL_ASSOC_RESP:
+ pktflag = VNDR_IE_ASSOCRSP_FLAG;
+ break;
+ }
+ if (pktflag)
+ ret = wl_cfgp2p_set_management_ie(wl, ndev, bssidx, pktflag, buf, len);
+ }
+
+ return ret;
+}
static __used void wl_dongle_poweron(struct wl_priv *wl)
{
-
WL_DBG(("Enter \n"));
dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON);
@@ -6481,8 +6759,6 @@
static __used void wl_dongle_poweroff(struct wl_priv *wl)
{
-
-
WL_DBG(("Enter \n"));
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)
wl_cfg80211_suspend(wl_to_wiphy(wl), NULL);
@@ -6496,6 +6772,7 @@
/* clean up dtim_skip setting */
dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
}
+
static int wl_debugfs_add_netdev_params(struct wl_priv *wl)
{
char buf[10+IFNAMSIZ];
@@ -6582,3 +6859,472 @@
err_out:
return err;
}
+
+#if defined(COEX_DHCP)
+/*
+ * get named driver variable to uint register value and return error indication
+ * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, ®_value)
+ */
+static int
+dev_wlc_intvar_get_reg(struct net_device *dev, char *name,
+ uint reg, int *retval)
+{
+ union {
+ char buf[WLC_IOCTL_SMLEN];
+ int val;
+ } var;
+ int error;
+
+ bcm_mkiovar(name, (char *)(®), sizeof(reg),
+ (char *)(&var), sizeof(var.buf));
+ error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false);
+
+ *retval = dtoh32(var.val);
+ return (error);
+}
+
+static int
+dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
+ char ioctlbuf[1024];
+#else
+ static char ioctlbuf[1024];
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
+
+ bcm_mkiovar(name, buf, len, ioctlbuf, sizeof(ioctlbuf));
+
+ return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf, sizeof(ioctlbuf), true));
+}
+/*
+get named driver variable to uint register value and return error indication
+calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value)
+*/
+static int
+dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val)
+{
+ char reg_addr[8];
+
+ memset(reg_addr, 0, sizeof(reg_addr));
+ memcpy((char *)®_addr[0], (char *)addr, 4);
+ memcpy((char *)®_addr[4], (char *)val, 4);
+
+ return (dev_wlc_bufvar_set(dev, name, (char *)®_addr[0], sizeof(reg_addr)));
+}
+
+static bool btcoex_is_sco_active(struct net_device *dev)
+{
+ int ioc_res = 0;
+ bool res = FALSE;
+ int sco_id_cnt = 0;
+ int param27;
+ int i;
+
+ for (i = 0; i < 12; i++) {
+
+ ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, ¶m27);
+
+ WL_TRACE(("%s, sample[%d], btc params: 27:%x\n",
+ __FUNCTION__, i, param27));
+
+ if (ioc_res < 0) {
+ WL_ERR(("%s ioc read btc params error\n", __FUNCTION__));
+ break;
+ }
+
+ if ((param27 & 0x6) == 2) { /* count both sco & esco */
+ sco_id_cnt++;
+ }
+
+ if (sco_id_cnt > 2) {
+ WL_TRACE(("%s, sco/esco detected, pkt id_cnt:%d samples:%d\n",
+ __FUNCTION__, sco_id_cnt, i));
+ res = TRUE;
+ break;
+ }
+
+ msleep(5);
+ }
+
+ return res;
+}
+
+#if defined(BT_DHCP_eSCO_FIX)
+/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */
+static int set_btc_esco_params(struct net_device *dev, bool trump_sco)
+{
+ static bool saved_status = FALSE;
+
+ char buf_reg50va_dhcp_on[8] =
+ { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 };
+ char buf_reg51va_dhcp_on[8] =
+ { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+ char buf_reg64va_dhcp_on[8] =
+ { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+ char buf_reg65va_dhcp_on[8] =
+ { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+ char buf_reg71va_dhcp_on[8] =
+ { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+ uint32 regaddr;
+ static uint32 saved_reg50;
+ static uint32 saved_reg51;
+ static uint32 saved_reg64;
+ static uint32 saved_reg65;
+ static uint32 saved_reg71;
+
+ if (trump_sco) {
+ /* this should reduce eSCO agressive retransmit
+ * w/o breaking it
+ */
+
+ /* 1st save current */
+ WL_TRACE(("Do new SCO/eSCO coex algo {save &"
+ "override}\n"));
+ if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) {
+ saved_status = TRUE;
+ WL_TRACE(("%s saved bt_params[50,51,64,65,71]:"
+ "0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ __FUNCTION__, saved_reg50, saved_reg51,
+ saved_reg64, saved_reg65, saved_reg71));
+ } else {
+ WL_ERR((":%s: save btc_params failed\n",
+ __FUNCTION__));
+ saved_status = FALSE;
+ return -1;
+ }
+
+ WL_TRACE(("override with [50,51,64,65,71]:"
+ "0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ *(u32 *)(buf_reg50va_dhcp_on+4),
+ *(u32 *)(buf_reg51va_dhcp_on+4),
+ *(u32 *)(buf_reg64va_dhcp_on+4),
+ *(u32 *)(buf_reg65va_dhcp_on+4),
+ *(u32 *)(buf_reg71va_dhcp_on+4)));
+
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg50va_dhcp_on[0], 8);
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg51va_dhcp_on[0], 8);
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg64va_dhcp_on[0], 8);
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg65va_dhcp_on[0], 8);
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg71va_dhcp_on[0], 8);
+
+ saved_status = TRUE;
+ } else if (saved_status) {
+ /* restore previously saved bt params */
+ WL_TRACE(("Do new SCO/eSCO coex algo {save &"
+ "override}\n"));
+
+ regaddr = 50;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)®addr, (char *)&saved_reg50);
+ regaddr = 51;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)®addr, (char *)&saved_reg51);
+ regaddr = 64;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)®addr, (char *)&saved_reg64);
+ regaddr = 65;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)®addr, (char *)&saved_reg65);
+ regaddr = 71;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)®addr, (char *)&saved_reg71);
+
+ WL_TRACE(("restore bt_params[50,51,64,65,71]:"
+ "0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ saved_reg50, saved_reg51, saved_reg64,
+ saved_reg65, saved_reg71));
+
+ saved_status = FALSE;
+ } else {
+ WL_ERR((":%s att to restore not saved BTCOEX params\n",
+ __FUNCTION__));
+ return -1;
+ }
+ return 0;
+}
+#endif /* BT_DHCP_eSCO_FIX */
+
+static void
+wl_cfg80211_bt_setflag(struct net_device *dev, bool set)
+{
+#if defined(BT_DHCP_USE_FLAGS)
+ char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 };
+ char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
+#endif
+
+#if defined(BT_DHCP_eSCO_FIX)
+ /* set = 1, save & turn on 0 - off & restore prev settings */
+ set_btc_esco_params(dev, set);
+#endif
+
+#if defined(BT_DHCP_USE_FLAGS)
+ WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set));
+ if (set == TRUE)
+ /* Forcing bt_flag7 */
+ dev_wlc_bufvar_set(dev, "btc_flags",
+ (char *)&buf_flag7_dhcp_on[0],
+ sizeof(buf_flag7_dhcp_on));
+ else
+ /* Restoring default bt flag7 */
+ dev_wlc_bufvar_set(dev, "btc_flags",
+ (char *)&buf_flag7_default[0],
+ sizeof(buf_flag7_default));
+#endif
+}
+
+static void wl_cfg80211_bt_timerfunc(ulong data)
+{
+ struct btcoex_info *bt_local = (struct btcoex_info *)data;
+ WL_TRACE(("%s\n", __FUNCTION__));
+ bt_local->timer_on = 0;
+ schedule_work(&bt_local->work);
+}
+
+static void wl_cfg80211_bt_handler(struct work_struct *work)
+{
+ struct btcoex_info *btcx_inf;
+
+ btcx_inf = container_of(work, struct btcoex_info, work);
+
+ if (btcx_inf->timer_on) {
+ btcx_inf->timer_on = 0;
+ del_timer_sync(&btcx_inf->timer);
+ }
+
+ switch (btcx_inf->bt_state) {
+ case BT_DHCP_START:
+ /* DHCP started
+ * provide OPPORTUNITY window to get DHCP address
+ */
+ WL_TRACE(("%s bt_dhcp stm: started \n",
+ __FUNCTION__));
+ btcx_inf->bt_state = BT_DHCP_OPPR_WIN;
+ mod_timer(&btcx_inf->timer,
+ jiffies + BT_DHCP_OPPR_WIN_TIME*HZ/1000);
+ btcx_inf->timer_on = 1;
+ break;
+
+ case BT_DHCP_OPPR_WIN:
+ if (btcx_inf->dhcp_done) {
+ WL_TRACE(("%s DHCP Done before T1 expiration\n",
+ __FUNCTION__));
+ goto btc_coex_idle;
+ }
+
+ /* DHCP is not over yet, start lowering BT priority
+ * enforce btc_params + flags if necessary
+ */
+ WL_TRACE(("%s DHCP T1:%d expired\n", __FUNCTION__,
+ BT_DHCP_OPPR_WIN_TIME));
+ if (btcx_inf->dev)
+ wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE);
+ btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT;
+ mod_timer(&btcx_inf->timer,
+ jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000);
+ btcx_inf->timer_on = 1;
+ break;
+
+ case BT_DHCP_FLAG_FORCE_TIMEOUT:
+ if (btcx_inf->dhcp_done) {
+ WL_TRACE(("%s DHCP Done before T2 expiration\n",
+ __FUNCTION__));
+ } else {
+ /* Noo dhcp during T1+T2, restore BT priority */
+ WL_TRACE(("%s DHCP wait interval T2:%d"
+ "msec expired\n", __FUNCTION__,
+ BT_DHCP_FLAG_FORCE_TIME));
+ }
+
+ /* Restoring default bt priority */
+ if (btcx_inf->dev)
+ wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
+btc_coex_idle:
+ btcx_inf->bt_state = BT_DHCP_IDLE;
+ btcx_inf->timer_on = 0;
+ break;
+
+ default:
+ WL_ERR(("%s error g_status=%d !!!\n", __FUNCTION__,
+ btcx_inf->bt_state));
+ if (btcx_inf->dev)
+ wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
+ btcx_inf->bt_state = BT_DHCP_IDLE;
+ btcx_inf->timer_on = 0;
+ break;
+ }
+
+ net_os_wake_unlock(btcx_inf->dev);
+}
+
+static int wl_cfg80211_btcoex_init(struct wl_priv *wl)
+{
+ struct btcoex_info *btco_inf = NULL;
+
+ btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL);
+ if (!btco_inf)
+ return -ENOMEM;
+
+ btco_inf->bt_state = BT_DHCP_IDLE;
+ btco_inf->ts_dhcp_start = 0;
+ btco_inf->ts_dhcp_ok = 0;
+ /* Set up timer for BT */
+ btco_inf->timer_ms = 10;
+ init_timer(&btco_inf->timer);
+ btco_inf->timer.data = (ulong)btco_inf;
+ btco_inf->timer.function = wl_cfg80211_bt_timerfunc;
+
+ btco_inf->dev = wl->wdev->netdev;
+
+ INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler);
+
+ wl->btcoex_info = btco_inf;
+ return 0;
+}
+
+static void
+wl_cfg80211_btcoex_deinit(struct wl_priv *wl)
+{
+ if (!wl->btcoex_info)
+ return;
+
+ if (!wl->btcoex_info->timer_on) {
+ wl->btcoex_info->timer_on = 0;
+ del_timer_sync(&wl->btcoex_info->timer);
+ }
+
+ cancel_work_sync(&wl->btcoex_info->work);
+
+ kfree(wl->btcoex_info);
+ wl->btcoex_info = NULL;
+}
+#endif /* COEX_DHCP */
+
+int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command)
+{
+ char powermode_val = 0;
+ char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 };
+ char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 };
+ char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 };
+
+ uint32 regaddr;
+ static uint32 saved_reg66;
+ static uint32 saved_reg41;
+ static uint32 saved_reg68;
+ static bool saved_status = FALSE;
+
+#ifdef COEX_DHCP
+ char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
+ struct btcoex_info *btco_inf = wlcfg_drv_priv->btcoex_info;
+#endif /* COEX_DHCP */
+
+ /* Figure out powermode 1 or o command */
+ strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1);
+
+ if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
+
+ WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__));
+
+ /* Retrieve and saved orig regs value */
+ if ((saved_status == FALSE) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) {
+ saved_status = TRUE;
+ WL_TRACE(("Saved 0x%x 0x%x 0x%x\n",
+ saved_reg66, saved_reg41, saved_reg68));
+
+ /* Disable PM mode during dhpc session */
+
+ /* Disable PM mode during dhpc session */
+#ifdef COEX_DHCP
+ /* Start BT timer only for SCO connection */
+ if (btcoex_is_sco_active(dev)) {
+ /* btc_params 66 */
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg66va_dhcp_on[0],
+ sizeof(buf_reg66va_dhcp_on));
+ /* btc_params 41 0x33 */
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg41va_dhcp_on[0],
+ sizeof(buf_reg41va_dhcp_on));
+ /* btc_params 68 0x190 */
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg68va_dhcp_on[0],
+ sizeof(buf_reg68va_dhcp_on));
+ saved_status = TRUE;
+
+ btco_inf->bt_state = BT_DHCP_START;
+ btco_inf->timer_on = 1;
+ mod_timer(&btco_inf->timer, btco_inf->timer.expires);
+ WL_TRACE(("%s enable BT DHCP Timer\n",
+ __FUNCTION__));
+ }
+#endif /* COEX_DHCP */
+ }
+ else if (saved_status == TRUE) {
+ WL_ERR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__));
+ }
+ }
+ else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) {
+
+
+ /* Restoring PM mode */
+
+#ifdef COEX_DHCP
+ /* Stop any bt timer because DHCP session is done */
+ WL_TRACE(("%s disable BT DHCP Timer\n", __FUNCTION__));
+ if (btco_inf->timer_on) {
+ btco_inf->timer_on = 0;
+ del_timer_sync(&btco_inf->timer);
+
+ if (btco_inf->bt_state != BT_DHCP_IDLE) {
+ /* need to restore original btc flags & extra btc params */
+ WL_TRACE(("%s bt->bt_state:%d\n",
+ __FUNCTION__, btco_inf->bt_state));
+ /* wake up btcoex thread to restore btlags+params */
+ schedule_work(&btco_inf->work);
+ }
+ }
+
+ /* Restoring btc_flag paramter anyway */
+ if (saved_status == TRUE)
+ dev_wlc_bufvar_set(dev, "btc_flags",
+ (char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
+#endif /* COEX_DHCP */
+
+ /* Restore original values */
+ if (saved_status == TRUE) {
+ regaddr = 66;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)®addr, (char *)&saved_reg66);
+ regaddr = 41;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)®addr, (char *)&saved_reg41);
+ regaddr = 68;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)®addr, (char *)&saved_reg68);
+
+ WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n",
+ saved_reg66, saved_reg41, saved_reg68));
+ }
+ saved_status = FALSE;
+
+ }
+ else {
+ WL_ERR(("%s Unkwown yet power setting, ignored\n",
+ __FUNCTION__));
+ }
+
+ snprintf(command, 3, "OK");
+
+ return (strlen("OK"));
+}
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h
index a563724..262335e 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h
@@ -52,11 +52,11 @@
#define dtohchanspec(i) i
#define WL_DBG_NONE 0
+#define WL_DBG_TRACE (1 << 4)
#define WL_DBG_SCAN (1 << 3)
#define WL_DBG_DBG (1 << 2)
#define WL_DBG_INFO (1 << 1)
#define WL_DBG_ERR (1 << 0)
-#define WL_DBG_MASK ((WL_DBG_DBG | WL_DBG_INFO | WL_DBG_ERR) << 1)
/* 0 invalidates all debug messages. default is 1 */
#define WL_DBG_LEVEL 0xFF
@@ -82,6 +82,13 @@
printk args; \
} \
} while (0)
+#define WL_TRACE(args) \
+do { \
+ if (wl_dbg_level & WL_DBG_TRACE) { \
+ printk(KERN_ERR "CFG80211-TRACE) %s :", __func__); \
+ printk args; \
+ } \
+} while (0)
#if (WL_DBG_LEVEL > 0)
#define WL_DBG(args) \
do { \
@@ -94,6 +101,7 @@
#define WL_DBG(args)
#endif /* (WL_DBG_LEVEL > 0) */
+
#define WL_SCAN_RETRY_MAX 3 /* used for ibss scan */
#define WL_NUM_PMKIDS_MAX MAXPMKID /* will be used
* for 2.6.33 kernel
@@ -119,9 +127,13 @@
#define WL_AP_MAX 256 /* virtually unlimitted as long
* as kernel memory allows
*/
-#define WL_FILE_NAME_MAX 256
-#define WL_DWELL_TIME 200
+#define WL_FILE_NAME_MAX 256
+#define WL_DWELL_TIME 200
+#define WL_LONG_DWELL_TIME 1000
#define VWDEV_CNT 3
+
+#define WL_SCAN_TIMER_INTERVAL_MS 8000 /* Scan timeout */
+
/* dongle status */
enum wl_status {
WL_STATUS_READY = 0,
@@ -171,6 +183,11 @@
WL_NVRAM_LOADING_DONE
};
+enum wl_management_type {
+ WL_BEACON = 0x1,
+ WL_PROBE_RESP = 0x2,
+ WL_ASSOC_RESP = 0x4
+};
/* beacon / probe_response */
struct beacon_proberesp {
__le64 timestamp;
@@ -196,7 +213,6 @@
typedef s32(*EVENT_HANDLER) (struct wl_priv *wl,
struct net_device *ndev, const wl_event_msg_t *e, void *data);
-
/* bss inform structure for cfg80211 interface */
struct wl_cfg80211_bss_info {
u16 band;
@@ -323,6 +339,27 @@
u8 *wps_ie;
bool security_mode;
};
+struct btcoex_info {
+ struct timer_list timer;
+ uint32 timer_ms;
+ uint32 timer_on;
+ uint32 ts_dhcp_start; /* ms ts ecord time stats */
+ uint32 ts_dhcp_ok; /* ms ts ecord time stats */
+ bool dhcp_done; /* flag, indicates that host done with
+ * dhcp before t1/t2 expiration
+ */
+ int bt_state;
+ struct work_struct work;
+ struct net_device *dev;
+};
+
+struct sta_info {
+ /* Structure to hold WPS IE for a STA */
+ u8 probe_req_ie[IE_MAX_LEN];
+ u8 assoc_req_ie[IE_MAX_LEN];
+ u32 probe_req_ie_len;
+ u32 assoc_req_ie_len;
+};
/* dongle private data of cfg80211 interface */
struct wl_priv {
struct wireless_dev *wdev; /* representing wl cfg80211 device */
@@ -343,9 +380,6 @@
struct wl_cfg80211_bss_info *bss_info;
/* information element object for internal purpose */
struct wl_ie ie;
- u8 scan_ie_buf[2048];
- int scan_ie_len;
- struct ether_addr bssid; /* bssid of currently engaged network */
/* for synchronization of main event thread */
struct wl_profile *profile; /* holding dongle profile */
@@ -357,7 +391,7 @@
/* control firwmare and nvram paramter downloading */
struct wl_fw_ctrl *fw;
struct wl_pmk_list *pmk_list; /* wpa2 pmk list */
- tsk_ctl_t event_tsk; /* task of main event handler thread */
+ tsk_ctl_t event_tsk; /* task of main event handler thread */
unsigned long status; /* current dongle status */
void *pub;
u32 channel; /* current channel */
@@ -385,9 +419,11 @@
u64 cache_cookie;
wait_queue_head_t dongle_event_wait;
struct ap_info *ap_info;
+ struct sta_info *sta_info;
struct p2p_info *p2p;
bool p2p_supported;
- s8 last_eventmask[WL_EVENTING_MASK_LEN];
+ struct btcoex_info *btcoex_info;
+ struct timer_list scan_timeout; /* Timer for catch scan event timeout */
};
#define wl_to_wiphy(w) (w->wdev->wiphy)
@@ -494,8 +530,7 @@
extern s32 wl_cfg80211_down(void); /* dongle down */
extern s32 wl_cfg80211_notify_ifadd(struct net_device *net, s32 idx, s32 bssidx,
int (*_net_attach)(dhd_pub_t *dhdp, int ifidx));
-extern s32 wl_cfg80211_ifdel_ops(struct net_device *net);
-extern s32 wl_cfg80211_notify_ifdel(struct net_device *net);
+extern s32 wl_cfg80211_notify_ifdel(struct net_device *ndev);
extern s32 wl_cfg80211_is_progress_ifadd(void);
extern s32 wl_cfg80211_is_progress_ifchange(void);
extern s32 wl_cfg80211_is_progress_ifadd(void);
@@ -507,9 +542,12 @@
extern s8 *wl_cfg80211_get_fwname(void);
extern s8 *wl_cfg80211_get_nvramname(void);
extern s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
-#ifdef CONFIG_SYSCTL
-extern s32 wl_cfg80211_sysctl_export_devaddr(void *data);
-#endif
+extern s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len);
+extern s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len);
+extern s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len,
+ enum wl_management_type type);
+extern s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len);
+extern int wl_cfg80211_hang(struct net_device *dev, u16 reason);
/* do scan abort */
extern s32
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
index 98271c2..4ee6557 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
+++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: wl_cfgp2p.c,v 1.1.4.1.2.14 2011-02-09 01:40:07 Exp $
+ * $Id: wl_cfgp2p.c,v 1.1.4.1.2.14 2011-02-09 01:40:07 $
*
*/
#include <typedefs.h>
@@ -59,7 +59,7 @@
static s32
wl_cfgp2p_vndr_ie(struct net_device *ndev, s32 bssidx, s32 pktflag,
s8 *oui, s32 ie_id, s8 *data, s32 data_len, s32 delete);
-/*
+/*
* Initialize variables related to P2P
*
*/
@@ -99,7 +99,7 @@
wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0;
wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = NULL;
wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = 0;
-
+ spin_lock_init(&wl->p2p->timer_lock);
return BCME_OK;
}
@@ -112,6 +112,7 @@
{
if (wl->p2p) {
kfree(wl->p2p);
+ wl->p2p = NULL;
}
wl->p2p_supported = 0;
}
@@ -122,15 +123,28 @@
wl_cfgp2p_set_firm_p2p(struct wl_priv *wl)
{
struct net_device *ndev = wl_to_prmry_ndev(wl);
+ struct ether_addr null_eth_addr = { { 0, 0, 0, 0, 0, 0 } };
s32 ret = BCME_OK;
s32 val = 0;
/* Do we have to check whether APSTA is enabled or not ? */
wldev_iovar_getint(ndev, "apsta", &val);
if (val == 0) {
val = 1;
- wldev_ioctl(ndev, WLC_DOWN, &val, sizeof(s32), false);
+ wldev_ioctl(ndev, WLC_DOWN, &val, sizeof(s32), true);
wldev_iovar_setint(ndev, "apsta", val);
- wldev_ioctl(ndev, WLC_UP, &val, sizeof(s32), false);
+ wldev_ioctl(ndev, WLC_UP, &val, sizeof(s32), true);
+ }
+ val = 1;
+ /* Disable firmware roaming for P2P */
+ wldev_iovar_setint(ndev, "roam_off", val);
+ /* In case of COB type, firmware has default mac address
+ * After Initializing firmware, we have to set current mac address to
+ * firmware for P2P device address
+ */
+ ret = wldev_iovar_setbuf_bsscfg(ndev, "p2p_da_override", &null_eth_addr,
+ sizeof(null_eth_addr), ioctlbuf, sizeof(ioctlbuf), 0);
+ if (ret && ret != BCME_UNSUPPORTED) {
+ CFGP2P_ERR(("failed to update device address\n"));
}
return ret;
}
@@ -179,10 +193,8 @@
CFGP2P_INFO(("------primary idx %d : wl p2p_ifdel %02x:%02x:%02x:%02x:%02x:%02x\n",
netdev->ifindex, mac->octet[0], mac->octet[1], mac->octet[2],
mac->octet[3], mac->octet[4], mac->octet[5]));
-
ret = wldev_iovar_setbuf(netdev, "p2p_ifdel", mac, sizeof(*mac),
ioctlbuf, sizeof(ioctlbuf));
-
if (unlikely(ret < 0)) {
printk("'wl p2p_ifdel' error %d\n", ret);
}
@@ -499,10 +511,11 @@
wl_escan_params_t *eparams;
wlc_ssid_t ssid;
/* Scan parameters */
-#define P2PAPI_SCAN_NPROBES 1
-#define P2PAPI_SCAN_DWELL_TIME_MS 40
+#define P2PAPI_SCAN_NPROBES 4
+#define P2PAPI_SCAN_DWELL_TIME_MS 80
+#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 100
#define P2PAPI_SCAN_HOME_TIME_MS 10
-
+ struct net_device *pri_dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY);
wl_set_p2p_status(wl, SCANNING);
/* Allocate scan params which need space for 3 channels and 0 ssids */
eparams_size = (WL_SCAN_PARAMS_FIXED_SIZE +
@@ -556,7 +569,12 @@
eparams->params.nprobes = htod32(P2PAPI_SCAN_NPROBES);
eparams->params.home_time = htod32(P2PAPI_SCAN_HOME_TIME_MS);
- eparams->params.active_time = htod32(-1);
+ if (wl_get_drv_status(wl, CONNECTED))
+ eparams->params.active_time = htod32(-1);
+ else if (num_chans == 3)
+ eparams->params.active_time = htod32(P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS);
+ else
+ eparams->params.active_time = htod32(P2PAPI_SCAN_DWELL_TIME_MS);
eparams->params.passive_time = htod32(-1);
eparams->params.channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) |
(num_chans & WL_SCAN_PARAMS_COUNT_MASK));
@@ -576,7 +594,7 @@
CFGP2P_INFO(("\n"));
- ret = wldev_iovar_setbuf_bsscfg(dev, "p2p_scan",
+ ret = wldev_iovar_setbuf_bsscfg(pri_dev, "p2p_scan",
memblk, memsize, smbuf, sizeof(ioctlbuf), bssidx);
return ret;
}
@@ -610,16 +628,14 @@
s32 ret = BCME_OK;
u32 pos;
u8 *ie_buf;
- u8 *mgmt_ie_buf;
- u32 mgmt_ie_buf_len;
- u32 *mgmt_ie_len;
+ u8 *mgmt_ie_buf = NULL;
+ u32 mgmt_ie_buf_len = 0;
+ u32 *mgmt_ie_len = 0;
u8 ie_id, ie_len;
u8 delete = 0;
#define IE_TYPE(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie)
#define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie_len)
- if (bssidx == -1)
- return BCME_BADARG;
- if (wl->p2p_supported && p2p_on(wl)) {
+ if (wl->p2p_supported && p2p_on(wl) && bssidx != -1) {
if (bssidx == P2PAPI_BSSCFG_PRIMARY)
bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
switch (pktflag) {
@@ -654,7 +670,7 @@
CFGP2P_ERR(("not suitable type\n"));
return -1;
}
- } else {
+ } else if (get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
switch (pktflag) {
case VNDR_IE_PRBRSP_FLAG :
mgmt_ie_buf = wl->ap_info->probe_res_ie;
@@ -672,37 +688,63 @@
CFGP2P_ERR(("not suitable type\n"));
return -1;
}
+ bssidx = 0;
+ } else if (bssidx == -1 && get_mode_by_netdev(wl, ndev) == WL_MODE_BSS) {
+ switch (pktflag) {
+ case VNDR_IE_PRBREQ_FLAG :
+ mgmt_ie_buf = wl->sta_info->probe_req_ie;
+ mgmt_ie_len = &wl->sta_info->probe_req_ie_len;
+ mgmt_ie_buf_len = sizeof(wl->sta_info->probe_req_ie);
+ break;
+ case VNDR_IE_ASSOCREQ_FLAG :
+ mgmt_ie_buf = wl->sta_info->assoc_req_ie;
+ mgmt_ie_len = &wl->sta_info->assoc_req_ie_len;
+ mgmt_ie_buf_len = sizeof(wl->sta_info->assoc_req_ie);
+ break;
+ default:
+ mgmt_ie_buf = NULL;
+ mgmt_ie_len = NULL;
+ CFGP2P_ERR(("not suitable type\n"));
+ return -1;
+ }
+ bssidx = 0;
+ } else {
+ CFGP2P_ERR(("not suitable type\n"));
+ return -1;
}
- /* Add if there is any extra IE */
- if (vndr_ie && vndr_ie_len) {
- CFGP2P_INFO(("Request has extra IE"));
- if (vndr_ie_len > mgmt_ie_buf_len) {
- CFGP2P_ERR(("extra IE size too big\n"));
- ret = -ENOMEM;
- } else {
- if (mgmt_ie_buf != NULL) {
- if ((vndr_ie_len == *mgmt_ie_len) &&
- (memcmp(mgmt_ie_buf, vndr_ie, vndr_ie_len) == 0)) {
- CFGP2P_INFO(("Previous mgmt IE is equals to current IE"));
- goto exit;
- }
- pos = 0;
- delete = 1;
- ie_buf = (u8 *) mgmt_ie_buf;
- while (pos < *mgmt_ie_len) {
- ie_id = ie_buf[pos++];
- ie_len = ie_buf[pos++];
- CFGP2P_INFO(("DELELED ID(%d), Len(%d),"
- "OUI(%02x:%02x:%02x)\n",
- ie_id, ie_len, ie_buf[pos],
- ie_buf[pos+1], ie_buf[pos+2]));
- ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag,
- ie_buf+pos, VNDR_SPEC_ELEMENT_ID,
- ie_buf+pos+3, ie_len-3, delete);
- pos += ie_len;
- }
+ if (vndr_ie_len > mgmt_ie_buf_len) {
+ CFGP2P_ERR(("extra IE size too big\n"));
+ ret = -ENOMEM;
+ } else {
+ if (mgmt_ie_buf != NULL) {
+ if (vndr_ie_len && (vndr_ie_len == *mgmt_ie_len) &&
+ (memcmp(mgmt_ie_buf, vndr_ie, vndr_ie_len) == 0)) {
+ CFGP2P_INFO(("Previous mgmt IE is equals to current IE"));
+ goto exit;
}
+ pos = 0;
+ delete = 1;
+ ie_buf = (u8 *) mgmt_ie_buf;
+ while (pos < *mgmt_ie_len) {
+ ie_id = ie_buf[pos++];
+ ie_len = ie_buf[pos++];
+ if ((ie_id == DOT11_MNG_VS_ID) &&
+ (wl_cfgp2p_is_wps_ie(&ie_buf[pos-2], NULL, 0) ||
+ wl_cfgp2p_is_p2p_ie(&ie_buf[pos-2], NULL, 0))) {
+ CFGP2P_INFO(("DELELED ID : %d, Len : %d , OUI :"
+ "%02x:%02x:%02x\n", ie_id, ie_len, ie_buf[pos],
+ ie_buf[pos+1], ie_buf[pos+2]));
+ ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag, ie_buf+pos,
+ VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3, ie_len-3, delete);
+ }
+ pos += ie_len;
+ }
+
+ }
+ *mgmt_ie_len = 0;
+ /* Add if there is any extra IE */
+ if (vndr_ie && vndr_ie_len) {
/* save the current IE in wl struct */
memcpy(mgmt_ie_buf, vndr_ie, vndr_ie_len);
*mgmt_ie_len = vndr_ie_len;
@@ -724,7 +766,6 @@
pos += ie_len;
}
}
-
}
#undef IE_TYPE
#undef IE_TYPE_LEN
@@ -918,13 +959,15 @@
CFGP2P_DBG((" Enter\n"));
if (wl_get_p2p_status(wl, LISTEN_EXPIRED) == 0) {
wl_set_p2p_status(wl, LISTEN_EXPIRED);
-
- if (wl->p2p->listen_timer)
- del_timer_sync(wl->p2p->listen_timer);
-
+ if (timer_pending(&wl->p2p->listen_timer)) {
+ spin_lock_bh(&wl->p2p->timer_lock);
+ del_timer_sync(&wl->p2p->listen_timer);
+ spin_unlock_bh(&wl->p2p->timer_lock);
+ }
cfg80211_remain_on_channel_expired(ndev, wl->cache_cookie, &wl->remain_on_chan,
wl->remain_on_chan_type, GFP_KERNEL);
- }
+ } else
+ wl_clr_p2p_status(wl, LISTEN_EXPIRED);
return ret;
@@ -932,7 +975,7 @@
/*
* Timer expire callback function for LISTEN
- * We can't report cfg80211_remain_on_channel_expired from Timer ISR context,
+ * We can't report cfg80211_remain_on_channel_expired from Timer ISR context,
* so lets do it from thread context.
*/
static void
@@ -946,7 +989,7 @@
wl_cfg80211_event(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), &msg, NULL);
}
-/*
+/*
* Do a P2P Listen on the given channel for the given duration.
* A listen consists of sitting idle and responding to P2P probe requests
* with a P2P probe response.
@@ -970,6 +1013,7 @@
} while (0);
s32 ret = BCME_OK;
+ struct timer_list *_timer;
CFGP2P_DBG((" Enter Channel : %d, Duration : %d\n", channel, duration_ms));
if (unlikely(wl_get_p2p_status(wl, DISCOVERY_ON) == 0)) {
@@ -978,26 +1022,21 @@
ret = BCME_NOTREADY;
goto exit;
}
+ if (timer_pending(&wl->p2p->listen_timer)) {
+ CFGP2P_DBG(("previous LISTEN is not completed yet\n"));
+ goto exit;
- wl_clr_p2p_status(wl, LISTEN_EXPIRED);
+ } else
+ wl_clr_p2p_status(wl, LISTEN_EXPIRED);
wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_LISTEN, channel, (u16) duration_ms,
wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
+ _timer = &wl->p2p->listen_timer;
- if (wl->p2p->listen_timer)
- del_timer_sync(wl->p2p->listen_timer);
-
- wl->p2p->listen_timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);
-
- if (wl->p2p->listen_timer == NULL) {
- CFGP2P_ERR(("listen_timer allocation failed\n"));
- return -ENOMEM;
- }
-
- /* We will wait to receive WLC_E_P2P_DISC_LISTEN_COMPLETE from dongle ,
+ /* We will wait to receive WLC_E_P2P_DISC_LISTEN_COMPLETE from dongle ,
* otherwise we will wait up to duration_ms + 200ms
*/
- INIT_TIMER(wl->p2p->listen_timer, wl_cfgp2p_listen_expired, duration_ms, 200);
+ INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration_ms, 200);
#undef INIT_TIMER
exit:
@@ -1058,9 +1097,7 @@
} else {
CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received,"
"status : %d\n", status));
-
}
-
return ret;
}
/* Send an action frame immediately without doing channel synchronization.
@@ -1098,8 +1135,8 @@
goto exit;
}
timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
- (wl_get_p2p_status(wl, ACTION_TX_COMPLETED) ||wl_get_p2p_status(wl, ACTION_TX_NOACK)),
- msecs_to_jiffies(MAX_WAIT_TIME));
+ (wl_get_p2p_status(wl, ACTION_TX_COMPLETED) || wl_get_p2p_status(wl, ACTION_TX_NOACK)),
+ msecs_to_jiffies(MAX_WAIT_TIME));
if (timeout > 0 && wl_get_p2p_status(wl, ACTION_TX_COMPLETED)) {
CFGP2P_INFO(("tx action frame operation is completed\n"));
@@ -1266,11 +1303,167 @@
}
return p2p_supported;
}
+
/* Cleanup P2P resources */
s32
wl_cfgp2p_down(struct wl_priv *wl)
{
- if (wl->p2p->listen_timer)
- del_timer_sync(wl->p2p->listen_timer);
+ if (timer_pending(&wl->p2p->listen_timer))
+ del_timer_sync(&wl->p2p->listen_timer);
+ wl_cfgp2p_deinit_priv(wl);
return 0;
}
+
+s32 wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len)
+{
+ s32 ret = -1;
+ int count, start, duration;
+ wl_p2p_sched_t dongle_noa;
+
+ CFGP2P_DBG((" Enter\n"));
+
+ memset(&dongle_noa, 0, sizeof(dongle_noa));
+
+ if (wl->p2p && wl->p2p->vif_created) {
+
+ wl->p2p->noa.desc[0].start = 0;
+
+ sscanf(buf, "%d %d %d", &count, &start, &duration);
+ CFGP2P_DBG(("set_p2p_noa count %d start %d duration %d\n",
+ count, start, duration));
+ if (count != -1)
+ wl->p2p->noa.desc[0].count = count;
+
+ /* supplicant gives interval as start */
+ if (start != -1)
+ wl->p2p->noa.desc[0].interval = start;
+
+ if (duration != -1)
+ wl->p2p->noa.desc[0].duration = duration;
+
+ if (wl->p2p->noa.desc[0].count != 255) {
+ wl->p2p->noa.desc[0].start = 200;
+ dongle_noa.type = WL_P2P_SCHED_TYPE_REQ_ABS;
+ dongle_noa.action = WL_P2P_SCHED_ACTION_GOOFF;
+ dongle_noa.option = WL_P2P_SCHED_OPTION_TSFOFS;
+ }
+ else {
+ /* Continuous NoA interval. */
+ dongle_noa.action = WL_P2P_SCHED_ACTION_NONE;
+ dongle_noa.type = WL_P2P_SCHED_TYPE_ABS;
+ if ((wl->p2p->noa.desc[0].interval == 102) ||
+ (wl->p2p->noa.desc[0].interval == 100)) {
+ wl->p2p->noa.desc[0].start = 100 -
+ wl->p2p->noa.desc[0].duration;
+ dongle_noa.option = WL_P2P_SCHED_OPTION_BCNPCT;
+ }
+ else {
+ dongle_noa.option = WL_P2P_SCHED_OPTION_NORMAL;
+ }
+ }
+ /* Put the noa descriptor in dongle format for dongle */
+ dongle_noa.desc[0].count = htod32(wl->p2p->noa.desc[0].count);
+ if (dongle_noa.option == WL_P2P_SCHED_OPTION_BCNPCT) {
+ dongle_noa.desc[0].start = htod32(wl->p2p->noa.desc[0].start);
+ dongle_noa.desc[0].duration = htod32(wl->p2p->noa.desc[0].duration);
+ }
+ else {
+ dongle_noa.desc[0].start = htod32(wl->p2p->noa.desc[0].start*1000);
+ dongle_noa.desc[0].duration = htod32(wl->p2p->noa.desc[0].duration*1000);
+ }
+ dongle_noa.desc[0].interval = htod32(wl->p2p->noa.desc[0].interval*1000);
+
+ ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION),
+ "p2p_noa", &dongle_noa, sizeof(dongle_noa), ioctlbuf, sizeof(ioctlbuf));
+
+ if (ret < 0) {
+ CFGP2P_ERR(("fw set p2p_noa failed %d\n", ret));
+ }
+ }
+ else {
+ CFGP2P_ERR(("ERROR: set_noa in non-p2p mode\n"));
+ }
+ return ret;
+}
+
+s32 wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int buf_len)
+{
+ wifi_p2p_noa_desc_t *noa_desc;
+ int len = 0, i;
+ char _buf[200];
+
+ CFGP2P_DBG((" Enter\n"));
+ buf[0] = '\0';
+ if (wl->p2p && wl->p2p->vif_created) {
+ if (wl->p2p->noa.desc[0].count || wl->p2p->ops.ops) {
+ _buf[0] = 1; /* noa index */
+ _buf[1] = (wl->p2p->ops.ops ? 0x80: 0) |
+ (wl->p2p->ops.ctw & 0x7f); /* ops + ctw */
+ len += 2;
+ if (wl->p2p->noa.desc[0].count) {
+ noa_desc = (wifi_p2p_noa_desc_t*)&_buf[len];
+ noa_desc->cnt_type = wl->p2p->noa.desc[0].count;
+ noa_desc->duration = wl->p2p->noa.desc[0].duration;
+ noa_desc->interval = wl->p2p->noa.desc[0].interval;
+ noa_desc->start = wl->p2p->noa.desc[0].start;
+ len += sizeof(wifi_p2p_noa_desc_t);
+ }
+ if (buf_len <= len * 2) {
+ CFGP2P_ERR(("ERROR: buf_len %d in not enough for"
+ "returning noa in string format\n", buf_len));
+ return -1;
+ }
+ /* We have to convert the buffer data into ASCII strings */
+ for (i = 0; i < len; i++) {
+ sprintf(buf, "%02x", _buf[i]);
+ buf += 2;
+ }
+ buf[i*2] = '\0';
+ }
+ }
+ else {
+ CFGP2P_ERR(("ERROR: get_noa in non-p2p mode\n"));
+ return -1;
+ }
+ return len * 2;
+}
+
+s32 wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len)
+{
+ int ps, ctw;
+ int ret = -1;
+ s32 legacy_ps;
+
+ CFGP2P_DBG((" Enter\n"));
+ if (wl->p2p && wl->p2p->vif_created) {
+ sscanf(buf, "%d %d %d", &legacy_ps, &ps, &ctw);
+ CFGP2P_DBG((" Enter legacy_ps %d ps %d ctw %d\n", legacy_ps, ps, ctw));
+ if (ctw != -1) {
+ wl->p2p->ops.ctw = ctw;
+ ret = 0;
+ }
+ if (ps != -1) {
+ wl->p2p->ops.ops = ps;
+ ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION),
+ "p2p_ops", &wl->p2p->ops, sizeof(wl->p2p->ops),
+ ioctlbuf, sizeof(ioctlbuf));
+ if (ret < 0) {
+ CFGP2P_ERR(("fw set p2p_ops failed %d\n", ret));
+ }
+ }
+
+ if (legacy_ps != -1) {
+ s32 pm = legacy_ps ? PM_MAX : PM_OFF;
+ ret = wldev_ioctl(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION),
+ WLC_SET_PM, &pm, sizeof(pm), true);
+ if (unlikely(ret)) {
+ CFGP2P_ERR(("error (%d)\n", ret));
+ }
+ }
+ }
+ else {
+ CFGP2P_ERR(("ERROR: set_p2p_ps in non-p2p mode\n"));
+ ret = -1;
+ }
+ return ret;
+}
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
index b08504d..5a69168 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
+++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
@@ -45,11 +45,11 @@
#define IE_MAX_LEN 300
/* Structure to hold all saved P2P and WPS IEs for a BSSCFG */
struct p2p_saved_ie {
- u8 p2p_probe_req_ie[IE_MAX_LEN];
- u8 p2p_probe_res_ie[IE_MAX_LEN];
- u8 p2p_assoc_req_ie[IE_MAX_LEN];
- u8 p2p_assoc_res_ie[IE_MAX_LEN];
- u8 p2p_beacon_ie[IE_MAX_LEN];
+ u8 p2p_probe_req_ie[IE_MAX_LEN];
+ u8 p2p_probe_res_ie[IE_MAX_LEN];
+ u8 p2p_assoc_req_ie[IE_MAX_LEN];
+ u8 p2p_assoc_res_ie[IE_MAX_LEN];
+ u8 p2p_beacon_ie[IE_MAX_LEN];
u32 p2p_probe_req_ie_len;
u32 p2p_probe_res_ie_len;
u32 p2p_assoc_req_ie_len;
@@ -73,8 +73,11 @@
struct ether_addr dev_addr;
struct ether_addr int_addr;
struct p2p_bss bss_idx[P2PAPI_BSSCFG_MAX];
- struct timer_list *listen_timer;
+ struct timer_list listen_timer;
+ wl_p2p_sched_t noa;
+ wl_p2p_ops_t ops;
wlc_ssid_t ssid;
+ spinlock_t timer_lock;
};
/* dongle status */
@@ -96,7 +99,7 @@
#define wl_to_p2p_bss_ndev(w, type) ((wl)->p2p->bss_idx[type].dev)
#define wl_to_p2p_bss_bssidx(w, type) ((wl)->p2p->bss_idx[type].bssidx)
#define wl_to_p2p_bss_saved_ie(w, type) ((wl)->p2p->bss_idx[type].saved_ie)
-#define wl_to_p2p_bss_private(w, type) ((wl)->p2p->bss_idx[type].private_data)
+#define wl_to_p2p_bss_private(w, type) ((wl)->p2p->bss_idx[type].private_data)
#define wl_to_p2p_bss(wl, type) ((wl)->p2p->bss_idx[type])
#define wl_get_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : test_bit(WLP2P_STATUS_ ## stat, \
&(wl)->p2p->status))
@@ -108,7 +111,7 @@
&(wl)->p2p->status))
#define p2p_on(wl) ((wl)->p2p->on)
#define p2p_scan(wl) ((wl)->p2p->scan)
-
+#define p2p_is_on(wl) ((wl)->p2p && (wl)->p2p->on)
/* dword align allocation */
#define WLC_IOCTL_MAXLEN 8192
@@ -223,6 +226,15 @@
extern s32
wl_cfgp2p_down(struct wl_priv *wl);
+extern s32
+wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len);
+
+extern s32
+wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len);
+
+extern s32
+wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len);
+
/* WiFi Direct */
#define SOCIAL_CHAN_1 1
#define SOCIAL_CHAN_2 6
diff --git a/drivers/net/wireless/bcmdhd/wl_iw.c b/drivers/net/wireless/bcmdhd/wl_iw.c
index 6d546fc..ba3cc6c 100644
--- a/drivers/net/wireless/bcmdhd/wl_iw.c
+++ b/drivers/net/wireless/bcmdhd/wl_iw.c
@@ -179,6 +179,11 @@
static wlc_ssid_t g_ssid;
+#ifdef CONFIG_WPS2
+static char *g_wps_probe_req_ie;
+static int g_wps_probe_req_ie_len;
+#endif
+
bool btcoex_is_sco_active(struct net_device *dev);
static wl_iw_ss_cache_ctrl_t g_ss_cache_ctrl;
#if defined(CONFIG_FIRST_SCAN)
@@ -1261,6 +1266,7 @@
&iovbuf, sizeof(iovbuf))) >= 0) {
p += snprintf(p, MAX_WX_STRING, "OK");
+
net_os_set_dtim_skip(dev, bcn_li_dtim);
WL_TRACE(("%s: set dtim_skip %d OK\n", __FUNCTION__,
@@ -1620,7 +1626,7 @@
strcpy(extra, flag);
wrqu.data.length = strlen(extra);
wireless_send_event(dev, cmd, &wrqu, extra);
- net_os_wake_lock_timeout_enable(dev);
+ net_os_wake_lock_timeout_enable(dev, DHD_EVENT_TIMEOUT);
WL_TRACE(("Send IWEVCUSTOM Event as %s\n", extra));
return 0;
@@ -1661,8 +1667,8 @@
#if defined(BCMLXSDMMC)
sdioh_start(NULL, 1);
#endif
-
- dhd_dev_init_ioctl(dev);
+ if (!ret)
+ dhd_dev_init_ioctl(dev);
g_onoff = G_WLAN_SET_ON;
}
@@ -1709,7 +1715,7 @@
g_iscan->iscan_state = ISCAN_STATE_IDLE;
#endif
- dhd_dev_reset(dev, 1);
+ ret = dhd_dev_reset(dev, 1);
#if defined(WL_IW_USE_ISCAN)
#if !defined(CSCAN)
@@ -1732,8 +1738,6 @@
sdioh_stop(NULL);
#endif
- net_os_set_dtim_skip(dev, 0);
-
dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
wl_iw_send_priv_event(dev, "STOP");
@@ -2410,7 +2414,7 @@
list = (wl_uint32_list_t *)channels;
dwrq->length = sizeof(struct iw_range);
- memset(range, 0, sizeof(range));
+ memset(range, 0, sizeof(*range));
range->min_nwid = range->max_nwid = 0;
@@ -4467,7 +4471,7 @@
g_ssid.SSID_len = htod32(g_ssid.SSID_len);
- memset(join_params, 0, sizeof(join_params));
+ memset(join_params, 0, sizeof(*join_params));
join_params_size = sizeof(join_params->ssid);
memcpy(join_params->ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
@@ -5280,6 +5284,7 @@
uint i;
int ret = 0;
char eabuf[ETHER_ADDR_STR_LEN];
+ pmkid_t * pmkid_array = pmkid_list.pmkids.pmkid;
WL_WSEC(("%s: SIOCSIWPMKSA\n", dev->name));
@@ -5312,18 +5317,18 @@
}
for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
- if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_list.pmkids.pmkid[i].BSSID,
+ if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_array[i].BSSID,
ETHER_ADDR_LEN))
break;
if ((pmkid_list.pmkids.npmkid > 0) && (i < pmkid_list.pmkids.npmkid)) {
- bzero(&pmkid_list.pmkids.pmkid[i], sizeof(pmkid_t));
+ bzero(&pmkid_array[i], sizeof(pmkid_t));
for (; i < (pmkid_list.pmkids.npmkid - 1); i++) {
- bcopy(&pmkid_list.pmkids.pmkid[i+1].BSSID,
- &pmkid_list.pmkids.pmkid[i].BSSID,
+ bcopy(&pmkid_array[i+1].BSSID,
+ &pmkid_array[i].BSSID,
ETHER_ADDR_LEN);
- bcopy(&pmkid_list.pmkids.pmkid[i+1].PMKID,
- &pmkid_list.pmkids.pmkid[i].PMKID,
+ bcopy(&pmkid_array[i+1].PMKID,
+ &pmkid_array[i].PMKID,
WPA2_PMKID_LEN);
}
pmkid_list.pmkids.npmkid--;
@@ -5334,14 +5339,14 @@
else if (iwpmksa->cmd == IW_PMKSA_ADD) {
for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
- if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_list.pmkids.pmkid[i].BSSID,
+ if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_array[i].BSSID,
ETHER_ADDR_LEN))
break;
if (i < MAXPMKID) {
bcopy(&iwpmksa->bssid.sa_data[0],
- &pmkid_list.pmkids.pmkid[i].BSSID,
+ &pmkid_array[i].BSSID,
ETHER_ADDR_LEN);
- bcopy(&iwpmksa->pmkid[0], &pmkid_list.pmkids.pmkid[i].PMKID,
+ bcopy(&iwpmksa->pmkid[0], &pmkid_array[i].PMKID,
WPA2_PMKID_LEN);
if (i == pmkid_list.pmkids.npmkid)
pmkid_list.pmkids.npmkid++;
@@ -5354,10 +5359,10 @@
uint k;
k = pmkid_list.pmkids.npmkid;
WL_WSEC(("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %s = ",
- bcm_ether_ntoa(&pmkid_list.pmkids.pmkid[k].BSSID,
+ bcm_ether_ntoa(&pmkid_array[k].BSSID,
eabuf)));
for (j = 0; j < WPA2_PMKID_LEN; j++)
- WL_WSEC(("%02x ", pmkid_list.pmkids.pmkid[k].PMKID[j]));
+ WL_WSEC(("%02x ", pmkid_array[k].PMKID[j]));
WL_WSEC(("\n"));
}
}
@@ -5365,10 +5370,10 @@
for (i = 0; i < pmkid_list.pmkids.npmkid; i++) {
uint j;
WL_WSEC(("\nPMKID[%d]: %s = ", i,
- bcm_ether_ntoa(&pmkid_list.pmkids.pmkid[i].BSSID,
+ bcm_ether_ntoa(&pmkid_array[i].BSSID,
eabuf)));
for (j = 0; j < WPA2_PMKID_LEN; j++)
- WL_WSEC(("%02x ", pmkid_list.pmkids.pmkid[i].PMKID[j]));
+ WL_WSEC(("%02x ", pmkid_array[i].PMKID[j]));
}
WL_WSEC(("\n"));
@@ -6242,6 +6247,125 @@
#endif
+#ifdef CONFIG_WPS2
+static int
+wl_iw_del_wps_probe_req_ie(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra
+)
+{
+ int ret;
+ vndr_ie_setbuf_t *ie_delbuf;
+
+ if (g_wps_probe_req_ie) {
+ ie_delbuf = (vndr_ie_setbuf_t *)(g_wps_probe_req_ie + strlen("vndr_ie "));
+ strncpy(ie_delbuf->cmd, "del", 3);
+ ie_delbuf->cmd[3] = '\0';
+
+ ret = dev_wlc_ioctl(dev, WLC_SET_VAR, g_wps_probe_req_ie, g_wps_probe_req_ie_len);
+ if (ret) {
+ WL_ERROR(("ioctl failed %d \n", ret));
+ }
+
+ kfree(g_wps_probe_req_ie);
+ g_wps_probe_req_ie = NULL;
+ g_wps_probe_req_ie_len = 0;
+ }
+
+ return 0;
+}
+
+static int
+wl_iw_add_wps_probe_req_ie(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra
+)
+{
+ char *str_ptr = NULL;
+ char *bufptr = NULL;
+ uint buflen, datalen, iecount, pktflag, iolen, total_len;
+ int ret = 0;
+ vndr_ie_setbuf_t *ie_setbuf = NULL;
+
+ if (!g_wps_probe_req_ie) {
+ ret = -1;
+ str_ptr = extra;
+ str_ptr += WPS_PROBE_REQ_IE_CMD_LENGTH;
+ datalen = wrqu->data.length - WPS_PROBE_REQ_IE_CMD_LENGTH;
+
+
+
+ buflen = sizeof(vndr_ie_setbuf_t) + datalen - sizeof(vndr_ie_t);
+ ie_setbuf = (vndr_ie_setbuf_t *)kmalloc(buflen, GFP_KERNEL);
+ if (!ie_setbuf) {
+ WL_ERROR(("memory alloc failure ie_setbuf\n"));
+ return ret;
+ }
+
+ memset(ie_setbuf, 0x00, buflen);
+
+
+ strncpy(ie_setbuf->cmd, "add", VNDR_IE_CMD_LEN - 1);
+ ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
+
+
+ iecount = htod32(1);
+ memcpy((void *)&ie_setbuf->vndr_ie_buffer.iecount, &iecount, sizeof(int));
+
+
+ pktflag = 0x10;
+ memcpy((void *)&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].pktflag,
+ &pktflag, sizeof(uint32));
+
+ memcpy((void *)&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data,
+ str_ptr, datalen);
+
+ total_len = strlen("vndr_ie ") + buflen;
+ bufptr = (char *)kmalloc(total_len, GFP_KERNEL);
+ if (!bufptr) {
+ WL_ERROR(("memory alloc failure bufptr\n"));
+ goto fail;
+ }
+
+ iolen = bcm_mkiovar("vndr_ie", (char *)ie_setbuf, buflen, bufptr, total_len);
+ if (iolen == 0) {
+ WL_ERROR(("Buffer length is illegal\n"));
+ goto fail2;
+ }
+
+ ret = dev_wlc_ioctl(dev, WLC_SET_VAR, bufptr, iolen);
+ if (ret) {
+ WL_ERROR(("ioctl failed\n"));
+ goto fail2;
+ }
+
+ g_wps_probe_req_ie = (char *)kmalloc(iolen, GFP_KERNEL);
+ if (!g_wps_probe_req_ie) {
+ WL_ERROR(("memory alloc failure g_wps_probe_req_ie\n"));
+ goto fail2;
+ }
+
+ memcpy(g_wps_probe_req_ie, bufptr, iolen);
+ g_wps_probe_req_ie_len = iolen;
+ }
+
+fail2:
+ if (bufptr) {
+ kfree(bufptr);
+ bufptr = NULL;
+ }
+fail:
+ if (ie_setbuf) {
+ kfree(ie_setbuf);
+ ie_setbuf = NULL;
+ }
+ return ret;
+}
+#endif
#ifdef SOFTAP
@@ -6345,11 +6469,14 @@
return res;
}
#endif
+
memset(&null_ssid, 0, sizeof(wlc_ssid_t));
res |= dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown));
+
#ifdef AP_ONLY
res |= dev_wlc_ioctl(dev, WLC_SET_SSID, &null_ssid, sizeof(null_ssid));
#else
+
iolen = wl_bssiovar_mkbuf("ssid", bsscfg_index, (char *)(&null_ssid),
null_ssid.SSID_len+4, buf, sizeof(buf), &mkvar_err);
ASSERT(iolen);
@@ -6660,6 +6787,7 @@
WL_SOFTAP((" channel = %d\n", ap->channel));
WL_SOFTAP((" max scb = %d\n", ap->max_scb));
+
if (strnicmp(ap->sec, "open", strlen("open")) == 0) {
@@ -7406,6 +7534,16 @@
else if (strnicmp(extra, CSCAN_COMMAND, strlen(CSCAN_COMMAND)) == 0)
ret = wl_iw_set_cscan(dev, info, (union iwreq_data *)dwrq, extra);
#endif
+#ifdef CONFIG_WPS2
+ else if (strnicmp(extra, WPS_ADD_PROBE_REQ_IE_CMD,
+ strlen(WPS_ADD_PROBE_REQ_IE_CMD)) == 0)
+ ret = wl_iw_add_wps_probe_req_ie(dev, info,
+ (union iwreq_data *)dwrq, extra);
+ else if (strnicmp(extra, WPS_DEL_PROBE_REQ_IE_CMD,
+ strlen(WPS_DEL_PROBE_REQ_IE_CMD)) == 0)
+ ret = wl_iw_del_wps_probe_req_ie(dev, info,
+ (union iwreq_data *)dwrq, extra);
+#endif
else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0)
ret = wl_iw_set_power_mode(dev, info, (union iwreq_data *)dwrq, extra);
else if (strnicmp(extra, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0)
@@ -7420,7 +7558,7 @@
WL_SOFTAP(("penguin, set AP_MAC_LIST_SET\n"));
set_ap_mac_list(dev, (extra + PROFILE_OFFSET));
}
-#endif
+#endif
else {
WL_ERROR(("Unknown PRIVATE command %s - ignored\n", extra));
snprintf(extra, MAX_WX_STRING, "OK");
@@ -7634,8 +7772,8 @@
{
WL_AP_STA_LIST,
- 0,
- IW_PRIV_TYPE_CHAR | 0,
+ IW_PRIV_TYPE_CHAR | 0,
+ IW_PRIV_TYPE_CHAR | 1024,
"AP_GET_STA_LIST"
},
@@ -7937,8 +8075,6 @@
uint32 datalen = ntoh32(e->datalen);
uint32 status = ntoh32(e->status);
uint32 toto;
- static uint32 roam_no_success = 0;
- static bool roam_no_success_send = FALSE;
memset(&wrqu, 0, sizeof(wrqu));
memset(extra, 0, sizeof(extra));
@@ -8006,26 +8142,12 @@
cmd = IWEVREGISTERED;
break;
case WLC_E_ROAM:
- if (status != WLC_E_STATUS_SUCCESS) {
- roam_no_success++;
- if ((roam_no_success == 3) && (roam_no_success_send == FALSE)) {
-
- roam_no_success_send = TRUE;
- bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN);
- bzero(&extra, ETHER_ADDR_LEN);
- cmd = SIOCGIWAP;
- WL_ERROR(("%s ROAMING did not succeeded , send Link Down\n",
- __FUNCTION__));
- } else {
- WL_TRACE(("##### ROAMING did not succeeded %d\n", roam_no_success));
- goto wl_iw_event_end;
- }
- } else {
- memcpy(wrqu.addr.sa_data, &e->addr.octet, ETHER_ADDR_LEN);
- wrqu.addr.sa_family = ARPHRD_ETHER;
- cmd = SIOCGIWAP;
+ if (status == WLC_E_STATUS_SUCCESS) {
+ WL_ASSOC((" WLC_E_ROAM : success \n"));
+ goto wl_iw_event_end;
}
break;
+
case WLC_E_DEAUTH_IND:
case WLC_E_DISASSOC_IND:
#if defined(SOFTAP)
@@ -8085,15 +8207,12 @@
wl_iw_send_priv_event(priv_dev, "AP_UP");
} else {
WL_TRACE(("STA_LINK_UP\n"));
- roam_no_success_send = FALSE;
- roam_no_success = 0;
}
#else
#endif
WL_TRACE(("Link UP\n"));
}
- net_os_wake_lock_timeout_enable(dev);
wrqu.addr.sa_family = ARPHRD_ETHER;
break;
case WLC_E_ACTION_FRAME:
@@ -8163,6 +8282,11 @@
case WLC_E_SCAN_COMPLETE:
#if defined(WL_IW_USE_ISCAN)
+ if (!g_iscan) {
+ WL_ERROR(("Event WLC_E_SCAN_COMPLETE on g_iscan NULL!"));
+ goto wl_iw_event_end;
+ }
+
if ((g_iscan) && (g_iscan->tsk_ctl.thr_pid >= 0) &&
(g_iscan->iscan_state != ISCAN_STATE_IDLE))
{
@@ -8189,7 +8313,6 @@
WL_ERROR(("%s Event WLC_E_PFN_NET_FOUND, send %s up : find %s len=%d\n",
__FUNCTION__, PNO_EVENT_UP, netinfo->pfnsubnet.SSID,
netinfo->pfnsubnet.SSID_len));
- net_os_wake_lock_timeout_enable(dev);
cmd = IWEVCUSTOM;
memset(&wrqu, 0, sizeof(wrqu));
strcpy(extra, PNO_EVENT_UP);
@@ -8546,6 +8669,10 @@
g_iscan->scan_flag = 0;
#endif
+#ifdef CONFIG_WPS2
+ g_wps_probe_req_ie = NULL;
+ g_wps_probe_req_ie_len = 0;
+#endif
iscan->timer_ms = 8000;
init_timer(&iscan->timer);
@@ -8613,6 +8740,14 @@
kfree(g_scan);
g_scan = NULL;
+#ifdef CONFIG_WPS2
+
+ if (g_wps_probe_req_ie) {
+ kfree(g_wps_probe_req_ie);
+ g_wps_probe_req_ie = NULL;
+ g_wps_probe_req_ie_len = 0;
+ }
+#endif
#if !defined(CSCAN)
wl_iw_release_ss_cache_ctrl();
#endif
diff --git a/drivers/net/wireless/bcmdhd/wl_iw.h b/drivers/net/wireless/bcmdhd/wl_iw.h
index a34472f..c0cc14b 100644
--- a/drivers/net/wireless/bcmdhd/wl_iw.h
+++ b/drivers/net/wireless/bcmdhd/wl_iw.h
@@ -203,7 +203,7 @@
extern int net_os_wake_lock(struct net_device *dev);
extern int net_os_wake_unlock(struct net_device *dev);
extern int net_os_wake_lock_timeout(struct net_device *dev);
-extern int net_os_wake_lock_timeout_enable(struct net_device *dev);
+extern int net_os_wake_lock_timeout_enable(struct net_device *dev, int val);
extern int net_os_set_suspend_disable(struct net_device *dev, int val);
extern int net_os_set_suspend(struct net_device *dev, int val);
extern int net_os_set_dtim_skip(struct net_device *dev, int val);
@@ -297,4 +297,10 @@
#define NETDEV_PRIV(dev) (*(wl_iw_t **)netdev_priv(dev))
+#ifdef CONFIG_WPS2
+#define WPS_ADD_PROBE_REQ_IE_CMD "ADD_WPS_PROBE_REQ_IE "
+#define WPS_DEL_PROBE_REQ_IE_CMD "DEL_WPS_PROBE_REQ_IE "
+#define WPS_PROBE_REQ_IE_CMD_LENGTH 21
+#endif
+
#endif
diff --git a/drivers/net/wireless/bcmdhd/wldev_common.c b/drivers/net/wireless/bcmdhd/wldev_common.c
index b01e4a2..bb3eaea 100644
--- a/drivers/net/wireless/bcmdhd/wldev_common.c
+++ b/drivers/net/wireless/bcmdhd/wldev_common.c
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: wldev_common.c,v 1.1.4.1.2.14 2011-02-09 01:40:07 Exp $
+ * $Id: wldev_common.c,v 1.1.4.1.2.14 2011-02-09 01:40:07 $
*/
#include <linux/module.h>
@@ -37,7 +37,6 @@
#define dtoh16(i) i
#define htodchanspec(i) i
#define dtohchanspec(i) i
-
extern int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd);
s32 wldev_ioctl(
@@ -78,7 +77,7 @@
s32 iovar_len = 0;
iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen);
- ret = wldev_ioctl(dev, WLC_GET_VAR, buf, iovar_len, FALSE);
+ ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE);
return ret;
}
@@ -184,7 +183,7 @@
s32 iovar_len = 0;
iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx);
- ret = wldev_ioctl(dev, WLC_GET_VAR, buf, iovar_len, FALSE);
+ ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE);
return ret;
}
@@ -309,18 +308,27 @@
if (!country_code)
return error;
- bzero(&scbval, sizeof(scb_val_t));
- error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), 1);
- if (error < 0) {
- DHD_ERROR(("%s: set country failed due to Disassoc error\n", __FUNCTION__));
- return error;
+ error = wldev_iovar_getbuf(dev, "country", &cspec, sizeof(cspec),
+ smbuf, sizeof(smbuf));
+ if (error < 0)
+ DHD_ERROR(("%s: get country failed = %d\n", __FUNCTION__, error));
+
+ if ((error < 0) ||
+ (strncmp(country_code, smbuf, WLC_CNTRY_BUF_SZ) != 0)) {
+ bzero(&scbval, sizeof(scb_val_t));
+ error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), 1);
+ if (error < 0) {
+ DHD_ERROR(("%s: set country failed due to Disassoc error %d\n",
+ __FUNCTION__, error));
+ return error;
+ }
}
cspec.rev = -1;
memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ);
memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ);
get_customized_country_code((char *)&cspec.country_abbrev, &cspec);
error = wldev_iovar_setbuf(dev, "country", &cspec, sizeof(cspec),
- smbuf, sizeof(smbuf));
+ smbuf, sizeof(smbuf));
if (error < 0) {
DHD_ERROR(("%s: set country for %s as %s rev %d failed\n",
__FUNCTION__, country_code, cspec.ccode, cspec.rev));
diff --git a/drivers/net/wireless/bcmdhd/wldev_common.h b/drivers/net/wireless/bcmdhd/wldev_common.h
index 2c1d968..4632680 100644
--- a/drivers/net/wireless/bcmdhd/wldev_common.h
+++ b/drivers/net/wireless/bcmdhd/wldev_common.h
@@ -89,7 +89,7 @@
extern int net_os_wake_lock(struct net_device *dev);
extern int net_os_wake_unlock(struct net_device *dev);
extern int net_os_wake_lock_timeout(struct net_device *dev);
-extern int net_os_wake_lock_timeout_enable(struct net_device *dev);
+extern int net_os_wake_lock_timeout_enable(struct net_device *dev, int val);
extern int net_os_set_dtim_skip(struct net_device *dev, int val);
extern int net_os_set_suspend_disable(struct net_device *dev, int val);
extern int net_os_set_suspend(struct net_device *dev, int val);
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index d508482..89a116f 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -855,6 +855,7 @@
iface = netdev_priv(dev);
ether_setup(dev);
+ dev->priv_flags &= ~IFF_TX_SKB_SHARING;
/* kernel callbacks */
if (iface) {
diff --git a/drivers/net/wireless/iwlegacy/iwl-3945-rs.c b/drivers/net/wireless/iwlegacy/iwl-3945-rs.c
index 977bd24..164bcae 100644
--- a/drivers/net/wireless/iwlegacy/iwl-3945-rs.c
+++ b/drivers/net/wireless/iwlegacy/iwl-3945-rs.c
@@ -822,12 +822,15 @@
out:
- rs_sta->last_txrate_idx = index;
- if (sband->band == IEEE80211_BAND_5GHZ)
- info->control.rates[0].idx = rs_sta->last_txrate_idx -
- IWL_FIRST_OFDM_RATE;
- else
+ if (sband->band == IEEE80211_BAND_5GHZ) {
+ if (WARN_ON_ONCE(index < IWL_FIRST_OFDM_RATE))
+ index = IWL_FIRST_OFDM_RATE;
+ rs_sta->last_txrate_idx = index;
+ info->control.rates[0].idx = index - IWL_FIRST_OFDM_RATE;
+ } else {
+ rs_sta->last_txrate_idx = index;
info->control.rates[0].idx = rs_sta->last_txrate_idx;
+ }
IWL_DEBUG_RATE(priv, "leave: %d\n", index);
}
diff --git a/drivers/net/wireless/iwlegacy/iwl-3945.c b/drivers/net/wireless/iwlegacy/iwl-3945.c
index d096dc2..dcc1552 100644
--- a/drivers/net/wireless/iwlegacy/iwl-3945.c
+++ b/drivers/net/wireless/iwlegacy/iwl-3945.c
@@ -1747,7 +1747,11 @@
}
memcpy(active_rxon, staging_rxon, sizeof(*active_rxon));
-
+ /*
+ * We do not commit tx power settings while channel changing,
+ * do it now if tx power changed.
+ */
+ iwl_legacy_set_tx_power(priv, priv->tx_power_next, false);
return 0;
}
diff --git a/drivers/net/wireless/iwlegacy/iwl-4965.c b/drivers/net/wireless/iwlegacy/iwl-4965.c
index facc94e..0a1babb 100644
--- a/drivers/net/wireless/iwlegacy/iwl-4965.c
+++ b/drivers/net/wireless/iwlegacy/iwl-4965.c
@@ -1237,7 +1237,12 @@
memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
iwl_legacy_print_rx_config_cmd(priv, ctx);
- goto set_tx_power;
+ /*
+ * We do not commit tx power settings while channel changing,
+ * do it now if tx power changed.
+ */
+ iwl_legacy_set_tx_power(priv, priv->tx_power_next, false);
+ return 0;
}
/* If we are currently associated and the new config requires
@@ -1317,7 +1322,6 @@
iwl4965_init_sensitivity(priv);
-set_tx_power:
/* If we issue a new RXON command which required a tune then we must
* send a new TXPOWER command or we won't be able to Tx any frames */
ret = iwl_legacy_set_tx_power(priv, priv->tx_power_next, true);
diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c
index 3be76bd..d273d50 100644
--- a/drivers/net/wireless/iwlegacy/iwl-core.c
+++ b/drivers/net/wireless/iwlegacy/iwl-core.c
@@ -938,7 +938,7 @@
&priv->contexts[IWL_RXON_CTX_BSS]);
#endif
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->wait_command_queue);
/* Keep the restart process from trying to send host
* commands by clearing the INIT status bit */
@@ -1776,7 +1776,7 @@
IWL_ERR(priv, "On demand firmware reload\n");
/* Set the FW error flag -- cleared on iwl_down */
set_bit(STATUS_FW_ERROR, &priv->status);
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->wait_command_queue);
/*
* Keep the restart process from trying to send host
* commands by clearing the INIT status bit
diff --git a/drivers/net/wireless/iwlegacy/iwl-hcmd.c b/drivers/net/wireless/iwlegacy/iwl-hcmd.c
index 62b4b09..ce1fc9f 100644
--- a/drivers/net/wireless/iwlegacy/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlegacy/iwl-hcmd.c
@@ -167,7 +167,7 @@
goto out;
}
- ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+ ret = wait_event_timeout(priv->wait_command_queue,
!test_bit(STATUS_HCMD_ACTIVE, &priv->status),
HOST_COMPLETE_TIMEOUT);
if (!ret) {
diff --git a/drivers/net/wireless/iwlegacy/iwl-tx.c b/drivers/net/wireless/iwlegacy/iwl-tx.c
index 4fff995..ef9e268 100644
--- a/drivers/net/wireless/iwlegacy/iwl-tx.c
+++ b/drivers/net/wireless/iwlegacy/iwl-tx.c
@@ -625,6 +625,8 @@
cmd = txq->cmd[cmd_index];
meta = &txq->meta[cmd_index];
+ txq->time_stamp = jiffies;
+
pci_unmap_single(priv->pci_dev,
dma_unmap_addr(meta, mapping),
dma_unmap_len(meta, len),
@@ -645,7 +647,7 @@
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s\n",
iwl_legacy_get_cmd_string(cmd->hdr.cmd));
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->wait_command_queue);
}
/* Mark as unmapped */
diff --git a/drivers/net/wireless/iwlegacy/iwl3945-base.c b/drivers/net/wireless/iwlegacy/iwl3945-base.c
index 0ee6be6..421d5c8 100644
--- a/drivers/net/wireless/iwlegacy/iwl3945-base.c
+++ b/drivers/net/wireless/iwlegacy/iwl3945-base.c
@@ -841,7 +841,7 @@
wiphy_rfkill_set_hw_state(priv->hw->wiphy,
test_bit(STATUS_RF_KILL_HW, &priv->status));
else
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->wait_command_queue);
}
/**
@@ -2518,7 +2518,7 @@
iwl3945_reg_txpower_periodic(priv);
IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->wait_command_queue);
return;
@@ -2549,7 +2549,7 @@
iwl_legacy_clear_driver_stations(priv);
/* Unblock any waiting calls */
- wake_up_interruptible_all(&priv->wait_command_queue);
+ wake_up_all(&priv->wait_command_queue);
/* Wipe out the EXIT_PENDING status bit if we are not actually
* exiting the module */
@@ -3125,7 +3125,7 @@
/* Wait for START_ALIVE from ucode. Otherwise callbacks from
* mac80211 will not be run successfully. */
- ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+ ret = wait_event_timeout(priv->wait_command_queue,
test_bit(STATUS_READY, &priv->status),
UCODE_READY_TIMEOUT);
if (!ret) {
diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c
index 7157ba5..0c37c02 100644
--- a/drivers/net/wireless/iwlegacy/iwl4965-base.c
+++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c
@@ -704,7 +704,7 @@
wiphy_rfkill_set_hw_state(priv->hw->wiphy,
test_bit(STATUS_RF_KILL_HW, &priv->status));
else
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->wait_command_queue);
}
/**
@@ -1054,7 +1054,7 @@
handled |= CSR_INT_BIT_FH_TX;
/* Wake up uCode load routine, now that load is complete */
priv->ucode_write_complete = 1;
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->wait_command_queue);
}
if (inta & ~handled) {
@@ -2126,7 +2126,7 @@
iwl4965_rf_kill_ct_config(priv);
IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->wait_command_queue);
iwl_legacy_power_update_mode(priv, true);
IWL_DEBUG_INFO(priv, "Updated power mode\n");
@@ -2159,7 +2159,7 @@
iwl_legacy_clear_driver_stations(priv);
/* Unblock any waiting calls */
- wake_up_interruptible_all(&priv->wait_command_queue);
+ wake_up_all(&priv->wait_command_queue);
/* Wipe out the EXIT_PENDING status bit if we are not actually
* exiting the module */
@@ -2597,7 +2597,7 @@
/* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from
* mac80211 will not be run successfully. */
- ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+ ret = wait_event_timeout(priv->wait_command_queue,
test_bit(STATUS_READY, &priv->status),
UCODE_READY_TIMEOUT);
if (!ret) {
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index e816c27..f1c3f49 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -421,6 +421,7 @@
.chain_noise_scale = 1000,
.wd_timeout = IWL_LONG_WD_TIMEOUT,
.max_event_log_size = 512,
+ .no_idle_support = true,
};
static struct iwl_ht_params iwl5000_ht_params = {
.ht_greenfield_support = true,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 8e1942e..f24165d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -2440,7 +2440,12 @@
IEEE80211_HW_SPECTRUM_MGMT |
IEEE80211_HW_REPORTS_TX_ACK_STATUS;
+ /*
+ * Including the following line will crash some AP's. This
+ * workaround removes the stimulus which causes the crash until
+ * the AP software can be fixed.
hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
+ */
hw->flags |= IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index a54d416..b76996a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -195,6 +195,7 @@
* @temperature_kelvin: temperature report by uCode in kelvin
* @max_event_log_size: size of event log buffer size for ucode event logging
* @shadow_reg_enable: HW shadhow register bit
+ * @no_idle_support: do not support idle mode
*/
struct iwl_base_params {
int eeprom_size;
@@ -216,6 +217,7 @@
bool temperature_kelvin;
u32 max_event_log_size;
const bool shadow_reg_enable;
+ const bool no_idle_support;
};
/*
* @advanced_bt_coexist: support advanced bt coexist
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index 595c930..4a05a6a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -355,7 +355,8 @@
dtimper = priv->hw->conf.ps_dtim_period ?: 1;
- if (priv->hw->conf.flags & IEEE80211_CONF_IDLE)
+ if (!priv->cfg->base_params->no_idle_support &&
+ priv->hw->conf.flags & IEEE80211_CONF_IDLE)
iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20);
else if (iwl_tt_is_low_power_state(priv)) {
/* in thermal throttling low power state */
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index d60d630..f524016 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -406,31 +406,33 @@
mutex_lock(&priv->mutex);
- if (test_bit(STATUS_SCANNING, &priv->status) &&
- priv->scan_type != IWL_SCAN_NORMAL) {
- IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
- ret = -EAGAIN;
- goto out_unlock;
- }
-
- /* mac80211 will only ask for one band at a time */
- priv->scan_request = req;
- priv->scan_vif = vif;
-
/*
* If an internal scan is in progress, just set
* up the scan_request as per above.
*/
if (priv->scan_type != IWL_SCAN_NORMAL) {
- IWL_DEBUG_SCAN(priv, "SCAN request during internal scan\n");
+ IWL_DEBUG_SCAN(priv,
+ "SCAN request during internal scan - defer\n");
+ priv->scan_request = req;
+ priv->scan_vif = vif;
ret = 0;
- } else
+ } else {
+ priv->scan_request = req;
+ priv->scan_vif = vif;
+ /*
+ * mac80211 will only ask for one band at a time
+ * so using channels[0] here is ok
+ */
ret = iwl_scan_initiate(priv, vif, IWL_SCAN_NORMAL,
req->channels[0]->band);
+ if (ret) {
+ priv->scan_request = NULL;
+ priv->scan_vif = NULL;
+ }
+ }
IWL_DEBUG_MAC80211(priv, "leave\n");
-out_unlock:
mutex_unlock(&priv->mutex);
return ret;
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 137dba9..c368c50 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -802,6 +802,8 @@
cmd = txq->cmd[cmd_index];
meta = &txq->meta[cmd_index];
+ txq->time_stamp = jiffies;
+
iwlagn_unmap_tfd(priv, meta, &txq->tfds[index], PCI_DMA_BIDIRECTIONAL);
/* Input error checking is done when commands are added to queue. */
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 2a6aa85..3f7ea1c 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -38,6 +38,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/sched.h>
#include "rt2x00.h"
#include "rt2800lib.h"
@@ -607,6 +608,15 @@
int wcid, ack, pid;
int tx_wcid, tx_ack, tx_pid;
+ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
+ !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) {
+ WARNING(entry->queue->rt2x00dev,
+ "Data pending for entry %u in queue %u\n",
+ entry->entry_idx, entry->queue->qid);
+ cond_resched();
+ return false;
+ }
+
wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
@@ -754,12 +764,11 @@
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
if (rt2800_txdone_entry_check(entry, reg))
break;
+ entry = NULL;
}
- if (!entry || rt2x00queue_empty(queue))
- break;
-
- rt2800_txdone_entry(entry, reg);
+ if (entry)
+ rt2800_txdone_entry(entry, reg);
}
}
EXPORT_SYMBOL_GPL(rt2800_txdone);
@@ -784,8 +793,7 @@
/*
* Add space for the TXWI in front of the skb.
*/
- skb_push(entry->skb, TXWI_DESC_SIZE);
- memset(entry->skb, 0, TXWI_DESC_SIZE);
+ memset(skb_push(entry->skb, TXWI_DESC_SIZE), 0, TXWI_DESC_SIZE);
/*
* Register descriptor details in skb frame descriptor.
@@ -3504,14 +3512,15 @@
rt2800_regbusy_read(rt2x00dev, EFUSE_CTRL, EFUSE_CTRL_KICK, ®);
/* Apparently the data is read from end to start */
- rt2800_register_read_lock(rt2x00dev, EFUSE_DATA3,
- (u32 *)&rt2x00dev->eeprom[i]);
- rt2800_register_read_lock(rt2x00dev, EFUSE_DATA2,
- (u32 *)&rt2x00dev->eeprom[i + 2]);
- rt2800_register_read_lock(rt2x00dev, EFUSE_DATA1,
- (u32 *)&rt2x00dev->eeprom[i + 4]);
- rt2800_register_read_lock(rt2x00dev, EFUSE_DATA0,
- (u32 *)&rt2x00dev->eeprom[i + 6]);
+ rt2800_register_read_lock(rt2x00dev, EFUSE_DATA3, ®);
+ /* The returned value is in CPU order, but eeprom is le */
+ rt2x00dev->eeprom[i] = cpu_to_le32(reg);
+ rt2800_register_read_lock(rt2x00dev, EFUSE_DATA2, ®);
+ *(u32 *)&rt2x00dev->eeprom[i + 2] = cpu_to_le32(reg);
+ rt2800_register_read_lock(rt2x00dev, EFUSE_DATA1, ®);
+ *(u32 *)&rt2x00dev->eeprom[i + 4] = cpu_to_le32(reg);
+ rt2800_register_read_lock(rt2x00dev, EFUSE_DATA0, ®);
+ *(u32 *)&rt2x00dev->eeprom[i + 6] = cpu_to_le32(reg);
mutex_unlock(&rt2x00dev->csr_mutex);
}
@@ -3677,19 +3686,23 @@
return -ENODEV;
}
- if (!rt2x00_rf(rt2x00dev, RF2820) &&
- !rt2x00_rf(rt2x00dev, RF2850) &&
- !rt2x00_rf(rt2x00dev, RF2720) &&
- !rt2x00_rf(rt2x00dev, RF2750) &&
- !rt2x00_rf(rt2x00dev, RF3020) &&
- !rt2x00_rf(rt2x00dev, RF2020) &&
- !rt2x00_rf(rt2x00dev, RF3021) &&
- !rt2x00_rf(rt2x00dev, RF3022) &&
- !rt2x00_rf(rt2x00dev, RF3052) &&
- !rt2x00_rf(rt2x00dev, RF3320) &&
- !rt2x00_rf(rt2x00dev, RF5370) &&
- !rt2x00_rf(rt2x00dev, RF5390)) {
- ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+ switch (rt2x00dev->chip.rf) {
+ case RF2820:
+ case RF2850:
+ case RF2720:
+ case RF2750:
+ case RF3020:
+ case RF2020:
+ case RF3021:
+ case RF3022:
+ case RF3052:
+ case RF3320:
+ case RF5370:
+ case RF5390:
+ break;
+ default:
+ ERROR(rt2x00dev, "Invalid RF chipset 0x%x detected.\n",
+ rt2x00dev->chip.rf);
return -ENODEV;
}
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index ba82c97..6e7fe94 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -477,8 +477,10 @@
while (!rt2x00queue_empty(queue)) {
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
- if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
+ !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
break;
+
if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
else if (rt2x00queue_status_timeout(entry))
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 93bec14..a76fdbe 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -113,7 +113,7 @@
* due to possible race conditions in mac80211.
*/
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
- goto exit_fail;
+ goto exit_free_skb;
/*
* Use the ATIM queue if appropriate and present.
@@ -127,7 +127,7 @@
ERROR(rt2x00dev,
"Attempt to send packet over invalid queue %d.\n"
"Please file bug report to %s.\n", qid, DRV_PROJECT);
- goto exit_fail;
+ goto exit_free_skb;
}
/*
@@ -159,6 +159,7 @@
exit_fail:
rt2x00queue_pause_queue(queue);
+ exit_free_skb:
dev_kfree_skb_any(skb);
}
EXPORT_SYMBOL_GPL(rt2x00mac_tx);
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index ab8c16f..2886d25 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -556,15 +556,21 @@
bool local)
{
struct ieee80211_tx_info *tx_info;
- struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
+ struct queue_entry *entry;
struct txentry_desc txdesc;
struct skb_frame_desc *skbdesc;
u8 rate_idx, rate_flags;
+ int ret = 0;
+
+ spin_lock(&queue->tx_lock);
+
+ entry = rt2x00queue_get_entry(queue, Q_INDEX);
if (unlikely(rt2x00queue_full(queue))) {
ERROR(queue->rt2x00dev,
"Dropping frame due to full tx queue %d.\n", queue->qid);
- return -ENOBUFS;
+ ret = -ENOBUFS;
+ goto out;
}
if (unlikely(test_and_set_bit(ENTRY_OWNER_DEVICE_DATA,
@@ -573,7 +579,8 @@
"Arrived at non-free entry in the non-full queue %d.\n"
"Please file bug report to %s.\n",
queue->qid, DRV_PROJECT);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
/*
@@ -635,7 +642,8 @@
if (unlikely(rt2x00queue_write_tx_data(entry, &txdesc))) {
clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
entry->skb = NULL;
- return -EIO;
+ ret = -EIO;
+ goto out;
}
set_bit(ENTRY_DATA_PENDING, &entry->flags);
@@ -644,7 +652,9 @@
rt2x00queue_write_tx_descriptor(entry, &txdesc);
rt2x00queue_kick_tx_queue(queue, &txdesc);
- return 0;
+out:
+ spin_unlock(&queue->tx_lock);
+ return ret;
}
int rt2x00queue_clear_beacon(struct rt2x00_dev *rt2x00dev,
@@ -1185,6 +1195,7 @@
struct data_queue *queue, enum data_queue_qid qid)
{
mutex_init(&queue->status_lock);
+ spin_lock_init(&queue->tx_lock);
spin_lock_init(&queue->index_lock);
queue->rt2x00dev = rt2x00dev;
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index 167d458..ad3d527 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -432,6 +432,7 @@
* @flags: Entry flags, see &enum queue_entry_flags.
* @status_lock: The mutex for protecting the start/stop/flush
* handling on this queue.
+ * @tx_lock: Spinlock to serialize tx operations on this queue.
* @index_lock: Spinlock to protect index handling. Whenever @index, @index_done or
* @index_crypt needs to be changed this lock should be grabbed to prevent
* index corruption due to concurrency.
@@ -458,6 +459,7 @@
unsigned long flags;
struct mutex status_lock;
+ spinlock_t tx_lock;
spinlock_t index_lock;
unsigned int count;
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 8f90f62..54f0b13 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -262,23 +262,20 @@
struct queue_entry *entry = (struct queue_entry *)urb->context;
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- if (!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return;
-
- if (rt2x00dev->ops->lib->tx_dma_done)
- rt2x00dev->ops->lib->tx_dma_done(entry);
-
- /*
- * Report the frame as DMA done
- */
- rt2x00lib_dmadone(entry);
-
/*
* Check if the frame was correctly uploaded
*/
if (urb->status)
set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
+ /*
+ * Report the frame as DMA done
+ */
+ rt2x00lib_dmadone(entry);
+ if (rt2x00dev->ops->lib->tx_dma_done)
+ rt2x00dev->ops->lib->tx_dma_done(entry);
/*
* Schedule the delayed work for reading the TX status
* from the device.
@@ -873,18 +870,8 @@
{
struct ieee80211_hw *hw = usb_get_intfdata(usb_intf);
struct rt2x00_dev *rt2x00dev = hw->priv;
- int retval;
- retval = rt2x00lib_suspend(rt2x00dev, state);
- if (retval)
- return retval;
-
- /*
- * Decrease usbdev refcount.
- */
- usb_put_dev(interface_to_usbdev(usb_intf));
-
- return 0;
+ return rt2x00lib_suspend(rt2x00dev, state);
}
EXPORT_SYMBOL_GPL(rt2x00usb_suspend);
@@ -893,8 +880,6 @@
struct ieee80211_hw *hw = usb_get_intfdata(usb_intf);
struct rt2x00_dev *rt2x00dev = hw->priv;
- usb_get_dev(interface_to_usbdev(usb_intf));
-
return rt2x00lib_resume(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00usb_resume);
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
index d2ec253..ce0444c 100644
--- a/drivers/net/wireless/rtlwifi/core.c
+++ b/drivers/net/wireless/rtlwifi/core.c
@@ -610,6 +610,11 @@
mac->link_state = MAC80211_NOLINK;
memset(mac->bssid, 0, 6);
+
+ /* reset sec info */
+ rtl_cam_reset_sec_info(hw);
+
+ rtl_cam_reset_all_entry(hw);
mac->vendor = PEER_UNKNOWN;
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
@@ -1063,6 +1068,9 @@
*or clear all entry here.
*/
rtl_cam_delete_one_entry(hw, mac_addr, key_idx);
+
+ rtl_cam_reset_sec_info(hw);
+
break;
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
index 254b64b..c872a23 100644
--- a/drivers/net/wireless/rtlwifi/pci.c
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -1709,15 +1709,17 @@
pcipriv->ndis_adapter.devnumber = PCI_SLOT(pdev->devfn);
pcipriv->ndis_adapter.funcnumber = PCI_FUNC(pdev->devfn);
- /*find bridge info */
- pcipriv->ndis_adapter.pcibridge_vendorid = bridge_pdev->vendor;
- for (tmp = 0; tmp < PCI_BRIDGE_VENDOR_MAX; tmp++) {
- if (bridge_pdev->vendor == pcibridge_vendors[tmp]) {
- pcipriv->ndis_adapter.pcibridge_vendor = tmp;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
- ("Pci Bridge Vendor is found index: %d\n",
- tmp));
- break;
+ if (bridge_pdev) {
+ /*find bridge info if available */
+ pcipriv->ndis_adapter.pcibridge_vendorid = bridge_pdev->vendor;
+ for (tmp = 0; tmp < PCI_BRIDGE_VENDOR_MAX; tmp++) {
+ if (bridge_pdev->vendor == pcibridge_vendors[tmp]) {
+ pcipriv->ndis_adapter.pcibridge_vendor = tmp;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ ("Pci Bridge Vendor is found index:"
+ " %d\n", tmp));
+ break;
+ }
}
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
index 3a92ba3..10b2ef0 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
@@ -549,15 +549,16 @@
(tcb_desc->rts_use_shortpreamble ? 1 : 0)
: (tcb_desc->rts_use_shortgi ? 1 : 0)));
if (mac->bw_40) {
- if (tcb_desc->packet_bw) {
+ if (rate_flag & IEEE80211_TX_RC_DUP_DATA) {
SET_TX_DESC_DATA_BW(txdesc, 1);
SET_TX_DESC_DATA_SC(txdesc, 3);
+ } else if(rate_flag & IEEE80211_TX_RC_40_MHZ_WIDTH){
+ SET_TX_DESC_DATA_BW(txdesc, 1);
+ SET_TX_DESC_DATA_SC(txdesc, mac->cur_40_prime_sc);
} else {
SET_TX_DESC_DATA_BW(txdesc, 0);
- if (rate_flag & IEEE80211_TX_RC_DUP_DATA)
- SET_TX_DESC_DATA_SC(txdesc,
- mac->cur_40_prime_sc);
- }
+ SET_TX_DESC_DATA_SC(txdesc, 0);
+ }
} else {
SET_TX_DESC_DATA_BW(txdesc, 0);
SET_TX_DESC_DATA_SC(txdesc, 0);
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c
index a9367eb..e4272b9 100644
--- a/drivers/net/wireless/rtlwifi/usb.c
+++ b/drivers/net/wireless/rtlwifi/usb.c
@@ -861,6 +861,7 @@
u8 tid = 0;
u16 seq_number = 0;
+ memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
if (ieee80211_is_auth(fc)) {
RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n"));
rtl_ips_nic_on(hw);
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 1c56f34..7453068 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -14,8 +14,8 @@
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/platform_device.h>
-#include <linux/firmware.h>
-#include <linux/parser.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
#include <linux/wcnss_wlan.h>
#include <linux/platform_data/qcom_wcnss_device.h>
#include <linux/workqueue.h>
@@ -31,7 +31,7 @@
/* module params */
#define WCNSS_CONFIG_UNSPECIFIED (-1)
static int has_48mhz_xo = WCNSS_CONFIG_UNSPECIFIED;
-module_param(has_48mhz_xo, int, S_IRUGO);
+module_param(has_48mhz_xo, int, S_IWUSR | S_IRUGO);
MODULE_PARM_DESC(has_48mhz_xo, "Is an external 48 MHz XO present");
static struct {
@@ -42,6 +42,7 @@
struct resource *rx_irq_res;
struct resource *gpios_5wire;
const struct dev_pm_ops *pm_ops;
+ int triggered;
int smd_channel_ready;
struct wcnss_wlan_config wlan_config;
struct delayed_work wcnss_work;
@@ -191,25 +192,16 @@
return 0;
}
-static int __devinit
-wcnss_wlan_probe(struct platform_device *pdev)
+static int
+wcnss_trigger_config(struct platform_device *pdev)
{
int ret;
struct qcom_wcnss_opts *pdata;
- /* verify we haven't been called more than once */
- if (penv) {
- dev_err(&pdev->dev, "cannot handle multiple devices.\n");
- return -ENODEV;
- }
-
- /* create an environment to track the device */
- penv = kzalloc(sizeof(*penv), GFP_KERNEL);
- if (!penv) {
- dev_err(&pdev->dev, "cannot allocate device memory.\n");
- return -ENOMEM;
- }
- penv->pdev = pdev;
+ /* make sure we are only triggered once */
+ if (penv->triggered)
+ return 0;
+ penv->triggered = 1;
/* initialize the WCNSS device configuration */
pdata = pdev->dev.platform_data;
@@ -281,6 +273,75 @@
return ret;
}
+#ifndef MODULE
+static int wcnss_node_open(struct inode *inode, struct file *file)
+{
+ struct platform_device *pdev;
+
+ pr_info(DEVICE " triggered by userspace\n");
+
+ pdev = penv->pdev;
+ return wcnss_trigger_config(pdev);
+}
+
+static const struct file_operations wcnss_node_fops = {
+ .owner = THIS_MODULE,
+ .open = wcnss_node_open,
+};
+
+static struct miscdevice wcnss_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = DEVICE,
+ .fops = &wcnss_node_fops,
+};
+#endif /* ifndef MODULE */
+
+
+static int __devinit
+wcnss_wlan_probe(struct platform_device *pdev)
+{
+ /* verify we haven't been called more than once */
+ if (penv) {
+ dev_err(&pdev->dev, "cannot handle multiple devices.\n");
+ return -ENODEV;
+ }
+
+ /* create an environment to track the device */
+ penv = kzalloc(sizeof(*penv), GFP_KERNEL);
+ if (!penv) {
+ dev_err(&pdev->dev, "cannot allocate device memory.\n");
+ return -ENOMEM;
+ }
+ penv->pdev = pdev;
+
+#ifdef MODULE
+
+ /*
+ * Since we were built as a module, we are running because
+ * the module was loaded, therefore we assume userspace
+ * applications are available to service PIL, so we can
+ * trigger the WCNSS configuration now
+ */
+ pr_info(DEVICE " probed in MODULE mode\n");
+ return wcnss_trigger_config(pdev);
+
+#else
+
+ /*
+ * Since we were built into the kernel we'll be called as part
+ * of kernel initialization. We don't know if userspace
+ * applications are available to service PIL at this time
+ * (they probably are not), so we simply create a device node
+ * here. When userspace is available it should touch the
+ * device so that we know that WCNSS configuration can take
+ * place
+ */
+ pr_info(DEVICE " probed in built-in mode\n");
+ return misc_register(&wcnss_misc);
+
+#endif
+}
+
static int __devexit
wcnss_wlan_remove(struct platform_device *pdev)
{
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index 3dc9bef..6dcc7e2 100644
--- a/drivers/pci/dmar.c
+++ b/drivers/pci/dmar.c
@@ -1388,7 +1388,7 @@
return ret;
}
- ret = request_irq(irq, dmar_fault, 0, iommu->name, iommu);
+ ret = request_irq(irq, dmar_fault, IRQF_NO_THREAD, iommu->name, iommu);
if (ret)
printk(KERN_ERR "IOMMU: can't request irq\n");
return ret;
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 75a6b5e..26441cd 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -13,7 +13,7 @@
config SPS
bool "SPS support"
depends on (HAS_IOMEM && (ARCH_MSM8960 || ARCH_MSM8X60 \
- || ARCH_APQ8064 || ARCH_MSM9615))
+ || ARCH_APQ8064 || ARCH_MSM9615 || ARCH_MSMCOPPER))
select GENERIC_ALLOCATOR
default n
help
@@ -28,10 +28,17 @@
depends on SPS
default n
help
- The BAM-DMA is used for Memory-to-Memory transfers.
- The main use cases is RPC between processors.
- The BAM-DMA hardware has 2 registers sets:
- 1. A BAM HW like all the peripherals.
- 2. A DMA channel configuration (i.e. channel priority).
+ The BAM-DMA is used for Memory-to-Memory transfers.
+ The main use cases is RPC between processors.
+ The BAM-DMA hardware has 2 registers sets:
+ 1. A BAM HW like all the peripherals.
+ 2. A DMA channel configuration (i.e. channel priority).
+
+config SPS_SUPPORT_NDP_BAM
+ bool "SPS support NDP BAM"
+ depends on SPS
+ default n
+ help
+ No-Data-Path BAM is used to improve BAM performance.
endmenu
diff --git a/drivers/platform/msm/sps/Makefile b/drivers/platform/msm/sps/Makefile
old mode 100755
new mode 100644
diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c
index 2af4fa4..4279603 100644
--- a/drivers/platform/msm/sps/bam.c
+++ b/drivers/platform/msm/sps/bam.c
@@ -28,6 +28,286 @@
#define BAM_MIN_VERSION 2
#define BAM_MAX_VERSION 0x1f
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+
+/* Maximum number of execution environment */
+#define BAM_MAX_EES 8
+
+/**
+ * BAM Hardware registers.
+ *
+ */
+#define CTRL (0x0)
+#define REVISION (0x4)
+#define SW_REVISION (0x80)
+#define NUM_PIPES (0x3c)
+#define TIMER (0x40)
+#define TIMER_CTRL (0x44)
+#define DESC_CNT_TRSHLD (0x8)
+#define IRQ_SRCS (0xc)
+#define IRQ_SRCS_MSK (0x10)
+#define IRQ_SRCS_UNMASKED (0x30)
+#define IRQ_STTS (0x14)
+#define IRQ_CLR (0x18)
+#define IRQ_EN (0x1c)
+#define AHB_MASTER_ERR_CTRLS (0x24)
+#define AHB_MASTER_ERR_ADDR (0x28)
+#define AHB_MASTER_ERR_DATA (0x2c)
+#define TRUST_REG (0x70)
+#define TEST_BUS_SEL (0x74)
+#define TEST_BUS_REG (0x78)
+#define CNFG_BITS (0x7c)
+#define IRQ_SRCS_EE(n) (0x800 + 128 * (n))
+#define IRQ_SRCS_MSK_EE(n) (0x804 + 128 * (n))
+#define IRQ_SRCS_UNMASKED_EE(n) (0x808 + 128 * (n))
+
+#define P_CTRL(n) (0x1000 + 4096 * (n))
+#define P_RST(n) (0x1004 + 4096 * (n))
+#define P_HALT(n) (0x1008 + 4096 * (n))
+#define P_IRQ_STTS(n) (0x1010 + 4096 * (n))
+#define P_IRQ_CLR(n) (0x1014 + 4096 * (n))
+#define P_IRQ_EN(n) (0x1018 + 4096 * (n))
+#define P_TIMER(n) (0x101c + 4096 * (n))
+#define P_TIMER_CTRL(n) (0x1020 + 4096 * (n))
+#define P_PRDCR_SDBND(n) (0x1024 + 4096 * (n))
+#define P_CNSMR_SDBND(n) (0x1028 + 4096 * (n))
+#define P_TRUST_REG(n) (0x1030 + 4096 * (n))
+#define P_EVNT_DEST_ADDR(n) (0x182c + 4096 * (n))
+#define P_EVNT_REG(n) (0x1818 + 4096 * (n))
+#define P_SW_OFSTS(n) (0x1800 + 4096 * (n))
+#define P_DATA_FIFO_ADDR(n) (0x1824 + 4096 * (n))
+#define P_DESC_FIFO_ADDR(n) (0x181c + 4096 * (n))
+#define P_EVNT_GEN_TRSHLD(n) (0x1828 + 4096 * (n))
+#define P_FIFO_SIZES(n) (0x1820 + 4096 * (n))
+#define P_RETR_CNTXT(n) (0x1834 + 4096 * (n))
+#define P_SI_CNTXT(n) (0x1838 + 4096 * (n))
+#define P_DF_CNTXT(n) (0x1830 + 4096 * (n))
+#define P_AU_PSM_CNTXT_1(n) (0x1804 + 4096 * (n))
+#define P_PSM_CNTXT_2(n) (0x1808 + 4096 * (n))
+#define P_PSM_CNTXT_3(n) (0x180c + 4096 * (n))
+#define P_PSM_CNTXT_4(n) (0x1810 + 4096 * (n))
+#define P_PSM_CNTXT_5(n) (0x1814 + 4096 * (n))
+
+/**
+ * BAM Hardware registers bitmask.
+ * format: <register>_<field>
+ *
+ */
+/* CTRL */
+#define IBC_DISABLE 0x10000
+#define BAM_CACHED_DESC_STORE 0x8000
+#define BAM_DESC_CACHE_SEL 0x6000
+#define BAM_EN_ACCUM 0x10
+#define BAM_EN 0x2
+#define BAM_SW_RST 0x1
+
+/* REVISION */
+#define BAM_INACTIV_TMR_BASE 0xff000000
+#define BAM_CMD_DESC_EN 0x800000
+#define BAM_DESC_CACHE_DEPTH 0x600000
+#define BAM_NUM_INACTIV_TMRS 0x100000
+#define BAM_INACTIV_TMRS_EXST 0x80000
+#define BAM_HIGH_FREQUENCY_BAM 0x40000
+#define BAM_HAS_NO_BYPASS 0x20000
+#define BAM_SECURED 0x10000
+#define BAM_USE_VMIDMT 0x8000
+#define BAM_AXI_ACTIVE 0x4000
+#define BAM_CE_BUFFER_SIZE 0x2000
+#define BAM_NUM_EES 0xf00
+#define BAM_REVISION 0xff
+
+/* SW_REVISION */
+#define BAM_MAJOR 0xf0000000
+#define BAM_MINOR 0xfff0000
+#define BAM_STEP 0xffff
+
+/* NUM_PIPES */
+#define BAM_NON_PIPE_GRP 0xff000000
+#define BAM_PERIPH_NON_PIPE_GRP 0xff0000
+#define BAM_NUM_PIPES 0xff
+
+/* TIMER */
+#define BAM_TIMER 0xffff
+
+/* TIMER_CTRL */
+#define TIMER_RST 0x80000000
+#define TIMER_RUN 0x40000000
+#define TIMER_MODE 0x20000000
+#define TIMER_TRSHLD 0xffff
+
+/* DESC_CNT_TRSHLD */
+#define BAM_DESC_CNT_TRSHLD 0xffff
+
+/* IRQ_SRCS */
+#define BAM_IRQ 0x80000000
+#define P_IRQ 0x7fffffff
+
+/* IRQ_STTS */
+#define IRQ_STTS_BAM_TIMER_IRQ 0x10
+#define IRQ_STTS_BAM_EMPTY_IRQ 0x8
+#define IRQ_STTS_BAM_ERROR_IRQ 0x4
+#define IRQ_STTS_BAM_HRESP_ERR_IRQ 0x2
+
+/* IRQ_CLR */
+#define IRQ_CLR_BAM_TIMER_IRQ 0x10
+#define IRQ_CLR_BAM_EMPTY_CLR 0x8
+#define IRQ_CLR_BAM_ERROR_CLR 0x4
+#define IRQ_CLR_BAM_HRESP_ERR_CLR 0x2
+
+/* IRQ_EN */
+#define IRQ_EN_BAM_TIMER_IRQ 0x10
+#define IRQ_EN_BAM_EMPTY_EN 0x8
+#define IRQ_EN_BAM_ERROR_EN 0x4
+#define IRQ_EN_BAM_HRESP_ERR_EN 0x2
+
+/* AHB_MASTER_ERR_CTRLS */
+#define AHB_MASTER_ERR_CTRLS_BAM_ERR_HVMID 0x7c0000
+#define AHB_MASTER_ERR_CTRLS_BAM_ERR_DIRECT_MODE 0x20000
+#define AHB_MASTER_ERR_CTRLS_BAM_ERR_HCID 0x1f000
+#define AHB_MASTER_ERR_CTRLS_BAM_ERR_HPROT 0xf00
+#define AHB_MASTER_ERR_CTRLS_BAM_ERR_HBURST 0xe0
+#define AHB_MASTER_ERR_CTRLS_BAM_ERR_HSIZE 0x18
+#define AHB_MASTER_ERR_CTRLS_BAM_ERR_HWRITE 0x4
+#define AHB_MASTER_ERR_CTRLS_BAM_ERR_HTRANS 0x3
+
+/* TRUST_REG */
+#define BAM_VMID 0x1f00
+#define BAM_RST_BLOCK 0x80
+#define BAM_EE 0x7
+
+/* TEST_BUS_SEL */
+#define BAM_DATA_ERASE 0x40000
+#define BAM_DATA_FLUSH 0x20000
+#define BAM_CLK_ALWAYS_ON 0x10000
+#define BAM_TESTBUS_SEL 0x7f
+
+/* CNFG_BITS */
+#define CNFG_BITS_BAM_CD_ENABLE 0x8000000
+#define CNFG_BITS_BAM_AU_ACCUMED 0x4000000
+#define CNFG_BITS_BAM_PSM_P_HD_DATA 0x2000000
+#define CNFG_BITS_BAM_REG_P_EN 0x1000000
+#define CNFG_BITS_BAM_WB_DSC_AVL_P_RST 0x800000
+#define CNFG_BITS_BAM_WB_RETR_SVPNT 0x400000
+#define CNFG_BITS_BAM_WB_CSW_ACK_IDL 0x200000
+#define CNFG_BITS_BAM_WB_BLK_CSW 0x100000
+#define CNFG_BITS_BAM_WB_P_RES 0x80000
+#define CNFG_BITS_BAM_SI_P_RES 0x40000
+#define CNFG_BITS_BAM_AU_P_RES 0x20000
+#define CNFG_BITS_BAM_PSM_P_RES 0x10000
+#define CNFG_BITS_BAM_PSM_CSW_REQ 0x8000
+#define CNFG_BITS_BAM_SB_CLK_REQ 0x4000
+#define CNFG_BITS_BAM_IBC_DISABLE 0x2000
+#define CNFG_BITS_BAM_NO_EXT_P_RST 0x1000
+#define CNFG_BITS_BAM_FULL_PIPE 0x800
+#define CNFG_BITS_BAM_PIPE_CNFG 0x4
+
+/* P_ctrln */
+#define P_LOCK_GROUP 0x1f0000
+#define P_WRITE_NWD 0x800
+#define P_PREFETCH_LIMIT 0x600
+#define P_AUTO_EOB_SEL 0x180
+#define P_AUTO_EOB 0x40
+#define P_SYS_MODE 0x20
+#define P_SYS_STRM 0x10
+#define P_DIRECTION 0x8
+#define P_EN 0x2
+
+/* P_RSTn */
+#define P_RST_P_SW_RST 0x1
+
+/* P_HALTn */
+#define P_HALT_P_PROD_HALTED 0x2
+#define P_HALT_P_HALT 0x1
+
+/* P_TRUST_REGn */
+#define BAM_P_VMID 0x1f00
+#define BAM_P_EE 0x7
+
+/* P_IRQ_STTSn */
+#define P_IRQ_STTS_P_TRNSFR_END_IRQ 0x20
+#define P_IRQ_STTS_P_ERR_IRQ 0x10
+#define P_IRQ_STTS_P_OUT_OF_DESC_IRQ 0x8
+#define P_IRQ_STTS_P_WAKE_IRQ 0x4
+#define P_IRQ_STTS_P_TIMER_IRQ 0x2
+#define P_IRQ_STTS_P_PRCSD_DESC_IRQ 0x1
+
+/* P_IRQ_CLRn */
+#define P_IRQ_CLR_P_TRNSFR_END_CLR 0x20
+#define P_IRQ_CLR_P_ERR_CLR 0x10
+#define P_IRQ_CLR_P_OUT_OF_DESC_CLR 0x8
+#define P_IRQ_CLR_P_WAKE_CLR 0x4
+#define P_IRQ_CLR_P_TIMER_CLR 0x2
+#define P_IRQ_CLR_P_PRCSD_DESC_CLR 0x1
+
+/* P_IRQ_ENn */
+#define P_IRQ_EN_P_TRNSFR_END_EN 0x20
+#define P_IRQ_EN_P_ERR_EN 0x10
+#define P_IRQ_EN_P_OUT_OF_DESC_EN 0x8
+#define P_IRQ_EN_P_WAKE_EN 0x4
+#define P_IRQ_EN_P_TIMER_EN 0x2
+#define P_IRQ_EN_P_PRCSD_DESC_EN 0x1
+
+/* P_TIMERn */
+#define P_TIMER_P_TIMER 0xffff
+
+/* P_TIMER_ctrln */
+#define P_TIMER_RST 0x80000000
+#define P_TIMER_RUN 0x40000000
+#define P_TIMER_MODE 0x20000000
+#define P_TIMER_TRSHLD 0xffff
+
+/* P_PRDCR_SDBNDn */
+#define P_PRDCR_SDBNDn_BAM_P_SB_UPDATED 0x1000000
+#define P_PRDCR_SDBNDn_BAM_P_TOGGLE 0x100000
+#define P_PRDCR_SDBNDn_BAM_P_CTRL 0xf0000
+#define P_PRDCR_SDBNDn_BAM_P_BYTES_FREE 0xffff
+
+/* P_CNSMR_SDBNDn */
+#define P_CNSMR_SDBNDn_BAM_P_SB_UPDATED 0x1000000
+#define P_CNSMR_SDBNDn_BAM_P_WAIT_4_ACK 0x800000
+#define P_CNSMR_SDBNDn_BAM_P_ACK_TOGGLE 0x400000
+#define P_CNSMR_SDBNDn_BAM_P_ACK_TOGGLE_R 0x200000
+#define P_CNSMR_SDBNDn_BAM_P_TOGGLE 0x100000
+#define P_CNSMR_SDBNDn_BAM_P_CTRL 0xf0000
+#define P_CNSMR_SDBNDn_BAM_P_BYTES_AVAIL 0xffff
+
+/* P_EVNT_regn */
+#define P_BYTES_CONSUMED 0xffff0000
+#define P_DESC_FIFO_PEER_OFST 0xffff
+
+/* P_SW_ofstsn */
+#define SW_OFST_IN_DESC 0xffff0000
+#define SW_DESC_OFST 0xffff
+
+/* P_EVNT_GEN_TRSHLDn */
+#define P_EVNT_GEN_TRSHLD_P_TRSHLD 0xffff
+
+/* P_FIFO_sizesn */
+#define P_DATA_FIFO_SIZE 0xffff0000
+#define P_DESC_FIFO_SIZE 0xffff
+
+#define P_RETR_CNTXT_RETR_DESC_OFST 0xffff0000
+#define P_RETR_CNTXT_RETR_OFST_IN_DESC 0xffff
+#define P_SI_CNTXT_SI_DESC_OFST 0xffff
+#define P_DF_CNTXT_WB_ACCUMULATED 0xffff0000
+#define P_DF_CNTXT_DF_DESC_OFST 0xffff
+#define P_AU_PSM_CNTXT_1_AU_PSM_ACCUMED 0xffff0000
+#define P_AU_PSM_CNTXT_1_AU_ACKED 0xffff
+#define P_PSM_CNTXT_2_PSM_DESC_VALID 0x80000000
+#define P_PSM_CNTXT_2_PSM_DESC_IRQ 0x40000000
+#define P_PSM_CNTXT_2_PSM_DESC_IRQ_DONE 0x20000000
+#define P_PSM_CNTXT_2_PSM_GENERAL_BITS 0x1e000000
+#define P_PSM_CNTXT_2_PSM_CONS_STATE 0x1c00000
+#define P_PSM_CNTXT_2_PSM_PROD_SYS_STATE 0x380000
+#define P_PSM_CNTXT_2_PSM_PROD_B2B_STATE 0x70000
+#define P_PSM_CNTXT_2_PSM_DESC_SIZE 0xffff
+#define P_PSM_CNTXT_4_PSM_DESC_OFST 0xffff0000
+#define P_PSM_CNTXT_4_PSM_SAVED_ACCUMED_SIZE 0xffff
+#define P_PSM_CNTXT_5_PSM_BLOCK_BYTE_CNT 0xffff0000
+#define P_PSM_CNTXT_5_PSM_OFST_IN_DESC 0xffff
+
+#else
+
/* Maximum number of execution environment */
#define BAM_MAX_EES 4
@@ -263,6 +543,7 @@
#define P_PSM_CNTXT_4_PSM_SAVED_ACCUMED_SIZE 0xffff
#define P_PSM_CNTXT_5_PSM_BLOCK_BYTE_CNT 0xffff0000
#define P_PSM_CNTXT_5_PSM_OFST_IN_DESC 0xffff
+#endif
#define BAM_ERROR (-1)
@@ -658,9 +939,10 @@
void bam_pipe_satellite_mti(void *base, u32 pipe, u32 irq_gen_addr, u32 ee)
{
bam_write_reg(base, P_IRQ_EN(pipe), 0);
+#ifndef CONFIG_SPS_SUPPORT_NDP_BAM
bam_write_reg(base, P_IRQ_DEST_ADDR(pipe), irq_gen_addr);
-
bam_write_reg_field(base, IRQ_SIC_SEL, (1 << pipe), 1);
+#endif
bam_write_reg_field(base, IRQ_SRCS_MSK, (1 << pipe), 1);
}
@@ -680,9 +962,9 @@
* interrupt. Since the remote processor enable both SIC and interrupt,
* the interrupt enable mask must be set to zero for polling mode.
*/
-
+#ifndef CONFIG_SPS_SUPPORT_NDP_BAM
bam_write_reg(base, P_IRQ_DEST_ADDR(pipe), irq_gen_addr);
-
+#endif
if (!irq_en)
src_mask = 0;
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index e43166e..b002657 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -26,6 +26,7 @@
#include <linux/platform_device.h> /* platform_get_resource_byname() */
#include <linux/debugfs.h>
#include <linux/uaccess.h>
+#include <linux/of.h>
#include <mach/msm_sps.h> /* msm_sps_platform_data */
#include "sps_bam.h"
@@ -1428,13 +1429,74 @@
return 0;
}
+/**
+ * Read data from device tree
+ */
+static int get_device_tree_data(struct platform_device *pdev)
+{
+#ifdef CONFIG_SPS_SUPPORT_BAMDMA
+ struct resource *resource;
+
+ if (of_property_read_u32((&pdev->dev)->of_node,
+ "qcom,bam-dma-res-pipes",
+ &sps->bamdma_restricted_pipes))
+ return -EINVAL;
+ else
+ SPS_DBG("sps:bamdma_restricted_pipes=0x%x.",
+ sps->bamdma_restricted_pipes);
+
+ resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (resource) {
+ sps->bamdma_bam_phys_base = resource->start;
+ sps->bamdma_bam_size = resource_size(resource);
+ SPS_DBG("sps:bamdma_bam.base=0x%x,size=0x%x.",
+ sps->bamdma_bam_phys_base,
+ sps->bamdma_bam_size);
+ } else {
+ SPS_ERR("sps:BAM DMA BAM mem unavailable.");
+ return -ENODEV;
+ }
+
+ resource = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (resource) {
+ sps->bamdma_dma_phys_base = resource->start;
+ sps->bamdma_dma_size = resource_size(resource);
+ SPS_DBG("sps:bamdma_dma.base=0x%x,size=0x%x.",
+ sps->bamdma_dma_phys_base,
+ sps->bamdma_dma_size);
+ } else {
+ SPS_ERR("sps:BAM DMA mem unavailable.");
+ return -ENODEV;
+ }
+
+ resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (resource) {
+ sps->bamdma_irq = resource->start;
+ SPS_DBG("sps:bamdma_irq=%d.", sps->bamdma_irq);
+ } else {
+ SPS_ERR("sps:BAM DMA IRQ unavailable.");
+ return -ENODEV;
+ }
+#endif
+
+ return 0;
+}
+
static int __devinit msm_sps_probe(struct platform_device *pdev)
{
int ret;
SPS_DBG("sps:msm_sps_probe.");
- ret = get_platform_data(pdev);
+ if (pdev->dev.of_node) {
+ SPS_DBG("sps:get data from device tree.");
+ ret = get_device_tree_data(pdev);
+
+ } else {
+ SPS_DBG("sps:get platform data.");
+ ret = get_platform_data(pdev);
+ }
+
if (ret)
return -ENODEV;
@@ -1542,11 +1604,18 @@
return 0;
}
+static struct of_device_id msm_sps_match[] = {
+ { .compatible = "qcom,msm_sps",
+ },
+ {}
+};
+
static struct platform_driver msm_sps_driver = {
.probe = msm_sps_probe,
.driver = {
.name = SPS_DRV_NAME,
.owner = THIS_MODULE,
+ .of_match_table = msm_sps_match,
},
.remove = __exit_p(msm_sps_remove),
};
diff --git a/drivers/platform/msm/sps/sps_dma.c b/drivers/platform/msm/sps/sps_dma.c
index 9f42403..b650098 100644
--- a/drivers/platform/msm/sps/sps_dma.c
+++ b/drivers/platform/msm/sps/sps_dma.c
@@ -26,14 +26,24 @@
*/
#define DMA_ENBL (0x00000000)
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+#define DMA_REVISION (0x00000004)
+#define DMA_CONFIG (0x00000008)
+#define DMA_CHNL_CONFIG(n) (0x00001000 + 4096 * (n))
+#else
#define DMA_CHNL_CONFIG(n) (0x00000004 + 4 * (n))
#define DMA_CONFIG (0x00000040)
+#endif
/**
* masks
*/
/* DMA_CHNL_confign */
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+#define DMA_CHNL_PRODUCER_PIPE_ENABLED 0x40000
+#define DMA_CHNL_CONSUMER_PIPE_ENABLED 0x20000
+#endif
#define DMA_CHNL_HALT_DONE 0x10000
#define DMA_CHNL_HALT 0x1000
#define DMA_CHNL_ENABLE 0x100
diff --git a/drivers/platform/msm/sps/sps_mem.c b/drivers/platform/msm/sps/sps_mem.c
index 3aee4ba..31c1314 100644
--- a/drivers/platform/msm/sps/sps_mem.c
+++ b/drivers/platform/msm/sps/sps_mem.c
@@ -104,10 +104,13 @@
*/
int sps_mem_init(u32 pipemem_phys_base, u32 pipemem_size)
{
+#ifndef CONFIG_SPS_SUPPORT_NDP_BAM
int res;
+#endif
/* 2^8=128. The desc-fifo and data-fifo minimal allocation. */
int min_alloc_order = 8;
+#ifndef CONFIG_SPS_SUPPORT_NDP_BAM
iomem_phys = pipemem_phys_base;
iomem_size = pipemem_size;
@@ -125,11 +128,14 @@
iomem_offset = 0;
SPS_DBG("sps:sps_mem_init.iomem_phys=0x%x,iomem_virt=0x%x.",
iomem_phys, (u32) iomem_virt);
+#endif
pool = gen_pool_create(min_alloc_order, nid);
+#ifndef CONFIG_SPS_SUPPORT_NDP_BAM
res = gen_pool_add(pool, (u32) iomem_virt, iomem_size, nid);
if (res)
return res;
+#endif
return 0;
}
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 3c7857c..e1678b9 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -797,8 +797,8 @@
* Hwmon device
*/
static ssize_t asus_hwmon_pwm1(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+ struct device_attribute *attr,
+ char *buf)
{
struct asus_wmi *asus = dev_get_drvdata(dev);
u32 value;
@@ -809,7 +809,7 @@
if (err < 0)
return err;
- value |= 0xFF;
+ value &= 0xFF;
if (value == 1) /* Low Speed */
value = 85;
@@ -869,7 +869,7 @@
* - reverved bits are non-zero
* - sfun and presence bit are not set
*/
- if (value != ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000
+ if (value == ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000
|| (!asus->sfun && !(value & ASUS_WMI_DSTS_PRESENCE_BIT)))
ok = false;
}
@@ -904,6 +904,7 @@
pr_err("Could not register asus hwmon device\n");
return PTR_ERR(hwmon);
}
+ dev_set_drvdata(hwmon, asus);
asus->hwmon_device = hwmon;
result = sysfs_create_group(&hwmon->kobj, &hwmon_attribute_group);
if (result)
@@ -1164,14 +1165,18 @@
static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- int value;
+ int value, rv;
if (!count || sscanf(buf, "%i", &value) != 1)
return -EINVAL;
if (value < 0 || value > 2)
return -EINVAL;
- return asus_wmi_evaluate_method(ASUS_WMI_METHODID_CFVS, value, 0, NULL);
+ rv = asus_wmi_evaluate_method(ASUS_WMI_METHODID_CFVS, value, 0, NULL);
+ if (rv < 0)
+ return rv;
+
+ return count;
}
static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv);
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c
index d347116..1658575 100644
--- a/drivers/platform/x86/samsung-laptop.c
+++ b/drivers/platform/x86/samsung-laptop.c
@@ -601,6 +601,16 @@
.callback = dmi_check_cb,
},
{
+ .ident = "N150/N210/N220",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR,
+ "SAMSUNG ELECTRONICS CO., LTD."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
+ DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
+ },
+ .callback = dmi_check_cb,
+ },
+ {
.ident = "N150/N210/N220/N230",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR,
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index cca1035..3dfa68e 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -244,7 +244,7 @@
config BATTERY_MSM8X60
tristate "MSM8X60 battery"
- select PMIC8058_BATTALARM
+ select PMIC8XXX_BATTALARM
help
Some MSM boards have dual charging paths to charge the battery.
Say Y to enable support for the battery charging in
@@ -332,7 +332,21 @@
help
Say Y here to enable support for pm8921 chip charger subdevice
+config PM8XXX_CCADC
+ tristate "PM8XXX battery current adc driver"
+ depends on MFD_PM8921_CORE
+ help
+ Say Y here to enable support for pm8921 chip bms subdevice
+
+config LTC4088_CHARGER
+ tristate "LTC4088 Charger driver"
+ depends on GPIOLIB
+ help
+ Say Y here to enable support for ltc4088 chip charger. It controls the
+ operations through GPIO pins.
+
config PM8921_BMS
+ select PM8XXX_CCADC
tristate "PM8921 Battery Monitoring System driver"
depends on MFD_PM8921_CORE
help
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index f61c88a..03db839 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -45,5 +45,7 @@
obj-$(CONFIG_BATTERY_BQ27520) += bq27520_fuelgauger.o
obj-$(CONFIG_BATTERY_BQ27541) += bq27541_fuelgauger.o
obj-$(CONFIG_SMB137B_CHARGER) += smb137b.o
+obj-$(CONFIG_PM8XXX_CCADC) += pm8xxx-ccadc.o
obj-$(CONFIG_PM8921_BMS) += pm8921-bms.o
obj-$(CONFIG_PM8921_CHARGER) += pm8921-charger.o
+obj-$(CONFIG_LTC4088_CHARGER) += ltc4088-charger.o
diff --git a/drivers/power/ltc4088-charger.c b/drivers/power/ltc4088-charger.c
new file mode 100644
index 0000000..dbc75cd
--- /dev/null
+++ b/drivers/power/ltc4088-charger.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/power/ltc4088-charger.h>
+
+#define MAX_CURRENT_UA(n) (n)
+#define MAX_CURRENT_MA(n) (n * MAX_CURRENT_UA(1000))
+
+/**
+ * ltc4088_max_current - A typical current values supported by the charger
+ * @LTC4088_MAX_CURRENT_100mA: 100mA current
+ * @LTC4088_MAX_CURRENT_500mA: 500mA current
+ * @LTC4088_MAX_CURRENT_1A: 1A current
+ */
+enum ltc4088_max_current {
+ LTC4088_MAX_CURRENT_100mA = 100,
+ LTC4088_MAX_CURRENT_500mA = 500,
+ LTC4088_MAX_CURRENT_1A = 1000,
+};
+
+/**
+ * struct ltc4088_chg_chip - Device information
+ * @dev: Device pointer to access the parent
+ * @lock: Enable mutual exclusion
+ * @usb_psy: USB device information
+ * @gpio_mode_select_d0: GPIO #pin for D0 charger line
+ * @gpio_mode_select_d1: GPIO #pin for D1 charger line
+ * @gpio_mode_select_d2: GPIO #pin for D2 charger line
+ * @max_current: Maximum current that is supplied at this time
+ */
+struct ltc4088_chg_chip {
+ struct device *dev;
+ struct mutex lock;
+ struct power_supply usb_psy;
+ unsigned int gpio_mode_select_d0;
+ unsigned int gpio_mode_select_d1;
+ unsigned int gpio_mode_select_d2;
+ unsigned int max_current;
+};
+
+static enum power_supply_property pm_power_props[] = {
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
+static char *pm_power_supplied_to[] = {
+ "battery",
+};
+
+static int ltc4088_set_charging(struct ltc4088_chg_chip *chip, bool enable)
+{
+ mutex_lock(&chip->lock);
+
+ if (enable) {
+ gpio_set_value_cansleep(chip->gpio_mode_select_d2, 0);
+ } else {
+ /* When disabling charger, set the max current to 0 also */
+ chip->max_current = 0;
+ gpio_set_value_cansleep(chip->gpio_mode_select_d0, 1);
+ gpio_set_value_cansleep(chip->gpio_mode_select_d1, 1);
+ gpio_set_value_cansleep(chip->gpio_mode_select_d2, 1);
+ }
+
+ mutex_unlock(&chip->lock);
+
+ return 0;
+}
+
+static void ltc4088_set_max_current(struct ltc4088_chg_chip *chip, int value)
+{
+ mutex_lock(&chip->lock);
+
+ /* If current is less than 100mA, we can not support that granularity */
+ if (value < MAX_CURRENT_MA(LTC4088_MAX_CURRENT_100mA)) {
+ chip->max_current = 0;
+ gpio_set_value_cansleep(chip->gpio_mode_select_d0, 1);
+ gpio_set_value_cansleep(chip->gpio_mode_select_d1, 1);
+ } else if (value < MAX_CURRENT_MA(LTC4088_MAX_CURRENT_500mA)) {
+ chip->max_current = MAX_CURRENT_MA(LTC4088_MAX_CURRENT_100mA);
+ gpio_set_value_cansleep(chip->gpio_mode_select_d0, 0);
+ gpio_set_value_cansleep(chip->gpio_mode_select_d1, 0);
+ } else if (value < MAX_CURRENT_MA(LTC4088_MAX_CURRENT_1A)) {
+ chip->max_current = MAX_CURRENT_MA(LTC4088_MAX_CURRENT_500mA);
+ gpio_set_value_cansleep(chip->gpio_mode_select_d0, 0);
+ gpio_set_value_cansleep(chip->gpio_mode_select_d1, 1);
+ } else {
+ chip->max_current = MAX_CURRENT_MA(LTC4088_MAX_CURRENT_1A);
+ gpio_set_value_cansleep(chip->gpio_mode_select_d0, 1);
+ gpio_set_value_cansleep(chip->gpio_mode_select_d1, 0);
+ }
+
+ mutex_unlock(&chip->lock);
+}
+
+static void ltc4088_set_charging_off(struct ltc4088_chg_chip *chip)
+{
+ gpio_set_value_cansleep(chip->gpio_mode_select_d0, 1);
+ gpio_set_value_cansleep(chip->gpio_mode_select_d1, 1);
+}
+
+static int ltc4088_set_initial_state(struct ltc4088_chg_chip *chip)
+{
+ int rc;
+
+ rc = gpio_request(chip->gpio_mode_select_d0, "ltc4088_D0");
+ if (rc) {
+ pr_err("gpio request failed for GPIO %d\n",
+ chip->gpio_mode_select_d0);
+ return rc;
+ }
+
+ rc = gpio_request(chip->gpio_mode_select_d1, "ltc4088_D1");
+ if (rc) {
+ pr_err("gpio request failed for GPIO %d\n",
+ chip->gpio_mode_select_d1);
+ goto gpio_err_d0;
+ }
+
+ rc = gpio_request(chip->gpio_mode_select_d2, "ltc4088_D2");
+ if (rc) {
+ pr_err("gpio request failed for GPIO %d\n",
+ chip->gpio_mode_select_d2);
+ goto gpio_err_d1;
+ }
+
+ rc = gpio_direction_output(chip->gpio_mode_select_d0, 0);
+ if (rc) {
+ pr_err("failed to set direction for GPIO %d\n",
+ chip->gpio_mode_select_d0);
+ goto gpio_err_d2;
+ }
+
+ rc = gpio_direction_output(chip->gpio_mode_select_d1, 0);
+ if (rc) {
+ pr_err("failed to set direction for GPIO %d\n",
+ chip->gpio_mode_select_d1);
+ goto gpio_err_d2;
+ }
+
+ rc = gpio_direction_output(chip->gpio_mode_select_d2, 1);
+ if (rc) {
+ pr_err("failed to set direction for GPIO %d\n",
+ chip->gpio_mode_select_d2);
+ goto gpio_err_d2;
+ }
+
+ return 0;
+
+gpio_err_d2:
+ gpio_free(chip->gpio_mode_select_d2);
+gpio_err_d1:
+ gpio_free(chip->gpio_mode_select_d1);
+gpio_err_d0:
+ gpio_free(chip->gpio_mode_select_d0);
+ return rc;
+}
+
+static int pm_power_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct ltc4088_chg_chip *chip;
+
+ if (psy->type == POWER_SUPPLY_TYPE_USB) {
+ chip = container_of(psy, struct ltc4088_chg_chip,
+ usb_psy);
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ if (chip->max_current)
+ val->intval = 1;
+ else
+ val->intval = 0;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ val->intval = chip->max_current;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int pm_power_set_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct ltc4088_chg_chip *chip;
+
+ if (psy->type == POWER_SUPPLY_TYPE_USB) {
+ chip = container_of(psy, struct ltc4088_chg_chip,
+ usb_psy);
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ ltc4088_set_charging(chip, val->intval);
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ ltc4088_set_max_current(chip, val->intval);
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int __devinit ltc4088_charger_probe(struct platform_device *pdev)
+{
+ int rc;
+ struct ltc4088_chg_chip *chip;
+ const struct ltc4088_charger_platform_data *pdata
+ = pdev->dev.platform_data;
+
+ if (!pdata) {
+ pr_err("missing platform data\n");
+ return -EINVAL;
+ }
+
+ chip = kzalloc(sizeof(struct ltc4088_chg_chip),
+ GFP_KERNEL);
+ if (!chip) {
+ pr_err("Cannot allocate pm_chg_chip\n");
+ return -ENOMEM;
+ }
+
+ chip->dev = &pdev->dev;
+
+ if (pdata->gpio_mode_select_d0 < 0 ||
+ pdata->gpio_mode_select_d1 < 0 ||
+ pdata->gpio_mode_select_d2 < 0) {
+ pr_err("Invalid platform data supplied\n");
+ rc = -EINVAL;
+ goto free_chip;
+ }
+
+ mutex_init(&chip->lock);
+
+ chip->gpio_mode_select_d0 = pdata->gpio_mode_select_d0;
+ chip->gpio_mode_select_d1 = pdata->gpio_mode_select_d1;
+ chip->gpio_mode_select_d2 = pdata->gpio_mode_select_d2;
+
+ chip->usb_psy.name = "usb",
+ chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
+ chip->usb_psy.supplied_to = pm_power_supplied_to,
+ chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
+ chip->usb_psy.properties = pm_power_props,
+ chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props),
+ chip->usb_psy.get_property = pm_power_get_property,
+ chip->usb_psy.set_property = pm_power_set_property,
+
+ rc = power_supply_register(chip->dev, &chip->usb_psy);
+ if (rc < 0) {
+ pr_err("power_supply_register usb failed rc = %d\n", rc);
+ goto free_chip;
+ }
+
+ platform_set_drvdata(pdev, chip);
+
+ rc = ltc4088_set_initial_state(chip);
+ if (rc < 0) {
+ pr_err("setting initial state failed rc = %d\n", rc);
+ goto unregister_usb;
+ }
+
+ return 0;
+
+unregister_usb:
+ platform_set_drvdata(pdev, NULL);
+ power_supply_unregister(&chip->usb_psy);
+free_chip:
+ kfree(chip);
+
+ return rc;
+}
+
+static int __devexit ltc4088_charger_remove(struct platform_device *pdev)
+{
+ struct ltc4088_chg_chip *chip = platform_get_drvdata(pdev);
+
+ ltc4088_set_charging_off(chip);
+
+ gpio_free(chip->gpio_mode_select_d2);
+ gpio_free(chip->gpio_mode_select_d1);
+ gpio_free(chip->gpio_mode_select_d0);
+
+ power_supply_unregister(&chip->usb_psy);
+
+ platform_set_drvdata(pdev, NULL);
+ mutex_destroy(&chip->lock);
+ kfree(chip);
+
+ return 0;
+}
+
+static struct platform_driver ltc4088_charger_driver = {
+ .probe = ltc4088_charger_probe,
+ .remove = __devexit_p(ltc4088_charger_remove),
+ .driver = {
+ .name = LTC4088_CHARGER_DEV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ltc4088_charger_init(void)
+{
+ return platform_driver_register(<c4088_charger_driver);
+}
+
+static void __exit ltc4088_charger_exit(void)
+{
+ platform_driver_unregister(<c4088_charger_driver);
+}
+
+subsys_initcall(ltc4088_charger_init);
+module_exit(ltc4088_charger_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("LTC4088 charger/battery driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:" LTC4088_CHARGER_DEV_NAME);
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index d7cf3a8..85d8a08 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -18,7 +18,8 @@
#include <linux/errno.h>
#include <linux/mfd/pm8xxx/pm8921-bms.h>
#include <linux/mfd/pm8xxx/core.h>
-#include <linux/mfd/pm8xxx/pm8921-adc.h>
+#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
+#include <linux/mfd/pm8xxx/ccadc.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/debugfs.h>
@@ -29,15 +30,6 @@
#define BMS_OUTPUT0 0x230
#define BMS_OUTPUT1 0x231
#define BMS_TEST1 0x237
-#define CCADC_ANA_PARAM 0x240
-#define CCADC_DIG_PARAM 0x241
-#define CCADC_RSV 0x242
-#define CCADC_DATA0 0x244
-#define CCADC_DATA1 0x245
-#define CCADC_OFFSET_TRIM1 0x34A
-#define CCADC_OFFSET_TRIM0 0x34B
-#define CCADC_FULLSCALE_TRIM1 0x34C
-#define CCADC_FULLSCALE_TRIM0 0x34D
#define ADC_ARB_SECP_CNTRL 0x190
#define ADC_ARB_SECP_AMUX_CNTRL 0x191
@@ -57,7 +49,6 @@
PM8921_BMS_OCV_FOR_R,
PM8921_BMS_GOOD_OCV,
PM8921_BMS_VSENSE_AVG,
- PM8921_BMS_CCADC_EOC,
PM_BMS_MAX_INTS,
};
@@ -75,8 +66,6 @@
struct work_struct calib_hkadc_work;
struct delayed_work calib_ccadc_work;
unsigned int calib_delay_ms;
- int ccadc_gain_uv;
- u16 ccadc_result_offset;
unsigned int revision;
unsigned int xoadc_v0625;
unsigned int xoadc_v125;
@@ -131,6 +120,15 @@
module_param_cb(last_ocv_uv, &bms_param_ops, &last_ocv_uv, 0644);
module_param_cb(last_soc, &bms_param_ops, &last_soc, 0644);
+/*
+ * bms_fake_battery is write only, this value is set in setups where a
+ * battery emulator is used instead of a real battery. This makes the
+ * bms driver report a higher value of charge regardless of the calculated
+ * state of charge.
+ */
+static int bms_fake_battery;
+module_param(bms_fake_battery, int, 0644);
+
static int interpolate_fcc(struct pm8921_bms_chip *chip, int batt_temp);
static void readjust_fcc_table(void)
{
@@ -400,56 +398,6 @@
cc_to_microvolt_v2((s64)cc);
}
-#define CCADC_READING_RESOLUTION_N_V1 1085069
-#define CCADC_READING_RESOLUTION_D_V1 100000
-#define CCADC_READING_RESOLUTION_N_V2 542535
-#define CCADC_READING_RESOLUTION_D_V2 100000
-static s64 ccadc_reading_to_microvolt_v1(s64 cc)
-{
- return div_s64(cc * CCADC_READING_RESOLUTION_N_V1,
- CCADC_READING_RESOLUTION_D_V1);
-}
-
-static s64 ccadc_reading_to_microvolt_v2(s64 cc)
-{
- return div_s64(cc * CCADC_READING_RESOLUTION_N_V2,
- CCADC_READING_RESOLUTION_D_V2);
-}
-
-static s64 ccadc_reading_to_microvolt(struct pm8921_bms_chip *chip, s64 cc)
-{
- /*
- * resolution (the value of a single bit) was changed after revision 2.0
- * for more accurate readings
- */
- return (chip->revision < PM8XXX_REVISION_8921_2p0) ?
- ccadc_reading_to_microvolt_v1((s64)cc) :
- ccadc_reading_to_microvolt_v2((s64)cc);
-}
-
-static s64 microvolt_to_ccadc_reading_v1(s64 uv)
-{
- return div_s64(uv * CCADC_READING_RESOLUTION_D_V1,
- CCADC_READING_RESOLUTION_N_V1);
-}
-
-static s64 microvolt_to_ccadc_reading_v2(s64 uv)
-{
- return div_s64(uv * CCADC_READING_RESOLUTION_D_V2,
- CCADC_READING_RESOLUTION_N_V2);
-}
-
-static s64 microvolt_to_ccadc_reading(struct pm8921_bms_chip *chip, s64 cc)
-{
- /*
- * resolution (the value of a single bit) was changed after revision 2.0
- * for more accurate readings
- */
- return (chip->revision < PM8XXX_REVISION_8921_2p0) ?
- microvolt_to_ccadc_reading_v1((s64)cc) :
- microvolt_to_ccadc_reading_v2((s64)cc);
-}
-
#define CC_READING_TICKS 55
#define SLEEP_CLK_HZ 32768
#define SECONDS_PER_HOUR 3600
@@ -459,19 +407,6 @@
SLEEP_CLK_HZ * SECONDS_PER_HOUR);
}
-#define GAIN_REFERENCE_UV 25000
-/*
- * gain compensation for ccadc readings - common for vsense based and
- * couloumb counter based readings
- */
-static s64 cc_adjust_for_gain(struct pm8921_bms_chip *chip, s64 cc)
-{
- if (chip->ccadc_gain_uv == 0)
- return cc;
-
- return div_s64(cc * GAIN_REFERENCE_UV, chip->ccadc_gain_uv);
-}
-
/* returns the signed value read from the hardware */
static int read_cc(struct pm8921_bms_chip *chip, int *result)
{
@@ -559,9 +494,9 @@
pr_err("fail to read VSENSE_FOR_RBATT rc = %d\n", rc);
return rc;
}
- *result = ccadc_reading_to_microvolt(chip, reading);
+ *result = pm8xxx_ccadc_reading_to_microvolt(chip->revision, reading);
pr_debug("raw = %04x vsense_for_r_uV = %u\n", reading, *result);
- *result = cc_adjust_for_gain(chip, *result);
+ *result = pm8xxx_cc_adjust_for_gain(*result);
pr_debug("after adj vsense_for_r_uV = %u\n", *result);
return 0;
}
@@ -593,9 +528,10 @@
pr_err("fail to read VSENSE_AVG rc = %d\n", rc);
return rc;
}
- *result = ccadc_reading_to_microvolt(chip, reading);
+ *result = pm8xxx_ccadc_reading_to_microvolt(the_chip->revision,
+ reading);
pr_debug("raw = %04x vsense = %d\n", reading, *result);
- *result = cc_adjust_for_gain(the_chip, (s64)*result);
+ *result = pm8xxx_cc_adjust_for_gain((s64)*result);
pr_debug("after adj vsense = %d\n", *result);
return 0;
}
@@ -912,9 +848,9 @@
static int get_battery_uvolts(struct pm8921_bms_chip *chip, int *uvolts)
{
int rc;
- struct pm8921_adc_chan_result result;
+ struct pm8xxx_adc_chan_result result;
- rc = pm8921_adc_read(chip->vbat_channel, &result);
+ rc = pm8xxx_adc_read(chip->vbat_channel, &result);
if (rc) {
pr_err("error reading adc channel = %d, rc = %d\n",
chip->vbat_channel, rc);
@@ -976,7 +912,7 @@
rc = read_cc(the_chip, coulumb_counter);
cc_voltage_uv = (int64_t)*coulumb_counter;
cc_voltage_uv = cc_to_microvolt(chip, cc_voltage_uv);
- cc_voltage_uv = cc_adjust_for_gain(chip, cc_voltage_uv);
+ cc_voltage_uv = pm8xxx_cc_adjust_for_gain(cc_voltage_uv);
pr_debug("cc_voltage_uv = %lld microvolts\n", cc_voltage_uv);
cc_uvh = ccmicrovolt_to_uvh(cc_voltage_uv);
pr_debug("cc_uvh = %lld micro_volt_hour\n", cc_uvh);
@@ -1064,7 +1000,8 @@
}
static int calculate_real_fcc(struct pm8921_bms_chip *chip,
- int batt_temp, int chargecycles)
+ int batt_temp, int chargecycles,
+ int *ret_fcc)
{
int fcc, unusable_charge;
int remaining_charge;
@@ -1078,8 +1015,9 @@
&cc_mah);
real_fcc = remaining_charge - cc_mah;
- pr_debug("real_fcc = %d, RC = %d CC = %lld\n",
- real_fcc, remaining_charge, cc_mah);
+ *ret_fcc = fcc;
+ pr_debug("real_fcc = %d, RC = %d CC = %lld fcc = %d\n",
+ real_fcc, remaining_charge, cc_mah, fcc);
return real_fcc;
}
/*
@@ -1088,8 +1026,6 @@
* - unusable charge (due to battery resistance)
* SOC% = (remaining usable charge/ fcc - usable_charge);
*/
-#define BMS_BATT_NOMINAL 3700000
-#define MIN_OPERABLE_SOC 10
#define BATTERY_POWER_SUPPLY_SOC 53
static int calculate_state_of_charge(struct pm8921_bms_chip *chip,
int batt_temp, int chargecycles)
@@ -1113,22 +1049,10 @@
soc = 100;
pr_debug("SOC = %u%%\n", soc);
- if (soc < MIN_OPERABLE_SOC) {
- int ocv = 0, rc;
-
- rc = adc_based_ocv(chip, &ocv);
- if (rc == 0 && ocv >= BMS_BATT_NOMINAL) {
- /*
- * The ocv doesnt seem to have dropped for
- * soc to go negative.
- * The setup must be using a power supply
- * instead of real batteries.
- * Fake high enough soc to prevent userspace
- * shutdown for low battery
- */
- soc = BATTERY_POWER_SUPPLY_SOC;
- pr_debug("Adjusting SOC to %d\n", soc);
- }
+ if (bms_fake_battery) {
+ soc = BATTERY_POWER_SUPPLY_SOC;
+ pr_debug("setting SOC = %u%% bms_fake_battery = %d\n", soc,
+ bms_fake_battery);
}
if (soc < 0) {
@@ -1142,6 +1066,7 @@
last_ocv_uv, chargecycles, batt_temp,
fcc, soc);
update_userspace = 0;
+ soc = 0;
}
if (last_soc == -EINVAL || soc <= last_soc) {
@@ -1180,9 +1105,9 @@
static void calib_hkadc(struct pm8921_bms_chip *chip)
{
int voltage, rc;
- struct pm8921_adc_chan_result result;
+ struct pm8xxx_adc_chan_result result;
- rc = pm8921_adc_read(the_chip->ref1p25v_channel, &result);
+ rc = pm8xxx_adc_read(the_chip->ref1p25v_channel, &result);
if (rc) {
pr_err("ADC failed for 1.25volts rc = %d\n", rc);
return;
@@ -1199,7 +1124,7 @@
voltage = XOADC_MIN_1P25V;
chip->xoadc_v125 = voltage;
- rc = pm8921_adc_read(the_chip->ref625mv_channel, &result);
+ rc = pm8xxx_adc_read(the_chip->ref625mv_channel, &result);
if (rc) {
pr_err("ADC failed for 1.25volts rc = %d\n", rc);
return;
@@ -1224,386 +1149,12 @@
calib_hkadc(chip);
}
-#define START_CONV_BIT BIT(7)
-#define EOC_CONV_BIT BIT(6)
-#define SEL_CCADC_BIT BIT(1)
-#define EN_ARB_BIT BIT(0)
-
-#define CCADC_CALIB_DIG_PARAM 0xE3
-#define CCADC_CALIB_RSV_GND 0x40
-#define CCADC_CALIB_RSV_25MV 0x80
-#define CCADC_CALIB_ANA_PARAM 0x1B
-#define SAMPLE_COUNT 16
-#define ADC_WAIT_COUNT 10
-
-#define CCADC_MAX_25MV 30000
-#define CCADC_MIN_25MV 20000
-#define CCADC_MAX_0UV -4000
-#define CCADC_MIN_0UV -7000
-
-#define CCADC_INTRINSIC_OFFSET 0xC000
-
-#define REG_SBI_CONFIG 0x04F
-#define PAGE3_ENABLE_MASK 0x6
-
-static int calib_ccadc_enable_trim_access(struct pm8921_bms_chip *chip,
- u8 *sbi_config)
-{
- u8 reg;
- int rc;
-
- rc = pm8xxx_readb(chip->dev->parent, REG_SBI_CONFIG, sbi_config);
- if (rc) {
- pr_err("error = %d reading sbi config reg\n", rc);
- return rc;
- }
-
- reg = *sbi_config | PAGE3_ENABLE_MASK;
- return pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, reg);
-}
-
-static int calib_ccadc_restore_trim_access(struct pm8921_bms_chip *chip,
- u8 sbi_config)
-{
- return pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, sbi_config);
-}
-
-static int calib_ccadc_enable_arbiter(struct pm8921_bms_chip *chip)
-{
- int rc;
-
- /* enable Arbiter, must be sent twice */
- rc = pm_bms_masked_write(chip, ADC_ARB_SECP_CNTRL,
- SEL_CCADC_BIT | EN_ARB_BIT, SEL_CCADC_BIT | EN_ARB_BIT);
- if (rc < 0) {
- pr_err("error = %d enabling arbiter for offset\n", rc);
- return rc;
- }
- rc = pm_bms_masked_write(chip, ADC_ARB_SECP_CNTRL,
- SEL_CCADC_BIT | EN_ARB_BIT, SEL_CCADC_BIT | EN_ARB_BIT);
- if (rc < 0) {
- pr_err("error = %d writing ADC_ARB_SECP_CNTRL\n", rc);
- return rc;
- }
- return 0;
-}
-
-static int calib_start_conv(struct pm8921_bms_chip *chip,
- u16 *result)
-{
- int rc, i;
- u8 data_msb, data_lsb, reg;
-
- /* Start conversion */
- rc = pm_bms_masked_write(chip, ADC_ARB_SECP_CNTRL,
- START_CONV_BIT, START_CONV_BIT);
- if (rc < 0) {
- pr_err("error = %d starting offset meas\n", rc);
- return rc;
- }
-
- /* Wait for End of conversion */
- for (i = 0; i < ADC_WAIT_COUNT; i++) {
- rc = pm8xxx_readb(chip->dev->parent,
- ADC_ARB_SECP_CNTRL, ®);
- if (rc < 0) {
- pr_err("error = %d read eoc for offset\n", rc);
- return rc;
- }
- if ((reg & (START_CONV_BIT | EOC_CONV_BIT)) != EOC_CONV_BIT)
- msleep(60);
- else
- break;
- }
- if (i == ADC_WAIT_COUNT) {
- pr_err("waited too long for offset eoc\n");
- return rc;
- }
-
- rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_DATA0, &data_lsb);
- if (rc < 0) {
- pr_err("error = %d reading offset lsb\n", rc);
- return rc;
- }
-
- rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_DATA1, &data_msb);
- if (rc < 0) {
- pr_err("error = %d reading offset msb\n", rc);
- return rc;
- }
-
- *result = (data_msb << 8) | data_lsb;
- return 0;
-}
-
-static int calib_ccadc_read_trim(struct pm8921_bms_chip *chip,
- int addr, u8 *data_msb, u8 *data_lsb)
-{
- int rc;
- u8 sbi_config;
-
- calib_ccadc_enable_trim_access(chip, &sbi_config);
- rc = pm8xxx_readb(chip->dev->parent, addr, data_msb);
- if (rc < 0) {
- pr_err("error = %d read msb\n", rc);
- return rc;
- }
- rc = pm8xxx_readb(chip->dev->parent, addr + 1, data_lsb);
- if (rc < 0) {
- pr_err("error = %d read lsb\n", rc);
- return rc;
- }
- calib_ccadc_restore_trim_access(chip, sbi_config);
- return 0;
-}
-
-static int calib_ccadc_read_gain_uv(struct pm8921_bms_chip *chip)
-{
- s8 data_msb;
- u8 data_lsb;
- int rc, gain, offset;
-
- rc = calib_ccadc_read_trim(chip, CCADC_FULLSCALE_TRIM1,
- &data_msb, &data_lsb);
- gain = (data_msb << 8) | data_lsb;
-
- rc = calib_ccadc_read_trim(chip, CCADC_OFFSET_TRIM1,
- &data_msb, &data_lsb);
- offset = (data_msb << 8) | data_lsb;
-
- pr_debug("raw gain trim = 0x%x offset trim =0x%x\n", gain, offset);
- gain = ccadc_reading_to_microvolt(chip, (s64)gain - offset);
- return gain;
-}
-
-#define CCADC_PROGRAM_TRIM_COUNT 2
-#define ADC_ARB_BMS_CNTRL_CCADC_SHIFT 4
-#define ADC_ARB_BMS_CNTRL_CONV_MASK 0x03
-#define BMS_CONV_IN_PROGRESS 0x2
-
-static int calib_ccadc_program_trim(struct pm8921_bms_chip *chip,
- int addr, u8 data_msb, u8 data_lsb,
- int wait)
-{
- int i, rc, loop;
- u8 cntrl, sbi_config;
- bool in_progress = 0;
-
- loop = wait ? CCADC_PROGRAM_TRIM_COUNT : 0;
-
- calib_ccadc_enable_trim_access(chip, &sbi_config);
-
- for (i = 0; i < loop; i++) {
- rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_BMS_CNTRL, &cntrl);
- if (rc < 0) {
- pr_err("error = %d reading ADC_ARB_BMS_CNTRL\n", rc);
- return rc;
- }
-
- /* break if a ccadc conversion is not happening */
- in_progress = (((cntrl >> ADC_ARB_BMS_CNTRL_CCADC_SHIFT)
- & ADC_ARB_BMS_CNTRL_CONV_MASK) == BMS_CONV_IN_PROGRESS);
-
- if (!in_progress)
- break;
- }
-
- if (in_progress) {
- pr_debug("conv in progress cannot write trim,returing EBUSY\n");
- return -EBUSY;
- }
-
- rc = pm8xxx_writeb(chip->dev->parent, addr, data_msb);
- if (rc < 0) {
- pr_err("error = %d write msb = 0x%x\n", rc, data_msb);
- return rc;
- }
- rc = pm8xxx_writeb(chip->dev->parent, addr + 1, data_lsb);
- if (rc < 0) {
- pr_err("error = %d write lsb = 0x%x\n", rc, data_lsb);
- return rc;
- }
- calib_ccadc_restore_trim_access(chip, sbi_config);
- return 0;
-}
-
-static void calib_ccadc(struct pm8921_bms_chip *chip)
-{
- u8 data_msb, data_lsb, sec_cntrl;
- int result_offset, voltage_offset, result_gain;
- u16 result;
- int i, rc;
-
- rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_CNTRL, &sec_cntrl);
- if (rc < 0) {
- pr_err("error = %d reading ADC_ARB_SECP_CNTRL\n", rc);
- return;
- }
-
- rc = calib_ccadc_enable_arbiter(chip);
- if (rc < 0) {
- pr_err("error = %d enabling arbiter for offset\n", rc);
- goto bail;
- }
-
- /*
- * Set decimation ratio to 4k, lower ratio may be used in order to speed
- * up, pending verification through bench
- */
- rc = pm8xxx_writeb(chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
- CCADC_CALIB_DIG_PARAM);
- if (rc < 0) {
- pr_err("error = %d writing ADC_ARB_SECP_DIG_PARAM\n", rc);
- goto bail;
- }
-
- result_offset = 0;
- for (i = 0; i < SAMPLE_COUNT; i++) {
- /* Short analog inputs to CCADC internally to ground */
- rc = pm8xxx_writeb(chip->dev->parent, ADC_ARB_SECP_RSV,
- CCADC_CALIB_RSV_GND);
- if (rc < 0) {
- pr_err("error = %d selecting gnd voltage\n", rc);
- goto bail;
- }
-
- /* Enable CCADC */
- rc = pm8xxx_writeb(chip->dev->parent, ADC_ARB_SECP_ANA_PARAM,
- CCADC_CALIB_ANA_PARAM);
- if (rc < 0) {
- pr_err("error = %d enabling ccadc\n", rc);
- goto bail;
- }
-
- rc = calib_start_conv(chip, &result);
- if (rc < 0) {
- pr_err("error = %d for zero volt measurement\n", rc);
- goto bail;
- }
-
- result_offset += result;
- }
-
- result_offset = result_offset / SAMPLE_COUNT;
-
- voltage_offset = ccadc_reading_to_microvolt(chip,
- ((s64)result_offset - CCADC_INTRINSIC_OFFSET));
-
- pr_debug("offset result_offset = 0x%x, voltage = %d microVolts\n",
- result_offset, voltage_offset);
-
- /* Sanity Check */
- if (voltage_offset > CCADC_MAX_0UV) {
- pr_err("offset voltage = %d is huge limiting to %d\n",
- voltage_offset, CCADC_MAX_0UV);
- result_offset = CCADC_INTRINSIC_OFFSET
- + microvolt_to_ccadc_reading(chip, (s64)CCADC_MAX_0UV);
- } else if (voltage_offset < CCADC_MIN_0UV) {
- pr_err("offset voltage = %d is too low limiting to %d\n",
- voltage_offset, CCADC_MIN_0UV);
- result_offset = CCADC_INTRINSIC_OFFSET
- + microvolt_to_ccadc_reading(chip, (s64)CCADC_MIN_0UV);
- }
-
- chip->ccadc_result_offset = result_offset;
- data_msb = chip->ccadc_result_offset >> 8;
- data_lsb = chip->ccadc_result_offset;
-
- rc = calib_ccadc_program_trim(chip, CCADC_OFFSET_TRIM1,
- data_msb, data_lsb, 1);
- if (rc) {
- pr_debug("error = %d programming offset trim 0x%02x 0x%02x\n",
- rc, data_msb, data_lsb);
- /* enable the interrupt and write it when it fires */
- pm8921_bms_enable_irq(chip, PM8921_BMS_CCADC_EOC);
- }
-
- rc = calib_ccadc_enable_arbiter(chip);
- if (rc < 0) {
- pr_err("error = %d enabling arbiter for gain\n", rc);
- goto bail;
- }
-
- /*
- * Set decimation ratio to 4k, lower ratio may be used in order to speed
- * up, pending verification through bench
- */
- rc = pm8xxx_writeb(chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
- CCADC_CALIB_DIG_PARAM);
- if (rc < 0) {
- pr_err("error = %d enabling decimation ration for gain\n", rc);
- goto bail;
- }
-
- result_gain = 0;
- for (i = 0; i < SAMPLE_COUNT; i++) {
- rc = pm8xxx_writeb(chip->dev->parent,
- ADC_ARB_SECP_RSV, CCADC_CALIB_RSV_25MV);
- if (rc < 0) {
- pr_err("error = %d selecting 25mV for gain\n", rc);
- goto bail;
- }
-
- /* Enable CCADC */
- rc = pm8xxx_writeb(chip->dev->parent, ADC_ARB_SECP_ANA_PARAM,
- CCADC_CALIB_ANA_PARAM);
- if (rc < 0) {
- pr_err("error = %d enabling ccadc\n", rc);
- goto bail;
- }
-
- rc = calib_start_conv(chip, &result);
- if (rc < 0) {
- pr_err("error = %d for adc reading 25mV\n", rc);
- goto bail;
- }
-
- result_gain += result;
- }
- result_gain = result_gain / SAMPLE_COUNT;
-
- /*
- * result_offset includes INTRINSIC OFFSET
- * chip->ccadc_gain_uv will be the actual voltage
- * measured for 25000UV
- */
- chip->ccadc_gain_uv = ccadc_reading_to_microvolt(chip,
- ((s64)result_gain - result_offset));
-
- pr_debug("gain result_gain = 0x%x, voltage = %d microVolts\n",
- result_gain,
- chip->ccadc_gain_uv);
- /* Sanity Check */
- if (chip->ccadc_gain_uv > CCADC_MAX_25MV) {
- pr_err("gain voltage = %d is huge limiting to %d\n",
- chip->ccadc_gain_uv, CCADC_MAX_25MV);
- chip->ccadc_gain_uv = CCADC_MAX_25MV;
- result_gain = result_offset +
- microvolt_to_ccadc_reading(chip, CCADC_MAX_25MV);
- } else if (chip->ccadc_gain_uv < CCADC_MIN_25MV) {
- pr_err("gain voltage = %d is too low limiting to %d\n",
- chip->ccadc_gain_uv, CCADC_MIN_25MV);
- chip->ccadc_gain_uv = CCADC_MIN_25MV;
- result_gain = result_offset +
- microvolt_to_ccadc_reading(chip, CCADC_MIN_25MV);
- }
-
- data_msb = result_gain >> 8;
- data_lsb = result_gain;
- rc = calib_ccadc_program_trim(chip, CCADC_FULLSCALE_TRIM1,
- data_msb, data_lsb, 0);
- if (rc)
- pr_debug("error = %d programming gain trim\n", rc);
-bail:
- pm8xxx_writeb(chip->dev->parent, ADC_ARB_SECP_CNTRL, sec_cntrl);
-}
-
static void calibrate_ccadc_work(struct work_struct *work)
{
struct pm8921_bms_chip *chip = container_of(work,
struct pm8921_bms_chip, calib_ccadc_work.work);
- calib_ccadc(chip);
+ pm8xxx_calib_ccadc();
schedule_delayed_work(&chip->calib_ccadc_work,
round_jiffies_relative(msecs_to_jiffies
(chip->calib_delay_ms)));
@@ -1657,14 +1208,14 @@
int pm8921_bms_get_percent_charge(void)
{
int batt_temp, rc;
- struct pm8921_adc_chan_result result;
+ struct pm8xxx_adc_chan_result result;
if (!the_chip) {
pr_err("called before initialization\n");
return -EINVAL;
}
- rc = pm8921_adc_read(the_chip->batt_temp_channel, &result);
+ rc = pm8xxx_adc_read(the_chip->batt_temp_channel, &result);
if (rc) {
pr_err("error reading adc channel = %d, rc = %d\n",
the_chip->batt_temp_channel, rc);
@@ -1681,14 +1232,14 @@
int pm8921_bms_get_fcc(void)
{
int batt_temp, rc;
- struct pm8921_adc_chan_result result;
+ struct pm8xxx_adc_chan_result result;
if (!the_chip) {
pr_err("called before initialization\n");
return -EINVAL;
}
- rc = pm8921_adc_read(the_chip->batt_temp_channel, &result);
+ rc = pm8xxx_adc_read(the_chip->batt_temp_channel, &result);
if (rc) {
pr_err("error reading adc channel = %d, rc = %d\n",
the_chip->batt_temp_channel, rc);
@@ -1708,14 +1259,16 @@
}
EXPORT_SYMBOL_GPL(pm8921_bms_charging_began);
+#define DELTA_FCC_PERCENT 3
void pm8921_bms_charging_end(int is_battery_full)
{
if (is_battery_full && the_chip != NULL) {
unsigned long flags;
int batt_temp, rc, cc_reading;
- struct pm8921_adc_chan_result result;
+ int fcc, new_fcc, delta_fcc;
+ struct pm8xxx_adc_chan_result result;
- rc = pm8921_adc_read(the_chip->batt_temp_channel, &result);
+ rc = pm8xxx_adc_read(the_chip->batt_temp_channel, &result);
if (rc) {
pr_err("error reading adc channel = %d, rc = %d\n",
the_chip->batt_temp_channel, rc);
@@ -1724,10 +1277,24 @@
pr_debug("batt_temp phy = %lld meas = 0x%llx", result.physical,
result.measurement);
batt_temp = (int)result.physical;
- last_real_fcc = calculate_real_fcc(the_chip,
- batt_temp, last_chargecycles);
- last_real_fcc_batt_temp = batt_temp;
- readjust_fcc_table();
+ new_fcc = calculate_real_fcc(the_chip,
+ batt_temp, last_chargecycles,
+ &fcc);
+ delta_fcc = new_fcc - fcc;
+ if (delta_fcc < 0)
+ delta_fcc = -delta_fcc;
+
+ if (delta_fcc * 100 <= (DELTA_FCC_PERCENT * fcc)) {
+ pr_debug("delta_fcc=%d < %d percent of fcc=%d\n",
+ delta_fcc, DELTA_FCC_PERCENT, fcc);
+ last_real_fcc = new_fcc;
+ last_real_fcc_batt_temp = batt_temp;
+ readjust_fcc_table();
+ } else {
+ pr_debug("delta_fcc=%d > %d percent of fcc=%d"
+ "will not update real fcc\n",
+ delta_fcc, DELTA_FCC_PERCENT, fcc);
+ }
spin_lock_irqsave(&the_chip->bms_output_lock, flags);
pm_bms_lock_output_data(the_chip);
@@ -1810,23 +1377,6 @@
return IRQ_HANDLED;
}
-static irqreturn_t pm8921_bms_ccadc_eoc_handler(int irq, void *data)
-{
- u8 data_msb, data_lsb;
- struct pm8921_bms_chip *chip = data;
- int rc;
-
- pr_debug("irq = %d triggered\n", irq);
- data_msb = chip->ccadc_result_offset >> 8;
- data_lsb = chip->ccadc_result_offset;
-
- rc = calib_ccadc_program_trim(chip, CCADC_OFFSET_TRIM1,
- data_msb, data_lsb, 0);
- pm8921_bms_disable_irq(chip, PM8921_BMS_CCADC_EOC);
-
- return IRQ_HANDLED;
-}
-
struct pm_bms_irq_init_data {
unsigned int irq_id;
char *name;
@@ -1857,8 +1407,6 @@
pm8921_bms_good_ocv_handler),
BMS_IRQ(PM8921_BMS_VSENSE_AVG, IRQF_TRIGGER_RISING,
pm8921_bms_vsense_avg_handler),
- BMS_IRQ(PM8921_BMS_CCADC_EOC, IRQF_TRIGGER_RISING,
- pm8921_bms_ccadc_eoc_handler),
};
static void free_irqs(struct pm8921_bms_chip *chip)
@@ -1947,9 +1495,9 @@
static int64_t read_battery_id(struct pm8921_bms_chip *chip)
{
int rc;
- struct pm8921_adc_chan_result result;
+ struct pm8xxx_adc_chan_result result;
- rc = pm8921_adc_read(chip->batt_id_channel, &result);
+ rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
if (rc) {
pr_err("error reading batt id channel = %d, rc = %d\n",
chip->vbat_channel, rc);
@@ -2076,7 +1624,7 @@
case CALIB_CCADC:
/* reading this will trigger calibration */
*val = 0;
- calib_ccadc(the_chip);
+ pm8xxx_calib_ccadc();
break;
default:
ret = -EINVAL;
@@ -2169,7 +1717,7 @@
{
int i;
- chip->dent = debugfs_create_dir("pm8921_bms", NULL);
+ chip->dent = debugfs_create_dir("pm8921-bms", NULL);
if (IS_ERR(chip->dent)) {
pr_err("pmic bms couldnt create debugfs dir\n");
@@ -2184,20 +1732,6 @@
(void *)BMS_OUTPUT1, ®_fops);
debugfs_create_file("BMS_TEST1", 0644, chip->dent,
(void *)BMS_TEST1, ®_fops);
- debugfs_create_file("CCADC_ANA_PARAM", 0644, chip->dent,
- (void *)CCADC_ANA_PARAM, ®_fops);
- debugfs_create_file("CCADC_DIG_PARAM", 0644, chip->dent,
- (void *)CCADC_DIG_PARAM, ®_fops);
- debugfs_create_file("CCADC_RSV", 0644, chip->dent,
- (void *)CCADC_RSV, ®_fops);
- debugfs_create_file("CCADC_DATA0", 0644, chip->dent,
- (void *)CCADC_DATA0, ®_fops);
- debugfs_create_file("CCADC_DATA1", 0644, chip->dent,
- (void *)CCADC_DATA1, ®_fops);
- debugfs_create_file("CCADC_OFFSET_TRIM1", 0644, chip->dent,
- (void *)CCADC_OFFSET_TRIM1, ®_fops);
- debugfs_create_file("CCADC_OFFSET_TRIM0", 0644, chip->dent,
- (void *)CCADC_OFFSET_TRIM0, ®_fops);
debugfs_create_file("test_batt_temp", 0644, chip->dent,
(void *)TEST_BATT_TEMP, &temp_fops);
@@ -2296,7 +1830,6 @@
create_debugfs_entries(chip);
check_initial_ocv(chip);
- chip->ccadc_gain_uv = calib_ccadc_read_gain_uv(chip);
INIT_DELAYED_WORK(&chip->calib_ccadc_work, calibrate_ccadc_work);
/* begin calibration only on chips > 2.0 */
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index cccb317..e908799 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -18,7 +18,8 @@
#include <linux/errno.h>
#include <linux/mfd/pm8xxx/pm8921-charger.h>
#include <linux/mfd/pm8xxx/pm8921-bms.h>
-#include <linux/mfd/pm8xxx/pm8921-adc.h>
+#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
+#include <linux/mfd/pm8xxx/ccadc.h>
#include <linux/mfd/pm8xxx/core.h>
#include <linux/interrupt.h>
#include <linux/power_supply.h>
@@ -201,8 +202,8 @@
* @update_time: how frequently the userland needs to be updated
* @max_voltage: the max volts the batt should be charged up to
* @min_voltage: the min battery voltage before turning the FETon
- * @resume_voltage: the voltage at which the battery should resume
- * charging
+ * @resume_voltage_delta: the voltage delta from vdd max at which the
+ * battery should resume charging
* @term_current: The charging based term current
*
*/
@@ -225,7 +226,9 @@
unsigned int warm_bat_chg_current;
unsigned int cool_bat_voltage;
unsigned int warm_bat_voltage;
- unsigned int resume_voltage;
+ unsigned int is_bat_cool;
+ unsigned int is_bat_warm;
+ unsigned int resume_voltage_delta;
unsigned int term_current;
unsigned int vbat_channel;
unsigned int batt_temp_channel;
@@ -247,7 +250,7 @@
int trkl_current;
int weak_current;
int vin_min;
- int *thermal_mitigation;
+ unsigned int *thermal_mitigation;
int thermal_levels;
struct delayed_work update_heartbeat_work;
struct delayed_work eoc_work;
@@ -261,7 +264,7 @@
static struct pm8921_chg_chip *the_chip;
-static struct pm8921_adc_arb_btm_param btm_config;
+static struct pm8xxx_adc_arb_btm_param btm_config;
static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
u8 mask, u8 val)
@@ -368,6 +371,19 @@
enable ? CHG_EN_BIT : 0);
}
+#define CHG_FAILED_CLEAR BIT(0)
+#define ATC_FAILED_CLEAR BIT(1)
+static int pm_chg_failed_clear(struct pm8921_chg_chip *chip, int clear)
+{
+ int rc;
+
+ rc = pm_chg_masked_write(chip, CHG_CNTRL_3, ATC_FAILED_CLEAR,
+ clear ? ATC_FAILED_CLEAR : 0);
+ rc |= pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_FAILED_CLEAR,
+ clear ? CHG_FAILED_CLEAR : 0);
+ return rc;
+}
+
#define CHG_CHARGE_DIS_BIT BIT(1)
static int pm_chg_charge_dis(struct pm8921_chg_chip *chip, int disable)
{
@@ -706,9 +722,9 @@
static int64_t read_battery_id(struct pm8921_chg_chip *chip)
{
int rc;
- struct pm8921_adc_chan_result result;
+ struct pm8xxx_adc_chan_result result;
- rc = pm8921_adc_read(chip->batt_id_channel, &result);
+ rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
if (rc) {
pr_err("error reading batt id channel = %d, rc = %d\n",
chip->vbat_channel, rc);
@@ -909,9 +925,9 @@
static int get_prop_battery_mvolts(struct pm8921_chg_chip *chip)
{
int rc;
- struct pm8921_adc_chan_result result;
+ struct pm8xxx_adc_chan_result result;
- rc = pm8921_adc_read(chip->vbat_channel, &result);
+ rc = pm8xxx_adc_read(chip->vbat_channel, &result);
if (rc) {
pr_err("error reading adc channel = %d, rc = %d\n",
chip->vbat_channel, rc);
@@ -922,10 +938,28 @@
return (int)result.physical;
}
+static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
+{
+ unsigned int current_voltage = get_prop_battery_mvolts(chip);
+ unsigned int low_voltage = chip->min_voltage;
+ unsigned int high_voltage = chip->max_voltage;
+
+ if (current_voltage <= low_voltage)
+ return 0;
+ else if (current_voltage >= high_voltage)
+ return 100;
+ else
+ return (current_voltage - low_voltage) * 100
+ / (high_voltage - low_voltage);
+}
+
static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
{
int percent_soc = pm8921_bms_get_percent_charge();
+ if (percent_soc == -ENXIO)
+ percent_soc = voltage_based_capacity(chip);
+
if (percent_soc <= 10)
pr_warn("low battery charge = %d%%\n", percent_soc);
@@ -937,6 +971,10 @@
int result_ma, rc;
rc = pm8921_bms_get_battery_current(&result_ma);
+ if (rc == -ENXIO) {
+ rc = pm8xxx_ccadc_get_battery_current(&result_ma);
+ }
+
if (rc) {
pr_err("unable to get batt current rc = %d\n", rc);
return rc;
@@ -1005,6 +1043,13 @@
int fsm_state = pm_chg_get_fsm_state(chip);
int i;
+ if (chip->ext) {
+ if (chip->ext_charge_done)
+ return POWER_SUPPLY_STATUS_FULL;
+ if (chip->ext_charging)
+ return POWER_SUPPLY_STATUS_CHARGING;
+ }
+
for (i = 0; i < ARRAY_SIZE(map); i++)
if (map[i].fsm_state == fsm_state)
batt_state = map[i].batt_state;
@@ -1022,9 +1067,9 @@
static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
{
int rc;
- struct pm8921_adc_chan_result result;
+ struct pm8xxx_adc_chan_result result;
- rc = pm8921_adc_read(chip->batt_temp_channel, &result);
+ rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
if (rc) {
pr_err("error reading adc channel = %d, rc = %d\n",
chip->vbat_channel, rc);
@@ -1234,6 +1279,28 @@
}
EXPORT_SYMBOL(pm8921_is_battery_present);
+/*
+ * Disabling the charge current limit causes current
+ * current limits to have no monitoring. An adequate charger
+ * capable of supplying high current while sustaining VIN_MIN
+ * is required if the limiting is disabled.
+ */
+int pm8921_disable_input_current_limit(bool disable)
+{
+ if (!the_chip) {
+ pr_err("called before init\n");
+ return -EINVAL;
+ }
+ if (disable) {
+ pr_warn("Disabling input current limit!\n");
+
+ return pm8xxx_writeb(the_chip->dev->parent,
+ CHG_BUCK_CTRL_TEST3, 0xF2);
+ }
+ return 0;
+}
+EXPORT_SYMBOL(pm8921_disable_input_current_limit);
+
int pm8921_set_max_battery_charge_current(int ma)
{
if (!the_chip) {
@@ -1322,6 +1389,7 @@
notify_usb_of_the_plugin_event(usb_present);
chip->usb_present = usb_present;
power_supply_changed(&chip->usb_psy);
+ power_supply_changed(&chip->batt_psy);
}
bms_notify_check(chip);
}
@@ -1340,6 +1408,7 @@
chip->ext->stop_charging(chip->ext->ctx);
chip->ext_charging = false;
+ chip->ext_charge_done = false;
}
static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
@@ -1405,6 +1474,7 @@
if (chip->dc_present ^ dc_present) {
chip->dc_present = dc_present;
power_supply_changed(&chip->dc_psy);
+ power_supply_changed(&chip->batt_psy);
}
bms_notify_check(chip);
}
@@ -1446,18 +1516,20 @@
static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
{
struct pm8921_chg_chip *chip = data;
+ int high_transition;
- pm8921_chg_disable_irq(chip, VBATDET_LOW_IRQ);
+ high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
- /* enable auto charging */
- pm_chg_auto_enable(chip, !charging_disabled);
+ if (high_transition) {
+ /* enable auto charging */
+ pm_chg_auto_enable(chip, !charging_disabled);
+ }
pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
power_supply_changed(&chip->batt_psy);
power_supply_changed(&chip->usb_psy);
power_supply_changed(&chip->dc_psy);
- pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
return IRQ_HANDLED;
}
@@ -1513,20 +1585,23 @@
chip->bms_notify.is_battery_full = 1;
bms_notify_check(chip);
- /*
- * since charging is now done, start monitoring for
- * battery voltage below resume voltage
- */
- pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
-
return IRQ_HANDLED;
}
static irqreturn_t chgfail_irq_handler(int irq, void *data)
{
struct pm8921_chg_chip *chip = data;
+ int ret;
- pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
+ ret = pm_chg_failed_clear(chip, 1);
+ if (ret)
+ pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
+
+ pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
+ get_prop_batt_present(chip),
+ pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
+ pm_chg_get_fsm_state(data));
+
power_supply_changed(&chip->batt_psy);
power_supply_changed(&chip->usb_psy);
power_supply_changed(&chip->dc_psy);
@@ -1556,14 +1631,17 @@
static irqreturn_t fastchg_irq_handler(int irq, void *data)
{
struct pm8921_chg_chip *chip = data;
+ int high_transition;
- /* disable this irq now, reenable it when resuming charging */
- pm8921_chg_disable_irq(chip, FASTCHG_IRQ);
- power_supply_changed(&chip->batt_psy);
- wake_lock(&chip->eoc_wake_lock);
- schedule_delayed_work(&chip->eoc_work,
- round_jiffies_relative(msecs_to_jiffies
+ high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
+ if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
+ wake_lock(&chip->eoc_wake_lock);
+ schedule_delayed_work(&chip->eoc_work,
+ round_jiffies_relative(msecs_to_jiffies
(EOC_CHECK_PERIOD_MS)));
+ }
+ power_supply_changed(&chip->batt_psy);
+ bms_notify_check(chip);
return IRQ_HANDLED;
}
@@ -1631,13 +1709,31 @@
power_supply_changed(&chip->dc_psy);
return IRQ_HANDLED;
}
-
+/*
+ *
+ * bat_temp_ok_irq_handler - is edge triggered, hence it will
+ * fire for two cases:
+ *
+ * If the interrupt line switches to high temperature is okay
+ * and thus charging begins.
+ * If bat_temp_ok is low this means the temperature is now
+ * too hot or cold, so charging is stopped.
+ *
+ */
static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
{
+ int bat_temp_ok;
struct pm8921_chg_chip *chip = data;
- pr_debug("batt temp ok fsm_state=%d\n", pm_chg_get_fsm_state(data));
- handle_start_ext_chg(chip);
+ bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
+
+ pr_debug("batt_temp_ok = %d fsm_state%d\n",
+ bat_temp_ok, pm_chg_get_fsm_state(data));
+
+ if (bat_temp_ok)
+ handle_start_ext_chg(chip);
+ else
+ handle_stop_ext_chg(chip);
power_supply_changed(&chip->batt_psy);
power_supply_changed(&chip->usb_psy);
@@ -1759,7 +1855,6 @@
pr_debug("fast_chg = %d\n", fast_chg);
if (fast_chg == 0) {
/* enable fastchg irq */
- pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
count = 0;
wake_unlock(&chip->eoc_wake_lock);
return;
@@ -1860,26 +1955,51 @@
{
int rc;
- rc = pm8921_adc_btm_configure(&btm_config);
+ rc = pm8xxx_adc_btm_configure(&btm_config);
if (rc)
pr_err("failed to configure btm rc=%d", rc);
}
DECLARE_WORK(btm_config_work, btm_configure_work);
+static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
+{
+ unsigned int chg_current = chip->max_bat_chg_current;
+
+ if (chip->is_bat_cool)
+ chg_current = min(chg_current, chip->cool_bat_chg_current);
+
+ if (chip->is_bat_warm)
+ chg_current = min(chg_current, chip->warm_bat_chg_current);
+
+ if (thermal_mitigation != 0 && !chip->thermal_mitigation)
+ chg_current = min(chg_current,
+ chip->thermal_mitigation[thermal_mitigation]);
+
+ pm_chg_ibatmax_set(the_chip, chg_current);
+}
+
#define TEMP_HYSTERISIS_DEGC 2
static void battery_cool(bool enter)
{
pr_debug("enter = %d\n", enter);
+ if (enter == the_chip->is_bat_cool)
+ return;
+ the_chip->is_bat_cool = enter;
if (enter) {
btm_config.low_thr_temp =
the_chip->cool_temp + TEMP_HYSTERISIS_DEGC;
- pm_chg_ibatmax_set(the_chip, the_chip->cool_bat_chg_current);
+ set_appropriate_battery_current(the_chip);
pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
+ pm_chg_vbatdet_set(the_chip,
+ the_chip->cool_bat_voltage
+ - the_chip->resume_voltage_delta);
} else {
btm_config.low_thr_temp = the_chip->cool_temp;
- pm_chg_ibatmax_set(the_chip, the_chip->max_bat_chg_current);
+ set_appropriate_battery_current(the_chip);
pm_chg_vddmax_set(the_chip, the_chip->max_voltage);
+ pm_chg_vbatdet_set(the_chip,
+ the_chip->max_voltage - the_chip->resume_voltage_delta);
}
schedule_work(&btm_config_work);
}
@@ -1887,15 +2007,23 @@
static void battery_warm(bool enter)
{
pr_debug("enter = %d\n", enter);
+ if (enter == the_chip->is_bat_warm)
+ return;
+ the_chip->is_bat_warm = enter;
if (enter) {
btm_config.high_thr_temp =
the_chip->warm_temp - TEMP_HYSTERISIS_DEGC;
- pm_chg_ibatmax_set(the_chip, the_chip->warm_bat_chg_current);
+ set_appropriate_battery_current(the_chip);
pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
+ pm_chg_vbatdet_set(the_chip,
+ the_chip->warm_bat_voltage
+ - the_chip->resume_voltage_delta);
} else {
btm_config.high_thr_temp = the_chip->warm_temp;
- pm_chg_ibatmax_set(the_chip, the_chip->max_bat_chg_current);
+ set_appropriate_battery_current(the_chip);
pm_chg_vddmax_set(the_chip, the_chip->max_voltage);
+ pm_chg_vbatdet_set(the_chip,
+ the_chip->max_voltage - the_chip->resume_voltage_delta);
}
schedule_work(&btm_config_work);
}
@@ -1909,10 +2037,10 @@
btm_config.low_thr_temp = chip->cool_temp;
btm_config.high_thr_temp = chip->warm_temp;
btm_config.interval = chip->temp_check_period;
- rc = pm8921_adc_btm_configure(&btm_config);
+ rc = pm8xxx_adc_btm_configure(&btm_config);
if (rc)
pr_err("failed to configure btm rc = %d\n", rc);
- rc = pm8921_adc_btm_start();
+ rc = pm8xxx_adc_btm_start();
if (rc)
pr_err("failed to start btm rc = %d\n", rc);
@@ -2009,8 +2137,7 @@
return -EINVAL;
}
- ret = pm_chg_ibatmax_set(chip,
- chip->thermal_mitigation[thermal_mitigation]);
+ set_appropriate_battery_current(chip);
return ret;
}
module_param_call(thermal_mitigation, set_therm_mitigation_level,
@@ -2047,13 +2174,16 @@
pm8921_chg_enable_irq(chip, USBIN_UV_IRQ);
pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
+ pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
+ pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
spin_lock_irqsave(&vbus_lock, flags);
if (usb_chg_current) {
/* reissue a vbus draw call */
__pm8921_charger_vbus_draw(usb_chg_current);
+ fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
}
spin_unlock_irqrestore(&vbus_lock, flags);
@@ -2092,7 +2222,8 @@
CHG_IRQ(USBIN_OV_IRQ, IRQF_TRIGGER_RISING, usbin_ov_irq_handler),
CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
batt_inserted_irq_handler),
- CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_HIGH, vbatdet_low_irq_handler),
+ CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ vbatdet_low_irq_handler),
CHG_IRQ(USBIN_UV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
usbin_uv_irq_handler),
CHG_IRQ(VBAT_OV_IRQ, IRQF_TRIGGER_RISING, vbat_ov_irq_handler),
@@ -2104,7 +2235,8 @@
CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
- CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_HIGH, fastchg_irq_handler),
+ CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ fastchg_irq_handler),
CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
batt_removed_irq_handler),
@@ -2188,10 +2320,11 @@
chip->max_voltage, rc);
return rc;
}
- rc = pm_chg_vbatdet_set(chip, chip->resume_voltage);
+ rc = pm_chg_vbatdet_set(chip,
+ chip->max_voltage - chip->resume_voltage_delta);
if (rc) {
pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
- chip->resume_voltage, rc);
+ chip->max_voltage - chip->resume_voltage_delta, rc);
return rc;
}
@@ -2208,7 +2341,6 @@
return rc;
}
- /* TODO needs to be changed as per the temeperature of the battery */
rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
if (rc) {
pr_err("Failed to set max current to 400 rc=%d\n", rc);
@@ -2348,6 +2480,12 @@
pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0C);
}
+ /* Workarounds for die 3.0 */
+ if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0)
+ pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xAC);
+
+ pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD9);
+
/* Disable EOC FSM processing */
pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91);
@@ -2435,6 +2573,24 @@
}
DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
+enum {
+ BAT_WARM_ZONE,
+ BAT_COOL_ZONE,
+};
+static int get_warm_cool(void *data, u64 * val)
+{
+ if (!the_chip) {
+ pr_err("%s called before init\n", __func__);
+ return -EINVAL;
+ }
+ if ((int)data == BAT_WARM_ZONE)
+ *val = the_chip->is_bat_warm;
+ if ((int)data == BAT_COOL_ZONE)
+ *val = the_chip->is_bat_cool;
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
+
static void create_debugfs_entries(struct pm8921_chg_chip *chip)
{
int i;
@@ -2501,6 +2657,11 @@
debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
®_loop_fops);
+ debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
+ (void *)BAT_WARM_ZONE, &warm_cool_fops);
+ debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
+ (void *)BAT_COOL_ZONE, &warm_cool_fops);
+
for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
debugfs_create_file(chg_irq_data[i].name, 0444,
@@ -2535,7 +2696,7 @@
chip->update_time = pdata->update_time;
chip->max_voltage = pdata->max_voltage;
chip->min_voltage = pdata->min_voltage;
- chip->resume_voltage = pdata->resume_voltage;
+ chip->resume_voltage_delta = pdata->resume_voltage_delta;
chip->term_current = pdata->term_current;
chip->vbat_channel = pdata->charger_cdata.vbat_channel;
chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
@@ -2622,6 +2783,8 @@
enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
enable_irq_wake(chip->pmic_chg_irq[USBIN_OV_IRQ]);
enable_irq_wake(chip->pmic_chg_irq[USBIN_UV_IRQ]);
+ enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
+ enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
/*
* if both the cool_temp and warm_temp are zero the device doesnt
* care for jeita compliance
diff --git a/drivers/power/pm8xxx-ccadc.c b/drivers/power/pm8xxx-ccadc.c
new file mode 100644
index 0000000..5e0f8ec
--- /dev/null
+++ b/drivers/power/pm8xxx-ccadc.c
@@ -0,0 +1,762 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/ccadc.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#define CCADC_ANA_PARAM 0x240
+#define CCADC_DIG_PARAM 0x241
+#define CCADC_RSV 0x242
+#define CCADC_DATA0 0x244
+#define CCADC_DATA1 0x245
+#define CCADC_OFFSET_TRIM1 0x34A
+#define CCADC_OFFSET_TRIM0 0x34B
+#define CCADC_FULLSCALE_TRIM1 0x34C
+#define CCADC_FULLSCALE_TRIM0 0x34D
+
+/* note : TRIM1 is the msb and TRIM0 is the lsb */
+#define ADC_ARB_SECP_CNTRL 0x190
+#define ADC_ARB_SECP_AMUX_CNTRL 0x191
+#define ADC_ARB_SECP_ANA_PARAM 0x192
+#define ADC_ARB_SECP_DIG_PARAM 0x193
+#define ADC_ARB_SECP_RSV 0x194
+#define ADC_ARB_SECP_DATA1 0x195
+#define ADC_ARB_SECP_DATA0 0x196
+
+#define ADC_ARB_BMS_CNTRL 0x18D
+
+#define START_CONV_BIT BIT(7)
+#define EOC_CONV_BIT BIT(6)
+#define SEL_CCADC_BIT BIT(1)
+#define EN_ARB_BIT BIT(0)
+
+#define CCADC_CALIB_DIG_PARAM 0xE3
+#define CCADC_CALIB_RSV_GND 0x40
+#define CCADC_CALIB_RSV_25MV 0x80
+#define CCADC_CALIB_ANA_PARAM 0x1B
+#define SAMPLE_COUNT 16
+#define ADC_WAIT_COUNT 10
+
+#define CCADC_MAX_25MV 30000
+#define CCADC_MIN_25MV 20000
+#define CCADC_MAX_0UV -4000
+#define CCADC_MIN_0UV -7000
+
+#define CCADC_INTRINSIC_OFFSET 0xC000
+
+struct pm8xxx_ccadc_chip {
+ struct device *dev;
+ struct dentry *dent;
+ u16 ccadc_offset;
+ int ccadc_gain_uv;
+ unsigned int revision;
+ int eoc_irq;
+ int r_sense;
+};
+
+static struct pm8xxx_ccadc_chip *the_chip;
+
+static s64 microvolt_to_ccadc_reading_v1(s64 uv)
+{
+ return div_s64(uv * CCADC_READING_RESOLUTION_D_V1,
+ CCADC_READING_RESOLUTION_N_V1);
+}
+
+static s64 microvolt_to_ccadc_reading_v2(s64 uv)
+{
+ return div_s64(uv * CCADC_READING_RESOLUTION_D_V2,
+ CCADC_READING_RESOLUTION_N_V2);
+}
+
+static s64 microvolt_to_ccadc_reading(struct pm8xxx_ccadc_chip *chip, s64 cc)
+{
+ /*
+ * resolution (the value of a single bit) was changed after revision 2.0
+ * for more accurate readings
+ */
+ return (the_chip->revision < PM8XXX_REVISION_8921_2p0) ?
+ microvolt_to_ccadc_reading_v1((s64)cc) :
+ microvolt_to_ccadc_reading_v2((s64)cc);
+}
+
+static int cc_adjust_for_offset(u16 raw)
+{
+ /* this has the intrinsic offset */
+ return (int)raw - the_chip->ccadc_offset;
+}
+
+#define GAIN_REFERENCE_UV 25000
+/*
+ * gain compensation for ccadc readings - common for vsense based and
+ * couloumb counter based readings
+ */
+s64 pm8xxx_cc_adjust_for_gain(s64 uv)
+{
+ if (the_chip == NULL || the_chip->ccadc_gain_uv == 0)
+ return uv;
+
+ return div_s64(uv * GAIN_REFERENCE_UV, the_chip->ccadc_gain_uv);
+}
+EXPORT_SYMBOL(pm8xxx_cc_adjust_for_gain);
+
+static int pm_ccadc_masked_write(struct pm8xxx_ccadc_chip *chip, u16 addr,
+ u8 mask, u8 val)
+{
+ int rc;
+ u8 reg;
+
+ rc = pm8xxx_readb(chip->dev->parent, addr, ®);
+ if (rc) {
+ pr_err("read failed addr = %03X, rc = %d\n", addr, rc);
+ return rc;
+ }
+ reg &= ~mask;
+ reg |= val & mask;
+ rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
+ if (rc) {
+ pr_err("write failed addr = %03X, rc = %d\n", addr, rc);
+ return rc;
+ }
+ return 0;
+}
+
+#define REG_SBI_CONFIG 0x04F
+#define PAGE3_ENABLE_MASK 0x6
+static int calib_ccadc_enable_trim_access(struct pm8xxx_ccadc_chip *chip,
+ u8 *sbi_config)
+{
+ u8 reg;
+ int rc;
+
+ rc = pm8xxx_readb(chip->dev->parent, REG_SBI_CONFIG, sbi_config);
+ if (rc) {
+ pr_err("error = %d reading sbi config reg\n", rc);
+ return rc;
+ }
+
+ reg = *sbi_config | PAGE3_ENABLE_MASK;
+ return pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, reg);
+}
+
+static int calib_ccadc_restore_trim_access(struct pm8xxx_ccadc_chip *chip,
+ u8 sbi_config)
+{
+ return pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, sbi_config);
+}
+
+static int calib_ccadc_enable_arbiter(struct pm8xxx_ccadc_chip *chip)
+{
+ int rc;
+
+ /* enable Arbiter, must be sent twice */
+ rc = pm_ccadc_masked_write(chip, ADC_ARB_SECP_CNTRL,
+ SEL_CCADC_BIT | EN_ARB_BIT, SEL_CCADC_BIT | EN_ARB_BIT);
+ if (rc < 0) {
+ pr_err("error = %d enabling arbiter for offset\n", rc);
+ return rc;
+ }
+ rc = pm_ccadc_masked_write(chip, ADC_ARB_SECP_CNTRL,
+ SEL_CCADC_BIT | EN_ARB_BIT, SEL_CCADC_BIT | EN_ARB_BIT);
+ if (rc < 0) {
+ pr_err("error = %d writing ADC_ARB_SECP_CNTRL\n", rc);
+ return rc;
+ }
+ return 0;
+}
+
+static int calib_start_conv(struct pm8xxx_ccadc_chip *chip,
+ u16 *result)
+{
+ int rc, i;
+ u8 data_msb, data_lsb, reg;
+
+ /* Start conversion */
+ rc = pm_ccadc_masked_write(chip, ADC_ARB_SECP_CNTRL,
+ START_CONV_BIT, START_CONV_BIT);
+ if (rc < 0) {
+ pr_err("error = %d starting offset meas\n", rc);
+ return rc;
+ }
+
+ /* Wait for End of conversion */
+ for (i = 0; i < ADC_WAIT_COUNT; i++) {
+ rc = pm8xxx_readb(chip->dev->parent,
+ ADC_ARB_SECP_CNTRL, ®);
+ if (rc < 0) {
+ pr_err("error = %d read eoc for offset\n", rc);
+ return rc;
+ }
+ if ((reg & (START_CONV_BIT | EOC_CONV_BIT)) != EOC_CONV_BIT)
+ msleep(60);
+ else
+ break;
+ }
+ if (i == ADC_WAIT_COUNT) {
+ pr_err("waited too long for offset eoc\n");
+ return rc;
+ }
+
+ rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_DATA0, &data_lsb);
+ if (rc < 0) {
+ pr_err("error = %d reading offset lsb\n", rc);
+ return rc;
+ }
+
+ rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_DATA1, &data_msb);
+ if (rc < 0) {
+ pr_err("error = %d reading offset msb\n", rc);
+ return rc;
+ }
+
+ *result = (data_msb << 8) | data_lsb;
+ return 0;
+}
+
+static int calib_ccadc_read_trim(struct pm8xxx_ccadc_chip *chip,
+ int addr, u8 *data_msb, u8 *data_lsb)
+{
+ int rc;
+ u8 sbi_config;
+
+ calib_ccadc_enable_trim_access(chip, &sbi_config);
+ rc = pm8xxx_readb(chip->dev->parent, addr, data_msb);
+ if (rc < 0) {
+ pr_err("error = %d read msb\n", rc);
+ return rc;
+ }
+ rc = pm8xxx_readb(chip->dev->parent, addr + 1, data_lsb);
+ if (rc < 0) {
+ pr_err("error = %d read lsb\n", rc);
+ return rc;
+ }
+ calib_ccadc_restore_trim_access(chip, sbi_config);
+ return 0;
+}
+
+static void calib_ccadc_read_offset_and_gain(struct pm8xxx_ccadc_chip *chip,
+ int *gain, u16 *offset)
+{
+ s8 data_msb;
+ u8 data_lsb;
+ int rc;
+
+ rc = calib_ccadc_read_trim(chip, CCADC_FULLSCALE_TRIM1,
+ &data_msb, &data_lsb);
+ *gain = (data_msb << 8) | data_lsb;
+
+ rc = calib_ccadc_read_trim(chip, CCADC_OFFSET_TRIM1,
+ &data_msb, &data_lsb);
+ *offset = (data_msb << 8) | data_lsb;
+
+ pr_debug("raw gain trim = 0x%x offset trim =0x%x\n", *gain, *offset);
+ *gain = pm8xxx_ccadc_reading_to_microvolt(chip->revision,
+ (s64)*gain - *offset);
+ pr_debug("gain uv = %duV offset=0x%x\n", *gain, *offset);
+}
+
+#define CCADC_PROGRAM_TRIM_COUNT 2
+#define ADC_ARB_BMS_CNTRL_CCADC_SHIFT 4
+#define ADC_ARB_BMS_CNTRL_CONV_MASK 0x03
+#define BMS_CONV_IN_PROGRESS 0x2
+
+static int calib_ccadc_program_trim(struct pm8xxx_ccadc_chip *chip,
+ int addr, u8 data_msb, u8 data_lsb,
+ int wait)
+{
+ int i, rc, loop;
+ u8 cntrl, sbi_config;
+ bool in_progress = 0;
+
+ loop = wait ? CCADC_PROGRAM_TRIM_COUNT : 0;
+
+ calib_ccadc_enable_trim_access(chip, &sbi_config);
+
+ for (i = 0; i < loop; i++) {
+ rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_BMS_CNTRL, &cntrl);
+ if (rc < 0) {
+ pr_err("error = %d reading ADC_ARB_BMS_CNTRL\n", rc);
+ return rc;
+ }
+
+ /* break if a ccadc conversion is not happening */
+ in_progress = (((cntrl >> ADC_ARB_BMS_CNTRL_CCADC_SHIFT)
+ & ADC_ARB_BMS_CNTRL_CONV_MASK) == BMS_CONV_IN_PROGRESS);
+
+ if (!in_progress)
+ break;
+ }
+
+ if (in_progress) {
+ pr_debug("conv in progress cannot write trim,returing EBUSY\n");
+ return -EBUSY;
+ }
+
+ rc = pm8xxx_writeb(chip->dev->parent, addr, data_msb);
+ if (rc < 0) {
+ pr_err("error = %d write msb = 0x%x\n", rc, data_msb);
+ return rc;
+ }
+ rc = pm8xxx_writeb(chip->dev->parent, addr + 1, data_lsb);
+ if (rc < 0) {
+ pr_err("error = %d write lsb = 0x%x\n", rc, data_lsb);
+ return rc;
+ }
+ calib_ccadc_restore_trim_access(chip, sbi_config);
+ return 0;
+}
+
+void pm8xxx_calib_ccadc(void)
+{
+ u8 data_msb, data_lsb, sec_cntrl;
+ int result_offset, voltage_offset, result_gain;
+ u16 result;
+ int i, rc;
+
+ rc = pm8xxx_readb(the_chip->dev->parent,
+ ADC_ARB_SECP_CNTRL, &sec_cntrl);
+ if (rc < 0) {
+ pr_err("error = %d reading ADC_ARB_SECP_CNTRL\n", rc);
+ return;
+ }
+
+ rc = calib_ccadc_enable_arbiter(the_chip);
+ if (rc < 0) {
+ pr_err("error = %d enabling arbiter for offset\n", rc);
+ goto bail;
+ }
+
+ /*
+ * Set decimation ratio to 4k, lower ratio may be used in order to speed
+ * up, pending verification through bench
+ */
+ rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
+ CCADC_CALIB_DIG_PARAM);
+ if (rc < 0) {
+ pr_err("error = %d writing ADC_ARB_SECP_DIG_PARAM\n", rc);
+ goto bail;
+ }
+
+ result_offset = 0;
+ for (i = 0; i < SAMPLE_COUNT; i++) {
+ /* Short analog inputs to CCADC internally to ground */
+ rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_RSV,
+ CCADC_CALIB_RSV_GND);
+ if (rc < 0) {
+ pr_err("error = %d selecting gnd voltage\n", rc);
+ goto bail;
+ }
+
+ /* Enable CCADC */
+ rc = pm8xxx_writeb(the_chip->dev->parent,
+ ADC_ARB_SECP_ANA_PARAM, CCADC_CALIB_ANA_PARAM);
+ if (rc < 0) {
+ pr_err("error = %d enabling ccadc\n", rc);
+ goto bail;
+ }
+
+ rc = calib_start_conv(the_chip, &result);
+ if (rc < 0) {
+ pr_err("error = %d for zero volt measurement\n", rc);
+ goto bail;
+ }
+
+ result_offset += result;
+ }
+
+ result_offset = result_offset / SAMPLE_COUNT;
+
+ voltage_offset = pm8xxx_ccadc_reading_to_microvolt(the_chip->revision,
+ ((s64)result_offset - CCADC_INTRINSIC_OFFSET));
+
+ pr_debug("offset result_offset = 0x%x, voltage = %d microVolts\n",
+ result_offset, voltage_offset);
+
+ /* Sanity Check */
+ if (voltage_offset > CCADC_MAX_0UV) {
+ pr_err("offset voltage = %d is huge limiting to %d\n",
+ voltage_offset, CCADC_MAX_0UV);
+ result_offset = CCADC_INTRINSIC_OFFSET
+ + microvolt_to_ccadc_reading(the_chip,
+ (s64)CCADC_MAX_0UV);
+ } else if (voltage_offset < CCADC_MIN_0UV) {
+ pr_err("offset voltage = %d is too low limiting to %d\n",
+ voltage_offset, CCADC_MIN_0UV);
+ result_offset = CCADC_INTRINSIC_OFFSET
+ + microvolt_to_ccadc_reading(the_chip,
+ (s64)CCADC_MIN_0UV);
+ }
+
+ the_chip->ccadc_offset = result_offset;
+ data_msb = the_chip->ccadc_offset >> 8;
+ data_lsb = the_chip->ccadc_offset;
+
+ rc = calib_ccadc_program_trim(the_chip, CCADC_OFFSET_TRIM1,
+ data_msb, data_lsb, 1);
+ if (rc) {
+ pr_debug("error = %d programming offset trim 0x%02x 0x%02x\n",
+ rc, data_msb, data_lsb);
+ /* enable the interrupt and write it when it fires */
+ enable_irq(the_chip->eoc_irq);
+ }
+
+ rc = calib_ccadc_enable_arbiter(the_chip);
+ if (rc < 0) {
+ pr_err("error = %d enabling arbiter for gain\n", rc);
+ goto bail;
+ }
+
+ /*
+ * Set decimation ratio to 4k, lower ratio may be used in order to speed
+ * up, pending verification through bench
+ */
+ rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
+ CCADC_CALIB_DIG_PARAM);
+ if (rc < 0) {
+ pr_err("error = %d enabling decimation ration for gain\n", rc);
+ goto bail;
+ }
+
+ result_gain = 0;
+ for (i = 0; i < SAMPLE_COUNT; i++) {
+ rc = pm8xxx_writeb(the_chip->dev->parent,
+ ADC_ARB_SECP_RSV, CCADC_CALIB_RSV_25MV);
+ if (rc < 0) {
+ pr_err("error = %d selecting 25mV for gain\n", rc);
+ goto bail;
+ }
+
+ /* Enable CCADC */
+ rc = pm8xxx_writeb(the_chip->dev->parent,
+ ADC_ARB_SECP_ANA_PARAM, CCADC_CALIB_ANA_PARAM);
+ if (rc < 0) {
+ pr_err("error = %d enabling ccadc\n", rc);
+ goto bail;
+ }
+
+ rc = calib_start_conv(the_chip, &result);
+ if (rc < 0) {
+ pr_err("error = %d for adc reading 25mV\n", rc);
+ goto bail;
+ }
+
+ result_gain += result;
+ }
+ result_gain = result_gain / SAMPLE_COUNT;
+
+ /*
+ * result_offset includes INTRINSIC OFFSET
+ * the_chip->ccadc_gain_uv will be the actual voltage
+ * measured for 25000UV
+ */
+ the_chip->ccadc_gain_uv = pm8xxx_ccadc_reading_to_microvolt(
+ the_chip->revision,
+ ((s64)result_gain - result_offset));
+
+ pr_debug("gain result_gain = 0x%x, voltage = %d microVolts\n",
+ result_gain, the_chip->ccadc_gain_uv);
+ /* Sanity Check */
+ if (the_chip->ccadc_gain_uv > CCADC_MAX_25MV) {
+ pr_err("gain voltage = %d is huge limiting to %d\n",
+ the_chip->ccadc_gain_uv,
+ CCADC_MAX_25MV);
+ the_chip->ccadc_gain_uv = CCADC_MAX_25MV;
+ result_gain = result_offset +
+ microvolt_to_ccadc_reading(the_chip, CCADC_MAX_25MV);
+ } else if (the_chip->ccadc_gain_uv < CCADC_MIN_25MV) {
+ pr_err("gain voltage = %d is too low limiting to %d\n",
+ the_chip->ccadc_gain_uv,
+ CCADC_MIN_25MV);
+ the_chip->ccadc_gain_uv = CCADC_MIN_25MV;
+ result_gain = result_offset +
+ microvolt_to_ccadc_reading(the_chip, CCADC_MIN_25MV);
+ }
+
+ data_msb = result_gain >> 8;
+ data_lsb = result_gain;
+ rc = calib_ccadc_program_trim(the_chip, CCADC_FULLSCALE_TRIM1,
+ data_msb, data_lsb, 0);
+ if (rc)
+ pr_debug("error = %d programming gain trim\n", rc);
+bail:
+ pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_CNTRL, sec_cntrl);
+}
+EXPORT_SYMBOL(pm8xxx_calib_ccadc);
+
+static irqreturn_t pm8921_bms_ccadc_eoc_handler(int irq, void *data)
+{
+ u8 data_msb, data_lsb;
+ struct pm8xxx_ccadc_chip *chip = data;
+ int rc;
+
+ pr_debug("irq = %d triggered\n", irq);
+ data_msb = chip->ccadc_offset >> 8;
+ data_lsb = chip->ccadc_offset;
+
+ rc = calib_ccadc_program_trim(chip, CCADC_OFFSET_TRIM1,
+ data_msb, data_lsb, 0);
+ disable_irq_nosync(chip->eoc_irq);
+
+ return IRQ_HANDLED;
+}
+
+#define CCADC_IBAT_DIG_PARAM 0xA3
+#define CCADC_IBAT_RSV 0x10
+#define CCADC_IBAT_ANA_PARAM 0x1A
+static int ccadc_get_rsense_voltage(int *voltage_uv)
+{
+ u16 raw;
+ int result;
+ int rc = 0;
+
+ rc = calib_ccadc_enable_arbiter(the_chip);
+ if (rc < 0) {
+ pr_err("error = %d enabling arbiter for offset\n", rc);
+ return rc;
+ }
+
+ rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
+ CCADC_IBAT_DIG_PARAM);
+ if (rc < 0) {
+ pr_err("error = %d writing ADC_ARB_SECP_DIG_PARAM\n", rc);
+ return rc;
+ }
+
+ rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_RSV,
+ CCADC_IBAT_RSV);
+ if (rc < 0) {
+ pr_err("error = %d selecting rsense\n", rc);
+ return rc;
+ }
+
+ rc = pm8xxx_writeb(the_chip->dev->parent,
+ ADC_ARB_SECP_ANA_PARAM, CCADC_IBAT_ANA_PARAM);
+ if (rc < 0) {
+ pr_err("error = %d enabling ccadc\n", rc);
+ return rc;
+ }
+
+ rc = calib_start_conv(the_chip, &raw);
+ if (rc < 0) {
+ pr_err("error = %d for zero volt measurement\n", rc);
+ return rc;
+ }
+
+ pr_debug("Vsense raw = 0x%x\n", raw);
+ result = cc_adjust_for_offset(raw);
+ pr_debug("Vsense after offset raw = 0x%x offset=0x%x\n",
+ result,
+ the_chip->ccadc_offset);
+ *voltage_uv = pm8xxx_ccadc_reading_to_microvolt(the_chip->revision,
+ ((s64)result));
+ pr_debug("Vsense before gain = %d uV\n", *voltage_uv);
+ *voltage_uv = pm8xxx_cc_adjust_for_gain(*voltage_uv);
+
+ pr_debug("Vsense = %d uV\n", *voltage_uv);
+ return 0;
+}
+
+int pm8xxx_ccadc_get_battery_current(int *bat_current)
+{
+ int voltage_uv, rc;
+
+ rc = ccadc_get_rsense_voltage(&voltage_uv);
+ if (rc) {
+ pr_err("cant get voltage across rsense rc = %d\n", rc);
+ return rc;
+ }
+
+ *bat_current = voltage_uv/the_chip->r_sense;
+ /*
+ * ccadc reads +ve current when the battery is charging
+ * We need to return -ve if the battery is charging
+ */
+ *bat_current = -1 * (*bat_current);
+ pr_debug("bat current = %d ma\n", *bat_current);
+ return 0;
+}
+EXPORT_SYMBOL(pm8xxx_ccadc_get_battery_current);
+
+static int get_reg(void *data, u64 * val)
+{
+ int addr = (int)data;
+ int ret;
+ u8 temp;
+
+ ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
+ if (ret) {
+ pr_err("pm8xxx_readb to %x value = %d errored = %d\n",
+ addr, temp, ret);
+ return -EAGAIN;
+ }
+ *val = temp;
+ return 0;
+}
+
+static int set_reg(void *data, u64 val)
+{
+ int addr = (int)data;
+ int ret;
+ u8 temp;
+
+ temp = (u8) val;
+ ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
+ if (ret) {
+ pr_err("pm8xxx_writeb to %x value = %d errored = %d\n",
+ addr, temp, ret);
+ return -EAGAIN;
+ }
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
+
+static int get_calc(void *data, u64 * val)
+{
+ int ibat, rc;
+
+ rc = pm8xxx_ccadc_get_battery_current(&ibat);
+ *val = ibat;
+ return rc;
+}
+DEFINE_SIMPLE_ATTRIBUTE(calc_fops, get_calc, NULL, "%lld\n");
+
+static void create_debugfs_entries(struct pm8xxx_ccadc_chip *chip)
+{
+ chip->dent = debugfs_create_dir("pm8xxx-ccadc", NULL);
+
+ if (IS_ERR(chip->dent)) {
+ pr_err("ccadc couldnt create debugfs dir\n");
+ return;
+ }
+
+ debugfs_create_file("CCADC_ANA_PARAM", 0644, chip->dent,
+ (void *)CCADC_ANA_PARAM, ®_fops);
+ debugfs_create_file("CCADC_DIG_PARAM", 0644, chip->dent,
+ (void *)CCADC_DIG_PARAM, ®_fops);
+ debugfs_create_file("CCADC_RSV", 0644, chip->dent,
+ (void *)CCADC_RSV, ®_fops);
+ debugfs_create_file("CCADC_DATA0", 0644, chip->dent,
+ (void *)CCADC_DATA0, ®_fops);
+ debugfs_create_file("CCADC_DATA1", 0644, chip->dent,
+ (void *)CCADC_DATA1, ®_fops);
+ debugfs_create_file("CCADC_OFFSET_TRIM1", 0644, chip->dent,
+ (void *)CCADC_OFFSET_TRIM1, ®_fops);
+ debugfs_create_file("CCADC_OFFSET_TRIM0", 0644, chip->dent,
+ (void *)CCADC_OFFSET_TRIM0, ®_fops);
+ debugfs_create_file("CCADC_FULLSCALE_TRIM1", 0644, chip->dent,
+ (void *)CCADC_FULLSCALE_TRIM1, ®_fops);
+ debugfs_create_file("CCADC_FULLSCALE_TRIM0", 0644, chip->dent,
+ (void *)CCADC_FULLSCALE_TRIM0, ®_fops);
+
+ debugfs_create_file("show_ibatt", 0644, chip->dent,
+ (void *)0, &calc_fops);
+}
+
+static int __devinit pm8xxx_ccadc_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ struct pm8xxx_ccadc_chip *chip;
+ struct resource *res;
+ const struct pm8xxx_ccadc_platform_data *pdata
+ = pdev->dev.platform_data;
+
+ if (!pdata) {
+ pr_err("missing platform data\n");
+ return -EINVAL;
+ }
+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+ "PM8921_BMS_CCADC_EOC");
+ if (!res) {
+ pr_err("failed to get irq\n");
+ return -EINVAL;
+ }
+
+ chip = kzalloc(sizeof(struct pm8xxx_ccadc_chip), GFP_KERNEL);
+ if (!chip) {
+ pr_err("Cannot allocate pm_bms_chip\n");
+ return -ENOMEM;
+ }
+ chip->dev = &pdev->dev;
+ chip->revision = pm8xxx_get_revision(chip->dev->parent);
+ chip->eoc_irq = res->start;
+ chip->r_sense = pdata->r_sense;
+
+ calib_ccadc_read_offset_and_gain(chip,
+ &chip->ccadc_gain_uv,
+ &chip->ccadc_offset);
+ rc = request_irq(chip->eoc_irq,
+ pm8921_bms_ccadc_eoc_handler, IRQF_TRIGGER_RISING,
+ "bms_eoc_ccadc", chip);
+ if (rc) {
+ pr_err("failed to request %d irq rc= %d\n", chip->eoc_irq, rc);
+ goto free_chip;
+ }
+ disable_irq_nosync(chip->eoc_irq);
+
+ platform_set_drvdata(pdev, chip);
+ the_chip = chip;
+
+ create_debugfs_entries(chip);
+
+ return 0;
+
+free_chip:
+ kfree(chip);
+ return rc;
+}
+
+static int __devexit pm8xxx_ccadc_remove(struct platform_device *pdev)
+{
+ struct pm8xxx_ccadc_chip *chip = platform_get_drvdata(pdev);
+
+ debugfs_remove_recursive(chip->dent);
+ the_chip = NULL;
+ kfree(chip);
+ return 0;
+}
+
+static struct platform_driver pm8xxx_ccadc_driver = {
+ .probe = pm8xxx_ccadc_probe,
+ .remove = __devexit_p(pm8xxx_ccadc_remove),
+ .driver = {
+ .name = PM8XXX_CCADC_DEV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pm8xxx_ccadc_init(void)
+{
+ return platform_driver_register(&pm8xxx_ccadc_driver);
+}
+
+static void __exit pm8xxx_ccadc_exit(void)
+{
+ platform_driver_unregister(&pm8xxx_ccadc_driver);
+}
+
+module_init(pm8xxx_ccadc_init);
+module_exit(pm8xxx_ccadc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PMIC8XXX ccadc driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:" PM8XXX_CCADC_DEV_NAME);
diff --git a/drivers/power/pmic8058-charger.c b/drivers/power/pmic8058-charger.c
index a3ce54d..70b5d59 100644
--- a/drivers/power/pmic8058-charger.c
+++ b/drivers/power/pmic8058-charger.c
@@ -15,7 +15,6 @@
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/errno.h>
-#include <linux/mfd/pmic8058.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/bitops.h>
@@ -25,8 +24,10 @@
#include <linux/slab.h>
#include <linux/msm_adc.h>
#include <linux/notifier.h>
-#include <linux/pmic8058-batt-alarm.h>
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pmic8058.h>
#include <linux/pmic8058-charger.h>
+#include <linux/mfd/pm8xxx/batt-alarm.h>
#include <mach/msm_xo.h>
#include <mach/msm_hsusb.h>
@@ -177,7 +178,6 @@
struct pm8058_charger {
struct pmic_charger_pdata *pdata;
- struct pm8058_chip *pm_chip;
struct device *dev;
int pmic_chg_irq[PMIC_CHG_MAX_INTS];
@@ -228,7 +228,11 @@
if (rc)
goto out;
- rc = pm8058_batt_alarm_threshold_set(resume_mv, 4300);
+ rc = pm8xxx_batt_alarm_threshold_set(
+ PM8XXX_BATT_ALARM_LOWER_COMPARATOR, resume_mv);
+ if (!rc)
+ rc = pm8xxx_batt_alarm_threshold_set(
+ PM8XXX_BATT_ALARM_UPPER_COMPARATOR, 4300);
out:
mutex_unlock(&batt_alarm_lock);
@@ -255,15 +259,9 @@
static int pm_chg_get_rt_status(int irq)
{
- int count = 3;
int ret;
- while ((ret =
- pm8058_irq_get_rt_status(pm8058_chg.pm_chip, irq)) == -EAGAIN
- && count--) {
- dev_info(pm8058_chg.dev, "%s trycount=%d\n", __func__, count);
- cpu_relax();
- }
+ ret = pm8xxx_read_irq_stat(pm8058_chg.dev->parent, irq);
if (ret == -EAGAIN)
return 0;
else
@@ -281,53 +279,53 @@
u8 temp;
int temp2;
- pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_CNTRL, &temp, 1);
+ pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_CNTRL, &temp);
dev_dbg(pm8058_chg.dev, "PM8058_CHG_CNTRL = 0x%x\n", temp);
- pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_CNTRL_2, &temp, 1);
+ pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_CNTRL_2, &temp);
dev_dbg(pm8058_chg.dev, "PM8058_CHG_CNTRL_2 = 0x%x\n", temp);
- pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_VMAX_SEL, &temp, 1);
+ pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_VMAX_SEL, &temp);
dev_dbg(pm8058_chg.dev, "PM8058_CHG_VMAX_SEL = 0x%x\n", temp);
- pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_VBAT_DET, &temp, 1);
+ pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_VBAT_DET, &temp);
dev_dbg(pm8058_chg.dev, "PM8058_CHG_VBAT_DET = 0x%x\n", temp);
- pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_IMAX, &temp, 1);
+ pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_IMAX, &temp);
dev_dbg(pm8058_chg.dev, "PM8058_CHG_IMAX = 0x%x\n", temp);
- pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_TRICKLE, &temp, 1);
+ pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_TRICKLE, &temp);
dev_dbg(pm8058_chg.dev, "PM8058_CHG_TRICKLE = 0x%x\n", temp);
- pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_ITERM, &temp, 1);
+ pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_ITERM, &temp);
dev_dbg(pm8058_chg.dev, "PM8058_CHG_ITERM = 0x%x\n", temp);
- pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_TTRKL_MAX, &temp, 1);
+ pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_TTRKL_MAX, &temp);
dev_dbg(pm8058_chg.dev, "PM8058_CHG_TTRKL_MAX = 0x%x\n", temp);
- pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_TCHG_MAX, &temp, 1);
+ pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_TCHG_MAX, &temp);
dev_dbg(pm8058_chg.dev, "PM8058_CHG_TCHG_MAX = 0x%x\n", temp);
- pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_TEMP_THRESH, &temp, 1);
+ pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_TEMP_THRESH, &temp);
dev_dbg(pm8058_chg.dev, "PM8058_CHG_TEMP_THRESH = 0x%x\n", temp);
- pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_TEMP_REG, &temp, 1);
+ pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_TEMP_REG, &temp);
dev_dbg(pm8058_chg.dev, "PM8058_CHG_TEMP_REG = 0x%x\n", temp);
- pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_PULSE, &temp, 1);
+ pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_PULSE, &temp);
dev_dbg(pm8058_chg.dev, "PM8058_CHG_PULSE = 0x%x\n", temp);
- pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_STATUS_CLEAR_IRQ_1,
- &temp, 1);
+ pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_STATUS_CLEAR_IRQ_1,
+ &temp);
dev_dbg(pm8058_chg.dev, "PM8058_CHG_STATUS_CLEAR_IRQ_1 = 0x%x\n", temp);
- pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_STATUS_CLEAR_IRQ_3,
- &temp, 1);
+ pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_STATUS_CLEAR_IRQ_3,
+ &temp);
dev_dbg(pm8058_chg.dev, "PM8058_CHG_STATUS_CLEAR_IRQ_3 = 0x%x\n", temp);
- pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_STATUS_CLEAR_IRQ_10,
- &temp, 1);
+ pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_STATUS_CLEAR_IRQ_10,
+ &temp);
dev_dbg(pm8058_chg.dev, "PM8058_CHG_STATUS_CLEAR_IRQ_10 = 0x%x\n",
temp);
- pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_STATUS_CLEAR_IRQ_11,
- &temp, 1);
+ pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_STATUS_CLEAR_IRQ_11,
+ &temp);
dev_dbg(pm8058_chg.dev, "PM8058_CHG_STATUS_CLEAR_IRQ_11 = 0x%x\n",
temp);
- pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_MASK_IRQ_1, &temp, 1);
+ pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_MASK_IRQ_1, &temp);
dev_dbg(pm8058_chg.dev, "PM8058_CHG_MASK_IRQ_1 = 0x%x\n", temp);
- pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_MASK_IRQ_3, &temp, 1);
+ pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_MASK_IRQ_3, &temp);
dev_dbg(pm8058_chg.dev, "PM8058_CHG_MASK_IRQ_3 = 0x%x\n", temp);
- pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_MASK_IRQ_10, &temp, 1);
+ pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_MASK_IRQ_10, &temp);
dev_dbg(pm8058_chg.dev, "PM8058_CHG_MASK_IRQ_10 = 0x%x\n", temp);
- pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_MASK_IRQ_11, &temp, 1);
+ pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_MASK_IRQ_11, &temp);
dev_dbg(pm8058_chg.dev, "PM8058_CHG_MASK_IRQ_11 = 0x%x\n", temp);
temp2 = pm_chg_get_rt_status(pm8058_chg.pmic_chg_irq[CHGVAL_IRQ]);
@@ -405,7 +403,7 @@
u8 temp;
int ret;
- ret = pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_CNTRL, &temp, 1);
+ ret = pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_CNTRL, &temp);
if (ret)
return ret;
if (value)
@@ -413,7 +411,7 @@
else
temp &= ~BIT(CHG_USB_SUSPEND);
- return pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_CNTRL, &temp, 1);
+ return pm8xxx_writeb(pm8058_chg.dev->parent, PM8058_CHG_CNTRL, temp);
}
static int pm_chg_auto_disable(int value)
@@ -421,7 +419,7 @@
u8 temp;
int ret;
- ret = pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_CNTRL_2, &temp, 1);
+ ret = pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_CNTRL_2, &temp);
if (ret)
return ret;
if (value)
@@ -429,7 +427,7 @@
else
temp &= ~BIT(CHARGE_AUTO_DIS);
- return pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_CNTRL_2, &temp, 1);
+ return pm8xxx_writeb(pm8058_chg.dev->parent, PM8058_CHG_CNTRL_2, temp);
}
static int pm_chg_batt_temp_disable(int value)
@@ -437,7 +435,7 @@
u8 temp;
int ret;
- ret = pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_CNTRL_2, &temp, 1);
+ ret = pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_CNTRL_2, &temp);
if (ret)
return ret;
if (value)
@@ -445,7 +443,7 @@
else
temp &= ~BIT(CHG_BATT_TEMP_DIS);
- return pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_CNTRL_2, &temp, 1);
+ return pm8xxx_writeb(pm8058_chg.dev->parent, PM8058_CHG_CNTRL_2, temp);
}
static int pm_chg_vbatdet_set(int voltage)
@@ -463,7 +461,7 @@
temp = diff / PM8058_CHG_V_STEP_MV;
dev_dbg(pm8058_chg.dev, "%s voltage=%d setting %02x\n", __func__,
voltage, temp);
- return pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_VBAT_DET, &temp, 1);
+ return pm8xxx_writeb(pm8058_chg.dev->parent, PM8058_CHG_VBAT_DET, temp);
}
static int pm_chg_imaxsel_set(int chg_current)
@@ -484,7 +482,7 @@
__func__, chg_current);
temp = 31;
}
- return pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_IMAX, &temp, 1);
+ return pm8xxx_writeb(pm8058_chg.dev->parent, PM8058_CHG_IMAX, temp);
}
#define PM8058_CHG_VMAX_MIN 3300
@@ -501,7 +499,7 @@
temp = (voltage - PM8058_CHG_V_MIN_MV) / PM8058_CHG_V_STEP_MV;
dev_dbg(pm8058_chg.dev, "%s mV=%d setting %02x\n", __func__, voltage,
temp);
- return pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_VMAX_SEL, &temp, 1);
+ return pm8xxx_writeb(pm8058_chg.dev->parent, PM8058_CHG_VMAX_SEL, temp);
}
static int pm_chg_failed_clear(int value)
@@ -509,14 +507,14 @@
u8 temp;
int ret;
- ret = pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_CNTRL_2, &temp, 1);
+ ret = pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_CNTRL_2, &temp);
if (ret)
return ret;
if (value)
temp |= BIT(CHG_FAILED_CLEAR);
else
temp &= ~BIT(CHG_FAILED_CLEAR);
- return pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_CNTRL_2, &temp, 1);
+ return pm8xxx_writeb(pm8058_chg.dev->parent, PM8058_CHG_CNTRL_2, temp);
}
static int pm_chg_iterm_set(int chg_current)
@@ -524,7 +522,7 @@
u8 temp;
temp = (chg_current / PM8058_CHG_I_TERM_STEP_MA) - 1;
- return pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_ITERM, &temp, 1);
+ return pm8xxx_writeb(pm8058_chg.dev->parent, PM8058_CHG_ITERM, temp);
}
static int pm_chg_tchg_set(int minutes)
@@ -532,7 +530,7 @@
u8 temp;
temp = (minutes >> PM8058_CHG_T_TCHG_SHIFT) - 1;
- return pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_TCHG_MAX, &temp, 1);
+ return pm8xxx_writeb(pm8058_chg.dev->parent, PM8058_CHG_TCHG_MAX, temp);
}
static int pm_chg_ttrkl_set(int minutes)
@@ -540,7 +538,8 @@
u8 temp;
temp = minutes - 1;
- return pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_TTRKL_MAX, &temp, 1);
+ return pm8xxx_writeb(pm8058_chg.dev->parent, PM8058_CHG_TTRKL_MAX,
+ temp);
}
static int pm_chg_enum_done_enable(int value)
@@ -548,7 +547,7 @@
u8 temp;
int ret;
- ret = pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_CNTRL_2, &temp, 1);
+ ret = pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_CNTRL_2, &temp);
if (ret)
return ret;
if (value)
@@ -556,7 +555,7 @@
else
temp &= ~BIT(ENUM_DONE);
- return pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_CNTRL_2, &temp, 1);
+ return pm8xxx_writeb(pm8058_chg.dev->parent, PM8058_CHG_CNTRL_2, temp);
}
static uint32_t get_fsm_state(void)
@@ -564,8 +563,8 @@
u8 temp;
temp = 0x00;
- pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_TEST_3, &temp, 1);
- pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_TEST_3, &temp, 1);
+ pm8xxx_writeb(pm8058_chg.dev->parent, PM8058_CHG_TEST_3, temp);
+ pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_TEST_3, &temp);
return (uint32_t)temp;
}
@@ -590,7 +589,7 @@
u8 temp;
int ret;
- ret = pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_CNTRL, &temp, 1);
+ ret = pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_CNTRL, &temp);
if (ret)
return ret;
if (value)
@@ -598,7 +597,7 @@
else
temp &= ~BIT(CHG_CHARGE_DIS);
- return pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_CNTRL, &temp, 1);
+ return pm8xxx_writeb(pm8058_chg.dev->parent, PM8058_CHG_CNTRL, temp);
}
static void pm8058_start_system_current(struct msm_hardware_charger *hw_chg,
@@ -734,7 +733,11 @@
case PMIC8058_CHG_STATE_ATC:
case PMIC8058_CHG_STATE_FAST_CHG:
case PMIC8058_CHG_STATE_TRKL_CHG:
- rc = pm8058_batt_alarm_state_set(0, 0);
+ rc = pm8xxx_batt_alarm_disable(
+ PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
+ if (!rc)
+ rc = pm8xxx_batt_alarm_disable(
+ PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
if (rc)
dev_err(pm8058_chg.dev,
"%s: unable to set alarm state\n", __func__);
@@ -863,25 +866,25 @@
}
} else {
if (pm8058_chg.present) {
- ret = pm8058_read(pm8058_chg.pm_chip,
+ ret = pm8xxx_readb(pm8058_chg.dev->parent,
PM8058_OVP_TEST_REG,
- &old, 1);
+ &old);
temp = old | BIT(FORCE_OVP_OFF);
- ret = pm8058_write(pm8058_chg.pm_chip,
+ ret = pm8xxx_writeb(pm8058_chg.dev->parent,
PM8058_OVP_TEST_REG,
- &temp, 1);
+ temp);
temp = 0xFC;
- ret = pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_TEST,
- &temp, 1);
+ ret = pm8xxx_writeb(pm8058_chg.dev->parent,
+ PM8058_CHG_TEST, temp);
/* 10 ms sleep is for the VCHG to discharge */
msleep(10);
temp = 0xF0;
- ret = pm8058_write(pm8058_chg.pm_chip,
+ ret = pm8xxx_writeb(pm8058_chg.dev->parent,
PM8058_CHG_TEST,
- &temp, 1);
- ret = pm8058_write(pm8058_chg.pm_chip,
+ temp);
+ ret = pm8xxx_writeb(pm8058_chg.dev->parent,
PM8058_OVP_TEST_REG,
- &old, 1);
+ old);
pm_chg_enum_done_enable(0);
pm_chg_auto_disable(1);
@@ -904,21 +907,21 @@
pm_chg_enum_done_enable(0);
pm_chg_auto_disable(1);
- ret = pm8058_read(pm8058_chg.pm_chip,
- PM8058_OVP_TEST_REG, &old, 1);
+ ret = pm8xxx_readb(pm8058_chg.dev->parent,
+ PM8058_OVP_TEST_REG, &old);
temp = old | BIT(FORCE_OVP_OFF);
- ret = pm8058_write(pm8058_chg.pm_chip,
- PM8058_OVP_TEST_REG, &temp, 1);
+ ret = pm8xxx_writeb(pm8058_chg.dev->parent,
+ PM8058_OVP_TEST_REG, temp);
temp = 0xFC;
- ret = pm8058_write(pm8058_chg.pm_chip,
- PM8058_CHG_TEST, &temp, 1);
+ ret = pm8xxx_writeb(pm8058_chg.dev->parent,
+ PM8058_CHG_TEST, temp);
/* 10 ms sleep is for the VCHG to discharge */
msleep(10);
temp = 0xF0;
- ret = pm8058_write(pm8058_chg.pm_chip,
- PM8058_CHG_TEST, &temp, 1);
- ret = pm8058_write(pm8058_chg.pm_chip,
- PM8058_OVP_TEST_REG, &old, 1);
+ ret = pm8xxx_writeb(pm8058_chg.dev->parent,
+ PM8058_CHG_TEST, temp);
+ ret = pm8xxx_writeb(pm8058_chg.dev->parent,
+ PM8058_OVP_TEST_REG, old);
if (!is_chg_plugged_in()) {
msm_charger_notify_event(&usb_hw_chg,
@@ -983,8 +986,8 @@
u8 temp;
temp = 0x00;
- if (!pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_TEST_3, &temp, 1)) {
- pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_TEST_3, &temp, 1);
+ if (!pm8xxx_writeb(pm8058_chg.dev->parent, PM8058_CHG_TEST_3, temp)) {
+ pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_TEST_3, &temp);
dev_dbg(pm8058_chg.dev, "%s state=%d\n", __func__, temp);
}
return IRQ_HANDLED;
@@ -1187,7 +1190,7 @@
"%s:couldnt find resource AUTO_CHGDONE\n", __func__);
goto err_out;
} else {
- ret = request_threaded_irq(res->start, NULL,
+ ret = request_irq(res->start,
pm8058_chg_auto_chgdone_handler,
IRQF_TRIGGER_RISING,
res->name, NULL);
@@ -1208,7 +1211,7 @@
"%s:couldnt find resource AUTO_CHGFAIL\n", __func__);
goto err_out;
} else {
- ret = request_threaded_irq(res->start, NULL,
+ ret = request_irq(res->start,
pm8058_chg_auto_chgfail_handler,
IRQF_TRIGGER_RISING, res->name, NULL);
if (ret < 0) {
@@ -1227,7 +1230,7 @@
"%s:couldnt find resource CHGSTATE\n", __func__);
goto err_out;
} else {
- ret = request_threaded_irq(res->start, NULL,
+ ret = request_irq(res->start,
pm8058_chg_chgstate_handler,
IRQF_TRIGGER_RISING, res->name, NULL);
if (ret < 0) {
@@ -1246,7 +1249,7 @@
"%s:couldnt find resource FASTCHG\n", __func__);
goto err_out;
} else {
- ret = request_threaded_irq(res->start, NULL,
+ ret = request_irq(res->start,
pm8058_chg_fastchg_handler,
IRQF_TRIGGER_RISING, res->name, NULL);
if (ret < 0) {
@@ -1265,7 +1268,7 @@
"%s:couldnt find resource CHG_END\n", __func__);
goto err_out;
} else {
- ret = request_threaded_irq(res->start, NULL,
+ ret = request_irq(res->start,
pm8058_chg_batttemp_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
res->name, NULL);
@@ -1286,7 +1289,7 @@
"%s:couldnt find resource BATT_REPLACE\n", __func__);
goto err_out;
} else {
- ret = request_threaded_irq(res->start, NULL,
+ ret = request_irq(res->start,
pm8058_chg_batt_replace_handler,
IRQF_TRIGGER_RISING, res->name, NULL);
if (ret < 0) {
@@ -1305,7 +1308,7 @@
"%s:couldnt find resource BATTCONNECT\n", __func__);
goto err_out;
} else {
- ret = request_threaded_irq(res->start, NULL,
+ ret = request_irq(res->start,
pm8058_chg_battconnect_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
res->name, NULL);
@@ -1351,7 +1354,7 @@
u8 temp;
int rc;
- rc = pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_CNTRL, &temp, 1);
+ rc = pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_CNTRL, &temp);
if (rc)
return rc;
@@ -1367,7 +1370,7 @@
u8 temp;
int rc;
- rc = pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_CNTRL, &temp, 1);
+ rc = pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_CNTRL, &temp);
if (rc)
return rc;
if (on)
@@ -1375,7 +1378,7 @@
else
temp &= ~BIT(CHG_CHARGE_BAT);
- return pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_CNTRL, &temp, 1);
+ return pm8xxx_writeb(pm8058_chg.dev->parent, PM8058_CHG_CNTRL, temp);
}
EXPORT_SYMBOL(pm8058_set_charge_batt);
@@ -1496,12 +1499,12 @@
u8 temp;
temp = 0xA3;
- pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_TEST_2, &temp, 1);
+ pm8xxx_writeb(pm8058_chg.dev->parent, PM8058_CHG_TEST_2, temp);
temp = 0x84;
- pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_TEST_2, &temp, 1);
+ pm8xxx_writeb(pm8058_chg.dev->parent, PM8058_CHG_TEST_2, temp);
msleep(2);
temp = 0x80;
- pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_TEST_2, &temp, 1);
+ pm8xxx_writeb(pm8058_chg.dev->parent, PM8058_CHG_TEST_2, temp);
return 0;
}
@@ -1511,7 +1514,7 @@
int ret;
u8 temp;
- ret = pm8058_read(pm8058_chg.pm_chip, i, &temp, 1);
+ ret = pm8xxx_readb(pm8058_chg.dev->parent, i, &temp);
if (ret)
return -EAGAIN;
*val = temp;
@@ -1525,7 +1528,7 @@
u8 temp;
temp = (u8) val;
- ret = pm8058_write(pm8058_chg.pm_chip, i, &temp, 1);
+ ret = pm8xxx_writeb(pm8058_chg.dev->parent, i, temp);
mb();
if (ret)
return -EAGAIN;
@@ -1821,7 +1824,11 @@
break;
/* expected case - trip of low threshold */
case 1:
- rc = pm8058_batt_alarm_state_set(0, 0);
+ rc = pm8xxx_batt_alarm_disable(
+ PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
+ if (!rc)
+ rc = pm8xxx_batt_alarm_disable(
+ PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
if (rc)
dev_err(pm8058_chg.dev,
"%s: unable to set alarm state\n", __func__);
@@ -1841,8 +1848,15 @@
static int pm8058_monitor_for_recharging(void)
{
+ int rc;
/* enable low comparator */
- return pm8058_batt_alarm_state_set(1, 0);
+ rc = pm8xxx_batt_alarm_disable(PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
+ if (!rc)
+ return pm8xxx_batt_alarm_enable(
+ PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
+
+ return rc;
+
}
static struct msm_battery_gauge pm8058_batt_gauge = {
@@ -1860,33 +1874,30 @@
int ret = 0;
temp = 0x10;
- ret |= pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_TEST, &temp, 1);
- ret |= pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_TEST, &old, 1);
+ ret |= pm8xxx_writeb(pm8058_chg.dev->parent, PM8058_CHG_TEST, temp);
+ ret |= pm8xxx_readb(pm8058_chg.dev->parent, PM8058_CHG_TEST, &old);
old = old & ~BIT(IGNORE_LL);
temp = 0x90 | (0xF & old);
- ret |= pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_TEST, &temp, 1);
+ ret |= pm8xxx_writeb(pm8058_chg.dev->parent, PM8058_CHG_TEST, temp);
return ret;
}
static int __devinit pm8058_charger_probe(struct platform_device *pdev)
{
- struct pm8058_chip *pm_chip;
struct pmic8058_charger_data *pdata;
int rc = 0;
- pm_chip = dev_get_drvdata(pdev->dev.parent);
- if (pm_chip == NULL) {
- pr_err("%s:no parent data passed in.\n", __func__);
- return -EFAULT;
- }
-
- pm8058_chg.pm_chip = pm_chip;
pm8058_chg.pdata = pdev->dev.platform_data;
pm8058_chg.dev = &pdev->dev;
pdata = (struct pmic8058_charger_data *) pm8058_chg.pdata;
- if (pdata) {
+ if (pdata == NULL) {
+ pr_err("%s: pdata not present\n", __func__);
+ return -EINVAL;
+ }
+
+ if (pdata->charger_data_valid) {
usb_hw_chg.type = pdata->charger_type;
chg_data.charger_type = pdata->charger_type;
chg_data.max_source_current = pdata->max_source_current;
@@ -1928,7 +1939,10 @@
pm8058_chg_enable_irq(BATTTEMP_IRQ);
pm8058_chg_enable_irq(BATTCONNECT_IRQ);
- rc = pm8058_batt_alarm_state_set(0, 0);
+ rc = pm8xxx_batt_alarm_disable(PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
+ if (!rc)
+ rc = pm8xxx_batt_alarm_disable(
+ PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
if (rc) {
pr_err("%s: unable to set batt alarm state\n", __func__);
goto free_irq;
@@ -1938,26 +1952,31 @@
* The batt-alarm driver requires sane values for both min / max,
* regardless of whether they're both activated.
*/
- rc = pm8058_batt_alarm_threshold_set(resume_mv, 4300);
+ rc = pm8xxx_batt_alarm_threshold_set(
+ PM8XXX_BATT_ALARM_LOWER_COMPARATOR, resume_mv);
+ if (!rc)
+ rc = pm8xxx_batt_alarm_threshold_set(
+ PM8XXX_BATT_ALARM_UPPER_COMPARATOR, 4300);
if (rc) {
pr_err("%s: unable to set batt alarm threshold\n", __func__);
goto free_irq;
}
- rc = pm8058_batt_alarm_hold_time_set(PM8058_BATT_ALARM_HOLD_TIME_16_MS);
+ rc = pm8xxx_batt_alarm_hold_time_set(
+ PM8XXX_BATT_ALARM_HOLD_TIME_16_MS);
if (rc) {
pr_err("%s: unable to set batt alarm hold time\n", __func__);
goto free_irq;
}
/* PWM enabled at 2Hz */
- rc = pm8058_batt_alarm_pwm_rate_set(1, 7, 4);
+ rc = pm8xxx_batt_alarm_pwm_rate_set(1, 7, 4);
if (rc) {
pr_err("%s: unable to set batt alarm pwm rate\n", __func__);
goto free_irq;
}
- rc = pm8058_batt_alarm_register_notifier(&alarm_notifier);
+ rc = pm8xxx_batt_alarm_register_notifier(&alarm_notifier);
if (rc) {
pr_err("%s: unable to register alarm notifier\n", __func__);
goto free_irq;
@@ -1987,11 +2006,14 @@
remove_debugfs_entries();
kfree(chip);
- rc = pm8058_batt_alarm_state_set(0, 0);
+ rc = pm8xxx_batt_alarm_disable(PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
+ if (!rc)
+ rc = pm8xxx_batt_alarm_disable(
+ PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
if (rc)
pr_err("%s: unable to set batt alarm state\n", __func__);
- rc |= pm8058_batt_alarm_unregister_notifier(&alarm_notifier);
+ rc |= pm8xxx_batt_alarm_unregister_notifier(&alarm_notifier);
if (rc)
pr_err("%s: unable to register alarm notifier\n", __func__);
return rc;
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index 03810ce..a184ab6 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -25,6 +25,44 @@
static struct device_type power_supply_dev_type;
+/**
+ * power_supply_set_current_limit - set current limit
+ * @psy: the power supply to control
+ * @limit: current limit in uA from the power supply.
+ * 0 will disable the power supply.
+ *
+ * This function will set a maximum supply current from a source
+ * and it will disable the charger when limit is 0.
+ */
+int power_supply_set_current_limit(struct power_supply *psy, int limit)
+{
+ const union power_supply_propval ret = {limit,};
+
+ if (psy->set_property)
+ return psy->set_property(psy, POWER_SUPPLY_PROP_CURRENT_MAX,
+ &ret);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(power_supply_set_current_limit);
+
+/**
+ * power_supply_set_charging_by - set charging state of the charger
+ * @psy: the power supply to control
+ * @enable: enables or disables the charger
+ */
+int power_supply_set_charging_by(struct power_supply *psy, bool enable)
+{
+ const union power_supply_propval ret = {enable,};
+
+ if (psy->set_property)
+ return psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE,
+ &ret);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(power_supply_set_charging_by);
+
static int __power_supply_changed_work(struct device *dev, void *data)
{
struct power_supply *psy = (struct power_supply *)data;
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index ee89358..ebe77dd 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -505,8 +505,7 @@
rdev->dev.dma_mask = &rdev->dma_mask;
rdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
- if ((rdev->pef & RIO_PEF_INB_DOORBELL) &&
- (rdev->dst_ops & RIO_DST_OPS_DOORBELL))
+ if (rdev->dst_ops & RIO_DST_OPS_DOORBELL)
rio_init_dbell_res(&rdev->riores[RIO_DOORBELL_RESOURCE],
0, 0xffff);
diff --git a/drivers/regulator/pm8058-xo.c b/drivers/regulator/pm8058-xo.c
index 581e228..b778660 100644
--- a/drivers/regulator/pm8058-xo.c
+++ b/drivers/regulator/pm8058-xo.c
@@ -19,6 +19,7 @@
#include <linux/bitops.h>
#include <linux/mfd/pmic8058.h>
#include <linux/regulator/driver.h>
+#include <linux/mfd/pm8xxx/core.h>
#include <linux/regulator/pm8058-xo.h>
/* XO buffer masks and values */
@@ -39,6 +40,7 @@
#define XO_DISABLE (XO_MODE_MANUAL | XO_BUFFER_DISABLE)
struct pm8058_xo_buffer {
+ struct device *dev;
struct pm8058_xo_pdata *pdata;
struct regulator_dev *rdev;
u16 ctrl_addr;
@@ -55,7 +57,7 @@
XO_BUFFER(A1, 0x186),
};
-static int pm8058_xo_buffer_write(struct pm8058_chip *chip,
+static int pm8058_xo_buffer_write(struct pm8058_xo_buffer *xo,
u16 addr, u8 val, u8 mask, u8 *reg_save)
{
u8 reg;
@@ -63,10 +65,10 @@
reg = (*reg_save & ~mask) | (val & mask);
if (reg != *reg_save)
- rc = pm8058_write(chip, addr, ®, 1);
+ rc = pm8xxx_writeb(xo->dev->parent, addr, reg);
if (rc)
- pr_err("FAIL: pm8058_write: rc=%d\n", rc);
+ pr_err("FAIL: pm8xxx_write: rc=%d\n", rc);
else
*reg_save = reg;
return rc;
@@ -75,10 +77,9 @@
static int pm8058_xo_buffer_enable(struct regulator_dev *dev)
{
struct pm8058_xo_buffer *xo = rdev_get_drvdata(dev);
- struct pm8058_chip *chip = dev_get_drvdata(dev->dev.parent);
int rc;
- rc = pm8058_xo_buffer_write(chip, xo->ctrl_addr, XO_ENABLE,
+ rc = pm8058_xo_buffer_write(xo, xo->ctrl_addr, XO_ENABLE,
XO_ENABLE_MASK, &xo->ctrl_reg);
if (rc)
pr_err("FAIL: pm8058_xo_buffer_write: rc=%d\n", rc);
@@ -99,10 +100,9 @@
static int pm8058_xo_buffer_disable(struct regulator_dev *dev)
{
struct pm8058_xo_buffer *xo = rdev_get_drvdata(dev);
- struct pm8058_chip *chip = dev_get_drvdata(dev->dev.parent);
int rc;
- rc = pm8058_xo_buffer_write(chip, xo->ctrl_addr, XO_DISABLE,
+ rc = pm8058_xo_buffer_write(xo, xo->ctrl_addr, XO_DISABLE,
XO_ENABLE_MASK, &xo->ctrl_reg);
if (rc)
pr_err("FAIL: pm8058_xo_buffer_write: rc=%d\n", rc);
@@ -130,23 +130,21 @@
VREG_DESCRIP(PM8058_XO_ID_A1, "8058_xo_a1", &pm8058_xo_ops),
};
-static int pm8058_init_xo_buffer(struct pm8058_chip *chip,
- struct pm8058_xo_buffer *xo)
+static int pm8058_init_xo_buffer(struct pm8058_xo_buffer *xo)
{
int rc;
/* Save the current control register state */
- rc = pm8058_read(chip, xo->ctrl_addr, &xo->ctrl_reg, 1);
+ rc = pm8xxx_readb(xo->dev->parent, xo->ctrl_addr, &xo->ctrl_reg);
if (rc)
- pr_err("FAIL: pm8058_read: rc=%d\n", rc);
+ pr_err("FAIL: pm8xxx_read: rc=%d\n", rc);
return rc;
}
static int __devinit pm8058_xo_buffer_probe(struct platform_device *pdev)
{
struct regulator_desc *rdesc;
- struct pm8058_chip *chip;
struct pm8058_xo_buffer *xo;
int rc = 0;
@@ -154,16 +152,15 @@
return -EINVAL;
if (pdev->id >= 0 && pdev->id < PM8058_XO_ID_MAX) {
- chip = dev_get_drvdata(pdev->dev.parent);
rdesc = &pm8058_xo_buffer_desc[pdev->id];
xo = &pm8058_xo_buffer[pdev->id];
xo->pdata = pdev->dev.platform_data;
+ xo->dev = &pdev->dev;
- rc = pm8058_init_xo_buffer(chip, xo);
+ rc = pm8058_init_xo_buffer(xo);
if (rc)
goto bail;
- platform_set_drvdata(pdev, chip);
xo->rdev = regulator_register(rdesc, &pdev->dev,
&xo->pdata->init_data, xo);
if (IS_ERR(xo->rdev)) {
diff --git a/drivers/regulator/pm8921-regulator.c b/drivers/regulator/pm8921-regulator.c
index 7e2ac6b..69a1318 100644
--- a/drivers/regulator/pm8921-regulator.c
+++ b/drivers/regulator/pm8921-regulator.c
@@ -85,9 +85,9 @@
#define LDO_CTRL_VPROG_MASK 0x1F
/* TEST register bank 0 */
-#define LDO_TEST_LPM_MASK 0x40
+#define LDO_TEST_LPM_MASK 0x04
#define LDO_TEST_LPM_SEL_CTRL 0x00
-#define LDO_TEST_LPM_SEL_TCXO 0x40
+#define LDO_TEST_LPM_SEL_TCXO 0x04
/* TEST register bank 2 */
#define LDO_TEST_VPROG_UPDATE_MASK 0x08
diff --git a/drivers/regulator/pmic8058-regulator.c b/drivers/regulator/pmic8058-regulator.c
index c11f32b..e137b0f 100644
--- a/drivers/regulator/pmic8058-regulator.c
+++ b/drivers/regulator/pmic8058-regulator.c
@@ -18,6 +18,7 @@
#include <linux/mfd/pmic8058.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
+#include <linux/mfd/pm8xxx/core.h>
#include <linux/regulator/pmic8058-regulator.h>
/* Regulator types */
@@ -205,6 +206,7 @@
};
struct pm8058_vreg {
+ struct device *dev;
struct pm8058_vreg_pdata *pdata;
struct regulator_dev *rdev;
struct pm8058_enable *global_enable[GLOBAL_ENABLE_MAX];
@@ -375,11 +377,9 @@
NCP(NCP, 0x090, 0x0EC),
};
-static int pm8058_smps_set_voltage_advanced(struct pm8058_vreg *vreg,
- struct pm8058_chip *chip, int uV,
+static int pm8058_smps_set_voltage_advanced(struct pm8058_vreg *vreg, int uV,
int force_on);
-static int pm8058_smps_set_voltage_legacy(struct pm8058_vreg *vreg,
- struct pm8058_chip *chip, int uV);
+static int pm8058_smps_set_voltage_legacy(struct pm8058_vreg *vreg, int uV);
static int _pm8058_vreg_is_enabled(struct pm8058_vreg *vreg);
static unsigned int pm8058_vreg_get_mode(struct regulator_dev *dev);
@@ -387,7 +387,7 @@
static void print_write_error(struct pm8058_vreg *vreg, int rc,
const char *func);
-static int pm8058_vreg_write(struct pm8058_chip *chip,
+static int pm8058_vreg_write(struct pm8058_vreg *vreg,
u16 addr, u8 val, u8 mask, u8 *reg_save)
{
int rc = 0;
@@ -395,9 +395,9 @@
reg = (*reg_save & ~mask) | (val & mask);
if (reg != *reg_save)
- rc = pm8058_write(chip, addr, ®, 1);
+ rc = pm8xxx_writeb(vreg->dev->parent, addr, reg);
if (rc)
- pr_err("%s: pm8058_write failed, rc=%d\n", __func__, rc);
+ pr_err("%s: pm8xxx_write failed, rc=%d\n", __func__, rc);
else
*reg_save = reg;
return rc;
@@ -416,14 +416,13 @@
}
-static int pm8058_vreg_set_global_enable(struct pm8058_vreg *vreg,
- struct pm8058_chip *chip, int on)
+static int pm8058_vreg_set_global_enable(struct pm8058_vreg *vreg, int on)
{
int rc = 0, i;
for (i = 0;
(i < GLOBAL_ENABLE_MAX) && !rc && vreg->global_enable[i]; i++)
- rc = pm8058_vreg_write(chip, vreg->global_enable[i]->addr,
+ rc = pm8058_vreg_write(vreg, vreg->global_enable[i]->addr,
(on ? vreg->global_enable_mask[i] : 0),
vreg->global_enable_mask[i],
&vreg->global_enable[i]->reg);
@@ -452,8 +451,7 @@
return ret;
}
-static int pm8058_vreg_set_pin_ctrl(struct pm8058_vreg *vreg,
- struct pm8058_chip *chip, int on)
+static int pm8058_vreg_set_pin_ctrl(struct pm8058_vreg *vreg, int on)
{
int rc = 0, bank;
u8 val = 0, mask;
@@ -473,7 +471,7 @@
val |= LDO_TEST_PIN_CTRL_EN3;
bank = (pf == PM8058_VREG_PIN_FN_ENABLE ? 5 : 6);
- rc = pm8058_vreg_write(chip, vreg->test_addr,
+ rc = pm8058_vreg_write(vreg, vreg->test_addr,
val | REGULATOR_BANK_SEL(bank)
| REGULATOR_BANK_WRITE,
LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
@@ -484,26 +482,25 @@
val = LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
| REGULATOR_BANK_SEL(0);
mask = LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK;
- rc = pm8058_vreg_write(chip, vreg->test_addr, val, mask,
+ rc = pm8058_vreg_write(vreg, vreg->test_addr, val, mask,
&vreg->test_reg[0]);
if (rc)
goto bail;
if (pf == PM8058_VREG_PIN_FN_ENABLE) {
/* Pin control ON/OFF */
- rc = pm8058_vreg_write(chip, vreg->ctrl_addr,
+ rc = pm8058_vreg_write(vreg, vreg->ctrl_addr,
LDO_CTRL_PM_HPM,
LDO_ENABLE_MASK | LDO_CTRL_PM_MASK,
&vreg->ctrl_reg);
if (rc)
goto bail;
- rc = pm8058_vreg_set_global_enable(vreg, chip,
- 0);
+ rc = pm8058_vreg_set_global_enable(vreg, 0);
if (rc)
goto bail;
} else {
/* Pin control LPM/HPM */
- rc = pm8058_vreg_write(chip, vreg->ctrl_addr,
+ rc = pm8058_vreg_write(vreg, vreg->ctrl_addr,
LDO_ENABLE | LDO_CTRL_PM_LPM,
LDO_ENABLE_MASK | LDO_CTRL_PM_MASK,
&vreg->ctrl_reg);
@@ -512,14 +509,14 @@
}
} else {
/* Pin control off */
- rc = pm8058_vreg_write(chip, vreg->test_addr,
+ rc = pm8058_vreg_write(vreg, vreg->test_addr,
REGULATOR_BANK_SEL(5) | REGULATOR_BANK_WRITE,
LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
&vreg->test_reg[5]);
if (rc)
goto bail;
- rc = pm8058_vreg_write(chip, vreg->test_addr,
+ rc = pm8058_vreg_write(vreg, vreg->test_addr,
REGULATOR_BANK_SEL(6) | REGULATOR_BANK_WRITE,
LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
&vreg->test_reg[6]);
@@ -551,29 +548,29 @@
if (pc & PM8058_VREG_PIN_CTRL_A1)
val |= SMPS_PIN_CTRL_LPM_A1;
}
- rc = pm8058_vreg_set_global_enable(vreg, chip, 0);
+ rc = pm8058_vreg_set_global_enable(vreg, 0);
if (rc)
goto bail;
- rc = pm8058_smps_set_voltage_legacy(vreg, chip,
+ rc = pm8058_smps_set_voltage_legacy(vreg,
vreg->save_uV);
if (rc)
goto bail;
- rc = pm8058_vreg_write(chip, vreg->sleep_ctrl_addr, val,
+ rc = pm8058_vreg_write(vreg, vreg->sleep_ctrl_addr, val,
SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK,
&vreg->sleep_ctrl_reg);
if (rc)
goto bail;
- rc = pm8058_vreg_write(chip, vreg->ctrl_addr,
+ rc = pm8058_vreg_write(vreg, vreg->ctrl_addr,
(pf == PM8058_VREG_PIN_FN_ENABLE
? 0 : SMPS_LEGACY_ENABLE),
SMPS_LEGACY_ENABLE, &vreg->ctrl_reg);
if (rc)
goto bail;
- rc = pm8058_vreg_write(chip, vreg->clk_ctrl_addr,
+ rc = pm8058_vreg_write(vreg, vreg->clk_ctrl_addr,
(pf == PM8058_VREG_PIN_FN_ENABLE
? SMPS_CLK_CTRL_PWM : SMPS_CLK_CTRL_PFM),
SMPS_CLK_CTRL_MASK, &vreg->clk_ctrl_reg);
@@ -584,20 +581,20 @@
if (!SMPS_IN_ADVANCED_MODE(vreg)) {
if (_pm8058_vreg_is_enabled(vreg))
val = SMPS_LEGACY_ENABLE;
- rc = pm8058_vreg_write(chip, vreg->ctrl_addr,
+ rc = pm8058_vreg_write(vreg, vreg->ctrl_addr,
val, SMPS_LEGACY_ENABLE,
&vreg->ctrl_reg);
if (rc)
goto bail;
}
- rc = pm8058_vreg_write(chip, vreg->sleep_ctrl_addr, 0,
+ rc = pm8058_vreg_write(vreg, vreg->sleep_ctrl_addr, 0,
SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK,
&vreg->sleep_ctrl_reg);
if (rc)
goto bail;
- rc = pm8058_smps_set_voltage_advanced(vreg, chip,
+ rc = pm8058_smps_set_voltage_advanced(vreg,
vreg->save_uV, 0);
if (rc)
goto bail;
@@ -615,13 +612,13 @@
if (pc & PM8058_VREG_PIN_CTRL_A1)
val |= LVS_PIN_CTRL_EN3;
- rc = pm8058_vreg_write(chip, vreg->ctrl_addr, val,
+ rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, val,
LVS_PIN_CTRL_MASK | LVS_ENABLE_MASK,
&vreg->ctrl_reg);
if (rc)
goto bail;
- rc = pm8058_vreg_set_global_enable(vreg, chip, 0);
+ rc = pm8058_vreg_set_global_enable(vreg, 0);
if (rc)
goto bail;
} else {
@@ -629,7 +626,7 @@
if (_pm8058_vreg_is_enabled(vreg))
val = LVS_ENABLE;
- rc = pm8058_vreg_write(chip, vreg->ctrl_addr, val,
+ rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, val,
LVS_ENABLE_MASK | LVS_PIN_CTRL_MASK,
&vreg->ctrl_reg);
if (rc)
@@ -649,7 +646,6 @@
static int pm8058_vreg_enable(struct regulator_dev *dev)
{
struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
- struct pm8058_chip *chip = dev_get_drvdata(dev->dev.parent);
int mode;
int rc = 0;
@@ -657,16 +653,15 @@
if (mode == REGULATOR_MODE_IDLE) {
/* Turn on pin control. */
- rc = pm8058_vreg_set_pin_ctrl(vreg, chip, 1);
+ rc = pm8058_vreg_set_pin_ctrl(vreg, 1);
if (rc)
goto bail;
return rc;
}
if (vreg->type == REGULATOR_TYPE_SMPS && SMPS_IN_ADVANCED_MODE(vreg))
- rc = pm8058_smps_set_voltage_advanced(vreg, chip,
- vreg->save_uV, 1);
+ rc = pm8058_smps_set_voltage_advanced(vreg, vreg->save_uV, 1);
else
- rc = pm8058_vreg_write(chip, vreg->ctrl_addr, REGULATOR_EN_MASK,
+ rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, REGULATOR_EN_MASK,
REGULATOR_EN_MASK, &vreg->ctrl_reg);
bail:
if (rc)
@@ -706,26 +701,25 @@
static int pm8058_vreg_disable(struct regulator_dev *dev)
{
struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
- struct pm8058_chip *chip = dev_get_drvdata(dev->dev.parent);
int rc = 0;
/* Disable in global control register. */
- rc = pm8058_vreg_set_global_enable(vreg, chip, 0);
+ rc = pm8058_vreg_set_global_enable(vreg, 0);
if (rc)
goto bail;
/* Turn off pin control. */
- rc = pm8058_vreg_set_pin_ctrl(vreg, chip, 0);
+ rc = pm8058_vreg_set_pin_ctrl(vreg, 0);
if (rc)
goto bail;
/* Disable in local control register. */
if (vreg->type == REGULATOR_TYPE_SMPS && SMPS_IN_ADVANCED_MODE(vreg))
- rc = pm8058_vreg_write(chip, vreg->ctrl_addr,
+ rc = pm8058_vreg_write(vreg, vreg->ctrl_addr,
SMPS_ADVANCED_BAND_OFF, SMPS_ADVANCED_BAND_MASK,
&vreg->ctrl_reg);
else
- rc = pm8058_vreg_write(chip, vreg->ctrl_addr, 0,
+ rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, 0,
REGULATOR_EN_MASK, &vreg->ctrl_reg);
bail:
@@ -735,8 +729,7 @@
return rc;
}
-static int pm8058_pldo_set_voltage(struct pm8058_chip *chip,
- struct pm8058_vreg *vreg, int uV)
+static int pm8058_pldo_set_voltage(struct pm8058_vreg *vreg, int uV)
{
int vmin, rc = 0;
unsigned vprog, fine_step;
@@ -775,7 +768,7 @@
|| ((range_sel ^ vreg->test_reg[2]) & LDO_TEST_RANGE_SEL_MASK)
|| ((fine_step_reg ^ vreg->test_reg[2])
& LDO_TEST_FINE_STEP_MASK))) {
- rc = pm8058_vreg_write(chip, vreg->test_addr,
+ rc = pm8058_vreg_write(vreg, vreg->test_addr,
REGULATOR_BANK_SEL(2) | REGULATOR_BANK_WRITE,
REGULATOR_BANK_MASK | LDO_TEST_VPROG_UPDATE_MASK,
&vreg->test_reg[2]);
@@ -784,13 +777,13 @@
}
/* Write new voltage. */
- rc = pm8058_vreg_write(chip, vreg->ctrl_addr, vprog,
+ rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, vprog,
LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
if (rc)
goto bail;
/* Write range extension. */
- rc = pm8058_vreg_write(chip, vreg->test_addr,
+ rc = pm8058_vreg_write(vreg, vreg->test_addr,
range_ext | REGULATOR_BANK_SEL(4)
| REGULATOR_BANK_WRITE,
LDO_TEST_RANGE_EXT_MASK | REGULATOR_BANK_MASK,
@@ -799,7 +792,7 @@
goto bail;
/* Write fine step, range select and program voltage update. */
- rc = pm8058_vreg_write(chip, vreg->test_addr,
+ rc = pm8058_vreg_write(vreg, vreg->test_addr,
fine_step_reg | range_sel | REGULATOR_BANK_SEL(2)
| REGULATOR_BANK_WRITE | LDO_TEST_VPROG_UPDATE_MASK,
LDO_TEST_FINE_STEP_MASK | LDO_TEST_RANGE_SEL_MASK
@@ -812,8 +805,7 @@
return rc;
}
-static int pm8058_nldo_set_voltage(struct pm8058_chip *chip,
- struct pm8058_vreg *vreg, int uV)
+static int pm8058_nldo_set_voltage(struct pm8058_vreg *vreg, int uV)
{
unsigned vprog, fine_step_reg;
int rc;
@@ -826,13 +818,13 @@
vprog >>= 1;
/* Write new voltage. */
- rc = pm8058_vreg_write(chip, vreg->ctrl_addr, vprog,
+ rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, vprog,
LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
if (rc)
goto bail;
/* Write fine step. */
- rc = pm8058_vreg_write(chip, vreg->test_addr,
+ rc = pm8058_vreg_write(vreg, vreg->test_addr,
fine_step_reg | REGULATOR_BANK_SEL(2)
| REGULATOR_BANK_WRITE | LDO_TEST_VPROG_UPDATE_MASK,
LDO_TEST_FINE_STEP_MASK | REGULATOR_BANK_MASK
@@ -849,12 +841,11 @@
int min_uV, int max_uV, unsigned *selector)
{
struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
- struct pm8058_chip *chip = dev_get_drvdata(dev->dev.parent);
if (vreg->is_nmos)
- return pm8058_nldo_set_voltage(chip, vreg, min_uV);
+ return pm8058_nldo_set_voltage(vreg, min_uV);
else
- return pm8058_pldo_set_voltage(chip, vreg, min_uV);
+ return pm8058_pldo_set_voltage(vreg, min_uV);
}
static int pm8058_pldo_get_voltage(struct pm8058_vreg *vreg)
@@ -967,8 +958,7 @@
}
static int pm8058_smps_set_voltage_advanced(struct pm8058_vreg *vreg,
- struct pm8058_chip *chip, int uV,
- int force_on)
+ int uV, int force_on)
{
u8 vprog, band;
int rc, new_uV;
@@ -992,7 +982,7 @@
band = SMPS_ADVANCED_BAND_OFF;
/* Set advanced mode bit to 1. */
- rc = pm8058_vreg_write(chip, vreg->test_addr, SMPS_ADVANCED_MODE
+ rc = pm8058_vreg_write(vreg, vreg->test_addr, SMPS_ADVANCED_MODE
| REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(7),
SMPS_ADVANCED_MODE_MASK | REGULATOR_BANK_MASK,
&vreg->test_reg[7]);
@@ -1000,7 +990,7 @@
goto bail;
/* Set voltage and voltage band. */
- rc = pm8058_vreg_write(chip, vreg->ctrl_addr, band | vprog,
+ rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, band | vprog,
SMPS_ADVANCED_BAND_MASK | SMPS_ADVANCED_VPROG_MASK,
&vreg->ctrl_reg);
if (rc)
@@ -1012,8 +1002,7 @@
return rc;
}
-static int pm8058_smps_set_voltage_legacy(struct pm8058_vreg *vreg,
- struct pm8058_chip *chip, int uV)
+static int pm8058_smps_set_voltage_legacy(struct pm8058_vreg *vreg, int uV)
{
u8 vlow, vref, vprog, pd, en;
int rc;
@@ -1033,7 +1022,7 @@
}
/* set vlow bit for ultra low voltage mode */
- rc = pm8058_vreg_write(chip, vreg->test_addr,
+ rc = pm8058_vreg_write(vreg, vreg->test_addr,
vlow | REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(1),
REGULATOR_BANK_MASK | SMPS_LEGACY_VLOW_SEL_MASK,
&vreg->test_reg[1]);
@@ -1041,7 +1030,7 @@
goto bail;
/* Set advanced mode bit to 0. */
- rc = pm8058_vreg_write(chip, vreg->test_addr, SMPS_LEGACY_MODE
+ rc = pm8058_vreg_write(vreg, vreg->test_addr, SMPS_LEGACY_MODE
| REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(7),
SMPS_ADVANCED_MODE_MASK | REGULATOR_BANK_MASK,
&vreg->test_reg[7]);
@@ -1052,7 +1041,7 @@
pd = (vreg->pdata->pull_down_enable ? SMPS_LEGACY_PULL_DOWN_ENABLE : 0);
/* Set voltage (and the rest of the control register). */
- rc = pm8058_vreg_write(chip, vreg->ctrl_addr, en | pd | vref | vprog,
+ rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, en | pd | vref | vprog,
SMPS_LEGACY_ENABLE | SMPS_LEGACY_PULL_DOWN_ENABLE
| SMPS_LEGACY_VREF_SEL_MASK | SMPS_LEGACY_VPROG_MASK,
&vreg->ctrl_reg);
@@ -1067,16 +1056,15 @@
int min_uV, int max_uV, unsigned *selector)
{
struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
- struct pm8058_chip *chip = dev_get_drvdata(dev->dev.parent);
int rc = 0;
if (min_uV < SMPS_UV_MIN || min_uV > SMPS_UV_MAX)
return -EINVAL;
if (SMPS_IN_ADVANCED_MODE(vreg))
- rc = pm8058_smps_set_voltage_advanced(vreg, chip, min_uV, 0);
+ rc = pm8058_smps_set_voltage_advanced(vreg, min_uV, 0);
else
- rc = pm8058_smps_set_voltage_legacy(vreg, chip, min_uV);
+ rc = pm8058_smps_set_voltage_legacy(vreg, min_uV);
if (rc)
print_write_error(vreg, rc, __func__);
@@ -1088,7 +1076,6 @@
int min_uV, int max_uV, unsigned *selector)
{
struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
- struct pm8058_chip *chip = dev_get_drvdata(dev->dev.parent);
int rc;
u8 val;
@@ -1098,7 +1085,7 @@
val = (min_uV - NCP_UV_MIN) / NCP_UV_STEP;
/* voltage setting */
- rc = pm8058_vreg_write(chip, vreg->ctrl_addr, val, NCP_VPROG_MASK,
+ rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, val, NCP_VPROG_MASK,
&vreg->ctrl_reg);
if (rc)
print_write_error(vreg, rc, __func__);
@@ -1113,8 +1100,7 @@
return NCP_UV_MIN + vprog * NCP_UV_STEP;
}
-static int pm8058_ldo_set_mode(struct pm8058_vreg *vreg,
- struct pm8058_chip *chip, unsigned int mode)
+static int pm8058_ldo_set_mode(struct pm8058_vreg *vreg, unsigned int mode)
{
int rc = 0;
u8 mask, val;
@@ -1125,13 +1111,13 @@
val = (_pm8058_vreg_is_enabled(vreg) ? LDO_ENABLE : 0)
| LDO_CTRL_PM_HPM;
mask = LDO_ENABLE_MASK | LDO_CTRL_PM_MASK;
- rc = pm8058_vreg_write(chip, vreg->ctrl_addr, val, mask,
+ rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, val, mask,
&vreg->ctrl_reg);
if (rc)
goto bail;
if (pm8058_vreg_using_pin_ctrl(vreg))
- rc = pm8058_vreg_set_pin_ctrl(vreg, chip, 0);
+ rc = pm8058_vreg_set_pin_ctrl(vreg, 0);
if (rc)
goto bail;
break;
@@ -1141,7 +1127,7 @@
val = (_pm8058_vreg_is_enabled(vreg) ? LDO_ENABLE : 0)
| LDO_CTRL_PM_LPM;
mask = LDO_ENABLE_MASK | LDO_CTRL_PM_MASK;
- rc = pm8058_vreg_write(chip, vreg->ctrl_addr, val, mask,
+ rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, val, mask,
&vreg->ctrl_reg);
if (rc)
goto bail;
@@ -1149,13 +1135,13 @@
val = LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
| REGULATOR_BANK_SEL(0);
mask = LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK;
- rc = pm8058_vreg_write(chip, vreg->test_addr, val, mask,
+ rc = pm8058_vreg_write(vreg, vreg->test_addr, val, mask,
&vreg->test_reg[0]);
if (rc)
goto bail;
if (pm8058_vreg_using_pin_ctrl(vreg))
- rc = pm8058_vreg_set_pin_ctrl(vreg, chip, 0);
+ rc = pm8058_vreg_set_pin_ctrl(vreg, 0);
if (rc)
goto bail;
break;
@@ -1163,7 +1149,7 @@
case REGULATOR_MODE_IDLE:
/* Pin Control */
if (_pm8058_vreg_is_enabled(vreg))
- rc = pm8058_vreg_set_pin_ctrl(vreg, chip, 1);
+ rc = pm8058_vreg_set_pin_ctrl(vreg, 1);
if (rc)
goto bail;
break;
@@ -1180,8 +1166,7 @@
return rc;
}
-static int pm8058_smps_set_mode(struct pm8058_vreg *vreg,
- struct pm8058_chip *chip, unsigned int mode)
+static int pm8058_smps_set_mode(struct pm8058_vreg *vreg, unsigned int mode)
{
int rc = 0;
u8 mask, val;
@@ -1191,13 +1176,13 @@
/* HPM */
val = SMPS_CLK_CTRL_PWM;
mask = SMPS_CLK_CTRL_MASK;
- rc = pm8058_vreg_write(chip, vreg->clk_ctrl_addr, val, mask,
+ rc = pm8058_vreg_write(vreg, vreg->clk_ctrl_addr, val, mask,
&vreg->clk_ctrl_reg);
if (rc)
goto bail;
if (pm8058_vreg_using_pin_ctrl(vreg))
- rc = pm8058_vreg_set_pin_ctrl(vreg, chip, 0);
+ rc = pm8058_vreg_set_pin_ctrl(vreg, 0);
if (rc)
goto bail;
break;
@@ -1206,13 +1191,13 @@
/* LPM */
val = SMPS_CLK_CTRL_PFM;
mask = SMPS_CLK_CTRL_MASK;
- rc = pm8058_vreg_write(chip, vreg->clk_ctrl_addr, val, mask,
+ rc = pm8058_vreg_write(vreg, vreg->clk_ctrl_addr, val, mask,
&vreg->clk_ctrl_reg);
if (rc)
goto bail;
if (pm8058_vreg_using_pin_ctrl(vreg))
- rc = pm8058_vreg_set_pin_ctrl(vreg, chip, 0);
+ rc = pm8058_vreg_set_pin_ctrl(vreg, 0);
if (rc)
goto bail;
break;
@@ -1220,7 +1205,7 @@
case REGULATOR_MODE_IDLE:
/* Pin Control */
if (_pm8058_vreg_is_enabled(vreg))
- rc = pm8058_vreg_set_pin_ctrl(vreg, chip, 1);
+ rc = pm8058_vreg_set_pin_ctrl(vreg, 1);
if (rc)
goto bail;
break;
@@ -1237,18 +1222,17 @@
return rc;
}
-static int pm8058_lvs_set_mode(struct pm8058_vreg *vreg,
- struct pm8058_chip *chip, unsigned int mode)
+static int pm8058_lvs_set_mode(struct pm8058_vreg *vreg, unsigned int mode)
{
int rc = 0;
if (mode == REGULATOR_MODE_IDLE) {
/* Use pin control. */
if (_pm8058_vreg_is_enabled(vreg))
- rc = pm8058_vreg_set_pin_ctrl(vreg, chip, 1);
+ rc = pm8058_vreg_set_pin_ctrl(vreg, 1);
} else {
/* Turn off pin control. */
- rc = pm8058_vreg_set_pin_ctrl(vreg, chip, 0);
+ rc = pm8058_vreg_set_pin_ctrl(vreg, 0);
}
return rc;
@@ -1268,7 +1252,6 @@
static int pm8058_vreg_set_mode(struct regulator_dev *dev, unsigned int mode)
{
struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
- struct pm8058_chip *chip = dev_get_drvdata(dev->dev.parent);
unsigned prev_optimum = vreg->optimum;
unsigned prev_pc_vote = vreg->pc_vote;
unsigned prev_mode_initialized = vreg->mode_initialized;
@@ -1320,13 +1303,13 @@
switch (vreg->type) {
case REGULATOR_TYPE_LDO:
- rc = pm8058_ldo_set_mode(vreg, chip, new_mode);
+ rc = pm8058_ldo_set_mode(vreg, new_mode);
break;
case REGULATOR_TYPE_SMPS:
- rc = pm8058_smps_set_mode(vreg, chip, new_mode);
+ rc = pm8058_smps_set_mode(vreg, new_mode);
break;
case REGULATOR_TYPE_LVS:
- rc = pm8058_lvs_set_mode(vreg, chip, new_mode);
+ rc = pm8058_lvs_set_mode(vreg, new_mode);
break;
}
@@ -1499,24 +1482,25 @@
VREG_DESCRIP(PM8058_VREG_ID_NCP, "8058_ncp", &pm8058_ncp_ops),
};
-static int pm8058_master_enable_init(struct pm8058_chip *chip)
+static int pm8058_master_enable_init(struct pm8058_vreg *vreg)
{
int rc = 0, i;
for (i = 0; i < MASTER_ENABLE_COUNT; i++) {
- rc = pm8058_read(chip, m_en[i].addr, &(m_en[i].reg), 1);
+ rc = pm8xxx_readb(vreg->dev->parent, m_en[i].addr,
+ &(m_en[i].reg));
if (rc)
goto bail;
}
bail:
if (rc)
- pr_err("%s: pm8058_read failed, rc=%d\n", __func__, rc);
+ pr_err("%s: pm8xxx_read failed, rc=%d\n", __func__, rc);
return rc;
}
-static int pm8058_init_ldo(struct pm8058_chip *chip, struct pm8058_vreg *vreg)
+static int pm8058_init_ldo(struct pm8058_vreg *vreg)
{
int rc = 0, i;
u8 bank;
@@ -1524,11 +1508,12 @@
/* Save the current test register state. */
for (i = 0; i < LDO_TEST_BANKS; i++) {
bank = REGULATOR_BANK_SEL(i);
- rc = pm8058_write(chip, vreg->test_addr, &bank, 1);
+ rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
if (rc)
goto bail;
- rc = pm8058_read(chip, vreg->test_addr, &vreg->test_reg[i], 1);
+ rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
+ &vreg->test_reg[i]);
if (rc)
goto bail;
vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
@@ -1540,14 +1525,14 @@
vreg->optimum = REGULATOR_MODE_FAST;
/* Set pull down enable based on platform data. */
- rc = pm8058_vreg_write(chip, vreg->ctrl_addr,
+ rc = pm8058_vreg_write(vreg, vreg->ctrl_addr,
(vreg->pdata->pull_down_enable ? LDO_PULL_DOWN_ENABLE : 0),
LDO_PULL_DOWN_ENABLE_MASK, &vreg->ctrl_reg);
bail:
return rc;
}
-static int pm8058_init_smps(struct pm8058_chip *chip, struct pm8058_vreg *vreg)
+static int pm8058_init_smps(struct pm8058_vreg *vreg)
{
int rc = 0, i;
u8 bank;
@@ -1555,24 +1540,26 @@
/* Save the current test2 register state. */
for (i = 0; i < SMPS_TEST_BANKS; i++) {
bank = REGULATOR_BANK_SEL(i);
- rc = pm8058_write(chip, vreg->test_addr, &bank, 1);
+ rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
if (rc)
goto bail;
- rc = pm8058_read(chip, vreg->test_addr, &vreg->test_reg[i],
- 1);
+ rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
+ &vreg->test_reg[i]);
if (rc)
goto bail;
vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
}
/* Save the current clock control register state. */
- rc = pm8058_read(chip, vreg->clk_ctrl_addr, &vreg->clk_ctrl_reg, 1);
+ rc = pm8xxx_readb(vreg->dev->parent, vreg->clk_ctrl_addr,
+ &vreg->clk_ctrl_reg);
if (rc)
goto bail;
/* Save the current sleep control register state. */
- rc = pm8058_read(chip, vreg->sleep_ctrl_addr, &vreg->sleep_ctrl_reg, 1);
+ rc = pm8xxx_readb(vreg->dev->parent, vreg->sleep_ctrl_addr,
+ &vreg->sleep_ctrl_reg);
if (rc)
goto bail;
@@ -1585,7 +1572,7 @@
vreg->optimum = REGULATOR_MODE_FAST;
/* Set advanced mode pull down enable based on platform data. */
- rc = pm8058_vreg_write(chip, vreg->test_addr,
+ rc = pm8058_vreg_write(vreg, vreg->test_addr,
(vreg->pdata->pull_down_enable
? SMPS_ADVANCED_PULL_DOWN_ENABLE : 0)
| REGULATOR_BANK_SEL(6) | REGULATOR_BANK_WRITE,
@@ -1596,7 +1583,7 @@
if (!SMPS_IN_ADVANCED_MODE(vreg)) {
/* Set legacy mode pull down enable based on platform data. */
- rc = pm8058_vreg_write(chip, vreg->ctrl_addr,
+ rc = pm8058_vreg_write(vreg, vreg->ctrl_addr,
(vreg->pdata->pull_down_enable
? SMPS_LEGACY_PULL_DOWN_ENABLE : 0),
SMPS_LEGACY_PULL_DOWN_ENABLE, &vreg->ctrl_reg);
@@ -1608,26 +1595,27 @@
return rc;
}
-static int pm8058_init_lvs(struct pm8058_chip *chip, struct pm8058_vreg *vreg)
+static int pm8058_init_lvs(struct pm8058_vreg *vreg)
{
int rc = 0;
vreg->optimum = REGULATOR_MODE_FAST;
/* Set pull down enable based on platform data. */
- rc = pm8058_vreg_write(chip, vreg->ctrl_addr,
+ rc = pm8058_vreg_write(vreg, vreg->ctrl_addr,
(vreg->pdata->pull_down_enable
? LVS_PULL_DOWN_ENABLE : LVS_PULL_DOWN_DISABLE),
LVS_PULL_DOWN_ENABLE_MASK, &vreg->ctrl_reg);
return rc;
}
-static int pm8058_init_ncp(struct pm8058_chip *chip, struct pm8058_vreg *vreg)
+static int pm8058_init_ncp(struct pm8058_vreg *vreg)
{
int rc = 0;
/* Save the current test1 register state. */
- rc = pm8058_read(chip, vreg->test_addr, &vreg->test_reg[0], 1);
+ rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
+ &vreg->test_reg[0]);
if (rc)
goto bail;
@@ -1637,8 +1625,7 @@
return rc;
}
-static int pm8058_init_regulator(struct pm8058_chip *chip,
- struct pm8058_vreg *vreg)
+static int pm8058_init_regulator(struct pm8058_vreg *vreg)
{
static int master_enable_inited;
int rc = 0;
@@ -1646,28 +1633,28 @@
vreg->mode_initialized = 0;
if (!master_enable_inited) {
- rc = pm8058_master_enable_init(chip);
+ rc = pm8058_master_enable_init(vreg);
if (!rc)
master_enable_inited = 1;
}
/* save the current control register state */
- rc = pm8058_read(chip, vreg->ctrl_addr, &vreg->ctrl_reg, 1);
+ rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
if (rc)
goto bail;
switch (vreg->type) {
case REGULATOR_TYPE_LDO:
- rc = pm8058_init_ldo(chip, vreg);
+ rc = pm8058_init_ldo(vreg);
break;
case REGULATOR_TYPE_SMPS:
- rc = pm8058_init_smps(chip, vreg);
+ rc = pm8058_init_smps(vreg);
break;
case REGULATOR_TYPE_LVS:
- rc = pm8058_init_lvs(chip, vreg);
+ rc = pm8058_init_lvs(vreg);
break;
case REGULATOR_TYPE_NCP:
- rc = pm8058_init_ncp(chip, vreg);
+ rc = pm8058_init_ncp(vreg);
break;
}
@@ -1681,7 +1668,6 @@
static int __devinit pm8058_vreg_probe(struct platform_device *pdev)
{
struct regulator_desc *rdesc;
- struct pm8058_chip *chip;
struct pm8058_vreg *vreg;
const char *reg_name = NULL;
int rc = 0;
@@ -1690,13 +1676,13 @@
return -EINVAL;
if (pdev->id >= 0 && pdev->id < PM8058_VREG_MAX) {
- chip = dev_get_drvdata(pdev->dev.parent);
rdesc = &pm8058_vreg_descrip[pdev->id];
vreg = &pm8058_vreg[pdev->id];
vreg->pdata = pdev->dev.platform_data;
reg_name = pm8058_vreg_descrip[pdev->id].name;
+ vreg->dev = &pdev->dev;
- rc = pm8058_init_regulator(chip, vreg);
+ rc = pm8058_init_regulator(vreg);
if (rc)
goto bail;
@@ -1705,7 +1691,6 @@
vreg->pdata->init_data.constraints.valid_modes_mask
&= ~(REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE);
- platform_set_drvdata(pdev, chip);
vreg->rdev = regulator_register(rdesc, &pdev->dev,
&vreg->pdata->init_data, vreg);
if (IS_ERR(vreg->rdev)) {
diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c
index 55dd4e6..425aab3 100644
--- a/drivers/regulator/tps65910-regulator.c
+++ b/drivers/regulator/tps65910-regulator.c
@@ -759,8 +759,13 @@
mult = (selector / VDD1_2_NUM_VOLTS) + 1;
volt = VDD1_2_MIN_VOLT +
(selector % VDD1_2_NUM_VOLTS) * VDD1_2_OFFSET;
+ break;
case TPS65911_REG_VDDCTRL:
volt = VDDCTRL_MIN_VOLT + (selector * VDDCTRL_OFFSET);
+ break;
+ default:
+ BUG();
+ return -EINVAL;
}
return volt * 100 * mult;
@@ -898,9 +903,11 @@
case TPS65910:
pmic->get_ctrl_reg = &tps65910_get_ctrl_register;
info = tps65910_regs;
+ break;
case TPS65911:
pmic->get_ctrl_reg = &tps65911_get_ctrl_register;
info = tps65911_regs;
+ break;
default:
pr_err("Invalid tps chip version\n");
return -ENODEV;
diff --git a/drivers/rtc/alarm.c b/drivers/rtc/alarm.c
index 3e7f698..2583137 100644
--- a/drivers/rtc/alarm.c
+++ b/drivers/rtc/alarm.c
@@ -413,7 +413,7 @@
hrtimer_cancel(&alarms[ANDROID_ALARM_RTC_WAKEUP].timer);
hrtimer_cancel(&alarms[
- ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK].timer);
+ ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].timer);
tmp_queue = &alarms[ANDROID_ALARM_RTC_WAKEUP];
if (tmp_queue->first)
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 4194e59..01a7df5 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -41,20 +41,41 @@
* system's wall clock; restore it on resume().
*/
-static time_t oldtime;
-static struct timespec oldts;
+static struct timespec old_rtc, old_system, old_delta;
+
static int rtc_suspend(struct device *dev, pm_message_t mesg)
{
struct rtc_device *rtc = to_rtc_device(dev);
struct rtc_time tm;
-
+ struct timespec delta, delta_delta;
if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
return 0;
+ /* snapshot the current RTC and system time at suspend*/
rtc_read_time(rtc, &tm);
- ktime_get_ts(&oldts);
- rtc_tm_to_time(&tm, &oldtime);
+ getnstimeofday(&old_system);
+ rtc_tm_to_time(&tm, &old_rtc.tv_sec);
+
+
+ /*
+ * To avoid drift caused by repeated suspend/resumes,
+ * which each can add ~1 second drift error,
+ * try to compensate so the difference in system time
+ * and rtc time stays close to constant.
+ */
+ delta = timespec_sub(old_system, old_rtc);
+ delta_delta = timespec_sub(delta, old_delta);
+ if (abs(delta_delta.tv_sec) >= 2) {
+ /*
+ * if delta_delta is too large, assume time correction
+ * has occured and set old_delta to the current delta.
+ */
+ old_delta = delta;
+ } else {
+ /* Otherwise try to adjust old_system to compensate */
+ old_system = timespec_sub(old_system, delta_delta);
+ }
return 0;
}
@@ -63,32 +84,42 @@
{
struct rtc_device *rtc = to_rtc_device(dev);
struct rtc_time tm;
- time_t newtime;
- struct timespec time;
- struct timespec newts;
+ struct timespec new_system, new_rtc;
+ struct timespec sleep_time;
if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
return 0;
- ktime_get_ts(&newts);
+ /* snapshot the current rtc and system time at resume */
+ getnstimeofday(&new_system);
rtc_read_time(rtc, &tm);
if (rtc_valid_tm(&tm) != 0) {
pr_debug("%s: bogus resume time\n", dev_name(&rtc->dev));
return 0;
}
- rtc_tm_to_time(&tm, &newtime);
- if (newtime <= oldtime) {
- if (newtime < oldtime)
+ rtc_tm_to_time(&tm, &new_rtc.tv_sec);
+ new_rtc.tv_nsec = 0;
+
+ if (new_rtc.tv_sec <= old_rtc.tv_sec) {
+ if (new_rtc.tv_sec < old_rtc.tv_sec)
pr_debug("%s: time travel!\n", dev_name(&rtc->dev));
return 0;
}
- /* calculate the RTC time delta */
- set_normalized_timespec(&time, newtime - oldtime, 0);
- /* subtract kernel time between rtc_suspend to rtc_resume */
- time = timespec_sub(time, timespec_sub(newts, oldts));
+ /* calculate the RTC time delta (sleep time)*/
+ sleep_time = timespec_sub(new_rtc, old_rtc);
- timekeeping_inject_sleeptime(&time);
+ /*
+ * Since these RTC suspend/resume handlers are not called
+ * at the very end of suspend or the start of resume,
+ * some run-time may pass on either sides of the sleep time
+ * so subtract kernel run-time between rtc_suspend to rtc_resume
+ * to keep things accurate.
+ */
+ sleep_time = timespec_sub(sleep_time,
+ timespec_sub(new_system, old_system));
+
+ timekeeping_inject_sleeptime(&sleep_time);
return 0;
}
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 3195dbd..eb4c883 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -708,7 +708,7 @@
int err = 0;
unsigned long flags;
- if (freq <= 0 || freq > 5000)
+ if (freq <= 0 || freq > RTC_MAX_FREQ)
return -EINVAL;
retry:
spin_lock_irqsave(&rtc->irq_task_lock, flags);
diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c
index 5c4e741..68be6e1 100644
--- a/drivers/s390/cio/qdio_thinint.c
+++ b/drivers/s390/cio/qdio_thinint.c
@@ -95,9 +95,11 @@
}
}
-static inline u32 shared_ind_set(void)
+static inline u32 clear_shared_ind(void)
{
- return q_indicators[TIQDIO_SHARED_IND].ind;
+ if (!atomic_read(&q_indicators[TIQDIO_SHARED_IND].count))
+ return 0;
+ return xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 0);
}
/**
@@ -107,7 +109,7 @@
*/
static void tiqdio_thinint_handler(void *alsi, void *data)
{
- u32 si_used = shared_ind_set();
+ u32 si_used = clear_shared_ind();
struct qdio_q *q;
last_ai_time = S390_lowcore.int_clock;
@@ -150,13 +152,6 @@
qperf_inc(q, adapter_int);
}
rcu_read_unlock();
-
- /*
- * If the shared indicator was used clear it now after all queues
- * were processed.
- */
- if (si_used && shared_ind_set())
- xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 0);
}
static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset)
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index b7bd5b0..3868ab2 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -1800,10 +1800,12 @@
switch (retval) {
case SCSI_MLQUEUE_HOST_BUSY:
twa_free_request_id(tw_dev, request_id);
+ twa_unmap_scsi_data(tw_dev, request_id);
break;
case 1:
tw_dev->state[request_id] = TW_S_COMPLETED;
twa_free_request_id(tw_dev, request_id);
+ twa_unmap_scsi_data(tw_dev, request_id);
SCpnt->result = (DID_ERROR << 16);
done(SCpnt);
retval = 0;
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 3c08f53..6153a66 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -88,7 +88,7 @@
obj-$(CONFIG_PCMCIA_QLOGIC) += qlogicfas408.o
obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o
obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx/
-obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx/
+obj-$(CONFIG_SCSI_QLA_ISCSI) += libiscsi.o qla4xxx/
obj-$(CONFIG_SCSI_LPFC) += lpfc/
obj-$(CONFIG_SCSI_BFA_FC) += bfa/
obj-$(CONFIG_SCSI_PAS16) += pas16.o
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index e7d0d47..e5f2d7d 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -1283,6 +1283,8 @@
kfree(aac->queues);
aac->queues = NULL;
free_irq(aac->pdev->irq, aac);
+ if (aac->msi)
+ pci_disable_msi(aac->pdev);
kfree(aac->fsa_dev);
aac->fsa_dev = NULL;
quirks = aac_get_driver_ident(index)->quirks;
diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h
index 0a404bf..856fcbf 100644
--- a/drivers/scsi/bnx2fc/bnx2fc.h
+++ b/drivers/scsi/bnx2fc/bnx2fc.h
@@ -152,7 +152,6 @@
spinlock_t fp_work_lock;
};
-
struct bnx2fc_hba {
struct list_head link;
struct cnic_dev *cnic;
@@ -179,6 +178,7 @@
#define BNX2FC_CTLR_INIT_DONE 1
#define BNX2FC_CREATE_DONE 2
struct fcoe_ctlr ctlr;
+ struct list_head vports;
u8 vlan_enabled;
int vlan_id;
u32 next_conn_id;
@@ -232,6 +232,11 @@
#define bnx2fc_from_ctlr(fip) container_of(fip, struct bnx2fc_hba, ctlr)
+struct bnx2fc_lport {
+ struct list_head list;
+ struct fc_lport *lport;
+};
+
struct bnx2fc_cmd_mgr {
struct bnx2fc_hba *hba;
u16 next_idx;
@@ -423,6 +428,7 @@
struct bnx2fc_unsol_els {
struct fc_lport *lport;
struct fc_frame *fp;
+ struct bnx2fc_hba *hba;
struct work_struct unsol_els_work;
};
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
index ab255fb..bdf62a5 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -1225,6 +1225,7 @@
hba->ctlr.get_src_addr = bnx2fc_get_src_mac;
set_bit(BNX2FC_CTLR_INIT_DONE, &hba->init_done);
+ INIT_LIST_HEAD(&hba->vports);
rc = bnx2fc_netdev_setup(hba);
if (rc)
goto setup_err;
@@ -1261,8 +1262,15 @@
struct fcoe_port *port;
struct Scsi_Host *shost;
struct fc_vport *vport = dev_to_vport(parent);
+ struct bnx2fc_lport *blport;
int rc = 0;
+ blport = kzalloc(sizeof(struct bnx2fc_lport), GFP_KERNEL);
+ if (!blport) {
+ BNX2FC_HBA_DBG(hba->ctlr.lp, "Unable to alloc bnx2fc_lport\n");
+ return NULL;
+ }
+
/* Allocate Scsi_Host structure */
if (!npiv)
lport = libfc_host_alloc(&bnx2fc_shost_template, sizeof(*port));
@@ -1271,7 +1279,7 @@
if (!lport) {
printk(KERN_ERR PFX "could not allocate scsi host structure\n");
- return NULL;
+ goto free_blport;
}
shost = lport->host;
port = lport_priv(lport);
@@ -1327,12 +1335,20 @@
}
bnx2fc_interface_get(hba);
+
+ spin_lock_bh(&hba->hba_lock);
+ blport->lport = lport;
+ list_add_tail(&blport->list, &hba->vports);
+ spin_unlock_bh(&hba->hba_lock);
+
return lport;
shost_err:
scsi_remove_host(shost);
lp_config_err:
scsi_host_put(lport->host);
+free_blport:
+ kfree(blport);
return NULL;
}
@@ -1348,6 +1364,7 @@
{
struct fcoe_port *port = lport_priv(lport);
struct bnx2fc_hba *hba = port->priv;
+ struct bnx2fc_lport *blport, *tmp;
BNX2FC_HBA_DBG(hba->ctlr.lp, "ENTERED bnx2fc_if_destroy\n");
/* Stop the transmit retry timer */
@@ -1372,6 +1389,15 @@
/* Free memory used by statistical counters */
fc_lport_free_stats(lport);
+ spin_lock_bh(&hba->hba_lock);
+ list_for_each_entry_safe(blport, tmp, &hba->vports, list) {
+ if (blport->lport == lport) {
+ list_del(&blport->list);
+ kfree(blport);
+ }
+ }
+ spin_unlock_bh(&hba->hba_lock);
+
/* Release Scsi_Host */
scsi_host_put(lport->host);
diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
index f756d5f..78baa46 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
@@ -480,16 +480,36 @@
return rc;
}
+static bool is_valid_lport(struct bnx2fc_hba *hba, struct fc_lport *lport)
+{
+ struct bnx2fc_lport *blport;
+
+ spin_lock_bh(&hba->hba_lock);
+ list_for_each_entry(blport, &hba->vports, list) {
+ if (blport->lport == lport) {
+ spin_unlock_bh(&hba->hba_lock);
+ return true;
+ }
+ }
+ spin_unlock_bh(&hba->hba_lock);
+ return false;
+
+}
+
+
static void bnx2fc_unsol_els_work(struct work_struct *work)
{
struct bnx2fc_unsol_els *unsol_els;
struct fc_lport *lport;
+ struct bnx2fc_hba *hba;
struct fc_frame *fp;
unsol_els = container_of(work, struct bnx2fc_unsol_els, unsol_els_work);
lport = unsol_els->lport;
fp = unsol_els->fp;
- fc_exch_recv(lport, fp);
+ hba = unsol_els->hba;
+ if (is_valid_lport(hba, lport))
+ fc_exch_recv(lport, fp);
kfree(unsol_els);
}
@@ -499,6 +519,7 @@
{
struct fcoe_port *port = tgt->port;
struct fc_lport *lport = port->lport;
+ struct bnx2fc_hba *hba = port->priv;
struct bnx2fc_unsol_els *unsol_els;
struct fc_frame_header *fh;
struct fc_frame *fp;
@@ -559,6 +580,7 @@
fr_eof(fp) = FC_EOF_T;
fr_crc(fp) = cpu_to_le32(~crc);
unsol_els->lport = lport;
+ unsol_els->hba = hba;
unsol_els->fp = fp;
INIT_WORK(&unsol_els->unsol_els_work, bnx2fc_unsol_els_work);
queue_work(bnx2fc_wq, &unsol_els->unsol_els_work);
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c
index b5b5c34..454c72c 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_io.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_io.c
@@ -1734,7 +1734,6 @@
printk(KERN_ERR PFX "SCp.ptr is NULL\n");
return;
}
- io_req->sc_cmd = NULL;
if (io_req->on_active_queue) {
list_del_init(&io_req->link);
@@ -1754,6 +1753,7 @@
}
bnx2fc_unmap_sg_list(io_req);
+ io_req->sc_cmd = NULL;
switch (io_req->fcp_status) {
case FC_GOOD:
diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
index fc2cdb6..b2d6611 100644
--- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
+++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
@@ -913,7 +913,7 @@
struct t3cdev *t3dev = (struct t3cdev *)csk->cdev->lldev;
if (csk->l2t) {
- l2t_release(L2DATA(t3dev), csk->l2t);
+ l2t_release(t3dev, csk->l2t);
csk->l2t = NULL;
cxgbi_sock_put(csk);
}
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 155d7b9..8885b3e 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -749,12 +749,27 @@
* The offload EM that this routine is associated with will handle any
* packets that are for SCSI read requests.
*
+ * This has been enhanced to work when FCoE stack is operating in target
+ * mode.
+ *
* Returns: True for read types I/O, otherwise returns false.
*/
bool fcoe_oem_match(struct fc_frame *fp)
{
- return fc_fcp_is_read(fr_fsp(fp)) &&
- (fr_fsp(fp)->data_len > fcoe_ddp_min);
+ struct fc_frame_header *fh = fc_frame_header_get(fp);
+ struct fcp_cmnd *fcp;
+
+ if (fc_fcp_is_read(fr_fsp(fp)) &&
+ (fr_fsp(fp)->data_len > fcoe_ddp_min))
+ return true;
+ else if (!(ntoh24(fh->fh_f_ctl) & FC_FC_EX_CTX)) {
+ fcp = fc_frame_payload_get(fp, sizeof(*fcp));
+ if (ntohs(fh->fh_rx_id) == FC_XID_UNKNOWN &&
+ fcp && (ntohl(fcp->fc_dl) > fcoe_ddp_min) &&
+ (fcp->fc_flags & FCP_CFL_WRDATA))
+ return true;
+ }
+ return false;
}
/**
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 6bba23a..78c2e20 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -676,6 +676,16 @@
BUG_ON(entry < 0 || entry >= HPSA_MAX_SCSI_DEVS_PER_HBA);
removed[*nremoved] = h->dev[entry];
(*nremoved)++;
+
+ /*
+ * New physical devices won't have target/lun assigned yet
+ * so we need to preserve the values in the slot we are replacing.
+ */
+ if (new_entry->target == -1) {
+ new_entry->target = h->dev[entry]->target;
+ new_entry->lun = h->dev[entry]->lun;
+ }
+
h->dev[entry] = new_entry;
added[*nadded] = new_entry;
(*nadded)++;
@@ -1548,10 +1558,17 @@
}
static int hpsa_update_device_info(struct ctlr_info *h,
- unsigned char scsi3addr[], struct hpsa_scsi_dev_t *this_device)
+ unsigned char scsi3addr[], struct hpsa_scsi_dev_t *this_device,
+ unsigned char *is_OBDR_device)
{
-#define OBDR_TAPE_INQ_SIZE 49
+
+#define OBDR_SIG_OFFSET 43
+#define OBDR_TAPE_SIG "$DR-10"
+#define OBDR_SIG_LEN (sizeof(OBDR_TAPE_SIG) - 1)
+#define OBDR_TAPE_INQ_SIZE (OBDR_SIG_OFFSET + OBDR_SIG_LEN)
+
unsigned char *inq_buff;
+ unsigned char *obdr_sig;
inq_buff = kzalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);
if (!inq_buff)
@@ -1583,6 +1600,16 @@
else
this_device->raid_level = RAID_UNKNOWN;
+ if (is_OBDR_device) {
+ /* See if this is a One-Button-Disaster-Recovery device
+ * by looking for "$DR-10" at offset 43 in inquiry data.
+ */
+ obdr_sig = &inq_buff[OBDR_SIG_OFFSET];
+ *is_OBDR_device = (this_device->devtype == TYPE_ROM &&
+ strncmp(obdr_sig, OBDR_TAPE_SIG,
+ OBDR_SIG_LEN) == 0);
+ }
+
kfree(inq_buff);
return 0;
@@ -1716,7 +1743,7 @@
return 0;
}
- if (hpsa_update_device_info(h, scsi3addr, this_device))
+ if (hpsa_update_device_info(h, scsi3addr, this_device, NULL))
return 0;
(*nmsa2xxx_enclosures)++;
hpsa_set_bus_target_lun(this_device, bus, target, 0);
@@ -1808,7 +1835,6 @@
*/
struct ReportLUNdata *physdev_list = NULL;
struct ReportLUNdata *logdev_list = NULL;
- unsigned char *inq_buff = NULL;
u32 nphysicals = 0;
u32 nlogicals = 0;
u32 ndev_allocated = 0;
@@ -1824,11 +1850,9 @@
GFP_KERNEL);
physdev_list = kzalloc(reportlunsize, GFP_KERNEL);
logdev_list = kzalloc(reportlunsize, GFP_KERNEL);
- inq_buff = kmalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);
tmpdevice = kzalloc(sizeof(*tmpdevice), GFP_KERNEL);
- if (!currentsd || !physdev_list || !logdev_list ||
- !inq_buff || !tmpdevice) {
+ if (!currentsd || !physdev_list || !logdev_list || !tmpdevice) {
dev_err(&h->pdev->dev, "out of memory\n");
goto out;
}
@@ -1863,7 +1887,7 @@
/* adjust our table of devices */
nmsa2xxx_enclosures = 0;
for (i = 0; i < nphysicals + nlogicals + 1; i++) {
- u8 *lunaddrbytes;
+ u8 *lunaddrbytes, is_OBDR = 0;
/* Figure out where the LUN ID info is coming from */
lunaddrbytes = figure_lunaddrbytes(h, raid_ctlr_position,
@@ -1874,7 +1898,8 @@
continue;
/* Get device type, vendor, model, device id */
- if (hpsa_update_device_info(h, lunaddrbytes, tmpdevice))
+ if (hpsa_update_device_info(h, lunaddrbytes, tmpdevice,
+ &is_OBDR))
continue; /* skip it if we can't talk to it. */
figure_bus_target_lun(h, lunaddrbytes, &bus, &target, &lun,
tmpdevice);
@@ -1898,7 +1923,7 @@
hpsa_set_bus_target_lun(this_device, bus, target, lun);
switch (this_device->devtype) {
- case TYPE_ROM: {
+ case TYPE_ROM:
/* We don't *really* support actual CD-ROM devices,
* just "One Button Disaster Recovery" tape drive
* which temporarily pretends to be a CD-ROM drive.
@@ -1906,15 +1931,8 @@
* device by checking for "$DR-10" in bytes 43-48 of
* the inquiry data.
*/
- char obdr_sig[7];
-#define OBDR_TAPE_SIG "$DR-10"
- strncpy(obdr_sig, &inq_buff[43], 6);
- obdr_sig[6] = '\0';
- if (strncmp(obdr_sig, OBDR_TAPE_SIG, 6) != 0)
- /* Not OBDR device, ignore it. */
- break;
- }
- ncurrent++;
+ if (is_OBDR)
+ ncurrent++;
break;
case TYPE_DISK:
if (i < nphysicals)
@@ -1947,7 +1965,6 @@
for (i = 0; i < ndev_allocated; i++)
kfree(currentsd[i]);
kfree(currentsd);
- kfree(inq_buff);
kfree(physdev_list);
kfree(logdev_list);
}
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index 26072f1..ef46d83 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -531,6 +531,9 @@
break;
case SCU_COMPLETION_TYPE_EVENT:
+ sci_controller_event_completion(ihost, ent);
+ break;
+
case SCU_COMPLETION_TYPE_NOTIFY: {
event_cycle ^= ((event_get+1) & SCU_MAX_EVENTS) <<
(SMU_COMPLETION_QUEUE_GET_EVENT_CYCLE_BIT_SHIFT - SCU_MAX_EVENTS_SHIFT);
diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c
index 79313a7..430fc8f 100644
--- a/drivers/scsi/isci/phy.c
+++ b/drivers/scsi/isci/phy.c
@@ -104,6 +104,7 @@
u32 parity_count = 0;
u32 llctl, link_rate;
u32 clksm_value = 0;
+ u32 sp_timeouts = 0;
iphy->link_layer_registers = reg;
@@ -211,6 +212,18 @@
llctl |= SCU_SAS_LLCTL_GEN_VAL(MAX_LINK_RATE, link_rate);
writel(llctl, &iphy->link_layer_registers->link_layer_control);
+ sp_timeouts = readl(&iphy->link_layer_registers->sas_phy_timeouts);
+
+ /* Clear the default 0x36 (54us) RATE_CHANGE timeout value. */
+ sp_timeouts &= ~SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0xFF);
+
+ /* Set RATE_CHANGE timeout value to 0x3B (59us). This ensures SCU can
+ * lock with 3Gb drive when SCU max rate is set to 1.5Gb.
+ */
+ sp_timeouts |= SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0x3B);
+
+ writel(sp_timeouts, &iphy->link_layer_registers->sas_phy_timeouts);
+
if (is_a2(ihost->pdev)) {
/* Program the max ARB time for the PHY to 700us so we inter-operate with
* the PMC expander which shuts down PHYs if the expander PHY generates too
diff --git a/drivers/scsi/isci/registers.h b/drivers/scsi/isci/registers.h
index 9b266c7..00afc73 100644
--- a/drivers/scsi/isci/registers.h
+++ b/drivers/scsi/isci/registers.h
@@ -1299,6 +1299,18 @@
#define SCU_AFE_XCVRCR_OFFSET 0x00DC
#define SCU_AFE_LUTCR_OFFSET 0x00E0
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_ALIGN_DETECTION_SHIFT (0UL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_ALIGN_DETECTION_MASK (0x000000FFUL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_HOT_PLUG_SHIFT (8UL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_HOT_PLUG_MASK (0x0000FF00UL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_COMSAS_DETECTION_SHIFT (16UL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_COMSAS_DETECTION_MASK (0x00FF0000UL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_RATE_CHANGE_SHIFT (24UL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_RATE_CHANGE_MASK (0xFF000000UL)
+
+#define SCU_SAS_PHYTOV_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_##name, value)
+
#define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_SHIFT (0)
#define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_MASK (0x00000003)
#define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN1 (0)
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index a46e07a..b5d3a8c 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -732,12 +732,20 @@
sci_change_state(&ireq->sm, SCI_REQ_ABORTING);
return SCI_SUCCESS;
case SCI_REQ_TASK_WAIT_TC_RESP:
+ /* The task frame was already confirmed to have been
+ * sent by the SCU HW. Since the state machine is
+ * now only waiting for the task response itself,
+ * abort the request and complete it immediately
+ * and don't wait for the task response.
+ */
sci_change_state(&ireq->sm, SCI_REQ_ABORTING);
sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
return SCI_SUCCESS;
case SCI_REQ_ABORTING:
- sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
- return SCI_SUCCESS;
+ /* If a request has a termination requested twice, return
+ * a failure indication, since HW confirmation of the first
+ * abort is still outstanding.
+ */
case SCI_REQ_COMPLETED:
default:
dev_warn(&ireq->owning_controller->pdev->dev,
@@ -2399,22 +2407,19 @@
}
}
-static void isci_request_process_stp_response(struct sas_task *task,
- void *response_buffer)
+static void isci_process_stp_response(struct sas_task *task, struct dev_to_host_fis *fis)
{
- struct dev_to_host_fis *d2h_reg_fis = response_buffer;
struct task_status_struct *ts = &task->task_status;
struct ata_task_resp *resp = (void *)&ts->buf[0];
- resp->frame_len = le16_to_cpu(*(__le16 *)(response_buffer + 6));
- memcpy(&resp->ending_fis[0], response_buffer + 16, 24);
+ resp->frame_len = sizeof(*fis);
+ memcpy(resp->ending_fis, fis, sizeof(*fis));
ts->buf_valid_size = sizeof(*resp);
- /**
- * If the device fault bit is set in the status register, then
+ /* If the device fault bit is set in the status register, then
* set the sense data and return.
*/
- if (d2h_reg_fis->status & ATA_DF)
+ if (fis->status & ATA_DF)
ts->stat = SAS_PROTO_RESPONSE;
else
ts->stat = SAM_STAT_GOOD;
@@ -2428,7 +2433,6 @@
{
struct sas_task *task = isci_request_access_task(request);
struct ssp_response_iu *resp_iu;
- void *resp_buf;
unsigned long task_flags;
struct isci_remote_device *idev = isci_lookup_device(task->dev);
enum service_response response = SAS_TASK_UNDELIVERED;
@@ -2565,9 +2569,7 @@
task);
if (sas_protocol_ata(task->task_proto)) {
- resp_buf = &request->stp.rsp;
- isci_request_process_stp_response(task,
- resp_buf);
+ isci_process_stp_response(task, &request->stp.rsp);
} else if (SAS_PROTOCOL_SSP == task->task_proto) {
/* crack the iu response buffer. */
diff --git a/drivers/scsi/isci/unsolicited_frame_control.c b/drivers/scsi/isci/unsolicited_frame_control.c
index e9e1e2a..16f88ab 100644
--- a/drivers/scsi/isci/unsolicited_frame_control.c
+++ b/drivers/scsi/isci/unsolicited_frame_control.c
@@ -72,7 +72,7 @@
*/
buf_len = SCU_MAX_UNSOLICITED_FRAMES * SCU_UNSOLICITED_FRAME_BUFFER_SIZE;
header_len = SCU_MAX_UNSOLICITED_FRAMES * sizeof(struct scu_unsolicited_frame_header);
- size = buf_len + header_len + SCU_MAX_UNSOLICITED_FRAMES * sizeof(dma_addr_t);
+ size = buf_len + header_len + SCU_MAX_UNSOLICITED_FRAMES * sizeof(uf_control->address_table.array[0]);
/*
* The Unsolicited Frame buffers are set at the start of the UF
diff --git a/drivers/scsi/isci/unsolicited_frame_control.h b/drivers/scsi/isci/unsolicited_frame_control.h
index 31cb950..75d8966 100644
--- a/drivers/scsi/isci/unsolicited_frame_control.h
+++ b/drivers/scsi/isci/unsolicited_frame_control.h
@@ -214,7 +214,7 @@
* starting address of the UF address table.
* 64-bit pointers are required by the hardware.
*/
- dma_addr_t *array;
+ u64 *array;
/**
* This field specifies the physical address location for the UF
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 3df9853..7724414 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -107,10 +107,12 @@
* If the socket is in CLOSE or CLOSE_WAIT we should
* not close the connection if there is still some
* data pending.
+ *
+ * Must be called with sk_callback_lock.
*/
static inline int iscsi_sw_sk_state_check(struct sock *sk)
{
- struct iscsi_conn *conn = (struct iscsi_conn*)sk->sk_user_data;
+ struct iscsi_conn *conn = sk->sk_user_data;
if ((sk->sk_state == TCP_CLOSE_WAIT || sk->sk_state == TCP_CLOSE) &&
!atomic_read(&sk->sk_rmem_alloc)) {
@@ -123,11 +125,17 @@
static void iscsi_sw_tcp_data_ready(struct sock *sk, int flag)
{
- struct iscsi_conn *conn = sk->sk_user_data;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+ struct iscsi_conn *conn;
+ struct iscsi_tcp_conn *tcp_conn;
read_descriptor_t rd_desc;
read_lock(&sk->sk_callback_lock);
+ conn = sk->sk_user_data;
+ if (!conn) {
+ read_unlock(&sk->sk_callback_lock);
+ return;
+ }
+ tcp_conn = conn->dd_data;
/*
* Use rd_desc to pass 'conn' to iscsi_tcp_recv.
@@ -141,11 +149,10 @@
iscsi_sw_sk_state_check(sk);
- read_unlock(&sk->sk_callback_lock);
-
/* If we had to (atomically) map a highmem page,
* unmap it now. */
iscsi_tcp_segment_unmap(&tcp_conn->in.segment);
+ read_unlock(&sk->sk_callback_lock);
}
static void iscsi_sw_tcp_state_change(struct sock *sk)
@@ -157,8 +164,11 @@
void (*old_state_change)(struct sock *);
read_lock(&sk->sk_callback_lock);
-
- conn = (struct iscsi_conn*)sk->sk_user_data;
+ conn = sk->sk_user_data;
+ if (!conn) {
+ read_unlock(&sk->sk_callback_lock);
+ return;
+ }
session = conn->session;
iscsi_sw_sk_state_check(sk);
@@ -178,11 +188,25 @@
**/
static void iscsi_sw_tcp_write_space(struct sock *sk)
{
- struct iscsi_conn *conn = (struct iscsi_conn*)sk->sk_user_data;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
+ struct iscsi_conn *conn;
+ struct iscsi_tcp_conn *tcp_conn;
+ struct iscsi_sw_tcp_conn *tcp_sw_conn;
+ void (*old_write_space)(struct sock *);
- tcp_sw_conn->old_write_space(sk);
+ read_lock_bh(&sk->sk_callback_lock);
+ conn = sk->sk_user_data;
+ if (!conn) {
+ read_unlock_bh(&sk->sk_callback_lock);
+ return;
+ }
+
+ tcp_conn = conn->dd_data;
+ tcp_sw_conn = tcp_conn->dd_data;
+ old_write_space = tcp_sw_conn->old_write_space;
+ read_unlock_bh(&sk->sk_callback_lock);
+
+ old_write_space(sk);
+
ISCSI_SW_TCP_DBG(conn, "iscsi_write_space\n");
iscsi_conn_queue_work(conn);
}
@@ -592,20 +616,17 @@
/* userspace may have goofed up and not bound us */
if (!sock)
return;
- /*
- * Make sure our recv side is stopped.
- * Older tools called conn stop before ep_disconnect
- * so IO could still be coming in.
- */
- write_lock_bh(&tcp_sw_conn->sock->sk->sk_callback_lock);
- set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
- write_unlock_bh(&tcp_sw_conn->sock->sk->sk_callback_lock);
sock->sk->sk_err = EIO;
wake_up_interruptible(sk_sleep(sock->sk));
- iscsi_conn_stop(cls_conn, flag);
+ /* stop xmit side */
+ iscsi_suspend_tx(conn);
+
+ /* stop recv side and release socket */
iscsi_sw_tcp_release_conn(conn);
+
+ iscsi_conn_stop(cls_conn, flag);
}
static int
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index 49e1ccc..3b66937 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -801,6 +801,20 @@
switch (rdata->rp_state) {
case RPORT_ST_INIT:
+ /*
+ * If received the FLOGI request on RPORT which is INIT state
+ * (means not transition to FLOGI either fc_rport timeout
+ * function didn;t trigger or this end hasn;t received
+ * beacon yet from other end. In that case only, allow RPORT
+ * state machine to continue, otherwise fall through which
+ * causes the code to send reject response.
+ * NOTE; Not checking for FIP->state such as VNMP_UP or
+ * VNMP_CLAIM because if FIP state is not one of those,
+ * RPORT wouldn;t have created and 'rport_lookup' would have
+ * failed anyway in that case.
+ */
+ if (lport->point_to_multipoint)
+ break;
case RPORT_ST_DELETE:
mutex_unlock(&rdata->rp_mutex);
rjt_data.reason = ELS_RJT_FIP;
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index e98ae33..09b232f 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -1084,7 +1084,8 @@
struct iscsi_cls_conn *cls_conn;
struct iscsi_tcp_conn *tcp_conn;
- cls_conn = iscsi_conn_setup(cls_session, sizeof(*tcp_conn), conn_idx);
+ cls_conn = iscsi_conn_setup(cls_session,
+ sizeof(*tcp_conn) + dd_data_size, conn_idx);
if (!cls_conn)
return NULL;
conn = cls_conn->dd_data;
@@ -1096,22 +1097,13 @@
tcp_conn = conn->dd_data;
tcp_conn->iscsi_conn = conn;
-
- tcp_conn->dd_data = kzalloc(dd_data_size, GFP_KERNEL);
- if (!tcp_conn->dd_data) {
- iscsi_conn_teardown(cls_conn);
- return NULL;
- }
+ tcp_conn->dd_data = conn->dd_data + sizeof(*tcp_conn);
return cls_conn;
}
EXPORT_SYMBOL_GPL(iscsi_tcp_conn_setup);
void iscsi_tcp_conn_teardown(struct iscsi_cls_conn *cls_conn)
{
- struct iscsi_conn *conn = cls_conn->dd_data;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-
- kfree(tcp_conn->dd_data);
iscsi_conn_teardown(cls_conn);
}
EXPORT_SYMBOL_GPL(iscsi_tcp_conn_teardown);
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index f84084b..16ad97d 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -1721,7 +1721,7 @@
list_for_each_entry(ch, &ex->children, siblings) {
if (ch->dev_type == EDGE_DEV || ch->dev_type == FANOUT_DEV) {
res = sas_find_bcast_dev(ch, src_dev);
- if (src_dev)
+ if (*src_dev)
return res;
}
}
@@ -1769,10 +1769,12 @@
sas_disable_routing(parent, phy->attached_sas_addr);
}
memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
- sas_port_delete_phy(phy->port, phy->phy);
- if (phy->port->num_phys == 0)
- sas_port_delete(phy->port);
- phy->port = NULL;
+ if (phy->port) {
+ sas_port_delete_phy(phy->port, phy->phy);
+ if (phy->port->num_phys == 0)
+ sas_port_delete(phy->port);
+ phy->port = NULL;
+ }
}
static int sas_discover_bfs_by_root_level(struct domain_device *root,
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 8ec2c86..0441361 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -20,6 +20,11 @@
*******************************************************************/
#include <scsi/scsi_host.h>
+
+#if defined(CONFIG_DEBUG_FS) && !defined(CONFIG_SCSI_LPFC_DEBUG_FS)
+#define CONFIG_SCSI_LPFC_DEBUG_FS
+#endif
+
struct lpfc_sli2_slim;
#define LPFC_PCI_DEV_LP 0x1
@@ -465,9 +470,10 @@
struct unsol_rcv_ct_ctx {
uint32_t ctxt_id;
uint32_t SID;
- uint32_t oxid;
uint32_t flags;
#define UNSOL_VALID 0x00000001
+ uint16_t oxid;
+ uint16_t rxid;
};
#define LPFC_USER_LINK_SPEED_AUTO 0 /* auto select (default)*/
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 135a53b..80ca11c 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -755,6 +755,47 @@
}
/**
+ * lpfc_sli4_pdev_status_reg_wait - Wait for pdev status register for readyness
+ * @phba: lpfc_hba pointer.
+ *
+ * Description:
+ * SLI4 interface type-2 device to wait on the sliport status register for
+ * the readyness after performing a firmware reset.
+ *
+ * Returns:
+ * zero for success
+ **/
+static int
+lpfc_sli4_pdev_status_reg_wait(struct lpfc_hba *phba)
+{
+ struct lpfc_register portstat_reg;
+ int i;
+
+
+ lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
+ &portstat_reg.word0);
+
+ /* wait for the SLI port firmware ready after firmware reset */
+ for (i = 0; i < LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT; i++) {
+ msleep(10);
+ lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
+ &portstat_reg.word0);
+ if (!bf_get(lpfc_sliport_status_err, &portstat_reg))
+ continue;
+ if (!bf_get(lpfc_sliport_status_rn, &portstat_reg))
+ continue;
+ if (!bf_get(lpfc_sliport_status_rdy, &portstat_reg))
+ continue;
+ break;
+ }
+
+ if (i < LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT)
+ return 0;
+ else
+ return -EIO;
+}
+
+/**
* lpfc_sli4_pdev_reg_request - Request physical dev to perform a register acc
* @phba: lpfc_hba pointer.
*
@@ -805,7 +846,10 @@
readl(phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PDEV_CTL_OFFSET);
/* delay driver action following IF_TYPE_2 reset */
- msleep(100);
+ rc = lpfc_sli4_pdev_status_reg_wait(phba);
+
+ if (rc)
+ return -EIO;
init_completion(&online_compl);
rc = lpfc_workq_post_event(phba, &status, &online_compl,
@@ -895,6 +939,10 @@
if (!phba->cfg_enable_hba_reset)
return -EACCES;
+
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "3050 lpfc_board_mode set to %s\n", buf);
+
init_completion(&online_compl);
if(strncmp(buf, "online", sizeof("online") - 1) == 0) {
@@ -1290,6 +1338,10 @@
if (phba->sli_rev == LPFC_SLI_REV4)
val = 0;
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "3051 lpfc_poll changed from %d to %d\n",
+ phba->cfg_poll, val);
+
spin_lock_irq(&phba->hbalock);
old_val = phba->cfg_poll;
@@ -1414,80 +1466,10 @@
struct Scsi_Host *shost = class_to_shost(dev);
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- struct pci_dev *pdev = phba->pcidev;
- union lpfc_sli4_cfg_shdr *shdr;
- uint32_t shdr_status, shdr_add_status;
- LPFC_MBOXQ_t *mboxq;
- struct lpfc_mbx_get_prof_cfg *get_prof_cfg;
- struct lpfc_rsrc_desc_pcie *desc;
- uint32_t max_nr_virtfn;
- uint32_t desc_count;
- int length, rc, i;
+ uint16_t max_nr_virtfn;
- if ((phba->sli_rev < LPFC_SLI_REV4) ||
- (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
- LPFC_SLI_INTF_IF_TYPE_2))
- return -EPERM;
-
- if (!pdev->is_physfn)
- return snprintf(buf, PAGE_SIZE, "%d\n", 0);
-
- mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!mboxq)
- return -ENOMEM;
-
- /* get the maximum number of virtfn support by physfn */
- length = (sizeof(struct lpfc_mbx_get_prof_cfg) -
- sizeof(struct lpfc_sli4_cfg_mhdr));
- lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON,
- LPFC_MBOX_OPCODE_GET_PROFILE_CONFIG,
- length, LPFC_SLI4_MBX_EMBED);
- shdr = (union lpfc_sli4_cfg_shdr *)
- &mboxq->u.mqe.un.sli4_config.header.cfg_shdr;
- bf_set(lpfc_mbox_hdr_pf_num, &shdr->request,
- phba->sli4_hba.iov.pf_number + 1);
-
- get_prof_cfg = &mboxq->u.mqe.un.get_prof_cfg;
- bf_set(lpfc_mbx_get_prof_cfg_prof_tp, &get_prof_cfg->u.request,
- LPFC_CFG_TYPE_CURRENT_ACTIVE);
-
- rc = lpfc_sli_issue_mbox_wait(phba, mboxq,
- lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG));
-
- if (rc != MBX_TIMEOUT) {
- /* check return status */
- shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
- shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
- &shdr->response);
- if (shdr_status || shdr_add_status || rc)
- goto error_out;
-
- } else
- goto error_out;
-
- desc_count = get_prof_cfg->u.response.prof_cfg.rsrc_desc_count;
-
- for (i = 0; i < LPFC_RSRC_DESC_MAX_NUM; i++) {
- desc = (struct lpfc_rsrc_desc_pcie *)
- &get_prof_cfg->u.response.prof_cfg.desc[i];
- if (LPFC_RSRC_DESC_TYPE_PCIE ==
- bf_get(lpfc_rsrc_desc_pcie_type, desc)) {
- max_nr_virtfn = bf_get(lpfc_rsrc_desc_pcie_nr_virtfn,
- desc);
- break;
- }
- }
-
- if (i < LPFC_RSRC_DESC_MAX_NUM) {
- if (rc != MBX_TIMEOUT)
- mempool_free(mboxq, phba->mbox_mem_pool);
- return snprintf(buf, PAGE_SIZE, "%d\n", max_nr_virtfn);
- }
-
-error_out:
- if (rc != MBX_TIMEOUT)
- mempool_free(mboxq, phba->mbox_mem_pool);
- return -EIO;
+ max_nr_virtfn = lpfc_sli_sriov_nr_virtfn_get(phba);
+ return snprintf(buf, PAGE_SIZE, "%d\n", max_nr_virtfn);
}
/**
@@ -1605,6 +1587,9 @@
lpfc_##attr##_set(struct lpfc_hba *phba, uint val) \
{ \
if (val >= minval && val <= maxval) {\
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, \
+ "3052 lpfc_" #attr " changed from %d to %d\n", \
+ phba->cfg_##attr, val); \
phba->cfg_##attr = val;\
return 0;\
}\
@@ -1762,6 +1747,9 @@
lpfc_##attr##_set(struct lpfc_vport *vport, uint val) \
{ \
if (val >= minval && val <= maxval) {\
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, \
+ "3053 lpfc_" #attr " changed from %d to %d\n", \
+ vport->cfg_##attr, val); \
vport->cfg_##attr = val;\
return 0;\
}\
@@ -2678,6 +2666,9 @@
if (nolip)
return strlen(buf);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "3054 lpfc_topology changed from %d to %d\n",
+ prev_val, val);
err = lpfc_issue_lip(lpfc_shost_from_vport(phba->pport));
if (err) {
phba->cfg_topology = prev_val;
@@ -3101,6 +3092,10 @@
if (sscanf(val_buf, "%i", &val) != 1)
return -EINVAL;
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "3055 lpfc_link_speed changed from %d to %d %s\n",
+ phba->cfg_link_speed, val, nolip ? "(nolip)" : "(lip)");
+
if (((val == LPFC_USER_LINK_SPEED_1G) && !(phba->lmt & LMT_1Gb)) ||
((val == LPFC_USER_LINK_SPEED_2G) && !(phba->lmt & LMT_2Gb)) ||
((val == LPFC_USER_LINK_SPEED_4G) && !(phba->lmt & LMT_4Gb)) ||
@@ -3678,7 +3673,9 @@
# - Default will result in registering capabilities for all profiles.
#
*/
-unsigned int lpfc_prot_mask = SHOST_DIF_TYPE1_PROTECTION;
+unsigned int lpfc_prot_mask = SHOST_DIF_TYPE1_PROTECTION |
+ SHOST_DIX_TYPE0_PROTECTION |
+ SHOST_DIX_TYPE1_PROTECTION;
module_param(lpfc_prot_mask, uint, S_IRUGO);
MODULE_PARM_DESC(lpfc_prot_mask, "host protection mask");
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index 7fb0ba4..f46378f 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -960,8 +960,10 @@
evt_dat->immed_dat].oxid,
phba->ct_ctx[
evt_dat->immed_dat].SID);
+ phba->ct_ctx[evt_dat->immed_dat].rxid =
+ piocbq->iocb.ulpContext;
phba->ct_ctx[evt_dat->immed_dat].oxid =
- piocbq->iocb.ulpContext;
+ piocbq->iocb.unsli3.rcvsli3.ox_id;
phba->ct_ctx[evt_dat->immed_dat].SID =
piocbq->iocb.un.rcvels.remoteID;
phba->ct_ctx[evt_dat->immed_dat].flags = UNSOL_VALID;
@@ -1312,7 +1314,8 @@
rc = IOCB_ERROR;
goto issue_ct_rsp_exit;
}
- icmd->ulpContext = phba->ct_ctx[tag].oxid;
+ icmd->ulpContext = phba->ct_ctx[tag].rxid;
+ icmd->unsli3.rcvsli3.ox_id = phba->ct_ctx[tag].oxid;
ndlp = lpfc_findnode_did(phba->pport, phba->ct_ctx[tag].SID);
if (!ndlp) {
lpfc_printf_log(phba, KERN_WARNING, LOG_ELS,
@@ -1337,9 +1340,7 @@
goto issue_ct_rsp_exit;
}
- icmd->un.ulpWord[3] = ndlp->nlp_rpi;
- if (phba->sli_rev == LPFC_SLI_REV4)
- icmd->ulpContext =
+ icmd->un.ulpWord[3] =
phba->sli4_hba.rpi_ids[ndlp->nlp_rpi];
/* The exchange is done, mark the entry as invalid */
@@ -1351,8 +1352,8 @@
/* Xmit CT response on exchange <xid> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "2722 Xmit CT response on exchange x%x Data: x%x x%x\n",
- icmd->ulpContext, icmd->ulpIoTag, phba->link_state);
+ "2722 Xmit CT response on exchange x%x Data: x%x x%x x%x\n",
+ icmd->ulpContext, icmd->ulpIoTag, tag, phba->link_state);
ctiocb->iocb_cmpl = NULL;
ctiocb->iocb_flag |= LPFC_IO_LIBDFC;
@@ -1471,13 +1472,12 @@
/**
* lpfc_bsg_diag_mode_enter - process preparing into device diag loopback mode
* @phba: Pointer to HBA context object.
- * @job: LPFC_BSG_VENDOR_DIAG_MODE
*
* This function is responsible for preparing driver for diag loopback
* on device.
*/
static int
-lpfc_bsg_diag_mode_enter(struct lpfc_hba *phba, struct fc_bsg_job *job)
+lpfc_bsg_diag_mode_enter(struct lpfc_hba *phba)
{
struct lpfc_vport **vports;
struct Scsi_Host *shost;
@@ -1521,7 +1521,6 @@
/**
* lpfc_bsg_diag_mode_exit - exit process from device diag loopback mode
* @phba: Pointer to HBA context object.
- * @job: LPFC_BSG_VENDOR_DIAG_MODE
*
* This function is responsible for driver exit processing of setting up
* diag loopback mode on device.
@@ -1586,7 +1585,7 @@
goto job_error;
}
- rc = lpfc_bsg_diag_mode_enter(phba, job);
+ rc = lpfc_bsg_diag_mode_enter(phba);
if (rc)
goto job_error;
@@ -1758,7 +1757,7 @@
goto job_error;
}
- rc = lpfc_bsg_diag_mode_enter(phba, job);
+ rc = lpfc_bsg_diag_mode_enter(phba);
if (rc)
goto job_error;
@@ -1982,7 +1981,7 @@
goto job_error;
}
- rc = lpfc_bsg_diag_mode_enter(phba, job);
+ rc = lpfc_bsg_diag_mode_enter(phba);
if (rc)
goto job_error;
@@ -3511,7 +3510,7 @@
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
"2947 Issued SLI_CONFIG ext-buffer "
"maibox command, rc:x%x\n", rc);
- return 1;
+ return SLI_CONFIG_HANDLED;
}
lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
"2948 Failed to issue SLI_CONFIG ext-buffer "
@@ -3549,7 +3548,7 @@
LPFC_MBOXQ_t *pmboxq = NULL;
MAILBOX_t *pmb;
uint8_t *mbx;
- int rc = 0, i;
+ int rc = SLI_CONFIG_NOT_HANDLED, i;
mbox_req =
(struct dfc_mbox_req *)job->request->rqst_data.h_vendor.vendor_cmd;
@@ -3660,7 +3659,7 @@
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
"2955 Issued SLI_CONFIG ext-buffer "
"maibox command, rc:x%x\n", rc);
- return 1;
+ return SLI_CONFIG_HANDLED;
}
lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
"2956 Failed to issue SLI_CONFIG ext-buffer "
@@ -3668,6 +3667,11 @@
rc = -EPIPE;
}
+ /* wait for additoinal external buffers */
+ job->reply->result = 0;
+ job->job_done(job);
+ return SLI_CONFIG_HANDLED;
+
job_error:
if (pmboxq)
mempool_free(pmboxq, phba->mbox_mem_pool);
@@ -3959,7 +3963,7 @@
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
"2969 Issued SLI_CONFIG ext-buffer "
"maibox command, rc:x%x\n", rc);
- return 1;
+ return SLI_CONFIG_HANDLED;
}
lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
"2970 Failed to issue SLI_CONFIG ext-buffer "
@@ -4039,14 +4043,14 @@
struct lpfc_dmabuf *dmabuf)
{
struct dfc_mbox_req *mbox_req;
- int rc;
+ int rc = SLI_CONFIG_NOT_HANDLED;
mbox_req =
(struct dfc_mbox_req *)job->request->rqst_data.h_vendor.vendor_cmd;
/* mbox command with/without single external buffer */
if (mbox_req->extMboxTag == 0 && mbox_req->extSeqNum == 0)
- return SLI_CONFIG_NOT_HANDLED;
+ return rc;
/* mbox command and first external buffer */
if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_IDLE) {
@@ -4249,7 +4253,7 @@
* mailbox extension size
*/
if ((transmit_length > receive_length) ||
- (transmit_length > MAILBOX_EXT_SIZE)) {
+ (transmit_length > BSG_MBOX_SIZE - sizeof(MAILBOX_t))) {
rc = -ERANGE;
goto job_done;
}
@@ -4272,7 +4276,7 @@
/* receive length cannot be greater than mailbox
* extension size
*/
- if (receive_length > MAILBOX_EXT_SIZE) {
+ if (receive_length > BSG_MBOX_SIZE - sizeof(MAILBOX_t)) {
rc = -ERANGE;
goto job_done;
}
@@ -4306,7 +4310,8 @@
bde = (struct ulp_bde64 *)&pmb->un.varWords[4];
/* bde size cannot be greater than mailbox ext size */
- if (bde->tus.f.bdeSize > MAILBOX_EXT_SIZE) {
+ if (bde->tus.f.bdeSize >
+ BSG_MBOX_SIZE - sizeof(MAILBOX_t)) {
rc = -ERANGE;
goto job_done;
}
@@ -4332,7 +4337,8 @@
* mailbox extension size
*/
if ((receive_length == 0) ||
- (receive_length > MAILBOX_EXT_SIZE)) {
+ (receive_length >
+ BSG_MBOX_SIZE - sizeof(MAILBOX_t))) {
rc = -ERANGE;
goto job_done;
}
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index fc20c24..1e41af8 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -432,6 +432,7 @@
int lpfc_send_rrq(struct lpfc_hba *, struct lpfc_node_rrq *);
int lpfc_set_rrq_active(struct lpfc_hba *, struct lpfc_nodelist *,
uint16_t, uint16_t, uint16_t);
+uint16_t lpfc_sli4_xri_inrange(struct lpfc_hba *, uint16_t);
void lpfc_cleanup_wt_rrqs(struct lpfc_hba *);
void lpfc_cleanup_vports_rrqs(struct lpfc_vport *, struct lpfc_nodelist *);
struct lpfc_node_rrq *lpfc_get_active_rrq(struct lpfc_vport *, uint16_t,
@@ -439,3 +440,4 @@
int lpfc_wr_object(struct lpfc_hba *, struct list_head *, uint32_t, uint32_t *);
/* functions to support SR-IOV */
int lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *, int);
+uint16_t lpfc_sli_sriov_nr_virtfn_get(struct lpfc_hba *);
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 32a0845..1725b81 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -647,21 +647,15 @@
}
lpfc_cleanup_pending_mbox(vport);
- if (phba->sli_rev == LPFC_SLI_REV4)
+ if (phba->sli_rev == LPFC_SLI_REV4) {
lpfc_sli4_unreg_all_rpis(vport);
-
- if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
lpfc_mbx_unreg_vpi(vport);
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
- spin_unlock_irq(shost->host_lock);
- }
- /*
- * If VPI is unreged, driver need to do INIT_VPI
- * before re-registering
- */
- if (phba->sli_rev == LPFC_SLI_REV4) {
- spin_lock_irq(shost->host_lock);
+ /*
+ * If VPI is unreged, driver need to do INIT_VPI
+ * before re-registering
+ */
vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
spin_unlock_irq(shost->host_lock);
}
@@ -1096,11 +1090,14 @@
/* Set the fcfi to the fcfi we registered with */
elsiocb->iocb.ulpContext = phba->fcf.fcfi;
}
- } else if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
- sp->cmn.request_multiple_Nport = 1;
- /* For FLOGI, Let FLOGI rsp set the NPortID for VPI 0 */
- icmd->ulpCt_h = 1;
- icmd->ulpCt_l = 0;
+ } else {
+ if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
+ sp->cmn.request_multiple_Nport = 1;
+ /* For FLOGI, Let FLOGI rsp set the NPortID for VPI 0 */
+ icmd->ulpCt_h = 1;
+ icmd->ulpCt_l = 0;
+ } else
+ sp->cmn.request_multiple_Nport = 0;
}
if (phba->fc_topology != LPFC_TOPOLOGY_LOOP) {
@@ -3656,7 +3653,8 @@
}
icmd = &elsiocb->iocb;
- icmd->ulpContext = oldcmd->ulpContext; /* Xri */
+ icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */
+ icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
pcmd += sizeof(uint32_t);
@@ -3673,7 +3671,8 @@
return 1;
icmd = &elsiocb->iocb;
- icmd->ulpContext = oldcmd->ulpContext; /* Xri */
+ icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */
+ icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
if (mbox)
@@ -3695,7 +3694,8 @@
return 1;
icmd = &elsiocb->iocb;
- icmd->ulpContext = oldcmd->ulpContext; /* Xri */
+ icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */
+ icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
memcpy(pcmd, ((struct lpfc_dmabuf *) oldiocb->context2)->virt,
@@ -3781,7 +3781,8 @@
icmd = &elsiocb->iocb;
oldcmd = &oldiocb->iocb;
- icmd->ulpContext = oldcmd->ulpContext; /* Xri */
+ icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */
+ icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_LS_RJT;
@@ -3853,7 +3854,8 @@
icmd = &elsiocb->iocb;
oldcmd = &oldiocb->iocb;
- icmd->ulpContext = oldcmd->ulpContext; /* Xri */
+ icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */
+ icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
/* Xmit ADISC ACC response tag <ulpIoTag> */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
@@ -3931,7 +3933,9 @@
icmd = &elsiocb->iocb;
oldcmd = &oldiocb->iocb;
- icmd->ulpContext = oldcmd->ulpContext; /* Xri */
+ icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */
+ icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
+
/* Xmit PRLI ACC response tag <ulpIoTag> */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"0131 Xmit PRLI ACC response tag x%x xri x%x, "
@@ -4035,7 +4039,9 @@
icmd = &elsiocb->iocb;
oldcmd = &oldiocb->iocb;
- icmd->ulpContext = oldcmd->ulpContext; /* Xri */
+ icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */
+ icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
+
/* Xmit RNID ACC response tag <ulpIoTag> */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"0132 Xmit RNID ACC response tag x%x xri x%x\n",
@@ -4163,7 +4169,9 @@
if (!elsiocb)
return 1;
- elsiocb->iocb.ulpContext = oldiocb->iocb.ulpContext; /* Xri */
+ elsiocb->iocb.ulpContext = oldiocb->iocb.ulpContext; /* Xri / rx_id */
+ elsiocb->iocb.unsli3.rcvsli3.ox_id = oldiocb->iocb.unsli3.rcvsli3.ox_id;
+
/* Xmit ECHO ACC response tag <ulpIoTag> */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"2876 Xmit ECHO ACC response tag x%x xri x%x\n",
@@ -5054,13 +5062,15 @@
uint8_t *pcmd;
struct lpfc_iocbq *elsiocb;
struct lpfc_nodelist *ndlp;
- uint16_t xri;
+ uint16_t oxid;
+ uint16_t rxid;
uint32_t cmdsize;
mb = &pmb->u.mb;
ndlp = (struct lpfc_nodelist *) pmb->context2;
- xri = (uint16_t) ((unsigned long)(pmb->context1));
+ rxid = (uint16_t) ((unsigned long)(pmb->context1) & 0xffff);
+ oxid = (uint16_t) (((unsigned long)(pmb->context1) >> 16) & 0xffff);
pmb->context1 = NULL;
pmb->context2 = NULL;
@@ -5082,7 +5092,8 @@
return;
icmd = &elsiocb->iocb;
- icmd->ulpContext = xri;
+ icmd->ulpContext = rxid;
+ icmd->unsli3.rcvsli3.ox_id = oxid;
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
@@ -5137,13 +5148,16 @@
uint8_t *pcmd;
struct lpfc_iocbq *elsiocb;
struct lpfc_nodelist *ndlp;
- uint16_t xri, status;
+ uint16_t status;
+ uint16_t oxid;
+ uint16_t rxid;
uint32_t cmdsize;
mb = &pmb->u.mb;
ndlp = (struct lpfc_nodelist *) pmb->context2;
- xri = (uint16_t) ((unsigned long)(pmb->context1));
+ rxid = (uint16_t) ((unsigned long)(pmb->context1) & 0xffff);
+ oxid = (uint16_t) (((unsigned long)(pmb->context1) >> 16) & 0xffff);
pmb->context1 = NULL;
pmb->context2 = NULL;
@@ -5165,7 +5179,8 @@
return;
icmd = &elsiocb->iocb;
- icmd->ulpContext = xri;
+ icmd->ulpContext = rxid;
+ icmd->unsli3.rcvsli3.ox_id = oxid;
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
@@ -5238,8 +5253,9 @@
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);
if (mbox) {
lpfc_read_lnk_stat(phba, mbox);
- mbox->context1 =
- (void *)((unsigned long) cmdiocb->iocb.ulpContext);
+ mbox->context1 = (void *)((unsigned long)
+ ((cmdiocb->iocb.unsli3.rcvsli3.ox_id << 16) |
+ cmdiocb->iocb.ulpContext)); /* rx_id */
mbox->context2 = lpfc_nlp_get(ndlp);
mbox->vport = vport;
mbox->mbox_cmpl = lpfc_els_rsp_rls_acc;
@@ -5314,7 +5330,8 @@
pcmd += sizeof(uint32_t); /* Skip past command */
/* use the command's xri in the response */
- elsiocb->iocb.ulpContext = cmdiocb->iocb.ulpContext;
+ elsiocb->iocb.ulpContext = cmdiocb->iocb.ulpContext; /* Xri / rx_id */
+ elsiocb->iocb.unsli3.rcvsli3.ox_id = cmdiocb->iocb.unsli3.rcvsli3.ox_id;
rtv_rsp = (struct RTV_RSP *)pcmd;
@@ -5399,8 +5416,9 @@
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);
if (mbox) {
lpfc_read_lnk_stat(phba, mbox);
- mbox->context1 =
- (void *)((unsigned long) cmdiocb->iocb.ulpContext);
+ mbox->context1 = (void *)((unsigned long)
+ ((cmdiocb->iocb.unsli3.rcvsli3.ox_id << 16) |
+ cmdiocb->iocb.ulpContext)); /* rx_id */
mbox->context2 = lpfc_nlp_get(ndlp);
mbox->vport = vport;
mbox->mbox_cmpl = lpfc_els_rsp_rps_acc;
@@ -5554,7 +5572,8 @@
icmd = &elsiocb->iocb;
oldcmd = &oldiocb->iocb;
- icmd->ulpContext = oldcmd->ulpContext; /* Xri */
+ icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */
+ icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
@@ -6586,7 +6605,7 @@
{
struct lpfc_vport *vport;
unsigned long flags;
- int i;
+ int i = 0;
/* The physical ports are always vpi 0 - translate is unnecessary. */
if (vpi > 0) {
@@ -6609,7 +6628,7 @@
spin_lock_irqsave(&phba->hbalock, flags);
list_for_each_entry(vport, &phba->port_list, listentry) {
- if (vport->vpi == vpi) {
+ if (vport->vpi == i) {
spin_unlock_irqrestore(&phba->hbalock, flags);
return vport;
}
@@ -7787,6 +7806,7 @@
{
uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri);
uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri);
+ uint16_t lxri = 0;
struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL;
unsigned long iflag = 0;
@@ -7815,7 +7835,12 @@
}
}
spin_unlock(&phba->sli4_hba.abts_sgl_list_lock);
- sglq_entry = __lpfc_get_active_sglq(phba, xri);
+ lxri = lpfc_sli4_xri_inrange(phba, xri);
+ if (lxri == NO_XRI) {
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
+ return;
+ }
+ sglq_entry = __lpfc_get_active_sglq(phba, lxri);
if (!sglq_entry || (sglq_entry->sli4_xritag != xri)) {
spin_unlock_irqrestore(&phba->hbalock, iflag);
return;
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 18d0dbf..bef17e3 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -2247,7 +2247,6 @@
spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag |= FCF_REDISC_FOV;
spin_unlock_irq(&phba->hbalock);
- lpfc_sli4_mbox_cmd_free(phba, mboxq);
lpfc_sli4_fcf_scan_read_fcf_rec(phba,
LPFC_FCOE_FCF_GET_FIRST);
return;
@@ -2645,6 +2644,7 @@
vport->vpi_state |= LPFC_VPI_REGISTERED;
vport->fc_flag |= FC_VFI_REGISTERED;
vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
+ vport->fc_flag &= ~FC_VPORT_NEEDS_INIT_VPI;
spin_unlock_irq(shost->host_lock);
if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index 9059524..df53d10 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -3470,11 +3470,16 @@
or CMD_IOCB_RCV_SEQ64_CX (0xB5) */
struct rcv_sli3 {
- uint32_t word8Rsvd;
#ifdef __BIG_ENDIAN_BITFIELD
+ uint16_t ox_id;
+ uint16_t seq_cnt;
+
uint16_t vpi;
uint16_t word9Rsvd;
#else /* __LITTLE_ENDIAN */
+ uint16_t seq_cnt;
+ uint16_t ox_id;
+
uint16_t word9Rsvd;
uint16_t vpi;
#endif
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 11e26a2..7f8003b 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -170,15 +170,8 @@
#define LPFC_PCI_FUNC3 3
#define LPFC_PCI_FUNC4 4
-/* SLI4 interface type-2 control register offsets */
-#define LPFC_CTL_PORT_SEM_OFFSET 0x400
-#define LPFC_CTL_PORT_STA_OFFSET 0x404
-#define LPFC_CTL_PORT_CTL_OFFSET 0x408
-#define LPFC_CTL_PORT_ER1_OFFSET 0x40C
-#define LPFC_CTL_PORT_ER2_OFFSET 0x410
+/* SLI4 interface type-2 PDEV_CTL register */
#define LPFC_CTL_PDEV_CTL_OFFSET 0x414
-
-/* Some SLI4 interface type-2 PDEV_CTL register bits */
#define LPFC_CTL_PDEV_CTL_DRST 0x00000001
#define LPFC_CTL_PDEV_CTL_FRST 0x00000002
#define LPFC_CTL_PDEV_CTL_DD 0x00000004
@@ -337,6 +330,7 @@
#define CQE_CODE_RELEASE_WQE 0x2
#define CQE_CODE_RECEIVE 0x4
#define CQE_CODE_XRI_ABORTED 0x5
+#define CQE_CODE_RECEIVE_V1 0x9
/* completion queue entry for wqe completions */
struct lpfc_wcqe_complete {
@@ -440,7 +434,10 @@
#define FC_STATUS_RQ_BUF_LEN_EXCEEDED 0x11 /* payload truncated */
#define FC_STATUS_INSUFF_BUF_NEED_BUF 0x12 /* Insufficient buffers */
#define FC_STATUS_INSUFF_BUF_FRM_DISC 0x13 /* Frame Discard */
- uint32_t reserved1;
+ uint32_t word1;
+#define lpfc_rcqe_fcf_id_v1_SHIFT 0
+#define lpfc_rcqe_fcf_id_v1_MASK 0x0000003F
+#define lpfc_rcqe_fcf_id_v1_WORD word1
uint32_t word2;
#define lpfc_rcqe_length_SHIFT 16
#define lpfc_rcqe_length_MASK 0x0000FFFF
@@ -451,6 +448,9 @@
#define lpfc_rcqe_fcf_id_SHIFT 0
#define lpfc_rcqe_fcf_id_MASK 0x0000003F
#define lpfc_rcqe_fcf_id_WORD word2
+#define lpfc_rcqe_rq_id_v1_SHIFT 0
+#define lpfc_rcqe_rq_id_v1_MASK 0x0000FFFF
+#define lpfc_rcqe_rq_id_v1_WORD word2
uint32_t word3;
#define lpfc_rcqe_valid_SHIFT lpfc_cqe_valid_SHIFT
#define lpfc_rcqe_valid_MASK lpfc_cqe_valid_MASK
@@ -515,7 +515,7 @@
/* The following BAR0 register sets are defined for if_type 0 and 2 UCNAs. */
#define LPFC_SLI_INTF 0x0058
-#define LPFC_SLIPORT_IF2_SMPHR 0x0400
+#define LPFC_CTL_PORT_SEM_OFFSET 0x400
#define lpfc_port_smphr_perr_SHIFT 31
#define lpfc_port_smphr_perr_MASK 0x1
#define lpfc_port_smphr_perr_WORD word0
@@ -575,7 +575,7 @@
#define LPFC_POST_STAGE_PORT_READY 0xC000
#define LPFC_POST_STAGE_PORT_UE 0xF000
-#define LPFC_SLIPORT_STATUS 0x0404
+#define LPFC_CTL_PORT_STA_OFFSET 0x404
#define lpfc_sliport_status_err_SHIFT 31
#define lpfc_sliport_status_err_MASK 0x1
#define lpfc_sliport_status_err_WORD word0
@@ -593,7 +593,7 @@
#define lpfc_sliport_status_rdy_WORD word0
#define MAX_IF_TYPE_2_RESETS 1000
-#define LPFC_SLIPORT_CNTRL 0x0408
+#define LPFC_CTL_PORT_CTL_OFFSET 0x408
#define lpfc_sliport_ctrl_end_SHIFT 30
#define lpfc_sliport_ctrl_end_MASK 0x1
#define lpfc_sliport_ctrl_end_WORD word0
@@ -604,8 +604,8 @@
#define lpfc_sliport_ctrl_ip_WORD word0
#define LPFC_SLIPORT_INIT_PORT 1
-#define LPFC_SLIPORT_ERR_1 0x040C
-#define LPFC_SLIPORT_ERR_2 0x0410
+#define LPFC_CTL_PORT_ER1_OFFSET 0x40C
+#define LPFC_CTL_PORT_ER2_OFFSET 0x410
/* The following Registers apply to SLI4 if_type 0 UCNAs. They typically
* reside in BAR 2.
@@ -3198,6 +3198,8 @@
#define lpfc_grp_hdr_id_MASK 0x000000FF
#define lpfc_grp_hdr_id_WORD word2
uint8_t rev_name[128];
+ uint8_t date[12];
+ uint8_t revision[32];
};
#define FCP_COMMAND 0x0
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 148b98d..027b797 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -2927,6 +2927,8 @@
sizeof fc_host_symbolic_name(shost));
fc_host_supported_speeds(shost) = 0;
+ if (phba->lmt & LMT_16Gb)
+ fc_host_supported_speeds(shost) |= FC_PORTSPEED_16GBIT;
if (phba->lmt & LMT_10Gb)
fc_host_supported_speeds(shost) |= FC_PORTSPEED_10GBIT;
if (phba->lmt & LMT_8Gb)
@@ -3647,7 +3649,7 @@
" tag 0x%x\n", acqe_fip->index, acqe_fip->event_tag);
vport = lpfc_find_vport_by_vpid(phba,
- acqe_fip->index - phba->vpi_base);
+ acqe_fip->index);
ndlp = lpfc_sli4_perform_vport_cvl(vport);
if (!ndlp)
break;
@@ -4035,6 +4037,34 @@
}
/**
+ * lpfc_sli_sriov_nr_virtfn_get - Get the number of sr-iov virtual functions
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This function enables the PCI SR-IOV virtual functions to a physical
+ * function. It invokes the PCI SR-IOV api with the @nr_vfn provided to
+ * enable the number of virtual functions to the physical function. As
+ * not all devices support SR-IOV, the return code from the pci_enable_sriov()
+ * API call does not considered as an error condition for most of the device.
+ **/
+uint16_t
+lpfc_sli_sriov_nr_virtfn_get(struct lpfc_hba *phba)
+{
+ struct pci_dev *pdev = phba->pcidev;
+ uint16_t nr_virtfn;
+ int pos;
+
+ if (!pdev->is_physfn)
+ return 0;
+
+ pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
+ if (pos == 0)
+ return 0;
+
+ pci_read_config_word(pdev, pos + PCI_SRIOV_TOTAL_VF, &nr_virtfn);
+ return nr_virtfn;
+}
+
+/**
* lpfc_sli_probe_sriov_nr_virtfn - Enable a number of sr-iov virtual functions
* @phba: pointer to lpfc hba data structure.
* @nr_vfn: number of virtual functions to be enabled.
@@ -4049,8 +4079,17 @@
lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *phba, int nr_vfn)
{
struct pci_dev *pdev = phba->pcidev;
+ uint16_t max_nr_vfn;
int rc;
+ max_nr_vfn = lpfc_sli_sriov_nr_virtfn_get(phba);
+ if (nr_vfn > max_nr_vfn) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "3057 Requested vfs (%d) greater than "
+ "supported vfs (%d)", nr_vfn, max_nr_vfn);
+ return -EINVAL;
+ }
+
rc = pci_enable_sriov(pdev, nr_vfn);
if (rc) {
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
@@ -4516,7 +4555,7 @@
}
}
- return rc;
+ return 0;
out_free_fcp_eq_hdl:
kfree(phba->sli4_hba.fcp_eq_hdl);
@@ -4966,17 +5005,14 @@
* @phba: pointer to lpfc hba data structure.
*
* This routine is invoked to post rpi header templates to the
- * HBA consistent with the SLI-4 interface spec. This routine
+ * port for those SLI4 ports that do not support extents. This routine
* posts a PAGE_SIZE memory region to the port to hold up to
- * PAGE_SIZE modulo 64 rpi context headers.
- * No locks are held here because this is an initialization routine
- * called only from probe or lpfc_online when interrupts are not
- * enabled and the driver is reinitializing the device.
+ * PAGE_SIZE modulo 64 rpi context headers. This is an initialization routine
+ * and should be called only when interrupts are disabled.
*
* Return codes
* 0 - successful
- * -ENOMEM - No available memory
- * -EIO - The mailbox failed to complete successfully.
+ * -ERROR - otherwise.
**/
int
lpfc_sli4_init_rpi_hdrs(struct lpfc_hba *phba)
@@ -5687,17 +5723,22 @@
break;
case LPFC_SLI_INTF_IF_TYPE_2:
phba->sli4_hba.u.if_type2.ERR1regaddr =
- phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_ERR_1;
+ phba->sli4_hba.conf_regs_memmap_p +
+ LPFC_CTL_PORT_ER1_OFFSET;
phba->sli4_hba.u.if_type2.ERR2regaddr =
- phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_ERR_2;
+ phba->sli4_hba.conf_regs_memmap_p +
+ LPFC_CTL_PORT_ER2_OFFSET;
phba->sli4_hba.u.if_type2.CTRLregaddr =
- phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_CNTRL;
+ phba->sli4_hba.conf_regs_memmap_p +
+ LPFC_CTL_PORT_CTL_OFFSET;
phba->sli4_hba.u.if_type2.STATUSregaddr =
- phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_STATUS;
+ phba->sli4_hba.conf_regs_memmap_p +
+ LPFC_CTL_PORT_STA_OFFSET;
phba->sli4_hba.SLIINTFregaddr =
phba->sli4_hba.conf_regs_memmap_p + LPFC_SLI_INTF;
phba->sli4_hba.PSMPHRregaddr =
- phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_IF2_SMPHR;
+ phba->sli4_hba.conf_regs_memmap_p +
+ LPFC_CTL_PORT_SEM_OFFSET;
phba->sli4_hba.RQDBregaddr =
phba->sli4_hba.conf_regs_memmap_p + LPFC_RQ_DOORBELL;
phba->sli4_hba.WQDBregaddr =
@@ -8859,11 +8900,11 @@
return -EINVAL;
}
lpfc_decode_firmware_rev(phba, fwrev, 1);
- if (strncmp(fwrev, image->rev_name, strnlen(fwrev, 16))) {
+ if (strncmp(fwrev, image->revision, strnlen(image->revision, 16))) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"3023 Updating Firmware. Current Version:%s "
"New Version:%s\n",
- fwrev, image->rev_name);
+ fwrev, image->revision);
for (i = 0; i < LPFC_MBX_WR_CONFIG_MAX_BDE; i++) {
dmabuf = kzalloc(sizeof(struct lpfc_dmabuf),
GFP_KERNEL);
@@ -8892,9 +8933,9 @@
fw->size - offset);
break;
}
- temp_offset += SLI4_PAGE_SIZE;
memcpy(dmabuf->virt, fw->data + temp_offset,
SLI4_PAGE_SIZE);
+ temp_offset += SLI4_PAGE_SIZE;
}
rc = lpfc_wr_object(phba, &dma_buffer_list,
(fw->size - offset), &offset);
@@ -9483,6 +9524,13 @@
}
pci_restore_state(pdev);
+
+ /*
+ * As the new kernel behavior of pci_restore_state() API call clears
+ * device saved_state flag, need to save the restored state again.
+ */
+ pci_save_state(pdev);
+
if (pdev->is_busmaster)
pci_set_master(pdev);
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index 5567670..83450cc 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -2031,7 +2031,7 @@
bf_set(lpfc_init_vfi_vp, init_vfi, 1);
bf_set(lpfc_init_vfi_vfi, init_vfi,
vport->phba->sli4_hba.vfi_ids[vport->vfi]);
- bf_set(lpfc_init_vpi_vpi, init_vfi,
+ bf_set(lpfc_init_vfi_vpi, init_vfi,
vport->phba->vpi_ids[vport->vpi]);
bf_set(lpfc_init_vfi_fcfi, init_vfi,
vport->phba->fcf.fcfi);
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 3ccc974..eadd241 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -1302,13 +1302,13 @@
case SCSI_PROT_NORMAL:
default:
lpfc_printf_log(phba, KERN_ERR, LOG_BG,
- "9063 BLKGRD: Bad op/guard:%d/%d combination\n",
- scsi_get_prot_op(sc), guard_type);
+ "9063 BLKGRD: Bad op/guard:%d/IP combination\n",
+ scsi_get_prot_op(sc));
ret = 1;
break;
}
- } else if (guard_type == SHOST_DIX_GUARD_CRC) {
+ } else {
switch (scsi_get_prot_op(sc)) {
case SCSI_PROT_READ_STRIP:
case SCSI_PROT_WRITE_INSERT:
@@ -1324,17 +1324,18 @@
case SCSI_PROT_READ_INSERT:
case SCSI_PROT_WRITE_STRIP:
+ *txop = BG_OP_IN_CRC_OUT_NODIF;
+ *rxop = BG_OP_IN_NODIF_OUT_CRC;
+ break;
+
case SCSI_PROT_NORMAL:
default:
lpfc_printf_log(phba, KERN_ERR, LOG_BG,
- "9075 BLKGRD: Bad op/guard:%d/%d combination\n",
- scsi_get_prot_op(sc), guard_type);
+ "9075 BLKGRD: Bad op/guard:%d/CRC combination\n",
+ scsi_get_prot_op(sc));
ret = 1;
break;
}
- } else {
- /* unsupported format */
- BUG();
}
return ret;
@@ -1352,45 +1353,6 @@
return sc->device->sector_size;
}
-/**
- * lpfc_get_cmd_dif_parms - Extract DIF parameters from SCSI command
- * @sc: in: SCSI command
- * @apptagmask: out: app tag mask
- * @apptagval: out: app tag value
- * @reftag: out: ref tag (reference tag)
- *
- * Description:
- * Extract DIF parameters from the command if possible. Otherwise,
- * use default parameters.
- *
- **/
-static inline void
-lpfc_get_cmd_dif_parms(struct scsi_cmnd *sc, uint16_t *apptagmask,
- uint16_t *apptagval, uint32_t *reftag)
-{
- struct scsi_dif_tuple *spt;
- unsigned char op = scsi_get_prot_op(sc);
- unsigned int protcnt = scsi_prot_sg_count(sc);
- static int cnt;
-
- if (protcnt && (op == SCSI_PROT_WRITE_STRIP ||
- op == SCSI_PROT_WRITE_PASS)) {
-
- cnt++;
- spt = page_address(sg_page(scsi_prot_sglist(sc))) +
- scsi_prot_sglist(sc)[0].offset;
- *apptagmask = 0;
- *apptagval = 0;
- *reftag = cpu_to_be32(spt->ref_tag);
-
- } else {
- /* SBC defines ref tag to be lower 32bits of LBA */
- *reftag = (uint32_t) (0xffffffff & scsi_get_lba(sc));
- *apptagmask = 0;
- *apptagval = 0;
- }
-}
-
/*
* This function sets up buffer list for protection groups of
* type LPFC_PG_TYPE_NO_DIF
@@ -1427,9 +1389,8 @@
dma_addr_t physaddr;
int i = 0, num_bde = 0, status;
int datadir = sc->sc_data_direction;
- unsigned blksize;
uint32_t reftag;
- uint16_t apptagmask, apptagval;
+ unsigned blksize;
uint8_t txop, rxop;
status = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop);
@@ -1438,17 +1399,16 @@
/* extract some info from the scsi command for pde*/
blksize = lpfc_cmd_blksize(sc);
- lpfc_get_cmd_dif_parms(sc, &apptagmask, &apptagval, &reftag);
+ reftag = scsi_get_lba(sc) & 0xffffffff;
/* setup PDE5 with what we have */
pde5 = (struct lpfc_pde5 *) bpl;
memset(pde5, 0, sizeof(struct lpfc_pde5));
bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR);
- pde5->reftag = reftag;
/* Endianness conversion if necessary for PDE5 */
pde5->word0 = cpu_to_le32(pde5->word0);
- pde5->reftag = cpu_to_le32(pde5->reftag);
+ pde5->reftag = cpu_to_le32(reftag);
/* advance bpl and increment bde count */
num_bde++;
@@ -1463,10 +1423,10 @@
if (datadir == DMA_FROM_DEVICE) {
bf_set(pde6_ce, pde6, 1);
bf_set(pde6_re, pde6, 1);
- bf_set(pde6_ae, pde6, 1);
}
bf_set(pde6_ai, pde6, 1);
- bf_set(pde6_apptagval, pde6, apptagval);
+ bf_set(pde6_ae, pde6, 0);
+ bf_set(pde6_apptagval, pde6, 0);
/* Endianness conversion if necessary for PDE6 */
pde6->word0 = cpu_to_le32(pde6->word0);
@@ -1551,7 +1511,6 @@
unsigned char pgdone = 0, alldone = 0;
unsigned blksize;
uint32_t reftag;
- uint16_t apptagmask, apptagval;
uint8_t txop, rxop;
int num_bde = 0;
@@ -1571,7 +1530,7 @@
/* extract some info from the scsi command */
blksize = lpfc_cmd_blksize(sc);
- lpfc_get_cmd_dif_parms(sc, &apptagmask, &apptagval, &reftag);
+ reftag = scsi_get_lba(sc) & 0xffffffff;
split_offset = 0;
do {
@@ -1579,11 +1538,10 @@
pde5 = (struct lpfc_pde5 *) bpl;
memset(pde5, 0, sizeof(struct lpfc_pde5));
bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR);
- pde5->reftag = reftag;
/* Endianness conversion if necessary for PDE5 */
pde5->word0 = cpu_to_le32(pde5->word0);
- pde5->reftag = cpu_to_le32(pde5->reftag);
+ pde5->reftag = cpu_to_le32(reftag);
/* advance bpl and increment bde count */
num_bde++;
@@ -1597,9 +1555,9 @@
bf_set(pde6_oprx, pde6, rxop);
bf_set(pde6_ce, pde6, 1);
bf_set(pde6_re, pde6, 1);
- bf_set(pde6_ae, pde6, 1);
bf_set(pde6_ai, pde6, 1);
- bf_set(pde6_apptagval, pde6, apptagval);
+ bf_set(pde6_ae, pde6, 0);
+ bf_set(pde6_apptagval, pde6, 0);
/* Endianness conversion if necessary for PDE6 */
pde6->word0 = cpu_to_le32(pde6->word0);
@@ -1621,8 +1579,8 @@
memset(pde7, 0, sizeof(struct lpfc_pde7));
bf_set(pde7_type, pde7, LPFC_PDE7_DESCRIPTOR);
- pde7->addrHigh = le32_to_cpu(putPaddrLow(protphysaddr));
- pde7->addrLow = le32_to_cpu(putPaddrHigh(protphysaddr));
+ pde7->addrHigh = le32_to_cpu(putPaddrHigh(protphysaddr));
+ pde7->addrLow = le32_to_cpu(putPaddrLow(protphysaddr));
protgrp_blks = protgroup_len / 8;
protgrp_bytes = protgrp_blks * blksize;
@@ -1632,7 +1590,7 @@
protgroup_remainder = 0x1000 - (pde7->addrLow & 0xfff);
protgroup_offset += protgroup_remainder;
protgrp_blks = protgroup_remainder / 8;
- protgrp_bytes = protgroup_remainder * blksize;
+ protgrp_bytes = protgrp_blks * blksize;
} else {
protgroup_offset = 0;
curr_prot++;
@@ -2006,16 +1964,21 @@
if (lpfc_bgs_get_hi_water_mark_present(bgstat)) {
/*
* setup sense data descriptor 0 per SPC-4 as an information
- * field, and put the failing LBA in it
+ * field, and put the failing LBA in it.
+ * This code assumes there was also a guard/app/ref tag error
+ * indication.
*/
- cmd->sense_buffer[8] = 0; /* Information */
- cmd->sense_buffer[9] = 0xa; /* Add. length */
+ cmd->sense_buffer[7] = 0xc; /* Additional sense length */
+ cmd->sense_buffer[8] = 0; /* Information descriptor type */
+ cmd->sense_buffer[9] = 0xa; /* Additional descriptor length */
+ cmd->sense_buffer[10] = 0x80; /* Validity bit */
bghm /= cmd->device->sector_size;
failing_sector = scsi_get_lba(cmd);
failing_sector += bghm;
- put_unaligned_be64(failing_sector, &cmd->sense_buffer[10]);
+ /* Descriptor Information */
+ put_unaligned_be64(failing_sector, &cmd->sense_buffer[12]);
}
if (!ret) {
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 98999bb..5b28ea1 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -560,7 +560,7 @@
rrq = mempool_alloc(phba->rrq_pool, GFP_KERNEL);
if (rrq) {
rrq->send_rrq = send_rrq;
- rrq->xritag = phba->sli4_hba.xri_ids[xritag];
+ rrq->xritag = xritag;
rrq->rrq_stop_time = jiffies + HZ * (phba->fc_ratov + 1);
rrq->ndlp = ndlp;
rrq->nlp_DID = ndlp->nlp_DID;
@@ -2452,7 +2452,8 @@
/* search continue save q for same XRI */
list_for_each_entry(iocbq, &pring->iocb_continue_saveq, clist) {
- if (iocbq->iocb.ulpContext == saveq->iocb.ulpContext) {
+ if (iocbq->iocb.unsli3.rcvsli3.ox_id ==
+ saveq->iocb.unsli3.rcvsli3.ox_id) {
list_add_tail(&saveq->list, &iocbq->list);
found = 1;
break;
@@ -3355,6 +3356,7 @@
irspiocbq);
break;
case CQE_CODE_RECEIVE:
+ case CQE_CODE_RECEIVE_V1:
dmabuf = container_of(cq_event, struct hbq_dmabuf,
cq_event);
lpfc_sli4_handle_received_buffer(phba, dmabuf);
@@ -5837,6 +5839,7 @@
"Advanced Error Reporting (AER)\n");
phba->cfg_aer_support = 0;
}
+ rc = 0;
}
if (!(phba->hba_flag & HBA_FCOE_MODE)) {
@@ -7318,12 +7321,12 @@
bf_set(wqe_qosd, &wqe->els_req.wqe_com, 1);
bf_set(wqe_lenloc, &wqe->els_req.wqe_com, LPFC_WQE_LENLOC_NONE);
bf_set(wqe_ebde_cnt, &wqe->els_req.wqe_com, 0);
- break;
+ break;
case CMD_XMIT_SEQUENCE64_CX:
bf_set(wqe_ctxt_tag, &wqe->xmit_sequence.wqe_com,
iocbq->iocb.un.ulpWord[3]);
bf_set(wqe_rcvoxid, &wqe->xmit_sequence.wqe_com,
- iocbq->iocb.ulpContext);
+ iocbq->iocb.unsli3.rcvsli3.ox_id);
/* The entire sequence is transmitted for this IOCB */
xmit_len = total_len;
cmnd = CMD_XMIT_SEQUENCE64_CR;
@@ -7341,7 +7344,7 @@
bf_set(wqe_ebde_cnt, &wqe->xmit_sequence.wqe_com, 0);
wqe->xmit_sequence.xmit_len = xmit_len;
command_type = OTHER_COMMAND;
- break;
+ break;
case CMD_XMIT_BCAST64_CN:
/* word3 iocb=iotag32 wqe=seq_payload_len */
wqe->xmit_bcast64.seq_payload_len = xmit_len;
@@ -7355,7 +7358,7 @@
bf_set(wqe_lenloc, &wqe->xmit_bcast64.wqe_com,
LPFC_WQE_LENLOC_WORD3);
bf_set(wqe_ebde_cnt, &wqe->xmit_bcast64.wqe_com, 0);
- break;
+ break;
case CMD_FCP_IWRITE64_CR:
command_type = FCP_COMMAND_DATA_OUT;
/* word3 iocb=iotag wqe=payload_offset_len */
@@ -7375,7 +7378,7 @@
LPFC_WQE_LENLOC_WORD4);
bf_set(wqe_ebde_cnt, &wqe->fcp_iwrite.wqe_com, 0);
bf_set(wqe_pu, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpPU);
- break;
+ break;
case CMD_FCP_IREAD64_CR:
/* word3 iocb=iotag wqe=payload_offset_len */
/* Add the FCP_CMD and FCP_RSP sizes to get the offset */
@@ -7394,7 +7397,7 @@
LPFC_WQE_LENLOC_WORD4);
bf_set(wqe_ebde_cnt, &wqe->fcp_iread.wqe_com, 0);
bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpPU);
- break;
+ break;
case CMD_FCP_ICMND64_CR:
/* word3 iocb=IO_TAG wqe=reserved */
wqe->fcp_icmd.rsrvd3 = 0;
@@ -7407,7 +7410,7 @@
bf_set(wqe_lenloc, &wqe->fcp_icmd.wqe_com,
LPFC_WQE_LENLOC_NONE);
bf_set(wqe_ebde_cnt, &wqe->fcp_icmd.wqe_com, 0);
- break;
+ break;
case CMD_GEN_REQUEST64_CR:
/* For this command calculate the xmit length of the
* request bde.
@@ -7442,7 +7445,7 @@
bf_set(wqe_lenloc, &wqe->gen_req.wqe_com, LPFC_WQE_LENLOC_NONE);
bf_set(wqe_ebde_cnt, &wqe->gen_req.wqe_com, 0);
command_type = OTHER_COMMAND;
- break;
+ break;
case CMD_XMIT_ELS_RSP64_CX:
ndlp = (struct lpfc_nodelist *)iocbq->context1;
/* words0-2 BDE memcpy */
@@ -7457,7 +7460,7 @@
((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l));
bf_set(wqe_pu, &wqe->xmit_els_rsp.wqe_com, iocbq->iocb.ulpPU);
bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com,
- iocbq->iocb.ulpContext);
+ iocbq->iocb.unsli3.rcvsli3.ox_id);
if (!iocbq->iocb.ulpCt_h && iocbq->iocb.ulpCt_l)
bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com,
phba->vpi_ids[iocbq->vport->vpi]);
@@ -7470,7 +7473,7 @@
bf_set(wqe_rsp_temp_rpi, &wqe->xmit_els_rsp,
phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]);
command_type = OTHER_COMMAND;
- break;
+ break;
case CMD_CLOSE_XRI_CN:
case CMD_ABORT_XRI_CN:
case CMD_ABORT_XRI_CX:
@@ -7509,7 +7512,7 @@
cmnd = CMD_ABORT_XRI_CX;
command_type = OTHER_COMMAND;
xritag = 0;
- break;
+ break;
case CMD_XMIT_BLS_RSP64_CX:
/* As BLS ABTS RSP WQE is very different from other WQEs,
* we re-construct this WQE here based on information in
@@ -7553,7 +7556,7 @@
bf_get(lpfc_rsn_code, &iocbq->iocb.un.bls_rsp));
}
- break;
+ break;
case CMD_XRI_ABORTED_CX:
case CMD_CREATE_XRI_CR: /* Do we expect to use this? */
case CMD_IOCB_FCP_IBIDIR64_CR: /* bidirectional xfer */
@@ -7565,7 +7568,7 @@
"2014 Invalid command 0x%x\n",
iocbq->iocb.ulpCommand);
return IOCB_ERROR;
- break;
+ break;
}
bf_set(wqe_xri_tag, &wqe->generic.wqe_com, xritag);
@@ -10481,10 +10484,14 @@
struct lpfc_queue *hrq = phba->sli4_hba.hdr_rq;
struct lpfc_queue *drq = phba->sli4_hba.dat_rq;
struct hbq_dmabuf *dma_buf;
- uint32_t status;
+ uint32_t status, rq_id;
unsigned long iflags;
- if (bf_get(lpfc_rcqe_rq_id, rcqe) != hrq->queue_id)
+ if (bf_get(lpfc_cqe_code, rcqe) == CQE_CODE_RECEIVE_V1)
+ rq_id = bf_get(lpfc_rcqe_rq_id_v1, rcqe);
+ else
+ rq_id = bf_get(lpfc_rcqe_rq_id, rcqe);
+ if (rq_id != hrq->queue_id)
goto out;
status = bf_get(lpfc_rcqe_status, rcqe);
@@ -10563,6 +10570,7 @@
(struct sli4_wcqe_xri_aborted *)&cqevt);
break;
case CQE_CODE_RECEIVE:
+ case CQE_CODE_RECEIVE_V1:
/* Process the RQ event */
phba->last_completion_time = jiffies;
workposted = lpfc_sli4_sp_handle_rcqe(phba,
@@ -12345,19 +12353,18 @@
}
/**
- * lpfc_sli4_init_rpi_hdrs - Post the rpi header memory region to the port
+ * lpfc_sli4_alloc_xri - Get an available rpi in the device's range
* @phba: pointer to lpfc hba data structure.
*
* This routine is invoked to post rpi header templates to the
- * port for those SLI4 ports that do not support extents. This routine
- * posts a PAGE_SIZE memory region to the port to hold up to
- * PAGE_SIZE modulo 64 rpi context headers. This is an initialization routine
- * and should be called only when interrupts are disabled.
+ * HBA consistent with the SLI-4 interface spec. This routine
+ * posts a SLI4_PAGE_SIZE memory region to the port to hold up to
+ * SLI4_PAGE_SIZE modulo 64 rpi context headers.
*
- * Return codes
- * 0 - successful
- * -ERROR - otherwise.
- */
+ * Returns
+ * A nonzero rpi defined as rpi_base <= rpi < max_rpi if successful
+ * LPFC_RPI_ALLOC_ERROR if no rpis are available.
+ **/
uint16_t
lpfc_sli4_alloc_xri(struct lpfc_hba *phba)
{
@@ -13406,7 +13413,7 @@
* This function validates the xri maps to the known range of XRIs allocated an
* used by the driver.
**/
-static uint16_t
+uint16_t
lpfc_sli4_xri_inrange(struct lpfc_hba *phba,
uint16_t xri)
{
@@ -13643,10 +13650,12 @@
static struct lpfc_iocbq *
lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
{
+ struct hbq_dmabuf *hbq_buf;
struct lpfc_dmabuf *d_buf, *n_buf;
struct lpfc_iocbq *first_iocbq, *iocbq;
struct fc_frame_header *fc_hdr;
uint32_t sid;
+ uint32_t len, tot_len;
struct ulp_bde64 *pbde;
fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt;
@@ -13655,6 +13664,7 @@
lpfc_update_rcv_time_stamp(vport);
/* get the Remote Port's SID */
sid = sli4_sid_from_fc_hdr(fc_hdr);
+ tot_len = 0;
/* Get an iocbq struct to fill in. */
first_iocbq = lpfc_sli_get_iocbq(vport->phba);
if (first_iocbq) {
@@ -13662,9 +13672,12 @@
first_iocbq->iocb.unsli3.rcvsli3.acc_len = 0;
first_iocbq->iocb.ulpStatus = IOSTAT_SUCCESS;
first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_SEQ64_CX;
- first_iocbq->iocb.ulpContext = be16_to_cpu(fc_hdr->fh_ox_id);
- /* iocbq is prepped for internal consumption. Logical vpi. */
- first_iocbq->iocb.unsli3.rcvsli3.vpi = vport->vpi;
+ first_iocbq->iocb.ulpContext = NO_XRI;
+ first_iocbq->iocb.unsli3.rcvsli3.ox_id =
+ be16_to_cpu(fc_hdr->fh_ox_id);
+ /* iocbq is prepped for internal consumption. Physical vpi. */
+ first_iocbq->iocb.unsli3.rcvsli3.vpi =
+ vport->phba->vpi_ids[vport->vpi];
/* put the first buffer into the first IOCBq */
first_iocbq->context2 = &seq_dmabuf->dbuf;
first_iocbq->context3 = NULL;
@@ -13672,9 +13685,9 @@
first_iocbq->iocb.un.cont64[0].tus.f.bdeSize =
LPFC_DATA_BUF_SIZE;
first_iocbq->iocb.un.rcvels.remoteID = sid;
- first_iocbq->iocb.unsli3.rcvsli3.acc_len +=
- bf_get(lpfc_rcqe_length,
+ tot_len = bf_get(lpfc_rcqe_length,
&seq_dmabuf->cq_event.cqe.rcqe_cmpl);
+ first_iocbq->iocb.unsli3.rcvsli3.acc_len = tot_len;
}
iocbq = first_iocbq;
/*
@@ -13692,9 +13705,13 @@
pbde = (struct ulp_bde64 *)
&iocbq->iocb.unsli3.sli3Words[4];
pbde->tus.f.bdeSize = LPFC_DATA_BUF_SIZE;
- first_iocbq->iocb.unsli3.rcvsli3.acc_len +=
- bf_get(lpfc_rcqe_length,
- &seq_dmabuf->cq_event.cqe.rcqe_cmpl);
+
+ /* We need to get the size out of the right CQE */
+ hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
+ len = bf_get(lpfc_rcqe_length,
+ &hbq_buf->cq_event.cqe.rcqe_cmpl);
+ iocbq->iocb.unsli3.rcvsli3.acc_len += len;
+ tot_len += len;
} else {
iocbq = lpfc_sli_get_iocbq(vport->phba);
if (!iocbq) {
@@ -13712,9 +13729,14 @@
iocbq->iocb.ulpBdeCount = 1;
iocbq->iocb.un.cont64[0].tus.f.bdeSize =
LPFC_DATA_BUF_SIZE;
- first_iocbq->iocb.unsli3.rcvsli3.acc_len +=
- bf_get(lpfc_rcqe_length,
- &seq_dmabuf->cq_event.cqe.rcqe_cmpl);
+
+ /* We need to get the size out of the right CQE */
+ hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
+ len = bf_get(lpfc_rcqe_length,
+ &hbq_buf->cq_event.cqe.rcqe_cmpl);
+ tot_len += len;
+ iocbq->iocb.unsli3.rcvsli3.acc_len = tot_len;
+
iocbq->iocb.un.rcvels.remoteID = sid;
list_add_tail(&iocbq->list, &first_iocbq->list);
}
@@ -13787,7 +13809,13 @@
lpfc_in_buf_free(phba, &dmabuf->dbuf);
return;
}
- fcfi = bf_get(lpfc_rcqe_fcf_id, &dmabuf->cq_event.cqe.rcqe_cmpl);
+ if ((bf_get(lpfc_cqe_code,
+ &dmabuf->cq_event.cqe.rcqe_cmpl) == CQE_CODE_RECEIVE_V1))
+ fcfi = bf_get(lpfc_rcqe_fcf_id_v1,
+ &dmabuf->cq_event.cqe.rcqe_cmpl);
+ else
+ fcfi = bf_get(lpfc_rcqe_fcf_id,
+ &dmabuf->cq_event.cqe.rcqe_cmpl);
vport = lpfc_fc_frame_to_vport(phba, fc_hdr, fcfi);
if (!vport || !(vport->vpi_state & LPFC_VPI_REGISTERED)) {
/* throw out the frame */
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index 4b17035..88387c1 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -81,6 +81,8 @@
(fc_hdr)->fh_f_ctl[1] << 8 | \
(fc_hdr)->fh_f_ctl[2])
+#define LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT 12000
+
enum lpfc_sli4_queue_type {
LPFC_EQ,
LPFC_GCQ,
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index efa0255..83035bd 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -94,7 +94,7 @@
MODULE_PARM_DESC(diag_buffer_enable, " post diag buffers "
"(TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)");
-int mpt2sas_fwfault_debug;
+static int mpt2sas_fwfault_debug;
MODULE_PARM_DESC(mpt2sas_fwfault_debug, " enable detection of firmware fault "
"and halt firmware - (default=0)");
@@ -857,7 +857,7 @@
completed_cmds = 0;
cb_idx = 0xFF;
do {
- rd.word = rpf->Words;
+ rd.word = le64_to_cpu(rpf->Words);
if (rd.u.low == UINT_MAX || rd.u.high == UINT_MAX)
goto out;
reply = 0;
@@ -906,7 +906,7 @@
next:
- rpf->Words = ULLONG_MAX;
+ rpf->Words = cpu_to_le64(ULLONG_MAX);
ioc->reply_post_host_index = (ioc->reply_post_host_index ==
(ioc->reply_post_queue_depth - 1)) ? 0 :
ioc->reply_post_host_index + 1;
@@ -1740,9 +1740,11 @@
static void
_base_display_intel_branding(struct MPT2SAS_ADAPTER *ioc)
{
- if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_INTEL &&
- ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008) {
+ if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_INTEL)
+ return;
+ switch (ioc->pdev->device) {
+ case MPI2_MFGPAGE_DEVID_SAS2008:
switch (ioc->pdev->subsystem_device) {
case MPT2SAS_INTEL_RMS2LL080_SSDID:
printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
@@ -1752,7 +1754,20 @@
printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
MPT2SAS_INTEL_RMS2LL040_BRANDING);
break;
+ default:
+ break;
}
+ case MPI2_MFGPAGE_DEVID_SAS2308_2:
+ switch (ioc->pdev->subsystem_device) {
+ case MPT2SAS_INTEL_RS25GB008_SSDID:
+ printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
+ MPT2SAS_INTEL_RS25GB008_BRANDING);
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
}
}
@@ -1817,7 +1832,9 @@
char desc[16];
u8 revision;
u32 iounit_pg1_flags;
+ u32 bios_version;
+ bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion);
pci_read_config_byte(ioc->pdev, PCI_CLASS_REVISION, &revision);
strncpy(desc, ioc->manu_pg0.ChipName, 16);
printk(MPT2SAS_INFO_FMT "%s: FWVersion(%02d.%02d.%02d.%02d), "
@@ -1828,10 +1845,10 @@
(ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
ioc->facts.FWVersion.Word & 0x000000FF,
revision,
- (ioc->bios_pg3.BiosVersion & 0xFF000000) >> 24,
- (ioc->bios_pg3.BiosVersion & 0x00FF0000) >> 16,
- (ioc->bios_pg3.BiosVersion & 0x0000FF00) >> 8,
- ioc->bios_pg3.BiosVersion & 0x000000FF);
+ (bios_version & 0xFF000000) >> 24,
+ (bios_version & 0x00FF0000) >> 16,
+ (bios_version & 0x0000FF00) >> 8,
+ bios_version & 0x000000FF);
_base_display_dell_branding(ioc);
_base_display_intel_branding(ioc);
@@ -2150,7 +2167,7 @@
static int
_base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
{
- Mpi2IOCFactsReply_t *facts;
+ struct mpt2sas_facts *facts;
u32 queue_size, queue_diff;
u16 max_sge_elements;
u16 num_of_reply_frames;
@@ -2783,7 +2800,7 @@
int i;
u8 failed;
u16 dummy;
- u32 *mfp;
+ __le32 *mfp;
/* make sure doorbell is not in use */
if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) {
@@ -2871,7 +2888,7 @@
writel(0, &ioc->chip->HostInterruptStatus);
if (ioc->logging_level & MPT_DEBUG_INIT) {
- mfp = (u32 *)reply;
+ mfp = (__le32 *)reply;
printk(KERN_INFO "\toffset:data\n");
for (i = 0; i < reply_bytes/4; i++)
printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4,
@@ -3097,7 +3114,8 @@
_base_get_port_facts(struct MPT2SAS_ADAPTER *ioc, int port, int sleep_flag)
{
Mpi2PortFactsRequest_t mpi_request;
- Mpi2PortFactsReply_t mpi_reply, *pfacts;
+ Mpi2PortFactsReply_t mpi_reply;
+ struct mpt2sas_port_facts *pfacts;
int mpi_reply_sz, mpi_request_sz, r;
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
@@ -3139,7 +3157,8 @@
_base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
{
Mpi2IOCFactsRequest_t mpi_request;
- Mpi2IOCFactsReply_t mpi_reply, *facts;
+ Mpi2IOCFactsReply_t mpi_reply;
+ struct mpt2sas_facts *facts;
int mpi_reply_sz, mpi_request_sz, r;
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
@@ -3225,17 +3244,6 @@
mpi_request.MsgVersion = cpu_to_le16(MPI2_VERSION);
mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION);
- /* In MPI Revision I (0xA), the SystemReplyFrameSize(offset 0x18) was
- * removed and made reserved. For those with older firmware will need
- * this fix. It was decided that the Reply and Request frame sizes are
- * the same.
- */
- if ((ioc->facts.HeaderVersion >> 8) < 0xA) {
- mpi_request.Reserved7 = cpu_to_le16(ioc->reply_sz);
-/* mpi_request.SystemReplyFrameSize =
- * cpu_to_le16(ioc->reply_sz);
- */
- }
mpi_request.SystemRequestFrameSize = cpu_to_le16(ioc->request_sz/4);
mpi_request.ReplyDescriptorPostQueueDepth =
@@ -3243,25 +3251,17 @@
mpi_request.ReplyFreeQueueDepth =
cpu_to_le16(ioc->reply_free_queue_depth);
-#if BITS_PER_LONG > 32
mpi_request.SenseBufferAddressHigh =
- cpu_to_le32(ioc->sense_dma >> 32);
+ cpu_to_le32((u64)ioc->sense_dma >> 32);
mpi_request.SystemReplyAddressHigh =
- cpu_to_le32(ioc->reply_dma >> 32);
+ cpu_to_le32((u64)ioc->reply_dma >> 32);
mpi_request.SystemRequestFrameBaseAddress =
- cpu_to_le64(ioc->request_dma);
+ cpu_to_le64((u64)ioc->request_dma);
mpi_request.ReplyFreeQueueAddress =
- cpu_to_le64(ioc->reply_free_dma);
+ cpu_to_le64((u64)ioc->reply_free_dma);
mpi_request.ReplyDescriptorPostQueueAddress =
- cpu_to_le64(ioc->reply_post_free_dma);
-#else
- mpi_request.SystemRequestFrameBaseAddress =
- cpu_to_le32(ioc->request_dma);
- mpi_request.ReplyFreeQueueAddress =
- cpu_to_le32(ioc->reply_free_dma);
- mpi_request.ReplyDescriptorPostQueueAddress =
- cpu_to_le32(ioc->reply_post_free_dma);
-#endif
+ cpu_to_le64((u64)ioc->reply_post_free_dma);
+
/* This time stamp specifies number of milliseconds
* since epoch ~ midnight January 1, 1970.
@@ -3271,10 +3271,10 @@
(current_time.tv_usec / 1000));
if (ioc->logging_level & MPT_DEBUG_INIT) {
- u32 *mfp;
+ __le32 *mfp;
int i;
- mfp = (u32 *)&mpi_request;
+ mfp = (__le32 *)&mpi_request;
printk(KERN_INFO "\toffset:data\n");
for (i = 0; i < sizeof(Mpi2IOCInitRequest_t)/4; i++)
printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4,
@@ -3759,7 +3759,7 @@
/* initialize Reply Post Free Queue */
for (i = 0; i < ioc->reply_post_queue_depth; i++)
- ioc->reply_post_free[i].Words = ULLONG_MAX;
+ ioc->reply_post_free[i].Words = cpu_to_le64(ULLONG_MAX);
r = _base_send_ioc_init(ioc, sleep_flag);
if (r)
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
index dcc289c..41a57a7 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -161,12 +161,15 @@
"Intel Integrated RAID Module RMS2LL080"
#define MPT2SAS_INTEL_RMS2LL040_BRANDING \
"Intel Integrated RAID Module RMS2LL040"
+#define MPT2SAS_INTEL_RS25GB008_BRANDING \
+ "Intel(R) RAID Controller RS25GB008"
/*
* Intel HBA SSDIDs
*/
#define MPT2SAS_INTEL_RMS2LL080_SSDID 0x350E
#define MPT2SAS_INTEL_RMS2LL040_SSDID 0x350F
+#define MPT2SAS_INTEL_RS25GB008_SSDID 0x3000
/*
@@ -541,6 +544,53 @@
typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
+/* IOC Facts and Port Facts converted from little endian to cpu */
+union mpi2_version_union {
+ MPI2_VERSION_STRUCT Struct;
+ u32 Word;
+};
+
+struct mpt2sas_facts {
+ u16 MsgVersion;
+ u16 HeaderVersion;
+ u8 IOCNumber;
+ u8 VP_ID;
+ u8 VF_ID;
+ u16 IOCExceptions;
+ u16 IOCStatus;
+ u32 IOCLogInfo;
+ u8 MaxChainDepth;
+ u8 WhoInit;
+ u8 NumberOfPorts;
+ u8 MaxMSIxVectors;
+ u16 RequestCredit;
+ u16 ProductID;
+ u32 IOCCapabilities;
+ union mpi2_version_union FWVersion;
+ u16 IOCRequestFrameSize;
+ u16 Reserved3;
+ u16 MaxInitiators;
+ u16 MaxTargets;
+ u16 MaxSasExpanders;
+ u16 MaxEnclosures;
+ u16 ProtocolFlags;
+ u16 HighPriorityCredit;
+ u16 MaxReplyDescriptorPostQueueDepth;
+ u8 ReplyFrameSize;
+ u8 MaxVolumes;
+ u16 MaxDevHandle;
+ u16 MaxPersistentEntries;
+ u16 MinDevHandle;
+};
+
+struct mpt2sas_port_facts {
+ u8 PortNumber;
+ u8 VP_ID;
+ u8 VF_ID;
+ u8 PortType;
+ u16 MaxPostedCmdBuffers;
+};
+
/**
* struct MPT2SAS_ADAPTER - per adapter struct
* @list: ioc_list
@@ -749,8 +799,8 @@
u32 event_masks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];
/* static config pages */
- Mpi2IOCFactsReply_t facts;
- Mpi2PortFactsReply_t *pfacts;
+ struct mpt2sas_facts facts;
+ struct mpt2sas_port_facts *pfacts;
Mpi2ManufacturingPage0_t manu_pg0;
Mpi2BiosPage2_t bios_pg2;
Mpi2BiosPage3_t bios_pg3;
@@ -840,7 +890,7 @@
/* reply free queue */
u16 reply_free_queue_depth;
- u32 *reply_free;
+ __le32 *reply_free;
dma_addr_t reply_free_dma;
struct dma_pool *reply_free_dma_pool;
u32 reply_free_host_index;
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
index 437c2d9..d1c3bba 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
@@ -2706,13 +2706,13 @@
_ctl_ioc_reset_count_show, NULL);
struct DIAG_BUFFER_START {
- u32 Size;
- u32 DiagVersion;
+ __le32 Size;
+ __le32 DiagVersion;
u8 BufferType;
u8 Reserved[3];
- u32 Reserved1;
- u32 Reserved2;
- u32 Reserved3;
+ __le32 Reserved1;
+ __le32 Reserved2;
+ __le32 Reserved3;
};
/**
* _ctl_host_trace_buffer_size_show - host buffer size (trace only)
diff --git a/drivers/scsi/mpt2sas/mpt2sas_debug.h b/drivers/scsi/mpt2sas/mpt2sas_debug.h
index 3dcddfe..9731f8e 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_debug.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_debug.h
@@ -164,7 +164,7 @@
_debug_dump_mf(void *mpi_request, int sz)
{
int i;
- u32 *mfp = (u32 *)mpi_request;
+ __le32 *mfp = (__le32 *)mpi_request;
printk(KERN_INFO "mf:\n\t");
for (i = 0; i < sz; i++) {
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index a7dbc68..8dc2ad4 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -1956,7 +1956,7 @@
case MPI2_RAID_VOL_TYPE_RAID1E:
qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
if (ioc->manu_pg10.OEMIdentifier &&
- (ioc->manu_pg10.GenericFlags0 &
+ (le32_to_cpu(ioc->manu_pg10.GenericFlags0) &
MFG10_GF0_R10_DISPLAY) &&
!(raid_device->num_pds % 2))
r_level = "RAID10";
@@ -3698,7 +3698,7 @@
return 0;
}
- if (ioc->pci_error_recovery) {
+ if (ioc->pci_error_recovery || ioc->remove_host) {
scmd->result = DID_NO_CONNECT << 16;
scmd->scsi_done(scmd);
return 0;
@@ -4598,7 +4598,7 @@
Mpi2SasEnclosurePage0_t enclosure_pg0;
u32 ioc_status;
u16 parent_handle;
- __le64 sas_address, sas_address_parent = 0;
+ u64 sas_address, sas_address_parent = 0;
int i;
unsigned long flags;
struct _sas_port *mpt2sas_port = NULL;
@@ -5404,7 +5404,7 @@
{
struct MPT2SAS_TARGET *target_priv_data;
struct _sas_device *sas_device;
- __le64 sas_address;
+ u64 sas_address;
unsigned long flags;
Mpi2EventDataSasDeviceStatusChange_t *event_data =
fw_event->event_data;
@@ -6566,7 +6566,7 @@
Mpi2ExpanderPage0_t expander_pg0;
Mpi2ConfigReply_t mpi_reply;
u16 ioc_status;
- __le64 sas_address;
+ u64 sas_address;
u16 handle;
printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
@@ -7211,7 +7211,6 @@
}
sas_remove_host(shost);
- _scsih_shutdown(pdev);
list_del(&ioc->list);
scsi_remove_host(shost);
scsi_host_put(shost);
@@ -7505,7 +7504,7 @@
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- u32 device_state;
+ pci_power_t device_state;
mpt2sas_base_stop_watchdog(ioc);
scsi_block_requests(shost);
@@ -7532,7 +7531,7 @@
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- u32 device_state = pdev->current_state;
+ pci_power_t device_state = pdev->current_state;
int r;
printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, previous "
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c
index cb1cdec..15c7980 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_transport.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c
@@ -299,7 +299,6 @@
void *data_out = NULL;
dma_addr_t data_out_dma;
u32 sz;
- u64 *sas_address_le;
u16 wait_state_count;
if (ioc->shost_recovery || ioc->pci_error_recovery) {
@@ -372,8 +371,7 @@
mpi_request->PhysicalPort = 0xFF;
mpi_request->VF_ID = 0; /* TODO */
mpi_request->VP_ID = 0;
- sas_address_le = (u64 *)&mpi_request->SASAddress;
- *sas_address_le = cpu_to_le64(sas_address);
+ mpi_request->SASAddress = cpu_to_le64(sas_address);
mpi_request->RequestDataLength =
cpu_to_le16(sizeof(struct rep_manu_request));
psge = &mpi_request->SGL;
@@ -1049,14 +1047,14 @@
u8 function; /* 0x11 */
u8 function_result;
u8 response_length;
- u16 expander_change_count;
+ __be16 expander_change_count;
u8 reserved_1[3];
u8 phy_identifier;
u8 reserved_2[2];
- u32 invalid_dword;
- u32 running_disparity_error;
- u32 loss_of_dword_sync;
- u32 phy_reset_problem;
+ __be32 invalid_dword;
+ __be32 running_disparity_error;
+ __be32 loss_of_dword_sync;
+ __be32 phy_reset_problem;
};
/**
@@ -1085,7 +1083,6 @@
void *data_out = NULL;
dma_addr_t data_out_dma;
u32 sz;
- u64 *sas_address_le;
u16 wait_state_count;
if (ioc->shost_recovery || ioc->pci_error_recovery) {
@@ -1160,8 +1157,7 @@
mpi_request->PhysicalPort = 0xFF;
mpi_request->VF_ID = 0; /* TODO */
mpi_request->VP_ID = 0;
- sas_address_le = (u64 *)&mpi_request->SASAddress;
- *sas_address_le = cpu_to_le64(phy->identify.sas_address);
+ mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address);
mpi_request->RequestDataLength =
cpu_to_le16(sizeof(struct phy_error_log_request));
psge = &mpi_request->SGL;
@@ -1406,7 +1402,6 @@
void *data_out = NULL;
dma_addr_t data_out_dma;
u32 sz;
- u64 *sas_address_le;
u16 wait_state_count;
if (ioc->shost_recovery) {
@@ -1486,8 +1481,7 @@
mpi_request->PhysicalPort = 0xFF;
mpi_request->VF_ID = 0; /* TODO */
mpi_request->VP_ID = 0;
- sas_address_le = (u64 *)&mpi_request->SASAddress;
- *sas_address_le = cpu_to_le64(phy->identify.sas_address);
+ mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address);
mpi_request->RequestDataLength =
cpu_to_le16(sizeof(struct phy_error_log_request));
psge = &mpi_request->SGL;
@@ -1914,7 +1908,7 @@
mpi_request->PhysicalPort = 0xFF;
mpi_request->VF_ID = 0; /* TODO */
mpi_request->VP_ID = 0;
- *((u64 *)&mpi_request->SASAddress) = (rphy) ?
+ mpi_request->SASAddress = (rphy) ?
cpu_to_le64(rphy->identify.sas_address) :
cpu_to_le64(ioc->sas_hba.sas_address);
mpi_request->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4);
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 920b76b..b2df2f9 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -3822,15 +3822,12 @@
req = vha->req;
rsp = req->rsp;
- atomic_set(&vha->loop_state, LOOP_UPDATE);
clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
if (vha->flags.online) {
if (!(rval = qla2x00_fw_ready(vha))) {
/* Wait at most MAX_TARGET RSCNs for a stable link. */
wait_time = 256;
do {
- atomic_set(&vha->loop_state, LOOP_UPDATE);
-
/* Issue a marker after FW becomes ready. */
qla2x00_marker(vha, req, rsp, 0, 0,
MK_SYNC_ALL);
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 1b60a95..e0fa877 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -736,7 +736,6 @@
vha->flags.rscn_queue_overflow = 1;
}
- atomic_set(&vha->loop_state, LOOP_UPDATE);
atomic_set(&vha->loop_down_timer, 0);
vha->flags.management_server_logged_in = 0;
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index f461925..a2a1a83 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -1240,10 +1240,9 @@
qla2x00_sp_compl(ha, sp);
} else {
ctx = sp->ctx;
- if (ctx->type == SRB_LOGIN_CMD ||
- ctx->type == SRB_LOGOUT_CMD) {
- ctx->u.iocb_cmd->free(sp);
- } else {
+ if (ctx->type == SRB_ELS_CMD_RPT ||
+ ctx->type == SRB_ELS_CMD_HST ||
+ ctx->type == SRB_CT_CMD) {
struct fc_bsg_job *bsg_job =
ctx->u.bsg_job;
if (bsg_job->request->msgcode
@@ -1255,6 +1254,8 @@
kfree(sp->ctx);
mempool_free(sp,
ha->srb_mempool);
+ } else {
+ ctx->u.iocb_cmd->free(sp);
}
}
}
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index 6aa111c..90e2687 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -993,8 +993,14 @@
e_addr[2] != QC_CHIPID_SL)
dev->pgdla = laddr;
if (!ret && !pm_runtime_enabled(dev->dev) &&
- laddr == (QC_MSM_DEVS - 1))
+ laddr == (QC_MSM_DEVS - 1)) {
pm_runtime_enable(dev->dev);
+ /*
+ * Avoid runtime-PM by default, but allow
+ * command line activation
+ */
+ pm_runtime_forbid(dev->dev);
+ }
} else if (mc == SLIM_MSG_MC_REPLY_INFORMATION ||
mc == SLIM_MSG_MC_REPLY_VALUE) {
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 86d5195..70131fa 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -35,6 +35,8 @@
#include <linux/oom.h>
#include <linux/sched.h>
#include <linux/notifier.h>
+#include <linux/memory.h>
+#include <linux/memory_hotplug.h>
static uint32_t lowmem_debug_level = 2;
static int lowmem_adj[6] = {
@@ -52,6 +54,7 @@
};
static int lowmem_minfree_size = 4;
+static unsigned int offlining;
static struct task_struct *lowmem_deathpending;
static unsigned long lowmem_deathpending_timeout;
@@ -79,6 +82,32 @@
return NOTIFY_OK;
}
+#ifdef CONFIG_MEMORY_HOTPLUG
+static int lmk_hotplug_callback(struct notifier_block *self,
+ unsigned long cmd, void *data)
+{
+ switch (cmd) {
+ /* Don't care LMK cases */
+ case MEM_ONLINE:
+ case MEM_OFFLINE:
+ case MEM_CANCEL_ONLINE:
+ case MEM_CANCEL_OFFLINE:
+ case MEM_GOING_ONLINE:
+ offlining = 0;
+ lowmem_print(4, "lmk in normal mode\n");
+ break;
+ /* LMK should account for movable zone */
+ case MEM_GOING_OFFLINE:
+ offlining = 1;
+ lowmem_print(4, "lmk in hotplug mode\n");
+ break;
+ }
+ return NOTIFY_DONE;
+}
+#endif
+
+
+
static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
{
struct task_struct *p;
@@ -93,7 +122,20 @@
int other_free = global_page_state(NR_FREE_PAGES);
int other_file = global_page_state(NR_FILE_PAGES) -
global_page_state(NR_SHMEM);
+ struct zone *zone;
+ if (offlining) {
+ /* Discount all free space in the section being offlined */
+ for_each_zone(zone) {
+ if (zone_idx(zone) == ZONE_MOVABLE) {
+ other_free -= zone_page_state(zone,
+ NR_FREE_PAGES);
+ lowmem_print(4, "lowmem_shrink discounted "
+ "%lu pages in movable zone\n",
+ zone_page_state(zone, NR_FREE_PAGES));
+ }
+ }
+ }
/*
* If we already have a death outstanding, then
* bail out right away; indicating to vmscan
@@ -190,6 +232,9 @@
{
task_free_register(&task_nb);
register_shrinker(&lowmem_shrinker);
+#ifdef CONFIG_MEMORY_HOTPLUG
+ hotplug_memory_notifier(lmk_hotplug_callback, 0);
+#endif
return 0;
}
diff --git a/drivers/staging/android/ram_console.c b/drivers/staging/android/ram_console.c
index 53f736b..cb42d89 100644
--- a/drivers/staging/android/ram_console.c
+++ b/drivers/staging/android/ram_console.c
@@ -21,6 +21,7 @@
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/io.h>
+#include <linux/platform_data/ram_console.h>
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
#include <linux/rslib.h>
@@ -155,14 +156,20 @@
}
static void __init
-ram_console_save_old(struct ram_console_buffer *buffer, char *dest)
+ram_console_save_old(struct ram_console_buffer *buffer, const char *bootinfo,
+ char *dest)
{
size_t old_log_size = buffer->size;
+ size_t bootinfo_size = 0;
+ size_t total_size = old_log_size;
+ char *ptr;
+ const char *bootinfo_label = "Boot info:\n";
+
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
uint8_t *block;
uint8_t *par;
char strbuf[80];
- int strbuf_len;
+ int strbuf_len = 0;
block = buffer->data;
par = ram_console_par_buffer;
@@ -197,11 +204,15 @@
"\nNo errors detected\n");
if (strbuf_len >= sizeof(strbuf))
strbuf_len = sizeof(strbuf) - 1;
- old_log_size += strbuf_len;
+ total_size += strbuf_len;
#endif
+ if (bootinfo)
+ bootinfo_size = strlen(bootinfo) + strlen(bootinfo_label);
+ total_size += bootinfo_size;
+
if (dest == NULL) {
- dest = kmalloc(old_log_size, GFP_KERNEL);
+ dest = kmalloc(total_size, GFP_KERNEL);
if (dest == NULL) {
printk(KERN_ERR
"ram_console: failed to allocate buffer\n");
@@ -210,19 +221,27 @@
}
ram_console_old_log = dest;
- ram_console_old_log_size = old_log_size;
+ ram_console_old_log_size = total_size;
memcpy(ram_console_old_log,
&buffer->data[buffer->start], buffer->size - buffer->start);
memcpy(ram_console_old_log + buffer->size - buffer->start,
&buffer->data[0], buffer->start);
+ ptr = ram_console_old_log + old_log_size;
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
- memcpy(ram_console_old_log + old_log_size - strbuf_len,
- strbuf, strbuf_len);
+ memcpy(ptr, strbuf, strbuf_len);
+ ptr += strbuf_len;
#endif
+ if (bootinfo) {
+ memcpy(ptr, bootinfo_label, strlen(bootinfo_label));
+ ptr += strlen(bootinfo_label);
+ memcpy(ptr, bootinfo, bootinfo_size);
+ ptr += bootinfo_size;
+ }
}
static int __init ram_console_init(struct ram_console_buffer *buffer,
- size_t buffer_size, char *old_buf)
+ size_t buffer_size, const char *bootinfo,
+ char *old_buf)
{
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
int numerr;
@@ -289,7 +308,7 @@
printk(KERN_INFO "ram_console: found existing buffer, "
"size %d, start %d\n",
buffer->size, buffer->start);
- ram_console_save_old(buffer, old_buf);
+ ram_console_save_old(buffer, bootinfo, old_buf);
}
} else {
printk(KERN_INFO "ram_console: no valid data in buffer "
@@ -313,6 +332,7 @@
return ram_console_init((struct ram_console_buffer *)
CONFIG_ANDROID_RAM_CONSOLE_EARLY_ADDR,
CONFIG_ANDROID_RAM_CONSOLE_EARLY_SIZE,
+ NULL,
ram_console_old_log_init_buffer);
}
#else
@@ -322,6 +342,8 @@
size_t start;
size_t buffer_size;
void *buffer;
+ const char *bootinfo = NULL;
+ struct ram_console_platform_data *pdata = pdev->dev.platform_data;
if (res == NULL || pdev->num_resources != 1 ||
!(res->flags & IORESOURCE_MEM)) {
@@ -339,7 +361,10 @@
return -ENOMEM;
}
- return ram_console_init(buffer, buffer_size, NULL/* allocate */);
+ if (pdata)
+ bootinfo = pdata->bootinfo;
+
+ return ram_console_init(buffer, buffer_size, bootinfo, NULL/* allocate */);
}
static struct platform_driver ram_console_driver = {
diff --git a/drivers/staging/ath6kl/os/linux/ar6000_drv.c b/drivers/staging/ath6kl/os/linux/ar6000_drv.c
index aa97efc..62487a7 100644
--- a/drivers/staging/ath6kl/os/linux/ar6000_drv.c
+++ b/drivers/staging/ath6kl/os/linux/ar6000_drv.c
@@ -6198,6 +6198,7 @@
ether_setup(dev);
init_netdev(dev, ap_ifname);
+ dev->priv_flags &= ~IFF_TX_SKB_SHARING;
if (register_netdev(dev)) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("ar6000_create_ap_interface: register_netdev failed\n"));
diff --git a/drivers/staging/gobi/QCUSBNet2k/Makefile b/drivers/staging/gobi/QCUSBNet2k/Makefile
old mode 100755
new mode 100644
diff --git a/drivers/staging/rtl8192u/r819xU_firmware.c b/drivers/staging/rtl8192u/r819xU_firmware.c
index 6766f46..4bb5fff 100644
--- a/drivers/staging/rtl8192u/r819xU_firmware.c
+++ b/drivers/staging/rtl8192u/r819xU_firmware.c
@@ -399,10 +399,7 @@
}
-
-
-
-
-
-
+MODULE_FIRMWARE("RTL8192U/boot.img");
+MODULE_FIRMWARE("RTL8192U/main.img");
+MODULE_FIRMWARE("RTL8192U/data.img");
diff --git a/drivers/thermal/msm8960_tsens.c b/drivers/thermal/msm8960_tsens.c
index 0accb32..63d8666 100644
--- a/drivers/thermal/msm8960_tsens.c
+++ b/drivers/thermal/msm8960_tsens.c
@@ -99,6 +99,7 @@
#define TSENS_SENSOR_SHIFT 16
#define TSENS_RED_SHIFT 8
#define TSENS_8960_QFPROM_SHIFT 4
+#define TSENS_SENSOR_QFPROM_SHIFT 2
#define TSENS_SENSOR0_SHIFT 3
#define TSENS_MASK1 1
@@ -680,12 +681,12 @@
for (i = 0; i < tmdev->tsens_num_sensor; i++) {
main_sensor_addr = TSENS_8960_QFPROM_ADDR0 +
(TSENS_8960_QFPROM_SHIFT *
- (i & TSENS_8960_QFPROM_SHIFT >> TSENS_SENSOR0_SHIFT));
+ ((i & TSENS_8960_QFPROM_SHIFT) >> TSENS_SENSOR_QFPROM_SHIFT));
sensor_shift = (i % TSENS_8960_QFPROM_SHIFT) * TSENS_RED_SHIFT;
sensor_mask = TSENS_THRESHOLD_MAX_CODE << sensor_shift;
backup_sensor_addr = TSENS_8960_QFPROM_SPARE_ADDR0 +
(TSENS_8960_QFPROM_SHIFT *
- (i & TSENS_8960_QFPROM_SHIFT >> TSENS_SENSOR0_SHIFT));
+ ((i & TSENS_8960_QFPROM_SHIFT) >> TSENS_SENSOR_QFPROM_SHIFT));
tmdev->sensor[i].calib_data = (readl_relaxed(main_sensor_addr)
& sensor_mask) >> sensor_shift;
diff --git a/drivers/thermal/pm8xxx-tm.c b/drivers/thermal/pm8xxx-tm.c
index d9f9c9e..50238f3 100644
--- a/drivers/thermal/pm8xxx-tm.c
+++ b/drivers/thermal/pm8xxx-tm.c
@@ -29,7 +29,8 @@
#include <linux/mfd/pm8xxx/core.h>
#include <linux/mfd/pm8xxx/tm.h>
#include <linux/completion.h>
-#include <linux/mfd/pm8xxx/pm8921-adc.h>
+#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
+#include <linux/msm_adc.h>
/* Register TEMP_ALARM_CTRL bits */
#define TEMP_ALARM_CTRL_ST3_SD 0x80
@@ -226,11 +227,12 @@
return 0;
}
-static int pm8xxx_tz_get_temp_pm8921_adc(struct thermal_zone_device *thermal,
- unsigned long *temp)
+static int pm8xxx_tz_get_temp_pm8058_adc(struct thermal_zone_device *thermal,
+ unsigned long *temp)
{
struct pm8xxx_tm_chip *chip = thermal->devdata;
- struct pm8921_adc_chan_result result = {
+ DECLARE_COMPLETION_ONSTACK(wait);
+ struct adc_chan_result adc_result = {
.physical = 0lu,
};
int rc;
@@ -240,7 +242,43 @@
*temp = chip->temp;
- rc = pm8921_adc_read(chip->cdata.adc_channel, &result);
+ rc = adc_channel_request_conv(chip->adc_handle, &wait);
+ if (rc < 0) {
+ pr_err("%s: adc_channel_request_conv() failed, rc = %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ wait_for_completion(&wait);
+
+ rc = adc_channel_read_result(chip->adc_handle, &adc_result);
+ if (rc < 0) {
+ pr_err("%s: adc_channel_read_result() failed, rc = %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ *temp = adc_result.physical;
+ chip->temp = adc_result.physical;
+
+ return 0;
+}
+
+static int pm8xxx_tz_get_temp_pm8xxx_adc(struct thermal_zone_device *thermal,
+ unsigned long *temp)
+{
+ struct pm8xxx_tm_chip *chip = thermal->devdata;
+ struct pm8xxx_adc_chan_result result = {
+ .physical = 0lu,
+ };
+ int rc;
+
+ if (!chip || !temp)
+ return -EINVAL;
+
+ *temp = chip->temp;
+
+ rc = pm8xxx_adc_read(chip->cdata.adc_channel, &result);
if (rc < 0) {
pr_err("%s: adc_channel_read_result() failed, rc = %d\n",
chip->cdata.tm_name, rc);
@@ -363,8 +401,17 @@
.get_crit_temp = pm8xxx_tz_get_crit_temp,
};
-static struct thermal_zone_device_ops pm8xxx_thermal_zone_ops_pm8921_adc = {
- .get_temp = pm8xxx_tz_get_temp_pm8921_adc,
+static struct thermal_zone_device_ops pm8xxx_thermal_zone_ops_pm8xxx_adc = {
+ .get_temp = pm8xxx_tz_get_temp_pm8xxx_adc,
+ .get_mode = pm8xxx_tz_get_mode,
+ .set_mode = pm8xxx_tz_set_mode,
+ .get_trip_type = pm8xxx_tz_get_trip_type,
+ .get_trip_temp = pm8xxx_tz_get_trip_temp,
+ .get_crit_temp = pm8xxx_tz_get_crit_temp,
+};
+
+static struct thermal_zone_device_ops pm8xxx_thermal_zone_ops_pm8058_adc = {
+ .get_temp = pm8xxx_tz_get_temp_pm8058_adc,
.get_mode = pm8xxx_tz_get_mode,
.set_mode = pm8xxx_tz_set_mode,
.get_trip_type = pm8xxx_tz_get_trip_type,
@@ -465,6 +512,24 @@
return rc;
}
+static int pm8xxx_init_adc(struct pm8xxx_tm_chip *chip, bool enable)
+{
+ int rc = 0;
+
+ if (chip->cdata.adc_type == PM8XXX_TM_ADC_PM8058_ADC) {
+ if (enable) {
+ rc = adc_channel_open(chip->cdata.adc_channel,
+ &(chip->adc_handle));
+ if (rc < 0)
+ pr_err("adc_channel_open() failed.\n");
+ } else {
+ adc_channel_close(chip->adc_handle);
+ }
+ }
+
+ return rc;
+}
+
static int __devinit pm8xxx_tm_probe(struct platform_device *pdev)
{
const struct pm8xxx_tm_core_data *cdata = pdev->dev.platform_data;
@@ -505,18 +570,27 @@
goto err_free_chip;
}
+ rc = pm8xxx_init_adc(chip, true);
+ if (rc < 0) {
+ pr_err("Unable to initialize adc\n");
+ goto err_free_chip;
+ }
+
/* Select proper thermal zone ops functions based on ADC type. */
- if (chip->cdata.adc_type == PM8XXX_TM_ADC_PM8921_ADC)
- tz_ops = &pm8xxx_thermal_zone_ops_pm8921_adc;
+ if (chip->cdata.adc_type == PM8XXX_TM_ADC_PM8XXX_ADC)
+ tz_ops = &pm8xxx_thermal_zone_ops_pm8xxx_adc;
+ else if (chip->cdata.adc_type == PM8XXX_TM_ADC_PM8058_ADC)
+ tz_ops = &pm8xxx_thermal_zone_ops_pm8058_adc;
else
tz_ops = &pm8xxx_thermal_zone_ops_no_adc;
chip->tz_dev = thermal_zone_device_register(chip->cdata.tm_name,
TRIP_NUM, chip, tz_ops, 0, 0, 0, 0);
+
if (chip->tz_dev == NULL) {
pr_err("thermal_zone_device_register() failed.\n");
rc = -ENODEV;
- goto err_free_chip;
+ goto err_fail_adc;
}
rc = pm8xxx_tm_init_reg(chip);
@@ -564,6 +638,8 @@
cancel_work_sync(&chip->irq_work);
err_free_tz:
thermal_zone_device_unregister(chip->tz_dev);
+err_fail_adc:
+ pm8xxx_init_adc(chip, false);
err_free_chip:
kfree(chip);
return rc;
@@ -579,6 +655,7 @@
free_irq(chip->overtemp_irq, chip);
free_irq(chip->tempstat_irq, chip);
pm8xxx_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_DISABLED);
+ pm8xxx_init_adc(chip, false);
thermal_zone_device_unregister(chip->tz_dev);
kfree(chip);
}
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 98b6e3b..e809e9d 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -446,8 +446,19 @@
int pty_limit = NR_UNIX98_PTY_DEFAULT;
static int pty_limit_min;
static int pty_limit_max = NR_UNIX98_PTY_MAX;
+static int tty_count;
static int pty_count;
+static inline void pty_inc_count(void)
+{
+ pty_count = (++tty_count) / 2;
+}
+
+static inline void pty_dec_count(void)
+{
+ pty_count = (--tty_count) / 2;
+}
+
static struct cdev ptmx_cdev;
static struct ctl_table pty_table[] = {
@@ -542,6 +553,7 @@
static void pty_unix98_shutdown(struct tty_struct *tty)
{
+ tty_driver_remove_tty(tty->driver, tty);
/* We have our own method as we don't use the tty index */
kfree(tty->termios);
}
@@ -588,7 +600,8 @@
*/
tty_driver_kref_get(driver);
tty->count++;
- pty_count++;
+ pty_inc_count(); /* tty */
+ pty_inc_count(); /* tty->link */
return 0;
err_free_mem:
deinitialize_tty_struct(o_tty);
@@ -602,7 +615,7 @@
static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
{
- pty_count--;
+ pty_dec_count();
}
static const struct tty_operations ptm_unix98_ops = {
diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c
index d32b5bb..762ce72 100644
--- a/drivers/tty/serial/8250.c
+++ b/drivers/tty/serial/8250.c
@@ -1819,6 +1819,8 @@
unsigned int iir, ier = 0, lsr;
unsigned long flags;
+ spin_lock_irqsave(&up->port.lock, flags);
+
/*
* Must disable interrupts or else we risk racing with the interrupt
* based handler.
@@ -1836,10 +1838,8 @@
* the "Diva" UART used on the management processor on many HP
* ia64 and parisc boxes.
*/
- spin_lock_irqsave(&up->port.lock, flags);
lsr = serial_in(up, UART_LSR);
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
- spin_unlock_irqrestore(&up->port.lock, flags);
if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) &&
(!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) &&
(lsr & UART_LSR_THRE)) {
@@ -1848,11 +1848,13 @@
}
if (!(iir & UART_IIR_NO_INT))
- serial8250_handle_port(up);
+ transmit_chars(up);
if (is_real_interrupt(up->port.irq))
serial_out(up, UART_IER, ier);
+ spin_unlock_irqrestore(&up->port.lock, flags);
+
/* Standard timer interval plus 0.2s to keep the port running */
mod_timer(&up->timer,
jiffies + uart_poll_timeout(&up->port) + HZ / 5);
diff --git a/drivers/tty/serial/8250_pci.c b/drivers/tty/serial/8250_pci.c
index f41b425..ff48fdb 100644
--- a/drivers/tty/serial/8250_pci.c
+++ b/drivers/tty/serial/8250_pci.c
@@ -3886,7 +3886,7 @@
0, 0, pbn_b0_1_115200 },
/*
- * Best Connectivity PCI Multi I/O cards
+ * Best Connectivity and Rosewill PCI Multi I/O cards
*/
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
@@ -3894,6 +3894,10 @@
0, 0, pbn_b0_1_115200 },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
+ 0xA000, 0x3002,
+ 0, 0, pbn_b0_bt_2_115200 },
+
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
0xA000, 0x3004,
0, 0, pbn_b0_bt_4_115200 },
/* Intel CE4100 */
diff --git a/drivers/tty/serial/8250_pnp.c b/drivers/tty/serial/8250_pnp.c
index fc301f6..a2f2365 100644
--- a/drivers/tty/serial/8250_pnp.c
+++ b/drivers/tty/serial/8250_pnp.c
@@ -109,6 +109,9 @@
/* IBM */
/* IBM Thinkpad 701 Internal Modem Voice */
{ "IBM0033", 0 },
+ /* Intermec */
+ /* Intermec CV60 touchscreen port */
+ { "PNP4972", 0 },
/* Intertex */
/* Intertex 28k8 33k6 Voice EXT PnP */
{ "IXDC801", 0 },
diff --git a/drivers/tty/serial/max3107-aava.c b/drivers/tty/serial/max3107-aava.c
index a1fe304..d73aadd 100644
--- a/drivers/tty/serial/max3107-aava.c
+++ b/drivers/tty/serial/max3107-aava.c
@@ -340,5 +340,5 @@
MODULE_DESCRIPTION("MAX3107 driver");
MODULE_AUTHOR("Aavamobile");
-MODULE_ALIAS("aava-max3107-spi");
+MODULE_ALIAS("spi:aava-max3107");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/max3107.c b/drivers/tty/serial/max3107.c
index 750b4f6..a816460 100644
--- a/drivers/tty/serial/max3107.c
+++ b/drivers/tty/serial/max3107.c
@@ -1209,5 +1209,5 @@
MODULE_DESCRIPTION("MAX3107 driver");
MODULE_AUTHOR("Aavamobile");
-MODULE_ALIAS("max3107-spi");
+MODULE_ALIAS("spi:max3107");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c
index a764bf9..23bc743 100644
--- a/drivers/tty/serial/mrst_max3110.c
+++ b/drivers/tty/serial/mrst_max3110.c
@@ -917,4 +917,4 @@
module_exit(serial_m3110_exit);
MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("max3110-uart");
+MODULE_ALIAS("spi:max3110-uart");
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index bc1a25b..84cb3f5 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -405,9 +405,9 @@
msm_uport->rx.rbuffer);
dma_pool_destroy(msm_uport->rx.pool);
- dma_unmap_single(dev, msm_uport->rx.cmdptr_dmaaddr, sizeof(u32 *),
+ dma_unmap_single(dev, msm_uport->rx.cmdptr_dmaaddr, sizeof(u32),
DMA_TO_DEVICE);
- dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr_ptr, sizeof(u32 *),
+ dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr_ptr, sizeof(u32),
DMA_TO_DEVICE);
dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr, sizeof(dmov_box),
DMA_TO_DEVICE);
@@ -897,7 +897,7 @@
mb();
dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr_ptr,
- sizeof(u32 *), DMA_TO_DEVICE);
+ sizeof(u32), DMA_TO_DEVICE);
msm_dmov_enqueue_cmd(msm_uport->dma_tx_channel, &tx->xfer);
}
@@ -1726,7 +1726,7 @@
if (!tx->command_ptr)
return -ENOMEM;
- tx->command_ptr_ptr = kmalloc(sizeof(u32 *), GFP_KERNEL | __GFP_DMA);
+ tx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA);
if (!tx->command_ptr_ptr) {
ret = -ENOMEM;
goto free_tx_command_ptr;
@@ -1736,7 +1736,7 @@
sizeof(dmov_box), DMA_TO_DEVICE);
tx->mapped_cmd_ptr_ptr = dma_map_single(uport->dev,
tx->command_ptr_ptr,
- sizeof(u32 *), DMA_TO_DEVICE);
+ sizeof(u32), DMA_TO_DEVICE);
tx->xfer.cmdptr = DMOV_CMD_ADDR(tx->mapped_cmd_ptr_ptr);
init_waitqueue_head(&rx->wait);
@@ -1772,7 +1772,7 @@
goto free_rx_buffer;
}
- rx->command_ptr_ptr = kmalloc(sizeof(u32 *), GFP_KERNEL | __GFP_DMA);
+ rx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA);
if (!rx->command_ptr_ptr) {
pr_err("%s(): cannot allocate rx->command_ptr_ptr", __func__);
ret = -ENOMEM;
@@ -1803,7 +1803,7 @@
*rx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(rx->mapped_cmd_ptr);
rx->cmdptr_dmaaddr = dma_map_single(uport->dev, rx->command_ptr_ptr,
- sizeof(u32 *), DMA_TO_DEVICE);
+ sizeof(u32), DMA_TO_DEVICE);
rx->xfer.cmdptr = DMOV_CMD_ADDR(rx->cmdptr_dmaaddr);
INIT_DELAYED_WORK(&rx->flip_insert_work, flip_insert_work);
@@ -1826,7 +1826,7 @@
tasklet_kill(&msm_uport->tx.tlet);
tasklet_kill(&msm_uport->rx.tlet);
dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr_ptr,
- sizeof(u32 *), DMA_TO_DEVICE);
+ sizeof(u32), DMA_TO_DEVICE);
dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr,
sizeof(dmov_box), DMA_TO_DEVICE);
kfree(msm_uport->tx.command_ptr_ptr);
@@ -1999,12 +1999,12 @@
tasklet_kill(&msm_uport->rx.tlet);
cancel_delayed_work_sync(&msm_uport->rx.flip_insert_work);
- spin_lock_irqsave(&uport->lock, flags);
clk_enable(msm_uport->clk);
pm_runtime_disable(uport->dev);
pm_runtime_set_suspended(uport->dev);
+ spin_lock_irqsave(&uport->lock, flags);
/* Disable the transmitter */
msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_TX_DISABLE_BMSK);
/* Disable the receiver */
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index 9ba7d2f..a094b4e 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -1138,7 +1138,7 @@
spin_unlock(&port->lock);
}
-static int __init msm_hsl_console_setup(struct console *co, char *options)
+static int msm_hsl_console_setup(struct console *co, char *options)
{
struct uart_port *port;
unsigned int vid;
@@ -1201,7 +1201,93 @@
};
#define MSM_HSL_CONSOLE (&msm_hsl_console)
+/*
+ * get_console_state - check the per-port serial console state.
+ * @port: uart_port structure describing the port
+ *
+ * Return the state of serial console availability on port.
+ * return 1: If serial console is enabled on particular UART port.
+ * return 0: If serial console is disabled on particular UART port.
+ */
+static int get_console_state(struct uart_port *port)
+{
+ if (is_console(port) && (port->cons->flags & CON_ENABLED))
+ return 1;
+ else
+ return 0;
+}
+/* show_msm_console - provide per-port serial console state. */
+static ssize_t show_msm_console(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int enable;
+ struct uart_port *port;
+
+ struct platform_device *pdev = to_platform_device(dev);
+ port = get_port_from_line(pdev->id);
+
+ enable = get_console_state(port);
+
+ return snprintf(buf, sizeof(enable), "%d\n", enable);
+}
+
+/*
+ * set_msm_console - allow to enable/disable serial console on port.
+ *
+ * writing 1 enables serial console on UART port.
+ * writing 0 disables serial console on UART port.
+ */
+static ssize_t set_msm_console(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int enable, cur_state;
+ struct uart_port *port;
+
+ struct platform_device *pdev = to_platform_device(dev);
+ port = get_port_from_line(pdev->id);
+
+ cur_state = get_console_state(port);
+ enable = buf[0] - '0';
+
+ if (enable == cur_state)
+ return count;
+
+ switch (enable) {
+ case 0:
+ pr_debug("%s(): Calling stop_console\n", __func__);
+ console_stop(port->cons);
+ pr_debug("%s(): Calling unregister_console\n", __func__);
+ unregister_console(port->cons);
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ /*
+ * Disable UART Core clk
+ * 3 - to disable the UART clock
+ * Thid parameter is not used here, but used in serial core.
+ */
+ msm_hsl_power(port, 3, 1);
+ break;
+ case 1:
+ pr_debug("%s(): Calling register_console\n", __func__);
+ /*
+ * Disable UART Core clk
+ * 0 - to enable the UART clock
+ * Thid parameter is not used here, but used in serial core.
+ */
+ msm_hsl_power(port, 0, 1);
+ pm_runtime_enable(&pdev->dev);
+ register_console(port->cons);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return count;
+}
+static DEVICE_ATTR(console, S_IWUSR | S_IRUGO, show_msm_console,
+ set_msm_console);
#else
#define MSM_HSL_CONSOLE NULL
#endif
@@ -1286,6 +1372,11 @@
device_set_wakeup_capable(&pdev->dev, 1);
platform_set_drvdata(pdev, port);
pm_runtime_enable(port->dev);
+#ifdef CONFIG_SERIAL_MSM_HSL_CONSOLE
+ ret = device_create_file(&pdev->dev, &dev_attr_console);
+ if (unlikely(ret))
+ pr_err("%s():Can't create console attribute\n", __func__);
+#endif
msm_hsl_debugfs_init(msm_hsl_port, pdev->id);
/* Temporarily increase the refcount on the GSBI clock to avoid a race
@@ -1305,6 +1396,9 @@
struct uart_port *port;
port = get_port_from_line(pdev->id);
+#ifdef CONFIG_SERIAL_MSM_HSL_CONSOLE
+ device_remove_file(&pdev->dev, &dev_attr_console);
+#endif
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 47cadf4..6d3ec14 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -806,8 +806,7 @@
serial_omap_set_mctrl(&up->port, up->port.mctrl);
/* Software Flow Control Configuration */
- if (termios->c_iflag & (IXON | IXOFF))
- serial_omap_configure_xonxoff(up, termios);
+ serial_omap_configure_xonxoff(up, termios);
spin_unlock_irqrestore(&up->port.lock, flags);
dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->pdev->id);
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index b6aee25..7dc8b53 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -1294,8 +1294,7 @@
*
* Locking: tty_mutex for now
*/
-static void tty_driver_remove_tty(struct tty_driver *driver,
- struct tty_struct *tty)
+void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct *tty)
{
if (driver->ops->remove)
driver->ops->remove(driver, tty);
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 385acb8..3f94ac3 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -268,7 +268,7 @@
dev_err(dev, "usb_bulk_msg returned %d\n", rv);
goto exit;
}
- } while ((actual = max_size) &&
+ } while ((actual == max_size) &&
(n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN));
if (actual == max_size) {
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index c962608..26678ca 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -123,10 +123,11 @@
}
if (usb_endpoint_xfer_isoc(&ep->desc))
- max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1) *
- (desc->bmAttributes + 1);
+ max_tx = (desc->bMaxBurst + 1) * (desc->bmAttributes + 1) *
+ le16_to_cpu(ep->desc.wMaxPacketSize);
else if (usb_endpoint_xfer_int(&ep->desc))
- max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1);
+ max_tx = le16_to_cpu(ep->desc.wMaxPacketSize) *
+ (desc->bMaxBurst + 1);
else
max_tx = 999999;
if (le16_to_cpu(desc->wBytesPerInterval) > max_tx) {
@@ -134,10 +135,10 @@
"config %d interface %d altsetting %d ep %d: "
"setting to %d\n",
usb_endpoint_xfer_isoc(&ep->desc) ? "Isoc" : "Int",
- desc->wBytesPerInterval,
+ le16_to_cpu(desc->wBytesPerInterval),
cfgno, inum, asnum, ep->desc.bEndpointAddress,
max_tx);
- ep->ss_ep_comp.wBytesPerInterval = max_tx;
+ ep->ss_ep_comp.wBytesPerInterval = cpu_to_le16(max_tx);
}
}
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 117d3bf..94ed950 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -1089,6 +1089,12 @@
This csw hack feature is for increasing the performance of the mass
storage
+config USB_MSC_PROFILING
+ bool "USB MSC performance profiling"
+ help
+ If you say Y here, support will be added for collecting
+ Mass-storage performance numbers at the VFS level.
+
config MODEM_SUPPORT
boolean "modem support in generic serial function driver"
depends on USB_G_ANDROID
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index fdd0ba8..af6f351 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -57,9 +57,12 @@
#include "u_smd.c"
#include "u_bam.c"
#include "u_rmnet_ctrl_smd.c"
+#include "u_ctrl_hsic.c"
+#include "u_data_hsic.c"
#include "f_serial.c"
//#include "f_acm.c"
#include "f_adb.c"
+#include "f_ccid.c"
#include "f_mtp.c"
#include "f_accessory.c"
#define USB_ETH_RNDIS y
@@ -98,8 +101,7 @@
/* Optional: called when the configuration is removed */
void (*unbind_config)(struct android_usb_function *, struct usb_configuration *);
- /* Optional: handle ctrl requests before the device is configured
- * and/or before the function is enabled */
+ /* Optional: handle ctrl requests before the device is configured */
int (*ctrlrequest)(struct android_usb_function *,
struct usb_composite_dev *,
const struct usb_ctrlrequest *);
@@ -176,22 +178,23 @@
char *disconnected[2] = { "USB_STATE=DISCONNECTED", NULL };
char *connected[2] = { "USB_STATE=CONNECTED", NULL };
char *configured[2] = { "USB_STATE=CONFIGURED", NULL };
+ char **uevent_envp = NULL;
unsigned long flags;
spin_lock_irqsave(&cdev->lock, flags);
- if (cdev->config) {
- spin_unlock_irqrestore(&cdev->lock, flags);
- kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE,
- configured);
- return;
- }
- if (dev->connected != dev->sw_connected) {
- dev->sw_connected = dev->connected;
- spin_unlock_irqrestore(&cdev->lock, flags);
- kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE,
- dev->sw_connected ? connected : disconnected);
+ if (cdev->config)
+ uevent_envp = configured;
+ else if (dev->connected != dev->sw_connected)
+ uevent_envp = dev->connected ? connected : disconnected;
+ dev->sw_connected = dev->connected;
+ spin_unlock_irqrestore(&cdev->lock, flags);
+
+ if (uevent_envp) {
+ kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, uevent_envp);
+ pr_info("%s: sent uevent %s\n", __func__, uevent_envp[0]);
} else {
- spin_unlock_irqrestore(&cdev->lock, flags);
+ pr_info("%s: did not send uevent (%d %d %p)\n", __func__,
+ dev->connected, dev->sw_connected, cdev->config);
}
}
@@ -252,14 +255,9 @@
.attributes = rmnet_smd_sdio_attributes,
};
-/* RMNET - used with BAM */
-#define MAX_RMNET_INSTANCES 1
-static int rmnet_instances;
-static int rmnet_function_init(struct android_usb_function *f,
- struct usb_composite_dev *cdev)
-{
- return frmnet_init_port(MAX_RMNET_INSTANCES);
-}
+/*rmnet transport string format(per port):"ctrl0,data0,ctrl1,data1..." */
+#define MAX_XPORT_STR_LEN 50
+static char rmnet_transports[MAX_XPORT_STR_LEN];
static void rmnet_function_cleanup(struct android_usb_function *f)
{
@@ -270,45 +268,74 @@
struct usb_configuration *c)
{
int i;
- int ret = 0;
+ int err = 0;
+ char *ctrl_name;
+ char *data_name;
+ char buf[MAX_XPORT_STR_LEN], *b;
+ static int rmnet_initialized, ports;
- for (i = 0; i < rmnet_instances; i++) {
- ret = frmnet_bind_config(c, i);
- if (ret) {
+ if (!rmnet_initialized) {
+ rmnet_initialized = 1;
+ strlcpy(buf, rmnet_transports, sizeof(buf));
+ b = strim(buf);
+ while (b) {
+ ctrl_name = strsep(&b, ",");
+ data_name = strsep(&b, ",");
+ if (ctrl_name && data_name) {
+ err = frmnet_init_port(ctrl_name, data_name);
+ if (err) {
+ pr_err("rmnet: Cannot open ctrl port:"
+ "'%s' data port:'%s'\n",
+ ctrl_name, data_name);
+ goto out;
+ }
+ ports++;
+ }
+ }
+
+ err = rmnet_gport_setup();
+ if (err) {
+ pr_err("rmnet: Cannot setup transports");
+ goto out;
+ }
+ }
+
+ for (i = 0; i < ports; i++) {
+ err = frmnet_bind_config(c, i);
+ if (err) {
pr_err("Could not bind rmnet%u config\n", i);
break;
}
}
-
- return ret;
+out:
+ return err;
}
-static ssize_t rmnet_instances_show(struct device *dev,
+static ssize_t rmnet_transports_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%d\n", rmnet_instances);
+ return snprintf(buf, PAGE_SIZE, "%s\n", rmnet_transports);
}
-static ssize_t rmnet_instances_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t size)
+static ssize_t rmnet_transports_store(
+ struct device *device, struct device_attribute *attr,
+ const char *buff, size_t size)
{
- int value;
+ strlcpy(rmnet_transports, buff, sizeof(rmnet_transports));
- sscanf(buf, "%d", &value);
- if (value > MAX_RMNET_INSTANCES)
- value = MAX_RMNET_INSTANCES;
- rmnet_instances = value;
return size;
}
-static DEVICE_ATTR(instances, S_IRUGO | S_IWUSR, rmnet_instances_show,
- rmnet_instances_store);
+static struct device_attribute dev_attr_rmnet_transports =
+ __ATTR(transports, S_IRUGO | S_IWUSR,
+ rmnet_transports_show,
+ rmnet_transports_store);
static struct device_attribute *rmnet_function_attributes[] = {
- &dev_attr_instances, NULL };
+ &dev_attr_rmnet_transports,
+ NULL };
static struct android_usb_function rmnet_function = {
.name = "rmnet",
- .init = rmnet_function_init,
.cleanup = rmnet_function_cleanup,
.bind_config = rmnet_function_bind_config,
.attributes = rmnet_function_attributes,
@@ -472,6 +499,31 @@
.bind_config = adb_function_bind_config,
};
+/* CCID */
+static int ccid_function_init(struct android_usb_function *f,
+ struct usb_composite_dev *cdev)
+{
+ return ccid_setup();
+}
+
+static void ccid_function_cleanup(struct android_usb_function *f)
+{
+ ccid_cleanup();
+}
+
+static int ccid_function_bind_config(struct android_usb_function *f,
+ struct usb_configuration *c)
+{
+ return ccid_bind_config(c);
+}
+
+static struct android_usb_function ccid_function = {
+ .name = "ccid",
+ .init = ccid_function_init,
+ .cleanup = ccid_function_cleanup,
+ .bind_config = ccid_function_bind_config,
+};
+
#if 0
#define MAX_ACM_INSTANCES 4
struct acm_function_config {
@@ -609,26 +661,14 @@
static int rndis_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev)
{
- int ret;
- struct rndis_function_config *rndis;
-
f->config = kzalloc(sizeof(struct rndis_function_config), GFP_KERNEL);
if (!f->config)
return -ENOMEM;
-
- rndis = f->config;
- ret = gether_setup_name(cdev->gadget, rndis->ethaddr, "usb");
- if (ret) {
- pr_err("%s: gether_setup failed\n", __func__);
- return ret;
- }
-
return 0;
}
static void rndis_function_cleanup(struct android_usb_function *f)
{
- gether_cleanup();
kfree(f->config);
f->config = NULL;
}
@@ -636,6 +676,7 @@
static int rndis_function_bind_config(struct android_usb_function *f,
struct usb_configuration *c)
{
+ int ret;
struct rndis_function_config *rndis = f->config;
if (!rndis) {
@@ -647,6 +688,12 @@
rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2],
rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]);
+ ret = gether_setup_name(c->cdev->gadget, rndis->ethaddr, "rndis");
+ if (ret) {
+ pr_err("%s: gether_setup failed\n", __func__);
+ return ret;
+ }
+
if (rndis->wceis) {
/* "Wireless" RNDIS; auto-detected by Windows */
rndis_iad_descriptor.bFunctionClass =
@@ -666,6 +713,7 @@
static void rndis_function_unbind_config(struct android_usb_function *f,
struct usb_configuration *c)
{
+ gether_cleanup();
}
static ssize_t rndis_manufacturer_show(struct device *dev,
@@ -919,6 +967,7 @@
&diag_function,
&serial_function,
&adb_function,
+ &ccid_function,
// &acm_function,
&mtp_function,
&ptp_function,
@@ -1041,6 +1090,32 @@
/*-------------------------------------------------------------------------*/
/* /sys/class/android_usb/android%d/ interface */
+static ssize_t remote_wakeup_show(struct device *pdev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ !!(android_config_driver.bmAttributes &
+ USB_CONFIG_ATT_WAKEUP));
+}
+
+static ssize_t remote_wakeup_store(struct device *pdev,
+ struct device_attribute *attr, const char *buff, size_t size)
+{
+ int enable = 0;
+
+ sscanf(buff, "%d", &enable);
+
+ pr_debug("android_usb: %s remote wakeup\n",
+ enable ? "enabling" : "disabling");
+
+ if (enable)
+ android_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+ else
+ android_config_driver.bmAttributes &= ~USB_CONFIG_ATT_WAKEUP;
+
+ return size;
+}
+
static ssize_t
functions_show(struct device *pdev, struct device_attribute *attr, char *buf)
{
@@ -1196,6 +1271,8 @@
static DEVICE_ATTR(functions, S_IRUGO | S_IWUSR, functions_show, functions_store);
static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store);
static DEVICE_ATTR(state, S_IRUGO, state_show, NULL);
+static DEVICE_ATTR(remote_wakeup, S_IRUGO | S_IWUSR,
+ remote_wakeup_show, remote_wakeup_store);
static struct device_attribute *android_usb_attributes[] = {
&dev_attr_idVendor,
@@ -1210,6 +1287,7 @@
&dev_attr_functions,
&dev_attr_enable,
&dev_attr_state,
+ &dev_attr_remote_wakeup,
NULL
};
@@ -1335,6 +1413,12 @@
}
}
+ /* Special case the accessory function.
+ * It needs to handle control requests before it is enabled.
+ */
+ if (value < 0)
+ value = acc_ctrlrequest(cdev, c);
+
if (value < 0)
value = composite_setup(gadget, c);
@@ -1354,9 +1438,15 @@
static void android_disconnect(struct usb_gadget *gadget)
{
struct android_dev *dev = _android_dev;
+ struct usb_composite_dev *cdev = get_gadget_data(gadget);
+ unsigned long flags;
+
+ composite_disconnect(gadget);
+
+ spin_lock_irqsave(&cdev->lock, flags);
dev->connected = 0;
schedule_work(&dev->work);
- composite_disconnect(gadget);
+ spin_unlock_irqrestore(&cdev->lock, flags);
}
static int android_create_device(struct android_dev *dev)
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 11bfe9f..e084278 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2773,6 +2773,7 @@
unsigned long flags;
int i, j;
int retval = -ENOMEM;
+ bool put = false;
trace("%p", driver);
@@ -2862,6 +2863,7 @@
udc->softconnect = 1;
spin_unlock_irqrestore(udc->lock, flags);
+ pm_runtime_get_sync(&udc->gadget.dev);
retval = bind(&udc->gadget); /* MAY SLEEP */
spin_lock_irqsave(udc->lock, flags);
@@ -2871,26 +2873,27 @@
}
udc->driver = driver;
- pm_runtime_get_sync(&udc->gadget.dev);
if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) {
if (udc->vbus_active) {
if (udc->udc_driver->flags & CI13XXX_REGS_SHARED)
hw_device_reset(udc);
} else {
- pm_runtime_put_sync(&udc->gadget.dev);
+ put = true;
goto done;
}
}
- if (!udc->softconnect)
+ if (!udc->softconnect) {
+ put = true;
goto done;
+ }
retval = hw_device_state(udc->ep0out.qh.dma);
- if (retval)
- pm_runtime_put_sync(&udc->gadget.dev);
done:
spin_unlock_irqrestore(udc->lock, flags);
+ if (retval || put)
+ pm_runtime_put_sync(&udc->gadget.dev);
return retval;
}
EXPORT_SYMBOL(usb_gadget_probe_driver);
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index 3fd12b1..7299dff 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -107,20 +107,6 @@
return container_of(p, struct f_acm, port);
}
-static char *transport_to_str(enum transport_type t)
-{
- switch (t) {
- case USB_GADGET_FSERIAL_TRANSPORT_TTY:
- return "TTY";
- case USB_GADGET_FSERIAL_TRANSPORT_SDIO:
- return "SDIO";
- case USB_GADGET_FSERIAL_TRANSPORT_SMD:
- return "SMD";
- }
-
- return "NONE";
-}
-
static int gport_setup(struct usb_configuration *c)
{
int ret = 0;
@@ -146,7 +132,7 @@
pr_debug("%s: transport:%s f_acm:%p gserial:%p port_num:%d cl_port_no:%d\n",
- __func__, transport_to_str(acm->transport),
+ __func__, xport_to_str(acm->transport),
acm, &acm->port, acm->port_num, port_num);
switch (acm->transport) {
@@ -161,7 +147,7 @@
break;
default:
pr_err("%s: Un-supported transport: %s\n", __func__,
- transport_to_str(acm->transport));
+ xport_to_str(acm->transport));
return -ENODEV;
}
@@ -175,7 +161,7 @@
port_num = gacm_ports[acm->port_num].client_port_num;
pr_debug("%s: transport:%s f_acm:%p gserial:%p port_num:%d cl_pno:%d\n",
- __func__, transport_to_str(acm->transport),
+ __func__, xport_to_str(acm->transport),
acm, &acm->port, acm->port_num, port_num);
switch (acm->transport) {
@@ -190,7 +176,7 @@
break;
default:
pr_err("%s: Un-supported transport:%s\n", __func__,
- transport_to_str(acm->transport));
+ xport_to_str(acm->transport));
return -ENODEV;
}
diff --git a/drivers/usb/gadget/f_ccid.c b/drivers/usb/gadget/f_ccid.c
new file mode 100644
index 0000000..a11f439
--- /dev/null
+++ b/drivers/usb/gadget/f_ccid.c
@@ -0,0 +1,1014 @@
+/*
+ * f_ccid.c -- CCID function Driver
+ *
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/slab.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/usb/android_composite.h>
+#include <linux/fs.h>
+#include <linux/usb/ccid_desc.h>
+#include <linux/miscdevice.h>
+
+#include "f_ccid.h"
+
+#define BULK_IN_BUFFER_SIZE sizeof(struct ccid_bulk_in_header)
+#define BULK_OUT_BUFFER_SIZE sizeof(struct ccid_bulk_out_header)
+#define CTRL_BUF_SIZE 4
+#define FUNCTION_NAME "ccid"
+#define CCID_NOTIFY_INTERVAL 5
+#define CCID_NOTIFY_MAXPACKET 4
+
+/* number of tx requests to allocate */
+#define TX_REQ_MAX 4
+
+struct ccid_descs {
+ struct usb_endpoint_descriptor *in;
+ struct usb_endpoint_descriptor *out;
+ struct usb_endpoint_descriptor *notify;
+};
+
+struct ccid_ctrl_dev {
+ atomic_t opened;
+ struct list_head tx_q;
+ wait_queue_head_t tx_wait_q;
+ unsigned char buf[CTRL_BUF_SIZE];
+ int tx_ctrl_done;
+};
+
+struct ccid_bulk_dev {
+ atomic_t error;
+ atomic_t opened;
+ atomic_t rx_req_busy;
+ wait_queue_head_t read_wq;
+ wait_queue_head_t write_wq;
+ struct usb_request *rx_req;
+ int rx_done;
+ struct list_head tx_idle;
+};
+
+struct f_ccid {
+ struct usb_function function;
+ struct usb_composite_dev *cdev;
+ int ifc_id;
+ spinlock_t lock;
+ atomic_t online;
+ /* usb descriptors */
+ struct ccid_descs fs;
+ struct ccid_descs hs;
+ /* usb eps*/
+ struct usb_ep *notify;
+ struct usb_ep *in;
+ struct usb_ep *out;
+ struct usb_endpoint_descriptor *in_desc;
+ struct usb_endpoint_descriptor *out_desc;
+ struct usb_endpoint_descriptor *notify_desc;
+ struct usb_request *notify_req;
+ struct ccid_ctrl_dev ctrl_dev;
+ struct ccid_bulk_dev bulk_dev;
+ int dtr_state;
+};
+
+static struct f_ccid *_ccid_dev;
+static struct miscdevice ccid_bulk_device;
+static struct miscdevice ccid_ctrl_device;
+
+/* Interface Descriptor: */
+static struct usb_interface_descriptor ccid_interface_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bNumEndpoints = 3,
+ .bInterfaceClass = USB_CLASS_CSCID,
+ .bInterfaceSubClass = 0,
+ .bInterfaceProtocol = 0,
+};
+/* CCID Class Descriptor */
+static struct usb_ccid_class_descriptor ccid_class_desc = {
+ .bLength = sizeof(ccid_class_desc),
+ .bDescriptorType = CCID_DECRIPTOR_TYPE,
+ .bcdCCID = CCID1_10,
+ .bMaxSlotIndex = 0,
+ /* This value indicates what voltages the CCID can supply to slots */
+ .bVoltageSupport = VOLTS_3_0,
+ .dwProtocols = PROTOCOL_TO,
+ /* Default ICC clock frequency in KHz */
+ .dwDefaultClock = 3580,
+ /* Maximum supported ICC clock frequency in KHz */
+ .dwMaximumClock = 3580,
+ .bNumClockSupported = 0,
+ /* Default ICC I/O data rate in bps */
+ .dwDataRate = 9600,
+ /* Maximum supported ICC I/O data rate in bps */
+ .dwMaxDataRate = 9600,
+ .bNumDataRatesSupported = 0,
+ .dwMaxIFSD = 0,
+ .dwSynchProtocols = 0,
+ .dwMechanical = 0,
+ /* This value indicates what intelligent features the CCID has */
+ .dwFeatures = CCID_FEATURES_EXC_SAPDU |
+ CCID_FEATURES_AUTO_PNEGO |
+ CCID_FEATURES_AUTO_BAUD |
+ CCID_FEATURES_AUTO_CLOCK |
+ CCID_FEATURES_AUTO_VOLT |
+ CCID_FEATURES_AUTO_ACTIV |
+ CCID_FEATURES_AUTO_PCONF,
+ /* extended APDU level Message Length */
+ .dwMaxCCIDMessageLength = 0x200,
+ .bClassGetResponse = 0x0,
+ .bClassEnvelope = 0x0,
+ .wLcdLayout = 0,
+ .bPINSupport = 0,
+ .bMaxCCIDBusySlots = 1
+};
+/* Full speed support: */
+static struct usb_endpoint_descriptor ccid_fs_notify_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = __constant_cpu_to_le16(CCID_NOTIFY_MAXPACKET),
+ .bInterval = 1 << CCID_NOTIFY_INTERVAL,
+};
+
+static struct usb_endpoint_descriptor ccid_fs_in_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = __constant_cpu_to_le16(64),
+};
+
+static struct usb_endpoint_descriptor ccid_fs_out_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = __constant_cpu_to_le16(64),
+};
+
+static struct usb_descriptor_header *ccid_fs_descs[] = {
+ (struct usb_descriptor_header *) &ccid_interface_desc,
+ (struct usb_descriptor_header *) &ccid_class_desc,
+ (struct usb_descriptor_header *) &ccid_fs_notify_desc,
+ (struct usb_descriptor_header *) &ccid_fs_in_desc,
+ (struct usb_descriptor_header *) &ccid_fs_out_desc,
+ NULL,
+};
+
+/* High speed support: */
+static struct usb_endpoint_descriptor ccid_hs_notify_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = __constant_cpu_to_le16(CCID_NOTIFY_MAXPACKET),
+ .bInterval = CCID_NOTIFY_INTERVAL + 4,
+};
+
+static struct usb_endpoint_descriptor ccid_hs_in_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = __constant_cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor ccid_hs_out_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = __constant_cpu_to_le16(512),
+};
+
+static struct usb_descriptor_header *ccid_hs_descs[] = {
+ (struct usb_descriptor_header *) &ccid_interface_desc,
+ (struct usb_descriptor_header *) &ccid_class_desc,
+ (struct usb_descriptor_header *) &ccid_hs_notify_desc,
+ (struct usb_descriptor_header *) &ccid_hs_in_desc,
+ (struct usb_descriptor_header *) &ccid_hs_out_desc,
+ NULL,
+};
+
+static inline struct f_ccid *func_to_ccid(struct usb_function *f)
+{
+ return container_of(f, struct f_ccid, function);
+}
+
+static void ccid_req_put(struct f_ccid *ccid_dev, struct list_head *head,
+ struct usb_request *req)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ccid_dev->lock, flags);
+ list_add_tail(&req->list, head);
+ spin_unlock_irqrestore(&ccid_dev->lock, flags);
+}
+
+static struct usb_request *ccid_req_get(struct f_ccid *ccid_dev,
+ struct list_head *head)
+{
+ unsigned long flags;
+ struct usb_request *req = NULL;
+
+ spin_lock_irqsave(&ccid_dev->lock, flags);
+ if (!list_empty(head)) {
+ req = list_first_entry(head, struct usb_request, list);
+ list_del(&req->list);
+ }
+ spin_unlock_irqrestore(&ccid_dev->lock, flags);
+ return req;
+}
+
+static void ccid_notify_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ switch (req->status) {
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ case 0:
+ break;
+ default:
+ pr_err("CCID notify ep error %d\n", req->status);
+ }
+}
+
+static void ccid_bulk_complete_in(struct usb_ep *ep, struct usb_request *req)
+{
+ struct f_ccid *ccid_dev = _ccid_dev;
+ struct ccid_bulk_dev *bulk_dev = &ccid_dev->bulk_dev;
+
+ if (req->status != 0)
+ atomic_set(&bulk_dev->error, 1);
+
+ ccid_req_put(ccid_dev, &bulk_dev->tx_idle, req);
+ wake_up(&bulk_dev->write_wq);
+}
+
+static void ccid_bulk_complete_out(struct usb_ep *ep, struct usb_request *req)
+{
+ struct f_ccid *ccid_dev = _ccid_dev;
+ struct ccid_bulk_dev *bulk_dev = &ccid_dev->bulk_dev;
+ if (req->status != 0)
+ atomic_set(&bulk_dev->error, 1);
+
+ bulk_dev->rx_done = 1;
+ wake_up(&bulk_dev->read_wq);
+}
+
+static struct usb_request *
+ccid_request_alloc(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags)
+{
+ struct usb_request *req;
+
+ req = usb_ep_alloc_request(ep, kmalloc_flags);
+
+ if (req != NULL) {
+ req->length = len;
+ req->buf = kmalloc(len, kmalloc_flags);
+ if (req->buf == NULL) {
+ usb_ep_free_request(ep, req);
+ req = NULL;
+ }
+ }
+
+ return req ? req : ERR_PTR(-ENOMEM);
+}
+
+static void ccid_request_free(struct usb_request *req, struct usb_ep *ep)
+{
+ if (req) {
+ kfree(req->buf);
+ usb_ep_free_request(ep, req);
+ }
+}
+
+static int
+ccid_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+{
+ struct f_ccid *ccid_dev = container_of(f, struct f_ccid, function);
+ struct ccid_ctrl_dev *ctrl_dev = &ccid_dev->ctrl_dev;
+ struct usb_composite_dev *cdev = f->config->cdev;
+ struct usb_request *req = cdev->req;
+ int ret = -EOPNOTSUPP;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u16 w_length = le16_to_cpu(ctrl->wLength);
+
+ if (!atomic_read(&ccid_dev->online))
+ return -ENOTCONN;
+
+ switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
+
+ case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+ | CCIDGENERICREQ_ABORT:
+ if (w_length != 0)
+ goto invalid;
+ ctrl_dev->buf[0] = CCIDGENERICREQ_ABORT;
+ ctrl_dev->buf[1] = w_value & 0xFF;
+ ctrl_dev->buf[2] = (w_value >> 8) & 0xFF;
+ ctrl_dev->buf[3] = 0x00;
+ ctrl_dev->tx_ctrl_done = 1;
+ wake_up(&ctrl_dev->tx_wait_q);
+ return 0;
+
+ case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+ | CCIDGENERICREQ_GET_CLOCK_FREQUENCIES:
+ if (w_length > req->length)
+ goto invalid;
+ *(u32 *) req->buf =
+ cpu_to_le32(ccid_class_desc.dwDefaultClock);
+ ret = min_t(u32, w_length,
+ sizeof(ccid_class_desc.dwDefaultClock));
+ break;
+
+ case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+ | CCIDGENERICREQ_GET_DATA_RATES:
+ if (w_length > req->length)
+ goto invalid;
+ *(u32 *) req->buf = cpu_to_le32(ccid_class_desc.dwDataRate);
+ ret = min_t(u32, w_length, sizeof(ccid_class_desc.dwDataRate));
+ break;
+
+ default:
+invalid:
+ pr_debug("invalid control req%02x.%02x v%04x i%04x l%d\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ w_value, w_index, w_length);
+ }
+
+ /* respond with data transfer or status phase? */
+ if (ret >= 0) {
+ pr_debug("ccid req%02x.%02x v%04x i%04x l%d\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ w_value, w_index, w_length);
+ req->length = ret;
+ ret = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+ if (ret < 0)
+ pr_err("ccid ep0 enqueue err %d\n", ret);
+ }
+
+ return ret;
+}
+
+static void ccid_function_disable(struct usb_function *f)
+{
+ struct f_ccid *ccid_dev = func_to_ccid(f);
+ struct ccid_bulk_dev *bulk_dev = &ccid_dev->bulk_dev;
+ struct ccid_ctrl_dev *ctrl_dev = &ccid_dev->ctrl_dev;
+ struct usb_request *req;
+
+ /* Disable endpoints */
+ usb_ep_disable(ccid_dev->notify);
+ usb_ep_disable(ccid_dev->in);
+ usb_ep_disable(ccid_dev->out);
+ /* Free endpoint related requests */
+ ccid_request_free(ccid_dev->notify_req, ccid_dev->notify);
+ if (!atomic_read(&bulk_dev->rx_req_busy))
+ ccid_request_free(bulk_dev->rx_req, ccid_dev->out);
+ while ((req = ccid_req_get(ccid_dev, &bulk_dev->tx_idle)))
+ ccid_request_free(req, ccid_dev->in);
+
+ ccid_dev->dtr_state = 0;
+ atomic_set(&ccid_dev->online, 0);
+ /* Wake up threads */
+ wake_up(&bulk_dev->write_wq);
+ wake_up(&bulk_dev->read_wq);
+ wake_up(&ctrl_dev->tx_wait_q);
+
+}
+
+static int
+ccid_function_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+ struct f_ccid *ccid_dev = func_to_ccid(f);
+ struct usb_composite_dev *cdev = ccid_dev->cdev;
+ struct ccid_bulk_dev *bulk_dev = &ccid_dev->bulk_dev;
+ struct usb_request *req;
+ int ret = 0;
+ int i;
+
+ ccid_dev->notify_req = ccid_request_alloc(ccid_dev->notify,
+ sizeof(struct usb_ccid_notification), GFP_ATOMIC);
+ if (IS_ERR(ccid_dev->notify_req)) {
+ pr_err("%s: unable to allocate memory for notify req\n",
+ __func__);
+ return PTR_ERR(ccid_dev->notify_req);
+ }
+ ccid_dev->notify_req->complete = ccid_notify_complete;
+ ccid_dev->notify_req->context = ccid_dev;
+
+ /* now allocate requests for our endpoints */
+ req = ccid_request_alloc(ccid_dev->out, BULK_OUT_BUFFER_SIZE,
+ GFP_ATOMIC);
+ if (IS_ERR(req)) {
+ pr_err("%s: unable to allocate memory for out req\n",
+ __func__);
+ ret = PTR_ERR(req);
+ goto free_notify;
+ }
+ req->complete = ccid_bulk_complete_out;
+ req->context = ccid_dev;
+ bulk_dev->rx_req = req;
+
+ for (i = 0; i < TX_REQ_MAX; i++) {
+ req = ccid_request_alloc(ccid_dev->in, BULK_IN_BUFFER_SIZE,
+ GFP_ATOMIC);
+ if (IS_ERR(req)) {
+ pr_err("%s: unable to allocate memory for in req\n",
+ __func__);
+ ret = PTR_ERR(req);
+ goto free_bulk_out;
+ }
+ req->complete = ccid_bulk_complete_in;
+ req->context = ccid_dev;
+ ccid_req_put(ccid_dev, &bulk_dev->tx_idle, req);
+ }
+
+ /* choose the descriptors and enable endpoints */
+ ccid_dev->notify_desc = ep_choose(cdev->gadget,
+ ccid_dev->hs.notify,
+ ccid_dev->fs.notify);
+ ret = usb_ep_enable(ccid_dev->notify, ccid_dev->notify_desc);
+ if (ret) {
+ pr_err("%s: usb ep#%s enable failed, err#%d\n",
+ __func__, ccid_dev->notify->name, ret);
+ goto free_bulk_in;
+ }
+ ccid_dev->notify->driver_data = ccid_dev;
+
+ ccid_dev->in_desc = ep_choose(cdev->gadget,
+ ccid_dev->hs.in, ccid_dev->fs.in);
+ ret = usb_ep_enable(ccid_dev->in, ccid_dev->in_desc);
+ if (ret) {
+ pr_err("%s: usb ep#%s enable failed, err#%d\n",
+ __func__, ccid_dev->in->name, ret);
+ goto disable_ep_notify;
+ }
+
+ ccid_dev->out_desc = ep_choose(cdev->gadget,
+ ccid_dev->hs.out, ccid_dev->fs.out);
+ ret = usb_ep_enable(ccid_dev->out, ccid_dev->out_desc);
+ if (ret) {
+ pr_err("%s: usb ep#%s enable failed, err#%d\n",
+ __func__, ccid_dev->out->name, ret);
+ goto disable_ep_in;
+ }
+ ccid_dev->dtr_state = 1;
+ atomic_set(&ccid_dev->online, 1);
+ return ret;
+
+disable_ep_in:
+ usb_ep_disable(ccid_dev->in);
+disable_ep_notify:
+ usb_ep_disable(ccid_dev->notify);
+ ccid_dev->notify->driver_data = NULL;
+free_bulk_in:
+ while ((req = ccid_req_get(ccid_dev, &bulk_dev->tx_idle)))
+ ccid_request_free(req, ccid_dev->in);
+free_bulk_out:
+ ccid_request_free(bulk_dev->rx_req, ccid_dev->out);
+free_notify:
+ ccid_request_free(ccid_dev->notify_req, ccid_dev->notify);
+ return ret;
+}
+
+static void ccid_function_unbind(struct usb_configuration *c,
+ struct usb_function *f)
+{
+ if (gadget_is_dualspeed(c->cdev->gadget))
+ usb_free_descriptors(f->hs_descriptors);
+ usb_free_descriptors(f->descriptors);
+
+}
+
+static int ccid_function_bind(struct usb_configuration *c,
+ struct usb_function *f)
+{
+ struct f_ccid *ccid_dev = func_to_ccid(f);
+ struct usb_ep *ep;
+ struct usb_composite_dev *cdev = c->cdev;
+ int ret = -ENODEV;
+
+ ccid_dev->ifc_id = usb_interface_id(c, f);
+ if (ccid_dev->ifc_id < 0) {
+ pr_err("%s: unable to allocate ifc id, err:%d",
+ __func__, ccid_dev->ifc_id);
+ return ccid_dev->ifc_id;
+ }
+ ccid_interface_desc.bInterfaceNumber = ccid_dev->ifc_id;
+
+ ep = usb_ep_autoconfig(cdev->gadget, &ccid_fs_notify_desc);
+ if (!ep) {
+ pr_err("%s: usb epnotify autoconfig failed\n", __func__);
+ return -ENODEV;
+ }
+ ccid_dev->notify = ep;
+ ep->driver_data = cdev;
+
+ ep = usb_ep_autoconfig(cdev->gadget, &ccid_fs_in_desc);
+ if (!ep) {
+ pr_err("%s: usb epin autoconfig failed\n", __func__);
+ ret = -ENODEV;
+ goto ep_auto_in_fail;
+ }
+ ccid_dev->in = ep;
+ ep->driver_data = cdev;
+
+ ep = usb_ep_autoconfig(cdev->gadget, &ccid_fs_out_desc);
+ if (!ep) {
+ pr_err("%s: usb epout autoconfig failed\n", __func__);
+ ret = -ENODEV;
+ goto ep_auto_out_fail;
+ }
+ ccid_dev->out = ep;
+ ep->driver_data = cdev;
+
+ f->descriptors = usb_copy_descriptors(ccid_fs_descs);
+ if (!f->descriptors)
+ goto ep_auto_out_fail;
+
+ ccid_dev->fs.in = usb_find_endpoint(ccid_fs_descs,
+ f->descriptors,
+ &ccid_fs_in_desc);
+ ccid_dev->fs.out = usb_find_endpoint(ccid_fs_descs,
+ f->descriptors,
+ &ccid_fs_out_desc);
+ ccid_dev->fs.notify = usb_find_endpoint(ccid_fs_descs,
+ f->descriptors,
+ &ccid_fs_notify_desc);
+
+ if (gadget_is_dualspeed(cdev->gadget)) {
+ ccid_hs_in_desc.bEndpointAddress =
+ ccid_fs_in_desc.bEndpointAddress;
+ ccid_hs_out_desc.bEndpointAddress =
+ ccid_fs_out_desc.bEndpointAddress;
+ ccid_hs_notify_desc.bEndpointAddress =
+ ccid_fs_notify_desc.bEndpointAddress;
+
+ /* copy descriptors, and track endpoint copies */
+ f->hs_descriptors = usb_copy_descriptors(ccid_hs_descs);
+ if (!f->hs_descriptors)
+ goto ep_auto_out_fail;
+
+ ccid_dev->hs.in = usb_find_endpoint(ccid_hs_descs,
+ f->hs_descriptors, &ccid_hs_in_desc);
+ ccid_dev->hs.out = usb_find_endpoint(ccid_hs_descs,
+ f->hs_descriptors, &ccid_hs_out_desc);
+ ccid_dev->hs.notify = usb_find_endpoint(ccid_hs_descs,
+ f->hs_descriptors, &ccid_hs_notify_desc);
+ }
+
+ pr_debug("%s: CCID %s Speed, IN:%s OUT:%s\n", __func__,
+ gadget_is_dualspeed(cdev->gadget) ? "dual" : "full",
+ ccid_dev->in->name, ccid_dev->out->name);
+
+ return 0;
+
+ep_auto_out_fail:
+ ccid_dev->out->driver_data = NULL;
+ ccid_dev->out = NULL;
+ep_auto_in_fail:
+ ccid_dev->in->driver_data = NULL;
+ ccid_dev->in = NULL;
+
+ return ret;
+}
+
+static int ccid_bulk_open(struct inode *ip, struct file *fp)
+{
+ struct f_ccid *ccid_dev = _ccid_dev;
+ struct ccid_bulk_dev *bulk_dev = &ccid_dev->bulk_dev;
+ unsigned long flags;
+
+ pr_debug("ccid_bulk_open\n");
+ if (!atomic_read(&ccid_dev->online)) {
+ pr_debug("%s: USB cable not connected\n", __func__);
+ return -ENODEV;
+ }
+
+ if (atomic_read(&bulk_dev->opened)) {
+ pr_debug("%s: bulk device is already opened\n", __func__);
+ return -EBUSY;
+ }
+ atomic_set(&bulk_dev->opened, 1);
+ /* clear the error latch */
+ atomic_set(&bulk_dev->error, 0);
+ spin_lock_irqsave(&ccid_dev->lock, flags);
+ fp->private_data = ccid_dev;
+ spin_unlock_irqrestore(&ccid_dev->lock, flags);
+
+ return 0;
+}
+
+static int ccid_bulk_release(struct inode *ip, struct file *fp)
+{
+ struct f_ccid *ccid_dev = fp->private_data;
+ struct ccid_bulk_dev *bulk_dev = &ccid_dev->bulk_dev;
+
+ pr_debug("ccid_bulk_release\n");
+ atomic_set(&bulk_dev->opened, 0);
+ return 0;
+}
+
+static ssize_t ccid_bulk_read(struct file *fp, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct f_ccid *ccid_dev = fp->private_data;
+ struct ccid_bulk_dev *bulk_dev = &ccid_dev->bulk_dev;
+ struct usb_request *req;
+ int r = count, xfer;
+ int ret;
+ unsigned long flags;
+
+ pr_debug("ccid_bulk_read(%d)\n", count);
+
+ if (count > BULK_OUT_BUFFER_SIZE) {
+ pr_err("%s: max_buffer_size:%d given_pkt_size:%d\n",
+ __func__, BULK_OUT_BUFFER_SIZE, count);
+ return -ENOMEM;
+ }
+
+ if (atomic_read(&bulk_dev->error)) {
+ r = -EIO;
+ pr_err("%s bulk_dev_error\n", __func__);
+ goto done;
+ }
+
+requeue_req:
+ spin_lock_irqsave(&ccid_dev->lock, flags);
+ if (!atomic_read(&ccid_dev->online)) {
+ pr_debug("%s: USB cable not connected\n", __func__);
+ return -ENODEV;
+ }
+ /* queue a request */
+ req = bulk_dev->rx_req;
+ req->length = count;
+ bulk_dev->rx_done = 0;
+ spin_unlock_irqrestore(&ccid_dev->lock, flags);
+ ret = usb_ep_queue(ccid_dev->out, req, GFP_KERNEL);
+ if (ret < 0) {
+ r = -EIO;
+ pr_err("%s usb ep queue failed\n", __func__);
+ atomic_set(&bulk_dev->error, 1);
+ goto done;
+ }
+ /* wait for a request to complete */
+ ret = wait_event_interruptible(bulk_dev->read_wq, bulk_dev->rx_done ||
+ atomic_read(&bulk_dev->error) ||
+ !atomic_read(&ccid_dev->online));
+ if (ret < 0) {
+ atomic_set(&bulk_dev->error, 1);
+ r = ret;
+ usb_ep_dequeue(ccid_dev->out, req);
+ goto done;
+ }
+ if (!atomic_read(&bulk_dev->error)) {
+ spin_lock_irqsave(&ccid_dev->lock, flags);
+ if (!atomic_read(&ccid_dev->online)) {
+ spin_unlock_irqrestore(&ccid_dev->lock, flags);
+ pr_debug("%s: USB cable not connected\n", __func__);
+ r = -ENODEV;
+ goto done;
+ }
+ /* If we got a 0-len packet, throw it back and try again. */
+ if (req->actual == 0) {
+ spin_unlock_irqrestore(&ccid_dev->lock, flags);
+ goto requeue_req;
+ }
+ xfer = (req->actual < count) ? req->actual : count;
+ atomic_set(&bulk_dev->rx_req_busy, 1);
+ spin_unlock_irqrestore(&ccid_dev->lock, flags);
+
+ if (copy_to_user(buf, req->buf, xfer))
+ r = -EFAULT;
+
+ spin_lock_irqsave(&ccid_dev->lock, flags);
+ atomic_set(&bulk_dev->rx_req_busy, 0);
+ if (!atomic_read(&ccid_dev->online)) {
+ ccid_request_free(bulk_dev->rx_req, ccid_dev->out);
+ spin_unlock_irqrestore(&ccid_dev->lock, flags);
+ pr_debug("%s: USB cable not connected\n", __func__);
+ r = -ENODEV;
+ goto done;
+ }
+ spin_unlock_irqrestore(&ccid_dev->lock, flags);
+ } else {
+ r = -EIO;
+ }
+done:
+ pr_debug("ccid_bulk_read returning %d\n", r);
+ return r;
+}
+
+static ssize_t ccid_bulk_write(struct file *fp, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct f_ccid *ccid_dev = fp->private_data;
+ struct ccid_bulk_dev *bulk_dev = &ccid_dev->bulk_dev;
+ struct usb_request *req = 0;
+ int r = count;
+ int ret;
+ unsigned long flags;
+
+ pr_debug("ccid_bulk_write(%d)\n", count);
+
+ if (!atomic_read(&ccid_dev->online)) {
+ pr_debug("%s: USB cable not connected\n", __func__);
+ return -ENODEV;
+ }
+
+ if (!count) {
+ pr_err("%s: zero length ctrl pkt\n", __func__);
+ return -ENODEV;
+ }
+ if (count > BULK_IN_BUFFER_SIZE) {
+ pr_err("%s: max_buffer_size:%d given_pkt_size:%d\n",
+ __func__, BULK_IN_BUFFER_SIZE, count);
+ return -ENOMEM;
+ }
+
+
+ /* get an idle tx request to use */
+ ret = wait_event_interruptible(bulk_dev->write_wq,
+ ((req = ccid_req_get(ccid_dev, &bulk_dev->tx_idle)) ||
+ atomic_read(&bulk_dev->error)));
+
+ if (ret < 0) {
+ r = ret;
+ goto done;
+ }
+
+ if (atomic_read(&bulk_dev->error)) {
+ pr_err(" %s dev->error\n", __func__);
+ r = -EIO;
+ goto done;
+ }
+ if (copy_from_user(req->buf, buf, count)) {
+ if (!atomic_read(&ccid_dev->online)) {
+ pr_debug("%s: USB cable not connected\n",
+ __func__);
+ ccid_request_free(req, ccid_dev->in);
+ r = -ENODEV;
+ } else {
+ ccid_req_put(ccid_dev, &bulk_dev->tx_idle, req);
+ r = -EFAULT;
+ }
+ goto done;
+ }
+ req->length = count;
+ ret = usb_ep_queue(ccid_dev->in, req, GFP_KERNEL);
+ if (ret < 0) {
+ pr_debug("ccid_bulk_write: xfer error %d\n", ret);
+ atomic_set(&bulk_dev->error, 1);
+ ccid_req_put(ccid_dev, &bulk_dev->tx_idle, req);
+ r = -EIO;
+ spin_lock_irqsave(&ccid_dev->lock, flags);
+ if (!atomic_read(&ccid_dev->online)) {
+ spin_unlock_irqrestore(&ccid_dev->lock, flags);
+ pr_debug("%s: USB cable not connected\n",
+ __func__);
+ while ((req = ccid_req_get(ccid_dev,
+ &bulk_dev->tx_idle)))
+ ccid_request_free(req, ccid_dev->in);
+ r = -ENODEV;
+ }
+ spin_unlock_irqrestore(&ccid_dev->lock, flags);
+ goto done;
+ }
+done:
+ pr_debug("ccid_bulk_write returning %d\n", r);
+ return r;
+}
+
+static const struct file_operations ccid_bulk_fops = {
+ .owner = THIS_MODULE,
+ .read = ccid_bulk_read,
+ .write = ccid_bulk_write,
+ .open = ccid_bulk_open,
+ .release = ccid_bulk_release,
+};
+
+static struct miscdevice ccid_bulk_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "ccid_bulk",
+ .fops = &ccid_bulk_fops,
+};
+
+static int ccid_bulk_device_init(struct f_ccid *dev)
+{
+ int ret;
+ struct ccid_bulk_dev *bulk_dev = &dev->bulk_dev;
+
+ init_waitqueue_head(&bulk_dev->read_wq);
+ init_waitqueue_head(&bulk_dev->write_wq);
+ INIT_LIST_HEAD(&bulk_dev->tx_idle);
+
+ ret = misc_register(&ccid_bulk_device);
+ if (ret) {
+ pr_err("%s: failed to register misc device\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ccid_ctrl_open(struct inode *inode, struct file *fp)
+{
+ struct f_ccid *ccid_dev = _ccid_dev;
+ struct ccid_ctrl_dev *ctrl_dev = &ccid_dev->ctrl_dev;
+ unsigned long flags;
+
+ if (!atomic_read(&ccid_dev->online)) {
+ pr_debug("%s: USB cable not connected\n", __func__);
+ return -ENODEV;
+ }
+ if (atomic_read(&ctrl_dev->opened)) {
+ pr_debug("%s: ctrl device is already opened\n", __func__);
+ return -EBUSY;
+ }
+ atomic_set(&ctrl_dev->opened, 1);
+ spin_lock_irqsave(&ccid_dev->lock, flags);
+ fp->private_data = ccid_dev;
+ spin_unlock_irqrestore(&ccid_dev->lock, flags);
+
+ return 0;
+}
+
+
+static int ccid_ctrl_release(struct inode *inode, struct file *fp)
+{
+ struct f_ccid *ccid_dev = fp->private_data;
+ struct ccid_ctrl_dev *ctrl_dev = &ccid_dev->ctrl_dev;
+
+ atomic_set(&ctrl_dev->opened, 0);
+
+ return 0;
+}
+
+static ssize_t ccid_ctrl_read(struct file *fp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct f_ccid *ccid_dev = fp->private_data;
+ struct ccid_ctrl_dev *ctrl_dev = &ccid_dev->ctrl_dev;
+ int ret = 0;
+
+ if (!atomic_read(&ccid_dev->online)) {
+ pr_debug("%s: USB cable not connected\n", __func__);
+ return -ENODEV;
+ }
+ if (count > CTRL_BUF_SIZE)
+ count = CTRL_BUF_SIZE;
+
+ ret = wait_event_interruptible(ctrl_dev->tx_wait_q,
+ ctrl_dev->tx_ctrl_done);
+ if (ret < 0)
+ return ret;
+ ctrl_dev->tx_ctrl_done = 0;
+
+ if (!atomic_read(&ccid_dev->online)) {
+ pr_debug("%s: USB cable not connected\n", __func__);
+ return -ENODEV;
+ }
+ ret = copy_to_user(buf, ctrl_dev->buf, count);
+ if (ret)
+ return -EFAULT;
+
+ return count;
+}
+
+static long
+ccid_ctrl_ioctl(struct file *fp, unsigned cmd, u_long arg)
+{
+ struct f_ccid *ccid_dev = fp->private_data;
+ struct usb_request *req = ccid_dev->notify_req;
+ struct usb_ccid_notification *ccid_notify = req->buf;
+ void __user *argp = (void __user *)arg;
+ int ret = 0;
+
+ switch (cmd) {
+ case CCID_NOTIFY_CARD:
+ if (copy_from_user(ccid_notify, argp,
+ sizeof(struct usb_ccid_notification)))
+ return -EFAULT;
+ req->length = 2;
+ break;
+ case CCID_NOTIFY_HWERROR:
+ if (copy_from_user(ccid_notify, argp,
+ sizeof(struct usb_ccid_notification)))
+ return -EFAULT;
+ req->length = 4;
+ break;
+ case CCID_READ_DTR:
+ if (copy_to_user((int *)arg, &ccid_dev->dtr_state, sizeof(int)))
+ return -EFAULT;
+ return 0;
+ }
+ ret = usb_ep_queue(ccid_dev->notify, ccid_dev->notify_req, GFP_KERNEL);
+ if (ret < 0) {
+ pr_err("ccid notify ep enqueue error %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+static const struct file_operations ccid_ctrl_fops = {
+ .owner = THIS_MODULE,
+ .open = ccid_ctrl_open,
+ .release = ccid_ctrl_release,
+ .read = ccid_ctrl_read,
+ .unlocked_ioctl = ccid_ctrl_ioctl,
+};
+
+static struct miscdevice ccid_ctrl_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "ccid_ctrl",
+ .fops = &ccid_ctrl_fops,
+};
+
+static int ccid_ctrl_device_init(struct f_ccid *dev)
+{
+ int ret;
+ struct ccid_ctrl_dev *ctrl_dev = &dev->ctrl_dev;
+
+ INIT_LIST_HEAD(&ctrl_dev->tx_q);
+ init_waitqueue_head(&ctrl_dev->tx_wait_q);
+
+ ret = misc_register(&ccid_ctrl_device);
+ if (ret) {
+ pr_err("%s: failed to register misc device\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ccid_bind_config(struct usb_configuration *c)
+{
+ struct f_ccid *ccid_dev = _ccid_dev;
+
+ pr_debug("ccid_bind_config\n");
+ ccid_dev->cdev = c->cdev;
+ ccid_dev->function.name = FUNCTION_NAME;
+ ccid_dev->function.descriptors = ccid_fs_descs;
+ ccid_dev->function.hs_descriptors = ccid_hs_descs;
+ ccid_dev->function.bind = ccid_function_bind;
+ ccid_dev->function.unbind = ccid_function_unbind;
+ ccid_dev->function.set_alt = ccid_function_set_alt;
+ ccid_dev->function.setup = ccid_function_setup;
+ ccid_dev->function.disable = ccid_function_disable;
+
+ return usb_add_function(c, &ccid_dev->function);
+
+}
+
+static int ccid_setup(void)
+{
+ struct f_ccid *ccid_dev;
+ int ret;
+
+ ccid_dev = kzalloc(sizeof(*ccid_dev), GFP_KERNEL);
+ if (!ccid_dev)
+ return -ENOMEM;
+
+ _ccid_dev = ccid_dev;
+ spin_lock_init(&ccid_dev->lock);
+
+ ret = ccid_ctrl_device_init(ccid_dev);
+ if (ret) {
+ pr_err("%s: ccid_ctrl_device_init failed, err:%d\n",
+ __func__, ret);
+ goto err_ctrl_init;
+ }
+ ret = ccid_bulk_device_init(ccid_dev);
+ if (ret) {
+ pr_err("%s: ccid_bulk_device_init failed, err:%d\n",
+ __func__, ret);
+ goto err_bulk_init;
+ }
+
+ return 0;
+err_bulk_init:
+ misc_deregister(&ccid_ctrl_device);
+err_ctrl_init:
+ kfree(ccid_dev);
+ pr_err("ccid gadget driver failed to initialize\n");
+ return ret;
+}
+
+static void ccid_cleanup(void)
+{
+ misc_deregister(&ccid_bulk_device);
+ misc_deregister(&ccid_ctrl_device);
+ kfree(_ccid_dev);
+}
diff --git a/drivers/usb/gadget/f_ccid.h b/drivers/usb/gadget/f_ccid.h
new file mode 100644
index 0000000..4d6a0ea
--- /dev/null
+++ b/drivers/usb/gadget/f_ccid.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 __F_CCID_H
+#define __F_CCID_H
+
+#define PROTOCOL_TO 0x01
+#define PROTOCOL_T1 0x02
+#define ABDATA_SIZE 512
+
+/* define for dwFeatures for Smart Card Device Class Descriptors */
+/* No special characteristics */
+#define CCID_FEATURES_NADA 0x00000000
+/* Automatic parameter configuration based on ATR data */
+#define CCID_FEATURES_AUTO_PCONF 0x00000002
+/* Automatic activation of ICC on inserting */
+#define CCID_FEATURES_AUTO_ACTIV 0x00000004
+/* Automatic ICC voltage selection */
+#define CCID_FEATURES_AUTO_VOLT 0x00000008
+/* Automatic ICC clock frequency change */
+#define CCID_FEATURES_AUTO_CLOCK 0x00000010
+/* Automatic baud rate change */
+#define CCID_FEATURES_AUTO_BAUD 0x00000020
+/*Automatic parameters negotiation made by the CCID */
+#define CCID_FEATURES_AUTO_PNEGO 0x00000040
+/* Automatic PPS made by the CCID according to the active parameters */
+#define CCID_FEATURES_AUTO_PPS 0x00000080
+/* CCID can set ICC in clock stop mode */
+#define CCID_FEATURES_ICCSTOP 0x00000100
+/* NAD value other than 00 accepted (T=1 protocol in use) */
+#define CCID_FEATURES_NAD 0x00000200
+/* Automatic IFSD exchange as first exchange (T=1 protocol in use) */
+#define CCID_FEATURES_AUTO_IFSD 0x00000400
+/* TPDU level exchanges with CCID */
+#define CCID_FEATURES_EXC_TPDU 0x00010000
+/* Short APDU level exchange with CCID */
+#define CCID_FEATURES_EXC_SAPDU 0x00020000
+/* Short and Extended APDU level exchange with CCID */
+#define CCID_FEATURES_EXC_APDU 0x00040000
+/* USB Wake up signaling supported on card insertion and removal */
+#define CCID_FEATURES_WAKEUP 0x00100000
+
+#define CCID_NOTIFY_CARD _IOW('C', 1, struct usb_ccid_notification)
+#define CCID_NOTIFY_HWERROR _IOW('C', 2, struct usb_ccid_notification)
+#define CCID_READ_DTR _IOR('C', 3, int)
+
+struct usb_ccid_notification {
+ unsigned char buf[4];
+} __packed;
+
+struct ccid_bulk_in_header {
+ unsigned char bMessageType;
+ unsigned long wLength;
+ unsigned char bSlot;
+ unsigned char bSeq;
+ unsigned char bStatus;
+ unsigned char bError;
+ unsigned char bSpecific;
+ unsigned char abData[ABDATA_SIZE];
+ unsigned char bSizeToSend;
+} __packed;
+
+struct ccid_bulk_out_header {
+ unsigned char bMessageType;
+ unsigned long wLength;
+ unsigned char bSlot;
+ unsigned char bSeq;
+ unsigned char bSpecific_0;
+ unsigned char bSpecific_1;
+ unsigned char bSpecific_2;
+ unsigned char APDU[ABDATA_SIZE];
+} __packed;
+#endif
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index 7686bf2..32791d9 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -17,7 +17,7 @@
#include <linux/usb/android_composite.h>
#include <linux/spinlock.h>
-#include <linux/platform_data/usb_rmnet.h>
+#include <mach/usb_gadget_xport.h>
#include "u_rmnet.h"
#include "gadget_chips.h"
@@ -63,7 +63,15 @@
#define NR_RMNET_PORTS 1
static unsigned int nr_rmnet_ports;
+static unsigned int no_ctrl_smd_ports;
+static unsigned int no_ctrl_hsic_ports;
+static unsigned int no_data_bam_ports;
+static unsigned int no_data_hsic_ports;
static struct rmnet_ports {
+ enum transport_type data_xport;
+ enum transport_type ctrl_xport;
+ unsigned data_xport_num;
+ unsigned ctrl_xport_num;
unsigned port_num;
struct f_rmnet *port;
} rmnet_ports[NR_RMNET_PORTS];
@@ -227,42 +235,123 @@
/* -------------------------------------------*/
-static int rmnet_gport_setup(int no_rmnet_ports)
+static int rmnet_gport_setup(void)
{
- int ret;
+ int ret;
+ int port_idx;
+ int i;
- pr_debug("%s: no_rmnet_ports:%d\n", __func__, no_rmnet_ports);
+ pr_debug("%s: bam ports: %u data hsic ports: %u smd ports: %u"
+ " ctrl hsic ports: %u nr_rmnet_ports: %u\n",
+ __func__, no_data_bam_ports, no_data_hsic_ports,
+ no_ctrl_smd_ports, no_ctrl_hsic_ports, nr_rmnet_ports);
- ret = gbam_setup(no_rmnet_ports);
- if (ret)
- return ret;
+ if (no_data_bam_ports) {
+ ret = gbam_setup(no_data_bam_ports);
+ if (ret)
+ return ret;
+ }
- ret = gsmd_ctrl_setup(no_rmnet_ports);
- if (ret)
- return ret;
+ if (no_ctrl_smd_ports) {
+ ret = gsmd_ctrl_setup(no_ctrl_smd_ports);
+ if (ret)
+ return ret;
+ }
+
+ if (no_data_hsic_ports) {
+ port_idx = ghsic_data_setup(no_data_hsic_ports,
+ USB_GADGET_RMNET);
+ if (port_idx < 0)
+ return port_idx;
+ for (i = 0; i < nr_rmnet_ports; i++) {
+ if (rmnet_ports[i].data_xport ==
+ USB_GADGET_XPORT_HSIC) {
+ rmnet_ports[i].data_xport_num = port_idx;
+ port_idx++;
+ }
+ }
+ }
+
+ if (no_ctrl_hsic_ports) {
+ port_idx = ghsic_ctrl_setup(no_ctrl_hsic_ports,
+ USB_GADGET_RMNET);
+ if (port_idx < 0)
+ return port_idx;
+ for (i = 0; i < nr_rmnet_ports; i++) {
+ if (rmnet_ports[i].ctrl_xport ==
+ USB_GADGET_XPORT_HSIC) {
+ rmnet_ports[i].ctrl_xport_num = port_idx;
+ port_idx++;
+ }
+ }
+ }
return 0;
}
static int gport_rmnet_connect(struct f_rmnet *dev)
{
- int ret;
+ int ret;
+ 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;
- pr_debug("%s:dev:%p portno:%d\n",
- __func__, dev, dev->port_num);
+ pr_debug("%s: ctrl xport: %s data xport: %s dev: %p portno: %d\n",
+ __func__, xport_to_str(cxport), xport_to_str(dxport),
+ dev, dev->port_num);
- ret = gsmd_ctrl_connect(&dev->port, dev->port_num);
- if (ret) {
- pr_err("%s: gsmd_ctrl_connect failed: err:%d\n",
- __func__, ret);
- return ret;
+ port_num = rmnet_ports[dev->port_num].ctrl_xport_num;
+ switch (cxport) {
+ case USB_GADGET_XPORT_SMD:
+ ret = gsmd_ctrl_connect(&dev->port, port_num);
+ if (ret) {
+ pr_err("%s: gsmd_ctrl_connect failed: err:%d\n",
+ __func__, ret);
+ return ret;
+ }
+ break;
+ case USB_GADGET_XPORT_HSIC:
+ ret = ghsic_ctrl_connect(&dev->port, port_num);
+ if (ret) {
+ pr_err("%s: ghsic_ctrl_connect failed: err:%d\n",
+ __func__, ret);
+ return ret;
+ }
+ break;
+ case USB_GADGET_XPORT_NONE:
+ break;
+ default:
+ pr_err("%s: Un-supported transport: %s\n", __func__,
+ xport_to_str(cxport));
+ return -ENODEV;
}
- ret = gbam_connect(&dev->port, dev->port_num);
- if (ret) {
- pr_err("%s: gbam_connect failed: err:%d\n",
- __func__, ret);
- return ret;
+ port_num = rmnet_ports[dev->port_num].data_xport_num;
+ switch (dxport) {
+ case USB_GADGET_XPORT_BAM:
+ ret = gbam_connect(&dev->port, port_num);
+ 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_HSIC:
+ ret = ghsic_data_connect(&dev->port, port_num);
+ if (ret) {
+ pr_err("%s: ghsic_data_connect failed: err:%d\n",
+ __func__, ret);
+ ghsic_ctrl_disconnect(&dev->port, port_num);
+ return ret;
+ }
+ break;
+ case USB_GADGET_XPORT_NONE:
+ break;
+ default:
+ pr_err("%s: Un-supported transport: %s\n", __func__,
+ xport_to_str(dxport));
+ return -ENODEV;
}
return 0;
@@ -270,12 +359,45 @@
static int gport_rmnet_disconnect(struct f_rmnet *dev)
{
- pr_debug("%s:dev:%p portno:%d\n",
- __func__, dev, dev->port_num);
+ 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;
- gbam_disconnect(&dev->port, dev->port_num);
+ pr_debug("%s: ctrl xport: %s data xport: %s dev: %p portno: %d\n",
+ __func__, xport_to_str(cxport), xport_to_str(dxport),
+ dev, dev->port_num);
- gsmd_ctrl_disconnect(&dev->port, dev->port_num);
+ port_num = rmnet_ports[dev->port_num].ctrl_xport_num;
+ switch (cxport) {
+ case USB_GADGET_XPORT_SMD:
+ gsmd_ctrl_disconnect(&dev->port, port_num);
+ break;
+ case USB_GADGET_XPORT_HSIC:
+ ghsic_ctrl_disconnect(&dev->port, port_num);
+ break;
+ case USB_GADGET_XPORT_NONE:
+ break;
+ default:
+ pr_err("%s: Un-supported transport: %s\n", __func__,
+ xport_to_str(cxport));
+ return -ENODEV;
+ }
+
+ port_num = rmnet_ports[dev->port_num].data_xport_num;
+ switch (dxport) {
+ case USB_GADGET_XPORT_BAM:
+ gbam_disconnect(&dev->port, port_num);
+ break;
+ case USB_GADGET_XPORT_HSIC:
+ ghsic_data_disconnect(&dev->port, port_num);
+ break;
+ case USB_GADGET_XPORT_NONE:
+ break;
+ default:
+ pr_err("%s: Un-supported transport: %s\n", __func__,
+ xport_to_str(dxport));
+ return -ENODEV;
+ }
return 0;
}
@@ -466,16 +588,24 @@
}
static int
-frmnet_send_cpkt_response(struct grmnet *gr, struct rmnet_ctrl_pkt *cpkt)
+frmnet_send_cpkt_response(void *gr, void *buf, size_t len)
{
struct f_rmnet *dev;
+ struct rmnet_ctrl_pkt *cpkt;
unsigned long flags;
- if (!gr || !cpkt) {
- pr_err("%s: Invalid grmnet/cpkt, grmnet:%p cpkt:%p\n",
- __func__, gr, cpkt);
+ if (!gr || !buf) {
+ pr_err("%s: Invalid grmnet/buf, grmnet:%p buf:%p\n",
+ __func__, gr, buf);
return -ENODEV;
}
+ cpkt = rmnet_alloc_ctrl_pkt(len, GFP_ATOMIC);
+ if (IS_ERR(cpkt)) {
+ pr_err("%s: Unable to allocate ctrl pkt\n", __func__);
+ return -ENOMEM;
+ }
+ memcpy(cpkt->buf, buf, len);
+ cpkt->len = len;
dev = port_to_rmnet(gr);
@@ -500,7 +630,7 @@
{
struct f_rmnet *dev = req->context;
struct usb_composite_dev *cdev;
- struct rmnet_ctrl_pkt *cpkt;
+ unsigned port_num;
if (!dev) {
pr_err("%s: rmnet dev is null\n", __func__);
@@ -511,16 +641,10 @@
cdev = dev->cdev;
- cpkt = rmnet_alloc_ctrl_pkt(req->actual, GFP_ATOMIC);
- if (IS_ERR(cpkt)) {
- pr_err("%s: Unable to allocate ctrl pkt\n", __func__);
- return;
+ if (dev->port.send_encap_cmd) {
+ port_num = rmnet_ports[dev->port_num].ctrl_xport_num;
+ dev->port.send_encap_cmd(port_num, req->buf, req->actual);
}
-
- memcpy(cpkt->buf, req->buf, req->actual);
-
- if (dev->port.send_cpkt_request)
- dev->port.send_cpkt_request(&dev->port, dev->port_num, cpkt);
}
static void frmnet_notify_complete(struct usb_ep *ep, struct usb_request *req)
@@ -561,6 +685,7 @@
struct f_rmnet *dev = func_to_rmnet(f);
struct usb_composite_dev *cdev = dev->cdev;
struct usb_request *req = cdev->req;
+ unsigned port_num;
u16 w_index = le16_to_cpu(ctrl->wIndex);
u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength);
@@ -615,10 +740,10 @@
break;
case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
| USB_CDC_REQ_SET_CONTROL_LINE_STATE:
- if (dev->port.send_cbits_tomodem)
- dev->port.send_cbits_tomodem(&dev->port,
- dev->port_num,
- w_value);
+ if (dev->port.notify_modem) {
+ port_num = rmnet_ports[dev->port_num].ctrl_xport_num;
+ dev->port.notify_modem(&dev->port, port_num, w_value);
+ }
ret = 0;
break;
@@ -827,42 +952,80 @@
kfree(rmnet_ports[i].port);
nr_rmnet_ports = 0;
+ no_ctrl_smd_ports = 0;
+ no_data_bam_ports = 0;
+ no_ctrl_hsic_ports = 0;
+ no_data_hsic_ports = 0;
}
-static int frmnet_init_port(int instances)
+static int frmnet_init_port(const char *ctrl_name, const char *data_name)
{
- int i;
- struct f_rmnet *dev;
- int ret;
+ struct f_rmnet *dev;
+ struct rmnet_ports *rmnet_port;
+ int ret;
+ int i;
- pr_debug("%s: instances :%d\n", __func__, instances);
-
- if (instances > NR_RMNET_PORTS) {
- pr_err("%s: Max-%d instances supported\n", __func__,
- NR_RMNET_PORTS);
+ if (nr_rmnet_ports >= NR_RMNET_PORTS) {
+ pr_err("%s: Max-%d instances supported\n",
+ __func__, NR_RMNET_PORTS);
return -EINVAL;
}
- for (i = 0; i < instances; i++) {
- dev = kzalloc(sizeof(struct f_rmnet), GFP_KERNEL);
- if (!dev) {
- pr_err("%s: Unable to allocate rmnet device\n",
- __func__);
- ret = -ENOMEM;
- goto fail_probe;
- }
+ pr_debug("%s: port#:%d, ctrl port: %s data port: %s\n",
+ __func__, nr_rmnet_ports, ctrl_name, data_name);
- dev->port_num = i;
- spin_lock_init(&dev->lock);
- INIT_LIST_HEAD(&dev->cpkt_resp_q);
-
- rmnet_ports[i].port = dev;
- rmnet_ports[i].port_num = i;
-
- nr_rmnet_ports++;
+ dev = kzalloc(sizeof(struct f_rmnet), GFP_KERNEL);
+ if (!dev) {
+ pr_err("%s: Unable to allocate rmnet device\n", __func__);
+ return -ENOMEM;
}
- rmnet_gport_setup(nr_rmnet_ports);
+ dev->port_num = nr_rmnet_ports;
+ spin_lock_init(&dev->lock);
+ INIT_LIST_HEAD(&dev->cpkt_resp_q);
+
+ rmnet_port = &rmnet_ports[nr_rmnet_ports];
+ rmnet_port->port = dev;
+ rmnet_port->port_num = nr_rmnet_ports;
+ rmnet_port->ctrl_xport = str_to_xport(ctrl_name);
+ rmnet_port->data_xport = str_to_xport(data_name);
+
+ switch (rmnet_port->ctrl_xport) {
+ case USB_GADGET_XPORT_SMD:
+ rmnet_port->ctrl_xport_num = no_ctrl_smd_ports;
+ no_ctrl_smd_ports++;
+ break;
+ case USB_GADGET_XPORT_HSIC:
+ rmnet_port->ctrl_xport_num = no_ctrl_hsic_ports;
+ no_ctrl_hsic_ports++;
+ break;
+ case USB_GADGET_XPORT_NONE:
+ break;
+ default:
+ pr_err("%s: Un-supported transport: %u\n", __func__,
+ rmnet_port->ctrl_xport);
+ ret = -ENODEV;
+ goto fail_probe;
+ }
+
+ switch (rmnet_port->data_xport) {
+ case USB_GADGET_XPORT_BAM:
+ rmnet_port->data_xport_num = no_data_bam_ports;
+ no_data_bam_ports++;
+ break;
+ case USB_GADGET_XPORT_HSIC:
+ rmnet_port->data_xport_num = no_data_hsic_ports;
+ no_data_hsic_ports++;
+ break;
+ case USB_GADGET_XPORT_NONE:
+ break;
+ default:
+ pr_err("%s: Un-supported transport: %u\n", __func__,
+ rmnet_port->data_xport);
+ ret = -ENODEV;
+ goto fail_probe;
+ }
+ nr_rmnet_ports++;
return 0;
@@ -870,5 +1033,11 @@
for (i = 0; i < nr_rmnet_ports; i++)
kfree(rmnet_ports[i].port);
+ nr_rmnet_ports = 0;
+ no_ctrl_smd_ports = 0;
+ no_data_bam_ports = 0;
+ no_ctrl_hsic_ports = 0;
+ no_data_hsic_ports = 0;
+
return ret;
}
diff --git a/drivers/usb/gadget/f_rmnet_smd_sdio.c b/drivers/usb/gadget/f_rmnet_smd_sdio.c
index 2ddbd7c..f974b8a 100644
--- a/drivers/usb/gadget/f_rmnet_smd_sdio.c
+++ b/drivers/usb/gadget/f_rmnet_smd_sdio.c
@@ -42,6 +42,7 @@
#include <mach/msm_smd.h>
#include <mach/sdio_cmux.h>
#include <mach/sdio_dmux.h>
+#include <mach/usb_gadget_xport.h>
#ifdef CONFIG_RMNET_SMD_SDIO_CTL_CHANNEL
static uint32_t rmnet_mux_sdio_ctl_ch = CONFIG_RMNET_SMD_SDIO_CTL_CHANNEL;
@@ -104,12 +105,6 @@
struct list_head list;
};
-enum usb_rmnet_mux_xport_type {
- USB_RMNET_MUX_XPORT_UNDEFINED,
- USB_RMNET_MUX_XPORT_SDIO,
- USB_RMNET_MUX_XPORT_SMD,
-};
-
struct rmnet_mux_ctrl_dev {
struct list_head tx_q;
wait_queue_head_t tx_wait_q;
@@ -176,7 +171,7 @@
struct rmnet_mux_ctrl_dev ctrl_dev;
u8 ifc_id;
- enum usb_rmnet_mux_xport_type xport;
+ enum transport_type xport;
spinlock_t lock;
atomic_t online;
atomic_t notify_count;
@@ -291,18 +286,6 @@
NULL,
};
-static char *xport_to_str(enum usb_rmnet_mux_xport_type t)
-{
- switch (t) {
- case USB_RMNET_MUX_XPORT_SDIO:
- return "SDIO";
- case USB_RMNET_MUX_XPORT_SMD:
- return "SMD";
- default:
- return "UNDEFINED";
- }
-}
-
static struct rmnet_mux_ctrl_pkt *rmnet_mux_alloc_ctrl_pkt(unsigned len,
gfp_t flags)
{
@@ -556,7 +539,7 @@
int status = req->status;
int queue = 0;
- if (dev->xport == USB_RMNET_MUX_XPORT_UNDEFINED) {
+ if (dev->xport == USB_GADGET_XPORT_UNDEF) {
dev_kfree_skb_any(skb);
req->buf = 0;
rmnet_mux_free_req(ep, req);
@@ -614,7 +597,7 @@
struct usb_composite_dev *cdev = dev->cdev;
int status = req->status;
- if (dev->xport == USB_RMNET_MUX_XPORT_UNDEFINED) {
+ if (dev->xport == USB_GADGET_XPORT_UNDEF) {
dev_kfree_skb_any(skb);
req->buf = 0;
rmnet_mux_free_req(ep, req);
@@ -797,7 +780,7 @@
int status = req->status;
int ret;
- if (dev->xport == USB_RMNET_MUX_XPORT_UNDEFINED) {
+ if (dev->xport == USB_GADGET_XPORT_UNDEF) {
rmnet_mux_free_req(ep, req);
return;
}
@@ -857,7 +840,7 @@
int status = req->status;
int schedule = 0;
- if (dev->xport == USB_RMNET_MUX_XPORT_UNDEFINED) {
+ if (dev->xport == USB_GADGET_XPORT_UNDEF) {
rmnet_mux_free_req(ep, req);
return;
}
@@ -1276,7 +1259,7 @@
struct rmnet_mux_smd_dev *smd_dev = &dev->smd_dev;
struct rmnet_mux_ctrl_dev *ctrl_dev = &dev->ctrl_dev;
- if (dev->xport == USB_RMNET_MUX_XPORT_SMD) {
+ if (dev->xport == USB_GADGET_XPORT_SMD) {
tasklet_kill(&smd_dev->smd_data.rx_tlet);
tasklet_kill(&smd_dev->smd_data.tx_tlet);
}
@@ -1416,8 +1399,8 @@
struct rmnet_mux_dev *dev = container_of(f, struct rmnet_mux_dev,
function);
int value;
- enum usb_rmnet_mux_xport_type given_xport;
- enum usb_rmnet_mux_xport_type t;
+ enum transport_type given_xport;
+ enum transport_type t;
struct rmnet_mux_smd_dev *smd_dev = &dev->smd_dev;
struct rmnet_mux_sdio_dev *sdio_dev = &dev->sdio_dev;
struct list_head *pool;
@@ -1433,9 +1416,9 @@
sscanf(buf, "%d", &value);
if (value)
- given_xport = USB_RMNET_MUX_XPORT_SDIO;
+ given_xport = USB_GADGET_XPORT_SDIO;
else
- given_xport = USB_RMNET_MUX_XPORT_SMD;
+ given_xport = USB_GADGET_XPORT_SMD;
if (given_xport == dev->xport) {
pr_err("%s: given_xport:%s cur_xport:%s doing nothing\n",
@@ -1449,14 +1432,14 @@
/* prevent any other pkts to/from usb */
t = dev->xport;
- dev->xport = USB_RMNET_MUX_XPORT_UNDEFINED;
- if (t != USB_RMNET_MUX_XPORT_UNDEFINED) {
+ dev->xport = USB_GADGET_XPORT_UNDEF;
+ if (t != USB_GADGET_XPORT_UNDEF) {
usb_ep_fifo_flush(dev->epin);
usb_ep_fifo_flush(dev->epout);
}
switch (t) {
- case USB_RMNET_MUX_XPORT_SDIO:
+ case USB_GADGET_XPORT_SDIO:
spin_lock_irqsave(&dev->lock, flags);
/* tx_idle */
@@ -1491,7 +1474,7 @@
spin_unlock_irqrestore(&dev->lock, flags);
break;
- case USB_RMNET_MUX_XPORT_SMD:
+ case USB_GADGET_XPORT_SMD:
/* close smd xport */
tasklet_kill(&smd_dev->smd_data.rx_tlet);
tasklet_kill(&smd_dev->smd_data.tx_tlet);
@@ -1530,10 +1513,10 @@
dev->xport = given_xport;
switch (dev->xport) {
- case USB_RMNET_MUX_XPORT_SDIO:
+ case USB_GADGET_XPORT_SDIO:
rmnet_mux_sdio_enable(dev);
break;
- case USB_RMNET_MUX_XPORT_SMD:
+ case USB_GADGET_XPORT_SMD:
rmnet_mux_smd_enable(dev);
break;
default:
diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c
index 6cf148a..de8c8ed 100644
--- a/drivers/usb/gadget/f_serial.c
+++ b/drivers/usb/gadget/f_serial.c
@@ -13,7 +13,7 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/device.h>
-#include <mach/usb_gadget_fserial.h>
+#include <mach/usb_gadget_xport.h>
#include "u_serial.h"
#include "gadget_chips.h"
@@ -27,6 +27,7 @@
* CDC ACM driver. However, for many purposes it's just as functional
* if you can arrange appropriate host side drivers.
*/
+#define GSERIAL_NO_PORTS 2
struct gser_descs {
struct usb_endpoint_descriptor *in;
@@ -75,6 +76,7 @@
static unsigned int no_tty_ports;
static unsigned int no_sdio_ports;
static unsigned int no_smd_ports;
+static unsigned int no_hsic_sports;
static unsigned int nr_ports;
static struct port_info {
@@ -85,7 +87,7 @@
static inline bool is_transport_sdio(enum transport_type t)
{
- if (t == USB_GADGET_FSERIAL_TRANSPORT_SDIO)
+ if (t == USB_GADGET_XPORT_SDIO)
return 1;
return 0;
}
@@ -250,37 +252,16 @@
NULL,
};
-static char *transport_to_str(enum transport_type t)
-{
- switch (t) {
- case USB_GADGET_FSERIAL_TRANSPORT_TTY:
- return "TTY";
- case USB_GADGET_FSERIAL_TRANSPORT_SDIO:
- return "SDIO";
- case USB_GADGET_FSERIAL_TRANSPORT_SMD:
- return "SMD";
- }
-
- return "NONE";
-}
-
-static enum transport_type serial_str_to_transport(const char *name)
-{
- if (!strcasecmp("SDIO", name))
- return USB_GADGET_FSERIAL_TRANSPORT_SDIO;
- if (!strcasecmp("SMD", name))
- return USB_GADGET_FSERIAL_TRANSPORT_SMD;
-
- return USB_GADGET_FSERIAL_TRANSPORT_TTY;
-}
-
-
static int gport_setup(struct usb_configuration *c)
{
int ret = 0;
+ int port_idx;
+ int i;
- pr_debug("%s: no_tty_ports:%u no_sdio_ports: %u nr_ports:%u\n",
- __func__, no_tty_ports, no_sdio_ports, nr_ports);
+ pr_debug("%s: no_tty_ports: %u no_sdio_ports: %u"
+ " no_smd_ports: %u no_hsic_sports: %u nr_ports: %u\n",
+ __func__, no_tty_ports, no_sdio_ports, no_smd_ports,
+ no_hsic_sports, nr_ports);
if (no_tty_ports)
ret = gserial_setup(c->cdev->gadget, no_tty_ports);
@@ -288,33 +269,67 @@
ret = gsdio_setup(c->cdev->gadget, no_sdio_ports);
if (no_smd_ports)
ret = gsmd_setup(c->cdev->gadget, no_smd_ports);
+ if (no_hsic_sports) {
+ port_idx = ghsic_data_setup(no_hsic_sports, USB_GADGET_SERIAL);
+ if (port_idx < 0)
+ return port_idx;
+ for (i = 0; i < nr_ports; i++) {
+ if (gserial_ports[i].transport ==
+ USB_GADGET_XPORT_HSIC) {
+ gserial_ports[i].client_port_num = port_idx;
+ port_idx++;
+ }
+ }
+
+ /*clinet port num is same for data setup and ctrl setup*/
+ ret = ghsic_ctrl_setup(no_hsic_sports, USB_GADGET_SERIAL);
+ if (ret < 0)
+ return ret;
+ return 0;
+ }
return ret;
}
static int gport_connect(struct f_gser *gser)
{
- unsigned port_num;
+ unsigned port_num;
+ int ret;
- pr_debug("%s: transport:%s f_gser:%p gserial:%p port_num:%d\n",
- __func__, transport_to_str(gser->transport),
+ pr_debug("%s: transport: %s f_gser: %p gserial: %p port_num: %d\n",
+ __func__, xport_to_str(gser->transport),
gser, &gser->port, gser->port_num);
port_num = gserial_ports[gser->port_num].client_port_num;
switch (gser->transport) {
- case USB_GADGET_FSERIAL_TRANSPORT_TTY:
+ case USB_GADGET_XPORT_TTY:
gserial_connect(&gser->port, port_num);
break;
- case USB_GADGET_FSERIAL_TRANSPORT_SDIO:
+ case USB_GADGET_XPORT_SDIO:
gsdio_connect(&gser->port, port_num);
break;
- case USB_GADGET_FSERIAL_TRANSPORT_SMD:
+ case USB_GADGET_XPORT_SMD:
gsmd_connect(&gser->port, port_num);
break;
+ case USB_GADGET_XPORT_HSIC:
+ ret = ghsic_ctrl_connect(&gser->port, port_num);
+ if (ret) {
+ pr_err("%s: ghsic_ctrl_connect failed: err:%d\n",
+ __func__, ret);
+ return ret;
+ }
+ ret = ghsic_data_connect(&gser->port, port_num);
+ if (ret) {
+ pr_err("%s: ghsic_data_connect failed: err:%d\n",
+ __func__, ret);
+ ghsic_ctrl_disconnect(&gser->port, port_num);
+ return ret;
+ }
+ break;
default:
pr_err("%s: Un-supported transport: %s\n", __func__,
- transport_to_str(gser->transport));
+ xport_to_str(gser->transport));
return -ENODEV;
}
@@ -325,25 +340,29 @@
{
unsigned port_num;
- pr_debug("%s: transport:%s f_gser:%p gserial:%p port_num:%d\n",
- __func__, transport_to_str(gser->transport),
+ pr_debug("%s: transport: %s f_gser: %p gserial: %p port_num: %d\n",
+ __func__, xport_to_str(gser->transport),
gser, &gser->port, gser->port_num);
port_num = gserial_ports[gser->port_num].client_port_num;
switch (gser->transport) {
- case USB_GADGET_FSERIAL_TRANSPORT_TTY:
+ case USB_GADGET_XPORT_TTY:
gserial_disconnect(&gser->port);
break;
- case USB_GADGET_FSERIAL_TRANSPORT_SDIO:
+ case USB_GADGET_XPORT_SDIO:
gsdio_disconnect(&gser->port, port_num);
break;
- case USB_GADGET_FSERIAL_TRANSPORT_SMD:
+ case USB_GADGET_XPORT_SMD:
gsmd_disconnect(&gser->port, port_num);
break;
+ case USB_GADGET_XPORT_HSIC:
+ ghsic_ctrl_disconnect(&gser->port, port_num);
+ ghsic_data_disconnect(&gser->port, port_num);
+ break;
default:
pr_err("%s: Un-supported transport:%s\n", __func__,
- transport_to_str(gser->transport));
+ xport_to_str(gser->transport));
return -ENODEV;
}
@@ -887,26 +906,30 @@
if (port_num >= GSERIAL_NO_PORTS)
return -ENODEV;
- transport = serial_str_to_transport(name);
+ transport = str_to_xport(name);
pr_debug("%s, port:%d, transport:%s\n", __func__,
- port_num, transport_to_str(transport));
+ port_num, xport_to_str(transport));
gserial_ports[port_num].transport = transport;
gserial_ports[port_num].port_num = port_num;
switch (transport) {
- case USB_GADGET_FSERIAL_TRANSPORT_TTY:
+ case USB_GADGET_XPORT_TTY:
gserial_ports[port_num].client_port_num = no_tty_ports;
no_tty_ports++;
break;
- case USB_GADGET_FSERIAL_TRANSPORT_SDIO:
+ case USB_GADGET_XPORT_SDIO:
gserial_ports[port_num].client_port_num = no_sdio_ports;
no_sdio_ports++;
break;
- case USB_GADGET_FSERIAL_TRANSPORT_SMD:
+ case USB_GADGET_XPORT_SMD:
gserial_ports[port_num].client_port_num = no_smd_ports;
no_smd_ports++;
break;
+ case USB_GADGET_XPORT_HSIC:
+ /*client port number will be updated in gport_setup*/
+ no_hsic_sports++;
+ break;
default:
pr_err("%s: Un-supported transport transport: %u\n",
__func__, gserial_ports[port_num].transport);
diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index 771ebfc..0c42292 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -1103,6 +1103,7 @@
struct msm_endpoint *ept = ui->ept + bit;
struct msm_request *req;
unsigned long flags;
+ int req_dequeue = 1;
unsigned info;
/*
@@ -1111,7 +1112,6 @@
ept->req, ept->req ? ept->req->item_dma : 0);
*/
- del_timer(&ept->prime_timer);
/* expire all requests that are no longer active */
spin_lock_irqsave(&ui->lock, flags);
while ((req = ept->req)) {
@@ -1123,13 +1123,23 @@
break;
}
+dequeue:
/* clean speculative fetches on req->item->info */
dma_coherent_post_ops();
info = req->item->info;
/* if the transaction is still in-flight, stop here */
- if (info & INFO_ACTIVE)
- break;
+ if (info & INFO_ACTIVE) {
+ if (req_dequeue) {
+ req_dequeue = 0;
+ udelay(10);
+ goto dequeue;
+ } else {
+ break;
+ }
+ }
+ req_dequeue = 0;
+ del_timer(&ept->prime_timer);
/* advance ept queue to the next request */
ept->req = req->next;
if (ept->req == 0)
diff --git a/drivers/usb/gadget/u_ctrl_hsic.c b/drivers/usb/gadget/u_ctrl_hsic.c
new file mode 100644
index 0000000..fdfab96
--- /dev/null
+++ b/drivers/usb/gadget/u_ctrl_hsic.c
@@ -0,0 +1,617 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/termios.h>
+#include <linux/debugfs.h>
+#include <linux/bitops.h>
+#include <linux/termios.h>
+#include <mach/usb_bridge.h>
+#include <mach/usb_gadget_xport.h>
+
+/* from cdc-acm.h */
+#define ACM_CTRL_RTS (1 << 1) /* unused with full duplex */
+#define ACM_CTRL_DTR (1 << 0) /* host is ready for data r/w */
+#define ACM_CTRL_OVERRUN (1 << 6)
+#define ACM_CTRL_PARITY (1 << 5)
+#define ACM_CTRL_FRAMING (1 << 4)
+#define ACM_CTRL_RI (1 << 3)
+#define ACM_CTRL_BRK (1 << 2)
+#define ACM_CTRL_DSR (1 << 1)
+#define ACM_CTRL_DCD (1 << 0)
+
+
+static unsigned int no_ctrl_ports;
+
+static const char *ctrl_bridge_names[] = {
+ "dun_ctrl_hsic0",
+ "rmnet_ctrl_hsic0"
+};
+
+#define CTRL_BRIDGE_NAME_MAX_LEN 20
+#define READ_BUF_LEN 1024
+
+#define CH_OPENED 0
+#define CH_READY 1
+
+struct gctrl_port {
+ /* port */
+ unsigned port_num;
+
+ /* gadget */
+ spinlock_t port_lock;
+ void *port_usb;
+
+ /* work queue*/
+ struct workqueue_struct *wq;
+ struct work_struct connect_w;
+ struct work_struct disconnect_w;
+
+ enum gadget_type gtype;
+
+ /*ctrl pkt response cb*/
+ int (*send_cpkt_response)(void *g, void *buf, size_t len);
+
+ struct bridge brdg;
+
+ /* bridge status */
+ unsigned long bridge_sts;
+
+ /* control bits */
+ unsigned cbits_tomodem;
+ unsigned cbits_tohost;
+
+ /* counters */
+ unsigned long to_modem;
+ unsigned long to_host;
+ unsigned long drp_cpkt_cnt;
+};
+
+static struct {
+ struct gctrl_port *port;
+ struct platform_driver pdrv;
+} gctrl_ports[NUM_PORTS];
+
+static int ghsic_ctrl_receive(void *dev, void *buf, size_t actual)
+{
+ struct gctrl_port *port = dev;
+ int retval = 0;
+
+ pr_debug_ratelimited("%s: read complete bytes read: %d\n",
+ __func__, actual);
+
+ /* send it to USB here */
+ if (port && port->send_cpkt_response) {
+ retval = port->send_cpkt_response(port->port_usb, buf, actual);
+ port->to_host++;
+ }
+
+ return retval;
+}
+
+static int
+ghsic_send_cpkt_tomodem(u8 portno, void *buf, size_t len)
+{
+ void *cbuf;
+ struct gctrl_port *port;
+
+ if (portno >= no_ctrl_ports) {
+ pr_err("%s: Invalid portno#%d\n", __func__, portno);
+ return -ENODEV;
+ }
+
+ port = gctrl_ports[portno].port;
+ if (!port) {
+ pr_err("%s: port is null\n", __func__);
+ return -ENODEV;
+ }
+
+ cbuf = kmalloc(len, GFP_ATOMIC);
+ if (!cbuf)
+ return -ENOMEM;
+
+ memcpy(cbuf, buf, len);
+
+ /* drop cpkt if ch is not open */
+ if (!test_bit(CH_OPENED, &port->bridge_sts)) {
+ port->drp_cpkt_cnt++;
+ kfree(cbuf);
+ return 0;
+ }
+
+ pr_debug("%s: ctrl_pkt:%d bytes\n", __func__, len);
+
+ ctrl_bridge_write(port->brdg.ch_id, cbuf, len);
+
+ port->to_modem++;
+
+ return 0;
+}
+
+static void
+ghsic_send_cbits_tomodem(void *gptr, u8 portno, int cbits)
+{
+ struct gctrl_port *port;
+
+ if (portno >= no_ctrl_ports || !gptr) {
+ pr_err("%s: Invalid portno#%d\n", __func__, portno);
+ return;
+ }
+
+ port = gctrl_ports[portno].port;
+ if (!port) {
+ pr_err("%s: port is null\n", __func__);
+ return;
+ }
+
+ if (cbits == port->cbits_tomodem)
+ return;
+
+ port->cbits_tomodem = cbits;
+
+ if (!test_bit(CH_OPENED, &port->bridge_sts))
+ return;
+
+ pr_debug("%s: ctrl_tomodem:%d\n", __func__, cbits);
+
+ ctrl_bridge_set_cbits(port->brdg.ch_id, cbits);
+}
+
+static void ghsic_ctrl_connect_w(struct work_struct *w)
+{
+ struct gserial *gser = NULL;
+ struct grmnet *gr = NULL;
+ struct gctrl_port *port =
+ container_of(w, struct gctrl_port, connect_w);
+ unsigned long flags;
+ int retval;
+ unsigned cbits;
+
+ if (!port || !test_bit(CH_READY, &port->bridge_sts))
+ return;
+
+ pr_debug("%s: port:%p\n", __func__, port);
+
+ retval = ctrl_bridge_open(&port->brdg);
+ if (retval) {
+ pr_err("%s: ctrl bridge open failed :%d\n", __func__, retval);
+ return;
+ }
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (!port->port_usb) {
+ ctrl_bridge_close(port->brdg.ch_id);
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ return;
+ }
+ set_bit(CH_OPENED, &port->bridge_sts);
+ spin_unlock_irqrestore(&port->port_lock, flags);
+
+ cbits = ctrl_bridge_get_cbits_tohost(port->brdg.ch_id);
+
+ if (port->gtype == USB_GADGET_SERIAL && (cbits & ACM_CTRL_DCD)) {
+ gser = port->port_usb;
+ if (gser && gser->connect)
+ gser->connect(gser);
+ return;
+ }
+
+ if (port->gtype == USB_GADGET_RMNET) {
+ gr = port->port_usb;
+ if (gr && gr->connect)
+ gr->connect(gr);
+ }
+}
+
+int ghsic_ctrl_connect(void *gptr, int port_num)
+{
+ struct gctrl_port *port;
+ struct gserial *gser;
+ struct grmnet *gr;
+ unsigned long flags;
+
+ pr_debug("%s: port#%d\n", __func__, port_num);
+
+ if (port_num > no_ctrl_ports || !gptr) {
+ pr_err("%s: invalid portno#%d\n", __func__, port_num);
+ return -ENODEV;
+ }
+
+ port = gctrl_ports[port_num].port;
+ if (!port) {
+ pr_err("%s: port is null\n", __func__);
+ return -ENODEV;
+ }
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (port->gtype == USB_GADGET_SERIAL) {
+ gser = gptr;
+ gser->notify_modem = ghsic_send_cbits_tomodem;
+ }
+
+ if (port->gtype == USB_GADGET_RMNET) {
+ gr = gptr;
+ port->send_cpkt_response = gr->send_cpkt_response;
+ gr->send_encap_cmd = ghsic_send_cpkt_tomodem;
+ gr->notify_modem = ghsic_send_cbits_tomodem;
+ }
+
+ port->port_usb = gptr;
+ port->to_host = 0;
+ port->to_modem = 0;
+ port->drp_cpkt_cnt = 0;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+
+ queue_work(port->wq, &port->connect_w);
+
+ return 0;
+}
+
+static void gctrl_disconnect_w(struct work_struct *w)
+{
+ struct gctrl_port *port =
+ container_of(w, struct gctrl_port, disconnect_w);
+
+ if (!test_bit(CH_OPENED, &port->bridge_sts))
+ return;
+
+ /* send the dtr zero */
+ ctrl_bridge_close(port->brdg.ch_id);
+ clear_bit(CH_OPENED, &port->bridge_sts);
+}
+
+void ghsic_ctrl_disconnect(void *gptr, int port_num)
+{
+ struct gctrl_port *port;
+ struct gserial *gser = NULL;
+ struct grmnet *gr = NULL;
+ unsigned long flags;
+
+ pr_debug("%s: port#%d\n", __func__, port_num);
+
+ port = gctrl_ports[port_num].port;
+
+ if (port_num > no_ctrl_ports) {
+ pr_err("%s: invalid portno#%d\n", __func__, port_num);
+ return;
+ }
+
+ if (!gptr || !port) {
+ pr_err("%s: grmnet port is null\n", __func__);
+ return;
+ }
+
+ if (port->gtype == USB_GADGET_SERIAL)
+ gser = gptr;
+ else
+ gr = gptr;
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (gr) {
+ gr->send_encap_cmd = 0;
+ gr->notify_modem = 0;
+ }
+
+ if (gser)
+ gser->notify_modem = 0;
+ port->cbits_tomodem = 0;
+ port->port_usb = 0;
+ port->send_cpkt_response = 0;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+
+ queue_work(port->wq, &port->disconnect_w);
+}
+
+static void ghsic_ctrl_status(void *ctxt, unsigned int ctrl_bits)
+{
+ struct gctrl_port *port = ctxt;
+ struct gserial *gser;
+
+ pr_debug("%s - input control lines: dcd%c dsr%c break%c "
+ "ring%c framing%c parity%c overrun%c\n", __func__,
+ ctrl_bits & ACM_CTRL_DCD ? '+' : '-',
+ ctrl_bits & ACM_CTRL_DSR ? '+' : '-',
+ ctrl_bits & ACM_CTRL_BRK ? '+' : '-',
+ ctrl_bits & ACM_CTRL_RI ? '+' : '-',
+ ctrl_bits & ACM_CTRL_FRAMING ? '+' : '-',
+ ctrl_bits & ACM_CTRL_PARITY ? '+' : '-',
+ ctrl_bits & ACM_CTRL_OVERRUN ? '+' : '-');
+
+ port->cbits_tohost = ctrl_bits;
+ gser = port->port_usb;
+ if (gser && gser->send_modem_ctrl_bits)
+ gser->send_modem_ctrl_bits(gser, ctrl_bits);
+}
+
+static int ghsic_ctrl_probe(struct platform_device *pdev)
+{
+ struct gctrl_port *port;
+ unsigned long flags;
+
+ pr_debug("%s: name:%s\n", __func__, pdev->name);
+
+ if (pdev->id >= no_ctrl_ports) {
+ pr_err("%s: invalid port: %d\n", __func__, pdev->id);
+ return -EINVAL;
+ }
+
+ port = gctrl_ports[pdev->id].port;
+ set_bit(CH_READY, &port->bridge_sts);
+
+ /* if usb is online, start read */
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (port->port_usb)
+ queue_work(port->wq, &port->connect_w);
+ spin_unlock_irqrestore(&port->port_lock, flags);
+
+ return 0;
+}
+
+static int ghsic_ctrl_remove(struct platform_device *pdev)
+{
+ struct gctrl_port *port;
+ struct gserial *gser = NULL;
+ struct grmnet *gr = NULL;
+ unsigned long flags;
+
+ pr_debug("%s: name:%s\n", __func__, pdev->name);
+
+ if (pdev->id >= no_ctrl_ports) {
+ pr_err("%s: invalid port: %d\n", __func__, pdev->id);
+ return -EINVAL;
+ }
+
+ port = gctrl_ports[pdev->id].port;
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (!port->port_usb) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ goto not_ready;
+ }
+
+ if (port->gtype == USB_GADGET_SERIAL)
+ gser = port->port_usb;
+ else
+ gr = port->port_usb;
+
+ port->cbits_tohost = 0;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+
+ if (gr && gr->disconnect)
+ gr->disconnect(gr);
+
+ if (gser && gser->disconnect)
+ gser->disconnect(gser);
+
+ ctrl_bridge_close(port->brdg.ch_id);
+
+ clear_bit(CH_OPENED, &port->bridge_sts);
+not_ready:
+ clear_bit(CH_READY, &port->bridge_sts);
+
+ return 0;
+}
+
+static void ghsic_ctrl_port_free(int portno)
+{
+ struct gctrl_port *port = gctrl_ports[portno].port;
+ struct platform_driver *pdrv = &gctrl_ports[portno].pdrv;
+
+ destroy_workqueue(port->wq);
+ kfree(port);
+
+ if (pdrv)
+ platform_driver_unregister(pdrv);
+}
+
+static int gctrl_port_alloc(int portno, enum gadget_type gtype)
+{
+ struct gctrl_port *port;
+ struct platform_driver *pdrv;
+
+ port = kzalloc(sizeof(struct gctrl_port), GFP_KERNEL);
+ if (!port)
+ return -ENOMEM;
+
+ port->wq = create_singlethread_workqueue(ctrl_bridge_names[portno]);
+ if (!port->wq) {
+ pr_err("%s: Unable to create workqueue:%s\n",
+ __func__, ctrl_bridge_names[portno]);
+ return -ENOMEM;
+ }
+
+ port->port_num = portno;
+ port->gtype = gtype;
+
+ spin_lock_init(&port->port_lock);
+
+ INIT_WORK(&port->connect_w, ghsic_ctrl_connect_w);
+ INIT_WORK(&port->disconnect_w, gctrl_disconnect_w);
+
+ port->brdg.ch_id = portno;
+ port->brdg.ctx = port;
+ port->brdg.ops.send_pkt = ghsic_ctrl_receive;
+ if (port->gtype == USB_GADGET_SERIAL)
+ port->brdg.ops.send_cbits = ghsic_ctrl_status;
+ gctrl_ports[portno].port = port;
+
+ pdrv = &gctrl_ports[portno].pdrv;
+ pdrv->probe = ghsic_ctrl_probe;
+ pdrv->remove = ghsic_ctrl_remove;
+ pdrv->driver.name = ctrl_bridge_names[portno];
+ pdrv->driver.owner = THIS_MODULE;
+
+ platform_driver_register(pdrv);
+
+ pr_debug("%s: port:%p portno:%d\n", __func__, port, portno);
+
+ return 0;
+}
+
+int ghsic_ctrl_setup(unsigned int num_ports, enum gadget_type gtype)
+{
+ int first_port_id = no_ctrl_ports;
+ int total_num_ports = num_ports + no_ctrl_ports;
+ int i;
+ int ret = 0;
+
+ if (!num_ports || total_num_ports > NUM_PORTS) {
+ pr_err("%s: Invalid num of ports count:%d\n",
+ __func__, num_ports);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: requested ports:%d\n", __func__, num_ports);
+
+ for (i = first_port_id; i < (first_port_id + num_ports); i++) {
+
+ /*probe can be called while port_alloc,so update no_ctrl_ports*/
+ no_ctrl_ports++;
+ ret = gctrl_port_alloc(i, gtype);
+ if (ret) {
+ no_ctrl_ports--;
+ pr_err("%s: Unable to alloc port:%d\n", __func__, i);
+ goto free_ports;
+ }
+ }
+
+ return first_port_id;
+
+free_ports:
+ for (i = first_port_id; i < no_ctrl_ports; i++)
+ ghsic_ctrl_port_free(i);
+ no_ctrl_ports = first_port_id;
+ return ret;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+#define DEBUG_BUF_SIZE 1024
+static ssize_t gctrl_read_stats(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct gctrl_port *port;
+ struct platform_driver *pdrv;
+ char *buf;
+ unsigned long flags;
+ int ret;
+ int i;
+ int temp = 0;
+
+ buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ for (i = 0; i < no_ctrl_ports; i++) {
+ port = gctrl_ports[i].port;
+ if (!port)
+ continue;
+ pdrv = &gctrl_ports[i].pdrv;
+ spin_lock_irqsave(&port->port_lock, flags);
+
+ temp += scnprintf(buf + temp, DEBUG_BUF_SIZE - temp,
+ "\nName: %s\n"
+ "#PORT:%d port: %p\n"
+ "to_usbhost: %lu\n"
+ "to_modem: %lu\n"
+ "cpkt_drp_cnt: %lu\n"
+ "DTR: %s\n"
+ "ch_open: %d\n"
+ "ch_ready: %d\n",
+ pdrv->driver.name,
+ i, port,
+ port->to_host, port->to_modem,
+ port->drp_cpkt_cnt,
+ port->cbits_tomodem ? "HIGH" : "LOW",
+ test_bit(CH_OPENED, &port->bridge_sts),
+ test_bit(CH_READY, &port->bridge_sts));
+
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ }
+
+ ret = simple_read_from_buffer(ubuf, count, ppos, buf, temp);
+
+ kfree(buf);
+
+ return ret;
+}
+
+static ssize_t gctrl_reset_stats(struct file *file,
+ const char __user *buf, size_t count, loff_t *ppos)
+{
+ struct gctrl_port *port;
+ int i;
+ unsigned long flags;
+
+ for (i = 0; i < no_ctrl_ports; i++) {
+ port = gctrl_ports[i].port;
+ if (!port)
+ continue;
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ port->to_host = 0;
+ port->to_modem = 0;
+ port->drp_cpkt_cnt = 0;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ }
+ return count;
+}
+
+const struct file_operations gctrl_stats_ops = {
+ .read = gctrl_read_stats,
+ .write = gctrl_reset_stats,
+};
+
+struct dentry *gctrl_dent;
+struct dentry *gctrl_dfile;
+static void gctrl_debugfs_init(void)
+{
+ gctrl_dent = debugfs_create_dir("ghsic_ctrl_xport", 0);
+ if (IS_ERR(gctrl_dent))
+ return;
+
+ gctrl_dfile =
+ debugfs_create_file("status", 0444, gctrl_dent, 0,
+ &gctrl_stats_ops);
+ if (!gctrl_dfile || IS_ERR(gctrl_dfile))
+ debugfs_remove(gctrl_dent);
+}
+
+static void gctrl_debugfs_exit(void)
+{
+ debugfs_remove(gctrl_dfile);
+ debugfs_remove(gctrl_dent);
+}
+
+#else
+static void gctrl_debugfs_init(void) { }
+static void gctrl_debugfs_exit(void) { }
+#endif
+
+static int __init gctrl_init(void)
+{
+ gctrl_debugfs_init();
+
+ return 0;
+}
+module_init(gctrl_init);
+
+static void __exit gctrl_exit(void)
+{
+ gctrl_debugfs_exit();
+}
+module_exit(gctrl_exit);
+MODULE_DESCRIPTION("hsic control xport driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/gadget/u_data_hsic.c b/drivers/usb/gadget/u_data_hsic.c
new file mode 100644
index 0000000..61458ea
--- /dev/null
+++ b/drivers/usb/gadget/u_data_hsic.c
@@ -0,0 +1,961 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/termios.h>
+#include <linux/netdevice.h>
+#include <linux/debugfs.h>
+#include <linux/bitops.h>
+#include <linux/termios.h>
+#include <mach/usb_bridge.h>
+#include <mach/usb_gadget_xport.h>
+
+static unsigned int no_data_ports;
+
+static const char *data_bridge_names[] = {
+ "dun_data_hsic0",
+ "rmnet_data_hsic0"
+};
+
+#define DATA_BRIDGE_NAME_MAX_LEN 20
+
+#define GHSIC_DATA_RMNET_RX_Q_SIZE 50
+#define GHSIC_DATA_RMNET_TX_Q_SIZE 300
+#define GHSIC_DATA_SERIAL_RX_Q_SIZE 2
+#define GHSIC_DATA_SERIAL_TX_Q_SIZE 2
+#define GHSIC_DATA_RX_REQ_SIZE 2048
+
+static unsigned int ghsic_data_rmnet_tx_q_size = GHSIC_DATA_RMNET_TX_Q_SIZE;
+module_param(ghsic_data_rmnet_tx_q_size, uint, S_IRUGO | S_IWUSR);
+
+static unsigned int ghsic_data_rmnet_rx_q_size = GHSIC_DATA_RMNET_RX_Q_SIZE;
+module_param(ghsic_data_rmnet_rx_q_size, uint, S_IRUGO | S_IWUSR);
+
+static unsigned int ghsic_data_serial_tx_q_size = GHSIC_DATA_SERIAL_TX_Q_SIZE;
+module_param(ghsic_data_serial_tx_q_size, uint, S_IRUGO | S_IWUSR);
+
+static unsigned int ghsic_data_serial_rx_q_size = GHSIC_DATA_SERIAL_RX_Q_SIZE;
+module_param(ghsic_data_serial_rx_q_size, uint, S_IRUGO | S_IWUSR);
+
+static unsigned int ghsic_data_rx_req_size = GHSIC_DATA_RX_REQ_SIZE;
+module_param(ghsic_data_rx_req_size, uint, S_IRUGO | S_IWUSR);
+
+/*flow ctrl*/
+#define GHSIC_DATA_FLOW_CTRL_EN_THRESHOLD 500
+#define GHSIC_DATA_FLOW_CTRL_DISABLE 300
+#define GHSIC_DATA_FLOW_CTRL_SUPPORT 1
+#define GHSIC_DATA_PENDLIMIT_WITH_BRIDGE 500
+
+static unsigned int ghsic_data_fctrl_support = GHSIC_DATA_FLOW_CTRL_SUPPORT;
+module_param(ghsic_data_fctrl_support, uint, S_IRUGO | S_IWUSR);
+
+static unsigned int ghsic_data_fctrl_en_thld =
+ GHSIC_DATA_FLOW_CTRL_EN_THRESHOLD;
+module_param(ghsic_data_fctrl_en_thld, uint, S_IRUGO | S_IWUSR);
+
+static unsigned int ghsic_data_fctrl_dis_thld = GHSIC_DATA_FLOW_CTRL_DISABLE;
+module_param(ghsic_data_fctrl_dis_thld, uint, S_IRUGO | S_IWUSR);
+
+static unsigned int ghsic_data_pend_limit_with_bridge =
+ GHSIC_DATA_PENDLIMIT_WITH_BRIDGE;
+module_param(ghsic_data_pend_limit_with_bridge, uint, S_IRUGO | S_IWUSR);
+
+#define CH_OPENED 0
+#define CH_READY 1
+
+struct gdata_port {
+ /* port */
+ unsigned port_num;
+
+ /* gadget */
+ spinlock_t port_lock;
+ void *port_usb;
+ struct usb_ep *in;
+ struct usb_ep *out;
+
+ enum gadget_type gtype;
+
+ /* data transfer queues */
+ unsigned int tx_q_size;
+ struct list_head tx_idle;
+ struct sk_buff_head tx_skb_q;
+
+ unsigned int rx_q_size;
+ struct list_head rx_idle;
+ struct sk_buff_head rx_skb_q;
+
+ /* work */
+ struct workqueue_struct *wq;
+ struct work_struct connect_w;
+ struct work_struct disconnect_w;
+ struct work_struct write_tomdm_w;
+ struct work_struct write_tohost_w;
+
+ struct bridge brdg;
+
+ /*bridge status*/
+ unsigned long bridge_sts;
+
+ /*counters*/
+ unsigned long to_modem;
+ unsigned long to_host;
+ unsigned int rx_throttled_cnt;
+ unsigned int rx_unthrottled_cnt;
+ unsigned int tx_throttled_cnt;
+ unsigned int tx_unthrottled_cnt;
+ unsigned int tomodem_drp_cnt;
+ unsigned int unthrottled_pnd_skbs;
+};
+
+static struct {
+ struct gdata_port *port;
+ struct platform_driver pdrv;
+} gdata_ports[NUM_PORTS];
+
+static void ghsic_data_start_rx(struct gdata_port *port);
+
+static void ghsic_data_free_requests(struct usb_ep *ep, struct list_head *head)
+{
+ struct usb_request *req;
+
+ while (!list_empty(head)) {
+ req = list_entry(head->next, struct usb_request, list);
+ list_del(&req->list);
+ usb_ep_free_request(ep, req);
+ }
+}
+
+static int ghsic_data_alloc_requests(struct usb_ep *ep, struct list_head *head,
+ int num,
+ void (*cb)(struct usb_ep *ep, struct usb_request *),
+ gfp_t flags)
+{
+ int i;
+ struct usb_request *req;
+
+ pr_debug("%s: ep:%s head:%p num:%d cb:%p", __func__,
+ ep->name, head, num, cb);
+
+ for (i = 0; i < num; i++) {
+ req = usb_ep_alloc_request(ep, flags);
+ if (!req) {
+ pr_debug("%s: req allocated:%d\n", __func__, i);
+ return list_empty(head) ? -ENOMEM : 0;
+ }
+ req->complete = cb;
+ list_add(&req->list, head);
+ }
+
+ return 0;
+}
+
+static void ghsic_data_unthrottle_tx(void *ctx)
+{
+ struct gdata_port *port = ctx;
+ unsigned long flags;
+
+ if (!port)
+ return;
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (port->port_usb) {
+ port->tx_unthrottled_cnt++;
+ queue_work(port->wq, &port->write_tomdm_w);
+ pr_debug("%s: port num =%d unthrottled\n", __func__,
+ port->port_num);
+ }
+ spin_unlock_irqrestore(&port->port_lock, flags);
+}
+
+static void ghsic_data_write_tohost(struct work_struct *w)
+{
+ unsigned long flags;
+ struct sk_buff *skb;
+ int ret;
+ struct usb_request *req;
+ struct usb_ep *ep;
+ struct gdata_port *port;
+
+ port = container_of(w, struct gdata_port, write_tohost_w);
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (!port->port_usb) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ return;
+ }
+
+ ep = port->in;
+
+ while (!list_empty(&port->tx_idle)) {
+ skb = __skb_dequeue(&port->tx_skb_q);
+ if (!skb)
+ break;
+
+ req = list_first_entry(&port->tx_idle, struct usb_request,
+ list);
+ req->context = skb;
+ req->buf = skb->data;
+ req->length = skb->len;
+
+ list_del(&req->list);
+
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ ret = usb_ep_queue(ep, req, GFP_KERNEL);
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (ret) {
+ pr_err("%s: usb epIn failed\n", __func__);
+ list_add(&req->list, &port->tx_idle);
+ dev_kfree_skb_any(skb);
+ break;
+ }
+ port->to_host++;
+ if (ghsic_data_fctrl_support &&
+ port->tx_skb_q.qlen <= ghsic_data_fctrl_dis_thld &&
+ test_and_clear_bit(RX_THROTTLED, &port->brdg.flags)) {
+ port->rx_unthrottled_cnt++;
+ port->unthrottled_pnd_skbs = port->tx_skb_q.qlen;
+ pr_debug_ratelimited("%s: disable flow ctrl:"
+ " tx skbq len: %u\n",
+ __func__, port->tx_skb_q.qlen);
+ data_bridge_unthrottle_rx(port->brdg.ch_id);
+ }
+ }
+ spin_unlock_irqrestore(&port->port_lock, flags);
+}
+
+static int ghsic_data_receive(void *p, void *data, size_t len)
+{
+ struct gdata_port *port = p;
+ unsigned long flags;
+ struct sk_buff *skb = data;
+
+ if (!port) {
+ dev_kfree_skb_any(skb);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: p:%p#%d skb_len:%d\n", __func__,
+ port, port->port_num, skb->len);
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (!port->port_usb) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ dev_kfree_skb_any(skb);
+ return -ENOTCONN;
+ }
+
+ __skb_queue_tail(&port->tx_skb_q, skb);
+
+ if (ghsic_data_fctrl_support &&
+ port->tx_skb_q.qlen >= ghsic_data_fctrl_en_thld) {
+ set_bit(RX_THROTTLED, &port->brdg.flags);
+ port->rx_throttled_cnt++;
+ pr_debug_ratelimited("%s: flow ctrl enabled: tx skbq len: %u\n",
+ __func__, port->tx_skb_q.qlen);
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ queue_work(port->wq, &port->write_tohost_w);
+ return -EBUSY;
+ }
+
+ spin_unlock_irqrestore(&port->port_lock, flags);
+
+ queue_work(port->wq, &port->write_tohost_w);
+
+ return 0;
+}
+
+static void ghsic_data_write_tomdm(struct work_struct *w)
+{
+ struct gdata_port *port;
+ struct sk_buff *skb;
+ unsigned long flags;
+ int ret;
+
+ port = container_of(w, struct gdata_port, write_tomdm_w);
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (!port->port_usb) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ return;
+ }
+
+ if (test_bit(TX_THROTTLED, &port->brdg.flags)) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ goto start_rx;
+ }
+
+ while ((skb = __skb_dequeue(&port->rx_skb_q))) {
+ pr_debug("%s: port:%p tom:%lu pno:%d\n", __func__,
+ port, port->to_modem, port->port_num);
+
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ ret = data_bridge_write(port->brdg.ch_id, skb);
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (ret < 0) {
+ if (ret == -EBUSY) {
+ /*flow control*/
+ port->tx_throttled_cnt++;
+ break;
+ }
+ pr_err_ratelimited("%s: write error:%d\n",
+ __func__, ret);
+ port->tomodem_drp_cnt++;
+ dev_kfree_skb_any(skb);
+ break;
+ }
+ port->to_modem++;
+ }
+ spin_unlock_irqrestore(&port->port_lock, flags);
+start_rx:
+ ghsic_data_start_rx(port);
+}
+
+static void ghsic_data_epin_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct gdata_port *port = ep->driver_data;
+ struct sk_buff *skb = req->context;
+ int status = req->status;
+
+ switch (status) {
+ case 0:
+ /* successful completion */
+ break;
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ /* connection gone */
+ dev_kfree_skb_any(skb);
+ req->buf = 0;
+ usb_ep_free_request(ep, req);
+ return;
+ default:
+ pr_err("%s: data tx ep error %d\n", __func__, status);
+ break;
+ }
+
+ dev_kfree_skb_any(skb);
+
+ spin_lock(&port->port_lock);
+ list_add_tail(&req->list, &port->tx_idle);
+ spin_unlock(&port->port_lock);
+
+ queue_work(port->wq, &port->write_tohost_w);
+}
+
+static void
+ghsic_data_epout_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct gdata_port *port = ep->driver_data;
+ struct sk_buff *skb = req->context;
+ int status = req->status;
+ int queue = 0;
+
+ switch (status) {
+ case 0:
+ skb_put(skb, req->actual);
+ queue = 1;
+ break;
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ /* cable disconnection */
+ dev_kfree_skb_any(skb);
+ req->buf = 0;
+ usb_ep_free_request(ep, req);
+ return;
+ default:
+ pr_err_ratelimited("%s: %s response error %d, %d/%d\n",
+ __func__, ep->name, status,
+ req->actual, req->length);
+ dev_kfree_skb_any(skb);
+ break;
+ }
+
+ spin_lock(&port->port_lock);
+ if (queue) {
+ __skb_queue_tail(&port->rx_skb_q, skb);
+ list_add_tail(&req->list, &port->rx_idle);
+ queue_work(port->wq, &port->write_tomdm_w);
+ }
+ spin_unlock(&port->port_lock);
+}
+
+static void ghsic_data_start_rx(struct gdata_port *port)
+{
+ struct usb_request *req;
+ struct usb_ep *ep;
+ unsigned long flags;
+ int ret;
+ struct sk_buff *skb;
+
+ pr_debug("%s: port:%p\n", __func__, port);
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (!port->port_usb) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ return;
+ }
+
+ ep = port->out;
+
+ while (port->port_usb && !list_empty(&port->rx_idle)) {
+ if (port->rx_skb_q.qlen > ghsic_data_pend_limit_with_bridge)
+ break;
+
+ req = list_first_entry(&port->rx_idle,
+ struct usb_request, list);
+
+ skb = alloc_skb(ghsic_data_rx_req_size, GFP_ATOMIC);
+ if (!skb)
+ break;
+
+ list_del(&req->list);
+ req->buf = skb->data;
+ req->length = ghsic_data_rx_req_size;
+ req->context = skb;
+
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ ret = usb_ep_queue(ep, req, GFP_KERNEL);
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (ret) {
+ dev_kfree_skb_any(skb);
+
+ pr_err_ratelimited("%s: rx queue failed\n", __func__);
+
+ if (port->port_usb)
+ list_add(&req->list, &port->rx_idle);
+ else
+ usb_ep_free_request(ep, req);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&port->port_lock, flags);
+}
+
+static void ghsic_data_start_io(struct gdata_port *port)
+{
+ unsigned long flags;
+ struct usb_ep *ep;
+ int ret;
+
+ pr_debug("%s: port:%p\n", __func__, port);
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (!port->port_usb) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ return;
+ }
+
+ ep = port->out;
+ ret = ghsic_data_alloc_requests(ep, &port->rx_idle,
+ port->rx_q_size, ghsic_data_epout_complete, GFP_ATOMIC);
+ if (ret) {
+ pr_err("%s: rx req allocation failed\n", __func__);
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ return;
+ }
+
+ ep = port->in;
+ ret = ghsic_data_alloc_requests(ep, &port->tx_idle,
+ port->tx_q_size, ghsic_data_epin_complete, GFP_ATOMIC);
+ if (ret) {
+ pr_err("%s: tx req allocation failed\n", __func__);
+ ghsic_data_free_requests(ep, &port->rx_idle);
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ return;
+ }
+
+ spin_unlock_irqrestore(&port->port_lock, flags);
+
+ /* queue out requests */
+ ghsic_data_start_rx(port);
+}
+
+static void ghsic_data_connect_w(struct work_struct *w)
+{
+ struct gdata_port *port =
+ container_of(w, struct gdata_port, connect_w);
+ int ret;
+
+ if (!port || !test_bit(CH_READY, &port->bridge_sts))
+ return;
+
+ pr_debug("%s: port:%p\n", __func__, port);
+
+ ret = data_bridge_open(&port->brdg);
+ if (ret) {
+ pr_err("%s: unable open bridge ch:%d err:%d\n",
+ __func__, port->brdg.ch_id, ret);
+ return;
+ }
+
+ set_bit(CH_OPENED, &port->bridge_sts);
+
+ ghsic_data_start_io(port);
+}
+
+static void ghsic_data_disconnect_w(struct work_struct *w)
+{
+ struct gdata_port *port =
+ container_of(w, struct gdata_port, disconnect_w);
+
+ if (!test_bit(CH_OPENED, &port->bridge_sts))
+ return;
+
+ data_bridge_close(port->brdg.ch_id);
+ clear_bit(CH_OPENED, &port->bridge_sts);
+}
+
+static void ghsic_data_free_buffers(struct gdata_port *port)
+{
+ struct sk_buff *skb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->port_lock, flags);
+
+ if (!port || !port->port_usb)
+ goto free_buf_out;
+
+ ghsic_data_free_requests(port->in, &port->tx_idle);
+ ghsic_data_free_requests(port->out, &port->rx_idle);
+
+ while ((skb = __skb_dequeue(&port->tx_skb_q)))
+ dev_kfree_skb_any(skb);
+
+ while ((skb = __skb_dequeue(&port->rx_skb_q)))
+ dev_kfree_skb_any(skb);
+
+free_buf_out:
+ spin_unlock_irqrestore(&port->port_lock, flags);
+}
+
+static int ghsic_data_probe(struct platform_device *pdev)
+{
+ struct gdata_port *port;
+ unsigned long flags;
+
+ pr_debug("%s: name:%s no_data_ports= %d\n",
+ __func__, pdev->name, no_data_ports);
+
+ if (pdev->id >= no_data_ports) {
+ pr_err("%s: invalid port: %d\n", __func__, pdev->id);
+ return -EINVAL;
+ }
+
+ port = gdata_ports[pdev->id].port;
+ set_bit(CH_READY, &port->bridge_sts);
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ /* if usb is online, try opening bridge */
+ if (port->port_usb)
+ queue_work(port->wq, &port->connect_w);
+ spin_unlock_irqrestore(&port->port_lock, flags);
+
+ return 0;
+}
+
+/* mdm disconnect */
+static int ghsic_data_remove(struct platform_device *pdev)
+{
+ struct gdata_port *port;
+ struct usb_ep *ep_in = NULL;
+ struct usb_ep *ep_out = NULL;
+ unsigned long flags;
+
+ pr_debug("%s: name:%s\n", __func__, pdev->name);
+
+ if (pdev->id >= no_data_ports) {
+ pr_err("%s: invalid port: %d\n", __func__, pdev->id);
+ return -EINVAL;
+ }
+
+ port = gdata_ports[pdev->id].port;
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (port->port_usb) {
+ ep_in = port->in;
+ ep_out = port->out;
+ }
+ spin_unlock_irqrestore(&port->port_lock, flags);
+
+ if (ep_in)
+ usb_ep_fifo_flush(ep_in);
+ if (ep_out)
+ usb_ep_fifo_flush(ep_out);
+
+ ghsic_data_free_buffers(port);
+
+ data_bridge_close(port->brdg.ch_id);
+
+ clear_bit(CH_READY, &port->bridge_sts);
+ clear_bit(CH_OPENED, &port->bridge_sts);
+
+ return 0;
+}
+
+static void ghsic_data_port_free(int portno)
+{
+ struct gdata_port *port = gdata_ports[portno].port;
+ struct platform_driver *pdrv = &gdata_ports[portno].pdrv;
+
+ destroy_workqueue(port->wq);
+ kfree(port);
+
+ if (pdrv)
+ platform_driver_unregister(pdrv);
+}
+
+static int ghsic_data_port_alloc(unsigned port_num, enum gadget_type gtype)
+{
+ struct gdata_port *port;
+ struct platform_driver *pdrv;
+
+ port = kzalloc(sizeof(struct gdata_port), GFP_KERNEL);
+ if (!port)
+ return -ENOMEM;
+
+ port->wq = create_singlethread_workqueue(data_bridge_names[port_num]);
+ if (!port->wq) {
+ pr_err("%s: Unable to create workqueue:%s\n",
+ __func__, data_bridge_names[port_num]);
+ return -ENOMEM;
+ }
+ port->port_num = port_num;
+
+ /* port initialization */
+ spin_lock_init(&port->port_lock);
+
+ INIT_WORK(&port->connect_w, ghsic_data_connect_w);
+ INIT_WORK(&port->disconnect_w, ghsic_data_disconnect_w);
+ INIT_WORK(&port->write_tohost_w, ghsic_data_write_tohost);
+ INIT_WORK(&port->write_tomdm_w, ghsic_data_write_tomdm);
+
+ INIT_LIST_HEAD(&port->tx_idle);
+ INIT_LIST_HEAD(&port->rx_idle);
+
+ skb_queue_head_init(&port->tx_skb_q);
+ skb_queue_head_init(&port->rx_skb_q);
+
+ port->gtype = gtype;
+ port->brdg.ch_id = port_num;
+ port->brdg.ctx = port;
+ port->brdg.ops.send_pkt = ghsic_data_receive;
+ port->brdg.ops.unthrottle_tx = ghsic_data_unthrottle_tx;
+ gdata_ports[port_num].port = port;
+
+ pdrv = &gdata_ports[port_num].pdrv;
+ pdrv->probe = ghsic_data_probe;
+ pdrv->remove = ghsic_data_remove;
+ pdrv->driver.name = data_bridge_names[port_num];
+ pdrv->driver.owner = THIS_MODULE;
+
+ platform_driver_register(pdrv);
+
+ pr_debug("%s: port:%p portno:%d\n", __func__, port, port_num);
+
+ return 0;
+}
+
+void ghsic_data_disconnect(void *gptr, int port_num)
+{
+ struct gdata_port *port;
+ unsigned long flags;
+
+ pr_debug("%s: port#%d\n", __func__, port_num);
+
+ port = gdata_ports[port_num].port;
+
+ if (port_num > no_data_ports) {
+ pr_err("%s: invalid portno#%d\n", __func__, port_num);
+ return;
+ }
+
+ if (!gptr || !port) {
+ pr_err("%s: port is null\n", __func__);
+ return;
+ }
+
+ ghsic_data_free_buffers(port);
+
+ /* disable endpoints */
+ if (port->in)
+ usb_ep_disable(port->out);
+
+ if (port->out)
+ usb_ep_disable(port->in);
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ port->port_usb = 0;
+ port->in = NULL;
+ port->out = NULL;
+ clear_bit(TX_THROTTLED, &port->brdg.flags);
+ clear_bit(RX_THROTTLED, &port->brdg.flags);
+ spin_unlock_irqrestore(&port->port_lock, flags);
+
+ queue_work(port->wq, &port->disconnect_w);
+}
+
+int ghsic_data_connect(void *gptr, int port_num)
+{
+ struct gdata_port *port;
+ struct gserial *gser;
+ struct grmnet *gr;
+ struct usb_endpoint_descriptor *in_desc;
+ struct usb_endpoint_descriptor *out_desc;
+ unsigned long flags;
+ int ret = 0;
+
+ pr_debug("%s: port#%d\n", __func__, port_num);
+
+ port = gdata_ports[port_num].port;
+
+ if (port_num > no_data_ports) {
+ pr_err("%s: invalid portno#%d\n", __func__, port_num);
+ return -ENODEV;
+ }
+
+ if (!gptr || !port) {
+ pr_err("%s: port is null\n", __func__);
+ return -ENODEV;
+ }
+
+ if (port->gtype == USB_GADGET_SERIAL) {
+ gser = gptr;
+ port->in = gser->in;
+ port->out = gser->out;
+ port->tx_q_size = ghsic_data_serial_tx_q_size;
+ port->rx_q_size = ghsic_data_serial_rx_q_size;
+ gser->in->driver_data = port;
+ gser->out->driver_data = port;
+ in_desc = gser->in_desc;
+ out_desc = gser->out_desc;
+ } else {
+ gr = gptr;
+ port->in = gr->in;
+ port->out = gr->out;
+ port->tx_q_size = ghsic_data_rmnet_tx_q_size;
+ port->rx_q_size = ghsic_data_rmnet_rx_q_size;
+ gr->in->driver_data = port;
+ gr->out->driver_data = port;
+ in_desc = gr->in_desc;
+ out_desc = gr->out_desc;
+ }
+
+ ret = usb_ep_enable(port->in, in_desc);
+ if (ret) {
+ pr_err("%s: usb_ep_enable failed eptype:IN ep:%p",
+ __func__, port->in);
+ goto fail;
+ }
+
+ ret = usb_ep_enable(port->out, out_desc);
+ if (ret) {
+ pr_err("%s: usb_ep_enable failed eptype:OUT ep:%p",
+ __func__, port->out);
+ usb_ep_disable(port->in);
+ goto fail;
+ }
+ spin_lock_irqsave(&port->port_lock, flags);
+ port->port_usb = gptr;
+ port->to_host = 0;
+ port->to_modem = 0;
+ port->tomodem_drp_cnt = 0;
+ port->rx_throttled_cnt = 0;
+ port->rx_unthrottled_cnt = 0;
+ port->tx_throttled_cnt = 0;
+ port->tx_unthrottled_cnt = 0;
+ port->unthrottled_pnd_skbs = 0;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+
+ queue_work(port->wq, &port->connect_w);
+fail:
+ return ret;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+#define DEBUG_BUF_SIZE 1024
+static ssize_t ghsic_data_read_stats(struct file *file,
+ char __user *ubuf, size_t count, loff_t *ppos)
+{
+ struct gdata_port *port;
+ struct platform_driver *pdrv;
+ char *buf;
+ unsigned long flags;
+ int ret;
+ int i;
+ int temp = 0;
+
+ buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ for (i = 0; i < no_data_ports; i++) {
+ port = gdata_ports[i].port;
+ if (!port)
+ continue;
+ pdrv = &gdata_ports[i].pdrv;
+ spin_lock_irqsave(&port->port_lock, flags);
+
+ temp += scnprintf(buf + temp, DEBUG_BUF_SIZE - temp,
+ "\nName: %s\n"
+ "#PORT:%d port#: %p\n"
+ "dpkts_to_usbhost: %lu\n"
+ "dpkts_to_modem: %lu\n"
+ "tomodem_drp_cnt: %u\n"
+ "tx_buf_len: %u\n"
+ "rx_buf_len: %u\n"
+ "rx thld cnt %u\n"
+ "rx unthld cnt %u\n"
+ "tx thld cnt %u\n"
+ "tx unthld cnt %u\n"
+ "uthld pnd skbs %u\n"
+ "RX_THROTTLED %d\n"
+ "TX_THROTTLED %d\n"
+ "data_ch_open: %d\n"
+ "data_ch_ready: %d\n",
+ pdrv->driver.name,
+ i, port,
+ port->to_host, port->to_modem,
+ port->tomodem_drp_cnt,
+ port->tx_skb_q.qlen,
+ port->rx_skb_q.qlen,
+ port->rx_throttled_cnt,
+ port->rx_unthrottled_cnt,
+ port->tx_throttled_cnt,
+ port->tx_unthrottled_cnt,
+ port->unthrottled_pnd_skbs,
+ test_bit(RX_THROTTLED, &port->brdg.flags),
+ test_bit(TX_THROTTLED, &port->brdg.flags),
+ test_bit(CH_OPENED, &port->bridge_sts),
+ test_bit(CH_READY, &port->bridge_sts));
+
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ }
+
+ ret = simple_read_from_buffer(ubuf, count, ppos, buf, temp);
+
+ kfree(buf);
+
+ return ret;
+}
+
+static ssize_t ghsic_data_reset_stats(struct file *file,
+ const char __user *buf, size_t count, loff_t *ppos)
+{
+ struct gdata_port *port;
+ int i;
+ unsigned long flags;
+
+ for (i = 0; i < no_data_ports; i++) {
+ port = gdata_ports[i].port;
+ if (!port)
+ continue;
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ port->to_host = 0;
+ port->to_modem = 0;
+ port->tomodem_drp_cnt = 0;
+ port->rx_throttled_cnt = 0;
+ port->rx_unthrottled_cnt = 0;
+ port->tx_throttled_cnt = 0;
+ port->tx_unthrottled_cnt = 0;
+ port->unthrottled_pnd_skbs = 0;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ }
+ return count;
+}
+
+const struct file_operations ghsic_stats_ops = {
+ .read = ghsic_data_read_stats,
+ .write = ghsic_data_reset_stats,
+};
+
+static struct dentry *gdata_dent;
+static struct dentry *gdata_dfile;
+
+static void ghsic_data_debugfs_init(void)
+{
+ gdata_dent = debugfs_create_dir("ghsic_data_xport", 0);
+ if (IS_ERR(gdata_dent))
+ return;
+
+ gdata_dfile = debugfs_create_file("status", 0444, gdata_dent, 0,
+ &ghsic_stats_ops);
+ if (!gdata_dfile || IS_ERR(gdata_dfile))
+ debugfs_remove(gdata_dent);
+}
+
+static void ghsic_data_debugfs_exit(void)
+{
+ debugfs_remove(gdata_dfile);
+ debugfs_remove(gdata_dent);
+}
+
+#else
+static void ghsic_data_debugfs_init(void) { }
+static void ghsic_data_debugfs_exit(void) { }
+
+#endif
+
+int ghsic_data_setup(unsigned num_ports, enum gadget_type gtype)
+{
+ int first_port_id = no_data_ports;
+ int total_num_ports = num_ports + no_data_ports;
+ int ret = 0;
+ int i;
+
+ if (!num_ports || total_num_ports > NUM_PORTS) {
+ pr_err("%s: Invalid num of ports count:%d\n",
+ __func__, num_ports);
+ return -EINVAL;
+ }
+ pr_debug("%s: count: %d\n", __func__, num_ports);
+
+ for (i = first_port_id; i < (num_ports + first_port_id); i++) {
+
+ /*probe can be called while port_alloc,so update no_data_ports*/
+ no_data_ports++;
+ ret = ghsic_data_port_alloc(i, gtype);
+ if (ret) {
+ no_data_ports--;
+ pr_err("%s: Unable to alloc port:%d\n", __func__, i);
+ goto free_ports;
+ }
+ }
+
+ /*return the starting index*/
+ return first_port_id;
+
+free_ports:
+ for (i = first_port_id; i < no_data_ports; i++)
+ ghsic_data_port_free(i);
+ no_data_ports = first_port_id;
+
+ return ret;
+}
+
+static int __init ghsic_data_init(void)
+{
+ ghsic_data_debugfs_init();
+
+ return 0;
+}
+module_init(ghsic_data_init);
+
+static void __exit ghsic_data_exit(void)
+{
+ ghsic_data_debugfs_exit();
+}
+module_exit(ghsic_data_exit);
+MODULE_DESCRIPTION("hsic data xport driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/gadget/u_rmnet.h b/drivers/usb/gadget/u_rmnet.h
index 3c21316..d8de31e 100644
--- a/drivers/usb/gadget/u_rmnet.h
+++ b/drivers/usb/gadget/u_rmnet.h
@@ -35,19 +35,14 @@
/* to usb host, aka laptop, windows pc etc. Will
* be filled by usb driver of rmnet functionality
*/
- int (*send_cpkt_response)(struct grmnet *g,
- struct rmnet_ctrl_pkt *pkt);
+ int (*send_cpkt_response)(void *g, void *buf, size_t len);
/* to modem, and to be filled by driver implementing
* control function
*/
- int (*send_cpkt_request)(struct grmnet *g,
- u8 port_num,
- struct rmnet_ctrl_pkt *pkt);
+ int (*send_encap_cmd)(u8 port_num, void *buf, size_t len);
- void (*send_cbits_tomodem)(struct grmnet *g,
- u8 port_num,
- int cbits);
+ void (*notify_modem)(void *g, u8 port_num, int cbits);
void (*disconnect)(struct grmnet *g);
void (*connect)(struct grmnet *g);
diff --git a/drivers/usb/gadget/u_rmnet_ctrl_smd.c b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
index fc159cc..8b08b7a 100644
--- a/drivers/usb/gadget/u_rmnet_ctrl_smd.c
+++ b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
@@ -83,6 +83,7 @@
kfree(pkt);
return ERR_PTR(-ENOMEM);
}
+
pkt->len = len;
return pkt;
@@ -103,7 +104,8 @@
struct smd_ch_info *c = container_of(w, struct smd_ch_info, read_w);
struct rmnet_ctrl_port *port = c->port;
int sz;
- struct rmnet_ctrl_pkt *cpkt;
+ size_t len;
+ void *buf;
unsigned long flags;
while (1) {
@@ -114,22 +116,20 @@
if (smd_read_avail(c->ch) < sz)
break;
- cpkt = alloc_rmnet_ctrl_pkt(sz, GFP_KERNEL);
- if (IS_ERR(cpkt)) {
- pr_err("%s: unable to allocate rmnet control pkt\n",
- __func__);
+ buf = kmalloc(sz, GFP_KERNEL);
+ if (!buf)
return;
- }
- cpkt->len = smd_read(c->ch, cpkt->buf, sz);
+
+ len = smd_read(c->ch, buf, sz);
/* send it to USB here */
spin_lock_irqsave(&port->port_lock, flags);
if (port->port_usb && port->port_usb->send_cpkt_response) {
- port->port_usb->send_cpkt_response(
- port->port_usb,
- cpkt);
+ port->port_usb->send_cpkt_response(port->port_usb,
+ buf, len);
c->to_host++;
}
+ kfree(buf);
spin_unlock_irqrestore(&port->port_lock, flags);
}
}
@@ -157,8 +157,7 @@
ret = smd_write(c->ch, cpkt->buf, cpkt->len);
spin_lock_irqsave(&port->port_lock, flags);
if (ret != cpkt->len) {
- pr_err("%s: smd_write failed err:%d\n",
- __func__, ret);
+ pr_err("%s: smd_write failed err:%d\n", __func__, ret);
free_rmnet_ctrl_pkt(cpkt);
break;
}
@@ -169,24 +168,29 @@
}
static int
-grmnet_ctrl_smd_send_cpkt_tomodem(struct grmnet *gr, u8 portno,
- struct rmnet_ctrl_pkt *cpkt)
+grmnet_ctrl_smd_send_cpkt_tomodem(u8 portno,
+ void *buf, size_t len)
{
unsigned long flags;
struct rmnet_ctrl_port *port;
struct smd_ch_info *c;
+ struct rmnet_ctrl_pkt *cpkt;
if (portno >= n_rmnet_ctrl_ports) {
pr_err("%s: Invalid portno#%d\n", __func__, portno);
return -ENODEV;
}
- if (!gr) {
- pr_err("%s: grmnet is null\n", __func__);
- return -ENODEV;
+ port = ctrl_smd_ports[portno].port;
+
+ cpkt = alloc_rmnet_ctrl_pkt(len, GFP_ATOMIC);
+ if (IS_ERR(cpkt)) {
+ pr_err("%s: Unable to allocate ctrl pkt\n", __func__);
+ return -ENOMEM;
}
- port = ctrl_smd_ports[portno].port;
+ memcpy(cpkt->buf, buf, len);
+ cpkt->len = len;
spin_lock_irqsave(&port->port_lock, flags);
c = &port->ctrl_ch;
@@ -207,7 +211,7 @@
#define RMNET_CTRL_DTR 0x01
static void
-gsmd_ctrl_send_cbits_tomodem(struct grmnet *gr, u8 portno, int cbits)
+gsmd_ctrl_send_cbits_tomodem(void *gptr, u8 portno, int cbits)
{
struct rmnet_ctrl_port *port;
struct smd_ch_info *c;
@@ -220,7 +224,7 @@
return;
}
- if (!gr) {
+ if (!gptr) {
pr_err("%s: grmnet is null\n", __func__);
return;
}
@@ -362,8 +366,8 @@
spin_lock_irqsave(&port->port_lock, flags);
port->port_usb = gr;
- gr->send_cpkt_request = grmnet_ctrl_smd_send_cpkt_tomodem;
- gr->send_cbits_tomodem = gsmd_ctrl_send_cbits_tomodem;
+ gr->send_encap_cmd = grmnet_ctrl_smd_send_cpkt_tomodem;
+ gr->notify_modem = gsmd_ctrl_send_cbits_tomodem;
spin_unlock_irqrestore(&port->port_lock, flags);
queue_work(grmnet_ctrl_wq, &port->connect_w);
@@ -395,8 +399,8 @@
spin_lock_irqsave(&port->port_lock, flags);
port->port_usb = 0;
- gr->send_cpkt_request = 0;
- gr->send_cbits_tomodem = 0;
+ gr->send_encap_cmd = 0;
+ gr->notify_modem = 0;
c->cbits_tomodem = 0;
while (!list_empty(&c->tx_q)) {
diff --git a/drivers/usb/gadget/u_sdio.c b/drivers/usb/gadget/u_sdio.c
index 6ba7543..9bd4370 100644
--- a/drivers/usb/gadget/u_sdio.c
+++ b/drivers/usb/gadget/u_sdio.c
@@ -639,10 +639,11 @@
port->cbits_to_modem, ~(port->cbits_to_modem));
}
-void gsdio_ctrl_notify_modem(struct gserial *gser, u8 portno, int ctrl_bits)
+void gsdio_ctrl_notify_modem(void *gptr, u8 portno, int ctrl_bits)
{
struct gsdio_port *port;
int temp;
+ struct gserial *gser = gptr;
if (portno >= n_sdio_ports) {
pr_err("%s: invalid portno#%d\n", __func__, portno);
diff --git a/drivers/usb/gadget/u_serial.h b/drivers/usb/gadget/u_serial.h
index fea53d8..c937006 100644
--- a/drivers/usb/gadget/u_serial.h
+++ b/drivers/usb/gadget/u_serial.h
@@ -55,7 +55,7 @@
int (*send_modem_ctrl_bits)(struct gserial *p, int ctrl_bits);
/* notification changes to modem */
- void (*notify_modem)(struct gserial *gser, u8 portno, int ctrl_bits);
+ void (*notify_modem)(void *gser, u8 portno, int ctrl_bits);
};
/* utilities to allocate/free request and buffer */
diff --git a/drivers/usb/gadget/u_smd.c b/drivers/usb/gadget/u_smd.c
index 60826b9..caccade 100644
--- a/drivers/usb/gadget/u_smd.c
+++ b/drivers/usb/gadget/u_smd.c
@@ -579,10 +579,11 @@
}
}
-static void gsmd_notify_modem(struct gserial *gser, u8 portno, int ctrl_bits)
+static void gsmd_notify_modem(void *gptr, u8 portno, int ctrl_bits)
{
struct gsmd_port *port;
int temp;
+ struct gserial *gser = gptr;
if (portno >= n_smd_ports) {
pr_err("%s: invalid portno#%d\n", __func__, portno);
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 15cac20..d438555 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -343,7 +343,7 @@
u32 temp;
u32 power_okay;
int i;
- u8 resume_needed = 0;
+ unsigned long resume_needed = 0;
if (time_before (jiffies, ehci->next_statechange))
msleep(5);
@@ -416,7 +416,7 @@
if (test_bit(i, &ehci->bus_suspended) &&
(temp & PORT_SUSPEND)) {
temp |= PORT_RESUME;
- resume_needed = 1;
+ set_bit(i, &resume_needed);
}
ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
}
@@ -431,8 +431,7 @@
i = HCS_N_PORTS (ehci->hcs_params);
while (i--) {
temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
- if (test_bit(i, &ehci->bus_suspended) &&
- (temp & PORT_SUSPEND)) {
+ if (test_bit(i, &resume_needed)) {
temp &= ~(PORT_RWC_BITS | PORT_RESUME);
ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
ehci_vdbg (ehci, "resumed port %d\n", i + 1);
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index a5bb387..9c24ff4 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -995,6 +995,12 @@
head->qh_next.qh = qh;
head->hw->hw_next = dma;
+ /*
+ * flush qh descriptor into memory immediately,
+ * see comments in qh_append_tds.
+ * */
+ ehci_sync_mem();
+
qh_get(qh);
qh->xacterrs = 0;
qh->qh_state = QH_STATE_LINKED;
@@ -1082,6 +1088,18 @@
wmb ();
dummy->hw_token = token;
+ /*
+ * Writing to dma coherent buffer on ARM may
+ * be delayed to reach memory, so HC may not see
+ * hw_token of dummy qtd in time, which can cause
+ * the qtd transaction to be executed very late,
+ * and degrade performance a lot. ehci_sync_mem
+ * is added to flush 'token' immediatelly into
+ * memory, so that ehci can execute the transaction
+ * ASAP.
+ * */
+ ehci_sync_mem();
+
urb->hcpriv = qh_get (qh);
}
}
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c
index e3374c8..491a209 100644
--- a/drivers/usb/host/ehci-s5p.c
+++ b/drivers/usb/host/ehci-s5p.c
@@ -86,6 +86,7 @@
goto fail_hcd;
}
+ s5p_ehci->hcd = hcd;
s5p_ehci->clk = clk_get(&pdev->dev, "usbhost");
if (IS_ERR(s5p_ehci->clk)) {
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 95802d9..05c7faf 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -738,6 +738,23 @@
#endif
+/*
+ * Writing to dma coherent memory on ARM may be delayed via L2
+ * writing buffer, so introduce the helper which can flush L2 writing
+ * buffer into memory immediately, especially used to flush ehci
+ * descriptor to memory.
+ * */
+#ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE
+static inline void ehci_sync_mem(void)
+{
+ mb();
+}
+#else
+static inline void ehci_sync_mem(void)
+{
+}
+#endif
+
/*-------------------------------------------------------------------------*/
#ifndef DEBUG
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 04b90ad..629a968 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -535,20 +535,34 @@
iounmap(base);
}
+static const struct dmi_system_id __devinitconst ehci_dmi_nohandoff_table[] = {
+ {
+ /* Pegatron Lucid (ExoPC) */
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "EXOPG06411"),
+ DMI_MATCH(DMI_BIOS_VERSION, "Lucid-CE-133"),
+ },
+ },
+ {
+ /* Pegatron Lucid (Ordissimo AIRIS) */
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "M11JB"),
+ DMI_MATCH(DMI_BIOS_VERSION, "Lucid-GE-133"),
+ },
+ },
+ { }
+};
+
static void __devinit ehci_bios_handoff(struct pci_dev *pdev,
void __iomem *op_reg_base,
u32 cap, u8 offset)
{
int try_handoff = 1, tried_handoff = 0;
- /* The Pegatron Lucid (ExoPC) tablet sporadically waits for 90
- * seconds trying the handoff on its unused controller. Skip
- * it. */
+ /* The Pegatron Lucid tablet sporadically waits for 98 seconds trying
+ * the handoff on its unused controller. Skip it. */
if (pdev->vendor == 0x8086 && pdev->device == 0x283a) {
- const char *dmi_bn = dmi_get_system_info(DMI_BOARD_NAME);
- const char *dmi_bv = dmi_get_system_info(DMI_BIOS_VERSION);
- if (dmi_bn && !strcmp(dmi_bn, "EXOPG06411") &&
- dmi_bv && !strcmp(dmi_bv, "Lucid-CE-133"))
+ if (dmi_check_system(ehci_dmi_nohandoff_table))
try_handoff = 0;
}
@@ -803,7 +817,7 @@
/* If the BIOS owns the HC, signal that the OS wants it, and wait */
if (val & XHCI_HC_BIOS_OWNED) {
- writel(val & XHCI_HC_OS_OWNED, base + ext_cap_offset);
+ writel(val | XHCI_HC_OS_OWNED, base + ext_cap_offset);
/* Wait for 5 seconds with 10 microsecond polling interval */
timeout = handshake(base + ext_cap_offset, XHCI_HC_BIOS_OWNED,
diff --git a/drivers/usb/host/pehci/host/otg.c b/drivers/usb/host/pehci/host/otg.c
old mode 100755
new mode 100644
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 0be788c..723f823 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -463,11 +463,12 @@
&& (temp & PORT_POWER))
status |= USB_PORT_STAT_SUSPEND;
}
- if ((temp & PORT_PLS_MASK) == XDEV_RESUME) {
+ if ((temp & PORT_PLS_MASK) == XDEV_RESUME &&
+ !DEV_SUPERSPEED(temp)) {
if ((temp & PORT_RESET) || !(temp & PORT_PE))
goto error;
- if (!DEV_SUPERSPEED(temp) && time_after_eq(jiffies,
- bus_state->resume_done[wIndex])) {
+ if (time_after_eq(jiffies,
+ bus_state->resume_done[wIndex])) {
xhci_dbg(xhci, "Resume USB2 port %d\n",
wIndex + 1);
bus_state->resume_done[wIndex] = 0;
@@ -487,6 +488,14 @@
xhci_ring_device(xhci, slot_id);
bus_state->port_c_suspend |= 1 << wIndex;
bus_state->suspended_ports &= ~(1 << wIndex);
+ } else {
+ /*
+ * The resume has been signaling for less than
+ * 20ms. Report the port status as SUSPEND,
+ * let the usbcore check port status again
+ * and clear resume signaling later.
+ */
+ status |= USB_PORT_STAT_SUSPEND;
}
}
if ((temp & PORT_PLS_MASK) == XDEV_U0
@@ -664,7 +673,7 @@
xhci_dbg(xhci, "PORTSC %04x\n", temp);
if (temp & PORT_RESET)
goto error;
- if (temp & XDEV_U3) {
+ if ((temp & PORT_PLS_MASK) == XDEV_U3) {
if ((temp & PORT_PE) == 0)
goto error;
@@ -752,7 +761,7 @@
memset(buf, 0, retval);
status = 0;
- mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC;
+ mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC;
spin_lock_irqsave(&xhci->lock, flags);
/* For each port, did anything change? If so, set that bit in buf. */
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 70cacbb..d0871ea 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -516,8 +516,12 @@
(unsigned long long) addr);
}
+/* flip_cycle means flip the cycle bit of all but the first and last TRB.
+ * (The last TRB actually points to the ring enqueue pointer, which is not part
+ * of this TD.) This is used to remove partially enqueued isoc TDs from a ring.
+ */
static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
- struct xhci_td *cur_td)
+ struct xhci_td *cur_td, bool flip_cycle)
{
struct xhci_segment *cur_seg;
union xhci_trb *cur_trb;
@@ -531,6 +535,12 @@
* leave the pointers intact.
*/
cur_trb->generic.field[3] &= cpu_to_le32(~TRB_CHAIN);
+ /* Flip the cycle bit (link TRBs can't be the first
+ * or last TRB).
+ */
+ if (flip_cycle)
+ cur_trb->generic.field[3] ^=
+ cpu_to_le32(TRB_CYCLE);
xhci_dbg(xhci, "Cancel (unchain) link TRB\n");
xhci_dbg(xhci, "Address = %p (0x%llx dma); "
"in seg %p (0x%llx dma)\n",
@@ -544,6 +554,11 @@
cur_trb->generic.field[2] = 0;
/* Preserve only the cycle bit of this TRB */
cur_trb->generic.field[3] &= cpu_to_le32(TRB_CYCLE);
+ /* Flip the cycle bit except on the first or last TRB */
+ if (flip_cycle && cur_trb != cur_td->first_trb &&
+ cur_trb != cur_td->last_trb)
+ cur_trb->generic.field[3] ^=
+ cpu_to_le32(TRB_CYCLE);
cur_trb->generic.field[3] |= cpu_to_le32(
TRB_TYPE(TRB_TR_NOOP));
xhci_dbg(xhci, "Cancel TRB %p (0x%llx dma) "
@@ -722,14 +737,14 @@
cur_td->urb->stream_id,
cur_td, &deq_state);
else
- td_to_noop(xhci, ep_ring, cur_td);
+ td_to_noop(xhci, ep_ring, cur_td, false);
remove_finished_td:
/*
* The event handler won't see a completion for this TD anymore,
* so remove it from the endpoint ring's TD list. Keep it in
* the cancelled TD list for URB completion later.
*/
- list_del(&cur_td->td_list);
+ list_del_init(&cur_td->td_list);
}
last_unlinked_td = cur_td;
xhci_stop_watchdog_timer_in_irq(xhci, ep);
@@ -757,7 +772,7 @@
do {
cur_td = list_entry(ep->cancelled_td_list.next,
struct xhci_td, cancelled_td_list);
- list_del(&cur_td->cancelled_td_list);
+ list_del_init(&cur_td->cancelled_td_list);
/* Clean up the cancelled URB */
/* Doesn't matter what we pass for status, since the core will
@@ -865,9 +880,9 @@
cur_td = list_first_entry(&ring->td_list,
struct xhci_td,
td_list);
- list_del(&cur_td->td_list);
+ list_del_init(&cur_td->td_list);
if (!list_empty(&cur_td->cancelled_td_list))
- list_del(&cur_td->cancelled_td_list);
+ list_del_init(&cur_td->cancelled_td_list);
xhci_giveback_urb_in_irq(xhci, cur_td,
-ESHUTDOWN, "killed");
}
@@ -876,7 +891,7 @@
&temp_ep->cancelled_td_list,
struct xhci_td,
cancelled_td_list);
- list_del(&cur_td->cancelled_td_list);
+ list_del_init(&cur_td->cancelled_td_list);
xhci_giveback_urb_in_irq(xhci, cur_td,
-ESHUTDOWN, "killed");
}
@@ -1567,10 +1582,10 @@
else
*status = 0;
}
- list_del(&td->td_list);
+ list_del_init(&td->td_list);
/* Was this TD slated to be cancelled but completed anyway? */
if (!list_empty(&td->cancelled_td_list))
- list_del(&td->cancelled_td_list);
+ list_del_init(&td->cancelled_td_list);
urb_priv->td_cnt++;
/* Giveback the urb when all the tds are completed */
@@ -2508,11 +2523,8 @@
if (td_index == 0) {
ret = usb_hcd_link_urb_to_ep(bus_to_hcd(urb->dev->bus), urb);
- if (unlikely(ret)) {
- xhci_urb_free_priv(xhci, urb_priv);
- urb->hcpriv = NULL;
+ if (unlikely(ret))
return ret;
- }
}
td->urb = urb;
@@ -2680,6 +2692,10 @@
{
int packets_transferred;
+ /* One TRB with a zero-length data packet. */
+ if (running_total == 0 && trb_buff_len == 0)
+ return 0;
+
/* All the TRB queueing functions don't count the current TRB in
* running_total.
*/
@@ -3121,21 +3137,16 @@
struct urb *urb, int i)
{
int num_trbs = 0;
- u64 addr, td_len, running_total;
+ u64 addr, td_len;
addr = (u64) (urb->transfer_dma + urb->iso_frame_desc[i].offset);
td_len = urb->iso_frame_desc[i].length;
- running_total = TRB_MAX_BUFF_SIZE - (addr & (TRB_MAX_BUFF_SIZE - 1));
- running_total &= TRB_MAX_BUFF_SIZE - 1;
- if (running_total != 0)
+ num_trbs = DIV_ROUND_UP(td_len + (addr & (TRB_MAX_BUFF_SIZE - 1)),
+ TRB_MAX_BUFF_SIZE);
+ if (num_trbs == 0)
num_trbs++;
- while (running_total < td_len) {
- num_trbs++;
- running_total += TRB_MAX_BUFF_SIZE;
- }
-
return num_trbs;
}
@@ -3234,6 +3245,7 @@
start_trb = &ep_ring->enqueue->generic;
start_cycle = ep_ring->cycle_state;
+ urb_priv = urb->hcpriv;
/* Queue the first TRB, even if it's zero-length */
for (i = 0; i < num_tds; i++) {
unsigned int total_packet_count;
@@ -3245,9 +3257,11 @@
addr = start_addr + urb->iso_frame_desc[i].offset;
td_len = urb->iso_frame_desc[i].length;
td_remain_len = td_len;
- /* FIXME: Ignoring zero-length packets, can those happen? */
total_packet_count = roundup(td_len,
le16_to_cpu(urb->ep->desc.wMaxPacketSize));
+ /* A zero-length transfer still involves at least one packet. */
+ if (total_packet_count == 0)
+ total_packet_count++;
burst_count = xhci_get_burst_count(xhci, urb->dev, urb,
total_packet_count);
residue = xhci_get_last_burst_packet_count(xhci,
@@ -3257,12 +3271,13 @@
ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index,
urb->stream_id, trbs_per_td, urb, i, mem_flags);
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ if (i == 0)
+ return ret;
+ goto cleanup;
+ }
- urb_priv = urb->hcpriv;
td = urb_priv->td[i];
-
for (j = 0; j < trbs_per_td; j++) {
u32 remainder = 0;
field = TRB_TBC(burst_count) | TRB_TLBPC(residue);
@@ -3352,6 +3367,27 @@
giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
start_cycle, start_trb);
return 0;
+cleanup:
+ /* Clean up a partially enqueued isoc transfer. */
+
+ for (i--; i >= 0; i--)
+ list_del_init(&urb_priv->td[i]->td_list);
+
+ /* Use the first TD as a temporary variable to turn the TDs we've queued
+ * into No-ops with a software-owned cycle bit. That way the hardware
+ * won't accidentally start executing bogus TDs when we partially
+ * overwrite them. td->first_trb and td->start_seg are already set.
+ */
+ urb_priv->td[0]->last_trb = ep_ring->enqueue;
+ /* Every TRB except the first & last will have its cycle bit flipped. */
+ td_to_noop(xhci, ep_ring, urb_priv->td[0], true);
+
+ /* Reset the ring enqueue back to the first TRB and its cycle bit. */
+ ep_ring->enqueue = urb_priv->td[0]->first_trb;
+ ep_ring->enq_seg = urb_priv->td[0]->start_seg;
+ ep_ring->cycle_state = start_cycle;
+ usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb);
+ return ret;
}
/*
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index f5fe1ac..7ea48b3 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -345,7 +345,8 @@
spin_lock_irqsave(&xhci->lock, flags);
temp = xhci_readl(xhci, &xhci->op_regs->status);
xhci_dbg(xhci, "op reg status = 0x%x\n", temp);
- if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING)) {
+ if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) ||
+ (xhci->xhc_state & XHCI_STATE_HALTED)) {
xhci_dbg(xhci, "HW died, polling stopped.\n");
spin_unlock_irqrestore(&xhci->lock, flags);
return;
@@ -939,8 +940,11 @@
return 0;
}
+ xhci = hcd_to_xhci(hcd);
+ if (xhci->xhc_state & XHCI_STATE_HALTED)
+ return -ENODEV;
+
if (check_virt_dev) {
- xhci = hcd_to_xhci(hcd);
if (!udev->slot_id || !xhci->devs
|| !xhci->devs[udev->slot_id]) {
printk(KERN_DEBUG "xHCI %s called with unaddressed "
@@ -1081,8 +1085,11 @@
if (urb->dev->speed == USB_SPEED_FULL) {
ret = xhci_check_maxpacket(xhci, slot_id,
ep_index, urb);
- if (ret < 0)
+ if (ret < 0) {
+ xhci_urb_free_priv(xhci, urb_priv);
+ urb->hcpriv = NULL;
return ret;
+ }
}
/* We have a spinlock and interrupts disabled, so we must pass
@@ -1093,6 +1100,8 @@
goto dying;
ret = xhci_queue_ctrl_tx(xhci, GFP_ATOMIC, urb,
slot_id, ep_index);
+ if (ret)
+ goto free_priv;
spin_unlock_irqrestore(&xhci->lock, flags);
} else if (usb_endpoint_xfer_bulk(&urb->ep->desc)) {
spin_lock_irqsave(&xhci->lock, flags);
@@ -1113,6 +1122,8 @@
ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb,
slot_id, ep_index);
}
+ if (ret)
+ goto free_priv;
spin_unlock_irqrestore(&xhci->lock, flags);
} else if (usb_endpoint_xfer_int(&urb->ep->desc)) {
spin_lock_irqsave(&xhci->lock, flags);
@@ -1120,6 +1131,8 @@
goto dying;
ret = xhci_queue_intr_tx(xhci, GFP_ATOMIC, urb,
slot_id, ep_index);
+ if (ret)
+ goto free_priv;
spin_unlock_irqrestore(&xhci->lock, flags);
} else {
spin_lock_irqsave(&xhci->lock, flags);
@@ -1127,18 +1140,22 @@
goto dying;
ret = xhci_queue_isoc_tx_prepare(xhci, GFP_ATOMIC, urb,
slot_id, ep_index);
+ if (ret)
+ goto free_priv;
spin_unlock_irqrestore(&xhci->lock, flags);
}
exit:
return ret;
dying:
- xhci_urb_free_priv(xhci, urb_priv);
- urb->hcpriv = NULL;
xhci_dbg(xhci, "Ep 0x%x: URB %p submitted for "
"non-responsive xHCI host.\n",
urb->ep->desc.bEndpointAddress, urb);
+ ret = -ESHUTDOWN;
+free_priv:
+ xhci_urb_free_priv(xhci, urb_priv);
+ urb->hcpriv = NULL;
spin_unlock_irqrestore(&xhci->lock, flags);
- return -ESHUTDOWN;
+ return ret;
}
/* Get the right ring for the given URB.
@@ -1235,6 +1252,13 @@
if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_HALTED)) {
xhci_dbg(xhci, "HW died, freeing TD.\n");
urb_priv = urb->hcpriv;
+ for (i = urb_priv->td_cnt; i < urb_priv->length; i++) {
+ td = urb_priv->td[i];
+ if (!list_empty(&td->td_list))
+ list_del_init(&td->td_list);
+ if (!list_empty(&td->cancelled_td_list))
+ list_del_init(&td->cancelled_td_list);
+ }
usb_hcd_unlink_urb_from_ep(hcd, urb);
spin_unlock_irqrestore(&xhci->lock, flags);
@@ -1242,7 +1266,8 @@
xhci_urb_free_priv(xhci, urb_priv);
return ret;
}
- if (xhci->xhc_state & XHCI_STATE_DYING) {
+ if ((xhci->xhc_state & XHCI_STATE_DYING) ||
+ (xhci->xhc_state & XHCI_STATE_HALTED)) {
xhci_dbg(xhci, "Ep 0x%x: URB %p to be canceled on "
"non-responsive xHCI host.\n",
urb->ep->desc.bEndpointAddress, urb);
@@ -2667,7 +2692,10 @@
int i, ret;
ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__);
- if (ret <= 0)
+ /* If the host is halted due to driver unload, we still need to free the
+ * device.
+ */
+ if (ret <= 0 && ret != -ENODEV)
return;
virt_dev = xhci->devs[udev->slot_id];
@@ -2681,7 +2709,8 @@
spin_lock_irqsave(&xhci->lock, flags);
/* Don't disable the slot if the host controller is dead. */
state = xhci_readl(xhci, &xhci->op_regs->status);
- if (state == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING)) {
+ if (state == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) ||
+ (xhci->xhc_state & XHCI_STATE_HALTED)) {
xhci_free_virt_device(xhci, udev->slot_id);
spin_unlock_irqrestore(&xhci->lock, flags);
return;
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index c5dcdbf..13828e0 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -283,27 +283,13 @@
To compile this driver as a module, choose M here: the
module will be called diag_bridge_test. If unsure, choose N.
-config USB_QCOM_DUN_BRIDGE
- tristate "USB Qualcomm modem DUN bridge driver"
+config USB_QCOM_MDM_BRIDGE
+ tristate "USB Qualcomm modem bridge driver for DUN and RMNET"
depends on USB
help
Say Y here if you have a Qualcomm modem device connected via USB that
- will be bridged in kernel space. This driver will enable bridging
- with the gadget serial driver for use in dial-up networking. This is
- not the same as the qcserial driver that exposes a TTY interface to
- userspace.
-
+ will be bridged in kernel space. This driver works as a bridge to pass
+ control and data packets between the modem and peripheral usb gadget
+ driver for dial up network and RMNET.
To compile this driver as a module, choose M here: the module
- will be called dun_bridge.
-
-config USB_QCOM_DUN_BRIDGE_TEST
- tristate "USB Qualcomm modem DUN bridge driver test"
- depends on USB && USB_QCOM_DUN_BRIDGE && !USB_SERIAL_QUALCOMM
- help
- Say Y here if you want to enable the test hook for the
- Qualcomm modem bridge driver. When enabled, this will create
- a debugfs file entry named "dun_bridge_test" which can be used
- to read and write directly to the modem.
-
- To compile this driver as a module, choose M here: the module
- will be called dun_bridge_test.
+ will be called mdm_bridge. If unsure, choose N.
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index bb69a02..b4aee65 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -31,5 +31,5 @@
obj-$(CONFIG_USB_QCOM_DIAG_BRIDGE) += diag_bridge.o
obj-$(CONFIG_USB_QCOM_DIAG_BRIDGE_TEST) += diag_bridge_test.o
-obj-$(CONFIG_USB_QCOM_DUN_BRIDGE) += dun_bridge.o
-obj-$(CONFIG_USB_QCOM_DUN_BRIDGE_TEST) += dun_bridge_test.o
+mdm_bridge-y := mdm_ctrl_bridge.o mdm_data_bridge.o
+obj-$(CONFIG_USB_QCOM_MDM_BRIDGE) += mdm_bridge.o
diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c
index 11f9ef6..00b2ec1 100644
--- a/drivers/usb/misc/diag_bridge.c
+++ b/drivers/usb/misc/diag_bridge.c
@@ -97,7 +97,7 @@
return -ENODEV;
}
- urb = usb_alloc_urb(0, GFP_KERNEL);
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
dev_err(&dev->udev->dev, "unable to allocate urb\n");
return -ENOMEM;
@@ -108,7 +108,7 @@
diag_bridge_read_cb, dev);
usb_anchor_urb(urb, &dev->submitted);
- ret = usb_submit_urb(urb, GFP_KERNEL);
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret) {
dev_err(&dev->udev->dev, "submitting urb failed err:%d\n", ret);
usb_unanchor_urb(urb);
@@ -154,7 +154,7 @@
return -ENODEV;
}
- urb = usb_alloc_urb(0, GFP_KERNEL);
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
err("unable to allocate urb");
return -ENOMEM;
@@ -165,7 +165,7 @@
diag_bridge_write_cb, dev);
usb_anchor_urb(urb, &dev->submitted);
- ret = usb_submit_urb(urb, GFP_KERNEL);
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret) {
err("submitting urb failed err:%d", ret);
usb_unanchor_urb(urb);
diff --git a/drivers/usb/misc/dun_bridge.c b/drivers/usb/misc/dun_bridge.c
deleted file mode 100644
index aca7714..0000000
--- a/drivers/usb/misc/dun_bridge.c
+++ /dev/null
@@ -1,520 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/kref.h>
-#include <linux/platform_device.h>
-#include <linux/usb.h>
-#include <linux/usb/cdc.h>
-#include <linux/usb/ch9.h>
-#include <asm/unaligned.h>
-#include <mach/usb_dun_bridge.h>
-
-#define DRIVER_DESC "Qualcomm USB DUN bridge driver"
-#define DRIVER_VERSION "1.0"
-
-struct dun_bridge {
- struct usb_device *udev;
- struct usb_interface *intf;
- struct usb_anchor submitted;
- u8 int_in_epaddr;
- unsigned in, out; /* bulk in/out pipes */
-
- struct urb *inturb;
- struct usb_ctrlrequest cmd;
- u8 *ctrl_buf;
-
- struct kref kref;
- struct platform_device *pdev;
-
- struct dun_bridge_ops *ops;
-};
-
-static struct dun_bridge *__dev;
-
-/* This assumes that __dev has already been initialized by probe(). */
-int dun_bridge_open(struct dun_bridge_ops *ops)
-{
- struct dun_bridge *dev = __dev;
- int ret = 0;
-
- if (!dev) {
- err("%s: dev is null", __func__);
- return -ENODEV;
- }
-
- if (!ops || !ops->read_complete || !ops->write_complete)
- return -EINVAL;
-
- dev->ops = ops;
- if (ops->ctrl_status) {
- ret = usb_submit_urb(dev->inturb, GFP_KERNEL);
- if (ret)
- pr_err("%s: submitting int urb failed: %d\n",
- __func__, ret);
- }
-
- return ret;
-}
-EXPORT_SYMBOL(dun_bridge_open);
-
-int dun_bridge_close(void)
-{
- struct dun_bridge *dev = __dev;
- if (!dev)
- return -ENODEV;
-
- dev_dbg(&dev->udev->dev, "%s:", __func__);
- usb_unlink_anchored_urbs(&dev->submitted);
- usb_unlink_urb(dev->inturb);
- dev->ops = NULL;
-
- return 0;
-}
-EXPORT_SYMBOL(dun_bridge_close);
-
-static void read_cb(struct urb *urb)
-{
- struct dun_bridge *dev = urb->context;
- struct dun_bridge_ops *ops;
-
- if (!dev || !dev->intf) {
- pr_err("%s: device is disconnected\n", __func__);
- kfree(urb->transfer_buffer);
- return;
- }
-
- dev_dbg(&dev->udev->dev, "%s: status:%d actual:%d\n", __func__,
- urb->status, urb->actual_length);
-
- usb_autopm_put_interface(dev->intf);
- ops = dev->ops;
- if (ops)
- ops->read_complete(ops->ctxt,
- urb->transfer_buffer,
- urb->transfer_buffer_length,
- /* callback must check this value for error */
- urb->status < 0 ?
- urb->status : urb->actual_length);
- else {
- /* can't call back, free buffer on caller's behalf */
- dev_err(&dev->udev->dev, "cannot complete read callback\n");
- kfree(urb->transfer_buffer);
- }
-}
-
-int dun_bridge_read(void *data, int len)
-{
- struct dun_bridge *dev = __dev;
- struct urb *urb;
- int ret;
-
- if (!dev || !dev->ops)
- return -ENODEV;
-
- if (!dev->intf) {
- pr_err("%s: device is disconnected\n", __func__);
- return -ENODEV;
- }
-
- if (!len) {
- dev_err(&dev->udev->dev, "%s: invalid len:%d\n", __func__, len);
- return -EINVAL;
- }
-
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb) {
- dev_err(&dev->udev->dev, "%s: Unable to alloc urb\n", __func__);
- return -ENOMEM;
- }
-
- usb_fill_bulk_urb(urb, dev->udev, dev->in,
- data, len, read_cb, dev);
- usb_anchor_urb(urb, &dev->submitted);
-
- usb_autopm_get_interface(dev->intf);
- ret = usb_submit_urb(urb, GFP_KERNEL);
- if (ret) {
- dev_err(&dev->udev->dev, "%s: submit urb err:%d\n",
- __func__, ret);
- usb_unanchor_urb(urb);
- usb_autopm_put_interface(dev->intf);
- }
-
- usb_free_urb(urb);
- return ret;
-}
-EXPORT_SYMBOL(dun_bridge_read);
-
-static void write_cb(struct urb *urb)
-{
- struct dun_bridge *dev = urb->context;
- struct dun_bridge_ops *ops;
-
- if (!dev || !dev->intf) {
- pr_err("%s: device is disconnected\n", __func__);
- kfree(urb->transfer_buffer);
- return;
- }
-
- dev_dbg(&dev->udev->dev, "%s: status:%d actual:%d\n", __func__,
- urb->status, urb->actual_length);
-
- usb_autopm_put_interface(dev->intf);
- ops = dev->ops;
- if (ops)
- ops->write_complete(ops->ctxt,
- urb->transfer_buffer,
- urb->transfer_buffer_length,
- /* callback must check this value for error */
- urb->status < 0 ?
- urb->status : urb->actual_length);
- else {
- /* can't call back, free buffer on caller's behalf */
- dev_err(&dev->udev->dev, "cannot complete write callback\n");
- kfree(urb->transfer_buffer);
- }
-}
-
-int dun_bridge_write(void *data, int len)
-{
- struct dun_bridge *dev = __dev;
- struct urb *urb;
- int ret;
-
- if (!dev || !dev->ops)
- return -ENODEV;
-
- if (!dev->intf) {
- pr_err("%s: device is disconnected\n", __func__);
- return -ENODEV;
- }
-
- if (!len) {
- dev_err(&dev->udev->dev, "%s: invalid len:%d\n", __func__, len);
- return -EINVAL;
- }
-
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb) {
- dev_err(&dev->udev->dev, "%s: Unable to alloc urb\n", __func__);
- return -ENOMEM;
- }
-
- usb_fill_bulk_urb(urb, dev->udev, dev->out,
- data, len, write_cb, dev);
- usb_anchor_urb(urb, &dev->submitted);
-
- usb_autopm_get_interface(dev->intf);
- ret = usb_submit_urb(urb, GFP_KERNEL);
- if (ret) {
- dev_err(&dev->udev->dev, "%s: submit urb err:%d\n",
- __func__, ret);
- usb_unanchor_urb(urb);
- usb_autopm_put_interface(dev->intf);
- }
-
- usb_free_urb(urb);
- return ret;
-}
-EXPORT_SYMBOL(dun_bridge_write);
-
-static void ctrl_cb(struct urb *urb)
-{
- struct dun_bridge *dev = urb->context;
- usb_autopm_put_interface(dev->intf);
-}
-
-int dun_bridge_send_ctrl_bits(unsigned ctrl_bits)
-{
- struct dun_bridge *dev = __dev;
- struct urb *urb = NULL;
- int ret;
-
- if (!dev || !dev->intf) {
- pr_err("%s: device is disconnected\n", __func__);
- return -ENODEV;
- }
-
- dev_dbg(&dev->udev->dev, "%s: %#x", __func__, ctrl_bits);
-
- dev->cmd.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
- dev->cmd.bRequest = USB_CDC_REQ_SET_CONTROL_LINE_STATE;
- dev->cmd.wValue = cpu_to_le16(ctrl_bits);
- dev->cmd.wIndex = cpu_to_le16(dev->int_in_epaddr);
- dev->cmd.wLength = 0;
-
- urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!urb) {
- dev_err(&dev->udev->dev, "%s: Unable to alloc urb\n", __func__);
- return -ENOMEM;
- }
-
- usb_fill_control_urb(urb, dev->udev, usb_sndctrlpipe(dev->udev, 0),
- (unsigned char *)&dev->cmd, NULL, 0,
- ctrl_cb, dev);
-
- usb_autopm_get_interface(dev->intf);
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret) {
- dev_err(&dev->udev->dev, "%s: submit urb err:%d\n",
- __func__, ret);
- usb_autopm_put_interface(dev->intf);
- }
-
- usb_free_urb(urb);
- return ret;
-}
-EXPORT_SYMBOL(dun_bridge_send_ctrl_bits);
-
-static void int_cb(struct urb *urb)
-{
- struct dun_bridge *dev = urb->context;
- struct usb_cdc_notification *dr = urb->transfer_buffer;
- unsigned char *data;
- unsigned int ctrl_bits;
- int status = urb->status;
-
- if (!dev || !dev->intf) {
- pr_err("%s: device is disconnected\n", __func__);
- return;
- }
-
- switch (status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dev_err(&dev->udev->dev,
- "%s - urb shutting down with status: %d\n",
- __func__, status);
- return;
- default:
- dev_err(&dev->udev->dev,
- "%s - nonzero urb status received: %d\n",
- __func__, status);
- goto resubmit_urb;
- }
-
- data = (unsigned char *)(dr + 1);
- switch (dr->bNotificationType) {
- case USB_CDC_NOTIFY_NETWORK_CONNECTION:
- dev_dbg(&dev->udev->dev, "%s network\n", dr->wValue ?
- "connected to" : "disconnected from");
- break;
-
- case USB_CDC_NOTIFY_SERIAL_STATE:
- ctrl_bits = get_unaligned_le16(data);
- dev_dbg(&dev->udev->dev, "serial state: %d\n", ctrl_bits);
- if (dev->ops && dev->ops->ctrl_status)
- dev->ops->ctrl_status(dev->ops->ctxt, ctrl_bits);
- break;
-
- default:
- dev_err(&dev->udev->dev, "unknown notification %d received: "
- "index %d len %d data0 %d data1 %d\n",
- dr->bNotificationType, dr->wIndex,
- dr->wLength, data[0], data[1]);
- break;
- }
-resubmit_urb:
- status = usb_submit_urb(dev->inturb, GFP_ATOMIC);
- if (status)
- dev_err(&dev->udev->dev, "%s: submit urb err:%d\n",
- __func__, status);
-}
-
-static void dun_bridge_delete(struct kref *kref)
-{
- struct dun_bridge *dev = container_of(kref, struct dun_bridge, kref);
-
- __dev = NULL;
- usb_put_dev(dev->udev);
- usb_free_urb(dev->inturb);
- kfree(dev->ctrl_buf);
- kfree(dev);
-}
-
-static int
-dun_bridge_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
- struct dun_bridge *dev;
- struct usb_host_interface *iface_desc;
- struct usb_endpoint_descriptor *epd;
- __u8 iface_num;
- int i;
- int ctrlsize = 0;
- int ret = -ENOMEM;
-
- iface_desc = intf->cur_altsetting;
- iface_num = iface_desc->desc.bInterfaceNumber;
-
- /* is this interface supported? */
- if (iface_num != id->driver_info)
- return -ENODEV;
-
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev) {
- pr_err("%s: unable to allocate dev\n", __func__);
- goto error;
- }
-
- dev->pdev = platform_device_alloc("dun_bridge", 0);
- if (!dev->pdev) {
- pr_err("%s: unable to allocate platform device\n", __func__);
- kfree(dev);
- return -ENOMEM;
- }
- __dev = dev;
-
- kref_init(&dev->kref);
- dev->udev = usb_get_dev(interface_to_usbdev(intf));
- dev->intf = intf;
-
- init_usb_anchor(&dev->submitted);
- dev->inturb = usb_alloc_urb(0, GFP_KERNEL);
- if (!dev->inturb) {
- ret = -ENOMEM;
- goto error;
- }
-
- for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
- epd = &iface_desc->endpoint[i].desc;
-
- if (usb_endpoint_is_int_in(epd)) {
- dev->int_in_epaddr = epd->bEndpointAddress;
- ctrlsize = le16_to_cpu(epd->wMaxPacketSize);
-
- dev->ctrl_buf = kzalloc(ctrlsize, GFP_KERNEL);
- if (!dev->ctrl_buf) {
- ret = -ENOMEM;
- goto error;
- }
-
- usb_fill_int_urb(dev->inturb, dev->udev,
- usb_rcvintpipe(dev->udev,
- dev->int_in_epaddr),
- dev->ctrl_buf, ctrlsize,
- int_cb, dev, epd->bInterval);
-
- } else if (usb_endpoint_is_bulk_in(epd))
- dev->in = usb_rcvbulkpipe(dev->udev,
- epd->bEndpointAddress &
- USB_ENDPOINT_NUMBER_MASK);
-
- else if (usb_endpoint_is_bulk_out(epd))
- dev->out = usb_sndbulkpipe(dev->udev,
- epd->bEndpointAddress &
- USB_ENDPOINT_NUMBER_MASK);
- }
-
- if (!dev->int_in_epaddr && !dev->in && !dev->out) {
- dev_err(&dev->udev->dev, "%s: could not find all endpoints\n",
- __func__);
- ret = -ENODEV;
- goto error;
- }
-
- usb_set_intfdata(intf, dev);
- platform_device_add(dev->pdev);
- return 0;
-error:
- if (dev)
- kref_put(&dev->kref, dun_bridge_delete);
- return ret;
-}
-
-static void dun_bridge_disconnect(struct usb_interface *intf)
-{
- struct dun_bridge *dev = usb_get_intfdata(intf);
-
- platform_device_del(dev->pdev);
- usb_set_intfdata(intf, NULL);
- dev->intf = NULL;
-
- kref_put(&dev->kref, dun_bridge_delete);
-
- pr_debug("%s: DUN Bridge now disconnected\n", __func__);
-}
-
-static int dun_bridge_suspend(struct usb_interface *intf, pm_message_t message)
-{
- struct dun_bridge *dev = usb_get_intfdata(intf);
-
- dev_dbg(&dev->udev->dev, "%s:", __func__);
- usb_unlink_anchored_urbs(&dev->submitted);
- usb_unlink_urb(dev->inturb);
-
- return 0;
-}
-
-static int dun_bridge_resume(struct usb_interface *intf)
-{
- struct dun_bridge *dev = usb_get_intfdata(intf);
- int ret = 0;
-
- if (dev->ops && dev->ops->ctrl_status) {
- ret = usb_submit_urb(dev->inturb, GFP_KERNEL);
- if (ret)
- dev_err(&dev->udev->dev, "%s: submit int urb err: %d\n",
- __func__, ret);
- }
-
- return ret;
-}
-
-#define VALID_INTERFACE_NUM 2
-static const struct usb_device_id id_table[] = {
- { USB_DEVICE(0x05c6, 0x9001), /* Generic QC Modem device */
- .driver_info = VALID_INTERFACE_NUM },
- { } /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_driver dun_bridge_driver = {
- .name = "dun_usb_bridge",
- .probe = dun_bridge_probe,
- .disconnect = dun_bridge_disconnect,
- .id_table = id_table,
- .suspend = dun_bridge_suspend,
- .resume = dun_bridge_resume,
- .supports_autosuspend = true,
-};
-
-static int __init dun_bridge_init(void)
-{
- int ret;
-
- ret = usb_register(&dun_bridge_driver);
- if (ret)
- pr_err("%s: unable to register dun_bridge_driver\n", __func__);
-
- return ret;
-}
-
-static void __exit dun_bridge_exit(void)
-{
- usb_deregister(&dun_bridge_driver);
-}
-
-module_init(dun_bridge_init);
-module_exit(dun_bridge_exit);
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL V2");
diff --git a/drivers/usb/misc/dun_bridge_test.c b/drivers/usb/misc/dun_bridge_test.c
deleted file mode 100644
index d545e13..0000000
--- a/drivers/usb/misc/dun_bridge_test.c
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * 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/slab.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/debugfs.h>
-#include <linux/usb/cdc.h>
-#include <linux/uaccess.h>
-#include <mach/usb_dun_bridge.h>
-
-#define RD_BUF_SIZE 2048
-#define DUN_TEST_CONNECTED 0
-
-
-struct dun_bridge_test_dev {
- char *read_buf;
- size_t buflen;
- struct work_struct read_w;
- unsigned long flags;
-
- struct dun_bridge_ops ops;
-};
-static struct dun_bridge_test_dev *__dev;
-
-static struct dentry *dfile;
-
-static void
-dun_bridge_test_read_complete(void *d, char *buf, size_t size, size_t actual)
-{
- if (actual < 0) {
- pr_err("%s: read complete err\n", __func__);
- return;
- }
-
- __dev->buflen = actual;
- buf[actual] = 0;
-
- pr_info("%s: %s\n", __func__, buf);
-
- if (test_bit(DUN_TEST_CONNECTED, &__dev->flags))
- schedule_work(&__dev->read_w);
-}
-
-static void dun_bridge_test_read_work(struct work_struct *w)
-{
- struct dun_bridge_test_dev *dev =
- container_of(w, struct dun_bridge_test_dev, read_w);
-
- dun_bridge_read(dev->read_buf, RD_BUF_SIZE);
-}
-
-static void
-dun_bridge_test_write_complete(void *d, char *buf, size_t size, size_t actual)
-{
- struct dun_bridge_test_dev *dev = d;
-
- if (actual > 0)
- schedule_work(&dev->read_w);
-
- kfree(buf);
-}
-
-#if defined(CONFIG_DEBUG_FS)
-#define DEBUG_BUF_SIZE 1024
-
-#define ACM_CTRL_DTR 0x01
-#define ACM_CTRL_RTS 0x02
-
-static int debug_open(struct inode *inode, struct file *file)
-{
- struct dun_bridge_test_dev *dev = __dev;
- int ret = 0;
-
- if (!dev)
- return -ENODEV;
-
- if (!test_bit(DUN_TEST_CONNECTED, &dev->flags)) {
- ret = dun_bridge_open(&dev->ops);
- if (ret)
- return ret;
- set_bit(DUN_TEST_CONNECTED, &dev->flags);
- dun_bridge_send_ctrl_bits(ACM_CTRL_DTR | ACM_CTRL_RTS);
- }
-
- return ret;
-}
-
-static ssize_t debug_read(struct file *file, char __user *ubuf,
- size_t count, loff_t *ppos)
-{
- struct dun_bridge_test_dev *dev = __dev;
- return simple_read_from_buffer(ubuf, count, ppos,
- dev->read_buf, dev->buflen);
-}
-
-static ssize_t debug_write(struct file *file, const char __user *ubuf,
- size_t count, loff_t *ppos)
-{
- struct dun_bridge_test_dev *dev = __dev;
- unsigned char *buf;
- int ret;
-
- if (!dev)
- return -ENODEV;
-
- buf = kmalloc(count, GFP_KERNEL);
- if (!buf) {
- pr_err("%s: unable to allocate mem for writing\n", __func__);
- return -ENOMEM;
- }
-
- if (!copy_from_user(buf, ubuf, count)) {
- ret = dun_bridge_write(buf, count);
- if (ret < 0) {
- pr_err("%s: error writing to dun_bridge\n", __func__);
- kfree(buf);
- return ret;
- }
- } else {
- pr_err("%s: error copying for writing\n", __func__);
- kfree(buf);
- }
-
- return count;
-}
-
-const struct file_operations dun_bridge_test_debug_ops = {
- .open = debug_open,
- .read = debug_read,
- .write = debug_write,
-};
-
-static void dun_bridge_test_debug_init(void)
-{
- dfile = debugfs_create_file("dun_bridge_test", 0555, NULL,
- NULL, &dun_bridge_test_debug_ops);
-}
-#else
-static void dun_bridge_test_debug_init(void) { }
-#endif
-
-static int __init dun_bridge_test_init(void)
-{
- struct dun_bridge_test_dev *dev;
-
- pr_info("%s\n", __func__);
-
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev)
- return -ENOMEM;
-
- __dev = dev;
-
- dev->ops.read_complete = dun_bridge_test_read_complete;
- dev->ops.write_complete = dun_bridge_test_write_complete;
- dev->read_buf = kmalloc(RD_BUF_SIZE, GFP_KERNEL);
- if (!dev->read_buf) {
- pr_err("%s: unable to allocate read buffer\n", __func__);
- kfree(dev);
- return -ENOMEM;
- }
-
- dev->ops.ctxt = dev;
- INIT_WORK(&dev->read_w, dun_bridge_test_read_work);
-
- dun_bridge_test_debug_init();
-
- return 0;
-}
-
-static void __exit dun_bridge_test_exit(void)
-{
- struct dun_bridge_test_dev *dev = __dev;
-
- pr_info("%s:\n", __func__);
-
- if (test_bit(DUN_TEST_CONNECTED, &dev->flags))
- dun_bridge_close();
-
- debugfs_remove(dfile);
-
- kfree(dev->read_buf);
- kfree(dev);
-}
-
-module_init(dun_bridge_test_init);
-module_exit(dun_bridge_test_exit);
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL V2");
diff --git a/drivers/usb/misc/mdm_ctrl_bridge.c b/drivers/usb/misc/mdm_ctrl_bridge.c
new file mode 100644
index 0000000..0397428
--- /dev/null
+++ b/drivers/usb/misc/mdm_ctrl_bridge.c
@@ -0,0 +1,729 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/debugfs.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/ratelimit.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/cdc.h>
+#include <linux/termios.h>
+#include <asm/unaligned.h>
+#include <mach/usb_bridge.h>
+
+static const char *ctrl_bridge_names[] = {
+ "dun_ctrl_hsic0",
+ "rmnet_ctrl_hsic0"
+};
+
+/* polling interval for Interrupt ep */
+#define HS_INTERVAL 7
+#define FS_LS_INTERVAL 3
+
+#define ACM_CTRL_DTR (1 << 0)
+#define DEFAULT_READ_URB_LENGTH 4096
+
+struct ctrl_bridge {
+
+ struct usb_device *udev;
+ struct usb_interface *intf;
+
+ unsigned int int_pipe;
+ struct urb *inturb;
+ void *intbuf;
+
+ struct urb *readurb;
+ void *readbuf;
+
+ struct usb_anchor tx_submitted;
+ struct usb_ctrlrequest *in_ctlreq;
+
+ struct bridge *brdg;
+ struct platform_device *pdev;
+
+ /* input control lines (DSR, CTS, CD, RI) */
+ unsigned int cbits_tohost;
+
+ /* output control lines (DTR, RTS) */
+ unsigned int cbits_tomdm;
+
+ /* counters */
+ unsigned int snd_encap_cmd;
+ unsigned int get_encap_res;
+ unsigned int resp_avail;
+ unsigned int set_ctrl_line_sts;
+ unsigned int notify_ser_state;
+
+};
+
+static struct ctrl_bridge *__dev[MAX_BRIDGE_DEVICES];
+
+/* counter used for indexing ctrl bridge devices */
+static int ch_id;
+
+unsigned int ctrl_bridge_get_cbits_tohost(unsigned int id)
+{
+ struct ctrl_bridge *dev;
+
+ if (id >= MAX_BRIDGE_DEVICES)
+ return -EINVAL;
+
+ dev = __dev[id];
+ if (!dev)
+ return -ENODEV;
+
+ return dev->cbits_tohost;
+}
+EXPORT_SYMBOL(ctrl_bridge_get_cbits_tohost);
+
+int ctrl_bridge_set_cbits(unsigned int id, unsigned int cbits)
+{
+ struct ctrl_bridge *dev;
+ struct bridge *brdg;
+ int retval;
+
+ if (id >= MAX_BRIDGE_DEVICES)
+ return -EINVAL;
+
+ dev = __dev[id];
+ if (!dev)
+ return -ENODEV;
+
+ pr_debug("%s: dev[id] =%u cbits : %u\n", __func__, id, cbits);
+
+ brdg = dev->brdg;
+ if (!brdg)
+ return -ENODEV;
+
+ dev->cbits_tomdm = cbits;
+
+ retval = ctrl_bridge_write(id, NULL, 0);
+
+ /* if DTR is high, update latest modem info to host */
+ if (brdg && (cbits & ACM_CTRL_DTR) && brdg->ops.send_cbits)
+ brdg->ops.send_cbits(brdg->ctx, dev->cbits_tohost);
+
+ return retval;
+}
+EXPORT_SYMBOL(ctrl_bridge_set_cbits);
+
+static void resp_avail_cb(struct urb *urb)
+{
+ struct ctrl_bridge *dev = urb->context;
+ struct usb_device *udev;
+ int status = 0;
+ int resubmit_urb = 1;
+ struct bridge *brdg = dev->brdg;
+
+ udev = interface_to_usbdev(dev->intf);
+ switch (urb->status) {
+ case 0:
+ /*success*/
+ dev->get_encap_res++;
+ if (brdg && brdg->ops.send_pkt)
+ brdg->ops.send_pkt(brdg->ctx, urb->transfer_buffer,
+ urb->actual_length);
+ break;
+
+ /*do not resubmit*/
+ case -ESHUTDOWN:
+ case -ENOENT:
+ case -ECONNRESET:
+ /* unplug */
+ case -EPROTO:
+ /*babble error*/
+ resubmit_urb = 0;
+ /*resubmit*/
+ case -EOVERFLOW:
+ default:
+ dev_dbg(&udev->dev, "%s: non zero urb status = %d\n",
+ __func__, urb->status);
+ }
+
+ if (resubmit_urb) {
+ /*re- submit int urb to check response available*/
+ status = usb_submit_urb(dev->inturb, GFP_ATOMIC);
+ if (status)
+ dev_err(&udev->dev,
+ "%s: Error re-submitting Int URB %d\n",
+ __func__, status);
+ }
+}
+
+static void notification_available_cb(struct urb *urb)
+{
+ int status;
+ struct usb_cdc_notification *ctrl;
+ struct usb_device *udev;
+ struct ctrl_bridge *dev = urb->context;
+ struct bridge *brdg = dev->brdg;
+ unsigned int ctrl_bits;
+ unsigned char *data;
+
+ udev = interface_to_usbdev(dev->intf);
+
+ switch (urb->status) {
+ case 0:
+ /*success*/
+ break;
+ case -ESHUTDOWN:
+ case -ENOENT:
+ case -ECONNRESET:
+ case -EPROTO:
+ /* unplug */
+ return;
+ case -EPIPE:
+ dev_err(&udev->dev, "%s: stall on int endpoint\n", __func__);
+ /* TBD : halt to be cleared in work */
+ case -EOVERFLOW:
+ default:
+ pr_debug_ratelimited("%s: non zero urb status = %d\n",
+ __func__, urb->status);
+ goto resubmit_int_urb;
+ }
+
+ ctrl = (struct usb_cdc_notification *)urb->transfer_buffer;
+ data = (unsigned char *)(ctrl + 1);
+
+ switch (ctrl->bNotificationType) {
+ case USB_CDC_NOTIFY_RESPONSE_AVAILABLE:
+ dev->resp_avail++;
+ usb_fill_control_urb(dev->readurb, udev,
+ usb_rcvctrlpipe(udev, 0),
+ (unsigned char *)dev->in_ctlreq,
+ dev->readbuf,
+ DEFAULT_READ_URB_LENGTH,
+ resp_avail_cb, dev);
+
+ status = usb_submit_urb(dev->readurb, GFP_ATOMIC);
+ if (status) {
+ dev_err(&udev->dev,
+ "%s: Error submitting Read URB %d\n",
+ __func__, status);
+ goto resubmit_int_urb;
+ }
+ return;
+ case USB_CDC_NOTIFY_NETWORK_CONNECTION:
+ dev_dbg(&udev->dev, "%s network\n", ctrl->wValue ?
+ "connected to" : "disconnected from");
+ break;
+ case USB_CDC_NOTIFY_SERIAL_STATE:
+ dev->notify_ser_state++;
+ ctrl_bits = get_unaligned_le16(data);
+ dev_dbg(&udev->dev, "serial state: %d\n", ctrl_bits);
+ dev->cbits_tohost = ctrl_bits;
+ if (brdg && brdg->ops.send_cbits)
+ brdg->ops.send_cbits(brdg->ctx, ctrl_bits);
+ break;
+ default:
+ dev_err(&udev->dev, "%s: unknown notification %d received:"
+ "index %d len %d data0 %d data1 %d",
+ __func__, ctrl->bNotificationType, ctrl->wIndex,
+ ctrl->wLength, data[0], data[1]);
+ }
+
+resubmit_int_urb:
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status)
+ dev_err(&udev->dev, "%s: Error re-submitting Int URB %d\n",
+ __func__, status);
+}
+
+int ctrl_bridge_start_read(struct ctrl_bridge *dev)
+{
+ int retval = 0;
+ struct usb_device *udev;
+
+ udev = interface_to_usbdev(dev->intf);
+
+ retval = usb_autopm_get_interface_async(dev->intf);
+ if (retval < 0) {
+ dev_err(&udev->dev, "%s resumption fail\n", __func__);
+ goto done_nopm;
+ }
+
+ retval = usb_submit_urb(dev->inturb, GFP_KERNEL);
+ if (retval < 0)
+ dev_err(&udev->dev, "%s intr submit %d\n", __func__, retval);
+
+ usb_autopm_put_interface_async(dev->intf);
+done_nopm:
+ return retval;
+}
+
+static int ctrl_bridge_stop_read(struct ctrl_bridge *dev)
+{
+ if (dev->readurb) {
+ dev_dbg(&dev->udev->dev, "killing rcv urb\n");
+ usb_unlink_urb(dev->readurb);
+ }
+
+ if (dev->inturb) {
+ dev_dbg(&dev->udev->dev, "killing int urb\n");
+ usb_unlink_urb(dev->inturb);
+ }
+
+ return 0;
+}
+
+int ctrl_bridge_open(struct bridge *brdg)
+{
+ struct ctrl_bridge *dev;
+
+ if (!brdg) {
+ err("bridge is null\n");
+ return -EINVAL;
+ }
+
+ if (brdg->ch_id >= MAX_BRIDGE_DEVICES)
+ return -EINVAL;
+
+ dev = __dev[brdg->ch_id];
+ if (!dev) {
+ err("dev is null\n");
+ return -ENODEV;
+ }
+
+ dev->brdg = brdg;
+ dev->snd_encap_cmd = 0;
+ dev->get_encap_res = 0;
+ dev->resp_avail = 0;
+ dev->set_ctrl_line_sts = 0;
+ dev->notify_ser_state = 0;
+
+ return ctrl_bridge_start_read(dev);
+}
+EXPORT_SYMBOL(ctrl_bridge_open);
+
+void ctrl_bridge_close(unsigned int id)
+{
+ struct ctrl_bridge *dev;
+
+ if (id >= MAX_BRIDGE_DEVICES)
+ return;
+
+ dev = __dev[id];
+ if (!dev || !dev->brdg)
+ return;
+
+ dev_dbg(&dev->udev->dev, "%s:\n", __func__);
+
+ ctrl_bridge_set_cbits(dev->brdg->ch_id, 0);
+ usb_unlink_anchored_urbs(&dev->tx_submitted);
+ ctrl_bridge_stop_read(dev);
+
+ dev->brdg = NULL;
+}
+EXPORT_SYMBOL(ctrl_bridge_close);
+
+static void ctrl_write_callback(struct urb *urb)
+{
+
+ if (urb->status) {
+ pr_debug("Write status/size %d/%d\n",
+ urb->status, urb->actual_length);
+ }
+
+ kfree(urb->transfer_buffer);
+ kfree(urb->setup_packet);
+ usb_free_urb(urb);
+}
+
+int ctrl_bridge_write(unsigned int id, char *data, size_t size)
+{
+ int result;
+ struct urb *writeurb;
+ struct usb_ctrlrequest *out_ctlreq;
+ struct usb_device *udev;
+ struct ctrl_bridge *dev;
+
+ if (id >= MAX_BRIDGE_DEVICES) {
+ result = -EINVAL;
+ goto free_data;
+ }
+
+ dev = __dev[id];
+
+ if (!dev) {
+ result = -ENODEV;
+ goto free_data;
+ }
+
+ udev = interface_to_usbdev(dev->intf);
+
+ dev_dbg(&udev->dev, "%s:[id]:%u: write (%d bytes)\n",
+ __func__, id, size);
+
+ writeurb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!writeurb) {
+ dev_err(&udev->dev, "%s: error allocating read urb\n",
+ __func__);
+ result = -ENOMEM;
+ goto free_data;
+ }
+
+ out_ctlreq = kmalloc(sizeof(*out_ctlreq), GFP_ATOMIC);
+ if (!out_ctlreq) {
+ dev_err(&udev->dev,
+ "%s: error allocating setup packet buffer\n",
+ __func__);
+ result = -ENOMEM;
+ goto free_urb;
+ }
+
+ /* CDC Send Encapsulated Request packet */
+ out_ctlreq->bRequestType = (USB_DIR_OUT | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE);
+ if (!data && !size) {
+ out_ctlreq->bRequest = USB_CDC_REQ_SET_CONTROL_LINE_STATE;
+ out_ctlreq->wValue = dev->cbits_tomdm;
+ dev->set_ctrl_line_sts++;
+ } else {
+ out_ctlreq->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND;
+ out_ctlreq->wValue = 0;
+ dev->snd_encap_cmd++;
+ }
+ out_ctlreq->wIndex =
+ dev->intf->cur_altsetting->desc.bInterfaceNumber;
+ out_ctlreq->wLength = cpu_to_le16(size);
+
+ usb_fill_control_urb(writeurb, udev,
+ usb_sndctrlpipe(udev, 0),
+ (unsigned char *)out_ctlreq,
+ (void *)data, size,
+ ctrl_write_callback, NULL);
+
+ result = usb_autopm_get_interface_async(dev->intf);
+ if (result < 0) {
+ dev_err(&udev->dev, "%s: unable to resume interface: %d\n",
+ __func__, result);
+
+ /*
+ * Revisit: if (result == -EPERM)
+ * bridge_suspend(dev->intf, PMSG_SUSPEND);
+ */
+
+ goto free_ctrlreq;
+ }
+
+ usb_anchor_urb(writeurb, &dev->tx_submitted);
+ result = usb_submit_urb(writeurb, GFP_ATOMIC);
+ if (result < 0) {
+ dev_err(&udev->dev, "%s: submit URB error %d\n",
+ __func__, result);
+ usb_autopm_put_interface_async(dev->intf);
+ goto unanchor_urb;
+ }
+
+ return size;
+
+unanchor_urb:
+ usb_unanchor_urb(writeurb);
+free_ctrlreq:
+ kfree(out_ctlreq);
+free_urb:
+ usb_free_urb(writeurb);
+free_data:
+ kfree(data);
+
+ return result;
+}
+EXPORT_SYMBOL(ctrl_bridge_write);
+
+int ctrl_bridge_suspend(unsigned int id)
+{
+ struct ctrl_bridge *dev;
+
+ if (id >= MAX_BRIDGE_DEVICES)
+ return -EINVAL;
+
+ dev = __dev[id];
+ if (!dev)
+ return -ENODEV;
+
+ usb_kill_anchored_urbs(&dev->tx_submitted);
+
+ return ctrl_bridge_stop_read(dev);
+}
+
+int ctrl_bridge_resume(unsigned int id)
+{
+ struct ctrl_bridge *dev;
+
+ if (id >= MAX_BRIDGE_DEVICES)
+ return -EINVAL;
+
+ dev = __dev[id];
+ if (!dev)
+ return -ENODEV;
+
+ return ctrl_bridge_start_read(dev);
+}
+
+#if defined(CONFIG_DEBUG_FS)
+#define DEBUG_BUF_SIZE 1024
+static ssize_t ctrl_bridge_read_stats(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct ctrl_bridge *dev;
+ char *buf;
+ int ret;
+ int i;
+ int temp = 0;
+
+ buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ for (i = 0; i < ch_id; i++) {
+ dev = __dev[i];
+ if (!dev)
+ continue;
+
+ temp += scnprintf(buf + temp, DEBUG_BUF_SIZE - temp,
+ "\nName#%s dev %p\n"
+ "snd encap cmd cnt: %u\n"
+ "get encap res cnt: %u\n"
+ "res available cnt: %u\n"
+ "set ctrlline sts cnt: %u\n"
+ "notify ser state cnt: %u\n"
+ "cbits_tomdm: %d\n"
+ "cbits_tohost: %d\n",
+ dev->pdev->name, dev,
+ dev->snd_encap_cmd,
+ dev->get_encap_res,
+ dev->resp_avail,
+ dev->set_ctrl_line_sts,
+ dev->notify_ser_state,
+ dev->cbits_tomdm,
+ dev->cbits_tohost);
+
+ }
+
+ ret = simple_read_from_buffer(ubuf, count, ppos, buf, temp);
+
+ kfree(buf);
+
+ return ret;
+}
+
+static ssize_t ctrl_bridge_reset_stats(struct file *file,
+ const char __user *buf, size_t count, loff_t *ppos)
+{
+ struct ctrl_bridge *dev;
+ int i;
+
+ for (i = 0; i < ch_id; i++) {
+ dev = __dev[i];
+ if (!dev)
+ continue;
+
+ dev->snd_encap_cmd = 0;
+ dev->get_encap_res = 0;
+ dev->resp_avail = 0;
+ dev->set_ctrl_line_sts = 0;
+ dev->notify_ser_state = 0;
+ }
+ return count;
+}
+
+const struct file_operations ctrl_stats_ops = {
+ .read = ctrl_bridge_read_stats,
+ .write = ctrl_bridge_reset_stats,
+};
+
+struct dentry *ctrl_dent;
+struct dentry *ctrl_dfile;
+static void ctrl_bridge_debugfs_init(void)
+{
+ ctrl_dent = debugfs_create_dir("ctrl_hsic_bridge", 0);
+ if (IS_ERR(ctrl_dent))
+ return;
+
+ ctrl_dfile =
+ debugfs_create_file("status", 0644, ctrl_dent, 0,
+ &ctrl_stats_ops);
+ if (!ctrl_dfile || IS_ERR(ctrl_dfile))
+ debugfs_remove(ctrl_dent);
+}
+
+static void ctrl_bridge_debugfs_exit(void)
+{
+ debugfs_remove(ctrl_dfile);
+ debugfs_remove(ctrl_dent);
+}
+
+#else
+static void ctrl_bridge_debugfs_init(void) { }
+static void ctrl_bridge_debugfs_exit(void) { }
+#endif
+
+int
+ctrl_bridge_probe(struct usb_interface *ifc, struct usb_host_endpoint *int_in,
+ int id)
+{
+ struct ctrl_bridge *dev;
+ struct usb_device *udev;
+ struct usb_endpoint_descriptor *ep;
+ u16 wMaxPacketSize;
+ int retval = 0;
+ int interval;
+
+ udev = interface_to_usbdev(ifc);
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ dev_err(&udev->dev, "%s: unable to allocate dev\n",
+ __func__);
+ return -ENOMEM;
+ }
+ dev->pdev = platform_device_alloc(ctrl_bridge_names[id], id);
+ if (!dev->pdev) {
+ dev_err(&dev->udev->dev,
+ "%s: unable to allocate platform device\n", __func__);
+ retval = -ENOMEM;
+ goto nomem;
+ }
+
+ dev->udev = udev;
+ dev->int_pipe = usb_rcvintpipe(udev,
+ int_in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ dev->intf = ifc;
+
+ init_usb_anchor(&dev->tx_submitted);
+
+ /*use max pkt size from ep desc*/
+ ep = &dev->intf->cur_altsetting->endpoint[0].desc;
+
+ dev->inturb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->inturb) {
+ dev_err(&udev->dev, "%s: error allocating int urb\n", __func__);
+ retval = -ENOMEM;
+ goto pdev_del;
+ }
+
+ wMaxPacketSize = le16_to_cpu(ep->wMaxPacketSize);
+
+ dev->intbuf = kmalloc(wMaxPacketSize, GFP_KERNEL);
+ if (!dev->intbuf) {
+ dev_err(&udev->dev, "%s: error allocating int buffer\n",
+ __func__);
+ retval = -ENOMEM;
+ goto free_inturb;
+ }
+
+ interval =
+ (udev->speed == USB_SPEED_HIGH) ? HS_INTERVAL : FS_LS_INTERVAL;
+
+ usb_fill_int_urb(dev->inturb, udev, dev->int_pipe,
+ dev->intbuf, wMaxPacketSize,
+ notification_available_cb, dev, interval);
+
+ dev->readurb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->readurb) {
+ dev_err(&udev->dev, "%s: error allocating read urb\n",
+ __func__);
+ retval = -ENOMEM;
+ goto free_intbuf;
+ }
+
+ dev->readbuf = kmalloc(DEFAULT_READ_URB_LENGTH, GFP_KERNEL);
+ if (!dev->readbuf) {
+ dev_err(&udev->dev, "%s: error allocating read buffer\n",
+ __func__);
+ retval = -ENOMEM;
+ goto free_rurb;
+ }
+
+ dev->in_ctlreq = kmalloc(sizeof(*dev->in_ctlreq), GFP_KERNEL);
+ if (!dev->in_ctlreq) {
+ dev_err(&udev->dev,
+ "%s:error allocating setup packet buffer\n",
+ __func__);
+ retval = -ENOMEM;
+ goto free_rbuf;
+ }
+
+ dev->in_ctlreq->bRequestType =
+ (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
+ dev->in_ctlreq->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
+ dev->in_ctlreq->wValue = 0;
+ dev->in_ctlreq->wIndex =
+ dev->intf->cur_altsetting->desc.bInterfaceNumber;
+ dev->in_ctlreq->wLength = cpu_to_le16(DEFAULT_READ_URB_LENGTH);
+
+ __dev[id] = dev;
+
+ platform_device_add(dev->pdev);
+
+ ch_id++;
+
+ return retval;
+
+free_rbuf:
+ kfree(dev->readbuf);
+free_rurb:
+ usb_free_urb(dev->readurb);
+free_intbuf:
+ kfree(dev->intbuf);
+free_inturb:
+ usb_free_urb(dev->inturb);
+pdev_del:
+ platform_device_del(dev->pdev);
+nomem:
+ kfree(dev);
+
+ return retval;
+}
+
+void ctrl_bridge_disconnect(unsigned int id)
+{
+ struct ctrl_bridge *dev = __dev[id];
+
+ dev_dbg(&dev->udev->dev, "%s:\n", __func__);
+
+ kfree(dev->in_ctlreq);
+ kfree(dev->readbuf);
+ kfree(dev->intbuf);
+
+ usb_free_urb(dev->readurb);
+ usb_free_urb(dev->inturb);
+
+ platform_device_del(dev->pdev);
+ __dev[id] = NULL;
+ ch_id--;
+
+ kfree(dev);
+}
+
+static int __init ctrl_bridge_init(void)
+{
+ ctrl_bridge_debugfs_init();
+
+ return 0;
+}
+module_init(ctrl_bridge_init);
+
+static void __exit ctrl_bridge_exit(void)
+{
+ ctrl_bridge_debugfs_exit();
+}
+module_exit(ctrl_bridge_exit);
+
+MODULE_DESCRIPTION("Qualcomm modem control bridge driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c
new file mode 100644
index 0000000..7c44a9a
--- /dev/null
+++ b/drivers/usb/misc/mdm_data_bridge.c
@@ -0,0 +1,925 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/ratelimit.h>
+#include <mach/usb_bridge.h>
+
+#define MAX_RX_URBS 50
+#define RMNET_RX_BUFSIZE 2048
+
+#define STOP_SUBMIT_URB_LIMIT 400
+#define FLOW_CTRL_EN_THRESHOLD 500
+#define FLOW_CTRL_DISABLE 300
+#define FLOW_CTRL_SUPPORT 1
+
+static const char *data_bridge_names[] = {
+ "dun_data_hsic0",
+ "rmnet_data_hsic0"
+};
+
+static struct workqueue_struct *bridge_wq;
+
+static unsigned int fctrl_support = FLOW_CTRL_SUPPORT;
+module_param(fctrl_support, uint, S_IRUGO | S_IWUSR);
+
+static unsigned int fctrl_en_thld = FLOW_CTRL_EN_THRESHOLD;
+module_param(fctrl_en_thld, uint, S_IRUGO | S_IWUSR);
+
+static unsigned int fctrl_dis_thld = FLOW_CTRL_DISABLE;
+module_param(fctrl_dis_thld, uint, S_IRUGO | S_IWUSR);
+
+unsigned int max_rx_urbs = MAX_RX_URBS;
+module_param(max_rx_urbs, uint, S_IRUGO | S_IWUSR);
+
+unsigned int stop_submit_urb_limit = STOP_SUBMIT_URB_LIMIT;
+module_param(stop_submit_urb_limit, uint, S_IRUGO | S_IWUSR);
+
+#define TX_HALT BIT(0)
+#define RX_HALT BIT(1)
+#define SUSPENDED BIT(2)
+
+struct data_bridge {
+ struct usb_interface *intf;
+ struct usb_device *udev;
+ unsigned int bulk_in;
+ unsigned int bulk_out;
+
+ /* keep track of in-flight URBs */
+ struct usb_anchor tx_active;
+ struct usb_anchor rx_active;
+
+ /* keep track of outgoing URBs during suspend */
+ struct usb_anchor delayed;
+
+ struct list_head rx_idle;
+ struct sk_buff_head rx_done;
+
+ struct workqueue_struct *wq;
+ struct work_struct process_rx_w;
+
+ struct bridge *brdg;
+
+ /* work queue function for handling halt conditions */
+ struct work_struct kevent;
+
+ unsigned long flags;
+
+ struct platform_device *pdev;
+
+ /* counters */
+ atomic_t pending_txurbs;
+ unsigned int txurb_drp_cnt;
+ unsigned long to_host;
+ unsigned long to_modem;
+ unsigned int tx_throttled_cnt;
+ unsigned int tx_unthrottled_cnt;
+ unsigned int rx_throttled_cnt;
+ unsigned int rx_unthrottled_cnt;
+};
+
+static struct data_bridge *__dev[MAX_BRIDGE_DEVICES];
+
+/* counter used for indexing data bridge devices */
+static int ch_id;
+
+static int submit_rx_urb(struct data_bridge *dev, struct urb *urb,
+ gfp_t flags);
+
+static inline bool rx_halted(struct data_bridge *dev)
+{
+ return test_bit(RX_HALT, &dev->flags);
+}
+
+static inline bool rx_throttled(struct bridge *brdg)
+{
+ return test_bit(RX_THROTTLED, &brdg->flags);
+}
+
+int data_bridge_unthrottle_rx(unsigned int id)
+{
+ struct data_bridge *dev;
+
+ if (id >= MAX_BRIDGE_DEVICES)
+ return -EINVAL;
+
+ dev = __dev[id];
+ if (!dev || !dev->brdg)
+ return -ENODEV;
+
+ dev->rx_unthrottled_cnt++;
+ queue_work(dev->wq, &dev->process_rx_w);
+
+ return 0;
+}
+EXPORT_SYMBOL(data_bridge_unthrottle_rx);
+
+static void data_bridge_process_rx(struct work_struct *work)
+{
+ int retval;
+ unsigned long flags;
+ struct urb *rx_idle;
+ struct sk_buff *skb;
+ struct data_bridge *dev =
+ container_of(work, struct data_bridge, process_rx_w);
+
+ struct bridge *brdg = dev->brdg;
+
+ if (!brdg || !brdg->ops.send_pkt || rx_halted(dev))
+ return;
+
+ while (!rx_throttled(brdg) && (skb = skb_dequeue(&dev->rx_done))) {
+ dev->to_host++;
+ /* hand off sk_buff to client,they'll need to free it */
+ retval = brdg->ops.send_pkt(brdg->ctx, skb, skb->len);
+ if (retval == -ENOTCONN || retval == -EINVAL) {
+ return;
+ } else if (retval == -EBUSY) {
+ dev->rx_throttled_cnt++;
+ break;
+ }
+ }
+
+ spin_lock_irqsave(&dev->rx_done.lock, flags);
+ if (dev->rx_done.qlen > stop_submit_urb_limit && rx_throttled(brdg)) {
+ spin_unlock_irqrestore(&dev->rx_done.lock, flags);
+ return;
+ }
+
+ while (!list_empty(&dev->rx_idle)) {
+
+ rx_idle = list_first_entry(&dev->rx_idle, struct urb, urb_list);
+ list_del(&rx_idle->urb_list);
+ spin_unlock_irqrestore(&dev->rx_done.lock, flags);
+ retval = submit_rx_urb(dev, rx_idle, GFP_KERNEL);
+ spin_lock_irqsave(&dev->rx_done.lock, flags);
+ if (retval)
+ break;
+ }
+ spin_unlock_irqrestore(&dev->rx_done.lock, flags);
+}
+
+static void data_bridge_read_cb(struct urb *urb)
+{
+ struct bridge *brdg;
+ struct sk_buff *skb = urb->context;
+ struct data_bridge *dev = *(struct data_bridge **)skb->cb;
+ bool queue = 0;
+
+ brdg = dev->brdg;
+
+ skb_put(skb, urb->actual_length);
+
+ switch (urb->status) {
+ case 0: /* success */
+ queue = 1;
+ spin_lock(&dev->rx_done.lock);
+ __skb_queue_tail(&dev->rx_done, skb);
+ spin_unlock(&dev->rx_done.lock);
+ break;
+
+ /*do not resubmit*/
+ case -EPIPE:
+ set_bit(RX_HALT, &dev->flags);
+ dev_err(&dev->udev->dev, "%s: epout halted\n", __func__);
+ schedule_work(&dev->kevent);
+ /* FALLTHROUGH */
+ case -ESHUTDOWN:
+ case -ENOENT: /* suspended */
+ case -ECONNRESET: /* unplug */
+ case -EPROTO:
+ dev_kfree_skb_any(skb);
+ break;
+
+ /*resubmit */
+ case -EOVERFLOW: /*babble error*/
+ default:
+ queue = 1;
+ dev_kfree_skb_any(skb);
+ pr_debug_ratelimited("%s: non zero urb status = %d\n",
+ __func__, urb->status);
+ break;
+ }
+
+ spin_lock(&dev->rx_done.lock);
+ list_add_tail(&urb->urb_list, &dev->rx_idle);
+ spin_unlock(&dev->rx_done.lock);
+
+ if (queue)
+ queue_work(dev->wq, &dev->process_rx_w);
+}
+
+static int submit_rx_urb(struct data_bridge *dev, struct urb *rx_urb,
+ gfp_t flags)
+{
+ struct sk_buff *skb;
+ int retval = -EINVAL;
+
+ skb = alloc_skb(RMNET_RX_BUFSIZE, flags);
+ if (!skb) {
+ usb_free_urb(rx_urb);
+ return -ENOMEM;
+ }
+
+ *((struct data_bridge **)skb->cb) = dev;
+
+ usb_fill_bulk_urb(rx_urb, dev->udev, dev->bulk_in,
+ skb->data, RMNET_RX_BUFSIZE,
+ data_bridge_read_cb, skb);
+
+ if (test_bit(SUSPENDED, &dev->flags))
+ goto suspended;
+
+ usb_anchor_urb(rx_urb, &dev->rx_active);
+ retval = usb_submit_urb(rx_urb, flags);
+ if (retval)
+ goto fail;
+
+ return 0;
+fail:
+ usb_unanchor_urb(rx_urb);
+suspended:
+ dev_kfree_skb_any(skb);
+ usb_free_urb(rx_urb);
+ return retval;
+}
+
+static int data_bridge_prepare_rx(struct data_bridge *dev)
+{
+ int i;
+ struct urb *rx_urb;
+
+ for (i = 0; i < max_rx_urbs; i++) {
+ rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!rx_urb)
+ return -ENOMEM;
+
+ list_add_tail(&rx_urb->urb_list, &dev->rx_idle);
+ }
+ return 0;
+}
+
+int data_bridge_open(struct bridge *brdg)
+{
+ struct data_bridge *dev;
+
+ if (!brdg) {
+ err("bridge is null\n");
+ return -EINVAL;
+ }
+
+ if (brdg->ch_id >= MAX_BRIDGE_DEVICES)
+ return -EINVAL;
+
+ dev = __dev[brdg->ch_id];
+ if (!dev) {
+ err("dev is null\n");
+ return -ENODEV;
+ }
+
+ dev_dbg(&dev->udev->dev, "%s: dev:%p\n", __func__, dev);
+
+ dev->brdg = brdg;
+ atomic_set(&dev->pending_txurbs, 0);
+ dev->to_host = 0;
+ dev->to_modem = 0;
+ dev->txurb_drp_cnt = 0;
+ dev->tx_throttled_cnt = 0;
+ dev->tx_unthrottled_cnt = 0;
+ dev->rx_throttled_cnt = 0;
+ dev->rx_unthrottled_cnt = 0;
+
+ queue_work(dev->wq, &dev->process_rx_w);
+
+ return 0;
+}
+EXPORT_SYMBOL(data_bridge_open);
+
+void data_bridge_close(unsigned int id)
+{
+ struct data_bridge *dev;
+ struct sk_buff *skb;
+ unsigned long flags;
+
+ if (id >= MAX_BRIDGE_DEVICES)
+ return;
+
+ dev = __dev[id];
+ if (!dev || !dev->brdg)
+ return;
+
+ dev_dbg(&dev->udev->dev, "%s:\n", __func__);
+
+ usb_unlink_anchored_urbs(&dev->tx_active);
+ usb_unlink_anchored_urbs(&dev->rx_active);
+ usb_unlink_anchored_urbs(&dev->delayed);
+
+ spin_lock_irqsave(&dev->rx_done.lock, flags);
+ while ((skb = __skb_dequeue(&dev->rx_done)))
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&dev->rx_done.lock, flags);
+
+ dev->brdg = NULL;
+}
+EXPORT_SYMBOL(data_bridge_close);
+
+static void defer_kevent(struct work_struct *work)
+{
+ int status;
+ struct data_bridge *dev =
+ container_of(work, struct data_bridge, kevent);
+
+ if (!dev)
+ return;
+
+ if (test_bit(TX_HALT, &dev->flags)) {
+ usb_unlink_anchored_urbs(&dev->tx_active);
+
+ status = usb_autopm_get_interface(dev->intf);
+ if (status < 0) {
+ dev_err(&dev->udev->dev,
+ "can't acquire interface, status %d\n", status);
+ return;
+ }
+
+ status = usb_clear_halt(dev->udev, dev->bulk_out);
+ usb_autopm_put_interface(dev->intf);
+ if (status < 0 && status != -EPIPE && status != -ESHUTDOWN)
+ dev_err(&dev->udev->dev,
+ "can't clear tx halt, status %d\n", status);
+ else
+ clear_bit(TX_HALT, &dev->flags);
+ }
+
+ if (test_bit(RX_HALT, &dev->flags)) {
+ usb_unlink_anchored_urbs(&dev->rx_active);
+
+ status = usb_autopm_get_interface(dev->intf);
+ if (status < 0) {
+ dev_err(&dev->udev->dev,
+ "can't acquire interface, status %d\n", status);
+ return;
+ }
+
+ status = usb_clear_halt(dev->udev, dev->bulk_in);
+ usb_autopm_put_interface(dev->intf);
+ if (status < 0 && status != -EPIPE && status != -ESHUTDOWN)
+ dev_err(&dev->udev->dev,
+ "can't clear rx halt, status %d\n", status);
+ else {
+ clear_bit(RX_HALT, &dev->flags);
+ if (dev->brdg)
+ queue_work(dev->wq, &dev->process_rx_w);
+ }
+ }
+}
+
+static void data_bridge_write_cb(struct urb *urb)
+{
+ struct sk_buff *skb = urb->context;
+ struct data_bridge *dev = *(struct data_bridge **)skb->cb;
+ struct bridge *brdg = dev->brdg;
+ int pending;
+
+ pr_debug("%s: dev:%p\n", __func__, dev);
+
+ switch (urb->status) {
+ case 0: /*success*/
+ break;
+ case -EPIPE:
+ set_bit(TX_HALT, &dev->flags);
+ dev_err(&dev->udev->dev, "%s: epout halted\n", __func__);
+ schedule_work(&dev->kevent);
+ /* FALLTHROUGH */
+ case -ESHUTDOWN:
+ case -ENOENT: /* suspended */
+ case -ECONNRESET: /* unplug */
+ case -EOVERFLOW: /*babble error*/
+ /* FALLTHROUGH */
+ default:
+ pr_debug_ratelimited("%s: non zero urb status = %d\n",
+ __func__, urb->status);
+ }
+
+ usb_free_urb(urb);
+ dev_kfree_skb_any(skb);
+
+ pending = atomic_dec_return(&dev->pending_txurbs);
+
+ /*flow ctrl*/
+ if (brdg && fctrl_support && pending <= fctrl_dis_thld &&
+ test_and_clear_bit(TX_THROTTLED, &brdg->flags)) {
+ pr_debug_ratelimited("%s: disable flow ctrl: pend urbs:%u\n",
+ __func__, pending);
+ dev->tx_unthrottled_cnt++;
+ if (brdg->ops.unthrottle_tx)
+ brdg->ops.unthrottle_tx(brdg->ctx);
+ }
+
+ usb_autopm_put_interface_async(dev->intf);
+}
+
+int data_bridge_write(unsigned int id, struct sk_buff *skb)
+{
+ int result;
+ int size = skb->len;
+ int pending;
+ struct urb *txurb;
+ struct data_bridge *dev = __dev[id];
+ struct bridge *brdg;
+
+ if (!dev || !dev->brdg || !usb_get_intfdata(dev->intf))
+ return -ENODEV;
+
+ brdg = dev->brdg;
+
+ dev_dbg(&dev->udev->dev, "%s: write (%d bytes)\n", __func__, skb->len);
+
+ result = usb_autopm_get_interface(dev->intf);
+ if (result < 0) {
+ dev_err(&dev->udev->dev, "%s: resume failure\n", __func__);
+ goto error;
+ }
+
+ txurb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!txurb) {
+ dev_err(&dev->udev->dev, "%s: error allocating read urb\n",
+ __func__);
+ result = -ENOMEM;
+ goto error;
+ }
+
+ /* store dev pointer in skb */
+ *((struct data_bridge **)skb->cb) = dev;
+
+ usb_fill_bulk_urb(txurb, dev->udev, dev->bulk_out,
+ skb->data, skb->len, data_bridge_write_cb, skb);
+
+ if (test_bit(SUSPENDED, &dev->flags)) {
+ usb_anchor_urb(txurb, &dev->delayed);
+ goto free_urb;
+ }
+
+ pending = atomic_inc_return(&dev->pending_txurbs);
+ usb_anchor_urb(txurb, &dev->tx_active);
+
+ result = usb_submit_urb(txurb, GFP_KERNEL);
+ if (result < 0) {
+ usb_unanchor_urb(txurb);
+ atomic_dec(&dev->pending_txurbs);
+ dev_err(&dev->udev->dev, "%s: submit URB error %d\n",
+ __func__, result);
+ goto free_urb;
+ }
+
+ dev->to_modem++;
+ dev_dbg(&dev->udev->dev, "%s: pending_txurbs: %u\n", __func__, pending);
+
+ /* flow control: last urb submitted but return -EBUSY */
+ if (fctrl_support && pending > fctrl_en_thld) {
+ set_bit(TX_THROTTLED, &brdg->flags);
+ dev->tx_throttled_cnt++;
+ pr_debug_ratelimited("%s: enable flow ctrl pend txurbs:%u\n",
+ __func__, pending);
+ return -EBUSY;
+ }
+
+ return size;
+
+free_urb:
+ usb_free_urb(txurb);
+error:
+ dev->txurb_drp_cnt++;
+ usb_autopm_put_interface(dev->intf);
+
+ return result;
+}
+EXPORT_SYMBOL(data_bridge_write);
+
+static int data_bridge_resume(struct data_bridge *dev)
+{
+ struct urb *urb;
+ int retval;
+
+ while ((urb = usb_get_from_anchor(&dev->delayed))) {
+ usb_anchor_urb(urb, &dev->tx_active);
+ atomic_inc(&dev->pending_txurbs);
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval < 0) {
+ atomic_dec(&dev->pending_txurbs);
+ usb_unanchor_urb(urb);
+
+ /* TODO: need to free urb data */
+ usb_scuttle_anchored_urbs(&dev->delayed);
+ break;
+ }
+ dev->to_modem++;
+ dev->txurb_drp_cnt--;
+ }
+
+ clear_bit(SUSPENDED, &dev->flags);
+
+ if (dev->brdg)
+ queue_work(dev->wq, &dev->process_rx_w);
+
+ return 0;
+}
+
+static int bridge_resume(struct usb_interface *iface)
+{
+ int retval = 0;
+ int oldstate;
+ struct data_bridge *dev = usb_get_intfdata(iface);
+ struct bridge *brdg = dev->brdg;
+
+ oldstate = iface->dev.power.power_state.event;
+ iface->dev.power.power_state.event = PM_EVENT_ON;
+
+ retval = data_bridge_resume(dev);
+ if (!retval) {
+ if (oldstate & PM_EVENT_SUSPEND && brdg)
+ retval = ctrl_bridge_resume(brdg->ch_id);
+ }
+ return retval;
+}
+
+static int data_bridge_suspend(struct data_bridge *dev, pm_message_t message)
+{
+ if (atomic_read(&dev->pending_txurbs) &&
+ (message.event & PM_EVENT_AUTO))
+ return -EBUSY;
+
+ set_bit(SUSPENDED, &dev->flags);
+
+ usb_kill_anchored_urbs(&dev->tx_active);
+ usb_kill_anchored_urbs(&dev->rx_active);
+
+ return 0;
+}
+
+static int bridge_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ int retval;
+ struct data_bridge *dev = usb_get_intfdata(intf);
+ struct bridge *brdg = dev->brdg;
+
+ retval = data_bridge_suspend(dev, message);
+ if (!retval) {
+ if (message.event & PM_EVENT_SUSPEND) {
+ if (brdg)
+ retval = ctrl_bridge_suspend(brdg->ch_id);
+ intf->dev.power.power_state.event = message.event;
+ }
+ } else {
+ dev_dbg(&dev->udev->dev, "%s: device is busy,cannot suspend\n",
+ __func__);
+ }
+ return retval;
+}
+
+static int data_bridge_probe(struct usb_interface *iface,
+ struct usb_host_endpoint *bulk_in,
+ struct usb_host_endpoint *bulk_out, int id)
+{
+ struct data_bridge *dev;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ err("%s: unable to allocate dev\n", __func__);
+ return -ENOMEM;
+ }
+
+ dev->pdev = platform_device_alloc(data_bridge_names[id], id);
+ if (!dev->pdev) {
+ err("%s: unable to allocate platform device\n", __func__);
+ kfree(dev);
+ return -ENOMEM;
+ }
+
+ init_usb_anchor(&dev->tx_active);
+ init_usb_anchor(&dev->rx_active);
+ init_usb_anchor(&dev->delayed);
+
+ INIT_LIST_HEAD(&dev->rx_idle);
+ skb_queue_head_init(&dev->rx_done);
+
+ dev->wq = bridge_wq;
+
+ dev->udev = interface_to_usbdev(iface);
+ dev->intf = iface;
+
+ dev->bulk_in = usb_rcvbulkpipe(dev->udev,
+ bulk_in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+
+ dev->bulk_out = usb_sndbulkpipe(dev->udev,
+ bulk_out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+
+ usb_set_intfdata(iface, dev);
+
+ INIT_WORK(&dev->kevent, defer_kevent);
+ INIT_WORK(&dev->process_rx_w, data_bridge_process_rx);
+
+ __dev[id] = dev;
+
+ /*allocate list of rx urbs*/
+ data_bridge_prepare_rx(dev);
+
+ platform_device_add(dev->pdev);
+
+ return 0;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+#define DEBUG_BUF_SIZE 1024
+static ssize_t data_bridge_read_stats(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct data_bridge *dev;
+ char *buf;
+ int ret;
+ int i;
+ int temp = 0;
+
+ buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ for (i = 0; i < ch_id; i++) {
+ dev = __dev[i];
+ if (!dev)
+ continue;
+
+ temp += scnprintf(buf + temp, DEBUG_BUF_SIZE - temp,
+ "\nName#%s dev %p\n"
+ "pending tx urbs: %u\n"
+ "tx urb drp cnt: %u\n"
+ "to host: %lu\n"
+ "to mdm: %lu\n"
+ "tx throttled cnt: %u\n"
+ "tx unthrottled cnt: %u\n"
+ "rx throttled cnt: %u\n"
+ "rx unthrottled cnt: %u\n"
+ "rx done skb qlen: %u\n"
+ "suspended: %d\n"
+ "TX_HALT: %d\n"
+ "RX_HALT: %d\n",
+ dev->pdev->name, dev,
+ atomic_read(&dev->pending_txurbs),
+ dev->txurb_drp_cnt,
+ dev->to_host,
+ dev->to_modem,
+ dev->tx_throttled_cnt,
+ dev->tx_unthrottled_cnt,
+ dev->rx_throttled_cnt,
+ dev->rx_unthrottled_cnt,
+ dev->rx_done.qlen,
+ test_bit(SUSPENDED, &dev->flags),
+ test_bit(TX_HALT, &dev->flags),
+ test_bit(RX_HALT, &dev->flags));
+
+ }
+
+ ret = simple_read_from_buffer(ubuf, count, ppos, buf, temp);
+
+ kfree(buf);
+
+ return ret;
+}
+
+static ssize_t data_bridge_reset_stats(struct file *file,
+ const char __user *buf, size_t count, loff_t *ppos)
+{
+ struct data_bridge *dev;
+ int i;
+
+ for (i = 0; i < ch_id; i++) {
+ dev = __dev[i];
+ if (!dev)
+ continue;
+
+ dev->to_host = 0;
+ dev->to_modem = 0;
+ dev->txurb_drp_cnt = 0;
+ dev->tx_throttled_cnt = 0;
+ dev->tx_unthrottled_cnt = 0;
+ dev->rx_throttled_cnt = 0;
+ dev->rx_unthrottled_cnt = 0;
+ }
+ return count;
+}
+
+const struct file_operations data_stats_ops = {
+ .read = data_bridge_read_stats,
+ .write = data_bridge_reset_stats,
+};
+
+struct dentry *data_dent;
+struct dentry *data_dfile;
+static void data_bridge_debugfs_init(void)
+{
+ data_dent = debugfs_create_dir("data_hsic_bridge", 0);
+ if (IS_ERR(data_dent))
+ return;
+
+ data_dfile = debugfs_create_file("status", 0644, data_dent, 0,
+ &data_stats_ops);
+ if (!data_dfile || IS_ERR(data_dfile))
+ debugfs_remove(data_dent);
+}
+
+static void data_bridge_debugfs_exit(void)
+{
+ debugfs_remove(data_dfile);
+ debugfs_remove(data_dent);
+}
+
+#else
+static void data_bridge_debugfs_init(void) { }
+static void data_bridge_debugfs_exit(void) { }
+#endif
+
+static int __devinit
+bridge_probe(struct usb_interface *iface, const struct usb_device_id *id)
+{
+ struct usb_host_endpoint *endpoint = NULL;
+ struct usb_host_endpoint *bulk_in = NULL;
+ struct usb_host_endpoint *bulk_out = NULL;
+ struct usb_host_endpoint *int_in = NULL;
+ struct usb_device *udev;
+ int i;
+ int status = 0;
+ int numends;
+ int iface_num;
+
+ iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
+
+ if (iface->num_altsetting != 1) {
+ err("%s invalid num_altsetting %u\n",
+ __func__, iface->num_altsetting);
+ return -EINVAL;
+ }
+
+ udev = interface_to_usbdev(iface);
+ usb_get_dev(udev);
+
+ if (iface_num != DUN_IFACE_NUM && iface_num != TETHERED_RMNET_IFACE_NUM)
+ return 0;
+
+ numends = iface->cur_altsetting->desc.bNumEndpoints;
+ for (i = 0; i < numends; i++) {
+ endpoint = iface->cur_altsetting->endpoint + i;
+ if (!endpoint) {
+ dev_err(&udev->dev, "%s: invalid endpoint %u\n",
+ __func__, i);
+ status = -EINVAL;
+ goto out;
+ }
+
+ if (usb_endpoint_is_bulk_in(&endpoint->desc))
+ bulk_in = endpoint;
+ else if (usb_endpoint_is_bulk_out(&endpoint->desc))
+ bulk_out = endpoint;
+ else if (usb_endpoint_is_int_in(&endpoint->desc))
+ int_in = endpoint;
+ }
+
+ if (!bulk_in || !bulk_out || !int_in) {
+ dev_err(&udev->dev, "%s: invalid endpoints\n", __func__);
+ status = -EINVAL;
+ goto out;
+ }
+
+ status = data_bridge_probe(iface, bulk_in, bulk_out, ch_id);
+ if (status < 0) {
+ dev_err(&udev->dev, "data_bridge_probe failed %d\n", status);
+ goto out;
+ }
+
+ status = ctrl_bridge_probe(iface, int_in, ch_id);
+ if (status < 0) {
+ dev_err(&udev->dev, "ctrl_bridge_probe failed %d\n", status);
+ goto free_data_bridge;
+ }
+ ch_id++;
+
+ return 0;
+
+free_data_bridge:
+ platform_device_del(__dev[ch_id]->pdev);
+ usb_set_intfdata(iface, NULL);
+ kfree(__dev[ch_id]);
+ __dev[ch_id] = NULL;
+out:
+ usb_put_dev(udev);
+
+ return status;
+}
+
+static void bridge_disconnect(struct usb_interface *intf)
+{
+ struct data_bridge *dev = usb_get_intfdata(intf);
+ struct list_head *head;
+ struct urb *rx_urb;
+ unsigned long flags;
+ int iface_num;
+
+ if (!dev) {
+ err("%s: data device not found\n", __func__);
+ return;
+ }
+
+ iface_num = intf->cur_altsetting->desc.bInterfaceNumber;
+ if (iface_num != DUN_IFACE_NUM && iface_num != TETHERED_RMNET_IFACE_NUM)
+ return;
+
+ ch_id--;
+ ctrl_bridge_disconnect(ch_id);
+ platform_device_del(dev->pdev);
+ usb_set_intfdata(intf, NULL);
+ __dev[ch_id] = NULL;
+
+ cancel_work_sync(&dev->process_rx_w);
+ cancel_work_sync(&dev->kevent);
+
+ /*free rx urbs*/
+ head = &dev->rx_idle;
+ spin_lock_irqsave(&dev->rx_done.lock, flags);
+ while (!list_empty(head)) {
+ rx_urb = list_entry(head->next, struct urb, urb_list);
+ list_del(&rx_urb->urb_list);
+ usb_free_urb(rx_urb);
+ }
+ spin_unlock_irqrestore(&dev->rx_done.lock, flags);
+
+ usb_put_dev(dev->udev);
+ kfree(dev);
+}
+
+static const struct usb_device_id bridge_ids[] = {
+ { USB_DEVICE(0x5c6, 0x9001) },
+
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, bridge_ids);
+
+static struct usb_driver bridge_driver = {
+ .name = "mdm_bridge",
+ .probe = bridge_probe,
+ .disconnect = bridge_disconnect,
+ .id_table = bridge_ids,
+ .suspend = bridge_suspend,
+ .resume = bridge_resume,
+ .supports_autosuspend = 1,
+};
+
+static int __init bridge_init(void)
+{
+ int ret;
+
+ ret = usb_register(&bridge_driver);
+ if (ret) {
+ err("%s: unable to register mdm_bridge driver", __func__);
+ return ret;
+ }
+
+ bridge_wq = create_singlethread_workqueue("mdm_bridge");
+ if (!bridge_wq) {
+ usb_deregister(&bridge_driver);
+ pr_err("%s: Unable to create workqueue:bridge\n", __func__);
+ return -ENOMEM;
+ }
+
+ data_bridge_debugfs_init();
+
+ return 0;
+}
+
+static void __exit bridge_exit(void)
+{
+ data_bridge_debugfs_exit();
+ destroy_workqueue(bridge_wq);
+ usb_deregister(&bridge_driver);
+}
+
+module_init(bridge_init);
+module_exit(bridge_exit);
+
+MODULE_DESCRIPTION("Qualcomm modem data bridge driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
index 149f3f3..318fb4e 100644
--- a/drivers/usb/musb/cppi_dma.c
+++ b/drivers/usb/musb/cppi_dma.c
@@ -226,8 +226,10 @@
struct cppi *controller;
void __iomem *tibase;
int i;
+ struct musb *musb;
controller = container_of(c, struct cppi, controller);
+ musb = controller->musb;
tibase = controller->tibase;
/* DISABLE INDIVIDUAL CHANNEL Interrupts */
@@ -289,9 +291,11 @@
u8 index;
struct cppi_channel *cppi_ch;
void __iomem *tibase;
+ struct musb *musb;
controller = container_of(c, struct cppi, controller);
tibase = controller->tibase;
+ musb = controller->musb;
/* ep0 doesn't use DMA; remember cppi indices are 0..N-1 */
index = ep->epnum - 1;
@@ -339,7 +343,8 @@
c = container_of(channel, struct cppi_channel, channel);
tibase = c->controller->tibase;
if (!c->hw_ep)
- dev_dbg(musb->controller, "releasing idle DMA channel %p\n", c);
+ dev_dbg(c->controller->musb->controller,
+ "releasing idle DMA channel %p\n", c);
else if (!c->transmit)
core_rxirq_enable(tibase, c->index + 1);
@@ -357,10 +362,11 @@
musb_ep_select(base, c->index + 1);
- DBG(level, "RX DMA%d%s: %d left, csr %04x, "
- "%08x H%08x S%08x C%08x, "
- "B%08x L%08x %08x .. %08x"
- "\n",
+ dev_dbg(c->controller->musb->controller,
+ "RX DMA%d%s: %d left, csr %04x, "
+ "%08x H%08x S%08x C%08x, "
+ "B%08x L%08x %08x .. %08x"
+ "\n",
c->index, tag,
musb_readl(c->controller->tibase,
DAVINCI_RXCPPI_BUFCNT0_REG + 4 * c->index),
@@ -387,10 +393,11 @@
musb_ep_select(base, c->index + 1);
- DBG(level, "TX DMA%d%s: csr %04x, "
- "H%08x S%08x C%08x %08x, "
- "F%08x L%08x .. %08x"
- "\n",
+ dev_dbg(c->controller->musb->controller,
+ "TX DMA%d%s: csr %04x, "
+ "H%08x S%08x C%08x %08x, "
+ "F%08x L%08x .. %08x"
+ "\n",
c->index, tag,
musb_readw(c->hw_ep->regs, MUSB_TXCSR),
@@ -1022,6 +1029,7 @@
int i;
dma_addr_t safe2ack;
void __iomem *regs = rx->hw_ep->regs;
+ struct musb *musb = cppi->musb;
cppi_dump_rx(6, rx, "/K");
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 6aeb363..548338c 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -1698,6 +1698,8 @@
is_on = !!is_on;
+ pm_runtime_get_sync(musb->controller);
+
/* NOTE: this assumes we are sensing vbus; we'd rather
* not pullup unless the B-session is active.
*/
@@ -1707,6 +1709,9 @@
musb_pullup(musb, is_on);
}
spin_unlock_irqrestore(&musb->lock, flags);
+
+ pm_runtime_put(musb->controller);
+
return 0;
}
diff --git a/drivers/usb/otg/msm72k_otg.c b/drivers/usb/otg/msm72k_otg.c
index 714099a..be3a279d 100644
--- a/drivers/usb/otg/msm72k_otg.c
+++ b/drivers/usb/otg/msm72k_otg.c
@@ -1226,11 +1226,17 @@
{
struct msm_otg *dev = the_msm_otg;
- if (!atomic_read(&dev->in_lpm) || !online)
- return;
+ /*
+ * Process disconnect only for wallcharger
+ * during fast plug-out plug-in at the
+ * AC source side.
+ */
+ if (online)
+ set_bit(B_SESS_VLD, &dev->inputs);
+ else
+ clear_bit(B_SESS_VLD, &dev->inputs);
wake_lock(&dev->wlock);
- set_bit(B_SESS_VLD, &dev->inputs);
queue_work(dev->wq, &dev->sm_work);
}
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 1eb8511..ec922f1 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -25,6 +25,8 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/dma-mapping.h>
#include <linux/usb.h>
#include <linux/usb/otg.h>
@@ -37,6 +39,7 @@
#include <linux/mfd/pm8xxx/pm8921-charger.h>
#include <mach/clk.h>
+#include <mach/msm_xo.h>
#define MSM_USB_BASE (motg->regs)
#define DRIVER_NAME "msm_otg"
@@ -504,14 +507,15 @@
return ret;
}
- ulpi_init(motg);
-
ret = msm_otg_link_reset(motg);
if (ret) {
dev_err(otg->dev, "link reset failed\n");
return ret;
}
msleep(100);
+
+ ulpi_init(motg);
+
/* Ensure that RESET operation is completed before turning off clock */
mb();
@@ -565,6 +569,8 @@
struct msm_otg_platform_data *pdata = motg->pdata;
int cnt = 0;
bool session_active;
+ u32 phy_ctrl_val = 0;
+ unsigned ret;
if (atomic_read(&motg->in_lpm))
return 0;
@@ -636,8 +642,13 @@
writel(readl(USB_USBCMD) | ASYNC_INTR_CTRL | ULPI_STP_CTRL, USB_USBCMD);
if (motg->caps & ALLOW_PHY_RETENTION && !session_active) {
- writel_relaxed(readl_relaxed(USB_PHY_CTRL) & ~PHY_RETEN,
- USB_PHY_CTRL);
+ phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
+ if (motg->pdata->otg_control == OTG_PHY_CONTROL)
+ /* Enable PHY HV interrupts to wake MPM/Link */
+ phy_ctrl_val |=
+ (PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
+
+ writel_relaxed(phy_ctrl_val & ~PHY_RETEN, USB_PHY_CTRL);
motg->lpm_flags |= PHY_RETENTIONED;
}
@@ -653,6 +664,12 @@
if (!IS_ERR(motg->pclk_src))
clk_disable(motg->pclk_src);
+ /* usb phy no more require TCXO clock, hence vote for TCXO disable */
+ ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
+ if (ret)
+ dev_err(otg->dev, "%s failed to devote for "
+ "TCXO D0 buffer%d\n", __func__, ret);
+
if (motg->caps & ALLOW_PHY_POWER_COLLAPSE && !session_active) {
msm_hsusb_ldo_enable(motg, 0);
motg->lpm_flags |= PHY_PWR_COLLAPSED;
@@ -686,11 +703,20 @@
struct usb_bus *bus = otg->host;
int cnt = 0;
unsigned temp;
+ u32 phy_ctrl_val = 0;
+ unsigned ret;
if (!atomic_read(&motg->in_lpm))
return 0;
wake_lock(&motg->wlock);
+
+ /* Vote for TCXO when waking up the phy */
+ ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
+ if (ret)
+ dev_err(otg->dev, "%s failed to vote for "
+ "TCXO D0 buffer%d\n", __func__, ret);
+
if (!IS_ERR(motg->pclk_src))
clk_enable(motg->pclk_src);
@@ -709,8 +735,13 @@
if (motg->lpm_flags & PHY_RETENTIONED) {
msm_hsusb_mhl_switch_enable(motg, 1);
msm_hsusb_config_vddcx(1);
- writel_relaxed(readl_relaxed(USB_PHY_CTRL) | PHY_RETEN,
- USB_PHY_CTRL);
+ phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
+ phy_ctrl_val |= PHY_RETEN;
+ if (motg->pdata->otg_control == OTG_PHY_CONTROL)
+ /* Disable PHY HV interrupts */
+ phy_ctrl_val &=
+ ~(PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
+ writel_relaxed(phy_ctrl_val, USB_PHY_CTRL);
motg->lpm_flags &= ~PHY_RETENTIONED;
}
@@ -2031,17 +2062,147 @@
debugfs_remove_recursive(msm_otg_dbg_root);
}
+static u64 msm_otg_dma_mask = DMA_BIT_MASK(64);
+static struct platform_device *msm_otg_add_pdev(
+ struct platform_device *ofdev, const char *name)
+{
+ struct platform_device *pdev;
+ const struct resource *res = ofdev->resource;
+ unsigned int num = ofdev->num_resources;
+ int retval;
+
+ pdev = platform_device_alloc(name, -1);
+ if (!pdev) {
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+ pdev->dev.dma_mask = &msm_otg_dma_mask;
+
+ if (num) {
+ retval = platform_device_add_resources(pdev, res, num);
+ if (retval)
+ goto error;
+ }
+
+ retval = platform_device_add(pdev);
+ if (retval)
+ goto error;
+
+ return pdev;
+
+error:
+ platform_device_put(pdev);
+ return ERR_PTR(retval);
+}
+
+static int msm_otg_setup_devices(struct platform_device *ofdev,
+ enum usb_mode_type mode, bool init)
+{
+ const char *gadget_name = "msm_hsusb";
+ const char *host_name = "msm_hsusb_host";
+ static struct platform_device *gadget_pdev;
+ static struct platform_device *host_pdev;
+ int retval = 0;
+
+ if (!init) {
+ if (gadget_pdev)
+ platform_device_unregister(gadget_pdev);
+ if (host_pdev)
+ platform_device_unregister(host_pdev);
+ return 0;
+ }
+
+ switch (mode) {
+ case USB_OTG:
+ /* fall through */
+ case USB_PERIPHERAL:
+ gadget_pdev = msm_otg_add_pdev(ofdev, gadget_name);
+ if (IS_ERR(gadget_pdev)) {
+ retval = PTR_ERR(gadget_pdev);
+ break;
+ }
+ if (mode == USB_PERIPHERAL)
+ break;
+ /* fall through */
+ case USB_HOST:
+ host_pdev = msm_otg_add_pdev(ofdev, host_name);
+ if (IS_ERR(host_pdev)) {
+ retval = PTR_ERR(host_pdev);
+ if (mode == USB_OTG)
+ platform_device_unregister(gadget_pdev);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return retval;
+}
+
+struct msm_otg_platform_data *msm_otg_dt_to_pdata(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct msm_otg_platform_data *pdata;
+ int len = 0;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ pr_err("unable to allocate platform data\n");
+ return NULL;
+ }
+ of_get_property(node, "qcom,hsusb-otg-phy-init-seq", &len);
+ if (len) {
+ pdata->phy_init_seq = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
+ if (!pdata->phy_init_seq)
+ return NULL;
+ of_property_read_u32_array(node, "qcom,hsusb-otg-phy-init-seq",
+ pdata->phy_init_seq,
+ len/sizeof(*pdata->phy_init_seq));
+ }
+ of_property_read_u32(node, "qcom,hsusb-otg-power-budget",
+ &pdata->power_budget);
+ of_property_read_u32(node, "qcom,hsusb-otg-mode",
+ &pdata->mode);
+ of_property_read_u32(node, "qcom,hsusb-otg-otg-control",
+ &pdata->otg_control);
+ of_property_read_u32(node, "qcom,hsusb-otg-default-mode",
+ &pdata->default_mode);
+ of_property_read_u32(node, "qcom,hsusb-otg-phy-type",
+ &pdata->phy_type);
+ of_property_read_u32(node, "qcom,hsusb-otg-pmic-id-irq",
+ &pdata->pmic_id_irq);
+ of_property_read_string(node, "qcom,hsusb-otg-pclk-src-name",
+ &pdata->pclk_src_name);
+ return pdata;
+}
+
static int __init msm_otg_probe(struct platform_device *pdev)
{
int ret = 0;
struct resource *res;
struct msm_otg *motg;
struct otg_transceiver *otg;
+ struct msm_otg_platform_data *pdata;
dev_info(&pdev->dev, "msm_otg probe\n");
- if (!pdev->dev.platform_data) {
+
+ if (pdev->dev.of_node) {
+ dev_dbg(&pdev->dev, "device tree enabled\n");
+ pdata = msm_otg_dt_to_pdata(pdev);
+ if (!pdata)
+ return -ENOMEM;
+ ret = msm_otg_setup_devices(pdev, pdata->mode, true);
+ if (ret) {
+ dev_err(&pdev->dev, "devices setup failed\n");
+ return ret;
+ }
+ } else if (!pdev->dev.platform_data) {
dev_err(&pdev->dev, "No platform data given. Bailing out\n");
return -ENODEV;
+ } else {
+ pdata = pdev->dev.platform_data;
}
motg = kzalloc(sizeof(struct msm_otg), GFP_KERNEL);
@@ -2051,7 +2212,7 @@
}
the_msm_otg = motg;
- motg->pdata = pdev->dev.platform_data;
+ motg->pdata = pdata;
otg = &motg->otg;
otg->dev = &pdev->dev;
@@ -2138,12 +2299,27 @@
goto free_regs;
}
+ motg->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "usb");
+ if (IS_ERR(motg->xo_handle)) {
+ dev_err(&pdev->dev, "%s not able to get the handle "
+ "to vote for TCXO D0 buffer\n", __func__);
+ ret = PTR_ERR(motg->xo_handle);
+ goto free_regs;
+ }
+
+ ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
+ if (ret) {
+ dev_err(&pdev->dev, "%s failed to vote for TCXO "
+ "D0 buffer%d\n", __func__, ret);
+ goto free_xo_handle;
+ }
+
clk_enable(motg->pclk);
ret = msm_hsusb_init_vddcx(motg, 1);
if (ret) {
dev_err(&pdev->dev, "hsusb vddcx init failed\n");
- goto free_regs;
+ goto devote_xo_handle;
}
ret = msm_hsusb_config_vddcx(1);
@@ -2230,13 +2406,17 @@
if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
pm8921_charger_register_vbus_sn(&msm_otg_set_vbus_state);
- if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
- motg->pdata->otg_control == OTG_PMIC_CONTROL &&
+ if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY) {
+ if (motg->pdata->otg_control == OTG_PMIC_CONTROL &&
motg->pdata->pmic_id_irq)
- motg->caps = ALLOW_PHY_POWER_COLLAPSE |
+ motg->caps = ALLOW_PHY_POWER_COLLAPSE |
ALLOW_PHY_RETENTION |
ALLOW_PHY_COMP_DISABLE;
+ if (motg->pdata->otg_control == OTG_PHY_CONTROL)
+ motg->caps = ALLOW_PHY_RETENTION;
+ }
+
wake_lock(&motg->wlock);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
@@ -2255,6 +2435,10 @@
msm_hsusb_ldo_init(motg, 0);
free_init_vddcx:
msm_hsusb_init_vddcx(motg, 0);
+devote_xo_handle:
+ msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
+free_xo_handle:
+ msm_xo_put(motg->xo_handle);
free_regs:
iounmap(motg->regs);
put_core_clk:
@@ -2289,6 +2473,8 @@
if (otg->host || otg->gadget)
return -EBUSY;
+ if (pdev->dev.of_node)
+ msm_otg_setup_devices(pdev, motg->pdata->mode, false);
if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
pm8921_charger_unregister_vbus_sn(0);
msm_otg_debugfs_cleanup();
@@ -2332,6 +2518,7 @@
clk_disable(motg->pclk_src);
clk_put(motg->pclk_src);
}
+ msm_xo_put(motg->xo_handle);
msm_hsusb_ldo_enable(motg, 0);
msm_hsusb_ldo_init(motg, 0);
msm_hsusb_init_vddcx(motg, 0);
@@ -2428,6 +2615,12 @@
};
#endif
+static struct of_device_id msm_otg_dt_match[] = {
+ { .compatible = "qcom,hsusb-otg",
+ },
+ {}
+};
+
static struct platform_driver msm_otg_driver = {
.remove = __devexit_p(msm_otg_remove),
.driver = {
@@ -2436,6 +2629,7 @@
#ifdef CONFIG_PM
.pm = &msm_otg_dev_pm_ops,
#endif
+ .of_match_table = msm_otg_dt_match,
},
};
diff --git a/drivers/usb/otg/otg-wakelock.c b/drivers/usb/otg/otg-wakelock.c
index 9931626..2f11472 100644
--- a/drivers/usb/otg/otg-wakelock.c
+++ b/drivers/usb/otg/otg-wakelock.c
@@ -21,13 +21,15 @@
#include <linux/spinlock.h>
#include <linux/usb/otg.h>
+#define TEMPORARY_HOLD_TIME 2000
+
static bool enabled = true;
static struct otg_transceiver *otgwl_xceiv;
static struct notifier_block otgwl_nb;
/*
* otgwl_spinlock is held while the VBUS lock is grabbed or dropped and the
- * locked field is updated to match.
+ * held field is updated to match.
*/
static DEFINE_SPINLOCK(otgwl_spinlock);
@@ -39,51 +41,62 @@
struct otgwl_lock {
char name[40];
struct wake_lock wakelock;
- bool locked;
+ bool held;
};
/*
- * VBUS present lock.
+ * VBUS present lock. Also used as a timed lock on charger
+ * connect/disconnect and USB host disconnect, to allow the system
+ * to react to the change in power.
*/
static struct otgwl_lock vbus_lock;
-static void otgwl_grab(struct otgwl_lock *lock)
+static void otgwl_hold(struct otgwl_lock *lock)
{
- if (!lock->locked) {
+ if (!lock->held) {
wake_lock(&lock->wakelock);
- lock->locked = true;
+ lock->held = true;
}
}
+static void otgwl_temporary_hold(struct otgwl_lock *lock)
+{
+ wake_lock_timeout(&lock->wakelock,
+ msecs_to_jiffies(TEMPORARY_HOLD_TIME));
+ lock->held = false;
+}
+
static void otgwl_drop(struct otgwl_lock *lock)
{
- if (lock->locked) {
+ if (lock->held) {
wake_unlock(&lock->wakelock);
- lock->locked = false;
+ lock->held = false;
}
}
-static int otgwl_otg_notifications(struct notifier_block *nb,
- unsigned long event, void *unused)
+static void otgwl_handle_event(unsigned long event)
{
unsigned long irqflags;
- if (!enabled)
- return NOTIFY_OK;
-
spin_lock_irqsave(&otgwl_spinlock, irqflags);
+ if (!enabled) {
+ otgwl_drop(&vbus_lock);
+ spin_unlock_irqrestore(&otgwl_spinlock, irqflags);
+ return;
+ }
+
switch (event) {
case USB_EVENT_VBUS:
case USB_EVENT_ENUMERATED:
- otgwl_grab(&vbus_lock);
+ otgwl_hold(&vbus_lock);
break;
case USB_EVENT_NONE:
case USB_EVENT_ID:
case USB_EVENT_CHARGER:
- otgwl_drop(&vbus_lock);
+ otgwl_temporary_hold(&vbus_lock);
break;
default:
@@ -91,71 +104,25 @@
}
spin_unlock_irqrestore(&otgwl_spinlock, irqflags);
+}
+
+static int otgwl_otg_notifications(struct notifier_block *nb,
+ unsigned long event, void *unused)
+{
+ otgwl_handle_event(event);
return NOTIFY_OK;
}
-static void sync_with_xceiv_state(void)
-{
- if ((otgwl_xceiv->last_event == USB_EVENT_VBUS) ||
- (otgwl_xceiv->last_event == USB_EVENT_ENUMERATED))
- otgwl_grab(&vbus_lock);
- else
- otgwl_drop(&vbus_lock);
-}
-
-static int init_for_xceiv(void)
-{
- int rv;
-
- if (!otgwl_xceiv) {
- otgwl_xceiv = otg_get_transceiver();
-
- if (!otgwl_xceiv) {
- pr_err("%s: No OTG transceiver found\n", __func__);
- return -ENODEV;
- }
-
- snprintf(vbus_lock.name, sizeof(vbus_lock.name), "vbus-%s",
- dev_name(otgwl_xceiv->dev));
- wake_lock_init(&vbus_lock.wakelock, WAKE_LOCK_SUSPEND,
- vbus_lock.name);
-
- rv = otg_register_notifier(otgwl_xceiv, &otgwl_nb);
-
- if (rv) {
- pr_err("%s: otg_register_notifier on transceiver %s"
- " failed\n", __func__,
- dev_name(otgwl_xceiv->dev));
- otgwl_xceiv = NULL;
- wake_lock_destroy(&vbus_lock.wakelock);
- return rv;
- }
- }
-
- return 0;
-}
-
static int set_enabled(const char *val, const struct kernel_param *kp)
{
- unsigned long irqflags;
int rv = param_set_bool(val, kp);
if (rv)
return rv;
- rv = init_for_xceiv();
+ if (otgwl_xceiv)
+ otgwl_handle_event(otgwl_xceiv->last_event);
- if (rv)
- return rv;
-
- spin_lock_irqsave(&otgwl_spinlock, irqflags);
-
- if (enabled)
- sync_with_xceiv_state();
- else
- otgwl_drop(&vbus_lock);
-
- spin_unlock_irqrestore(&otgwl_spinlock, irqflags);
return 0;
}
@@ -169,22 +136,34 @@
static int __init otg_wakelock_init(void)
{
- unsigned long irqflags;
+ int ret;
- otgwl_nb.notifier_call = otgwl_otg_notifications;
+ otgwl_xceiv = otg_get_transceiver();
- if (!init_for_xceiv()) {
- spin_lock_irqsave(&otgwl_spinlock, irqflags);
-
- if (enabled)
- sync_with_xceiv_state();
-
- spin_unlock_irqrestore(&otgwl_spinlock, irqflags);
- } else {
- enabled = false;
+ if (!otgwl_xceiv) {
+ pr_err("%s: No OTG transceiver found\n", __func__);
+ return -ENODEV;
}
- return 0;
+ snprintf(vbus_lock.name, sizeof(vbus_lock.name), "vbus-%s",
+ dev_name(otgwl_xceiv->dev));
+ wake_lock_init(&vbus_lock.wakelock, WAKE_LOCK_SUSPEND,
+ vbus_lock.name);
+
+ otgwl_nb.notifier_call = otgwl_otg_notifications;
+ ret = otg_register_notifier(otgwl_xceiv, &otgwl_nb);
+
+ if (ret) {
+ pr_err("%s: otg_register_notifier on transceiver %s"
+ " failed\n", __func__,
+ dev_name(otgwl_xceiv->dev));
+ otgwl_xceiv = NULL;
+ wake_lock_destroy(&vbus_lock.wakelock);
+ return ret;
+ }
+
+ otgwl_handle_event(otgwl_xceiv->last_event);
+ return ret;
}
late_initcall(otg_wakelock_init);
diff --git a/drivers/usb/otg/otg_id.c b/drivers/usb/otg/otg_id.c
index 64e1bd4..7c38390 100644
--- a/drivers/usb/otg/otg_id.c
+++ b/drivers/usb/otg/otg_id.c
@@ -26,6 +26,8 @@
static struct otg_id_notifier_block *otg_id_active;
static bool otg_id_cancelling;
static bool otg_id_inited;
+static int otg_id_suspended;
+static bool otg_id_pending;
static void otg_id_cancel(void)
{
@@ -139,8 +141,65 @@
if (otg_id_cancelling)
goto out;
- __otg_id_notify();
+ if (otg_id_suspended != 0) {
+ otg_id_pending = true;
+ goto out;
+ }
+ __otg_id_notify();
+out:
+ mutex_unlock(&otg_id_lock);
+}
+
+/**
+ * otg_id_suspend
+ *
+ * Mark the otg_id subsystem as going into suspend. From here on out,
+ * any notifications will be deferred until the last otg_id client resumes.
+ * If there is a pending notification when calling this function, it will
+ * return a negative errno and expects that the caller will abort suspend.
+ * Returs 0 on success.
+ */
+int otg_id_suspend(void)
+{
+ int ret = 0;
+
+ mutex_lock(&otg_id_lock);
+
+ /*
+ * if there's a pending notification, tell the caller to abort suspend
+ */
+ if (otg_id_suspended != 0 && otg_id_pending) {
+ pr_info("otg_id: pending notification, should abort suspend\n");
+ ret = -EBUSY;
+ goto out;
+ }
+
+ otg_id_suspended++;
+out:
+ mutex_unlock(&otg_id_lock);
+ return ret;
+}
+
+/**
+ * otg_id_resume
+ *
+ * Inform the otg_id subsystem that a client is resuming. If this is the
+ * last client to be resumed and there's a pending notification,
+ * otg_id_notify() is called.
+ */
+void otg_id_resume(void)
+{
+ mutex_lock(&otg_id_lock);
+ if (WARN(!otg_id_suspended, "unbalanced otg_id_resume\n"))
+ goto out;
+ if (--otg_id_suspended == 0) {
+ if (otg_id_pending) {
+ pr_info("otg_id: had pending notification\n");
+ otg_id_pending = false;
+ __otg_id_notify();
+ }
+ }
out:
mutex_unlock(&otg_id_lock);
}
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 2e06b90..f968a3d 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -101,6 +101,7 @@
static int ftdi_mtxorb_hack_setup(struct usb_serial *serial);
static int ftdi_NDI_device_setup(struct usb_serial *serial);
static int ftdi_stmclite_probe(struct usb_serial *serial);
+static int ftdi_8u2232c_probe(struct usb_serial *serial);
static void ftdi_USB_UIRT_setup(struct ftdi_private *priv);
static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv);
@@ -128,6 +129,10 @@
.probe = ftdi_stmclite_probe,
};
+static struct ftdi_sio_quirk ftdi_8u2232c_quirk = {
+ .probe = ftdi_8u2232c_probe,
+};
+
/*
* The 8U232AM has the same API as the sio except for:
* - it can support MUCH higher baudrates; up to:
@@ -177,7 +182,8 @@
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_232RL_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) ,
+ .driver_info = (kernel_ulong_t)&ftdi_8u2232c_quirk },
{ USB_DEVICE(FTDI_VID, FTDI_4232H_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_232H_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) },
@@ -1171,7 +1177,7 @@
case FT2232H: /* FT2232H chip */
case FT4232H: /* FT4232H chip */
case FT232H: /* FT232H chip */
- if ((baud <= 12000000) & (baud >= 1200)) {
+ if ((baud <= 12000000) && (baud >= 1200)) {
div_value = ftdi_2232h_baud_to_divisor(baud);
} else if (baud < 1200) {
div_value = ftdi_232bm_baud_to_divisor(baud);
@@ -1733,6 +1739,18 @@
return 0;
}
+static int ftdi_8u2232c_probe(struct usb_serial *serial)
+{
+ struct usb_device *udev = serial->dev;
+
+ dbg("%s", __func__);
+
+ if (strcmp(udev->manufacturer, "CALAO Systems") == 0)
+ return ftdi_jtag_probe(serial);
+
+ return 0;
+}
+
/*
* First and second port on STMCLiteadaptors is reserved for JTAG interface
* and the forth port for pio
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 60b25d8..fe22e90 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -148,6 +148,12 @@
#define HUAWEI_PRODUCT_K4505 0x1464
#define HUAWEI_PRODUCT_K3765 0x1465
#define HUAWEI_PRODUCT_E14AC 0x14AC
+#define HUAWEI_PRODUCT_K3806 0x14AE
+#define HUAWEI_PRODUCT_K4605 0x14C6
+#define HUAWEI_PRODUCT_K3770 0x14C9
+#define HUAWEI_PRODUCT_K3771 0x14CA
+#define HUAWEI_PRODUCT_K4510 0x14CB
+#define HUAWEI_PRODUCT_K4511 0x14CC
#define HUAWEI_PRODUCT_ETS1220 0x1803
#define HUAWEI_PRODUCT_E353 0x1506
@@ -412,6 +418,56 @@
#define SAMSUNG_VENDOR_ID 0x04e8
#define SAMSUNG_PRODUCT_GT_B3730 0x6889
+/* YUGA products www.yuga-info.com*/
+#define YUGA_VENDOR_ID 0x257A
+#define YUGA_PRODUCT_CEM600 0x1601
+#define YUGA_PRODUCT_CEM610 0x1602
+#define YUGA_PRODUCT_CEM500 0x1603
+#define YUGA_PRODUCT_CEM510 0x1604
+#define YUGA_PRODUCT_CEM800 0x1605
+#define YUGA_PRODUCT_CEM900 0x1606
+
+#define YUGA_PRODUCT_CEU818 0x1607
+#define YUGA_PRODUCT_CEU816 0x1608
+#define YUGA_PRODUCT_CEU828 0x1609
+#define YUGA_PRODUCT_CEU826 0x160A
+#define YUGA_PRODUCT_CEU518 0x160B
+#define YUGA_PRODUCT_CEU516 0x160C
+#define YUGA_PRODUCT_CEU528 0x160D
+#define YUGA_PRODUCT_CEU526 0x160F
+
+#define YUGA_PRODUCT_CWM600 0x2601
+#define YUGA_PRODUCT_CWM610 0x2602
+#define YUGA_PRODUCT_CWM500 0x2603
+#define YUGA_PRODUCT_CWM510 0x2604
+#define YUGA_PRODUCT_CWM800 0x2605
+#define YUGA_PRODUCT_CWM900 0x2606
+
+#define YUGA_PRODUCT_CWU718 0x2607
+#define YUGA_PRODUCT_CWU716 0x2608
+#define YUGA_PRODUCT_CWU728 0x2609
+#define YUGA_PRODUCT_CWU726 0x260A
+#define YUGA_PRODUCT_CWU518 0x260B
+#define YUGA_PRODUCT_CWU516 0x260C
+#define YUGA_PRODUCT_CWU528 0x260D
+#define YUGA_PRODUCT_CWU526 0x260F
+
+#define YUGA_PRODUCT_CLM600 0x2601
+#define YUGA_PRODUCT_CLM610 0x2602
+#define YUGA_PRODUCT_CLM500 0x2603
+#define YUGA_PRODUCT_CLM510 0x2604
+#define YUGA_PRODUCT_CLM800 0x2605
+#define YUGA_PRODUCT_CLM900 0x2606
+
+#define YUGA_PRODUCT_CLU718 0x2607
+#define YUGA_PRODUCT_CLU716 0x2608
+#define YUGA_PRODUCT_CLU728 0x2609
+#define YUGA_PRODUCT_CLU726 0x260A
+#define YUGA_PRODUCT_CLU518 0x260B
+#define YUGA_PRODUCT_CLU516 0x260C
+#define YUGA_PRODUCT_CLU528 0x260D
+#define YUGA_PRODUCT_CLU526 0x260F
+
/* some devices interfaces need special handling due to a number of reasons */
enum option_blacklist_reason {
OPTION_BLACKLIST_NONE = 0,
@@ -547,6 +603,16 @@
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ETS1220, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3806, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x31) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x32) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3771, 0xff, 0x02, 0x31) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3771, 0xff, 0x02, 0x32) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4510, 0xff, 0x01, 0x31) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4510, 0xff, 0x01, 0x32) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x31) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x32) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x01) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) },
@@ -993,6 +1059,48 @@
{ USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */
{ USB_DEVICE(ONDA_VENDOR_ID, ONDA_MT825UP) }, /* ONDA MT825UP modem */
{ USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_GT_B3730, USB_CLASS_CDC_DATA, 0x00, 0x00) }, /* Samsung GT-B3730 LTE USB modem.*/
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM600) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM610) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM500) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM510) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM800) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM900) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU818) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU816) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU828) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU826) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU518) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU516) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU528) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU526) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM600) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM610) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM500) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM510) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM800) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM900) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU718) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU716) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU728) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU726) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU518) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU516) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU528) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU526) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM600) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM610) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM500) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM510) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM800) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM900) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU718) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU716) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU728) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU726) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU518) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU516) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU528) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU526) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
@@ -1122,11 +1230,13 @@
serial->interface->cur_altsetting->desc.bInterfaceClass != 0xff)
return -ENODEV;
- /* Don't bind network interfaces on Huawei K3765 & K4505 */
+ /* Don't bind network interfaces on Huawei K3765, K4505 & K4605 */
if (serial->dev->descriptor.idVendor == HUAWEI_VENDOR_ID &&
(serial->dev->descriptor.idProduct == HUAWEI_PRODUCT_K3765 ||
- serial->dev->descriptor.idProduct == HUAWEI_PRODUCT_K4505) &&
- serial->interface->cur_altsetting->desc.bInterfaceNumber == 1)
+ serial->dev->descriptor.idProduct == HUAWEI_PRODUCT_K4505 ||
+ serial->dev->descriptor.idProduct == HUAWEI_PRODUCT_K4605) &&
+ (serial->interface->cur_altsetting->desc.bInterfaceNumber == 1 ||
+ serial->interface->cur_altsetting->desc.bInterfaceNumber == 2))
return -ENODEV;
/* Don't bind network interface on Samsung GT-B3730, it is handled by a separate module */
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 0c20831..1d33260 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -343,10 +343,28 @@
baud = 6000000;
}
dbg("%s - baud set = %d", __func__, baud);
- buf[0] = baud & 0xff;
- buf[1] = (baud >> 8) & 0xff;
- buf[2] = (baud >> 16) & 0xff;
- buf[3] = (baud >> 24) & 0xff;
+ if (baud <= 115200) {
+ buf[0] = baud & 0xff;
+ buf[1] = (baud >> 8) & 0xff;
+ buf[2] = (baud >> 16) & 0xff;
+ buf[3] = (baud >> 24) & 0xff;
+ } else {
+ /* apparently the formula for higher speeds is:
+ * baudrate = 12M * 32 / (2^buf[1]) / buf[0]
+ */
+ unsigned tmp = 12*1000*1000*32 / baud;
+ buf[3] = 0x80;
+ buf[2] = 0;
+ buf[1] = (tmp >= 256);
+ while (tmp >= 256) {
+ tmp >>= 2;
+ buf[1] <<= 1;
+ }
+ if (tmp > 256) {
+ tmp %= 256;
+ }
+ buf[0] = tmp;
+ }
}
/* For reference buf[4]=0 is 1 stop bits */
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index 9788db4..6bc70ba 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -44,6 +44,7 @@
{USB_DEVICE(0x05c6, 0x9203)}, /* Generic Gobi Modem device */
{USB_DEVICE(0x05c6, 0x9222)}, /* Generic Gobi Modem device */
{USB_DEVICE(0x05c6, 0x9008)}, /* Generic Gobi QDL device */
+ {USB_DEVICE(0x05c6, 0x9009)}, /* Generic Gobi Modem device */
{USB_DEVICE(0x05c6, 0x9201)}, /* Generic Gobi QDL device */
{USB_DEVICE(0x05c6, 0x9221)}, /* Generic Gobi QDL device */
{USB_DEVICE(0x05c6, 0x9231)}, /* Generic Gobi QDL device */
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index ccff348..3041a97 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -1988,6 +1988,16 @@
"Micro Mini 1GB",
USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ),
+/*
+ * Nick Bowler <nbowler@elliptictech.com>
+ * SCSI stack spams (otherwise harmless) error messages.
+ */
+UNUSUAL_DEV( 0xc251, 0x4003, 0x0100, 0x0100,
+ "Keil Software, Inc.",
+ "V2M MotherBoard",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_NOT_LOCKABLE),
+
/* Reported by Andrew Simmons <andrew.simmons@gmail.com> */
UNUSUAL_DEV( 0xed06, 0x4500, 0x0001, 0x0001,
"DataStor",
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
index f7bf993..35d1714 100644
--- a/drivers/video/msm/Kconfig
+++ b/drivers/video/msm/Kconfig
@@ -295,11 +295,11 @@
select FB_MSM_MIPI_DSI_SIMULATOR
default n
-config FB_MSM_OVERLAY_WRITEBACK
+config FB_MSM_OVERLAY0_WRITEBACK
depends on FB_MSM_OVERLAY
- bool "MDP overlay write back mode enable"
+ bool "MDP overlay0 write back mode enable"
---help---
- Support for MDP4 OVERLAY write back mode
+ Support for MDP4 OVERLAY0 write back mode
config FB_MSM_WRITEBACK_MSM_PANEL
depends on FB_MSM_OVERLAY
diff --git a/drivers/video/msm/Makefile b/drivers/video/msm/Makefile
index f5a7c9e..dc02da4 100644
--- a/drivers/video/msm/Makefile
+++ b/drivers/video/msm/Makefile
@@ -10,6 +10,7 @@
ifeq ($(CONFIG_FB_MSM_MDP40),y)
obj-y += mdp4_util.o
+obj-y += mdp4_hsic.o
else
obj-y += mdp_hw_init.o
obj-y += mdp_ppp.o
diff --git a/drivers/video/msm/external_common.c b/drivers/video/msm/external_common.c
index 1d87de6..5d9795a 100644
--- a/drivers/video/msm/external_common.c
+++ b/drivers/video/msm/external_common.c
@@ -18,7 +18,6 @@
/* #define DEBUG */
#define DEV_DBG_PREFIX "EXT_COMMON: "
-/* #define CEC_COMPLIANCE_TESTING */
#include "msm_fb.h"
#include "hdmi_msm.h"
#include "external_common.h"
@@ -370,7 +369,7 @@
struct device_attribute *attr, const char *buf, size_t count)
{
-#ifdef CEC_COMPLIANCE_TESTING
+#ifdef DRVR_ONLY_CECT_NO_DAEMON
/*
* Only for testing
*/
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index 4b34969..0f1d19b 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -16,7 +16,7 @@
/* #define REG_DUMP */
#define CEC_MSG_PRINT
-/* #define CEC_COMPLIANCE_TESTING */
+#define TOGGLE_CEC_HARDWARE_FSM
#include <linux/types.h>
#include <linux/bitops.h>
@@ -49,6 +49,14 @@
#define MSM_HDMI_SAMPLE_RATE_MAX 7
#define MSM_HDMI_SAMPLE_RATE_FORCE_32BIT 0x7FFFFFFF
+static int msm_hdmi_sample_rate = MSM_HDMI_SAMPLE_RATE_48KHZ;
+
+/* HDMI/HDCP Registers */
+#define HDCP_DDC_STATUS 0x0128
+#define HDCP_DDC_CTRL_0 0x0120
+#define HDCP_DDC_CTRL_1 0x0124
+#define HDMI_DDC_CTRL 0x020C
+
struct workqueue_struct *hdmi_work_queue;
struct hdmi_msm_state_type *hdmi_msm_state;
@@ -69,6 +77,11 @@
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT
+#ifdef TOGGLE_CEC_HARDWARE_FSM
+static boolean msg_send_complete = TRUE;
+static boolean msg_recv_complete = TRUE;
+#endif
+
#define HDMI_MSM_CEC_REFTIMER_REFTIMER_ENABLE BIT(16)
#define HDMI_MSM_CEC_REFTIMER_REFTIMER(___t) (((___t)&0xFFFF) << 0)
@@ -97,10 +110,9 @@
#define HDMI_MSM_CEC_INT_FRAME_WR_DONE_INT BIT(0)
#define HDMI_MSM_CEC_FRAME_WR_SUCCESS(___st) (((___st)&0xF) ==\
- (HDMI_MSM_CEC_INT_FRAME_WR_DONE_INT &&\
- HDMI_MSM_CEC_INT_FRAME_WR_DONE_MASK &&\
- (HDMI_MSM_CEC_INT_FRAME_ERROR_MASK &&\
- !(HDMI_MSM_CEC_INT_FRAME_ERROR_INT))))
+ (HDMI_MSM_CEC_INT_FRAME_WR_DONE_INT |\
+ HDMI_MSM_CEC_INT_FRAME_WR_DONE_MASK |\
+ HDMI_MSM_CEC_INT_FRAME_ERROR_MASK))
#define HDMI_MSM_CEC_RETRANSMIT_NUM(___num) (((___num)&0xF) << 4)
#define HDMI_MSM_CEC_RETRANSMIT_ENABLE BIT(0)
@@ -193,6 +205,10 @@
boolean frameType = (msg->recvr_id == 15 ? BIT(0) : 0);
+#ifdef TOGGLE_CEC_HARDWARE_FSM
+ msg_send_complete = FALSE;
+#endif
+
INIT_COMPLETION(hdmi_msm_state->cec_frame_wr_done);
hdmi_msm_state->cec_frame_wr_status = 0;
@@ -251,13 +267,23 @@
msg->frame_size);
hdmi_msm_dump_cec_msg(msg);
}
+
+#ifdef TOGGLE_CEC_HARDWARE_FSM
+ if (!msg_recv_complete) {
+ /* Toggle CEC hardware FSM */
+ HDMI_OUTP(0x028C, 0x0);
+ HDMI_OUTP(0x028C, HDMI_MSM_CEC_CTRL_ENABLE);
+ msg_recv_complete = TRUE;
+ }
+ msg_send_complete = TRUE;
+#endif
}
void hdmi_msm_cec_msg_recv(void)
{
uint32 data;
int i;
-#ifdef CEC_COMPLIANCE_TESTING
+#ifdef DRVR_ONLY_CECT_NO_DAEMON
struct hdmi_msm_cec_msg temp_msg;
#endif
mutex_lock(&hdmi_msm_state_mutex);
@@ -265,7 +291,7 @@
&& hdmi_msm_state->cec_queue_full) {
mutex_unlock(&hdmi_msm_state_mutex);
DEV_ERR("CEC message queue is overflowing\n");
-#ifdef CEC_COMPLIANCE_TESTING
+#ifdef DRVR_ONLY_CECT_NO_DAEMON
/*
* Without CEC daemon:
* Compliance tests fail once the queue gets filled up.
@@ -325,7 +351,7 @@
hdmi_msm_dump_cec_msg(hdmi_msm_state->cec_queue_wr);
DEV_DBG("=======================================\n");
-#ifdef CEC_COMPLIANCE_TESTING
+#ifdef DRVR_ONLY_CECT_NO_DAEMON
switch (hdmi_msm_state->cec_queue_wr->opcode) {
case 0x64:
/* Set OSD String */
@@ -490,7 +516,7 @@
#endif /* __SEND_ABORT__ */
}
-#endif /* CEC_COMPLIANCE_TESTING */
+#endif /* DRVR_ONLY_CECT_NO_DAEMON */
mutex_lock(&hdmi_msm_state_mutex);
hdmi_msm_state->cec_queue_wr++;
if (hdmi_msm_state->cec_queue_wr == CEC_QUEUE_END)
@@ -1052,6 +1078,8 @@
DEV_DBG("calling reauthenticate from %s HDCP FAIL INT ",
__func__);
+ /* Clear AUTH_FAIL_INFO as well */
+ HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 7)));
return IRQ_HANDLED;
}
/* [8] DDC_XFER_REQ_INT [R] HDCP DDC Transfer Request
@@ -1099,9 +1127,11 @@
}
if ((cec_intr_status & (1 << 2)) && (cec_intr_status & (1 << 3))) {
DEV_DBG("CEC_IRQ_FRAME_ERROR\n");
+#ifdef TOGGLE_CEC_HARDWARE_FSM
/* Toggle CEC hardware FSM */
HDMI_OUTP(0x028C, 0x0);
HDMI_OUTP(0x028C, HDMI_MSM_CEC_CTRL_ENABLE);
+#endif
HDMI_OUTP(0x029C, cec_intr_status);
mutex_lock(&hdmi_msm_state_mutex);
hdmi_msm_state->cec_frame_wr_status |= CEC_STATUS_WR_ERROR;
@@ -1119,9 +1149,15 @@
HDMI_MSM_CEC_INT_FRAME_RD_DONE_ACK);
hdmi_msm_cec_msg_recv();
- /* Toggle CEC hardware FSM */
- HDMI_OUTP(0x028C, 0x0);
- HDMI_OUTP(0x028C, HDMI_MSM_CEC_CTRL_ENABLE);
+#ifdef TOGGLE_CEC_HARDWARE_FSM
+ if (!msg_send_complete)
+ msg_recv_complete = FALSE;
+ else {
+ /* Toggle CEC hardware FSM */
+ HDMI_OUTP(0x028C, 0x0);
+ HDMI_OUTP(0x028C, HDMI_MSM_CEC_CTRL_ENABLE);
+ }
+#endif
return IRQ_HANDLED;
}
@@ -1947,13 +1983,14 @@
* Read HDMI_I2C_DATA with the following fields set
* RW = 0x1 (read)
* DATA = BCAPS (this is field where data is pulled from)
- * INDEX = 0x3 (where the data has been placed in buffer by hardware)
+ * INDEX = 0x5 (where the data has been placed in buffer by hardware)
* INDEX_WRITE = 0x1 (explicitly define offset) */
/* Write this data to DDC buffer */
- HDMI_OUTP_ND(0x0238, 0x1 | (3 << 16) | (1 << 31));
+ HDMI_OUTP_ND(0x0238, 0x1 | (5 << 16) | (1 << 31));
/* Discard first byte */
HDMI_INP_ND(0x0238);
+
for (ndx = 0; ndx < data_len; ++ndx) {
reg_val = HDMI_INP_ND(0x0238);
data_buf[ndx] = (uint8) ((reg_val & 0x0000FF00) >> 8);
@@ -2127,8 +2164,109 @@
if (hdcp_link_status & 0x00000004)
hdcp_auth_info((hdcp_link_status & 0x000000F0) >> 4);
+
+ /* Disable HDCP interrupts */
+ HDMI_OUTP(0x0118, 0x0);
}
+static void check_and_clear_HDCP_DDC_Failure(void)
+{
+ int hdcp_ddc_ctrl1_reg;
+ int hdcp_ddc_status;
+ int failure;
+ int nack0;
+
+ /*
+ * Check for any DDC transfer failures
+ * 0x0128 HDCP_DDC_STATUS
+ * [16] FAILED Indicates that the last HDCP HW DDC transer
+ * failed. This occurs when a transfer is
+ * attempted with HDCP DDC disabled
+ * (HDCP_DDC_DISABLE=1) or the number of retries
+ * match HDCP_DDC_RETRY_CNT
+ *
+ * [14] NACK0 Indicates that the last HDCP HW DDC transfer
+ * was aborted due to a NACK on the first
+ * transaction - cleared by writing 0 to GO bit
+ */
+ hdcp_ddc_status = HDMI_INP(HDCP_DDC_STATUS);
+ failure = (hdcp_ddc_status >> 16) & 0x1;
+ nack0 = (hdcp_ddc_status >> 14) & 0x1;
+ DEV_DBG("%s: On Entry: HDCP_DDC_STATUS = 0x%x, FAILURE = %d,"
+ "NACK0 = %d\n", __func__ , hdcp_ddc_status, failure, nack0);
+
+ if (failure == 0x1) {
+ /*
+ * Indicates that the last HDCP HW DDC transfer failed.
+ * This occurs when a transfer is attempted with HDCP DDC
+ * disabled (HDCP_DDC_DISABLE=1) or the number of retries
+ * matches HDCP_DDC_RETRY_CNT.
+ * Failure occured, let's clear it.
+ */
+ DEV_INFO("%s: DDC failure detected. HDCP_DDC_STATUS=0x%08x\n",
+ __func__, hdcp_ddc_status);
+ /*
+ * First, Disable DDC
+ * 0x0120 HDCP_DDC_CTRL_0
+ * [0] DDC_DISABLE Determines whether HDCP Ri and Pj reads
+ * are done unassisted by hardware or by
+ * software via HDMI_DDC (HDCP provides
+ * interrupts to request software
+ * transfers)
+ * 0 : Use Hardware DDC
+ * 1 : Use Software DDC
+ */
+ HDMI_OUTP(HDCP_DDC_CTRL_0, 0x1);
+
+ /*
+ * ACK the Failure to Clear it
+ * 0x0124 HDCP_DDC_CTRL_1
+ * [0] DDC_FAILED_ACK Write 1 to clear
+ * HDCP_STATUS.HDCP_DDC_FAILED
+ */
+ hdcp_ddc_ctrl1_reg = HDMI_INP(HDCP_DDC_CTRL_1);
+ HDMI_OUTP(HDCP_DDC_CTRL_1, hdcp_ddc_ctrl1_reg | 0x1);
+
+ /* Check if the FAILURE got Cleared */
+ hdcp_ddc_status = HDMI_INP(HDCP_DDC_STATUS);
+ hdcp_ddc_status = (hdcp_ddc_status >> 16) & 0x1;
+ if (hdcp_ddc_status == 0x0) {
+ DEV_INFO("%s: HDCP DDC Failure has been cleared\n",
+ __func__);
+ } else {
+ DEV_WARN("%s: Error: HDCP DDC Failure DID NOT get"
+ "cleared\n", __func__);
+ }
+
+ /* Re-Enable HDCP DDC */
+ HDMI_OUTP(HDCP_DDC_CTRL_0, 0x0);
+ }
+
+ if (nack0 == 0x1) {
+ /*
+ * 0x020C HDMI_DDC_CTRL
+ * [3] SW_STATUS_RESET Write 1 to reset HDMI_DDC_SW_STATUS
+ * flags, will reset SW_DONE, ABORTED,
+ * TIMEOUT, SW_INTERRUPTED,
+ * BUFFER_OVERFLOW, STOPPED_ON_NACK, NACK0,
+ * NACK1, NACK2, NACK3
+ */
+ HDMI_OUTP_ND(HDMI_DDC_CTRL,
+ HDMI_INP(HDMI_DDC_CTRL) | (0x1 << 3));
+ msleep(20);
+ HDMI_OUTP_ND(HDMI_DDC_CTRL,
+ HDMI_INP(HDMI_DDC_CTRL) & ~(0x1 << 3));
+ }
+
+ hdcp_ddc_status = HDMI_INP(HDCP_DDC_STATUS);
+
+ failure = (hdcp_ddc_status >> 16) & 0x1;
+ nack0 = (hdcp_ddc_status >> 14) & 0x1;
+ DEV_DBG("%s: On Exit: HDCP_DDC_STATUS = 0x%x, FAILURE = %d,"
+ "NACK0 = %d\n", __func__ , hdcp_ddc_status, failure, nack0);
+}
+
+
static int hdcp_authentication_part1(void)
{
int ret = 0;
@@ -2246,6 +2384,12 @@
/* encryption_enable | enable */
HDMI_OUTP(0x0110, (1 << 8) | (1 << 0));
+ /*
+ * Check to see if a HDCP DDC Failure is indicated in
+ * HDCP_DDC_STATUS. If yes, clear it.
+ */
+ check_and_clear_HDCP_DDC_Failure();
+
/* 0x0118 HDCP_INT_CTRL
* [2] AUTH_SUCCESS_MASK [R/W] Mask bit for\
* HDCP Authentication
@@ -2285,6 +2429,12 @@
goto error;
}
+ /*
+ * A small delay is needed here to avoid device crash observed
+ * during reauthentication in MSM8960
+ */
+ msleep(20);
+
/* 0x0168 HDCP_RCVPORT_DATA12
[23:8] BSTATUS
[7:0] BCAPS */
@@ -2644,7 +2794,30 @@
for (i = 0; i < ksv_bytes - 1; i++) {
/* Write KSV byte and do not set DONE bit[0] */
HDMI_OUTP_ND(0x0244, kvs_fifo[i] << 16);
+
+ /* Once 64 bytes have been written, we need to poll for
+ * HDCP_SHA_BLOCK_DONE before writing any further
+ */
+ if (i && !((i+1)%64)) {
+ timeout_count = 100;
+ while (!(HDMI_INP_ND(0x0240) & 0x1)
+ && (--timeout_count)) {
+ DEV_DBG("HDCP Auth Part II: Waiting for the "
+ "computation of the current 64 byte to "
+ "complete. HDCP_SHA_STATUS=%08x. "
+ "timeout_count=%d\n",
+ HDMI_INP_ND(0x0240), timeout_count);
+ msleep(20);
+ }
+ if (!timeout_count) {
+ ret = -ETIMEDOUT;
+ DEV_ERR("%s(%d): timedout", __func__, __LINE__);
+ goto error;
+ }
+ }
+
}
+
/* Write l to DONE bit[0] */
HDMI_OUTP_ND(0x0244, (kvs_fifo[ksv_bytes - 1] << 16) | 0x1);
@@ -2652,8 +2825,9 @@
[4] COMP_DONE */
/* Now wait for HDCP_SHA_COMP_DONE */
timeout_count = 100;
- while ((0x10 != (HDMI_INP_ND(0x0240) & 0x10)) && timeout_count--)
+ while ((0x10 != (HDMI_INP_ND(0x0240) & 0xFFFFFF10)) && --timeout_count)
msleep(20);
+
if (!timeout_count) {
ret = -ETIMEDOUT;
DEV_ERR("%s(%d): timedout", __func__, __LINE__);
@@ -2664,8 +2838,10 @@
[20] V_MATCHES */
timeout_count = 100;
while (((HDMI_INP_ND(0x011C) & (1 << 20)) != (1 << 20))
- && timeout_count--)
+ && --timeout_count) {
msleep(20);
+ }
+
if (!timeout_count) {
ret = -ETIMEDOUT;
DEV_ERR("%s(%d): timedout", __func__, __LINE__);
@@ -3305,6 +3481,23 @@
}
#endif
+int hdmi_msm_audio_get_sample_rate(void)
+{
+ return msm_hdmi_sample_rate;
+}
+EXPORT_SYMBOL(hdmi_msm_audio_get_sample_rate);
+
+void hdmi_msm_audio_sample_rate_reset(int rate)
+{
+ msm_hdmi_sample_rate = rate;
+
+ if (hdmi_msm_has_hdcp())
+ hdcp_deauthenticate();
+ else
+ hdmi_msm_turn_on();
+}
+EXPORT_SYMBOL(hdmi_msm_audio_sample_rate_reset);
+
static void hdmi_msm_audio_setup(void)
{
const int channels = MSM_HDMI_AUDIO_CHANNEL_2;
@@ -3318,11 +3511,9 @@
DEV_DBG("Not setting ACP, ISRC1, ISRC2 packets\n");
hdmi_msm_audio_acr_setup(TRUE,
external_common_state->video_resolution,
- MSM_HDMI_SAMPLE_RATE_48KHZ, channels);
+ msm_hdmi_sample_rate, channels);
hdmi_msm_audio_info_setup(TRUE, channels, 0, FALSE);
- hdmi_msm_audio_ctrl_setup(FALSE, 1);
-
/* Turn on Audio FIFO and SAM DROP ISR */
HDMI_OUTP(0x02CC, HDMI_INP(0x02CC) | BIT(1) | BIT(3));
DEV_INFO("HDMI Audio: Enabled\n");
@@ -3360,35 +3551,35 @@
}
-static uint8 hdmi_msm_avi_iframe_lut[][15] = {
-/* 480p60 480i60 576p50 576i50 720p60 720p50 1080p60 1080i60 1080p50
- 1080i50 1080p24 1080p30 1080p25 640x480p 480p60_16_9*/
- {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
- 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, /*00*/
- {0x18, 0x18, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0x18, 0x28}, /*01*/
- {0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
- 0x04, 0x04, 0x04, 0x04, 0x88, 0x04}, /*02*/
- {0x02, 0x06, 0x11, 0x15, 0x04, 0x13, 0x10, 0x05, 0x1F,
- 0x14, 0x20, 0x22, 0x21, 0x01, 0x03}, /*03*/
- {0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*04*/
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*05*/
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*06*/
- {0xE1, 0xE1, 0x41, 0x41, 0xD1, 0xd1, 0x39, 0x39, 0x39,
- 0x39, 0x39, 0x39, 0x39, 0xe1, 0xE1}, /*07*/
- {0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04,
- 0x04, 0x04, 0x04, 0x04, 0x01, 0x01}, /*08*/
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*09*/
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*10*/
- {0xD1, 0xD1, 0xD1, 0xD1, 0x01, 0x01, 0x81, 0x81, 0x81,
- 0x81, 0x81, 0x81, 0x81, 0x81, 0xD1}, /*11*/
- {0x02, 0x02, 0x02, 0x02, 0x05, 0x05, 0x07, 0x07, 0x07,
- 0x07, 0x07, 0x07, 0x07, 0x02, 0x02} /*12*/
+static uint8 hdmi_msm_avi_iframe_lut[][16] = {
+/* 480p60 480i60 576p50 576i50 720p60 720p50 1080p60 1080i60 1080p50
+ 1080i50 1080p24 1080p30 1080p25 640x480p 480p60_16_9 576p50_4_3 */
+ {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, /*00*/
+ {0x18, 0x18, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x18, 0x28, 0x18}, /*01*/
+ {0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x88, 0x04, 0x04}, /*02*/
+ {0x02, 0x06, 0x11, 0x15, 0x04, 0x13, 0x10, 0x05, 0x1F,
+ 0x14, 0x20, 0x22, 0x21, 0x01, 0x03, 0x11}, /*03*/
+ {0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*04*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*05*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*06*/
+ {0xE1, 0xE1, 0x41, 0x41, 0xD1, 0xd1, 0x39, 0x39, 0x39,
+ 0x39, 0x39, 0x39, 0x39, 0xe1, 0xE1, 0x41}, /*07*/
+ {0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x01, 0x01, 0x02}, /*08*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*09*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*10*/
+ {0xD1, 0xD1, 0xD1, 0xD1, 0x01, 0x01, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0xD1, 0xD1}, /*11*/
+ {0x02, 0x02, 0x02, 0x02, 0x05, 0x05, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x02, 0x02, 0x02} /*12*/
};
static void hdmi_msm_avi_info_frame(void)
@@ -3447,6 +3638,9 @@
case HDMI_VFRMT_720x480p60_16_9:
mode = 14;
break;
+ case HDMI_VFRMT_720x576p50_4_3:
+ mode = 15;
+ break;
default:
DEV_INFO("%s: mode %d not supported\n", __func__,
external_common_state->video_resolution);
@@ -3655,7 +3849,27 @@
static void hdmi_msm_turn_on(void)
{
uint32 hpd_ctrl;
+ uint32 audio_pkt_ctrl, audio_cfg;
+ /*
+ * Number of wait iterations for QDSP to disable Audio Engine
+ * before resetting HDMI core
+ */
+ int i = 10;
+ audio_pkt_ctrl = HDMI_INP_ND(0x0020);
+ audio_cfg = HDMI_INP_ND(0x01D0);
+ /*
+ * Checking BIT[0] of AUDIO PACKET CONTROL and
+ * AUDIO CONFIGURATION register
+ */
+ while (((audio_pkt_ctrl & 0x00000001) || (audio_cfg & 0x00000001))
+ && (i--)) {
+ audio_pkt_ctrl = HDMI_INP_ND(0x0020);
+ audio_cfg = HDMI_INP_ND(0x01D0);
+ DEV_DBG("%d times :: HDMI AUDIO PACKET is %08x and "
+ "AUDIO CFG is %08x", i, audio_pkt_ctrl, audio_cfg);
+ msleep(20);
+ }
hdmi_msm_reset_core();
hdmi_msm_init_phy(external_common_state->video_resolution);
/* HDMI_USEC_REFTIMER[0x0208] */
@@ -4245,6 +4459,9 @@
{
int rc;
+ if (cpu_is_msm8627())
+ return 0;
+
if (msm_fb_detect_client("hdmi_msm"))
return 0;
diff --git a/drivers/video/msm/lcdc.c b/drivers/video/msm/lcdc.c
index cf8a5ff..135bf68 100644
--- a/drivers/video/msm/lcdc.c
+++ b/drivers/video/msm/lcdc.c
@@ -29,7 +29,6 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
-#include <mach/clk.h>
#include "msm_fb.h"
@@ -78,7 +77,7 @@
#ifndef CONFIG_MSM_BUS_SCALING
if (mfd->ebi1_clk) {
if (mdp_rev == MDP_REV_303) {
- if (clk_set_min_rate(mfd->ebi1_clk, 0))
+ if (clk_set_rate(mfd->ebi1_clk, 0))
pr_err("%s: ebi1_lcdc_clk set rate failed\n",
__func__);
}
@@ -117,7 +116,7 @@
if (mfd->ebi1_clk) {
if (mdp_rev == MDP_REV_303) {
- if (clk_set_min_rate(mfd->ebi1_clk, 65000000))
+ if (clk_set_rate(mfd->ebi1_clk, 65000000))
pr_err("%s: ebi1_lcdc_clk set rate failed\n",
__func__);
} else {
diff --git a/drivers/video/msm/mddi.c b/drivers/video/msm/mddi.c
index 9b9ee94..c6f9fb2 100644
--- a/drivers/video/msm/mddi.c
+++ b/drivers/video/msm/mddi.c
@@ -241,7 +241,8 @@
#ifdef ENABLE_FWD_LINK_SKEW_CALIBRATION
if (mddi_client_type < 2) {
/* For skew calibration, clock should be less than 50MHz */
- if (!clk_set_min_rate(mddi_clk, 49000000)) {
+ clk_rate = clk_round_rate(mddi_clk, 49000000);
+ if (!clk_set_rate(mddi_clk, clk_rate)) {
stat_reg = mddi_host_reg_in(STAT);
printk(KERN_DEBUG "\n stat_reg = 0x%x", stat_reg);
mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE);
@@ -253,7 +254,7 @@
mddi_host_reg_out(CMD, MDDI_CMD_SEND_RTD);
mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE | 1);
} else {
- printk(KERN_ERR "%s: clk_set_min_rate failed\n",
+ printk(KERN_ERR "%s: clk_set_rate failed\n",
__func__);
}
}
@@ -269,8 +270,9 @@
"%s: can't select mddi io clk targate rate = %d\n",
__func__, clk_rate);
- if (clk_set_min_rate(mddi_clk, clk_rate) < 0)
- printk(KERN_ERR "%s: clk_set_min_rate failed\n",
+ clk_rate = clk_round_rate(mddi_clk, clk_rate);
+ if (clk_set_rate(mddi_clk, clk_rate) < 0)
+ printk(KERN_ERR "%s: clk_set_rate failed\n",
__func__);
#ifdef CONFIG_MSM_BUS_SCALING
@@ -449,9 +451,6 @@
mddi_pad_ctrl = mddi_host_reg_in(PAD_CTL);
mddi_host_reg_out(PAD_CTL, 0x0);
- if (clk_set_min_rate(mddi_clk, 0) < 0)
- printk(KERN_ERR "%s: clk_set_min_rate failed\n", __func__);
-
pmdh_clk_disable();
if (mddi_pdata && mddi_pdata->mddi_power_save)
@@ -477,9 +476,6 @@
mddi_pad_ctrl = mddi_host_reg_in(PAD_CTL);
mddi_host_reg_out(PAD_CTL, 0x0);
- if (clk_set_min_rate(mddi_clk, 0) < 0)
- printk(KERN_ERR "%s: clk_set_min_rate failed\n", __func__);
-
pmdh_clk_disable();
return 0;
@@ -551,6 +547,7 @@
static int __init mddi_driver_init(void)
{
int ret;
+ unsigned long rate;
pmdh_clk_status = 0;
mddi_clk = clk_get(NULL, "mddi_clk");
@@ -558,9 +555,10 @@
printk(KERN_ERR "can't find mddi_clk\n");
return PTR_ERR(mddi_clk);
}
- ret = clk_set_min_rate(mddi_clk, 49000000);
+ rate = clk_round_rate(mddi_clk, 49000000);
+ ret = clk_set_rate(mddi_clk, rate);
if (ret)
- printk(KERN_ERR "Can't set mddi_clk min rate to 49000000\n");
+ printk(KERN_ERR "Can't set mddi_clk min rate to %lu\n", rate);
printk(KERN_INFO "mddi_clk init rate is %lu\n",
clk_get_rate(mddi_clk));
diff --git a/drivers/video/msm/mddi_ext.c b/drivers/video/msm/mddi_ext.c
index 0ecd593..677b46c 100644
--- a/drivers/video/msm/mddi_ext.c
+++ b/drivers/video/msm/mddi_ext.c
@@ -126,8 +126,9 @@
"%s: can't select mddi io clk targate rate = %d\n",
__func__, clk_rate);
- if (clk_set_min_rate(mddi_ext_clk, clk_rate) < 0)
- printk(KERN_ERR "%s: clk_set_min_rate failed\n",
+ clk_rate = clk_round_rate(mddi_ext_clk, clk_rate);
+ if (clk_set_rate(mddi_ext_clk, clk_rate) < 0)
+ printk(KERN_ERR "%s: clk_set_rate failed\n",
__func__);
mddi_host_start_ext_display();
@@ -265,9 +266,6 @@
mddi_ext_is_in_suspend = 1;
- if (clk_set_min_rate(mddi_ext_clk, 0) < 0)
- printk(KERN_ERR "%s: clk_set_min_rate failed\n", __func__);
-
clk_disable(mddi_ext_clk);
if (mddi_ext_pclk)
clk_disable(mddi_ext_pclk);
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index aeeb503..462ede1 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -237,8 +237,10 @@
static boolean mdp_is_hist_start = FALSE;
#endif
static DEFINE_MUTEX(mdp_hist_mutex);
+static boolean mdp_is_hist_data = FALSE;
-int mdp_histogram_ctrl(boolean en)
+/*should hold mdp_hist_mutex before calling this function*/
+int _mdp_histogram_ctrl(boolean en)
{
unsigned long flag;
unsigned long hist_base;
@@ -250,6 +252,9 @@
hist_base = 0x94000;
if (en == TRUE) {
+ if (mdp_is_hist_start)
+ return -EINVAL;
+
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
mdp_hist_frame_cnt = 1;
mdp_enable_irq(MDP_HISTOGRAM_TERM);
@@ -262,7 +267,14 @@
MDP_OUTP(MDP_BASE + hist_base + 0x4, mdp_hist_frame_cnt);
MDP_OUTP(MDP_BASE + hist_base, 1);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ mdp_is_hist_data = TRUE;
} else {
+ if (!mdp_is_hist_start && !mdp_is_hist_data)
+ return -EINVAL;
+
+ mdp_is_hist_data = FALSE;
+ complete(&mdp_hist_comp);
+
if (mdp_rev >= MDP_REV_40) {
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
status = inpdw(MDP_BASE + hist_base + 0x1C);
@@ -280,6 +292,15 @@
return 0;
}
+int mdp_histogram_ctrl(boolean en)
+{
+ int ret = 0;
+ mutex_lock(&mdp_hist_mutex);
+ ret = _mdp_histogram_ctrl(en);
+ mutex_unlock(&mdp_hist_mutex);
+ return ret;
+}
+
int mdp_start_histogram(struct fb_info *info)
{
unsigned long flag;
@@ -292,7 +313,7 @@
goto mdp_hist_start_err;
}
- ret = mdp_histogram_ctrl(TRUE);
+ ret = _mdp_histogram_ctrl(TRUE);
spin_lock_irqsave(&mdp_spin_lock, flag);
mdp_is_hist_start = TRUE;
@@ -319,21 +340,21 @@
mdp_is_hist_start = FALSE;
spin_unlock_irqrestore(&mdp_spin_lock, flag);
- ret = mdp_histogram_ctrl(FALSE);
+ ret = _mdp_histogram_ctrl(FALSE);
mdp_hist_stop_err:
mutex_unlock(&mdp_hist_mutex);
return ret;
}
-static int mdp_copy_hist_data(struct mdp_histogram *hist)
+/*call from within mdp_hist_mutex*/
+static int _mdp_copy_hist_data(struct mdp_histogram *hist)
{
char *mdp_hist_base;
uint32 r_data_offset = 0x100, g_data_offset = 0x200;
uint32 b_data_offset = 0x300;
int ret = 0;
- mutex_lock(&mdp_hist_mutex);
if (mdp_rev >= MDP_REV_42) {
mdp_hist_base = MDP_BASE + 0x95000;
r_data_offset = 0x400;
@@ -374,7 +395,6 @@
MDP_OUTP(mdp_hist_base, 1);
}
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
- mutex_unlock(&mdp_hist_mutex);
return 0;
hist_err:
@@ -384,6 +404,8 @@
static int mdp_do_histogram(struct fb_info *info, struct mdp_histogram *hist)
{
+ int ret = 0;
+
if (!hist->frame_cnt || (hist->bin_cnt == 0))
return -EINVAL;
@@ -393,18 +415,29 @@
return -EINVAL;
mutex_lock(&mdp_hist_mutex);
+ if (!mdp_is_hist_data) {
+ ret = -EINVAL;
+ goto error;
+ }
+
if (!mdp_is_hist_start) {
printk(KERN_ERR "%s histogram not started\n", __func__);
- mutex_unlock(&mdp_hist_mutex);
- return -EPERM;
+ ret = -EPERM;
+ goto error;
}
- mutex_unlock(&mdp_hist_mutex);
INIT_COMPLETION(mdp_hist_comp);
mdp_hist_frame_cnt = hist->frame_cnt;
+ mutex_unlock(&mdp_hist_mutex);
+
wait_for_completion_killable(&mdp_hist_comp);
- return mdp_copy_hist_data(hist);
+ mutex_lock(&mdp_hist_mutex);
+ if (mdp_is_hist_data)
+ ret = _mdp_copy_hist_data(hist);
+error:
+ mutex_unlock(&mdp_hist_mutex);
+ return ret;
}
#endif
@@ -1106,11 +1139,10 @@
{
uint8 count;
uint32 current_rate;
- if (mdp_clk && mdp_pdata
- && mdp_pdata->mdp_core_clk_table) {
- if (clk_set_min_rate(mdp_clk,
- min_clk_rate) < 0)
- printk(KERN_ERR "%s: clk_set_min_rate failed\n",
+ if (mdp_clk && mdp_pdata && mdp_pdata->mdp_core_clk_table) {
+ min_clk_rate = clk_round_rate(mdp_clk, min_clk_rate);
+ if (clk_set_rate(mdp_clk, min_clk_rate) < 0)
+ printk(KERN_ERR "%s: clk_set_rate failed\n",
__func__);
else {
count = 0;
@@ -1340,6 +1372,10 @@
/* link to the latest pdev */
mfd->pdev = msm_fb_dev;
+ mfd->mdp_rev = mdp_rev;
+
+ mfd->ov0_blt_state = 0;
+ mfd->use_ov0_blt = 0 ;
/* add panel data */
if (platform_device_add_data
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 0aeb91e..2bcac9c 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -35,6 +35,10 @@
#define MDP4_RGB_BASE 0x40000
#define MDP4_RGB_OFF 0x10000
+/* chip select controller */
+#define CS_CONTROLLER_0 0x0707ffff
+#define CS_CONTROLLER_1 0x03073f3f
+
enum {
OVERLAY_PERF_LEVEL1 = 1,
OVERLAY_PERF_LEVEL2,
@@ -135,14 +139,16 @@
OVERLAY_PIPE_RGB2,
OVERLAY_PIPE_VG1, /* video/graphic */
OVERLAY_PIPE_VG2,
+ OVERLAY_PIPE_RGB3,
+ OVERLAY_PIPE_VG3,
OVERLAY_PIPE_MAX
};
-/* 2 VG pipes can be shared by RGB and VIDEO */
-#define MDP4_MAX_PIPE (OVERLAY_PIPE_MAX + 2)
-
-#define OVERLAY_TYPE_RGB 0x01
-#define OVERLAY_TYPE_VIDEO 0x02
+enum {
+ OVERLAY_TYPE_RGB,
+ OVERLAY_TYPE_VIDEO,
+ OVERLAY_TYPE_BF
+};
enum {
MDP4_MIXER0,
@@ -150,8 +156,6 @@
MDP4_MIXER_MAX
};
-#define MDP4_MAX_MIXER 2
-
enum {
OVERLAY_PLANE_INTERLEAVED,
OVERLAY_PLANE_PLANAR,
@@ -215,6 +219,10 @@
#define MDP4_OP_SCALEX_FIR (0 << 2)
#define MDP4_OP_SCALEX_MN_PHASE (1 << 2)
#define MDP4_OP_SCALEX_PIXEL_RPT (2 << 2)
+#define MDP4_OP_SCALE_RGB_PIXEL_RPT (0 << 3)
+#define MDP4_OP_SCALE_RGB_BILINEAR (1 << 3)
+#define MDP4_OP_SCALE_ALPHA_PIXEL_RPT (0 << 2)
+#define MDP4_OP_SCALE_ALPHA_BILINEAR (1 << 2)
#define MDP4_OP_SCALEY_EN BIT(1)
#define MDP4_OP_SCALEX_EN BIT(0)
@@ -222,6 +230,15 @@
#define MDP4_MAX_PLANE 4
+struct mdp4_hsic_regs {
+ int32_t params[NUM_HSIC_PARAM];
+ int32_t conv_matrix[3][3];
+ int32_t pre_limit[6];
+ int32_t post_limit[6];
+ int32_t pre_bias[3];
+ int32_t post_bias[3];
+ int32_t dirty;
+};
struct mdp4_overlay_pipe {
uint32 pipe_used;
@@ -298,19 +315,11 @@
uint32 dmap_cnt;
uint32 blt_end;
uint32 luma_align_size;
+ struct mdp4_hsic_regs hsic_regs;
struct completion dmas_comp;
struct mdp_overlay req_data;
};
-#define MDP4_MAX_SHARE 2
-
-struct mdp4_pipe_desc {
- int share;
- int ref_cnt;
- int ndx_list[MDP4_MAX_SHARE];
- struct mdp4_overlay_pipe *player;
-};
-
struct mdp4_statistic {
ulong intr_tot;
ulong intr_dma_p;
@@ -318,20 +327,33 @@
ulong intr_dma_e;
ulong intr_overlay0;
ulong intr_overlay1;
+ ulong intr_vsync_p; /* Primary interface */
ulong intr_underrun_p; /* Primary interface */
+ ulong intr_vsync_e; /* external interface */
ulong intr_underrun_e; /* external interface */
+ ulong intr_histogram;
+ ulong intr_rd_ptr;
+ ulong dsi_mdp_start;
+ ulong dsi_clk_on;
+ ulong dsi_clk_off;
ulong intr_dsi;
- ulong kickoff_mddi;
- ulong kickoff_lcdc;
- ulong kickoff_dtv;
- ulong kickoff_atv;
- ulong kickoff_dsi;
- ulong kickoff_writeback;
- ulong writeback; /* blt */
+ ulong intr_dsi_mdp;
+ ulong intr_dsi_cmd;
+ ulong intr_dsi_err;
+ ulong kickoff_ov0;
+ ulong kickoff_ov1;
+ ulong kickoff_dmap;
+ ulong kickoff_dmae;
+ ulong kickoff_dmas;
+ ulong blt_dsi_cmd; /* blt */
+ ulong blt_dsi_video; /* blt */
+ ulong blt_lcdc; /* blt */
+ ulong blt_dtv; /* blt */
+ ulong blt_mddi; /* blt */
ulong overlay_set[MDP4_MIXER_MAX];
ulong overlay_unset[MDP4_MIXER_MAX];
ulong overlay_play[MDP4_MIXER_MAX];
- ulong pipe[MDP4_MAX_PIPE];
+ ulong pipe[OVERLAY_PIPE_MAX];
ulong dsi_clkoff;
ulong err_mixer;
ulong err_zorder;
@@ -396,6 +418,17 @@
}
#endif
+static inline int mdp4_overlay_borderfill_supported(void)
+{
+ unsigned int mdp_hw_version;
+ mdp_hw_version = inpdw(MDP_BASE + 0x0); /* MDP_HW_VERSION */
+ return (mdp_hw_version >= 0x0402030b);
+}
+
+int mdp4_overlay_dtv_set(struct msm_fb_data_type *mfd,
+ struct mdp4_overlay_pipe *pipe);
+int mdp4_overlay_dtv_unset(struct msm_fb_data_type *mfd,
+ struct mdp4_overlay_pipe *pipe);
void mdp4_dtv_overlay(struct msm_fb_data_type *mfd);
int mdp4_dtv_on(struct platform_device *pdev);
int mdp4_dtv_off(struct platform_device *pdev);
@@ -430,8 +463,7 @@
int mdp4_overlay_play_wait(struct fb_info *info,
struct msmfb_overlay_data *req);
int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req);
-struct mdp4_overlay_pipe *mdp4_overlay_pipe_alloc(int ptype, int mixer,
- int req_share);
+struct mdp4_overlay_pipe *mdp4_overlay_pipe_alloc(int ptype, int mixer);
void mdp4_overlay_pipe_free(struct mdp4_overlay_pipe *pipe);
void mdp4_overlay_dmap_cfg(struct msm_fb_data_type *mfd, int lcdc);
void mdp4_overlay_dmap_xy(struct mdp4_overlay_pipe *pipe);
@@ -547,6 +579,7 @@
int mdp4_mddi_overlay_blt_offset(int *off);
void mdp4_mddi_overlay_blt(ulong addr);
void mdp4_overlay_panel_mode(int mixer_num, uint32 mode);
+void mdp4_overlay_panel_mode_unset(int mixer_num, uint32 mode);
int mdp4_overlay_mixer_play(int mixer_num);
uint32 mdp4_overlay_panel_list(void);
void mdp4_lcdc_overlay_kickoff(struct msm_fb_data_type *mfd,
@@ -637,4 +670,6 @@
int mdp4_writeback_init(struct fb_info *info);
int mdp4_writeback_terminate(struct fb_info *info);
+void mdp4_hsic_set(struct mdp4_overlay_pipe *pipe, struct dpp_ctrl *ctrl);
+void mdp4_hsic_update(struct mdp4_overlay_pipe *pipe);
#endif /* MDP_H */
diff --git a/drivers/video/msm/mdp4_hsic.c b/drivers/video/msm/mdp4_hsic.c
new file mode 100644
index 0000000..5735f45
--- /dev/null
+++ b/drivers/video/msm/mdp4_hsic.c
@@ -0,0 +1,534 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/module.h>
+#include <linux/types.h>
+#include <linux/msm_mdp.h>
+#include "mdp.h"
+#include "mdp4.h"
+
+/* Definitions */
+#define MDP4_CSC_MV_OFF 0x4400
+#define MDP4_CSC_PRE_BV_OFF 0x4500
+#define MDP4_CSC_POST_BV_OFF 0x4580
+#define MDP4_CSC_PRE_LV_OFF 0x4600
+#define MDP4_CSC_POST_LV_OFF 0x4680
+#define MDP_VG1_BASE (MDP_BASE + MDP4_VIDEO_BASE)
+
+#define MDP_VG1_CSC_MVn(n) (MDP_VG1_BASE + MDP4_CSC_MV_OFF + 4 * (n))
+#define MDP_VG1_CSC_PRE_LVn(n) (MDP_VG1_BASE + MDP4_CSC_PRE_LV_OFF + 4 * (n))
+#define MDP_VG1_CSC_POST_LVn(n) (MDP_VG1_BASE + MDP4_CSC_POST_LV_OFF + 4 * (n))
+#define MDP_VG1_CSC_PRE_BVn(n) (MDP_VG1_BASE + MDP4_CSC_PRE_BV_OFF + 4 * (n))
+#define MDP_VG1_CSC_POST_BVn(n) (MDP_VG1_BASE + MDP4_CSC_POST_BV_OFF + 4 * (n))
+
+#define Q16 (16)
+#define Q16_ONE (1 << Q16)
+
+#define Q16_VALUE(x) ((int32_t)((uint32_t)x << Q16))
+#define Q16_PERCENT_VALUE(x, n) ((int32_t)( \
+ div_s64(((int64_t)x * (int64_t)Q16_ONE), n)))
+
+#define Q16_WHOLE(x) ((int32_t)(x >> 16))
+#define Q16_FRAC(x) ((int32_t)(x & 0xFFFF))
+#define Q16_S1Q16_MUL(x, y) (((x >> 1) * (y >> 1)) >> 14)
+
+#define Q16_MUL(x, y) ((int32_t)((((int64_t)x) * ((int64_t)y)) >> Q16))
+#define Q16_NEGATE(x) (0 - (x))
+
+/*
+ * HSIC Control min/max values
+ * These settings are based on the maximum/minimum allowed modifications to
+ * HSIC controls for layer and display color. Allowing too much variation in
+ * the CSC block will result in color clipping resulting in unwanted color
+ * shifts.
+ */
+#define TRIG_MAX Q16_VALUE(128)
+#define CON_SAT_MAX Q16_VALUE(128)
+#define INTENSITY_MAX (Q16_VALUE(2047) >> 12)
+
+#define HUE_MAX Q16_VALUE(100)
+#define HUE_MIN Q16_VALUE(-100)
+#define HUE_DEF Q16_VALUE(0)
+
+#define SAT_MAX Q16_VALUE(100)
+#define SAT_MIN Q16_VALUE(-100)
+#define SAT_DEF CON_SAT_MAX
+
+#define CON_MAX Q16_VALUE(100)
+#define CON_MIN Q16_VALUE(-100)
+#define CON_DEF CON_SAT_MAX
+
+#define INTEN_MAX Q16_VALUE(100)
+#define INTEN_MIN Q16_VALUE(-100)
+#define INTEN_DEF Q16_VALUE(0)
+
+enum {
+ DIRTY,
+ GENERATED,
+ CLEAN
+};
+
+/* local vars*/
+static int32_t csc_matrix_tab[3][3] = {
+ {0x00012a00, 0x00000000, 0x00019880},
+ {0x00012a00, 0xffff9b80, 0xffff3000},
+ {0x00012a00, 0x00020480, 0x00000000}
+};
+
+static int32_t csc_yuv2rgb_conv_tab[3][3] = {
+ {0x00010000, 0x00000000, 0x000123cb},
+ {0x00010000, 0xffff9af9, 0xffff6b5e},
+ {0x00010000, 0x00020838, 0x00000000}
+};
+
+static int32_t csc_rgb2yuv_conv_tab[3][3] = {
+ {0x00004c8b, 0x00009645, 0x00001d2f},
+ {0xffffda56, 0xffffb60e, 0x00006f9d},
+ {0x00009d70, 0xffff7c2a, 0xffffe666}
+};
+
+static uint32_t csc_pre_bv_tab[3] = {0xfffff800, 0xffffc000, 0xffffc000};
+static uint32_t csc_post_bv_tab[3] = {0x00000000, 0x00000000, 0x00000000};
+
+static uint32_t csc_pre_lv_tab[6] = {0x00000000, 0x00007f80, 0x00000000,
+ 0x00007f80, 0x00000000, 0x00007f80};
+static uint32_t csc_post_lv_tab[6] = {0x00000000, 0x00007f80, 0x00000000,
+ 0x00007f80, 0x00000000, 0x00007f80};
+
+/* Lookup table for Sin/Cos lookup - Q16*/
+static const int32_t trig_lut[65] = {
+ 0x00000000, /* sin((2*M_PI/256) * 0x00);*/
+ 0x00000648, /* sin((2*M_PI/256) * 0x01);*/
+ 0x00000C90, /* sin((2*M_PI/256) * 0x02);*/
+ 0x000012D5,
+ 0x00001918,
+ 0x00001F56,
+ 0x00002590,
+ 0x00002BC4,
+ 0x000031F1,
+ 0x00003817,
+ 0x00003E34,
+ 0x00004447,
+ 0x00004A50,
+ 0x0000504D,
+ 0x0000563E,
+ 0x00005C22,
+ 0x000061F8,
+ 0x000067BE,
+ 0x00006D74,
+ 0x0000731A,
+ 0x000078AD,
+ 0x00007E2F,
+ 0x0000839C,
+ 0x000088F6,
+ 0x00008E3A,
+ 0x00009368,
+ 0x00009880,
+ 0x00009D80,
+ 0x0000A268,
+ 0x0000A736,
+ 0x0000ABEB,
+ 0x0000B086,
+ 0x0000B505,
+ 0x0000B968,
+ 0x0000BDAF,
+ 0x0000C1D8,
+ 0x0000C5E4,
+ 0x0000C9D1,
+ 0x0000CD9F,
+ 0x0000D14D,
+ 0x0000D4DB,
+ 0x0000D848,
+ 0x0000DB94,
+ 0x0000DEBE,
+ 0x0000E1C6,
+ 0x0000E4AA,
+ 0x0000E768,
+ 0x0000EA0A,
+ 0x0000EC83,
+ 0x0000EED9,
+ 0x0000F109,
+ 0x0000F314,
+ 0x0000F4FA,
+ 0x0000F6BA,
+ 0x0000F854,
+ 0x0000F9C8,
+ 0x0000FB15,
+ 0x0000FC3B,
+ 0x0000FD3B,
+ 0x0000FE13,
+ 0x0000FEC4,
+ 0x0000FF4E,
+ 0x0000FFB1,
+ 0x0000FFEC,
+ 0x00010000, /* sin((2*M_PI/256) * 0x40);*/
+};
+
+void trig_values_q16(int32_t deg, int32_t *cos, int32_t *sin)
+{
+ int32_t angle;
+ int32_t quad, anglei, anglef;
+ int32_t v0 = 0, v1 = 0;
+ int32_t t1, t2;
+
+ /*
+ * Scale the angle so that 256 is one complete revolution and mask it
+ * to this domain
+ * NOTE: 0xB60B == 256/360
+ */
+ angle = Q16_MUL(deg, 0xB60B) & 0x00FFFFFF;
+
+ /* Obtain a quadrant number, integer, and fractional part */
+ quad = angle >> 22;
+ anglei = (angle >> 16) & 0x3F;
+ anglef = angle & 0xFFFF;
+
+ /*
+ * Using the integer part, obtain the lookup table entry and its
+ * complement. Using the quadrant, swap and negate these as
+ * necessary.
+ * (The values and all derivatives of sine and cosine functions
+ * can be derived from these values)
+ */
+ switch (quad) {
+ case 0x0:
+ v0 += trig_lut[anglei];
+ v1 += trig_lut[0x40-anglei];
+ break;
+
+ case 0x1:
+ v0 += trig_lut[0x40-anglei];
+ v1 -= trig_lut[anglei];
+ break;
+
+ case 0x2:
+ v0 -= trig_lut[anglei];
+ v1 -= trig_lut[0x40-anglei];
+ break;
+
+ case 0x3:
+ v0 -= trig_lut[0x40-anglei];
+ v1 += trig_lut[anglei];
+ break;
+ }
+
+ /*
+ * Multiply the fractional part by 2*PI/256 to move it from lookup
+ * table units to radians, giving us the coefficient for first
+ * derivatives.
+ */
+ t1 = Q16_S1Q16_MUL(anglef, 0x0648);
+
+ /*
+ * Square this and divide by 2 to get the coefficient for second
+ * derivatives
+ */
+ t2 = Q16_S1Q16_MUL(t1, t1) >> 1;
+
+ *sin = v0 + Q16_S1Q16_MUL(v1, t1) - Q16_S1Q16_MUL(v0, t2);
+
+ *cos = v1 - Q16_S1Q16_MUL(v0, t1) - Q16_S1Q16_MUL(v1, t2);
+}
+
+/* Convert input Q16 value to s4.9 */
+int16_t convert_q16_s49(int32_t q16Value)
+{ /* Top half is the whole number, Bottom half is fractional portion*/
+ int16_t whole = Q16_WHOLE(q16Value);
+ int32_t fraction = Q16_FRAC(q16Value);
+
+ /* Clamp whole to 3 bits */
+ if (whole > 7)
+ whole = 7;
+ else if (whole < -7)
+ whole = -7;
+
+ /* Reduce fraction to 9 bits. */
+ fraction = (fraction<<9)>>Q16;
+
+ return (int16_t) ((int16_t)whole<<9) | ((int16_t)fraction);
+}
+
+/* Convert input Q16 value to uint16 */
+int16_t convert_q16_int16(int32_t val)
+{
+ int32_t rounded;
+
+ if (val >= 0) {
+ /* Add 0.5 */
+ rounded = val + (Q16_ONE>>1);
+ } else {
+ /* Subtract 0.5 */
+ rounded = val - (Q16_ONE>>1);
+ }
+
+ /* Truncate rounded value */
+ return (int16_t)(rounded>>Q16);
+}
+
+/*
+ * norm_q16
+ * Return a Q16 value represeting a normalized value
+ *
+ * value -100% 0% +100%
+ * |-----------------|----------------|
+ * ^ ^ ^
+ * q16MinValue q16DefaultValue q16MaxValue
+ *
+ */
+int32_t norm_q16(int32_t value, int32_t min, int32_t default_val, int32_t max,
+ int32_t range)
+{
+ int32_t diff, perc, mul, result;
+
+ if (0 == value) {
+ result = default_val;
+ } else if (value > 0) {
+ /* value is between 0% and +100% represent 1.0 -> QRange Max */
+ diff = range;
+ perc = Q16_PERCENT_VALUE(value, max);
+ mul = Q16_MUL(perc, diff);
+ result = default_val + mul;
+ } else {
+ /* if (value <= 0) */
+ diff = -range;
+ perc = Q16_PERCENT_VALUE(-value, -min);
+ mul = Q16_MUL(perc, diff);
+ result = default_val + mul;
+ }
+ return result;
+}
+
+void matrix_mul_3x3(int32_t dest[][3], int32_t a[][3], int32_t b[][3])
+{
+ int32_t i, j, k;
+ int32_t tmp[3][3];
+
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < 3; j++) {
+ tmp[i][j] = 0;
+ for (k = 0; k < 3; k++)
+ tmp[i][j] += Q16_MUL(a[i][k], b[k][j]);
+ }
+ }
+
+ /* in case dest = a or b*/
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < 3; j++)
+ dest[i][j] = tmp[i][j];
+ }
+}
+
+#define CONVERT(x) (x)/*convert_q16_s49((x))*/
+void pr_params(struct mdp4_hsic_regs *regs)
+{
+ int i;
+ if (regs) {
+ for (i = 0; i < NUM_HSIC_PARAM; i++) {
+ pr_info("\t: hsic->params[%d] = 0x%08x [raw = 0x%08x]\n",
+ i, CONVERT(regs->params[i]), regs->params[i]);
+ }
+ }
+}
+
+void pr_3x3_matrix(int32_t in[][3])
+{
+ pr_info("\t[0x%08x\t0x%08x\t0x%08x]\n", CONVERT(in[0][0]),
+ CONVERT(in[0][1]), CONVERT(in[0][2]));
+ pr_info("\t[0x%08x\t0x%08x\t0x%08x]\n", CONVERT(in[1][0]),
+ CONVERT(in[1][1]), CONVERT(in[1][2]));
+ pr_info("\t[0x%08x\t0x%08x\t0x%08x]\n", CONVERT(in[2][0]),
+ CONVERT(in[2][1]), CONVERT(in[2][2]));
+}
+
+void _hsic_get(struct mdp4_hsic_regs *regs, int32_t type, int8_t *val)
+{
+ if (type < 0 || type >= NUM_HSIC_PARAM)
+ BUG_ON(-EINVAL);
+ *val = regs->params[type];
+ pr_info("%s: getting params[%d] = %d\n", __func__, type, *val);
+}
+
+void _hsic_set(struct mdp4_hsic_regs *regs, int32_t type, int8_t val)
+{
+ if (type < 0 || type >= NUM_HSIC_PARAM)
+ BUG_ON(-EINVAL);
+
+ if (regs->params[type] != Q16_VALUE(val)) {
+ regs->params[type] = Q16_VALUE(val);
+ regs->dirty = DIRTY;
+ }
+}
+
+void _hsic_generate_csc_matrix(struct mdp4_overlay_pipe *pipe)
+{
+ int i, j;
+ int32_t sin, cos;
+
+ int32_t hue_matrix[3][3];
+ int32_t con_sat_matrix[3][3];
+ struct mdp4_hsic_regs *regs = &(pipe->hsic_regs);
+
+ memset(con_sat_matrix, 0x0, sizeof(con_sat_matrix));
+ memset(hue_matrix, 0x0, sizeof(hue_matrix));
+
+ /*
+ * HSIC control require matrix multiplication of these two tables
+ * [T 0 0][1 0 0] T = Contrast C=Cos(Hue)
+ * [0 S 0][0 C -N] S = Saturation N=Sin(Hue)
+ * [0 0 S][0 N C]
+ */
+
+ con_sat_matrix[0][0] = norm_q16(regs->params[HSIC_CON], CON_MIN,
+ CON_DEF, CON_MAX, CON_SAT_MAX);
+ con_sat_matrix[1][1] = norm_q16(regs->params[HSIC_SAT], SAT_MIN,
+ SAT_DEF, SAT_MAX, CON_SAT_MAX);
+ con_sat_matrix[2][2] = con_sat_matrix[1][1];
+
+ hue_matrix[0][0] = TRIG_MAX;
+
+ trig_values_q16(norm_q16(regs->params[HSIC_HUE], HUE_MIN, HUE_DEF,
+ HUE_MAX, TRIG_MAX), &cos, &sin);
+
+ cos = Q16_MUL(cos, TRIG_MAX);
+ sin = Q16_MUL(sin, TRIG_MAX);
+
+ hue_matrix[1][1] = cos;
+ hue_matrix[2][2] = cos;
+ hue_matrix[2][1] = sin;
+ hue_matrix[1][2] = Q16_NEGATE(sin);
+
+ /* Generate YUV CSC matrix */
+ matrix_mul_3x3(regs->conv_matrix, con_sat_matrix, hue_matrix);
+
+ if (!(pipe->op_mode & MDP4_OP_SRC_DATA_YCBCR)) {
+ /* Convert input RGB to YUV then apply CSC matrix */
+ pr_info("Pipe %d, has RGB input\n", pipe->pipe_num);
+ matrix_mul_3x3(regs->conv_matrix, regs->conv_matrix,
+ csc_rgb2yuv_conv_tab);
+ }
+
+ /* Normalize the matrix */
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < 3; j++)
+ regs->conv_matrix[i][j] = (regs->conv_matrix[i][j]>>14);
+ }
+
+ /* Multiply above result by current csc table */
+ matrix_mul_3x3(regs->conv_matrix, regs->conv_matrix, csc_matrix_tab);
+
+ if (!(pipe->op_mode & MDP4_OP_SRC_DATA_YCBCR)) {
+ /*HACK:only "works"for src side*/
+ /* Convert back to RGB */
+ pr_info("Pipe %d, has RGB output\n", pipe->pipe_num);
+ matrix_mul_3x3(regs->conv_matrix, csc_yuv2rgb_conv_tab,
+ regs->conv_matrix);
+ }
+
+ /* Update clamps pre and post. */
+ /* TODO: different tables for different color formats? */
+ for (i = 0; i < 6; i++) {
+ regs->pre_limit[i] = csc_pre_lv_tab[i];
+ regs->post_limit[i] = csc_post_lv_tab[i];
+ }
+
+ /* update bias values, pre and post */
+ for (i = 0; i < 3; i++) {
+ regs->pre_bias[i] = csc_pre_bv_tab[i];
+ regs->post_bias[i] = csc_post_bv_tab[i] +
+ norm_q16(regs->params[HSIC_INT],
+ INTEN_MIN, INTEN_DEF, INTEN_MAX, INTENSITY_MAX);
+ }
+
+ regs->dirty = GENERATED;
+}
+
+void _hsic_update_mdp(struct mdp4_overlay_pipe *pipe)
+{
+ struct mdp4_hsic_regs *regs = &(pipe->hsic_regs);
+ int i, j, k;
+
+ uint32_t *csc_mv;
+ uint32_t *pre_lv;
+ uint32_t *post_lv;
+ uint32_t *pre_bv;
+ uint32_t *post_bv;
+
+ switch (pipe->pipe_num) {
+ case OVERLAY_PIPE_VG2:
+ csc_mv = (uint32_t *) (MDP_VG1_CSC_MVn(0) +
+ MDP4_VIDEO_OFF);
+ pre_lv = (uint32_t *) (MDP_VG1_CSC_PRE_LVn(0) +
+ MDP4_VIDEO_OFF);
+ post_lv = (uint32_t *) (MDP_VG1_CSC_POST_LVn(0) +
+ MDP4_VIDEO_OFF);
+ pre_bv = (uint32_t *) (MDP_VG1_CSC_PRE_BVn(0) +
+ MDP4_VIDEO_OFF);
+ post_bv = (uint32_t *) (MDP_VG1_CSC_POST_BVn(0) +
+ MDP4_VIDEO_OFF);
+ break;
+ case OVERLAY_PIPE_VG1:
+ default:
+ csc_mv = (uint32_t *) MDP_VG1_CSC_MVn(0);
+ pre_lv = (uint32_t *) MDP_VG1_CSC_PRE_LVn(0);
+ post_lv = (uint32_t *) MDP_VG1_CSC_POST_LVn(0);
+ pre_bv = (uint32_t *) MDP_VG1_CSC_PRE_BVn(0);
+ post_bv = (uint32_t *) MDP_VG1_CSC_POST_BVn(0);
+ break;
+ }
+
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < 3; j++) {
+ k = (3*i) + j;
+ MDP_OUTP(csc_mv + k, convert_q16_s49(
+ regs->conv_matrix[i][j]));
+ }
+ }
+
+ for (i = 0; i < 6; i++) {
+ MDP_OUTP(pre_lv + i, convert_q16_s49(regs->pre_limit[i]));
+ MDP_OUTP(post_lv + i, convert_q16_s49(regs->post_limit[i]));
+ }
+
+ for (i = 0; i < 3; i++) {
+ MDP_OUTP(pre_bv + i, convert_q16_s49(regs->pre_bias[i]));
+ MDP_OUTP(post_bv + i, convert_q16_s49(regs->post_bias[i]));
+ }
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+ regs->dirty = CLEAN;
+}
+
+void mdp4_hsic_get(struct mdp4_overlay_pipe *pipe, struct dpp_ctrl *ctrl)
+{
+ int i;
+ for (i = 0; i < NUM_HSIC_PARAM; i++)
+ _hsic_get(&(pipe->hsic_regs), i, &(ctrl->hsic_params[i]));
+}
+
+void mdp4_hsic_set(struct mdp4_overlay_pipe *pipe, struct dpp_ctrl *ctrl)
+{
+ int i;
+ for (i = 0; i < NUM_HSIC_PARAM; i++)
+ _hsic_set(&(pipe->hsic_regs), i, ctrl->hsic_params[i]);
+
+ if (pipe->hsic_regs.dirty == DIRTY)
+ _hsic_generate_csc_matrix(pipe);
+}
+
+void mdp4_hsic_update(struct mdp4_overlay_pipe *pipe)
+{
+ if (pipe->hsic_regs.dirty == GENERATED)
+ _hsic_update_mdp(pipe);
+}
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index dbed160..72a11a2 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -41,28 +41,15 @@
#define VERSION_KEY_MASK 0xFFFFFF00
struct mdp4_overlay_ctrl {
- struct mdp4_pipe_desc ov_pipe[OVERLAY_PIPE_MAX];/* 4 */
- struct mdp4_overlay_pipe plist[MDP4_MAX_PIPE]; /* 4 + 2 */
- struct mdp4_overlay_pipe *stage[MDP4_MAX_MIXER][MDP4_MIXER_STAGE_MAX];
+ struct mdp4_overlay_pipe plist[OVERLAY_PIPE_MAX];
+ struct mdp4_overlay_pipe *stage[MDP4_MIXER_MAX][MDP4_MIXER_STAGE_MAX];
+ uint32 cs_controller;
uint32 panel_3d;
uint32 panel_mode;
uint32 mixer0_played;
uint32 mixer1_played;
} mdp4_overlay_db = {
- .ov_pipe = {
- {
- .share = 0, /* RGB 1 */
- },
- {
- .share = 0, /* RGB 2 */
- },
- {
- .share = 1, /* VG 1 */
- },
- {
- .share = 1, /* VG 2 */
- },
- },
+ .cs_controller = CS_CONTROLLER_0,
.plist = {
{
.pipe_type = OVERLAY_TYPE_RGB,
@@ -75,24 +62,26 @@
.pipe_ndx = 2,
},
{
- .pipe_type = OVERLAY_TYPE_RGB, /* shared */
+ .pipe_type = OVERLAY_TYPE_VIDEO,
.pipe_num = OVERLAY_PIPE_VG1,
.pipe_ndx = 3,
},
{
- .pipe_type = OVERLAY_TYPE_RGB, /* shared */
+ .pipe_type = OVERLAY_TYPE_VIDEO,
.pipe_num = OVERLAY_PIPE_VG2,
.pipe_ndx = 4,
},
{
- .pipe_type = OVERLAY_TYPE_VIDEO, /* shared */
- .pipe_num = OVERLAY_PIPE_VG1,
+ .pipe_type = OVERLAY_TYPE_BF,
+ .pipe_num = OVERLAY_PIPE_RGB3,
.pipe_ndx = 5,
+ .mixer_num = MDP4_MIXER0,
},
{
- .pipe_type = OVERLAY_TYPE_VIDEO, /* shared */
- .pipe_num = OVERLAY_PIPE_VG2,
+ .pipe_type = OVERLAY_TYPE_BF,
+ .pipe_num = OVERLAY_PIPE_VG3,
.pipe_ndx = 6,
+ .mixer_num = MDP4_MIXER1,
},
},
};
@@ -131,6 +120,11 @@
ctrl->panel_mode |= mode;
}
+void mdp4_overlay_panel_mode_unset(int mixer_num, uint32 mode)
+{
+ ctrl->panel_mode &= ~mode;
+}
+
uint32 mdp4_overlay_panel_list(void)
{
return ctrl->panel_mode;
@@ -362,11 +356,8 @@
static void mdp4_scale_setup(struct mdp4_overlay_pipe *pipe)
{
- int ptype;
-
pipe->phasex_step = MDP4_VG_PHASE_STEP_DEFAULT;
pipe->phasey_step = MDP4_VG_PHASE_STEP_DEFAULT;
- ptype = mdp4_overlay_format2type(pipe->src_format);
if (pipe->dst_h && pipe->src_h != pipe->dst_h) {
if (pipe->dst_h > pipe->src_h * 8) /* too much */
@@ -374,10 +365,15 @@
pipe->op_mode |= MDP4_OP_SCALEY_EN;
if (pipe->pipe_num >= OVERLAY_PIPE_VG1) {
- if (pipe->dst_h <= (pipe->src_h / 4))
+ if (pipe->alpha_enable)
+ pipe->op_mode |= MDP4_OP_SCALEY_PIXEL_RPT;
+ else if (pipe->dst_h <= (pipe->src_h / 4))
pipe->op_mode |= MDP4_OP_SCALEY_MN_PHASE;
else
pipe->op_mode |= MDP4_OP_SCALEY_FIR;
+ } else { /* RGB pipe */
+ pipe->op_mode |= MDP4_OP_SCALE_RGB_BILINEAR;
+ pipe->op_mode |= MDP4_OP_SCALE_ALPHA_BILINEAR;
}
pipe->phasey_step = mdp4_scale_phase_step(29,
@@ -390,10 +386,15 @@
pipe->op_mode |= MDP4_OP_SCALEX_EN;
if (pipe->pipe_num >= OVERLAY_PIPE_VG1) {
- if (pipe->dst_w <= (pipe->src_w / 4))
+ if (pipe->alpha_enable)
+ pipe->op_mode |= MDP4_OP_SCALEX_PIXEL_RPT;
+ else if (pipe->dst_w <= (pipe->src_w / 4))
pipe->op_mode |= MDP4_OP_SCALEX_MN_PHASE;
else
pipe->op_mode |= MDP4_OP_SCALEX_FIR;
+ } else { /* RGB pipe */
+ pipe->op_mode |= MDP4_OP_SCALE_RGB_BILINEAR;
+ pipe->op_mode |= MDP4_OP_SCALE_ALPHA_BILINEAR;
}
pipe->phasex_step = mdp4_scale_phase_step(29,
@@ -509,6 +510,7 @@
char *vg_base;
uint32 frame_size, src_size, src_xy, dst_size, dst_xy;
uint32 format, pattern, luma_offset, chroma_offset;
+ uint32 mask;
int pnum, ptype;
pnum = pipe->pipe_num - OVERLAY_PIPE_VG1; /* start from 0 */
@@ -599,6 +601,24 @@
1));
}
+ if (mdp_rev > MDP_REV_41) {
+ /* mdp chip select controller */
+ mask = 0;
+ if (pipe->pipe_num == OVERLAY_PIPE_VG1)
+ mask = 0x020; /* bit 5 */
+ else if (pipe->pipe_num == OVERLAY_PIPE_VG2)
+ mask = 0x02000; /* bit 13 */
+ if (mask) {
+ if (pipe->op_mode & MDP4_OP_SCALEY_MN_PHASE)
+ ctrl->cs_controller &= ~mask;
+ else
+ ctrl->cs_controller |= mask;
+ /* NOT double buffered */
+ outpdw(MDP_BASE + 0x00c0, ctrl->cs_controller);
+ }
+ }
+
+
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
mdp4_stat.pipe[pipe->pipe_num]++;
@@ -1198,7 +1218,7 @@
struct mdp4_overlay_pipe *spipe;
spipe = mdp4_overlay_stage_pipe(pipe->mixer_num, pipe->mixer_stage);
- if ((spipe != NULL) && (spipe != pipe)) {
+ if ((spipe != NULL) && (spipe->pipe_num != pipe->pipe_num)) {
pr_err("%s: unable to stage pipe=%d at mixer_stage=%d\n",
__func__, pipe->pipe_ndx, pipe->mixer_stage);
return;
@@ -1216,7 +1236,9 @@
if (mixer == MDP4_MIXER1)
stage += 8;
- if (pipe->pipe_num >= OVERLAY_PIPE_VG1) {/* VG1 and VG2 */
+ if (pipe->pipe_type == OVERLAY_TYPE_BF) {
+ snum = 16 + (4 * mixer);
+ } else if (pipe->pipe_num >= OVERLAY_PIPE_VG1) {/* VG1 and VG2 */
pnum -= OVERLAY_PIPE_VG1; /* start from 0 */
snum = 0;
snum += (4 * pnum);
@@ -1260,7 +1282,9 @@
if (mixer == MDP4_MIXER1)
stage += 8;
- if (pipe->pipe_num >= OVERLAY_PIPE_VG1) {/* VG1 and VG2 */
+ if (pipe->pipe_type == OVERLAY_TYPE_BF) {
+ snum = 16 + (4 * mixer);
+ } else if (pipe->pipe_num >= OVERLAY_PIPE_VG1) {
pnum -= OVERLAY_PIPE_VG1; /* start from 0 */
snum = 0;
snum += (4 * pnum);
@@ -1287,8 +1311,12 @@
struct mdp4_overlay_pipe *bg_pipe;
unsigned char *overlay_base, *rgb_base;
uint32 c0, c1, c2, blend_op, constant_color = 0, rgb_src_format;
+ uint32 fg_color3_out;
int off;
+ if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE)
+ return;
+
if (pipe->mixer_num) /* mixer number, /dev/fb0, /dev/fb1 */
overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */
else
@@ -1298,7 +1326,7 @@
off = 0x20 * (pipe->mixer_stage - MDP4_MIXER_STAGE0);
bg_pipe = mdp4_overlay_stage_pipe(pipe->mixer_num,
- MDP4_MIXER_STAGE_BASE);
+ MDP4_MIXER_STAGE_BASE);
if (bg_pipe == NULL) {
pr_err("%s: Error: no bg_pipe\n", __func__);
return;
@@ -1306,14 +1334,15 @@
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- blend_op = 0;
+ blend_op = (MDP4_BLEND_FG_ALPHA_FG_CONST |
+ MDP4_BLEND_BG_ALPHA_BG_CONST);
+ outpdw(overlay_base + off + 0x108, pipe->alpha);
+ outpdw(overlay_base + off + 0x10c, 0xff - pipe->alpha);
+ fg_color3_out = 0; /* keep bg alpha by default */
if (pipe->is_fg) {
- blend_op |= (MDP4_BLEND_FG_ALPHA_FG_CONST |
- MDP4_BLEND_BG_ALPHA_BG_CONST);
- outpdw(overlay_base + off + 0x108, pipe->alpha);
- outpdw(overlay_base + off + 0x10c, 0xff - pipe->alpha);
- if (pipe->alpha == 0xff) {
+ if (pipe->alpha == 0xff &&
+ bg_pipe->pipe_num <= OVERLAY_PIPE_RGB2) {
rgb_base = MDP_BASE + MDP4_RGB_BASE;
rgb_base += MDP4_RGB_OFF * bg_pipe->pipe_num;
rgb_src_format = inpdw(rgb_base + 0x50);
@@ -1321,21 +1350,20 @@
outpdw(rgb_base + 0x50, rgb_src_format);
outpdw(rgb_base + 0x1008, constant_color);
}
- } else {
- if (bg_pipe->alpha_enable && pipe->alpha_enable) {
- /* both pipe have alpha */
- blend_op |= (MDP4_BLEND_FG_ALPHA_BG_PIXEL |
- MDP4_BLEND_FG_INV_ALPHA |
- MDP4_BLEND_BG_ALPHA_BG_PIXEL);
- } else if (bg_pipe->alpha_enable && pipe->alpha_enable == 0) {
- /* no alpha on both pipe */
- blend_op = (MDP4_BLEND_BG_ALPHA_BG_PIXEL |
- MDP4_BLEND_FG_ALPHA_BG_PIXEL |
- MDP4_BLEND_FG_INV_ALPHA);
- }
+ } else if (pipe->alpha_enable) {
+ /* pick fg alpha */
+ blend_op = (MDP4_BLEND_BG_ALPHA_FG_PIXEL |
+ MDP4_BLEND_FG_ALPHA_FG_PIXEL |
+ MDP4_BLEND_BG_INV_ALPHA);
+ fg_color3_out = 1; /* keep fg alpha */
+ } else if (bg_pipe->alpha_enable) {
+ /* pick bg alpha */
+ blend_op = (MDP4_BLEND_BG_ALPHA_BG_PIXEL |
+ MDP4_BLEND_FG_ALPHA_BG_PIXEL |
+ MDP4_BLEND_FG_INV_ALPHA);
+ fg_color3_out = 0; /* keep bg alpha */
}
-
if (pipe->transp != MDP_TRANSP_NOP) {
if (pipe->is_fg) {
transp_color_key(pipe->src_format, pipe->transp,
@@ -1367,6 +1395,7 @@
}
outpdw(overlay_base + off + 0x104, blend_op);
+ outpdw(overlay_base + (off << 5) + 0x1004, fg_color3_out);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
@@ -1381,7 +1410,7 @@
else
bits |= 0x01;
- if (all) {
+ if (all && pipe->pipe_type != OVERLAY_TYPE_BF) {
if (pipe->pipe_num <= OVERLAY_PIPE_RGB2) {
if (pipe->pipe_num == OVERLAY_PIPE_RGB2)
bits |= 0x20;
@@ -1421,7 +1450,7 @@
{
struct mdp4_overlay_pipe *pipe;
- if (ndx <= 0 || ndx > MDP4_MAX_PIPE)
+ if (ndx <= 0 || ndx > OVERLAY_PIPE_MAX)
return NULL;
pipe = &ctrl->plist[ndx - 1]; /* ndx start from 1 */
@@ -1432,65 +1461,28 @@
return pipe;
}
-struct mdp4_overlay_pipe *mdp4_overlay_pipe_alloc(
- int ptype, int mixer, int req_share)
+struct mdp4_overlay_pipe *mdp4_overlay_pipe_alloc(int ptype, int mixer)
{
- int i, j, ndx, found;
- struct mdp4_overlay_pipe *pipe, *opipe;
- struct mdp4_pipe_desc *pd;
+ int i;
+ struct mdp4_overlay_pipe *pipe;
- found = 0;
- pipe = &ctrl->plist[0];
-
- for (i = 0; i < MDP4_MAX_PIPE; i++) {
- if (pipe->pipe_type == ptype && pipe->pipe_used == 0) {
- pd = &ctrl->ov_pipe[pipe->pipe_num];
- if (pd->share) { /* pipe can be shared */
- if (pd->ref_cnt == 0) {
- /* not yet been used */
- found++;
- break;
- }
- /* pipe occupied already */
- if (req_share && pd->ref_cnt < MDP4_MAX_SHARE) {
- for (j = 0; j < MDP4_MAX_SHARE; j++) {
- ndx = pd->ndx_list[j];
- if (ndx != 0)
- break;
- }
- /* ndx satrt from 1 */
- opipe = &ctrl->plist[ndx - 1];
- /*
- * occupied pipe willing to share and
- * same mixer
- */
- if (opipe->pipe_share &&
- opipe->mixer_num == mixer) {
- found++;
- break;
- }
- }
- } else { /* not a shared pipe */
- if (req_share == 0 && pd->ref_cnt == 0) {
- found++;
- break;
- }
- }
+ for (i = 0; i < OVERLAY_PIPE_MAX; i++) {
+ pipe = &ctrl->plist[i];
+ if ((pipe->pipe_used == 0) && ((pipe->pipe_type == ptype) ||
+ (ptype == OVERLAY_TYPE_RGB &&
+ pipe->pipe_type == OVERLAY_TYPE_VIDEO))) {
+ if (ptype == OVERLAY_TYPE_BF &&
+ mixer != pipe->mixer_num)
+ continue;
+ init_completion(&pipe->comp);
+ init_completion(&pipe->dmas_comp);
+ pr_info("%s: pipe=%x ndx=%d num=%d\n", __func__,
+ (int)pipe, pipe->pipe_ndx, pipe->pipe_num);
+ return pipe;
}
- pipe++;
}
- if (found) {
- init_completion(&pipe->comp);
- init_completion(&pipe->dmas_comp);
- pr_info("%s: pipe=%x ndx=%d num=%d share=%d cnt=%d\n",
- __func__, (int)pipe, pipe->pipe_ndx, pipe->pipe_num,
- pd->share, pd->ref_cnt);
- return pipe;
- }
-
- pr_debug("%s: ptype=%d mixer=%d req_share=%d FAILED\n",
- __func__, ptype, mixer, req_share);
+ pr_err("%s: ptype=%d FAILED\n", __func__, ptype);
return NULL;
}
@@ -1498,34 +1490,21 @@
void mdp4_overlay_pipe_free(struct mdp4_overlay_pipe *pipe)
{
- int i;
- uint32 ptype, num, ndx;
- struct mdp4_pipe_desc *pd;
+ uint32 ptype, num, ndx, mixer;
- pr_info("%s: pipe=%x ndx=%d\n", __func__,
- (int)pipe, pipe->pipe_ndx);
- pd = &ctrl->ov_pipe[pipe->pipe_num];
- if (pd->ref_cnt) {
- pd->ref_cnt--;
- for (i = 0; i < MDP4_MAX_SHARE; i++) {
- if (pd->ndx_list[i] == pipe->pipe_ndx) {
- pd->ndx_list[i] = 0;
- break;
- }
- }
- }
-
- pd->player = NULL;
+ pr_info("%s: pipe=%x ndx=%d\n", __func__, (int)pipe, pipe->pipe_ndx);
ptype = pipe->pipe_type;
num = pipe->pipe_num;
ndx = pipe->pipe_ndx;
+ mixer = pipe->mixer_num;
memset(pipe, 0, sizeof(*pipe));
pipe->pipe_type = ptype;
pipe->pipe_num = num;
pipe->pipe_ndx = ndx;
+ pipe->mixer_num = mixer;
}
int mdp4_overlay_req_check(uint32 id, uint32 z_order, uint32 mixer)
@@ -1614,8 +1593,8 @@
pr_debug("fillratex100 %lu, mdp_pixels_produced %lu\n",
fillratex100, mdp_pixels_produced);
if (mdp_pixels_produced <= mfd->panel_info.xres) {
- pr_err("%s(): LCDC underflow detected during downscale\n",
- __func__);
+ pr_err("%s():display underflow detected with downscale"
+ " params\n", __func__);
return -ERANGE;
}
@@ -1627,16 +1606,14 @@
struct msm_fb_data_type *mfd)
{
struct mdp4_overlay_pipe *pipe;
- struct mdp4_pipe_desc *pd;
- int ret, ptype, req_share;
- int j;
+ int ret, ptype;
if (mfd == NULL) {
pr_err("%s: mfd == NULL, -ENODEV\n", __func__);
return -ENODEV;
}
- if (mixer >= MDP4_MAX_MIXER) {
+ if (mixer >= MDP4_MIXER_MAX) {
pr_err("%s: mixer out of range!\n", __func__);
mdp4_stat.err_mixer++;
return -ERANGE;
@@ -1729,10 +1706,11 @@
return ptype;
}
- req_share = (req->flags & MDP_OV_PIPE_SHARE);
+ if (req->flags & MDP_OV_PIPE_SHARE)
+ ptype = OVERLAY_TYPE_VIDEO; /* VG pipe supports both RGB+YUV */
if (req->id == MSMFB_NEW_REQUEST) /* new request */
- pipe = mdp4_overlay_pipe_alloc(ptype, mixer, req_share);
+ pipe = mdp4_overlay_pipe_alloc(ptype, mixer);
else
pipe = mdp4_overlay_ndx2pipe(req->id);
@@ -1741,17 +1719,9 @@
return -ENOMEM;
}
- /* no down scale at rgb pipe */
- if (pipe->pipe_num <= OVERLAY_PIPE_RGB2) {
- if ((req->src_rect.h > req->dst_rect.h) ||
- (req->src_rect.w > req->dst_rect.w)) {
- pr_err("%s: h>h || w>w!\n", __func__);
- return -ERANGE;
- }
- }
-
pipe->src_format = req->src.format;
ret = mdp4_overlay_format2pipe(pipe);
+
if (ret < 0) {
pr_err("%s: mdp4_overlay_format2pipe!\n", __func__);
return ret;
@@ -1764,15 +1734,6 @@
* zorder 2 == stage 2 == 4
*/
if (req->id == MSMFB_NEW_REQUEST) { /* new request */
- pd = &ctrl->ov_pipe[pipe->pipe_num];
- for (j = 0; j < MDP4_MAX_SHARE; j++) {
- if (pd->ndx_list[j] == 0) {
- pd->ndx_list[j] = pipe->pipe_ndx;
- break;
- }
- }
- pipe->pipe_share = req_share;
- pd->ref_cnt++;
pipe->pipe_used++;
pipe->mixer_num = mixer;
pipe->mixer_stage = req->z_order + MDP4_MIXER_STAGE0;
@@ -1902,7 +1863,6 @@
}
#endif
-#ifdef CONFIG_FB_MSM_OVERLAY_WRITEBACK
int mdp4_overlay_blt(struct fb_info *info, struct msmfb_overlay_blt *req)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
@@ -1945,7 +1905,6 @@
return ret;
}
-#endif
int mdp4_overlay_get(struct fb_info *info, struct mdp_overlay *req)
{
@@ -1957,6 +1916,9 @@
*req = pipe->req_data;
+ if (mdp4_overlay_borderfill_supported())
+ req->flags |= MDP_BORDERFILL_SUPPORTED;
+
return 0;
}
@@ -2004,8 +1966,8 @@
else if (mdp4_overlay_is_rgb_type(req->src.format))
return OVERLAY_PERF_LEVEL1;
- if (ctrl->ov_pipe[OVERLAY_PIPE_VG1].ref_cnt &&
- ctrl->ov_pipe[OVERLAY_PIPE_VG2].ref_cnt)
+ if (ctrl->plist[OVERLAY_PIPE_VG1].pipe_used &&
+ ctrl->plist[OVERLAY_PIPE_VG2].pipe_used)
return OVERLAY_PERF_LEVEL1;
if (req->src.width*req->src.height <= OVERLAY_VGA_SIZE)
@@ -2037,6 +1999,60 @@
}
}
+static void mdp4_overlay_update_blt_mode(struct msm_fb_data_type *mfd)
+{
+ if (mfd->use_ov0_blt) {
+ if (mfd->panel_info.type == LCDC_PANEL)
+ mdp4_lcdc_overlay_blt_start(mfd);
+ else if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
+ mdp4_dsi_video_blt_start(mfd);
+ else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
+ mdp4_dsi_overlay_blt_start(mfd);
+ } else {
+ if (mfd->panel_info.type == LCDC_PANEL)
+ mdp4_lcdc_overlay_blt_stop(mfd);
+ else if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
+ mdp4_dsi_video_blt_stop(mfd);
+ else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
+ mdp4_dsi_overlay_blt_stop(mfd);
+ }
+}
+
+static u32 mdp4_overlay_blt_enable(struct mdp_overlay *req,
+ struct msm_fb_data_type *mfd, uint32 perf_level)
+{
+ u32 clk_rate = mfd->panel_info.clk_rate;
+ u32 pull_mode = 0, use_blt = 0;
+
+ if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
+ clk_rate = (&mfd->panel_info.mipi)->dsi_pclk_rate;
+
+ if ((mfd->panel_info.type == LCDC_PANEL) ||
+ (mfd->panel_info.type == MIPI_VIDEO_PANEL))
+ pull_mode = 1;
+
+ if (pull_mode && (req->src_rect.h > req->dst_rect.h ||
+ req->src_rect.w > req->dst_rect.w)) {
+ if (mdp4_overlay_validate_downscale(req, mfd, perf_level,
+ clk_rate))
+ use_blt = 1;
+ }
+
+ if (mfd->mdp_rev == MDP_REV_41) {
+ /*
+ * writeback (blt) mode to provide work around for
+ * dsi cmd mode interface hardware bug.
+ */
+ if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
+ if (req->dst_rect.x != 0)
+ use_blt = 1;
+ }
+ if (mfd->panel_info.xres > 1280)
+ use_blt = 1;
+ }
+ return use_blt;
+}
+
int mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
@@ -2061,22 +2077,6 @@
perf_level = mdp4_overlay_get_perf_level(req);
- if ((mfd->panel_info.type == LCDC_PANEL) &&
- (req->src_rect.h >
- req->dst_rect.h || req->src_rect.w > req->dst_rect.w)) {
- if (mdp4_overlay_validate_downscale(req, mfd,
- perf_level, mfd->panel_info.clk_rate))
- mdp4_lcdc_overlay_blt_start(mfd);
- }
-
- if ((mfd->panel_info.type == MIPI_VIDEO_PANEL) &&
- (req->src_rect.h >
- req->dst_rect.h || req->src_rect.w > req->dst_rect.w)) {
- if (mdp4_overlay_validate_downscale(req, mfd,
- perf_level, (&mfd->panel_info.mipi)->dsi_pclk_rate))
- mdp4_dsi_video_blt_start(mfd);
- }
-
mixer = mfd->panel_info.pdest; /* DISPLAY_1 or DISPLAY_2 */
ret = mdp4_overlay_req2pipe(req, mixer, &pipe, mfd);
@@ -2086,15 +2086,10 @@
return ret;
}
- /*
- * writeback (blt) mode to provide work around for
- * dsi cmd mode interface hardware bug.
- */
- if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
- if (mixer == MDP4_MIXER0 && req->dst_rect.x != 0) {
- mdp4_dsi_blt_dmap_busy_wait(mfd);
- mdp4_dsi_overlay_blt_start(mfd);
- }
+ if (mixer == MDP4_MIXER0) {
+ u32 use_blt = mdp4_overlay_blt_enable(req, mfd, perf_level);
+ mfd->use_ov0_blt &= ~(1 << (pipe->pipe_ndx-1));
+ mfd->use_ov0_blt |= (use_blt << (pipe->pipe_ndx-1));
}
/* return id back to user */
@@ -2114,6 +2109,10 @@
}
}
+ /* precompute HSIC matrices */
+ if (req->flags & MDP_DPP_HSIC)
+ mdp4_hsic_set(pipe, &(req->dpp));
+
mdp4_stat.overlay_set[pipe->mixer_num]++;
if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
@@ -2122,6 +2121,10 @@
mdp4_overlay_status_write(MDP4_OVERLAY_TYPE_SET, true);
}
+ if (ctrl->panel_mode & MDP4_PANEL_DTV &&
+ pipe->mixer_num == MDP4_MIXER1)
+ mdp4_overlay_dtv_set(mfd, pipe);
+
if (new_perf_level != perf_level) {
mdp4_update_perf_level(perf_level);
@@ -2144,10 +2147,8 @@
mdp4_overlay_dtv_vsync_push(mfd, pipe);
}
}
-
mutex_unlock(&mfd->dma->ov_mutex);
-
#ifdef CONFIG_MSM_BUS_SCALING
if (pipe->mixer_num == MDP4_MIXER0) {
mdp_bus_scale_update_request(OVERLAY_BUS_SCALE_TABLE_BASE
@@ -2163,6 +2164,8 @@
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
struct mdp4_overlay_pipe *pipe;
uint32 flags;
+ struct dpp_ctrl dpp;
+ int i;
if (mfd == NULL)
return -ENODEV;
@@ -2199,11 +2202,11 @@
mdp4_mixer_stage_down(pipe);
if (pipe->mixer_num == MDP4_MIXER0) {
+
#ifdef CONFIG_FB_MSM_MIPI_DSI
if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
if (mfd->panel_power_on)
- if (mdp4_dsi_overlay_blt_stop(mfd) == 0)
- mdp4_dsi_cmd_overlay_restore();
+ mdp4_dsi_cmd_overlay_restore();
} else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
mdp4_overlay_reg_flush(pipe, 1);
if (mfd->panel_power_on) {
@@ -2212,7 +2215,6 @@
mdp4_overlay_dsi_video_vsync_push(mfd, pipe);
pipe->flags = flags;
}
- mdp4_dsi_video_blt_stop(mfd);
}
#else
if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
@@ -2231,29 +2233,34 @@
mdp4_overlay_lcdc_vsync_push(mfd, pipe);
pipe->flags = flags;
}
- mdp4_lcdc_overlay_blt_stop(mfd);
}
+
+ mfd->use_ov0_blt &= ~(1 << (pipe->pipe_ndx-1));
+ mdp4_overlay_update_blt_mode(mfd);
+ mfd->ov0_blt_state = mfd->use_ov0_blt;
+
}
-#ifdef CONFIG_FB_MSM_DTV
else { /* mixer1, DTV, ATV */
- if (ctrl->panel_mode & MDP4_PANEL_DTV) {
- if (mfd->panel_power_on) {
- flags = pipe->flags;
- pipe->flags &= ~MDP_OV_PLAY_NOWAIT;
- mdp4_overlay_dtv_vsync_push(mfd, pipe);
- pipe->flags = flags;
- }
- }
+ if (ctrl->panel_mode & MDP4_PANEL_DTV)
+ mdp4_overlay_dtv_unset(mfd, pipe);
}
-#endif
+
+ /* Reset any HSIC settings to default */
+ if (pipe->flags & MDP_DPP_HSIC) {
+ for (i = 0; i < NUM_HSIC_PARAM; i++)
+ dpp.hsic_params[i] = 0;
+
+ mdp4_hsic_set(pipe, &dpp);
+ mdp4_hsic_update(pipe);
+ }
mdp4_stat.overlay_unset[pipe->mixer_num]++;
mdp4_overlay_pipe_free(pipe);
- if (!(ctrl->ov_pipe[OVERLAY_PIPE_VG1].ref_cnt +
- ctrl->ov_pipe[OVERLAY_PIPE_VG2].ref_cnt))
- mdp4_update_perf_level(OVERLAY_PERF_LEVEL4);
+ if (!(ctrl->plist[OVERLAY_PIPE_VG1].pipe_used +
+ ctrl->plist[OVERLAY_PIPE_VG2].pipe_used))
+ mdp4_update_perf_level(OVERLAY_PERF_LEVEL4);
mutex_unlock(&mfd->dma->ov_mutex);
@@ -2329,7 +2336,6 @@
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
struct msmfb_data *img;
struct mdp4_overlay_pipe *pipe;
- struct mdp4_pipe_desc *pd;
ulong start, addr;
ulong len = 0;
struct file *srcp0_file = NULL;
@@ -2354,16 +2360,6 @@
if (mutex_lock_interruptible(&mfd->dma->ov_mutex))
return -EINTR;
- pd = &ctrl->ov_pipe[pipe->pipe_num];
- if (pd->player && pipe != pd->player) {
- if (pipe->pipe_type == OVERLAY_TYPE_RGB) {
- mutex_unlock(&mfd->dma->ov_mutex);
- return 0; /* ignore it, kicked out already */
- }
- }
-
- pd->player = pipe; /* keep */
-
img = &req->data;
get_img(img, info, &start, &len, &srcp0_file, &srcp0_ihdl);
if (len == 0) {
@@ -2467,6 +2463,11 @@
}
}
+ if (mfd->use_ov0_blt != mfd->ov0_blt_state) {
+ mdp4_overlay_update_blt_mode(mfd);
+ mfd->ov0_blt_state = mfd->use_ov0_blt;
+ }
+
if (pipe->pipe_num >= OVERLAY_PIPE_VG1)
mdp4_overlay_vg_setup(pipe); /* video/graphic pipe */
else {
@@ -2533,6 +2534,10 @@
}
}
+ /* write out DPP HSIC registers */
+ if (pipe->flags & MDP_DPP_HSIC)
+ mdp4_hsic_update(pipe);
+
mdp4_stat.overlay_play[pipe->mixer_num]++;
mutex_unlock(&mfd->dma->ov_mutex);
end:
diff --git a/drivers/video/msm/mdp4_overlay_atv.c b/drivers/video/msm/mdp4_overlay_atv.c
index 420a9bc..f9951e9 100644
--- a/drivers/video/msm/mdp4_overlay_atv.c
+++ b/drivers/video/msm/mdp4_overlay_atv.c
@@ -62,7 +62,7 @@
if (atv_pipe == NULL) {
ptype = mdp4_overlay_format2type(mfd->fb_imgType);
- pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER1, 0);
+ pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER1);
if (pipe == NULL)
return -EBUSY;
pipe->pipe_used++;
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index 07322dc..4479ece 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -65,7 +65,6 @@
{
if (mipi_dsi_clk_on) {
if (dsi_state == ST_DSI_PLAYING) {
- mdp4_stat.dsi_clkoff++;
mipi_dsi_turn_off_clks();
mdp4_overlay_dsi_state_set(ST_DSI_CLK_OFF);
}
@@ -139,7 +138,7 @@
ptype = mdp4_overlay_format2type(mfd->fb_imgType);
if (ptype < 0)
printk(KERN_INFO "%s: format2type failed\n", __func__);
- pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0, 0);
+ pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0);
if (pipe == NULL)
printk(KERN_INFO "%s: pipe_alloc failed\n", __func__);
pipe->pipe_used++;
@@ -303,8 +302,6 @@
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
-
-#ifdef CONFIG_FB_MSM_OVERLAY_WRITEBACK
int mdp4_dsi_overlay_blt_start(struct msm_fb_data_type *mfd)
{
unsigned long flag;
@@ -325,7 +322,7 @@
dsi_pipe->ov_cnt = 0;
dsi_pipe->dmap_cnt = 0;
dsi_pipe->blt_addr = dsi_pipe->blt_base;
- mdp4_stat.writeback++;
+ mdp4_stat.blt_dsi_cmd++;
spin_unlock_irqrestore(&mdp_spin_lock, flag);
return 0;
}
@@ -371,21 +368,6 @@
mdp4_dsi_overlay_blt_stop(mfd);
}
-#else
-int mdp4_dsi_overlay_blt_offset(struct msm_fb_data_type *mfd,
- struct msmfb_overlay_blt *req)
-{
- return 0;
-}
-int mdp4_dsi_overlay_blt_start(struct msm_fb_data_type *mfd)
-{
- return -EBUSY;
-}
-int mdp4_dsi_overlay_blt_stop(struct msm_fb_data_type *mfd)
-{
- return -EBUSY;
-}
-#endif
void mdp4_blt_xy_update(struct mdp4_overlay_pipe *pipe)
{
@@ -465,6 +447,7 @@
mdp4_blt_xy_update(dsi_pipe);
/* kick off dmap */
outpdw(MDP_BASE + 0x000c, 0x0);
+ mdp4_stat.kickoff_dmap++;
/* trigger dsi cmd engine */
mipi_dsi_cmd_mdp_start();
@@ -525,6 +508,7 @@
mdp_enable_irq(MDP_DMA2_TERM); /* enable intr */
/* kick off dmap */
outpdw(MDP_BASE + 0x000c, 0x0);
+ mdp4_stat.kickoff_dmap++;
/* trigger dsi cmd engine */
mipi_dsi_cmd_mdp_start();
mdp_disable_irq_nosync(MDP_OVERLAY0_TERM);
@@ -615,10 +599,21 @@
void mdp4_dsi_cmd_kickoff_video(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe)
{
+ /*
+ * a video kickoff may happen before UI kickoff after
+ * blt enabled. mdp4_overlay_update_dsi_cmd() need
+ * to be called before kickoff.
+ * vice versa for blt disabled.
+ */
if (dsi_pipe->blt_addr && dsi_pipe->blt_cnt == 0)
- mdp4_overlay_update_dsi_cmd(mfd);
+ mdp4_overlay_update_dsi_cmd(mfd); /* first time */
+ else if (dsi_pipe->blt_addr == 0 && dsi_pipe->blt_cnt) {
+ mdp4_overlay_update_dsi_cmd(mfd); /* last time */
+ dsi_pipe->blt_cnt = 0;
+ }
- pr_debug("%s: pid=%d\n", __func__, current->pid);
+ pr_debug("%s: blt_addr=%d blt_cnt=%d\n",
+ __func__, (int)dsi_pipe->blt_addr, dsi_pipe->blt_cnt);
if (dsi_pipe->blt_addr)
mdp4_dsi_blt_dmap_busy_wait(dsi_mfd);
@@ -659,6 +654,7 @@
/* start OVERLAY pipe */
spin_unlock_irqrestore(&mdp_spin_lock, flag);
mdp_pipe_kickoff(MDP_OVERLAY0_TERM, mfd);
+ mdp4_stat.kickoff_ov0++;
}
void mdp4_dsi_cmd_overlay(struct msm_fb_data_type *mfd)
@@ -675,9 +671,6 @@
mdp4_dsi_cmd_kickoff_ui(mfd, dsi_pipe);
-
- mdp4_stat.kickoff_dsi++;
-
/* signal if pan function is waiting for the update completion */
if (mfd->pan_waiting) {
mfd->pan_waiting = FALSE;
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 4e47093..938d7c6 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -124,7 +124,7 @@
ptype = mdp4_overlay_format2type(mfd->fb_imgType);
if (ptype < 0)
printk(KERN_INFO "%s: format2type failed\n", __func__);
- pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0, 0);
+ pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0);
if (pipe == NULL) {
printk(KERN_INFO "%s: pipe_alloc failed\n", __func__);
return -EBUSY;
@@ -479,29 +479,6 @@
mdp4_set_perf_level();
}
-static void mdp4_overlay_dsi_video_prefill(struct msm_fb_data_type *mfd)
-{
- unsigned long flag;
-
- if (dsi_pipe->blt_addr) {
- mdp4_overlay_dsi_video_dma_busy_wait(mfd);
-
- mdp4_dsi_video_blt_ov_update(dsi_pipe);
- dsi_pipe->ov_cnt++;
-
- spin_lock_irqsave(&mdp_spin_lock, flag);
- outp32(MDP_INTR_CLEAR, INTR_OVERLAY0_DONE);
- mdp_intr_mask |= INTR_OVERLAY0_DONE;
- outp32(MDP_INTR_ENABLE, mdp_intr_mask);
- mdp_enable_irq(MDP_OVERLAY0_TERM);
- mfd->dma->busy = TRUE;
- mb(); /* make sure all registers updated */
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
- outpdw(MDP_BASE + 0x0004, 0); /* kickoff overlay engine */
- mb();
- }
-}
-
void mdp4_overlay_dsi_video_vsync_push(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe)
{
@@ -525,6 +502,7 @@
mb(); /* make sure all registers updated */
spin_unlock_irqrestore(&mdp_spin_lock, flag);
outpdw(MDP_BASE + 0x0004, 0); /* kickoff overlay engine */
+ mdp4_stat.kickoff_ov0++;
mb();
mdp4_overlay_dsi_video_wait4event(mfd, INTR_DMA_P_DONE);
} else {
@@ -567,7 +545,30 @@
complete(&dma->comp);
}
-#ifdef CONFIG_FB_MSM_OVERLAY_WRITEBACK
+static void mdp4_overlay_dsi_video_prefill(struct msm_fb_data_type *mfd)
+{
+ unsigned long flag;
+
+ if (dsi_pipe->blt_addr) {
+ mdp4_overlay_dsi_video_dma_busy_wait(mfd);
+
+ mdp4_dsi_video_blt_ov_update(dsi_pipe);
+ dsi_pipe->ov_cnt++;
+
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ outp32(MDP_INTR_CLEAR, INTR_OVERLAY0_DONE);
+ mdp_intr_mask |= INTR_OVERLAY0_DONE;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ mdp_enable_irq(MDP_OVERLAY0_TERM);
+ mfd->dma->busy = TRUE;
+ mb(); /* make sure all registers updated */
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+ outpdw(MDP_BASE + 0x0004, 0); /* kickoff overlay engine */
+ mdp4_stat.kickoff_ov0++;
+ mb();
+ }
+}
+
/*
* make sure the MIPI_DSI_WRITEBACK_SIZE defined at boardfile
* has enough space h * w * 3 * 2
@@ -589,6 +590,7 @@
dsi_pipe->blt_cnt = 0;
dsi_pipe->ov_cnt = 0;
dsi_pipe->dmap_cnt = 0;
+ mdp4_stat.blt_dsi_video++;
change++;
} else if (enable == 0 && dsi_pipe->blt_addr) {
dsi_pipe->blt_addr = 0;
@@ -655,24 +657,6 @@
{
mdp4_dsi_video_do_blt(mfd, 0);
}
-#else
-int mdp4_dsi_video_overlay_blt_offset(struct msm_fb_data_type *mfd,
- struct msmfb_overlay_blt *req)
-{
- return 0;
-}
-void mdp4_dsi_video_overlay_blt(struct msm_fb_data_type *mfd,
- struct msmfb_overlay_blt *req)
-{
- return;
-}
-void mdp4_dsi_video_blt_start(struct msm_fb_data_type *mfd)
-{
-}
-void mdp4_dsi_video_blt_stop(struct msm_fb_data_type *mfd)
-{
-}
-#endif
void mdp4_dsi_video_overlay(struct msm_fb_data_type *mfd)
{
@@ -698,5 +682,4 @@
mdp4_overlay_reg_flush(pipe, 1);
mdp4_overlay_dsi_video_vsync_push(mfd, pipe);
mutex_unlock(&mfd->dma->ov_mutex);
- mdp4_stat.kickoff_dsi++;
}
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index 13449d6..c8135d4 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -54,7 +54,7 @@
static struct mdp4_overlay_pipe *dtv_pipe;
-int mdp4_dtv_on(struct platform_device *pdev)
+static int mdp4_dtv_start(struct msm_fb_data_type *mfd)
{
int dtv_width;
int dtv_height;
@@ -86,16 +86,8 @@
int data_en_polarity;
int hsync_start_x;
int hsync_end_x;
- uint8 *buf;
- int bpp, ptype;
- uint32 format;
struct fb_info *fbi;
struct fb_var_screeninfo *var;
- struct msm_fb_data_type *mfd;
- struct mdp4_overlay_pipe *pipe;
- int ret;
-
- mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
@@ -103,50 +95,12 @@
if (mfd->key != MFD_KEY)
return -EINVAL;
+ if (dtv_pipe == NULL)
+ return -EINVAL;
+
fbi = mfd->fbi;
var = &fbi->var;
- bpp = fbi->var.bits_per_pixel / 8;
- buf = (uint8 *) fbi->fix.smem_start;
- buf += fbi->var.xoffset * bpp +
- fbi->var.yoffset * fbi->fix.line_length;
-
- if (bpp == 2)
- format = MDP_RGB_565;
- else if (bpp == 3)
- format = MDP_RGB_888;
- else {
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
- format = MSMFB_DEFAULT_TYPE;
-#else
- format = MDP_ARGB_8888;
-#endif
- }
-
- if (dtv_pipe == NULL) {
- ptype = mdp4_overlay_format2type(format);
- if (ptype < 0)
- printk(KERN_INFO "%s: format2type failed\n", __func__);
- pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER1, 0);
- if (pipe == NULL) {
- printk(KERN_INFO "%s: pipe_alloc failed\n", __func__);
- return -EBUSY;
- }
- pipe->pipe_used++;
- pipe->mixer_stage = MDP4_MIXER_STAGE_BASE;
- pipe->mixer_num = MDP4_MIXER1;
- pipe->src_format = format;
- mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_DTV);
- ret = mdp4_overlay_format2pipe(pipe);
- if (ret < 0)
- printk(KERN_INFO "%s: format2type failed\n", __func__);
-
- dtv_pipe = pipe; /* keep it */
- } else {
- pipe = dtv_pipe;
- }
-
- /* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
if (is_mdp4_hw_reset()) {
@@ -154,24 +108,8 @@
outpdw(MDP_BASE + 0x0038, mdp4_display_intf);
}
#endif
- pipe->src_height = fbi->var.yres;
- pipe->src_width = fbi->var.xres;
- pipe->src_h = fbi->var.yres;
- pipe->src_w = fbi->var.xres;
- pipe->src_y = 0;
- pipe->src_x = 0;
- pipe->srcp0_addr = (uint32) buf;
- pipe->srcp0_ystride = fbi->fix.line_length;
-
- mdp4_overlay_dmae_xy(pipe); /* dma_e */
mdp4_overlay_dmae_cfg(mfd, 0);
- mdp4_overlay_rgb_setup(pipe);
-
- mdp4_mixer_stage_up(pipe);
-
- mdp4_overlayproc_cfg(pipe);
-
/*
* DTV timing setting
*/
@@ -255,24 +193,19 @@
/* Test pattern 8 x 8 pixel */
/* MDP_OUTP(MDP_BASE + DTV_BASE + 0x4C, 0x80000808); */
- ret = panel_next_on(pdev);
- if (ret == 0) {
- /* enable DTV block */
- MDP_OUTP(MDP_BASE + DTV_BASE, 1);
- mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- dev_info(&pdev->dev, "mdp4_overlay_dtv: on");
- } else {
- dev_warn(&pdev->dev, "mdp4_overlay_dtv: panel_next_on failed");
- }
+ /* enable DTV block */
+ MDP_OUTP(MDP_BASE + DTV_BASE, 1);
+ mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
- return ret;
+ return 0;
}
-int mdp4_dtv_off(struct platform_device *pdev)
+static int mdp4_dtv_stop(struct msm_fb_data_type *mfd)
{
- int ret = 0;
+ if (dtv_pipe == NULL)
+ return -EINVAL;
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
@@ -286,24 +219,56 @@
* the last frame finishes
*/
msleep(20);
- pr_info("%s\n", __func__);
- ret = panel_next_off(pdev);
+ return 0;
+}
- /* dis-engage rgb2 from mixer1 */
- if (dtv_pipe)
+int mdp4_dtv_on(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd;
+ int ret = 0;
+
+ mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+
+ if (!mfd)
+ return -ENODEV;
+
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ mdp4_overlay_panel_mode(MDP4_MIXER1, MDP4_PANEL_DTV);
+ if (dtv_pipe != NULL)
+ ret = mdp4_dtv_start(mfd);
+
+ ret = panel_next_on(pdev);
+ if (ret != 0)
+ dev_warn(&pdev->dev, "mdp4_overlay_dtv: panel_next_on failed");
+
+ dev_info(&pdev->dev, "mdp4_overlay_dtv: on");
+
+ return ret;
+}
+
+int mdp4_dtv_off(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd;
+ int ret = 0;
+
+ mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+
+ if (dtv_pipe != NULL) {
mdp4_mixer_stage_down(dtv_pipe);
-
- /*
- * wait for another vsync == 16.6 ms to make sure
- * rgb2 dis-engaged
- */
- msleep(20);
- if (dtv_pipe) {
+ mdp4_dtv_stop(mfd);
mdp4_overlay_pipe_free(dtv_pipe);
dtv_pipe = NULL;
}
+ mdp4_overlay_panel_mode_unset(MDP4_MIXER1, MDP4_PANEL_DTV);
+ ret = panel_next_off(pdev);
+
+ msleep(20);
+
+ dev_info(&pdev->dev, "mdp4_overlay_dtv: off");
return ret;
}
@@ -327,7 +292,6 @@
void mdp4_overlay_dtv_vsync_push(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe)
{
-
mdp4_overlay_reg_flush(pipe, 1);
if (pipe->flags & MDP_OV_PLAY_NOWAIT)
return;
@@ -338,6 +302,114 @@
mdp4_set_perf_level();
}
+static void mdp4_overlay_dtv_alloc_pipe(struct msm_fb_data_type *mfd,
+ int32 ptype)
+{
+ int ret = 0;
+ struct fb_info *fbi = mfd->fbi;
+ struct mdp4_overlay_pipe *pipe;
+
+ if (dtv_pipe != NULL)
+ return;
+
+ pr_debug("%s: ptype=%d\n", __func__, ptype);
+
+ pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER1);
+ if (pipe == NULL) {
+ pr_err("%s: pipe_alloc failed\n", __func__);
+ return;
+ }
+ pipe->pipe_used++;
+ pipe->mixer_stage = MDP4_MIXER_STAGE_BASE;
+ pipe->mixer_num = MDP4_MIXER1;
+
+ if (ptype == OVERLAY_TYPE_BF) {
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ /* LSP_BORDER_COLOR */
+ MDP_OUTP(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x5004,
+ ((0x0 & 0xFFF) << 16) | /* 12-bit B */
+ (0x0 & 0xFFF)); /* 12-bit G */
+ /* MSP_BORDER_COLOR */
+ MDP_OUTP(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x5008,
+ (0x0 & 0xFFF)); /* 12-bit R */
+ mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+ pipe->src_format = MDP_ARGB_8888;
+ } else {
+ switch (mfd->ibuf.bpp) {
+ case 2:
+ pipe->src_format = MDP_RGB_565;
+ break;
+ case 3:
+ pipe->src_format = MDP_RGB_888;
+ break;
+ case 4:
+ default:
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+ pipe->src_format = MSMFB_DEFAULT_TYPE;
+#else
+ pipe->src_format = MDP_ARGB_8888;
+#endif
+ break;
+ }
+ }
+
+ pipe->src_height = fbi->var.yres;
+ pipe->src_width = fbi->var.xres;
+ pipe->src_h = fbi->var.yres;
+ pipe->src_w = fbi->var.xres;
+ pipe->src_y = 0;
+ pipe->src_x = 0;
+ pipe->srcp0_ystride = fbi->fix.line_length;
+
+ ret = mdp4_overlay_format2pipe(pipe);
+ if (ret < 0)
+ pr_warn("%s: format2type failed\n", __func__);
+
+ mdp4_overlay_dmae_xy(pipe); /* dma_e */
+ mdp4_overlayproc_cfg(pipe);
+ mdp4_mixer_stage_up(pipe);
+
+ dtv_pipe = pipe; /* keep it */
+}
+
+int mdp4_overlay_dtv_set(struct msm_fb_data_type *mfd,
+ struct mdp4_overlay_pipe *pipe)
+{
+ if (dtv_pipe != NULL)
+ return 0;
+
+ if (pipe != NULL && pipe->mixer_stage == MDP4_MIXER_STAGE_BASE &&
+ pipe->pipe_type == OVERLAY_TYPE_RGB)
+ dtv_pipe = pipe; /* keep it */
+ else if (mdp4_overlay_borderfill_supported())
+ mdp4_overlay_dtv_alloc_pipe(mfd, OVERLAY_TYPE_BF);
+ else
+ mdp4_overlay_dtv_alloc_pipe(mfd, OVERLAY_TYPE_RGB);
+ if (dtv_pipe == NULL)
+ return -ENODEV;
+ return mdp4_dtv_start(mfd);
+}
+
+int mdp4_overlay_dtv_unset(struct msm_fb_data_type *mfd,
+ struct mdp4_overlay_pipe *pipe)
+{
+ unsigned int flags;
+ int result = 0;
+
+ flags = pipe->flags;
+ pipe->flags &= ~MDP_OV_PLAY_NOWAIT;
+ mdp4_overlay_dtv_vsync_push(mfd, pipe);
+ pipe->flags = flags;
+
+ if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE &&
+ pipe->pipe_type == OVERLAY_TYPE_RGB) {
+ result = mdp4_dtv_stop(mfd);
+ dtv_pipe = NULL;
+ }
+ return result;
+}
+
static void mdp4_overlay_dtv_ov_start(struct msm_fb_data_type *mfd)
{
unsigned long flag;
@@ -370,7 +442,6 @@
void mdp4_overlay_dtv_ov_done_push(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe)
{
-
mdp4_overlay_reg_flush(pipe, 1);
mdp4_overlay_dtv_ov_start(mfd);
@@ -439,32 +510,29 @@
void mdp4_dtv_overlay(struct msm_fb_data_type *mfd)
{
- struct fb_info *fbi = mfd->fbi;
- uint8 *buf;
- int bpp;
struct mdp4_overlay_pipe *pipe;
if (!mfd->panel_power_on)
return;
- /* no need to power on cmd block since it's lcdc mode */
- bpp = fbi->var.bits_per_pixel / 8;
- buf = (uint8 *) fbi->fix.smem_start;
- buf += fbi->var.xoffset * bpp +
- fbi->var.yoffset * fbi->fix.line_length;
-
mutex_lock(&mfd->dma->ov_mutex);
+ if (dtv_pipe == NULL) {
+ if (mdp4_overlay_dtv_set(mfd, NULL)) {
+ pr_warn("%s: dtv_pipe == NULL\n", __func__);
+ mutex_unlock(&mfd->dma->ov_mutex);
+ return;
+ }
+ }
pipe = dtv_pipe;
- pipe->srcp0_addr = (uint32) buf;
- mdp4_overlay_rgb_setup(pipe);
-
+ if (pipe->pipe_type == OVERLAY_TYPE_RGB) {
+ pipe->srcp0_addr = (uint32) mfd->ibuf.buf;
+ mdp4_overlay_rgb_setup(pipe);
+ }
if (mfd->ov_start) {
mdp4_overlay_dtv_wait4_ov_done(mfd, pipe);
mfd->ov_end = true;
}
mdp4_overlay_dtv_ov_done_push(mfd, pipe);
-
- mdp4_stat.kickoff_dtv++;
mutex_unlock(&mfd->dma->ov_mutex);
}
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index 75264ef..f318691 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -114,7 +114,7 @@
ptype = mdp4_overlay_format2type(mfd->fb_imgType);
if (ptype < 0)
printk(KERN_INFO "%s: format2type failed\n", __func__);
- pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0, 0);
+ pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0);
if (pipe == NULL)
printk(KERN_INFO "%s: pipe_alloc failed\n", __func__);
pipe->pipe_used++;
@@ -422,6 +422,7 @@
mb(); /* make sure all registers updated */
spin_unlock_irqrestore(&mdp_spin_lock, flag);
outpdw(MDP_BASE + 0x0004, 0); /* kickoff overlay engine */
+ mdp4_stat.kickoff_ov0++;
mb();
mdp4_overlay_lcdc_wait4event(mfd, INTR_DMA_P_DONE);
} else {
@@ -463,7 +464,6 @@
complete(&dma->comp);
}
-#ifdef CONFIG_FB_MSM_OVERLAY_WRITEBACK
/*
* make sure the MIPI_DSI_WRITEBACK_SIZE defined at boardfile
* has enough space h * w * 3 * 2
@@ -485,6 +485,7 @@
lcdc_pipe->blt_cnt = 0;
lcdc_pipe->ov_cnt = 0;
lcdc_pipe->dmap_cnt = 0;
+ mdp4_stat.blt_lcdc++;
} else if (enable == 0 && lcdc_pipe->blt_addr) {
lcdc_pipe->blt_addr = 0;
change++;
@@ -529,24 +530,6 @@
{
mdp4_lcdc_do_blt(mfd, 0);
}
-#else
-int mdp4_lcdc_overlay_blt_offset(struct msm_fb_data_type *mfd,
- struct msmfb_overlay_blt *req)
-{
- return 0;
-}
-void mdp4_lcdc_overlay_blt(struct msm_fb_data_type *mfd,
- struct msmfb_overlay_blt *req)
-{
- return;
-}
-void mdp4_lcdc_overlay_blt_start(struct msm_fb_data_type *mfd)
-{
-}
-void mdp4_lcdc_overlay_blt_stop(struct msm_fb_data_type *mfd)
-{
-}
-#endif
void mdp4_lcdc_overlay(struct msm_fb_data_type *mfd)
{
@@ -572,5 +555,4 @@
mdp4_overlay_reg_flush(pipe, 1);
mdp4_overlay_lcdc_vsync_push(mfd, pipe);
mutex_unlock(&mfd->dma->ov_mutex);
- mdp4_stat.kickoff_lcdc++;
}
diff --git a/drivers/video/msm/mdp4_overlay_mddi.c b/drivers/video/msm/mdp4_overlay_mddi.c
index bd94c56..83959df 100644
--- a/drivers/video/msm/mdp4_overlay_mddi.c
+++ b/drivers/video/msm/mdp4_overlay_mddi.c
@@ -112,7 +112,7 @@
ptype = mdp4_overlay_format2type(mfd->fb_imgType);
if (ptype < 0)
printk(KERN_INFO "%s: format2type failed\n", __func__);
- pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0, 0);
+ pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0);
if (pipe == NULL)
printk(KERN_INFO "%s: pipe_alloc failed\n", __func__);
pipe->pipe_used++;
@@ -475,6 +475,7 @@
mfd->dma->busy = TRUE;
/* start OVERLAY pipe */
mdp_pipe_kickoff(MDP_OVERLAY0_TERM, mfd);
+ mdp4_stat.kickoff_ov0++;
}
void mdp4_dma_s_update_lcd(struct msm_fb_data_type *mfd,
@@ -557,6 +558,7 @@
mfd->ibuf_flushed = TRUE;
/* start dma_s pipe */
mdp_pipe_kickoff(MDP_DMA_S_TERM, mfd);
+ mdp4_stat.kickoff_dmas++;
/* wait until DMA finishes the current job */
wait_for_completion(&mfd->dma->comp);
@@ -593,8 +595,6 @@
} else /* no dams dmap switch */
mdp4_mddi_kickoff_ui(mfd, mddi_pipe);
- mdp4_stat.kickoff_mddi++;
-
/* signal if pan function is waiting for the update completion */
if (mfd->pan_waiting) {
mfd->pan_waiting = FALSE;
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index 8370208..f51427c 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -258,6 +258,12 @@
mdp4_sw_reset(0x17);
#endif
+ if (mdp_rev > MDP_REV_41) {
+ /* mdp chip select controller */
+ outpdw(MDP_BASE + 0x00c0, CS_CONTROLLER_0);
+ outpdw(MDP_BASE + 0x00c4, CS_CONTROLLER_1);
+ }
+
mdp4_clear_lcdc();
mdp4_mixer_blend_init(0);
@@ -394,6 +400,7 @@
panel = mdp4_overlay_panel_list();
if (isr & INTR_PRIMARY_VSYNC) {
+ mdp4_stat.intr_vsync_p++;
dma = &dma2_data;
spin_lock(&mdp_spin_lock);
mdp_intr_mask &= ~INTR_PRIMARY_VSYNC;
@@ -409,6 +416,7 @@
}
#ifdef CONFIG_FB_MSM_DTV
if (isr & INTR_EXTERNAL_VSYNC) {
+ mdp4_stat.intr_vsync_e++;
dma = &dma_e_data;
spin_lock(&mdp_spin_lock);
mdp_intr_mask &= ~INTR_EXTERNAL_VSYNC;
@@ -542,6 +550,7 @@
spin_unlock(&mdp_spin_lock);
}
if (isr & INTR_DMA_P_HISTOGRAM) {
+ mdp4_stat.intr_histogram++;
isr = inpdw(MDP_DMA_P_HIST_INTR_STATUS);
mask = inpdw(MDP_DMA_P_HIST_INTR_ENABLE);
outpdw(MDP_DMA_P_HIST_INTR_CLEAR, isr);
diff --git a/drivers/video/msm/mdp_debugfs.c b/drivers/video/msm/mdp_debugfs.c
index b89e8c7..9ae1d9c 100644
--- a/drivers/video/msm/mdp_debugfs.c
+++ b/drivers/video/msm/mdp_debugfs.c
@@ -272,7 +272,6 @@
int tot = 0;
int dlen;
char *bp;
- unsigned long flag;
if (*ppos)
@@ -281,124 +280,210 @@
bp = debug_buf;
dlen = sizeof(debug_buf);
- spin_lock_irqsave(&mdp_spin_lock, flag);
- len = snprintf(bp, dlen, "intr_total: %08lu\n",
+ len = snprintf(bp, dlen, "\nmdp:\n");
+ bp += len;
+ dlen -= len;
+
+ len = snprintf(bp, dlen, "int_total: %08lu\t",
mdp4_stat.intr_tot);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "intr_dma_p: %08lu\n",
- mdp4_stat.intr_dma_p);
- bp += len;
- dlen -= len;
- len = snprintf(bp, dlen, "intr_dma_s: %08lu\n",
- mdp4_stat.intr_dma_s);
- bp += len;
- dlen -= len;
- len = snprintf(bp, dlen, "intr_dma_e: %08lu\n",
- mdp4_stat.intr_dma_e);
- bp += len;
- dlen -= len;
- len = snprintf(bp, dlen, "intr_overlay0: %08lu\n",
+
+ len = snprintf(bp, dlen, "int_overlay0: %08lu\t",
mdp4_stat.intr_overlay0);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "intr_overlay1: %08lu\n",
+ len = snprintf(bp, dlen, "int_overlay1: %08lu\n",
mdp4_stat.intr_overlay1);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "unerrun_primary: %08lu\n",
+
+ len = snprintf(bp, dlen, "int_dmap: %08lu\t",
+ mdp4_stat.intr_dma_p);
+ bp += len;
+ dlen -= len;
+ len = snprintf(bp, dlen, "int_dmas: %08lu\t",
+ mdp4_stat.intr_dma_s);
+ bp += len;
+ dlen -= len;
+ len = snprintf(bp, dlen, "int_dmae: %08lu\n",
+ mdp4_stat.intr_dma_e);
+ bp += len;
+ dlen -= len;
+
+ len = snprintf(bp, dlen, "primary: vsync: %08lu\t",
+ mdp4_stat.intr_vsync_p);
+ bp += len;
+ dlen -= len;
+ len = snprintf(bp, dlen, "underrun: %08lu\n",
mdp4_stat.intr_underrun_p);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "unerrun_external: %08lu\n\n",
+ len = snprintf(bp, dlen, "external: vsync: %08lu\t",
+ mdp4_stat.intr_vsync_e);
+ bp += len;
+ dlen -= len;
+ len = snprintf(bp, dlen, "underrun: %08lu\n",
mdp4_stat.intr_underrun_e);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "intr_dsi : %08lu\n\n",
- mdp4_stat.intr_dsi);
+ len = snprintf(bp, dlen, "histogram: %08lu\t",
+ mdp4_stat.intr_histogram);
+ bp += len;
+ dlen -= len;
+ len = snprintf(bp, dlen, "read_ptr: %08lu\n\n",
+ mdp4_stat.intr_rd_ptr);
+ bp += len;
+ dlen -= len;
+ len = snprintf(bp, dlen, "dsi:\n");
+ bp += len;
+ dlen -= len;
+ len = snprintf(bp, dlen, "int_total: %08lu\tmdp_start: %08lu\n",
+ mdp4_stat.intr_dsi, mdp4_stat.dsi_mdp_start);
+ bp += len;
+ dlen -= len;
+ len = snprintf(bp, dlen, "int_cmd: %08lu\t",
+ mdp4_stat.intr_dsi_cmd);
bp += len;
dlen -= len;
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
-
- len = snprintf(bp, dlen, "kickoff_mddi: %08lu\n",
- mdp4_stat.kickoff_mddi);
- bp += len;
- dlen -= len;
- len = snprintf(bp, dlen, "kickoff_lcdc: %08lu\n",
- mdp4_stat.kickoff_lcdc);
- bp += len;
- dlen -= len;
- len = snprintf(bp, dlen, "kickoff_dtv: %08lu\n",
- mdp4_stat.kickoff_dtv);
+ len = snprintf(bp, dlen, "int_mdp: %08lu\t",
+ mdp4_stat.intr_dsi_mdp);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "kickoff_atv: %08lu\n",
- mdp4_stat.kickoff_atv);
+
+ len = snprintf(bp, dlen, "int_err: %08lu\n",
+ mdp4_stat.intr_dsi_err);
+
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "kickoff_dsi: %08lu\n\n",
- mdp4_stat.kickoff_dsi);
+ len = snprintf(bp, dlen, "clk_on : %08lu\t",
+ mdp4_stat.dsi_clk_on);
+
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "writeback: %08lu\n",
- mdp4_stat.writeback);
+ len = snprintf(bp, dlen, "clk_off: %08lu\n\n",
+ mdp4_stat.dsi_clk_off);
+
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "overlay0_set: %08lu\n",
+ len = snprintf(bp, dlen, "kickoff:\n");
+ bp += len;
+ dlen -= len;
+
+ len = snprintf(bp, dlen, "overlay0: %08lu\t",
+ mdp4_stat.kickoff_ov0);
+ bp += len;
+ dlen -= len;
+ len = snprintf(bp, dlen, "dmap: %08lu\t",
+ mdp4_stat.kickoff_dmap);
+ bp += len;
+ dlen -= len;
+ len = snprintf(bp, dlen, "dmas: %08lu\n",
+ mdp4_stat.kickoff_dmas);
+
+ bp += len;
+ dlen -= len;
+ len = snprintf(bp, dlen, "overlay1: %08lu\t",
+ mdp4_stat.kickoff_ov1);
+ bp += len;
+ dlen -= len;
+ len = snprintf(bp, dlen, "dmae: %08lu\n\n",
+ mdp4_stat.kickoff_dmae);
+
+ bp += len;
+ dlen -= len;
+
+ len = snprintf(bp, dlen, "overlay0_play:\n");
+ bp += len;
+ dlen -= len;
+
+ len = snprintf(bp, dlen, "set: %08lu\t",
mdp4_stat.overlay_set[0]);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "overlay0_unset: %08lu\n",
+ len = snprintf(bp, dlen, "unset: %08lu\t",
mdp4_stat.overlay_unset[0]);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "overlay0_play: %08lu\n",
+ len = snprintf(bp, dlen, "play: %08lu\n",
mdp4_stat.overlay_play[0]);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "overlay1_set: %08lu\n",
+
+ len = snprintf(bp, dlen, "overlay1_play:\n");
+ bp += len;
+ dlen -= len;
+ len = snprintf(bp, dlen, "set: %08lu\t",
mdp4_stat.overlay_set[1]);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "overlay1_unset: %08lu\n",
+ len = snprintf(bp, dlen, "unset: %08lu\t",
mdp4_stat.overlay_unset[1]);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "overlay1_play: %08lu\n\n",
+ len = snprintf(bp, dlen, "play: %08lu\n\n",
mdp4_stat.overlay_play[1]);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "pipe_rgb1: %08lu\n", mdp4_stat.pipe[0]);
- bp += len;
- dlen -= len;
- len = snprintf(bp, dlen, "pipe_rgb2: %08lu\n", mdp4_stat.pipe[1]);
- bp += len;
- dlen -= len;
- len = snprintf(bp, dlen, "pipe_vg1: %08lu\n", mdp4_stat.pipe[2]);
- bp += len;
- dlen -= len;
- len = snprintf(bp, dlen, "pipe_vg2: %08lu\n\n", mdp4_stat.pipe[3]);
+ len = snprintf(bp, dlen, "frame_push:\n");
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "dsi_clkoff: %08lu\n\n", mdp4_stat.dsi_clkoff);
+ len = snprintf(bp, dlen, "rgb1: %08lu\t\t", mdp4_stat.pipe[0]);
+ bp += len;
+ dlen -= len;
+ len = snprintf(bp, dlen, "rgb2: %08lu\n", mdp4_stat.pipe[1]);
+ bp += len;
+ dlen -= len;
+ len = snprintf(bp, dlen, "vg1: %08lu\t\t", mdp4_stat.pipe[2]);
+ bp += len;
+ dlen -= len;
+ len = snprintf(bp, dlen, "vg2: %08lu\n", mdp4_stat.pipe[3]);
+ bp += len;
+ dlen -= len;
+ len = snprintf(bp, dlen, "err_mixer: %08lu\t", mdp4_stat.err_mixer);
+ bp += len;
+ dlen -= len;
+ len = snprintf(bp, dlen, "err_size : %08lu\n", mdp4_stat.err_size);
+ bp += len;
+ dlen -= len;
+ len = snprintf(bp, dlen, "err_scale: %08lu\t", mdp4_stat.err_scale);
+ bp += len;
+ dlen -= len;
+ len = snprintf(bp, dlen, "err_format: %08lu\n\n", mdp4_stat.err_format);
+ bp += len;
+ dlen -= len;
+ len = snprintf(bp, dlen, "writeback:\n");
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "err_mixer: %08lu\n", mdp4_stat.err_mixer);
+
+ len = snprintf(bp, dlen, "dsi_cmd: %08lu\t",
+ mdp4_stat.blt_dsi_cmd);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "err_size: %08lu\n", mdp4_stat.err_size);
+
+ len = snprintf(bp, dlen, "dsi_video: %08lu\n",
+ mdp4_stat.blt_dsi_video);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "err_scale: %08lu\n", mdp4_stat.err_scale);
+
+ len = snprintf(bp, dlen, "lcdc: %08lu\t",
+ mdp4_stat.blt_lcdc);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "err_format: %08lu\n", mdp4_stat.err_format);
+
+ len = snprintf(bp, dlen, "dtv: %08lu\t",
+ mdp4_stat.blt_dtv);
+ bp += len;
+ dlen -= len;
+
+ len = snprintf(bp, dlen, "mddi: %08lu\n\n",
+ mdp4_stat.blt_mddi);
bp += len;
dlen -= len;
diff --git a/drivers/video/msm/mipi_dsi_host.c b/drivers/video/msm/mipi_dsi_host.c
index 8d07e56..35af84d 100644
--- a/drivers/video/msm/mipi_dsi_host.c
+++ b/drivers/video/msm/mipi_dsi_host.c
@@ -51,6 +51,39 @@
static struct list_head pre_kickoff_list;
static struct list_head post_kickoff_list;
+enum {
+ STAT_DSI_START,
+ STAT_DSI_ERROR,
+ STAT_DSI_CMD,
+ STAT_DSI_MDP
+};
+
+#ifdef CONFIG_FB_MSM_MDP40
+void mipi_dsi_mdp_stat_inc(int which)
+{
+ switch (which) {
+ case STAT_DSI_START:
+ mdp4_stat.dsi_mdp_start++;
+ break;
+ case STAT_DSI_ERROR:
+ mdp4_stat.intr_dsi_err++;
+ break;
+ case STAT_DSI_CMD:
+ mdp4_stat.intr_dsi_cmd++;
+ break;
+ case STAT_DSI_MDP:
+ mdp4_stat.intr_dsi_mdp++;
+ break;
+ default:
+ break;
+ }
+}
+#else
+void mipi_dsi_mdp_stat_inc(int which)
+{
+}
+#endif
+
void mipi_dsi_init(void)
{
init_completion(&dsi_dma_comp);
@@ -986,6 +1019,7 @@
__func__, current->pid);
}
+
void mipi_dsi_cmd_mdp_start(void)
{
unsigned long flag;
@@ -994,6 +1028,8 @@
if (!in_interrupt())
mipi_dsi_pre_kickoff_action();
+ mipi_dsi_mdp_stat_inc(STAT_DSI_START);
+
spin_lock_irqsave(&dsi_mdp_lock, flag);
mipi_dsi_enable_irq();
dsi_mdp_busy = TRUE;
@@ -1166,7 +1202,7 @@
if (mfd->panel_info.mipi.no_max_pkt_size) {
/* Only support rlen = 4*n */
rlen += 3;
- rlen &= 0x03;
+ rlen &= ~0x03;
}
len = rlen;
@@ -1438,6 +1474,7 @@
#endif
if (isr & DSI_INTR_ERROR) {
+ mipi_dsi_mdp_stat_inc(STAT_DSI_ERROR);
mipi_dsi_error();
}
@@ -1448,10 +1485,12 @@
}
if (isr & DSI_INTR_CMD_DMA_DONE) {
+ mipi_dsi_mdp_stat_inc(STAT_DSI_CMD);
complete(&dsi_dma_comp);
}
if (isr & DSI_INTR_CMD_MDP_DONE) {
+ mipi_dsi_mdp_stat_inc(STAT_DSI_MDP);
spin_lock(&dsi_mdp_lock);
dsi_mdp_busy = FALSE;
spin_unlock(&dsi_mdp_lock);
diff --git a/drivers/video/msm/mipi_tc358764_dsi2lvds.c b/drivers/video/msm/mipi_tc358764_dsi2lvds.c
index 2594c1d..8055bd0 100644
--- a/drivers/video/msm/mipi_tc358764_dsi2lvds.c
+++ b/drivers/video/msm/mipi_tc358764_dsi2lvds.c
@@ -236,10 +236,9 @@
mipi_dsi_buf_init(&d2l_tx_buf);
mipi_dsi_buf_init(&d2l_rx_buf);
- mutex_lock(&mfd->dma->ov_mutex);
+ /* mutex had been acquried at dsi_on */
len = mipi_dsi_cmds_rx(mfd, &d2l_tx_buf, &d2l_rx_buf,
&cmd_read_reg, len);
- mutex_unlock(&mfd->dma->ov_mutex);
data = *(u32 *)d2l_rx_buf.data;
@@ -269,9 +268,8 @@
payload.addr = reg;
payload.data = data;
- mutex_lock(&mfd->dma->ov_mutex);
+ /* mutex had been acquried at dsi_on */
mipi_dsi_cmds_tx(mfd, &d2l_tx_buf, &cmd_write_reg, 1);
- mutex_unlock(&mfd->dma->ov_mutex);
pr_debug("%s: reg=0x%x. data=0x%x.\n", __func__, reg, data);
diff --git a/drivers/video/msm/msm_dss_io_7x27a.c b/drivers/video/msm/msm_dss_io_7x27a.c
index 5f1abd4..032c9cd 100644
--- a/drivers/video/msm/msm_dss_io_7x27a.c
+++ b/drivers/video/msm/msm_dss_io_7x27a.c
@@ -13,7 +13,6 @@
#include <linux/clk.h>
#include "msm_fb.h"
#include "mipi_dsi.h"
-#include <mach/clk.h>
/* multimedia sub system sfpb */
char *mmss_sfpb_base;
@@ -313,7 +312,7 @@
unsigned data = 0;
uint32 pll_ctrl;
- if (clk_set_min_rate(ebi1_dsi_clk, 65000000)) /* 65 MHz */
+ if (clk_set_rate(ebi1_dsi_clk, 65000000)) /* 65 MHz */
pr_err("%s: ebi1_dsi_clk set rate failed\n", __func__);
clk_enable(ebi1_dsi_clk);
@@ -339,7 +338,7 @@
clk_disable(mdp_dsi_pclk);
/* DSIPHY_PLL_CTRL_0, disable dsi pll */
MIPI_OUTP(MIPI_DSI_BASE + 0x0200, 0x40);
- if (clk_set_min_rate(ebi1_dsi_clk, 0))
+ if (clk_set_rate(ebi1_dsi_clk, 0))
pr_err("%s: ebi1_dsi_clk set rate failed\n", __func__);
clk_disable(ebi1_dsi_clk);
}
diff --git a/drivers/video/msm/msm_dss_io_8960.c b/drivers/video/msm/msm_dss_io_8960.c
index ba93df76..52a10ab 100644
--- a/drivers/video/msm/msm_dss_io_8960.c
+++ b/drivers/video/msm/msm_dss_io_8960.c
@@ -12,6 +12,8 @@
*/
#include <linux/clk.h>
#include "msm_fb.h"
+#include "mdp.h"
+#include "mdp4.h"
#include "mipi_dsi.h"
#include "hdmi_msm.h"
#include <mach/msm_iomap.h>
@@ -555,6 +557,7 @@
mipi_dsi_clk_ctrl(&dsicore_clk, 1);
clk_enable(dsi_byte_div_clk);
clk_enable(dsi_esc_clk);
+ mdp4_stat.dsi_clk_on++;
}
void mipi_dsi_clk_disable(void)
@@ -565,6 +568,7 @@
mipi_dsi_clk_ctrl(&dsicore_clk, 0);
/* DSIPHY_PLL_CTRL_0, disable dsi pll */
MIPI_OUTP(MIPI_DSI_BASE + 0x0200, 0x0);
+ mdp4_stat.dsi_clk_off++;
}
void mipi_dsi_phy_ctrl(int on)
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 10e4156..59c2afe 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -2569,8 +2569,6 @@
return 0;
}
-
-#ifdef CONFIG_FB_MSM_OVERLAY_WRITEBACK
static int msmfb_overlay_blt(struct fb_info *info, unsigned long *argp)
{
int ret;
@@ -2607,16 +2605,6 @@
return ret;
}
-#else
-static int msmfb_overlay_blt(struct fb_info *info, unsigned long *argp)
-{
- return 0;
-}
-static int msmfb_overlay_blt_off(struct fb_info *info, unsigned long *argp)
-{
- return 0;
-}
-#endif
#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
static int msmfb_overlay_ioctl_writeback_init(struct fb_info *info)
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index bc25062..de2734d 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -166,7 +166,6 @@
struct completion msmfb_update_notify;
struct completion msmfb_no_update_notify;
u32 ov_start, ov_end;
-
struct mutex writeback_mutex;
struct mutex unregister_mutex;
struct list_head writeback_busy_queue;
@@ -174,6 +173,8 @@
struct list_head writeback_register_queue;
wait_queue_head_t wait_q;
struct ion_client *client;
+ u32 mdp_rev;
+ u32 use_ov0_blt, ov0_blt_state;
};
struct dentry *msm_fb_get_debugfs_root(void);
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
index a0637aa..df65d26 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
@@ -64,7 +64,7 @@
}
addr->alloc_handle = ion_alloc(
ddl_context->video_ion_client, alloc_size, SZ_4K,
- (1<<ION_HEAP_EBI_ID));
+ (1<<res_trk_get_mem_type()));
if (!addr->alloc_handle) {
DDL_MSG_ERROR("%s() :DDL ION alloc failed\n",
__func__);
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index 8b293b6..cf8f712 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -242,7 +242,11 @@
decoder->hw_bufs.desc),
seq_start_param.descriptor_buffer_size =
decoder->hw_bufs.desc.buffer_size;
- if (decoder->codec.codec == VCD_CODEC_MPEG4)
+ if ((decoder->codec.codec == VCD_CODEC_MPEG4) ||
+ (decoder->codec.codec == VCD_CODEC_DIVX_4) ||
+ (decoder->codec.codec == VCD_CODEC_DIVX_5) ||
+ (decoder->codec.codec == VCD_CODEC_DIVX_6) ||
+ (decoder->codec.codec == VCD_CODEC_XVID))
vidc_sm_set_mpeg4_profile_override(
&ddl->shared_mem[ddl->command_channel],
VIDC_SM_PROFILE_INFO_ASP);
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.c b/drivers/video/msm/vidc/common/init/vidc_init.c
index 8da4ba5..1217f1f 100644
--- a/drivers/video/msm/vidc/common/init/vidc_init.c
+++ b/drivers/video/msm/vidc/common/init/vidc_init.c
@@ -526,7 +526,8 @@
}
phys_addr += buffer_addr_offset;
(*kernel_vaddr) += buffer_addr_offset;
- flags = MSM_SUBSYSTEM_MAP_IOVA;
+ flags = (buffer == BUFFER_TYPE_INPUT) ? MSM_SUBSYSTEM_MAP_IOVA :
+ MSM_SUBSYSTEM_MAP_IOVA|MSM_SUBSYSTEM_ALIGN_IOVA_8K;
mapped_buffer = msm_subsystem_map_buffer(phys_addr, length,
flags, vidc_mmu_subsystem,
sizeof(vidc_mmu_subsystem)/sizeof(unsigned int));
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 35ee946..75e0acf 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -57,8 +57,8 @@
pr_err("%s() map table is full", __func__);
goto bailout;
}
+ memtype = res_trk_get_mem_type();
if (!cctxt->vcd_enable_ion) {
- memtype = res_trk_get_mem_type();
map_buffer->phy_addr = (phys_addr_t)
allocate_contiguous_memory_nomap(sz, memtype, SZ_4K);
if (!map_buffer->phy_addr) {
@@ -68,7 +68,7 @@
} else {
map_buffer->alloc_handle = ion_alloc(
cctxt->vcd_ion_client, sz, SZ_4K,
- (1<<ION_HEAP_EBI_ID));
+ (1<<memtype));
if (!map_buffer->alloc_handle) {
pr_err("%s() ION alloc failed", __func__);
goto bailout;
@@ -1900,7 +1900,8 @@
VCD_MSG_HIGH("Got input done for EOS initiator");
transc->input_done = false;
transc->in_use = true;
- if (codec_config ||
+ if ((codec_config &&
+ (status != VCD_ERR_BITSTREAM_ERR)) ||
((status == VCD_ERR_BITSTREAM_ERR) &&
!(cctxt->status.mask & VCD_FIRST_IP_DONE) &&
(core_type == VCD_CORE_720P)))
diff --git a/drivers/video/savage/savagefb.h b/drivers/video/savage/savagefb.h
index 32549d1..dcaab90 100644
--- a/drivers/video/savage/savagefb.h
+++ b/drivers/video/savage/savagefb.h
@@ -55,7 +55,7 @@
#define S3_SAVAGE3D_SERIES(chip) ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE_MX))
-#define S3_SAVAGE4_SERIES(chip) ((chip>=S3_SAVAGE4) || (chip<=S3_PROSAVAGEDDR))
+#define S3_SAVAGE4_SERIES(chip) ((chip>=S3_SAVAGE4) && (chip<=S3_PROSAVAGEDDR))
#define S3_SAVAGE_MOBILE_SERIES(chip) ((chip==S3_SAVAGE_MX) || (chip==S3_SUPERSAVAGE))
diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c
index e0c2807..181fa81 100644
--- a/drivers/zorro/zorro.c
+++ b/drivers/zorro/zorro.c
@@ -148,10 +148,10 @@
}
platform_set_drvdata(pdev, bus);
- /* Register all devices */
pr_info("Zorro: Probing AutoConfig expansion devices: %u device%s\n",
zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s");
+ /* First identify all devices ... */
for (i = 0; i < zorro_num_autocon; i++) {
z = &zorro_autocon[i];
z->id = (z->rom.er_Manufacturer<<16) | (z->rom.er_Product<<8);
@@ -172,6 +172,11 @@
dev_set_name(&z->dev, "%02x", i);
z->dev.parent = &bus->dev;
z->dev.bus = &zorro_bus_type;
+ }
+
+ /* ... then register them */
+ for (i = 0; i < zorro_num_autocon; i++) {
+ z = &zorro_autocon[i];
error = device_register(&z->dev);
if (error) {
dev_err(&bus->dev, "Error registering device %s\n",
diff --git a/fs/9p/acl.c b/fs/9p/acl.c
index 535ab6e..4a866cd 100644
--- a/fs/9p/acl.c
+++ b/fs/9p/acl.c
@@ -185,12 +185,15 @@
}
int v9fs_set_create_acl(struct dentry *dentry,
- struct posix_acl *dpacl, struct posix_acl *pacl)
+ struct posix_acl **dpacl, struct posix_acl **pacl)
{
- v9fs_set_acl(dentry, ACL_TYPE_DEFAULT, dpacl);
- v9fs_set_acl(dentry, ACL_TYPE_ACCESS, pacl);
- posix_acl_release(dpacl);
- posix_acl_release(pacl);
+ if (dentry) {
+ v9fs_set_acl(dentry, ACL_TYPE_DEFAULT, *dpacl);
+ v9fs_set_acl(dentry, ACL_TYPE_ACCESS, *pacl);
+ }
+ posix_acl_release(*dpacl);
+ posix_acl_release(*pacl);
+ *dpacl = *pacl = NULL;
return 0;
}
@@ -212,11 +215,11 @@
struct posix_acl *clone;
if (S_ISDIR(mode))
- *dpacl = acl;
+ *dpacl = posix_acl_dup(acl);
clone = posix_acl_clone(acl, GFP_NOFS);
- retval = -ENOMEM;
+ posix_acl_release(acl);
if (!clone)
- goto cleanup;
+ return -ENOMEM;
retval = posix_acl_create_masq(clone, &mode);
if (retval < 0) {
@@ -225,11 +228,12 @@
}
if (retval > 0)
*pacl = clone;
+ else
+ posix_acl_release(clone);
}
*modep = mode;
return 0;
cleanup:
- posix_acl_release(acl);
return retval;
}
diff --git a/fs/9p/acl.h b/fs/9p/acl.h
index 7ef3ac9..c47ea9c 100644
--- a/fs/9p/acl.h
+++ b/fs/9p/acl.h
@@ -19,7 +19,7 @@
extern int v9fs_check_acl(struct inode *inode, int mask, unsigned int flags);
extern int v9fs_acl_chmod(struct dentry *);
extern int v9fs_set_create_acl(struct dentry *,
- struct posix_acl *, struct posix_acl *);
+ struct posix_acl **, struct posix_acl **);
extern int v9fs_acl_mode(struct inode *dir, mode_t *modep,
struct posix_acl **dpacl, struct posix_acl **pacl);
#else
@@ -33,8 +33,8 @@
return 0;
}
static inline int v9fs_set_create_acl(struct dentry *dentry,
- struct posix_acl *dpacl,
- struct posix_acl *pacl)
+ struct posix_acl **dpacl,
+ struct posix_acl **pacl)
{
return 0;
}
diff --git a/fs/9p/cache.c b/fs/9p/cache.c
index 5b335c5..945aa5f 100644
--- a/fs/9p/cache.c
+++ b/fs/9p/cache.c
@@ -108,11 +108,10 @@
void *buffer, uint16_t bufmax)
{
const struct v9fs_inode *v9inode = cookie_netfs_data;
- memcpy(buffer, &v9inode->fscache_key->path,
- sizeof(v9inode->fscache_key->path));
+ memcpy(buffer, &v9inode->qid.path, sizeof(v9inode->qid.path));
P9_DPRINTK(P9_DEBUG_FSC, "inode %p get key %llu", &v9inode->vfs_inode,
- v9inode->fscache_key->path);
- return sizeof(v9inode->fscache_key->path);
+ v9inode->qid.path);
+ return sizeof(v9inode->qid.path);
}
static void v9fs_cache_inode_get_attr(const void *cookie_netfs_data,
@@ -129,11 +128,10 @@
void *buffer, uint16_t buflen)
{
const struct v9fs_inode *v9inode = cookie_netfs_data;
- memcpy(buffer, &v9inode->fscache_key->version,
- sizeof(v9inode->fscache_key->version));
+ memcpy(buffer, &v9inode->qid.version, sizeof(v9inode->qid.version));
P9_DPRINTK(P9_DEBUG_FSC, "inode %p get aux %u", &v9inode->vfs_inode,
- v9inode->fscache_key->version);
- return sizeof(v9inode->fscache_key->version);
+ v9inode->qid.version);
+ return sizeof(v9inode->qid.version);
}
static enum
@@ -143,11 +141,11 @@
{
const struct v9fs_inode *v9inode = cookie_netfs_data;
- if (buflen != sizeof(v9inode->fscache_key->version))
+ if (buflen != sizeof(v9inode->qid.version))
return FSCACHE_CHECKAUX_OBSOLETE;
- if (memcmp(buffer, &v9inode->fscache_key->version,
- sizeof(v9inode->fscache_key->version)))
+ if (memcmp(buffer, &v9inode->qid.version,
+ sizeof(v9inode->qid.version)))
return FSCACHE_CHECKAUX_OBSOLETE;
return FSCACHE_CHECKAUX_OKAY;
diff --git a/fs/9p/cache.h b/fs/9p/cache.h
index 049507a..40cc54c 100644
--- a/fs/9p/cache.h
+++ b/fs/9p/cache.h
@@ -93,15 +93,6 @@
BUG_ON(PageFsCache(page));
}
-static inline void v9fs_fscache_set_key(struct inode *inode,
- struct p9_qid *qid)
-{
- struct v9fs_inode *v9inode = V9FS_I(inode);
- spin_lock(&v9inode->fscache_lock);
- v9inode->fscache_key = qid;
- spin_unlock(&v9inode->fscache_lock);
-}
-
static inline void v9fs_fscache_wait_on_page_write(struct inode *inode,
struct page *page)
{
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index c82b017..ef96618 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -78,6 +78,25 @@
{Opt_err, NULL}
};
+/* Interpret mount options for cache mode */
+static int get_cache_mode(char *s)
+{
+ int version = -EINVAL;
+
+ if (!strcmp(s, "loose")) {
+ version = CACHE_LOOSE;
+ P9_DPRINTK(P9_DEBUG_9P, "Cache mode: loose\n");
+ } else if (!strcmp(s, "fscache")) {
+ version = CACHE_FSCACHE;
+ P9_DPRINTK(P9_DEBUG_9P, "Cache mode: fscache\n");
+ } else if (!strcmp(s, "none")) {
+ version = CACHE_NONE;
+ P9_DPRINTK(P9_DEBUG_9P, "Cache mode: none\n");
+ } else
+ printk(KERN_INFO "9p: Unknown Cache mode %s.\n", s);
+ return version;
+}
+
/**
* v9fs_parse_options - parse mount options into session structure
* @v9ses: existing v9fs session information
@@ -97,7 +116,7 @@
/* setup defaults */
v9ses->afid = ~0;
v9ses->debug = 0;
- v9ses->cache = 0;
+ v9ses->cache = CACHE_NONE;
#ifdef CONFIG_9P_FSCACHE
v9ses->cachetag = NULL;
#endif
@@ -171,13 +190,13 @@
"problem allocating copy of cache arg\n");
goto free_and_return;
}
+ ret = get_cache_mode(s);
+ if (ret == -EINVAL) {
+ kfree(s);
+ goto free_and_return;
+ }
- if (strcmp(s, "loose") == 0)
- v9ses->cache = CACHE_LOOSE;
- else if (strcmp(s, "fscache") == 0)
- v9ses->cache = CACHE_FSCACHE;
- else
- v9ses->cache = CACHE_NONE;
+ v9ses->cache = ret;
kfree(s);
break;
@@ -200,9 +219,15 @@
} else {
v9ses->flags |= V9FS_ACCESS_SINGLE;
v9ses->uid = simple_strtoul(s, &e, 10);
- if (*e != '\0')
- v9ses->uid = ~0;
+ if (*e != '\0') {
+ ret = -EINVAL;
+ printk(KERN_INFO "9p: Unknown access "
+ "argument %s.\n", s);
+ kfree(s);
+ goto free_and_return;
+ }
}
+
kfree(s);
break;
@@ -487,8 +512,8 @@
struct v9fs_inode *v9inode = (struct v9fs_inode *)foo;
#ifdef CONFIG_9P_FSCACHE
v9inode->fscache = NULL;
- v9inode->fscache_key = NULL;
#endif
+ memset(&v9inode->qid, 0, sizeof(v9inode->qid));
inode_init_once(&v9inode->vfs_inode);
}
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index e5ebedf..e78956c 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -125,8 +125,8 @@
#ifdef CONFIG_9P_FSCACHE
spinlock_t fscache_lock;
struct fscache_cookie *fscache;
- struct p9_qid *fscache_key;
#endif
+ struct p9_qid qid;
unsigned int cache_validity;
struct p9_fid *writeback_fid;
struct mutex v_mutex;
@@ -153,13 +153,13 @@
void *p);
extern struct inode *v9fs_inode_from_fid(struct v9fs_session_info *v9ses,
struct p9_fid *fid,
- struct super_block *sb);
+ struct super_block *sb, int new);
extern const struct inode_operations v9fs_dir_inode_operations_dotl;
extern const struct inode_operations v9fs_file_inode_operations_dotl;
extern const struct inode_operations v9fs_symlink_inode_operations_dotl;
extern struct inode *v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses,
struct p9_fid *fid,
- struct super_block *sb);
+ struct super_block *sb, int new);
/* other default globals */
#define V9FS_PORT 564
@@ -201,8 +201,27 @@
struct super_block *sb)
{
if (v9fs_proto_dotl(v9ses))
- return v9fs_inode_from_fid_dotl(v9ses, fid, sb);
+ return v9fs_inode_from_fid_dotl(v9ses, fid, sb, 0);
else
- return v9fs_inode_from_fid(v9ses, fid, sb);
+ return v9fs_inode_from_fid(v9ses, fid, sb, 0);
}
+
+/**
+ * v9fs_get_new_inode_from_fid - Helper routine to populate an inode by
+ * issuing a attribute request
+ * @v9ses: session information
+ * @fid: fid to issue attribute request for
+ * @sb: superblock on which to create inode
+ *
+ */
+static inline struct inode *
+v9fs_get_new_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
+ struct super_block *sb)
+{
+ if (v9fs_proto_dotl(v9ses))
+ return v9fs_inode_from_fid_dotl(v9ses, fid, sb, 1);
+ else
+ return v9fs_inode_from_fid(v9ses, fid, sb, 1);
+}
+
#endif
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
index 4014160..f9a28ea 100644
--- a/fs/9p/v9fs_vfs.h
+++ b/fs/9p/v9fs_vfs.h
@@ -54,9 +54,9 @@
struct inode *v9fs_alloc_inode(struct super_block *sb);
void v9fs_destroy_inode(struct inode *inode);
-struct inode *v9fs_get_inode(struct super_block *sb, int mode);
+struct inode *v9fs_get_inode(struct super_block *sb, int mode, dev_t);
int v9fs_init_inode(struct v9fs_session_info *v9ses,
- struct inode *inode, int mode);
+ struct inode *inode, int mode, dev_t);
void v9fs_evict_inode(struct inode *inode);
ino_t v9fs_qid2ino(struct p9_qid *qid);
void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *);
@@ -82,4 +82,6 @@
v9inode->cache_validity |= V9FS_INO_INVALID_ATTR;
return;
}
+
+int v9fs_open_to_dotl_flags(int flags);
#endif
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index ffed558..9d6e168 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -65,7 +65,7 @@
v9inode = V9FS_I(inode);
v9ses = v9fs_inode2v9ses(inode);
if (v9fs_proto_dotl(v9ses))
- omode = file->f_flags;
+ omode = v9fs_open_to_dotl_flags(file->f_flags);
else
omode = v9fs_uflags2omode(file->f_flags,
v9fs_proto_dotu(v9ses));
@@ -169,7 +169,18 @@
/* convert posix lock to p9 tlock args */
memset(&flock, 0, sizeof(flock));
- flock.type = fl->fl_type;
+ /* map the lock type */
+ switch (fl->fl_type) {
+ case F_RDLCK:
+ flock.type = P9_LOCK_TYPE_RDLCK;
+ break;
+ case F_WRLCK:
+ flock.type = P9_LOCK_TYPE_WRLCK;
+ break;
+ case F_UNLCK:
+ flock.type = P9_LOCK_TYPE_UNLCK;
+ break;
+ }
flock.start = fl->fl_start;
if (fl->fl_end == OFFSET_MAX)
flock.length = 0;
@@ -245,7 +256,7 @@
/* convert posix lock to p9 tgetlock args */
memset(&glock, 0, sizeof(glock));
- glock.type = fl->fl_type;
+ glock.type = P9_LOCK_TYPE_UNLCK;
glock.start = fl->fl_start;
if (fl->fl_end == OFFSET_MAX)
glock.length = 0;
@@ -257,17 +268,26 @@
res = p9_client_getlock_dotl(fid, &glock);
if (res < 0)
return res;
- if (glock.type != F_UNLCK) {
- fl->fl_type = glock.type;
+ /* map 9p lock type to os lock type */
+ switch (glock.type) {
+ case P9_LOCK_TYPE_RDLCK:
+ fl->fl_type = F_RDLCK;
+ break;
+ case P9_LOCK_TYPE_WRLCK:
+ fl->fl_type = F_WRLCK;
+ break;
+ case P9_LOCK_TYPE_UNLCK:
+ fl->fl_type = F_UNLCK;
+ break;
+ }
+ if (glock.type != P9_LOCK_TYPE_UNLCK) {
fl->fl_start = glock.start;
if (glock.length == 0)
fl->fl_end = OFFSET_MAX;
else
fl->fl_end = glock.start + glock.length - 1;
fl->fl_pid = glock.proc_id;
- } else
- fl->fl_type = F_UNLCK;
-
+ }
return res;
}
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 7f6c677..c72e20c 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -95,15 +95,18 @@
/**
* p9mode2unixmode- convert plan9 mode bits to unix mode bits
* @v9ses: v9fs session information
- * @mode: mode to convert
+ * @stat: p9_wstat from which mode need to be derived
+ * @rdev: major number, minor number in case of device files.
*
*/
-
-static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
+static int p9mode2unixmode(struct v9fs_session_info *v9ses,
+ struct p9_wstat *stat, dev_t *rdev)
{
int res;
+ int mode = stat->mode;
- res = mode & 0777;
+ res = mode & S_IALLUGO;
+ *rdev = 0;
if ((mode & P9_DMDIR) == P9_DMDIR)
res |= S_IFDIR;
@@ -116,9 +119,26 @@
&& (v9ses->nodev == 0))
res |= S_IFIFO;
else if ((mode & P9_DMDEVICE) && (v9fs_proto_dotu(v9ses))
- && (v9ses->nodev == 0))
- res |= S_IFBLK;
- else
+ && (v9ses->nodev == 0)) {
+ char type = 0, ext[32];
+ int major = -1, minor = -1;
+
+ strncpy(ext, stat->extension, sizeof(ext));
+ sscanf(ext, "%c %u %u", &type, &major, &minor);
+ switch (type) {
+ case 'c':
+ res |= S_IFCHR;
+ break;
+ case 'b':
+ res |= S_IFBLK;
+ break;
+ default:
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "Unknown special type %c %s\n", type,
+ stat->extension);
+ };
+ *rdev = MKDEV(major, minor);
+ } else
res |= S_IFREG;
if (v9fs_proto_dotu(v9ses)) {
@@ -131,7 +151,6 @@
if ((mode & P9_DMSETVTX) == P9_DMSETVTX)
res |= S_ISVTX;
}
-
return res;
}
@@ -216,7 +235,6 @@
return NULL;
#ifdef CONFIG_9P_FSCACHE
v9inode->fscache = NULL;
- v9inode->fscache_key = NULL;
spin_lock_init(&v9inode->fscache_lock);
#endif
v9inode->writeback_fid = NULL;
@@ -243,13 +261,13 @@
}
int v9fs_init_inode(struct v9fs_session_info *v9ses,
- struct inode *inode, int mode)
+ struct inode *inode, int mode, dev_t rdev)
{
int err = 0;
inode_init_owner(inode, NULL, mode);
inode->i_blocks = 0;
- inode->i_rdev = 0;
+ inode->i_rdev = rdev;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_mapping->a_ops = &v9fs_addr_operations;
@@ -336,7 +354,7 @@
*
*/
-struct inode *v9fs_get_inode(struct super_block *sb, int mode)
+struct inode *v9fs_get_inode(struct super_block *sb, int mode, dev_t rdev)
{
int err;
struct inode *inode;
@@ -349,7 +367,7 @@
P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n");
return ERR_PTR(-ENOMEM);
}
- err = v9fs_init_inode(v9ses, inode, mode);
+ err = v9fs_init_inode(v9ses, inode, mode, rdev);
if (err) {
iput(inode);
return ERR_PTR(err);
@@ -433,17 +451,62 @@
}
}
+static int v9fs_test_inode(struct inode *inode, void *data)
+{
+ int umode;
+ dev_t rdev;
+ struct v9fs_inode *v9inode = V9FS_I(inode);
+ struct p9_wstat *st = (struct p9_wstat *)data;
+ struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
+
+ umode = p9mode2unixmode(v9ses, st, &rdev);
+ /* don't match inode of different type */
+ if ((inode->i_mode & S_IFMT) != (umode & S_IFMT))
+ return 0;
+
+ /* compare qid details */
+ if (memcmp(&v9inode->qid.version,
+ &st->qid.version, sizeof(v9inode->qid.version)))
+ return 0;
+
+ if (v9inode->qid.type != st->qid.type)
+ return 0;
+ return 1;
+}
+
+static int v9fs_test_new_inode(struct inode *inode, void *data)
+{
+ return 0;
+}
+
+static int v9fs_set_inode(struct inode *inode, void *data)
+{
+ struct v9fs_inode *v9inode = V9FS_I(inode);
+ struct p9_wstat *st = (struct p9_wstat *)data;
+
+ memcpy(&v9inode->qid, &st->qid, sizeof(st->qid));
+ return 0;
+}
+
static struct inode *v9fs_qid_iget(struct super_block *sb,
struct p9_qid *qid,
- struct p9_wstat *st)
+ struct p9_wstat *st,
+ int new)
{
+ dev_t rdev;
int retval, umode;
unsigned long i_ino;
struct inode *inode;
struct v9fs_session_info *v9ses = sb->s_fs_info;
+ int (*test)(struct inode *, void *);
+
+ if (new)
+ test = v9fs_test_new_inode;
+ else
+ test = v9fs_test_inode;
i_ino = v9fs_qid2ino(qid);
- inode = iget_locked(sb, i_ino);
+ inode = iget5_locked(sb, i_ino, test, v9fs_set_inode, st);
if (!inode)
return ERR_PTR(-ENOMEM);
if (!(inode->i_state & I_NEW))
@@ -453,14 +516,14 @@
* FIXME!! we may need support for stale inodes
* later.
*/
- umode = p9mode2unixmode(v9ses, st->mode);
- retval = v9fs_init_inode(v9ses, inode, umode);
+ inode->i_ino = i_ino;
+ umode = p9mode2unixmode(v9ses, st, &rdev);
+ retval = v9fs_init_inode(v9ses, inode, umode, rdev);
if (retval)
goto error;
v9fs_stat2inode(st, inode, sb);
#ifdef CONFIG_9P_FSCACHE
- v9fs_fscache_set_key(inode, &st->qid);
v9fs_cache_inode_get_cookie(inode);
#endif
unlock_new_inode(inode);
@@ -474,7 +537,7 @@
struct inode *
v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
- struct super_block *sb)
+ struct super_block *sb, int new)
{
struct p9_wstat *st;
struct inode *inode = NULL;
@@ -483,7 +546,7 @@
if (IS_ERR(st))
return ERR_CAST(st);
- inode = v9fs_qid_iget(sb, &st->qid, st);
+ inode = v9fs_qid_iget(sb, &st->qid, st, new);
p9stat_free(st);
kfree(st);
return inode;
@@ -585,19 +648,17 @@
}
/* instantiate inode and assign the unopened fid to the dentry */
- inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
+ inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err);
goto error;
}
- d_instantiate(dentry, inode);
err = v9fs_fid_add(dentry, fid);
if (err < 0)
goto error;
-
+ d_instantiate(dentry, inode);
return ofid;
-
error:
if (ofid)
p9_client_clunk(ofid);
@@ -738,6 +799,7 @@
struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *nameidata)
{
+ struct dentry *res;
struct super_block *sb;
struct v9fs_session_info *v9ses;
struct p9_fid *dfid, *fid;
@@ -769,22 +831,35 @@
return ERR_PTR(result);
}
-
- inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
+ /*
+ * Make sure we don't use a wrong inode due to parallel
+ * unlink. For cached mode create calls request for new
+ * inode. But with cache disabled, lookup should do this.
+ */
+ if (v9ses->cache)
+ inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
+ else
+ inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
if (IS_ERR(inode)) {
result = PTR_ERR(inode);
inode = NULL;
goto error;
}
-
result = v9fs_fid_add(dentry, fid);
if (result < 0)
goto error_iput;
-
inst_out:
- d_add(dentry, inode);
- return NULL;
-
+ /*
+ * If we had a rename on the server and a parallel lookup
+ * for the new name, then make sure we instantiate with
+ * the new name. ie look up for a/b, while on server somebody
+ * moved b under k and client parallely did a lookup for
+ * k/b.
+ */
+ res = d_materialise_unique(dentry, inode);
+ if (!IS_ERR(res))
+ return res;
+ result = PTR_ERR(res);
error_iput:
iput(inode);
error:
@@ -950,7 +1025,7 @@
return PTR_ERR(st);
v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb);
- generic_fillattr(dentry->d_inode, stat);
+ generic_fillattr(dentry->d_inode, stat);
p9stat_free(st);
kfree(st);
@@ -1034,6 +1109,7 @@
v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
struct super_block *sb)
{
+ mode_t mode;
char ext[32];
char tag_name[14];
unsigned int i_nlink;
@@ -1069,31 +1145,9 @@
inode->i_nlink = i_nlink;
}
}
- inode->i_mode = p9mode2unixmode(v9ses, stat->mode);
- if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) {
- char type = 0;
- int major = -1;
- int minor = -1;
-
- strncpy(ext, stat->extension, sizeof(ext));
- sscanf(ext, "%c %u %u", &type, &major, &minor);
- switch (type) {
- case 'c':
- inode->i_mode &= ~S_IFBLK;
- inode->i_mode |= S_IFCHR;
- break;
- case 'b':
- break;
- default:
- P9_DPRINTK(P9_DEBUG_ERROR,
- "Unknown special type %c %s\n", type,
- stat->extension);
- };
- inode->i_rdev = MKDEV(major, minor);
- init_special_inode(inode, inode->i_mode, inode->i_rdev);
- } else
- inode->i_rdev = 0;
-
+ mode = stat->mode & S_IALLUGO;
+ mode |= inode->i_mode & ~S_IALLUGO;
+ inode->i_mode = mode;
i_size_write(inode, stat->length);
/* not real number of blocks, but 512 byte ones ... */
@@ -1359,6 +1413,8 @@
int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode)
{
+ int umode;
+ dev_t rdev;
loff_t i_size;
struct p9_wstat *st;
struct v9fs_session_info *v9ses;
@@ -1367,6 +1423,12 @@
st = p9_client_stat(fid);
if (IS_ERR(st))
return PTR_ERR(st);
+ /*
+ * Don't update inode if the file type is different
+ */
+ umode = p9mode2unixmode(v9ses, st, &rdev);
+ if ((inode->i_mode & S_IFMT) != (umode & S_IFMT))
+ goto out;
spin_lock(&inode->i_lock);
/*
@@ -1378,6 +1440,7 @@
if (v9ses->cache)
inode->i_size = i_size;
spin_unlock(&inode->i_lock);
+out:
p9stat_free(st);
kfree(st);
return 0;
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
index 691c78f..c873172 100644
--- a/fs/9p/vfs_inode_dotl.c
+++ b/fs/9p/vfs_inode_dotl.c
@@ -86,18 +86,63 @@
return dentry;
}
+static int v9fs_test_inode_dotl(struct inode *inode, void *data)
+{
+ struct v9fs_inode *v9inode = V9FS_I(inode);
+ struct p9_stat_dotl *st = (struct p9_stat_dotl *)data;
+
+ /* don't match inode of different type */
+ if ((inode->i_mode & S_IFMT) != (st->st_mode & S_IFMT))
+ return 0;
+
+ if (inode->i_generation != st->st_gen)
+ return 0;
+
+ /* compare qid details */
+ if (memcmp(&v9inode->qid.version,
+ &st->qid.version, sizeof(v9inode->qid.version)))
+ return 0;
+
+ if (v9inode->qid.type != st->qid.type)
+ return 0;
+ return 1;
+}
+
+/* Always get a new inode */
+static int v9fs_test_new_inode_dotl(struct inode *inode, void *data)
+{
+ return 0;
+}
+
+static int v9fs_set_inode_dotl(struct inode *inode, void *data)
+{
+ struct v9fs_inode *v9inode = V9FS_I(inode);
+ struct p9_stat_dotl *st = (struct p9_stat_dotl *)data;
+
+ memcpy(&v9inode->qid, &st->qid, sizeof(st->qid));
+ inode->i_generation = st->st_gen;
+ return 0;
+}
+
static struct inode *v9fs_qid_iget_dotl(struct super_block *sb,
struct p9_qid *qid,
struct p9_fid *fid,
- struct p9_stat_dotl *st)
+ struct p9_stat_dotl *st,
+ int new)
{
int retval;
unsigned long i_ino;
struct inode *inode;
struct v9fs_session_info *v9ses = sb->s_fs_info;
+ int (*test)(struct inode *, void *);
+
+ if (new)
+ test = v9fs_test_new_inode_dotl;
+ else
+ test = v9fs_test_inode_dotl;
i_ino = v9fs_qid2ino(qid);
- inode = iget_locked(sb, i_ino);
+ inode = iget5_locked(sb, i_ino, test, v9fs_set_inode_dotl, st);
if (!inode)
return ERR_PTR(-ENOMEM);
if (!(inode->i_state & I_NEW))
@@ -107,13 +152,14 @@
* FIXME!! we may need support for stale inodes
* later.
*/
- retval = v9fs_init_inode(v9ses, inode, st->st_mode);
+ inode->i_ino = i_ino;
+ retval = v9fs_init_inode(v9ses, inode,
+ st->st_mode, new_decode_dev(st->st_rdev));
if (retval)
goto error;
v9fs_stat2inode_dotl(st, inode);
#ifdef CONFIG_9P_FSCACHE
- v9fs_fscache_set_key(inode, &st->qid);
v9fs_cache_inode_get_cookie(inode);
#endif
retval = v9fs_get_acl(inode, fid);
@@ -131,20 +177,72 @@
struct inode *
v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid,
- struct super_block *sb)
+ struct super_block *sb, int new)
{
struct p9_stat_dotl *st;
struct inode *inode = NULL;
- st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
+ st = p9_client_getattr_dotl(fid, P9_STATS_BASIC | P9_STATS_GEN);
if (IS_ERR(st))
return ERR_CAST(st);
- inode = v9fs_qid_iget_dotl(sb, &st->qid, fid, st);
+ inode = v9fs_qid_iget_dotl(sb, &st->qid, fid, st, new);
kfree(st);
return inode;
}
+struct dotl_openflag_map {
+ int open_flag;
+ int dotl_flag;
+};
+
+static int v9fs_mapped_dotl_flags(int flags)
+{
+ int i;
+ int rflags = 0;
+ struct dotl_openflag_map dotl_oflag_map[] = {
+ { O_CREAT, P9_DOTL_CREATE },
+ { O_EXCL, P9_DOTL_EXCL },
+ { O_NOCTTY, P9_DOTL_NOCTTY },
+ { O_TRUNC, P9_DOTL_TRUNC },
+ { O_APPEND, P9_DOTL_APPEND },
+ { O_NONBLOCK, P9_DOTL_NONBLOCK },
+ { O_DSYNC, P9_DOTL_DSYNC },
+ { FASYNC, P9_DOTL_FASYNC },
+ { O_DIRECT, P9_DOTL_DIRECT },
+ { O_LARGEFILE, P9_DOTL_LARGEFILE },
+ { O_DIRECTORY, P9_DOTL_DIRECTORY },
+ { O_NOFOLLOW, P9_DOTL_NOFOLLOW },
+ { O_NOATIME, P9_DOTL_NOATIME },
+ { O_CLOEXEC, P9_DOTL_CLOEXEC },
+ { O_SYNC, P9_DOTL_SYNC},
+ };
+ for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) {
+ if (flags & dotl_oflag_map[i].open_flag)
+ rflags |= dotl_oflag_map[i].dotl_flag;
+ }
+ return rflags;
+}
+
+/**
+ * v9fs_open_to_dotl_flags- convert Linux specific open flags to
+ * plan 9 open flag.
+ * @flags: flags to convert
+ */
+int v9fs_open_to_dotl_flags(int flags)
+{
+ int rflags = 0;
+
+ /*
+ * We have same bits for P9_DOTL_READONLY, P9_DOTL_WRONLY
+ * and P9_DOTL_NOACCESS
+ */
+ rflags |= flags & O_ACCMODE;
+ rflags |= v9fs_mapped_dotl_flags(flags);
+
+ return rflags;
+}
+
/**
* v9fs_vfs_create_dotl - VFS hook to create files for 9P2000.L protocol.
* @dir: directory inode that is being created
@@ -213,7 +311,8 @@
"Failed to get acl values in creat %d\n", err);
goto error;
}
- err = p9_client_create_dotl(ofid, name, flags, mode, gid, &qid);
+ err = p9_client_create_dotl(ofid, name, v9fs_open_to_dotl_flags(flags),
+ mode, gid, &qid);
if (err < 0) {
P9_DPRINTK(P9_DEBUG_VFS,
"p9_client_open_dotl failed in creat %d\n",
@@ -230,19 +329,19 @@
fid = NULL;
goto error;
}
- inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
+ inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err);
goto error;
}
- d_instantiate(dentry, inode);
err = v9fs_fid_add(dentry, fid);
if (err < 0)
goto error;
+ d_instantiate(dentry, inode);
/* Now set the ACL based on the default value */
- v9fs_set_create_acl(dentry, dacl, pacl);
+ v9fs_set_create_acl(dentry, &dacl, &pacl);
v9inode = V9FS_I(inode);
mutex_lock(&v9inode->v_mutex);
@@ -283,6 +382,7 @@
err_clunk_old_fid:
if (ofid)
p9_client_clunk(ofid);
+ v9fs_set_create_acl(NULL, &dacl, &pacl);
return err;
}
@@ -350,17 +450,17 @@
goto error;
}
- inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
+ inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n",
err);
goto error;
}
- d_instantiate(dentry, inode);
err = v9fs_fid_add(dentry, fid);
if (err < 0)
goto error;
+ d_instantiate(dentry, inode);
fid = NULL;
} else {
/*
@@ -368,7 +468,7 @@
* inode with stat. We need to get an inode
* so that we can set the acl with dentry
*/
- inode = v9fs_get_inode(dir->i_sb, mode);
+ inode = v9fs_get_inode(dir->i_sb, mode, 0);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
goto error;
@@ -376,12 +476,13 @@
d_instantiate(dentry, inode);
}
/* Now set the ACL based on the default value */
- v9fs_set_create_acl(dentry, dacl, pacl);
+ v9fs_set_create_acl(dentry, &dacl, &pacl);
inc_nlink(dir);
v9fs_invalidate_inode_attr(dir);
error:
if (fid)
p9_client_clunk(fid);
+ v9fs_set_create_acl(NULL, &dacl, &pacl);
return err;
}
@@ -493,6 +594,7 @@
void
v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)
{
+ mode_t mode;
struct v9fs_inode *v9inode = V9FS_I(inode);
if ((stat->st_result_mask & P9_STATS_BASIC) == P9_STATS_BASIC) {
@@ -505,11 +607,10 @@
inode->i_uid = stat->st_uid;
inode->i_gid = stat->st_gid;
inode->i_nlink = stat->st_nlink;
- inode->i_mode = stat->st_mode;
- inode->i_rdev = new_decode_dev(stat->st_rdev);
- if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode)))
- init_special_inode(inode, inode->i_mode, inode->i_rdev);
+ mode = stat->st_mode & S_IALLUGO;
+ mode |= inode->i_mode & ~S_IALLUGO;
+ inode->i_mode = mode;
i_size_write(inode, stat->st_size);
inode->i_blocks = stat->st_blocks;
@@ -547,7 +648,7 @@
inode->i_blocks = stat->st_blocks;
}
if (stat->st_result_mask & P9_STATS_GEN)
- inode->i_generation = stat->st_gen;
+ inode->i_generation = stat->st_gen;
/* Currently we don't support P9_STATS_BTIME and P9_STATS_DATA_VERSION
* because the inode structure does not have fields for them.
@@ -603,21 +704,21 @@
}
/* instantiate inode and assign the unopened fid to dentry */
- inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
+ inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n",
err);
goto error;
}
- d_instantiate(dentry, inode);
err = v9fs_fid_add(dentry, fid);
if (err < 0)
goto error;
+ d_instantiate(dentry, inode);
fid = NULL;
} else {
/* Not in cached mode. No need to populate inode with stat */
- inode = v9fs_get_inode(dir->i_sb, S_IFLNK);
+ inode = v9fs_get_inode(dir->i_sb, S_IFLNK, 0);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
goto error;
@@ -756,24 +857,24 @@
goto error;
}
- inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
+ inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n",
err);
goto error;
}
- d_instantiate(dentry, inode);
err = v9fs_fid_add(dentry, fid);
if (err < 0)
goto error;
+ d_instantiate(dentry, inode);
fid = NULL;
} else {
/*
* Not in cached mode. No need to populate inode with stat.
* socket syscall returns a fd, so we need instantiate
*/
- inode = v9fs_get_inode(dir->i_sb, mode);
+ inode = v9fs_get_inode(dir->i_sb, mode, rdev);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
goto error;
@@ -781,10 +882,11 @@
d_instantiate(dentry, inode);
}
/* Now set the ACL based on the default value */
- v9fs_set_create_acl(dentry, dacl, pacl);
+ v9fs_set_create_acl(dentry, &dacl, &pacl);
error:
if (fid)
p9_client_clunk(fid);
+ v9fs_set_create_acl(NULL, &dacl, &pacl);
return err;
}
@@ -838,6 +940,11 @@
st = p9_client_getattr_dotl(fid, P9_STATS_ALL);
if (IS_ERR(st))
return PTR_ERR(st);
+ /*
+ * Don't update inode if the file type is different
+ */
+ if ((inode->i_mode & S_IFMT) != (st->st_mode & S_IFMT))
+ goto out;
spin_lock(&inode->i_lock);
/*
@@ -849,6 +956,7 @@
if (v9ses->cache)
inode->i_size = i_size;
spin_unlock(&inode->i_lock);
+out:
kfree(st);
return 0;
}
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index feef6cd..c70251d 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -149,7 +149,7 @@
else
sb->s_d_op = &v9fs_dentry_operations;
- inode = v9fs_get_inode(sb, S_IFDIR | mode);
+ inode = v9fs_get_inode(sb, S_IFDIR | mode, 0);
if (IS_ERR(inode)) {
retval = PTR_ERR(inode);
goto release_sb;
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index 54b8c28..720d885 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -474,17 +474,22 @@
befs_data_stream *data = &befs_ino->i_data.ds;
befs_off_t len = data->size;
- befs_debug(sb, "Follow long symlink");
-
- link = kmalloc(len, GFP_NOFS);
- if (!link) {
- link = ERR_PTR(-ENOMEM);
- } else if (befs_read_lsymlink(sb, data, link, len) != len) {
- kfree(link);
- befs_error(sb, "Failed to read entire long symlink");
+ if (len == 0) {
+ befs_error(sb, "Long symlink with illegal length");
link = ERR_PTR(-EIO);
} else {
- link[len - 1] = '\0';
+ befs_debug(sb, "Follow long symlink");
+
+ link = kmalloc(len, GFP_NOFS);
+ if (!link) {
+ link = ERR_PTR(-ENOMEM);
+ } else if (befs_read_lsymlink(sb, data, link, len) != len) {
+ kfree(link);
+ befs_error(sb, "Failed to read entire long symlink");
+ link = ERR_PTR(-EIO);
+ } else {
+ link[len - 1] = '\0';
+ }
}
} else {
link = befs_ino->i_data.symlink;
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 610e8e0..194cf66 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -1419,6 +1419,11 @@
WARN_ON_ONCE(bdev->bd_holders);
sync_blockdev(bdev);
kill_bdev(bdev);
+ /* ->release can cause the old bdi to disappear,
+ * so must switch it out first
+ */
+ bdev_inode_switch_bdi(bdev->bd_inode,
+ &default_backing_dev_info);
}
if (bdev->bd_contains == bdev) {
if (disk->fops->release)
@@ -1432,8 +1437,6 @@
disk_put_part(bdev->bd_part);
bdev->bd_part = NULL;
bdev->bd_disk = NULL;
- bdev_inode_switch_bdi(bdev->bd_inode,
- &default_backing_dev_info);
if (bdev != bdev->bd_contains)
victim = bdev->bd_contains;
bdev->bd_contains = NULL;
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 71cd456..7e20a65 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -1784,6 +1784,9 @@
for (i = 0; i < multi->num_stripes; i++, stripe++) {
+ if (!stripe->dev->can_discard)
+ continue;
+
ret = btrfs_issue_discard(stripe->dev->bdev,
stripe->physical,
stripe->length);
@@ -1791,11 +1794,16 @@
discarded_bytes += stripe->length;
else if (ret != -EOPNOTSUPP)
break;
+
+ /*
+ * Just in case we get back EOPNOTSUPP for some reason,
+ * just ignore the return value so we don't screw up
+ * people calling discard_extent.
+ */
+ ret = 0;
}
kfree(multi);
}
- if (discarded_bytes && ret == -EOPNOTSUPP)
- ret = 0;
if (actual_bytes)
*actual_bytes = discarded_bytes;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 3601f0a..d42e6bf 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -4124,7 +4124,8 @@
/* special case for "." */
if (filp->f_pos == 0) {
- over = filldir(dirent, ".", 1, 1, btrfs_ino(inode), DT_DIR);
+ over = filldir(dirent, ".", 1,
+ filp->f_pos, btrfs_ino(inode), DT_DIR);
if (over)
return 0;
filp->f_pos = 1;
@@ -4133,7 +4134,7 @@
if (filp->f_pos == 1) {
u64 pino = parent_ino(filp->f_path.dentry);
over = filldir(dirent, "..", 2,
- 2, pino, DT_DIR);
+ filp->f_pos, pino, DT_DIR);
if (over)
return 0;
filp->f_pos = 2;
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 4ce8a9f..7fa128d 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -799,14 +799,15 @@
struct extent_buffer *eb, int slot,
struct btrfs_key *key)
{
- struct inode *dir;
- int ret;
struct btrfs_inode_ref *ref;
+ struct btrfs_dir_item *di;
+ struct inode *dir;
struct inode *inode;
- char *name;
- int namelen;
unsigned long ref_ptr;
unsigned long ref_end;
+ char *name;
+ int namelen;
+ int ret;
int search_done = 0;
/*
@@ -909,6 +910,25 @@
}
btrfs_release_path(path);
+ /* look for a conflicting sequence number */
+ di = btrfs_lookup_dir_index_item(trans, root, path, btrfs_ino(dir),
+ btrfs_inode_ref_index(eb, ref),
+ name, namelen, 0);
+ if (di && !IS_ERR(di)) {
+ ret = drop_one_dir_item(trans, root, path, dir, di);
+ BUG_ON(ret);
+ }
+ btrfs_release_path(path);
+
+ /* look for a conflicing name */
+ di = btrfs_lookup_dir_item(trans, root, path, btrfs_ino(dir),
+ name, namelen, 0);
+ if (di && !IS_ERR(di)) {
+ ret = drop_one_dir_item(trans, root, path, dir, di);
+ BUG_ON(ret);
+ }
+ btrfs_release_path(path);
+
insert:
/* insert our name */
ret = btrfs_add_link(trans, dir, inode, name, namelen, 0,
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 19450bc..43baaf0 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -500,6 +500,9 @@
fs_devices->rw_devices--;
}
+ if (device->can_discard)
+ fs_devices->num_can_discard--;
+
new_device = kmalloc(sizeof(*new_device), GFP_NOFS);
BUG_ON(!new_device);
memcpy(new_device, device, sizeof(*new_device));
@@ -508,6 +511,7 @@
new_device->bdev = NULL;
new_device->writeable = 0;
new_device->in_fs_metadata = 0;
+ new_device->can_discard = 0;
list_replace_rcu(&device->dev_list, &new_device->dev_list);
call_rcu(&device->rcu, free_device);
@@ -547,6 +551,7 @@
static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
fmode_t flags, void *holder)
{
+ struct request_queue *q;
struct block_device *bdev;
struct list_head *head = &fs_devices->devices;
struct btrfs_device *device;
@@ -603,6 +608,12 @@
seeding = 0;
}
+ q = bdev_get_queue(bdev);
+ if (blk_queue_discard(q)) {
+ device->can_discard = 1;
+ fs_devices->num_can_discard++;
+ }
+
device->bdev = bdev;
device->in_fs_metadata = 0;
device->mode = flags;
@@ -1542,6 +1553,7 @@
int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
{
+ struct request_queue *q;
struct btrfs_trans_handle *trans;
struct btrfs_device *device;
struct block_device *bdev;
@@ -1611,6 +1623,9 @@
lock_chunks(root);
+ q = bdev_get_queue(bdev);
+ if (blk_queue_discard(q))
+ device->can_discard = 1;
device->writeable = 1;
device->work.func = pending_bios_fn;
generate_random_uuid(device->uuid);
@@ -1646,6 +1661,8 @@
root->fs_info->fs_devices->num_devices++;
root->fs_info->fs_devices->open_devices++;
root->fs_info->fs_devices->rw_devices++;
+ if (device->can_discard)
+ root->fs_info->fs_devices->num_can_discard++;
root->fs_info->fs_devices->total_rw_bytes += device->total_bytes;
if (!blk_queue_nonrot(bdev_get_queue(bdev)))
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 7c12d61..6d866db 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -48,6 +48,7 @@
int writeable;
int in_fs_metadata;
int missing;
+ int can_discard;
spinlock_t io_lock;
@@ -104,6 +105,7 @@
u64 rw_devices;
u64 missing_devices;
u64 total_rw_bytes;
+ u64 num_can_discard;
struct block_device *latest_bdev;
/* all of the devices in the FS, protected by a mutex
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index bc4b12c..53e7d72 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -566,6 +566,12 @@
struct inode *dir = dentry->d_inode;
struct dentry *child;
+ if (!dir) {
+ dput(dentry);
+ dentry = ERR_PTR(-ENOENT);
+ break;
+ }
+
/* skip separators */
while (*s == sep)
s++;
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 1a9fe7f..07132c4 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -4079,7 +4079,8 @@
T2_FNEXT_RSP_PARMS *parms;
char *response_data;
int rc = 0;
- int bytes_returned, name_len;
+ int bytes_returned;
+ unsigned int name_len;
__u16 params, byte_count;
cFYI(1, "In FindNext");
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index ccc1afa..2451627 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1258,7 +1258,7 @@
/* ignore */
} else if (strnicmp(data, "guest", 5) == 0) {
/* ignore */
- } else if (strnicmp(data, "rw", 2) == 0) {
+ } else if (strnicmp(data, "rw", 2) == 0 && strlen(data) == 2) {
/* ignore */
} else if (strnicmp(data, "ro", 2) == 0) {
/* ignore */
@@ -1361,7 +1361,7 @@
vol->server_ino = 1;
} else if (strnicmp(data, "noserverino", 9) == 0) {
vol->server_ino = 0;
- } else if (strnicmp(data, "rwpidforward", 4) == 0) {
+ } else if (strnicmp(data, "rwpidforward", 12) == 0) {
vol->rwpidforward = 1;
} else if (strnicmp(data, "cifsacl", 7) == 0) {
vol->cifs_acl = 1;
@@ -2838,7 +2838,8 @@
kfree(volume_info->username);
kzfree(volume_info->password);
kfree(volume_info->UNC);
- kfree(volume_info->UNCip);
+ if (volume_info->UNCip != volume_info->UNC + 2)
+ kfree(volume_info->UNCip);
kfree(volume_info->domainname);
kfree(volume_info->iocharset);
kfree(volume_info->prepath);
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index d8d26f3..16cdd6d 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -110,8 +110,8 @@
}
rcu_read_unlock();
if (namelen != dfsplen || read_seqretry(&rename_lock, seq)) {
- cERROR(1, "did not end path lookup where expected namelen is %d",
- namelen);
+ cFYI(1, "did not end path lookup where expected. namelen=%d "
+ "dfsplen=%d", namelen, dfsplen);
/* presumably this is only possible if racing with a rename
of one of the parent directories (we can not lock the dentries
above us to prevent this, but retrying should be harmless) */
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 9b018c8..a7b2dcd 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -764,20 +764,10 @@
if (full_path == NULL)
return full_path;
- if (dfsplen) {
+ if (dfsplen)
strncpy(full_path, tcon->treeName, dfsplen);
- /* switch slash direction in prepath depending on whether
- * windows or posix style path names
- */
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
- int i;
- for (i = 0; i < dfsplen; i++) {
- if (full_path[i] == '\\')
- full_path[i] = '/';
- }
- }
- }
strncpy(full_path + dfsplen, vol->prepath, pplen);
+ convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb));
full_path[dfsplen + pplen] = 0; /* add trailing null */
return full_path;
}
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 147aa22..c1b9c4b 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -362,6 +362,8 @@
mid = AllocMidQEntry(hdr, server);
if (mid == NULL) {
mutex_unlock(&server->srv_mutex);
+ atomic_dec(&server->inFlight);
+ wake_up(&server->request_q);
return -ENOMEM;
}
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 9f1bb74..b4a6bef 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -175,6 +175,7 @@
ecryptfs_opt_encrypted_view, ecryptfs_opt_fnek_sig,
ecryptfs_opt_fn_cipher, ecryptfs_opt_fn_cipher_key_bytes,
ecryptfs_opt_unlink_sigs, ecryptfs_opt_mount_auth_tok_only,
+ ecryptfs_opt_check_dev_ruid,
ecryptfs_opt_err };
static const match_table_t tokens = {
@@ -191,6 +192,7 @@
{ecryptfs_opt_fn_cipher_key_bytes, "ecryptfs_fn_key_bytes=%u"},
{ecryptfs_opt_unlink_sigs, "ecryptfs_unlink_sigs"},
{ecryptfs_opt_mount_auth_tok_only, "ecryptfs_mount_auth_tok_only"},
+ {ecryptfs_opt_check_dev_ruid, "ecryptfs_check_dev_ruid"},
{ecryptfs_opt_err, NULL}
};
@@ -236,6 +238,7 @@
* ecryptfs_parse_options
* @sb: The ecryptfs super block
* @options: The options passed to the kernel
+ * @check_ruid: set to 1 if device uid should be checked against the ruid
*
* Parse mount options:
* debug=N - ecryptfs_verbosity level for debug output
@@ -251,7 +254,8 @@
*
* Returns zero on success; non-zero on error
*/
-static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options)
+static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options,
+ uid_t *check_ruid)
{
char *p;
int rc = 0;
@@ -276,6 +280,8 @@
char *cipher_key_bytes_src;
char *fn_cipher_key_bytes_src;
+ *check_ruid = 0;
+
if (!options) {
rc = -EINVAL;
goto out;
@@ -380,6 +386,9 @@
mount_crypt_stat->flags |=
ECRYPTFS_GLOBAL_MOUNT_AUTH_TOK_ONLY;
break;
+ case ecryptfs_opt_check_dev_ruid:
+ *check_ruid = 1;
+ break;
case ecryptfs_opt_err:
default:
printk(KERN_WARNING
@@ -475,6 +484,7 @@
const char *err = "Getting sb failed";
struct inode *inode;
struct path path;
+ uid_t check_ruid;
int rc;
sbi = kmem_cache_zalloc(ecryptfs_sb_info_cache, GFP_KERNEL);
@@ -483,7 +493,7 @@
goto out;
}
- rc = ecryptfs_parse_options(sbi, raw_data);
+ rc = ecryptfs_parse_options(sbi, raw_data, &check_ruid);
if (rc) {
err = "Error parsing options";
goto out;
@@ -521,6 +531,15 @@
"known incompatibilities\n");
goto out_free;
}
+
+ if (check_ruid && path.dentry->d_inode->i_uid != current_uid()) {
+ rc = -EPERM;
+ printk(KERN_ERR "Mount of device (uid: %d) not owned by "
+ "requested user (uid: %d)\n",
+ path.dentry->d_inode->i_uid, current_uid());
+ goto out_free;
+ }
+
ecryptfs_set_superblock_lower(s, path.dentry->d_sb);
s->s_maxbytes = path.dentry->d_sb->s_maxbytes;
s->s_blocksize = path.dentry->d_sb->s_blocksize;
diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c
index 85d4309..3745f7c 100644
--- a/fs/ecryptfs/read_write.c
+++ b/fs/ecryptfs/read_write.c
@@ -39,15 +39,16 @@
int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data,
loff_t offset, size_t size)
{
- struct ecryptfs_inode_info *inode_info;
+ struct file *lower_file;
mm_segment_t fs_save;
ssize_t rc;
- inode_info = ecryptfs_inode_to_private(ecryptfs_inode);
- BUG_ON(!inode_info->lower_file);
+ lower_file = ecryptfs_inode_to_private(ecryptfs_inode)->lower_file;
+ if (!lower_file)
+ return -EIO;
fs_save = get_fs();
set_fs(get_ds());
- rc = vfs_write(inode_info->lower_file, data, size, &offset);
+ rc = vfs_write(lower_file, data, size, &offset);
set_fs(fs_save);
mark_inode_dirty_sync(ecryptfs_inode);
return rc;
@@ -225,15 +226,16 @@
int ecryptfs_read_lower(char *data, loff_t offset, size_t size,
struct inode *ecryptfs_inode)
{
- struct ecryptfs_inode_info *inode_info =
- ecryptfs_inode_to_private(ecryptfs_inode);
+ struct file *lower_file;
mm_segment_t fs_save;
ssize_t rc;
- BUG_ON(!inode_info->lower_file);
+ lower_file = ecryptfs_inode_to_private(ecryptfs_inode)->lower_file;
+ if (!lower_file)
+ return -EIO;
fs_save = get_fs();
set_fs(get_ds());
- rc = vfs_read(inode_info->lower_file, data, size, &offset);
+ rc = vfs_read(lower_file, data, size, &offset);
set_fs(fs_save);
return rc;
}
diff --git a/fs/exec.c b/fs/exec.c
index 6075a1e..044c13f 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1411,6 +1411,8 @@
printable(bprm->buf[2]) &&
printable(bprm->buf[3]))
break; /* -ENOEXEC */
+ if (try)
+ break; /* -ENOEXEC */
request_module("binfmt-%04x", *(unsigned short *)(&bprm->buf[2]));
#endif
}
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index 34b6d9b..e5a7111 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -2210,9 +2210,11 @@
/*
* For non-fast symlinks, we just allocate inode and put it on
* orphan list in the first transaction => we need bitmap,
- * group descriptor, sb, inode block, quota blocks.
+ * group descriptor, sb, inode block, quota blocks, and
+ * possibly selinux xattr blocks.
*/
- credits = 4 + EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb);
+ credits = 4 + EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb) +
+ EXT3_XATTR_TRANS_BLOCKS;
} else {
/*
* Fast symlink. We have to add entry to directory
diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h
index bb85757..5802fa1 100644
--- a/fs/ext4/ext4_jbd2.h
+++ b/fs/ext4/ext4_jbd2.h
@@ -289,10 +289,10 @@
static inline int ext4_should_writeback_data(struct inode *inode)
{
- if (!S_ISREG(inode->i_mode))
- return 0;
if (EXT4_JOURNAL(inode) == NULL)
return 1;
+ if (!S_ISREG(inode->i_mode))
+ return 0;
if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA))
return 0;
if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 1593004..c94774c 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -189,6 +189,12 @@
int err;
trace_ext4_evict_inode(inode);
+
+ mutex_lock(&inode->i_mutex);
+ ext4_flush_completed_IO(inode);
+ mutex_unlock(&inode->i_mutex);
+ ext4_ioend_wait(inode);
+
if (inode->i_nlink) {
truncate_inode_pages(&inode->i_data, 0);
goto no_delete;
@@ -1849,6 +1855,8 @@
from = pos & (PAGE_CACHE_SIZE - 1);
to = from + len;
+ BUG_ON(!ext4_handle_valid(handle));
+
if (copied < len) {
if (!PageUptodate(page))
copied = 0;
@@ -2569,6 +2577,8 @@
goto out;
}
+ BUG_ON(!ext4_handle_valid(handle));
+
ret = walk_page_buffers(handle, page_bufs, 0, len, NULL,
do_journal_get_write_access);
@@ -2746,7 +2756,7 @@
index = wbc->range_start >> PAGE_CACHE_SHIFT;
end = wbc->range_end >> PAGE_CACHE_SHIFT;
- if (wbc->sync_mode == WB_SYNC_ALL)
+ if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages)
tag = PAGECACHE_TAG_TOWRITE;
else
tag = PAGECACHE_TAG_DIRTY;
@@ -2978,7 +2988,7 @@
}
retry:
- if (wbc->sync_mode == WB_SYNC_ALL)
+ if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages)
tag_pages_for_writeback(mapping, index, end);
while (!ret && wbc->nr_to_write > 0) {
@@ -3640,8 +3650,15 @@
goto out;
}
- io_end->flag = EXT4_IO_END_UNWRITTEN;
+ /*
+ * It may be over-defensive here to check EXT4_IO_END_UNWRITTEN now,
+ * but being more careful is always safe for the future change.
+ */
inode = io_end->inode;
+ if (!(io_end->flag & EXT4_IO_END_UNWRITTEN)) {
+ io_end->flag |= EXT4_IO_END_UNWRITTEN;
+ atomic_inc(&EXT4_I(inode)->i_aiodio_unwritten);
+ }
/* Add the io_end to per-inode completed io list*/
spin_lock_irqsave(&EXT4_I(inode)->i_completed_io_lock, flags);
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index b754b77..458a394 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -2264,9 +2264,11 @@
/*
* For non-fast symlinks, we just allocate inode and put it on
* orphan list in the first transaction => we need bitmap,
- * group descriptor, sb, inode block, quota blocks.
+ * group descriptor, sb, inode block, quota blocks, and
+ * possibly selinux xattr blocks.
*/
- credits = 4 + EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb);
+ credits = 4 + EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb) +
+ EXT4_XATTR_TRANS_BLOCKS;
} else {
/*
* Fast symlink. We have to add entry to directory
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
index 7bb8f76..97e5e98 100644
--- a/fs/ext4/page-io.c
+++ b/fs/ext4/page-io.c
@@ -338,8 +338,10 @@
if ((io_end->num_io_pages >= MAX_IO_PAGES) &&
(io_end->pages[io_end->num_io_pages-1] != io_page))
goto submit_and_retry;
- if (buffer_uninit(bh))
- io->io_end->flag |= EXT4_IO_END_UNWRITTEN;
+ if (buffer_uninit(bh) && !(io_end->flag & EXT4_IO_END_UNWRITTEN)) {
+ io_end->flag |= EXT4_IO_END_UNWRITTEN;
+ atomic_inc(&EXT4_I(inode)->i_aiodio_unwritten);
+ }
io->io_end->size += bh->b_size;
io->io_next_block++;
ret = bio_add_page(io->io_bio, bh->b_page, bh->b_size, bh_offset(bh));
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 9ea71aa..111ed9d 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -892,7 +892,6 @@
static void ext4_destroy_inode(struct inode *inode)
{
- ext4_ioend_wait(inode);
if (!list_empty(&(EXT4_I(inode)->i_orphan))) {
ext4_msg(inode->i_sb, KERN_ERR,
"Inode %lu (%p): orphan list check failed!",
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 3c72c99..49c8c98 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -36,6 +36,7 @@
long nr_pages;
struct super_block *sb;
enum writeback_sync_modes sync_mode;
+ unsigned int tagged_writepages:1;
unsigned int for_kupdate:1;
unsigned int range_cyclic:1;
unsigned int for_background:1;
@@ -418,6 +419,15 @@
spin_lock(&inode->i_lock);
inode->i_state &= ~I_SYNC;
if (!(inode->i_state & I_FREEING)) {
+ /*
+ * Sync livelock prevention. Each inode is tagged and synced in
+ * one shot. If still dirty, it will be redirty_tail()'ed below.
+ * Update the dirty time to prevent enqueue and sync it again.
+ */
+ if ((inode->i_state & I_DIRTY) &&
+ (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages))
+ inode->dirtied_when = jiffies;
+
if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) {
/*
* We didn't write back all the pages. nfs_writepages()
@@ -650,6 +660,7 @@
{
struct writeback_control wbc = {
.sync_mode = work->sync_mode,
+ .tagged_writepages = work->tagged_writepages,
.older_than_this = NULL,
.for_kupdate = work->for_kupdate,
.for_background = work->for_background,
@@ -657,7 +668,7 @@
};
unsigned long oldest_jif;
long wrote = 0;
- long write_chunk;
+ long write_chunk = MAX_WRITEBACK_PAGES;
struct inode *inode;
if (wbc.for_kupdate) {
@@ -683,9 +694,7 @@
* (quickly) tag currently dirty pages
* (maybe slowly) sync all tagged pages
*/
- if (wbc.sync_mode == WB_SYNC_NONE)
- write_chunk = MAX_WRITEBACK_PAGES;
- else
+ if (wbc.sync_mode == WB_SYNC_ALL || wbc.tagged_writepages)
write_chunk = LONG_MAX;
wbc.wb_start = jiffies; /* livelock avoidance */
@@ -1188,10 +1197,11 @@
{
DECLARE_COMPLETION_ONSTACK(done);
struct wb_writeback_work work = {
- .sb = sb,
- .sync_mode = WB_SYNC_NONE,
- .done = &done,
- .nr_pages = nr,
+ .sb = sb,
+ .sync_mode = WB_SYNC_NONE,
+ .tagged_writepages = 1,
+ .done = &done,
+ .nr_pages = nr,
};
WARN_ON(!rwsem_is_locked(&sb->s_umount));
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 99e1334..fb6fc95 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -259,10 +259,14 @@
forget->forget_one.nlookup = nlookup;
spin_lock(&fc->lock);
- fc->forget_list_tail->next = forget;
- fc->forget_list_tail = forget;
- wake_up(&fc->waitq);
- kill_fasync(&fc->fasync, SIGIO, POLL_IN);
+ if (fc->connected) {
+ fc->forget_list_tail->next = forget;
+ fc->forget_list_tail = forget;
+ wake_up(&fc->waitq);
+ kill_fasync(&fc->fasync, SIGIO, POLL_IN);
+ } else {
+ kfree(forget);
+ }
spin_unlock(&fc->lock);
}
@@ -1362,6 +1366,10 @@
if (outarg.namelen > FUSE_NAME_MAX)
goto err;
+ err = -EINVAL;
+ if (size != sizeof(outarg) + outarg.namelen + 1)
+ goto err;
+
name.name = buf;
name.len = outarg.namelen;
err = fuse_copy_one(cs, buf, outarg.namelen + 1);
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
index d685752..4e7f64b 100644
--- a/fs/hfsplus/hfsplus_fs.h
+++ b/fs/hfsplus/hfsplus_fs.h
@@ -13,6 +13,7 @@
#include <linux/fs.h>
#include <linux/mutex.h>
#include <linux/buffer_head.h>
+#include <linux/blkdev.h>
#include "hfsplus_raw.h"
#define DBG_BNODE_REFS 0x00000001
@@ -110,7 +111,9 @@
struct hfs_btree;
struct hfsplus_sb_info {
+ void *s_vhdr_buf;
struct hfsplus_vh *s_vhdr;
+ void *s_backup_vhdr_buf;
struct hfsplus_vh *s_backup_vhdr;
struct hfs_btree *ext_tree;
struct hfs_btree *cat_tree;
@@ -258,6 +261,15 @@
struct hfsplus_cat_key key;
};
+/*
+ * Find minimum acceptible I/O size for an hfsplus sb.
+ */
+static inline unsigned short hfsplus_min_io_size(struct super_block *sb)
+{
+ return max_t(unsigned short, bdev_logical_block_size(sb->s_bdev),
+ HFSPLUS_SECTOR_SIZE);
+}
+
#define hfs_btree_open hfsplus_btree_open
#define hfs_btree_close hfsplus_btree_close
#define hfs_btree_write hfsplus_btree_write
@@ -436,8 +448,8 @@
/* wrapper.c */
int hfsplus_read_wrapper(struct super_block *);
int hfs_part_find(struct super_block *, sector_t *, sector_t *);
-int hfsplus_submit_bio(struct block_device *bdev, sector_t sector,
- void *data, int rw);
+int hfsplus_submit_bio(struct super_block *sb, sector_t sector,
+ void *buf, void **data, int rw);
/* time macros */
#define __hfsp_mt2ut(t) (be32_to_cpu(t) - 2082844800U)
diff --git a/fs/hfsplus/part_tbl.c b/fs/hfsplus/part_tbl.c
index 40ad88c..eb355d8 100644
--- a/fs/hfsplus/part_tbl.c
+++ b/fs/hfsplus/part_tbl.c
@@ -88,11 +88,12 @@
return -ENOENT;
}
-static int hfs_parse_new_pmap(struct super_block *sb, struct new_pmap *pm,
- sector_t *part_start, sector_t *part_size)
+static int hfs_parse_new_pmap(struct super_block *sb, void *buf,
+ struct new_pmap *pm, sector_t *part_start, sector_t *part_size)
{
struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
int size = be32_to_cpu(pm->pmMapBlkCnt);
+ int buf_size = hfsplus_min_io_size(sb);
int res;
int i = 0;
@@ -107,11 +108,14 @@
if (++i >= size)
return -ENOENT;
- res = hfsplus_submit_bio(sb->s_bdev,
- *part_start + HFS_PMAP_BLK + i,
- pm, READ);
- if (res)
- return res;
+ pm = (struct new_pmap *)((u8 *)pm + HFSPLUS_SECTOR_SIZE);
+ if ((u8 *)pm - (u8 *)buf >= buf_size) {
+ res = hfsplus_submit_bio(sb,
+ *part_start + HFS_PMAP_BLK + i,
+ buf, (void **)&pm, READ);
+ if (res)
+ return res;
+ }
} while (pm->pmSig == cpu_to_be16(HFS_NEW_PMAP_MAGIC));
return -ENOENT;
@@ -124,15 +128,15 @@
int hfs_part_find(struct super_block *sb,
sector_t *part_start, sector_t *part_size)
{
- void *data;
+ void *buf, *data;
int res;
- data = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL);
- if (!data)
+ buf = kmalloc(hfsplus_min_io_size(sb), GFP_KERNEL);
+ if (!buf)
return -ENOMEM;
- res = hfsplus_submit_bio(sb->s_bdev, *part_start + HFS_PMAP_BLK,
- data, READ);
+ res = hfsplus_submit_bio(sb, *part_start + HFS_PMAP_BLK,
+ buf, &data, READ);
if (res)
goto out;
@@ -141,13 +145,13 @@
res = hfs_parse_old_pmap(sb, data, part_start, part_size);
break;
case HFS_NEW_PMAP_MAGIC:
- res = hfs_parse_new_pmap(sb, data, part_start, part_size);
+ res = hfs_parse_new_pmap(sb, buf, data, part_start, part_size);
break;
default:
res = -ENOENT;
break;
}
out:
- kfree(data);
+ kfree(buf);
return res;
}
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index 84a47b7..c3a76fd 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -197,17 +197,17 @@
write_backup = 1;
}
- error2 = hfsplus_submit_bio(sb->s_bdev,
+ error2 = hfsplus_submit_bio(sb,
sbi->part_start + HFSPLUS_VOLHEAD_SECTOR,
- sbi->s_vhdr, WRITE_SYNC);
+ sbi->s_vhdr_buf, NULL, WRITE_SYNC);
if (!error)
error = error2;
if (!write_backup)
goto out;
- error2 = hfsplus_submit_bio(sb->s_bdev,
+ error2 = hfsplus_submit_bio(sb,
sbi->part_start + sbi->sect_count - 2,
- sbi->s_backup_vhdr, WRITE_SYNC);
+ sbi->s_backup_vhdr_buf, NULL, WRITE_SYNC);
if (!error)
error2 = error;
out:
@@ -251,8 +251,8 @@
hfs_btree_close(sbi->ext_tree);
iput(sbi->alloc_file);
iput(sbi->hidden_dir);
- kfree(sbi->s_vhdr);
- kfree(sbi->s_backup_vhdr);
+ kfree(sbi->s_vhdr_buf);
+ kfree(sbi->s_backup_vhdr_buf);
unload_nls(sbi->nls);
kfree(sb->s_fs_info);
sb->s_fs_info = NULL;
@@ -508,8 +508,8 @@
out_close_ext_tree:
hfs_btree_close(sbi->ext_tree);
out_free_vhdr:
- kfree(sbi->s_vhdr);
- kfree(sbi->s_backup_vhdr);
+ kfree(sbi->s_vhdr_buf);
+ kfree(sbi->s_backup_vhdr_buf);
out_unload_nls:
unload_nls(sbi->nls);
unload_nls(nls);
diff --git a/fs/hfsplus/wrapper.c b/fs/hfsplus/wrapper.c
index 4ac88ff..7b8112da 100644
--- a/fs/hfsplus/wrapper.c
+++ b/fs/hfsplus/wrapper.c
@@ -31,25 +31,67 @@
complete(bio->bi_private);
}
-int hfsplus_submit_bio(struct block_device *bdev, sector_t sector,
- void *data, int rw)
+/*
+ * hfsplus_submit_bio - Perfrom block I/O
+ * @sb: super block of volume for I/O
+ * @sector: block to read or write, for blocks of HFSPLUS_SECTOR_SIZE bytes
+ * @buf: buffer for I/O
+ * @data: output pointer for location of requested data
+ * @rw: direction of I/O
+ *
+ * The unit of I/O is hfsplus_min_io_size(sb), which may be bigger than
+ * HFSPLUS_SECTOR_SIZE, and @buf must be sized accordingly. On reads
+ * @data will return a pointer to the start of the requested sector,
+ * which may not be the same location as @buf.
+ *
+ * If @sector is not aligned to the bdev logical block size it will
+ * be rounded down. For writes this means that @buf should contain data
+ * that starts at the rounded-down address. As long as the data was
+ * read using hfsplus_submit_bio() and the same buffer is used things
+ * will work correctly.
+ */
+int hfsplus_submit_bio(struct super_block *sb, sector_t sector,
+ void *buf, void **data, int rw)
{
DECLARE_COMPLETION_ONSTACK(wait);
struct bio *bio;
int ret = 0;
+ unsigned int io_size;
+ loff_t start;
+ int offset;
+
+ /*
+ * Align sector to hardware sector size and find offset. We
+ * assume that io_size is a power of two, which _should_
+ * be true.
+ */
+ io_size = hfsplus_min_io_size(sb);
+ start = (loff_t)sector << HFSPLUS_SECTOR_SHIFT;
+ offset = start & (io_size - 1);
+ sector &= ~((io_size >> HFSPLUS_SECTOR_SHIFT) - 1);
bio = bio_alloc(GFP_NOIO, 1);
bio->bi_sector = sector;
- bio->bi_bdev = bdev;
+ bio->bi_bdev = sb->s_bdev;
bio->bi_end_io = hfsplus_end_io_sync;
bio->bi_private = &wait;
- /*
- * We always submit one sector at a time, so bio_add_page must not fail.
- */
- if (bio_add_page(bio, virt_to_page(data), HFSPLUS_SECTOR_SIZE,
- offset_in_page(data)) != HFSPLUS_SECTOR_SIZE)
- BUG();
+ if (!(rw & WRITE) && data)
+ *data = (u8 *)buf + offset;
+
+ while (io_size > 0) {
+ unsigned int page_offset = offset_in_page(buf);
+ unsigned int len = min_t(unsigned int, PAGE_SIZE - page_offset,
+ io_size);
+
+ ret = bio_add_page(bio, virt_to_page(buf), len, page_offset);
+ if (ret != len) {
+ ret = -EIO;
+ goto out;
+ }
+ io_size -= len;
+ buf = (u8 *)buf + len;
+ }
submit_bio(rw, bio);
wait_for_completion(&wait);
@@ -57,8 +99,9 @@
if (!bio_flagged(bio, BIO_UPTODATE))
ret = -EIO;
+out:
bio_put(bio);
- return ret;
+ return ret < 0 ? ret : 0;
}
static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd)
@@ -147,17 +190,17 @@
}
error = -ENOMEM;
- sbi->s_vhdr = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL);
- if (!sbi->s_vhdr)
+ sbi->s_vhdr_buf = kmalloc(hfsplus_min_io_size(sb), GFP_KERNEL);
+ if (!sbi->s_vhdr_buf)
goto out;
- sbi->s_backup_vhdr = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL);
- if (!sbi->s_backup_vhdr)
+ sbi->s_backup_vhdr_buf = kmalloc(hfsplus_min_io_size(sb), GFP_KERNEL);
+ if (!sbi->s_backup_vhdr_buf)
goto out_free_vhdr;
reread:
- error = hfsplus_submit_bio(sb->s_bdev,
- part_start + HFSPLUS_VOLHEAD_SECTOR,
- sbi->s_vhdr, READ);
+ error = hfsplus_submit_bio(sb, part_start + HFSPLUS_VOLHEAD_SECTOR,
+ sbi->s_vhdr_buf, (void **)&sbi->s_vhdr,
+ READ);
if (error)
goto out_free_backup_vhdr;
@@ -186,9 +229,9 @@
goto reread;
}
- error = hfsplus_submit_bio(sb->s_bdev,
- part_start + part_size - 2,
- sbi->s_backup_vhdr, READ);
+ error = hfsplus_submit_bio(sb, part_start + part_size - 2,
+ sbi->s_backup_vhdr_buf,
+ (void **)&sbi->s_backup_vhdr, READ);
if (error)
goto out_free_backup_vhdr;
@@ -232,9 +275,9 @@
return 0;
out_free_backup_vhdr:
- kfree(sbi->s_backup_vhdr);
+ kfree(sbi->s_backup_vhdr_buf);
out_free_vhdr:
- kfree(sbi->s_vhdr);
+ kfree(sbi->s_vhdr_buf);
out:
return error;
}
diff --git a/fs/namei.c b/fs/namei.c
index 14ab8d3..b456c7a 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2582,6 +2582,7 @@
if (!dir->i_op->rmdir)
return -EPERM;
+ dget(dentry);
mutex_lock(&dentry->d_inode->i_mutex);
error = -EBUSY;
@@ -2602,6 +2603,7 @@
out:
mutex_unlock(&dentry->d_inode->i_mutex);
+ dput(dentry);
if (!error)
d_delete(dentry);
return error;
@@ -3005,6 +3007,7 @@
if (error)
return error;
+ dget(new_dentry);
if (target)
mutex_lock(&target->i_mutex);
@@ -3025,6 +3028,7 @@
out:
if (target)
mutex_unlock(&target->i_mutex);
+ dput(new_dentry);
if (!error)
if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE))
d_move(old_dentry,new_dentry);
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h
index b257383..07df5f1 100644
--- a/fs/nfs/callback.h
+++ b/fs/nfs/callback.h
@@ -38,6 +38,7 @@
struct cb_process_state {
__be32 drc_status;
struct nfs_client *clp;
+ int slotid;
};
struct cb_compound_hdr_arg {
@@ -166,7 +167,6 @@
void *dummy, struct cb_process_state *cps);
extern void nfs4_check_drain_bc_complete(struct nfs4_session *ses);
-extern void nfs4_cb_take_slot(struct nfs_client *clp);
struct cb_devicenotifyitem {
uint32_t cbd_notify_type;
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index d4d1954..aaa09e9 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -333,7 +333,7 @@
/* Normal */
if (likely(args->csa_sequenceid == slot->seq_nr + 1)) {
slot->seq_nr++;
- return htonl(NFS4_OK);
+ goto out_ok;
}
/* Replay */
@@ -352,11 +352,14 @@
/* Wraparound */
if (args->csa_sequenceid == 1 && (slot->seq_nr + 1) == 0) {
slot->seq_nr = 1;
- return htonl(NFS4_OK);
+ goto out_ok;
}
/* Misordered request */
return htonl(NFS4ERR_SEQ_MISORDERED);
+out_ok:
+ tbl->highest_used_slotid = args->csa_slotid;
+ return htonl(NFS4_OK);
}
/*
@@ -418,26 +421,37 @@
struct cb_sequenceres *res,
struct cb_process_state *cps)
{
+ struct nfs4_slot_table *tbl;
struct nfs_client *clp;
int i;
__be32 status = htonl(NFS4ERR_BADSESSION);
- cps->clp = NULL;
-
clp = nfs4_find_client_sessionid(args->csa_addr, &args->csa_sessionid);
if (clp == NULL)
goto out;
+ tbl = &clp->cl_session->bc_slot_table;
+
+ spin_lock(&tbl->slot_tbl_lock);
/* state manager is resetting the session */
if (test_bit(NFS4_SESSION_DRAINING, &clp->cl_session->session_state)) {
- status = NFS4ERR_DELAY;
+ spin_unlock(&tbl->slot_tbl_lock);
+ status = htonl(NFS4ERR_DELAY);
+ /* Return NFS4ERR_BADSESSION if we're draining the session
+ * in order to reset it.
+ */
+ if (test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state))
+ status = htonl(NFS4ERR_BADSESSION);
goto out;
}
status = validate_seqid(&clp->cl_session->bc_slot_table, args);
+ spin_unlock(&tbl->slot_tbl_lock);
if (status)
goto out;
+ cps->slotid = args->csa_slotid;
+
/*
* Check for pending referring calls. If a match is found, a
* related callback was received before the response to the original
@@ -454,7 +468,6 @@
res->csr_slotid = args->csa_slotid;
res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
- nfs4_cb_take_slot(clp);
out:
cps->clp = clp; /* put in nfs4_callback_compound */
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
index c6c86a7..918ad64 100644
--- a/fs/nfs/callback_xdr.c
+++ b/fs/nfs/callback_xdr.c
@@ -754,26 +754,15 @@
* Let the state manager know callback processing done.
* A single slot, so highest used slotid is either 0 or -1
*/
- tbl->highest_used_slotid--;
+ tbl->highest_used_slotid = -1;
nfs4_check_drain_bc_complete(session);
spin_unlock(&tbl->slot_tbl_lock);
}
-static void nfs4_cb_free_slot(struct nfs_client *clp)
+static void nfs4_cb_free_slot(struct cb_process_state *cps)
{
- if (clp && clp->cl_session)
- nfs4_callback_free_slot(clp->cl_session);
-}
-
-/* A single slot, so highest used slotid is either 0 or -1 */
-void nfs4_cb_take_slot(struct nfs_client *clp)
-{
- struct nfs4_slot_table *tbl = &clp->cl_session->bc_slot_table;
-
- spin_lock(&tbl->slot_tbl_lock);
- tbl->highest_used_slotid++;
- BUG_ON(tbl->highest_used_slotid != 0);
- spin_unlock(&tbl->slot_tbl_lock);
+ if (cps->slotid != -1)
+ nfs4_callback_free_slot(cps->clp->cl_session);
}
#else /* CONFIG_NFS_V4_1 */
@@ -784,7 +773,7 @@
return htonl(NFS4ERR_MINOR_VERS_MISMATCH);
}
-static void nfs4_cb_free_slot(struct nfs_client *clp)
+static void nfs4_cb_free_slot(struct cb_process_state *cps)
{
}
#endif /* CONFIG_NFS_V4_1 */
@@ -866,6 +855,7 @@
struct cb_process_state cps = {
.drc_status = 0,
.clp = NULL,
+ .slotid = -1,
};
unsigned int nops = 0;
@@ -906,7 +896,7 @@
*hdr_res.status = status;
*hdr_res.nops = htonl(nops);
- nfs4_cb_free_slot(cps.clp);
+ nfs4_cb_free_slot(&cps);
nfs_put_client(cps.clp);
dprintk("%s: done, status = %u\n", __func__, ntohl(status));
return rpc_success;
diff --git a/fs/nfs/objlayout/objio_osd.c b/fs/nfs/objlayout/objio_osd.c
index 8ff2ea3..1d1dc1e 100644
--- a/fs/nfs/objlayout/objio_osd.c
+++ b/fs/nfs/objlayout/objio_osd.c
@@ -479,7 +479,6 @@
for (i = 0; i < ios->numdevs; i++) {
struct osd_sense_info osi;
struct osd_request *or = ios->per_dev[i].or;
- unsigned dev;
int ret;
if (!or)
@@ -500,9 +499,8 @@
continue; /* we recovered */
}
- dev = ios->per_dev[i].dev;
- objlayout_io_set_result(&ios->ol_state, dev,
- &ios->layout->comps[dev].oc_object_id,
+ objlayout_io_set_result(&ios->ol_state, i,
+ &ios->layout->comps[i].oc_object_id,
osd_pri_2_pnfs_err(osi.osd_err_pri),
ios->per_dev[i].offset,
ios->per_dev[i].length,
@@ -589,22 +587,19 @@
}
static int _add_stripe_unit(struct objio_state *ios, unsigned *cur_pg,
- unsigned pgbase, struct _objio_per_comp *per_dev, int cur_len,
+ unsigned pgbase, struct _objio_per_comp *per_dev, int len,
gfp_t gfp_flags)
{
unsigned pg = *cur_pg;
+ int cur_len = len;
struct request_queue *q =
osd_request_queue(_io_od(ios, per_dev->dev));
- per_dev->length += cur_len;
-
if (per_dev->bio == NULL) {
- unsigned stripes = ios->layout->num_comps /
- ios->layout->mirrors_p1;
- unsigned pages_in_stripe = stripes *
+ unsigned pages_in_stripe = ios->layout->group_width *
(ios->layout->stripe_unit / PAGE_SIZE);
unsigned bio_size = (ios->ol_state.nr_pages + pages_in_stripe) /
- stripes;
+ ios->layout->group_width;
if (BIO_MAX_PAGES_KMALLOC < bio_size)
bio_size = BIO_MAX_PAGES_KMALLOC;
@@ -632,6 +627,7 @@
}
BUG_ON(cur_len);
+ per_dev->length += len;
*cur_pg = pg;
return 0;
}
@@ -650,7 +646,7 @@
int ret = 0;
while (length) {
- struct _objio_per_comp *per_dev = &ios->per_dev[dev];
+ struct _objio_per_comp *per_dev = &ios->per_dev[dev - first_dev];
unsigned cur_len, page_off = 0;
if (!per_dev->length) {
@@ -670,8 +666,8 @@
cur_len = stripe_unit;
}
- if (max_comp < dev)
- max_comp = dev;
+ if (max_comp < dev - first_dev)
+ max_comp = dev - first_dev;
} else {
cur_len = stripe_unit;
}
@@ -806,7 +802,7 @@
struct _objio_per_comp *per_dev = &ios->per_dev[cur_comp];
unsigned dev = per_dev->dev;
struct pnfs_osd_object_cred *cred =
- &ios->layout->comps[dev];
+ &ios->layout->comps[cur_comp];
struct osd_obj_id obj = {
.partition = cred->oc_object_id.oid_partition_id,
.id = cred->oc_object_id.oid_object_id,
@@ -904,7 +900,7 @@
for (; cur_comp < last_comp; ++cur_comp, ++dev) {
struct osd_request *or = NULL;
struct pnfs_osd_object_cred *cred =
- &ios->layout->comps[dev];
+ &ios->layout->comps[cur_comp];
struct osd_obj_id obj = {
.partition = cred->oc_object_id.oid_partition_id,
.id = cred->oc_object_id.oid_object_id,
diff --git a/fs/nfs/objlayout/pnfs_osd_xdr_cli.c b/fs/nfs/objlayout/pnfs_osd_xdr_cli.c
index 16fc758..b3918f7 100644
--- a/fs/nfs/objlayout/pnfs_osd_xdr_cli.c
+++ b/fs/nfs/objlayout/pnfs_osd_xdr_cli.c
@@ -170,6 +170,9 @@
p = _osd_xdr_decode_data_map(p, &layout->olo_map);
layout->olo_comps_index = be32_to_cpup(p++);
layout->olo_num_comps = be32_to_cpup(p++);
+ dprintk("%s: olo_comps_index=%d olo_num_comps=%d\n", __func__,
+ layout->olo_comps_index, layout->olo_num_comps);
+
iter->total_comps = layout->olo_num_comps;
return 0;
}
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 25b6a88..5afaa58 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -877,30 +877,54 @@
struct numa_maps md;
};
-static void gather_stats(struct page *page, struct numa_maps *md, int pte_dirty)
+static void gather_stats(struct page *page, struct numa_maps *md, int pte_dirty,
+ unsigned long nr_pages)
{
int count = page_mapcount(page);
- md->pages++;
+ md->pages += nr_pages;
if (pte_dirty || PageDirty(page))
- md->dirty++;
+ md->dirty += nr_pages;
if (PageSwapCache(page))
- md->swapcache++;
+ md->swapcache += nr_pages;
if (PageActive(page) || PageUnevictable(page))
- md->active++;
+ md->active += nr_pages;
if (PageWriteback(page))
- md->writeback++;
+ md->writeback += nr_pages;
if (PageAnon(page))
- md->anon++;
+ md->anon += nr_pages;
if (count > md->mapcount_max)
md->mapcount_max = count;
- md->node[page_to_nid(page)]++;
+ md->node[page_to_nid(page)] += nr_pages;
+}
+
+static struct page *can_gather_numa_stats(pte_t pte, struct vm_area_struct *vma,
+ unsigned long addr)
+{
+ struct page *page;
+ int nid;
+
+ if (!pte_present(pte))
+ return NULL;
+
+ page = vm_normal_page(vma, addr, pte);
+ if (!page)
+ return NULL;
+
+ if (PageReserved(page))
+ return NULL;
+
+ nid = page_to_nid(page);
+ if (!node_isset(nid, node_states[N_HIGH_MEMORY]))
+ return NULL;
+
+ return page;
}
static int gather_pte_stats(pmd_t *pmd, unsigned long addr,
@@ -912,26 +936,32 @@
pte_t *pte;
md = walk->private;
+ spin_lock(&walk->mm->page_table_lock);
+ if (pmd_trans_huge(*pmd)) {
+ if (pmd_trans_splitting(*pmd)) {
+ spin_unlock(&walk->mm->page_table_lock);
+ wait_split_huge_page(md->vma->anon_vma, pmd);
+ } else {
+ pte_t huge_pte = *(pte_t *)pmd;
+ struct page *page;
+
+ page = can_gather_numa_stats(huge_pte, md->vma, addr);
+ if (page)
+ gather_stats(page, md, pte_dirty(huge_pte),
+ HPAGE_PMD_SIZE/PAGE_SIZE);
+ spin_unlock(&walk->mm->page_table_lock);
+ return 0;
+ }
+ } else {
+ spin_unlock(&walk->mm->page_table_lock);
+ }
+
orig_pte = pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl);
do {
- struct page *page;
- int nid;
-
- if (!pte_present(*pte))
- continue;
-
- page = vm_normal_page(md->vma, addr, *pte);
+ struct page *page = can_gather_numa_stats(*pte, md->vma, addr);
if (!page)
continue;
-
- if (PageReserved(page))
- continue;
-
- nid = page_to_nid(page);
- if (!node_isset(nid, node_states[N_HIGH_MEMORY]))
- continue;
-
- gather_stats(page, md, pte_dirty(*pte));
+ gather_stats(page, md, pte_dirty(*pte), 1);
} while (pte++, addr += PAGE_SIZE, addr != end);
pte_unmap_unlock(orig_pte, ptl);
@@ -952,7 +982,7 @@
return 0;
md = walk->private;
- gather_stats(page, md, pte_dirty(*pte));
+ gather_stats(page, md, pte_dirty(*pte), 1);
return 0;
}
diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h
index 8633521..8731516 100644
--- a/fs/xfs/linux-2.6/xfs_linux.h
+++ b/fs/xfs/linux-2.6/xfs_linux.h
@@ -70,6 +70,8 @@
#include <linux/ctype.h>
#include <linux/writeback.h>
#include <linux/capability.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
#include <linux/list_sort.h>
#include <asm/page.h>
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index a1a881e..347cae9 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -1412,37 +1412,35 @@
sb->s_time_gran = 1;
set_posix_acl_flag(sb);
- error = xfs_syncd_init(mp);
- if (error)
- goto out_filestream_unmount;
-
xfs_inode_shrinker_register(mp);
error = xfs_mountfs(mp);
if (error)
- goto out_syncd_stop;
+ goto out_filestream_unmount;
+
+ error = xfs_syncd_init(mp);
+ if (error)
+ goto out_unmount;
root = igrab(VFS_I(mp->m_rootip));
if (!root) {
error = ENOENT;
- goto fail_unmount;
+ goto out_syncd_stop;
}
if (is_bad_inode(root)) {
error = EINVAL;
- goto fail_vnrele;
+ goto out_syncd_stop;
}
sb->s_root = d_alloc_root(root);
if (!sb->s_root) {
error = ENOMEM;
- goto fail_vnrele;
+ goto out_iput;
}
return 0;
- out_syncd_stop:
- xfs_inode_shrinker_unregister(mp);
- xfs_syncd_stop(mp);
out_filestream_unmount:
+ xfs_inode_shrinker_unregister(mp);
xfs_filestream_unmount(mp);
out_free_sb:
xfs_freesb(mp);
@@ -1456,17 +1454,12 @@
out:
return -error;
- fail_vnrele:
- if (sb->s_root) {
- dput(sb->s_root);
- sb->s_root = NULL;
- } else {
- iput(root);
- }
-
- fail_unmount:
- xfs_inode_shrinker_unregister(mp);
+ out_iput:
+ iput(root);
+ out_syncd_stop:
xfs_syncd_stop(mp);
+ out_unmount:
+ xfs_inode_shrinker_unregister(mp);
/*
* Blow away any referenced inode in the filestreams cache.
@@ -1667,24 +1660,13 @@
*/
xfs_syncd_wq = alloc_workqueue("xfssyncd", WQ_CPU_INTENSIVE, 8);
if (!xfs_syncd_wq)
- goto out;
-
- xfs_ail_wq = alloc_workqueue("xfsail", WQ_CPU_INTENSIVE, 8);
- if (!xfs_ail_wq)
- goto out_destroy_syncd;
-
+ return -ENOMEM;
return 0;
-
-out_destroy_syncd:
- destroy_workqueue(xfs_syncd_wq);
-out:
- return -ENOMEM;
}
STATIC void
xfs_destroy_workqueues(void)
{
- destroy_workqueue(xfs_ail_wq);
destroy_workqueue(xfs_syncd_wq);
}
diff --git a/fs/xfs/quota/xfs_dquot_item.c b/fs/xfs/quota/xfs_dquot_item.c
index 9e0e2fa..8126fc2 100644
--- a/fs/xfs/quota/xfs_dquot_item.c
+++ b/fs/xfs/quota/xfs_dquot_item.c
@@ -183,13 +183,14 @@
* search the buffer cache can be a time consuming thing, and AIL lock is a
* spinlock.
*/
-STATIC void
+STATIC bool
xfs_qm_dquot_logitem_pushbuf(
struct xfs_log_item *lip)
{
struct xfs_dq_logitem *qlip = DQUOT_ITEM(lip);
struct xfs_dquot *dqp = qlip->qli_dquot;
struct xfs_buf *bp;
+ bool ret = true;
ASSERT(XFS_DQ_IS_LOCKED(dqp));
@@ -201,17 +202,20 @@
if (completion_done(&dqp->q_flush) ||
!(lip->li_flags & XFS_LI_IN_AIL)) {
xfs_dqunlock(dqp);
- return;
+ return true;
}
bp = xfs_incore(dqp->q_mount->m_ddev_targp, qlip->qli_format.qlf_blkno,
dqp->q_mount->m_quotainfo->qi_dqchunklen, XBF_TRYLOCK);
xfs_dqunlock(dqp);
if (!bp)
- return;
+ return true;
if (XFS_BUF_ISDELAYWRITE(bp))
xfs_buf_delwri_promote(bp);
+ if (XFS_BUF_ISPINNED(bp))
+ ret = false;
xfs_buf_relse(bp);
+ return ret;
}
/*
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
index 7b7e005..a7342e8 100644
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -632,7 +632,7 @@
* the xfsbufd to get this buffer written. We have to unlock the buffer
* to allow the xfsbufd to write it, too.
*/
-STATIC void
+STATIC bool
xfs_buf_item_pushbuf(
struct xfs_log_item *lip)
{
@@ -646,6 +646,7 @@
xfs_buf_delwri_promote(bp);
xfs_buf_relse(bp);
+ return true;
}
STATIC void
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index b1e88d5..391044c 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -713,13 +713,14 @@
* marked delayed write. If that's the case, we'll promote it and that will
* allow the caller to write the buffer by triggering the xfsbufd to run.
*/
-STATIC void
+STATIC bool
xfs_inode_item_pushbuf(
struct xfs_log_item *lip)
{
struct xfs_inode_log_item *iip = INODE_ITEM(lip);
struct xfs_inode *ip = iip->ili_inode;
struct xfs_buf *bp;
+ bool ret = true;
ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED));
@@ -730,7 +731,7 @@
if (completion_done(&ip->i_flush) ||
!(lip->li_flags & XFS_LI_IN_AIL)) {
xfs_iunlock(ip, XFS_ILOCK_SHARED);
- return;
+ return true;
}
bp = xfs_incore(ip->i_mount->m_ddev_targp, iip->ili_format.ilf_blkno,
@@ -738,10 +739,13 @@
xfs_iunlock(ip, XFS_ILOCK_SHARED);
if (!bp)
- return;
+ return true;
if (XFS_BUF_ISDELAYWRITE(bp))
xfs_buf_delwri_promote(bp);
+ if (XFS_BUF_ISPINNED(bp))
+ ret = false;
xfs_buf_relse(bp);
+ return ret;
}
/*
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index c83f63b..efc147f 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -1426,6 +1426,7 @@
static inline void
xfs_log_item_batch_insert(
struct xfs_ail *ailp,
+ struct xfs_ail_cursor *cur,
struct xfs_log_item **log_items,
int nr_items,
xfs_lsn_t commit_lsn)
@@ -1434,7 +1435,7 @@
spin_lock(&ailp->xa_lock);
/* xfs_trans_ail_update_bulk drops ailp->xa_lock */
- xfs_trans_ail_update_bulk(ailp, log_items, nr_items, commit_lsn);
+ xfs_trans_ail_update_bulk(ailp, cur, log_items, nr_items, commit_lsn);
for (i = 0; i < nr_items; i++)
IOP_UNPIN(log_items[i], 0);
@@ -1452,6 +1453,13 @@
* as an iclog write error even though we haven't started any IO yet. Hence in
* this case all we need to do is IOP_COMMITTED processing, followed by an
* IOP_UNPIN(aborted) call.
+ *
+ * The AIL cursor is used to optimise the insert process. If commit_lsn is not
+ * at the end of the AIL, the insert cursor avoids the need to walk
+ * the AIL to find the insertion point on every xfs_log_item_batch_insert()
+ * call. This saves a lot of needless list walking and is a net win, even
+ * though it slightly increases that amount of AIL lock traffic to set it up
+ * and tear it down.
*/
void
xfs_trans_committed_bulk(
@@ -1463,8 +1471,13 @@
#define LOG_ITEM_BATCH_SIZE 32
struct xfs_log_item *log_items[LOG_ITEM_BATCH_SIZE];
struct xfs_log_vec *lv;
+ struct xfs_ail_cursor cur;
int i = 0;
+ spin_lock(&ailp->xa_lock);
+ xfs_trans_ail_cursor_last(ailp, &cur, commit_lsn);
+ spin_unlock(&ailp->xa_lock);
+
/* unpin all the log items */
for (lv = log_vector; lv; lv = lv->lv_next ) {
struct xfs_log_item *lip = lv->lv_item;
@@ -1493,7 +1506,9 @@
/*
* Not a bulk update option due to unusual item_lsn.
* Push into AIL immediately, rechecking the lsn once
- * we have the ail lock. Then unpin the item.
+ * we have the ail lock. Then unpin the item. This does
+ * not affect the AIL cursor the bulk insert path is
+ * using.
*/
spin_lock(&ailp->xa_lock);
if (XFS_LSN_CMP(item_lsn, lip->li_lsn) > 0)
@@ -1507,7 +1522,7 @@
/* Item is a candidate for bulk AIL insert. */
log_items[i++] = lv->lv_item;
if (i >= LOG_ITEM_BATCH_SIZE) {
- xfs_log_item_batch_insert(ailp, log_items,
+ xfs_log_item_batch_insert(ailp, &cur, log_items,
LOG_ITEM_BATCH_SIZE, commit_lsn);
i = 0;
}
@@ -1515,7 +1530,11 @@
/* make sure we insert the remainder! */
if (i)
- xfs_log_item_batch_insert(ailp, log_items, i, commit_lsn);
+ xfs_log_item_batch_insert(ailp, &cur, log_items, i, commit_lsn);
+
+ spin_lock(&ailp->xa_lock);
+ xfs_trans_ail_cursor_done(ailp, &cur);
+ spin_unlock(&ailp->xa_lock);
}
/*
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index 06a9759..53597f4 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -350,7 +350,7 @@
void (*iop_unlock)(xfs_log_item_t *);
xfs_lsn_t (*iop_committed)(xfs_log_item_t *, xfs_lsn_t);
void (*iop_push)(xfs_log_item_t *);
- void (*iop_pushbuf)(xfs_log_item_t *);
+ bool (*iop_pushbuf)(xfs_log_item_t *);
void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t);
} xfs_item_ops_t;
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
index 5fc2380..a4c281b 100644
--- a/fs/xfs/xfs_trans_ail.c
+++ b/fs/xfs/xfs_trans_ail.c
@@ -28,8 +28,6 @@
#include "xfs_trans_priv.h"
#include "xfs_error.h"
-struct workqueue_struct *xfs_ail_wq; /* AIL workqueue */
-
#ifdef DEBUG
/*
* Check that the list is sorted as it should be.
@@ -272,9 +270,9 @@
}
/*
- * Return the item in the AIL with the current lsn.
- * Return the current tree generation number for use
- * in calls to xfs_trans_next_ail().
+ * Initialise the cursor to the first item in the AIL with the given @lsn.
+ * This searches the list from lowest LSN to highest. Pass a @lsn of zero
+ * to initialise the cursor to the first item in the AIL.
*/
xfs_log_item_t *
xfs_trans_ail_cursor_first(
@@ -300,31 +298,97 @@
}
/*
- * splice the log item list into the AIL at the given LSN.
+ * Initialise the cursor to the last item in the AIL with the given @lsn.
+ * This searches the list from highest LSN to lowest. If there is no item with
+ * the value of @lsn, then it sets the cursor to the last item with an LSN lower
+ * than @lsn.
+ */
+static struct xfs_log_item *
+__xfs_trans_ail_cursor_last(
+ struct xfs_ail *ailp,
+ xfs_lsn_t lsn)
+{
+ xfs_log_item_t *lip;
+
+ list_for_each_entry_reverse(lip, &ailp->xa_ail, li_ail) {
+ if (XFS_LSN_CMP(lip->li_lsn, lsn) <= 0)
+ return lip;
+ }
+ return NULL;
+}
+
+/*
+ * Initialise the cursor to the last item in the AIL with the given @lsn.
+ * This searches the list from highest LSN to lowest.
+ */
+struct xfs_log_item *
+xfs_trans_ail_cursor_last(
+ struct xfs_ail *ailp,
+ struct xfs_ail_cursor *cur,
+ xfs_lsn_t lsn)
+{
+ xfs_trans_ail_cursor_init(ailp, cur);
+ cur->item = __xfs_trans_ail_cursor_last(ailp, lsn);
+ return cur->item;
+}
+
+/*
+ * splice the log item list into the AIL at the given LSN. We splice to the
+ * tail of the given LSN to maintain insert order for push traversals. The
+ * cursor is optional, allowing repeated updates to the same LSN to avoid
+ * repeated traversals.
*/
static void
xfs_ail_splice(
- struct xfs_ail *ailp,
- struct list_head *list,
- xfs_lsn_t lsn)
+ struct xfs_ail *ailp,
+ struct xfs_ail_cursor *cur,
+ struct list_head *list,
+ xfs_lsn_t lsn)
{
- xfs_log_item_t *next_lip;
+ struct xfs_log_item *lip = cur ? cur->item : NULL;
+ struct xfs_log_item *next_lip;
- /* If the list is empty, just insert the item. */
- if (list_empty(&ailp->xa_ail)) {
- list_splice(list, &ailp->xa_ail);
- return;
+ /*
+ * Get a new cursor if we don't have a placeholder or the existing one
+ * has been invalidated.
+ */
+ if (!lip || (__psint_t)lip & 1) {
+ lip = __xfs_trans_ail_cursor_last(ailp, lsn);
+
+ if (!lip) {
+ /* The list is empty, so just splice and return. */
+ if (cur)
+ cur->item = NULL;
+ list_splice(list, &ailp->xa_ail);
+ return;
+ }
}
- list_for_each_entry_reverse(next_lip, &ailp->xa_ail, li_ail) {
- if (XFS_LSN_CMP(next_lip->li_lsn, lsn) <= 0)
- break;
+ /*
+ * Our cursor points to the item we want to insert _after_, so we have
+ * to update the cursor to point to the end of the list we are splicing
+ * in so that it points to the correct location for the next splice.
+ * i.e. before the splice
+ *
+ * lsn -> lsn -> lsn + x -> lsn + x ...
+ * ^
+ * | cursor points here
+ *
+ * After the splice we have:
+ *
+ * lsn -> lsn -> lsn -> lsn -> .... -> lsn -> lsn + x -> lsn + x ...
+ * ^ ^
+ * | cursor points here | needs to move here
+ *
+ * So we set the cursor to the last item in the list to be spliced
+ * before we execute the splice, resulting in the cursor pointing to
+ * the correct item after the splice occurs.
+ */
+ if (cur) {
+ next_lip = list_entry(list->prev, struct xfs_log_item, li_ail);
+ cur->item = next_lip;
}
-
- ASSERT(&next_lip->li_ail == &ailp->xa_ail ||
- XFS_LSN_CMP(next_lip->li_lsn, lsn) <= 0);
-
- list_splice_init(list, &next_lip->li_ail);
+ list_splice(list, &lip->li_ail);
}
/*
@@ -340,16 +404,10 @@
xfs_trans_ail_cursor_clear(ailp, lip);
}
-/*
- * xfs_ail_worker does the work of pushing on the AIL. It will requeue itself
- * to run at a later time if there is more work to do to complete the push.
- */
-STATIC void
-xfs_ail_worker(
- struct work_struct *work)
+static long
+xfsaild_push(
+ struct xfs_ail *ailp)
{
- struct xfs_ail *ailp = container_of(to_delayed_work(work),
- struct xfs_ail, xa_work);
xfs_mount_t *mp = ailp->xa_mount;
struct xfs_ail_cursor *cur = &ailp->xa_cursors;
xfs_log_item_t *lip;
@@ -412,8 +470,13 @@
case XFS_ITEM_PUSHBUF:
XFS_STATS_INC(xs_push_ail_pushbuf);
- IOP_PUSHBUF(lip);
- ailp->xa_last_pushed_lsn = lsn;
+
+ if (!IOP_PUSHBUF(lip)) {
+ stuck++;
+ flush_log = 1;
+ } else {
+ ailp->xa_last_pushed_lsn = lsn;
+ }
push_xfsbufd = 1;
break;
@@ -425,7 +488,6 @@
case XFS_ITEM_LOCKED:
XFS_STATS_INC(xs_push_ail_locked);
- ailp->xa_last_pushed_lsn = lsn;
stuck++;
break;
@@ -486,20 +548,6 @@
/* We're past our target or empty, so idle */
ailp->xa_last_pushed_lsn = 0;
- /*
- * We clear the XFS_AIL_PUSHING_BIT first before checking
- * whether the target has changed. If the target has changed,
- * this pushes the requeue race directly onto the result of the
- * atomic test/set bit, so we are guaranteed that either the
- * the pusher that changed the target or ourselves will requeue
- * the work (but not both).
- */
- clear_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags);
- smp_rmb();
- if (XFS_LSN_CMP(ailp->xa_target, target) == 0 ||
- test_and_set_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags))
- return;
-
tout = 50;
} else if (XFS_LSN_CMP(lsn, target) >= 0) {
/*
@@ -522,9 +570,30 @@
tout = 20;
}
- /* There is more to do, requeue us. */
- queue_delayed_work(xfs_syncd_wq, &ailp->xa_work,
- msecs_to_jiffies(tout));
+ return tout;
+}
+
+static int
+xfsaild(
+ void *data)
+{
+ struct xfs_ail *ailp = data;
+ long tout = 0; /* milliseconds */
+
+ while (!kthread_should_stop()) {
+ if (tout && tout <= 20)
+ __set_current_state(TASK_KILLABLE);
+ else
+ __set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(tout ?
+ msecs_to_jiffies(tout) : MAX_SCHEDULE_TIMEOUT);
+
+ try_to_freeze();
+
+ tout = xfsaild_push(ailp);
+ }
+
+ return 0;
}
/*
@@ -559,8 +628,9 @@
*/
smp_wmb();
xfs_trans_ail_copy_lsn(ailp, &ailp->xa_target, &threshold_lsn);
- if (!test_and_set_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags))
- queue_delayed_work(xfs_syncd_wq, &ailp->xa_work, 0);
+ smp_wmb();
+
+ wake_up_process(ailp->xa_task);
}
/*
@@ -645,6 +715,7 @@
void
xfs_trans_ail_update_bulk(
struct xfs_ail *ailp,
+ struct xfs_ail_cursor *cur,
struct xfs_log_item **log_items,
int nr_items,
xfs_lsn_t lsn) __releases(ailp->xa_lock)
@@ -674,7 +745,7 @@
list_add(&lip->li_ail, &tmp);
}
- xfs_ail_splice(ailp, &tmp, lsn);
+ xfs_ail_splice(ailp, cur, &tmp, lsn);
if (!mlip_changed) {
spin_unlock(&ailp->xa_lock);
@@ -794,9 +865,18 @@
ailp->xa_mount = mp;
INIT_LIST_HEAD(&ailp->xa_ail);
spin_lock_init(&ailp->xa_lock);
- INIT_DELAYED_WORK(&ailp->xa_work, xfs_ail_worker);
+
+ ailp->xa_task = kthread_run(xfsaild, ailp, "xfsaild/%s",
+ ailp->xa_mount->m_fsname);
+ if (IS_ERR(ailp->xa_task))
+ goto out_free_ailp;
+
mp->m_ail = ailp;
return 0;
+
+out_free_ailp:
+ kmem_free(ailp);
+ return ENOMEM;
}
void
@@ -805,6 +885,6 @@
{
struct xfs_ail *ailp = mp->m_ail;
- cancel_delayed_work_sync(&ailp->xa_work);
+ kthread_stop(ailp->xa_task);
kmem_free(ailp);
}
diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h
index 6b164e9..fe2e3cb 100644
--- a/fs/xfs/xfs_trans_priv.h
+++ b/fs/xfs/xfs_trans_priv.h
@@ -64,24 +64,19 @@
*/
struct xfs_ail {
struct xfs_mount *xa_mount;
+ struct task_struct *xa_task;
struct list_head xa_ail;
xfs_lsn_t xa_target;
struct xfs_ail_cursor xa_cursors;
spinlock_t xa_lock;
- struct delayed_work xa_work;
xfs_lsn_t xa_last_pushed_lsn;
- unsigned long xa_flags;
};
-#define XFS_AIL_PUSHING_BIT 0
-
/*
* From xfs_trans_ail.c
*/
-
-extern struct workqueue_struct *xfs_ail_wq; /* AIL workqueue */
-
void xfs_trans_ail_update_bulk(struct xfs_ail *ailp,
+ struct xfs_ail_cursor *cur,
struct xfs_log_item **log_items, int nr_items,
xfs_lsn_t lsn) __releases(ailp->xa_lock);
static inline void
@@ -90,7 +85,7 @@
struct xfs_log_item *lip,
xfs_lsn_t lsn) __releases(ailp->xa_lock)
{
- xfs_trans_ail_update_bulk(ailp, &lip, 1, lsn);
+ xfs_trans_ail_update_bulk(ailp, NULL, &lip, 1, lsn);
}
void xfs_trans_ail_delete_bulk(struct xfs_ail *ailp,
@@ -111,10 +106,13 @@
void xfs_trans_unlocked_item(struct xfs_ail *,
xfs_log_item_t *);
-struct xfs_log_item *xfs_trans_ail_cursor_first(struct xfs_ail *ailp,
+struct xfs_log_item * xfs_trans_ail_cursor_first(struct xfs_ail *ailp,
struct xfs_ail_cursor *cur,
xfs_lsn_t lsn);
-struct xfs_log_item *xfs_trans_ail_cursor_next(struct xfs_ail *ailp,
+struct xfs_log_item * xfs_trans_ail_cursor_last(struct xfs_ail *ailp,
+ struct xfs_ail_cursor *cur,
+ xfs_lsn_t lsn);
+struct xfs_log_item * xfs_trans_ail_cursor_next(struct xfs_ail *ailp,
struct xfs_ail_cursor *cur);
void xfs_trans_ail_cursor_done(struct xfs_ail *ailp,
struct xfs_ail_cursor *cur);
diff --git a/fs/yaffs2/yaffs_vfs.c b/fs/yaffs2/yaffs_vfs.c
index a4db5cc..f56e12c 100644
--- a/fs/yaffs2/yaffs_vfs.c
+++ b/fs/yaffs2/yaffs_vfs.c
@@ -65,7 +65,7 @@
#define YPROC_ROOT NULL
-#define Y_INIT_TIMER(a) init_timer_on_stack(a)
+#define Y_INIT_TIMER(a, b, c) setup_deferrable_timer_on_stack(a, b, c)
#define WRITE_SIZE_STR "writesize"
#define WRITE_SIZE(mtd) ((mtd)->writesize)
@@ -1674,10 +1674,9 @@
if (time_before(expires, now))
expires = now + HZ;
- Y_INIT_TIMER(&timer);
+ Y_INIT_TIMER(&timer, yaffs_background_waker,
+ (unsigned long)current);
timer.expires = expires + 1;
- timer.data = (unsigned long)current;
- timer.function = yaffs_background_waker;
set_current_state(TASK_INTERRUPTIBLE);
add_timer(&timer);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 33d12f8..0ec3687 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -802,6 +802,7 @@
extern int drm_add_modes_noedid(struct drm_connector *connector,
int hdisplay, int vdisplay);
+extern int drm_edid_header_is_valid(const u8 *raw_edid);
extern bool drm_edid_is_valid(struct edid *edid);
struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
int hsize, int vsize, int fresh);
diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h
index c4d6dbf..28c0d11 100644
--- a/include/drm/i915_drm.h
+++ b/include/drm/i915_drm.h
@@ -237,7 +237,7 @@
#define DRM_IOCTL_I915_GEM_GET_APERTURE DRM_IOR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_APERTURE, struct drm_i915_gem_get_aperture)
#define DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GET_PIPE_FROM_CRTC_ID, struct drm_i915_get_pipe_from_crtc_id)
#define DRM_IOCTL_I915_GEM_MADVISE DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MADVISE, struct drm_i915_gem_madvise)
-#define DRM_IOCTL_I915_OVERLAY_PUT_IMAGE DRM_IOW(DRM_COMMAND_BASE + DRM_IOCTL_I915_OVERLAY_ATTRS, struct drm_intel_overlay_put_image)
+#define DRM_IOCTL_I915_OVERLAY_PUT_IMAGE DRM_IOW(DRM_COMMAND_BASE + DRM_I915_OVERLAY_PUT_IMAGE, struct drm_intel_overlay_put_image)
#define DRM_IOCTL_I915_OVERLAY_ATTRS DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_OVERLAY_ATTRS, struct drm_intel_overlay_attrs)
/* Allow drivers to submit batchbuffers directly to hardware, relying
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index e3fbecb..4900e9c 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -420,8 +420,14 @@
header-y += msm_audio_wma.h
header-y += msm_audio_wmapro.h
header-y += msm_audio_mvs.h
+header-y += msm_audio_qcp.h
+header-y += msm_audio_amrnb.h
+header-y += msm_audio_voicememo.h
+header-y += msm_audio_sbc.h
header-y += msm_ipc.h
header-y += msm_charm.h
header-y += tzcom.h
header-y += qcedev.h
header-y += idle_stats_device.h
+header-y += genlock.h
+header-y += msm_audio_amrwb.h
diff --git a/include/linux/atmel_maxtouch.h b/include/linux/atmel_maxtouch.h
index c582529..012e68b 100644
--- a/include/linux/atmel_maxtouch.h
+++ b/include/linux/atmel_maxtouch.h
@@ -283,7 +283,7 @@
#endif
/**
- * struct mxt_platform_data - includes platform specific informatio
+ * struct maxtouch_platform_data - includes platform specific informatio
* related to Atmel maXTouch touchscreen controller.
*
* @numtouch: Number of simultaneous touches supported
@@ -298,7 +298,7 @@
* @max_y: Reported Y range
*/
-struct mxt_platform_data {
+struct maxtouch_platform_data {
u8 numtouch; /* Number of touches to report */
int (*init_platform_hw)(struct i2c_client *client);
int (*exit_platform_hw)(struct i2c_client *client);
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1d37f42..7213b52 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -11,6 +11,8 @@
#ifndef __LINUX_CLK_H
#define __LINUX_CLK_H
+#include <linux/kernel.h>
+
struct device;
/*
@@ -41,11 +43,31 @@
struct clk *clk_get(struct device *dev, const char *id);
/**
+ * clk_prepare - prepare a clock source
+ * @clk: clock source
+ *
+ * This prepares the clock source for use.
+ *
+ * Must not be called from within atomic context.
+ */
+#ifdef CONFIG_HAVE_CLK_PREPARE
+int clk_prepare(struct clk *clk);
+#else
+static inline int clk_prepare(struct clk *clk)
+{
+ might_sleep();
+ return 0;
+}
+#endif
+
+/**
* clk_enable - inform the system when the clock source should be running.
* @clk: clock source
*
* If the clock can not be enabled/disabled, this should return success.
*
+ * May be called from atomic contexts.
+ *
* Returns success (0) or negative errno.
*/
int clk_enable(struct clk *clk);
@@ -57,6 +79,8 @@
* Inform the system that a clock source is no longer required by
* a driver and may be shut down.
*
+ * May be called from atomic contexts.
+ *
* Implementation detail: if the clock source is shared between
* multiple drivers, clk_enable() calls must be balanced by the
* same number of clk_disable() calls for the clock source to be
@@ -64,6 +88,25 @@
*/
void clk_disable(struct clk *clk);
+
+/**
+ * clk_unprepare - undo preparation of a clock source
+ * @clk: clock source
+ *
+ * This undoes a previously prepared clock. The caller must balance
+ * the number of prepare and unprepare calls.
+ *
+ * Must not be called from within atomic context.
+ */
+#ifdef CONFIG_HAVE_CLK_PREPARE
+void clk_unprepare(struct clk *clk);
+#else
+static inline void clk_unprepare(struct clk *clk)
+{
+ might_sleep();
+}
+#endif
+
/**
* clk_get_rate - obtain the current clock rate (in Hz) for a clock source.
* This is only valid once the clock source has been enabled.
diff --git a/include/linux/cpu_pm.h b/include/linux/cpu_pm.h
new file mode 100644
index 0000000..d399bf8
--- /dev/null
+++ b/include/linux/cpu_pm.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Author:
+ * Colin Cross <ccross <at> android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_CPU_PM_H
+#define _LINUX_CPU_PM_H
+
+#include <linux/kernel.h>
+#include <linux/notifier.h>
+
+/*
+ * When a CPU goes to a low power state that turns off power to the CPU's
+ * power domain, the contents of some blocks (floating point coprocessors,
+ * interrutp controllers, caches, timers) in the same power domain can
+ * be lost. The cpm_pm notifiers provide a method for platform idle, suspend,
+ * and hotplug implementations to notify the drivers for these blocks that
+ * they may be reset.
+ *
+ * All cpu_pm notifications must be called with interrupts disabled.
+ *
+ * The notifications are split into two classes, CPU notifications and CPU
+ * cluster notifications.
+ *
+ * CPU notifications apply to a single CPU, and must be called on the affected
+ * CPU. They are used to save per-cpu context for affected blocks.
+ *
+ * CPU cluster notifications apply to all CPUs in a single power domain. They
+ * are used to save any global context for affected blocks, and must be called
+ * after all the CPUs in the power domain have been notified of the low power
+ * state.
+ *
+ */
+
+/*
+ * Event codes passed as unsigned long val to notifier calls
+ */
+enum cpu_pm_event {
+ /* A single cpu is entering a low power state */
+ CPU_PM_ENTER,
+
+ /* A single cpu failed to enter a low power state */
+ CPU_PM_ENTER_FAILED,
+
+ /* A single cpu is exiting a low power state */
+ CPU_PM_EXIT,
+
+ /* A cpu power domain is entering a low power state */
+ CPU_CLUSTER_PM_ENTER,
+
+ /* A cpu power domain failed to enter a low power state */
+ CPU_CLUSTER_PM_ENTER_FAILED,
+
+ /* A cpu power domain is exiting a low power state */
+ CPU_CLUSTER_PM_EXIT,
+};
+
+#ifdef CONFIG_CPU_PM
+int cpu_pm_register_notifier(struct notifier_block *nb);
+#else
+static inline int cpu_pm_register_notifier(struct notifier_block *nb)
+{ return 0; }
+#endif
+
+int cpu_pm_unregister_notifier(struct notifier_block *nb);
+
+/*
+ * cpm_pm_enter
+ *
+ * Notifies listeners that a single cpu is entering a low power state that may
+ * cause some blocks in the same power domain as the cpu to reset.
+ *
+ * Must be called on the affected cpu with interrupts disabled. Platform is
+ * responsible for ensuring that cpu_pm_enter is not called twice on the same
+ * cpu before cpu_pm_exit is called.
+ */
+int cpu_pm_enter(void);
+
+/*
+ * cpm_pm_exit
+ *
+ * Notifies listeners that a single cpu is exiting a low power state that may
+ * have caused some blocks in the same power domain as the cpu to reset.
+ *
+ * Must be called on the affected cpu with interrupts disabled.
+ */
+int cpu_pm_exit(void);
+
+/*
+ * cpm_cluster_pm_enter
+ *
+ * Notifies listeners that all cpus in a power domain are entering a low power
+ * state that may cause some blocks in the same power domain to reset.
+ *
+ * Must be called after cpu_pm_enter has been called on all cpus in the power
+ * domain, and before cpu_pm_exit has been called on any cpu in the power
+ * domain.
+ *
+ * Must be called with interrupts disabled.
+ */
+int cpu_cluster_pm_enter(void);
+
+/*
+ * cpm_pm_enter
+ *
+ * Notifies listeners that a single cpu is entering a low power state that may
+ * cause some blocks in the same power domain as the cpu to reset.
+ *
+ * Must be called after cpu_pm_enter has been called on all cpus in the power
+ * domain, and before cpu_pm_exit has been called on any cpu in the power
+ * domain.
+ *
+ * Must be called with interrupts disabled.
+ */
+int cpu_cluster_pm_exit(void);
+
+#endif
diff --git a/include/linux/cryptohash.h b/include/linux/cryptohash.h
index ec78a4b..d2984fb 100644
--- a/include/linux/cryptohash.h
+++ b/include/linux/cryptohash.h
@@ -8,6 +8,11 @@
void sha_init(__u32 *buf);
void sha_transform(__u32 *digest, const char *data, __u32 *W);
+#define MD5_DIGEST_WORDS 4
+#define MD5_MESSAGE_BYTES 64
+
+void md5_transform(__u32 *hash, __u32 const *in);
+
__u32 half_md4_transform(__u32 buf[4], __u32 const in[8]);
#endif
diff --git a/include/linux/earlysuspend.h b/include/linux/earlysuspend.h
old mode 100755
new mode 100644
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 9d88e1c..f0c0e8a 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -19,6 +19,8 @@
#include <asm/ftrace.h>
+struct ftrace_hash;
+
#ifdef CONFIG_FUNCTION_TRACER
extern int ftrace_enabled;
@@ -29,8 +31,6 @@
typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip);
-struct ftrace_hash;
-
enum {
FTRACE_OPS_FL_ENABLED = 1 << 0,
FTRACE_OPS_FL_GLOBAL = 1 << 1,
@@ -123,7 +123,8 @@
struct ftrace_func_command {
struct list_head list;
char *name;
- int (*func)(char *func, char *cmd,
+ int (*func)(struct ftrace_hash *hash,
+ char *func, char *cmd,
char *params, int enable);
};
diff --git a/include/linux/genlock.h b/include/linux/genlock.h
new file mode 100644
index 0000000..2e9f9d6
--- /dev/null
+++ b/include/linux/genlock.h
@@ -0,0 +1,45 @@
+#ifndef _GENLOCK_H_
+#define _GENLOCK_H_
+
+#ifdef __KERNEL__
+
+struct genlock;
+struct genlock_handle;
+
+struct genlock_handle *genlock_get_handle(void);
+struct genlock_handle *genlock_get_handle_fd(int fd);
+void genlock_put_handle(struct genlock_handle *handle);
+struct genlock *genlock_create_lock(struct genlock_handle *);
+struct genlock *genlock_attach_lock(struct genlock_handle *, int fd);
+int genlock_wait(struct genlock_handle *handle, u32 timeout);
+void genlock_release_lock(struct genlock_handle *);
+int genlock_lock(struct genlock_handle *handle, int op, int flags,
+ u32 timeout);
+#endif
+
+#define GENLOCK_UNLOCK 0
+#define GENLOCK_WRLOCK 1
+#define GENLOCK_RDLOCK 2
+
+#define GENLOCK_NOBLOCK (1 << 0)
+
+struct genlock_lock {
+ int fd;
+ int op;
+ int flags;
+ int timeout;
+};
+
+#define GENLOCK_IOC_MAGIC 'G'
+
+#define GENLOCK_IOC_NEW _IO(GENLOCK_IOC_MAGIC, 0)
+#define GENLOCK_IOC_EXPORT _IOR(GENLOCK_IOC_MAGIC, 1, \
+ struct genlock_lock)
+#define GENLOCK_IOC_ATTACH _IOW(GENLOCK_IOC_MAGIC, 2, \
+ struct genlock_lock)
+#define GENLOCK_IOC_LOCK _IOW(GENLOCK_IOC_MAGIC, 3, \
+ struct genlock_lock)
+#define GENLOCK_IOC_RELEASE _IO(GENLOCK_IOC_MAGIC, 4)
+#define GENLOCK_IOC_WAIT _IOW(GENLOCK_IOC_MAGIC, 5, \
+ struct genlock_lock)
+#endif
diff --git a/include/linux/gpio_event.h b/include/linux/gpio_event.h
index 8c3f090..ccff7fc 100644
--- a/include/linux/gpio_event.h
+++ b/include/linux/gpio_event.h
@@ -98,6 +98,7 @@
/* GPIOEDF_USE_IRQ = (1U << 2) | GPIOIDF_USE_DOWN_IRQ, */
GPIOEDF_PRINT_KEYS = 1U << 8,
GPIOEDF_PRINT_KEY_DEBOUNCE = 1U << 9,
+ GPIOEDF_PRINT_KEY_UNSTABLE = 1U << 10,
};
struct gpio_event_direct_entry {
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 42f7e2f..4bfb4ca 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -597,6 +597,8 @@
* @input_mapping: invoked on input registering before mapping an usage
* @input_mapped: invoked on input registering after mapping an usage
* @feature_mapping: invoked on feature registering
+ * @input_register: called just before input device is registered after reports
+ * are parsed.
* @suspend: invoked on suspend (NULL means nop)
* @resume: invoked on resume if device was not reset (NULL means nop)
* @reset_resume: invoked on resume if device was reset (NULL means nop)
@@ -643,6 +645,8 @@
void (*feature_mapping)(struct hid_device *hdev,
struct hid_field *field,
struct hid_usage *usage);
+ int (*input_register)(struct hid_device *hdev, struct hid_input
+ *hidinput);
#ifdef CONFIG_PM
int (*suspend)(struct hid_device *hdev, pm_message_t message);
int (*resume)(struct hid_device *hdev);
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index bf56b6f..1c4085e 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1305,6 +1305,7 @@
WLAN_KEY_LEN_CCMP = 16,
WLAN_KEY_LEN_TKIP = 32,
WLAN_KEY_LEN_AES_CMAC = 16,
+ WLAN_KEY_LEN_WAPI_SMS4 = 32,
};
/**
@@ -1434,6 +1435,7 @@
#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04
#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05
#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06
+#define WLAN_CIPHER_SUITE_SMS4 0x00147201
/* AKM suite selectors */
#define WLAN_AKM_SUITE_8021X 0x000FAC01
diff --git a/include/linux/if.h b/include/linux/if.h
index 3bc63e6..03489ca 100644
--- a/include/linux/if.h
+++ b/include/linux/if.h
@@ -76,6 +76,8 @@
#define IFF_BRIDGE_PORT 0x4000 /* device used as bridge port */
#define IFF_OVS_DATAPATH 0x8000 /* device used as Open vSwitch
* datapath port */
+#define IFF_TX_SKB_SHARING 0x10000 /* The interface supports sharing
+ * skbs on transmit */
#define IF_GET_IFACE 0x0001 /* for querying only */
#define IF_GET_PROTO 0x0002
diff --git a/include/linux/input/pmic8xxx-pwrkey.h b/include/linux/input/pmic8xxx-pwrkey.h
index 6d2974e..a32eafd 100644
--- a/include/linux/input/pmic8xxx-pwrkey.h
+++ b/include/linux/input/pmic8xxx-pwrkey.h
@@ -24,6 +24,13 @@
*/
struct pm8xxx_pwrkey_platform_data {
bool pull_up;
+ /* Time delay for pwr-key state change interrupt triggering in micro-
+ * second. The actual delay can only be one of these eight levels:
+ * 2 sec, 1 sec, 1/2 sec, 1/4 sec, 1/8 sec, 1/16 sec, 1/32 sec, and
+ * 1/64 sec. The valid range of kpd_trigger_delay_us is 1/64 second to
+ * 2 seconds. A value within the valid range will be rounded down to the
+ * closest level. Any value outside the valid range will be rejected.
+ */
u32 kpd_trigger_delay_us;
u32 wakeup;
};
diff --git a/include/linux/ion.h b/include/linux/ion.h
index 7de40d4..b396369 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -35,6 +35,7 @@
ION_HEAP_TYPE_SYSTEM,
ION_HEAP_TYPE_SYSTEM_CONTIG,
ION_HEAP_TYPE_CARVEOUT,
+ ION_HEAP_TYPE_IOMMU,
ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always
are at the end of this enum */
ION_NUM_HEAPS,
@@ -59,6 +60,7 @@
ION_HEAP_SMI_ID,
ION_HEAP_ADSP_ID,
ION_HEAP_AUDIO_ID,
+ ION_HEAP_IOMMU_ID,
};
#define ION_KMALLOC_HEAP_NAME "kmalloc"
@@ -66,6 +68,7 @@
#define ION_EBI1_HEAP_NAME "EBI1"
#define ION_ADSP_HEAP_NAME "adsp"
#define ION_SMI_HEAP_NAME "smi"
+#define ION_IOMMU_HEAP_NAME "iommu"
#define CACHED 1
#define UNCACHED 0
@@ -99,6 +102,11 @@
* @name: used for debug purposes
* @base: base address of heap in physical memory if applicable
* @size: size of the heap in bytes if applicable
+ * @request_region: function to be called when the number of allocations goes
+ * from 0 -> 1
+ * @release_region: function to be called when the number of allocations goes
+ * from 1 -> 0
+ * @setup_region: function to be called upon ion registration
*
* Provided by the board file.
*/
@@ -109,6 +117,9 @@
ion_phys_addr_t base;
size_t size;
enum ion_memory_types memory_type;
+ void (*request_region)(void *);
+ void (*release_region)(void *);
+ void *(*setup_region)(void);
};
/**
@@ -298,6 +309,65 @@
int ion_handle_get_flags(struct ion_client *client, struct ion_handle *handle,
unsigned long *flags);
+
+/**
+ * ion_map_iommu - map the given handle into an iommu
+ *
+ * @client - client who allocated the handle
+ * @handle - handle to map
+ * @domain_num - domain number to map to
+ * @partition_num - partition number to allocate iova from
+ * @align - alignment for the iova
+ * @iova_length - length of iova to map. If the iova length is
+ * greater than the handle length, the remaining
+ * address space will be mapped to a dummy buffer.
+ * @iova - pointer to store the iova address
+ * @buffer_size - pointer to store the size of the buffer
+ * @flags - flags for options to map
+ *
+ * Maps the handle into the iova space specified via domain number. Iova
+ * will be allocated from the partition specified via partition_num.
+ * Returns 0 on success, negative value on error.
+ */
+int ion_map_iommu(struct ion_client *client, struct ion_handle *handle,
+ int domain_num, int partition_num, unsigned long align,
+ unsigned long iova_length, unsigned long *iova,
+ unsigned long *buffer_size,
+ unsigned long flags);
+
+
+/**
+ * ion_handle_get_size - get the allocated size of a given handle
+ *
+ * @client - client who allocated the handle
+ * @handle - handle to get the size
+ * @size - pointer to store the size
+ *
+ * gives the allocated size of a handle. returns 0 on success, negative
+ * value on error
+ *
+ * NOTE: This is intended to be used only to get a size to pass to map_iommu.
+ * You should *NOT* rely on this for any other usage.
+ */
+
+int ion_handle_get_size(struct ion_client *client, struct ion_handle *handle,
+ unsigned long *size);
+
+/**
+ * ion_unmap_iommu - unmap the handle from an iommu
+ *
+ * @client - client who allocated the handle
+ * @handle - handle to unmap
+ * @domain_num - domain to unmap from
+ * @partition_num - partition to unmap from
+ *
+ * Decrement the reference count on the iommu mapping. If the count is
+ * 0, the mapping will be removed from the iommu.
+ */
+void ion_unmap_iommu(struct ion_client *client, struct ion_handle *handle,
+ int domain_num, int partition_num);
+
+
#else
static inline struct ion_client *ion_client_create(struct ion_device *dev,
unsigned int heap_mask, const char *name)
@@ -370,6 +440,24 @@
{
return -ENODEV;
}
+
+static inline int ion_map_iommu(struct ion_client *client,
+ struct ion_handle *handle, int domain_num,
+ int partition_num, unsigned long align,
+ unsigned long iova_length, unsigned long *iova,
+ unsigned long flags)
+{
+ return -ENODEV;
+}
+
+static inline void ion_unmap_iommu(struct ion_client *client,
+ struct ion_handle *handle, int domain_num,
+ int partition_num)
+{
+ return;
+}
+
+
#endif /* CONFIG_ION */
#endif /* __KERNEL__ */
@@ -438,6 +526,7 @@
/* struct ion_flush_data - data passed to ion for flushing caches
*
* @handle: handle with data to flush
+ * @fd: fd to flush
* @vaddr: userspace virtual address mapped with mmap
* @offset: offset into the handle to flush
* @length: length of handle to flush
@@ -448,6 +537,7 @@
*/
struct ion_flush_data {
struct ion_handle *handle;
+ int fd;
void *vaddr;
unsigned int offset;
unsigned int length;
diff --git a/include/linux/kernel_debugger.h b/include/linux/kernel_debugger.h
deleted file mode 100644
index b4dbfe9..0000000
--- a/include/linux/kernel_debugger.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * include/linux/kernel_debugger.h
- *
- * Copyright (C) 2008 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef _LINUX_KERNEL_DEBUGGER_H_
-#define _LINUX_KERNEL_DEBUGGER_H_
-
-struct kdbg_ctxt {
- int (*printf)(void *cookie, const char *fmt, ...);
- void *cookie;
-};
-
-/* kernel_debugger() is called from IRQ context and should
- * use the kdbg_ctxt.printf to write output (do NOT call
- * printk, do operations not safe from IRQ context, etc).
- *
- * kdbg_ctxt.printf will return -1 if there is not enough
- * buffer space or if you are being aborted. In this case
- * you must return as soon as possible.
- *
- * Return non-zero if more data is available -- if buffer
- * space ran and you had to stop, but could print more,
- * for example.
- *
- * Additional calls where cmd is "more" will be made if
- * the additional data is desired.
- */
-int kernel_debugger(struct kdbg_ctxt *ctxt, char *cmd);
-
-#endif
diff --git a/include/linux/mfd/pm8xxx/ccadc.h b/include/linux/mfd/pm8xxx/ccadc.h
new file mode 100644
index 0000000..6f6cb39
--- /dev/null
+++ b/include/linux/mfd/pm8xxx/ccadc.h
@@ -0,0 +1,100 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 __PMIC8XXX_CCADC_H__
+#define __PMIC8XXX_CCADC_H__
+
+#include <linux/mfd/pm8xxx/core.h>
+
+#define PM8XXX_CCADC_DEV_NAME "pm8xxx-ccadc"
+
+/**
+ * struct pm8xxx_ccadc_platform_data -
+ * @r_sense: sense resistor value in (mOhms)
+ */
+struct pm8xxx_ccadc_platform_data {
+ int r_sense;
+};
+
+#define CCADC_READING_RESOLUTION_N_V1 1085069
+#define CCADC_READING_RESOLUTION_D_V1 100000
+#define CCADC_READING_RESOLUTION_N_V2 542535
+#define CCADC_READING_RESOLUTION_D_V2 100000
+
+static s64 pm8xxx_ccadc_reading_to_microvolt_v1(s64 cc)
+{
+ return div_s64(cc * CCADC_READING_RESOLUTION_N_V1,
+ CCADC_READING_RESOLUTION_D_V1);
+}
+
+static s64 pm8xxx_ccadc_reading_to_microvolt_v2(s64 cc)
+{
+ return div_s64(cc * CCADC_READING_RESOLUTION_N_V2,
+ CCADC_READING_RESOLUTION_D_V2);
+}
+
+static inline s64 pm8xxx_ccadc_reading_to_microvolt(int revision, s64 cc)
+{
+ /*
+ * resolution (the value of a single bit) was changed after revision 2.0
+ * for more accurate readings
+ */
+ return (revision < PM8XXX_REVISION_8921_2p0) ?
+ pm8xxx_ccadc_reading_to_microvolt_v1((s64)cc) :
+ pm8xxx_ccadc_reading_to_microvolt_v2((s64)cc);
+}
+
+#if defined(CONFIG_PM8XXX_CCADC) || defined(CONFIG_PM8XXX_CCADC_MODULE)
+/**
+ * pm8xxx_cc_adjust_for_gain - the function to adjust the voltage read from
+ * ccadc for gain compensation
+ * @v: the voltage which needs to be gain compensated in microVolts
+ *
+ *
+ * RETURNS: gain compensated voltage
+ */
+s64 pm8xxx_cc_adjust_for_gain(s64 uv);
+
+/**
+ * pm8xxx_calib_ccadc - calibration for ccadc. This will calculate gain
+ * and offset and reprogram them in the appropriate
+ * registers
+ */
+void pm8xxx_calib_ccadc(void);
+
+/**
+ * pm8xxx_ccadc_get_battery_current - return the battery current based on vsense
+ * resitor in milliamperes
+ * @result: The pointer where the voltage will be updated. A -ve
+ * result means that the current is flowing in
+ * the battery - during battery charging
+ *
+ * RETURNS: Error code if there was a problem reading vsense, Zero otherwise
+ * The result won't be updated in case of an error.
+ *
+ */
+int pm8xxx_ccadc_get_battery_current(int *bat_current);
+#else
+static inline s64 pm8xxx_cc_adjust_for_gain(s64 uv)
+{
+ return -ENXIO;
+}
+static inline void pm8xxx_calib_ccadc(void)
+{
+}
+static inline int pm8xxx_ccadc_get_battery_current(int *bat_current)
+{
+ return -ENXIO;
+}
+#endif
+
+#endif /* __PMIC8XXX_CCADC_H__ */
diff --git a/include/linux/mfd/pm8xxx/core.h b/include/linux/mfd/pm8xxx/core.h
index a4c23b0..5ed615b 100644
--- a/include/linux/mfd/pm8xxx/core.h
+++ b/include/linux/mfd/pm8xxx/core.h
@@ -26,6 +26,8 @@
PM8XXX_VERSION_8921,
PM8XXX_VERSION_8821,
PM8XXX_VERSION_8018,
+ PM8XXX_VERSION_8922,
+ PM8XXX_VERSION_8038,
};
/* PMIC version specific silicon revisions */
@@ -44,6 +46,7 @@
#define PM8XXX_REVISION_8921_1p0 1
#define PM8XXX_REVISION_8921_1p1 2
#define PM8XXX_REVISION_8921_2p0 3
+#define PM8XXX_REVISION_8921_3p0 4
#define PM8XXX_REVISION_8821_TEST 0
#define PM8XXX_REVISION_8821_1p0 1
@@ -55,6 +58,16 @@
#define PM8XXX_REVISION_8018_1p1 2
#define PM8XXX_REVISION_8018_2p0 3
+#define PM8XXX_REVISION_8922_TEST 0
+#define PM8XXX_REVISION_8922_1p0 1
+#define PM8XXX_REVISION_8922_1p1 2
+#define PM8XXX_REVISION_8922_2p0 3
+
+#define PM8XXX_REVISION_8038_TEST 0
+#define PM8XXX_REVISION_8038_1p0 1
+#define PM8XXX_REVISION_8038_2p0 2
+#define PM8XXX_REVISION_8038_2p1 3
+
struct pm8xxx_drvdata {
int (*pmic_readb) (const struct device *dev,
u16 addr, u8 *val);
diff --git a/include/linux/mfd/pm8xxx/gpio.h b/include/linux/mfd/pm8xxx/gpio.h
index 0a9c95d..9918620 100644
--- a/include/linux/mfd/pm8xxx/gpio.h
+++ b/include/linux/mfd/pm8xxx/gpio.h
@@ -59,6 +59,25 @@
#define PM_GPIO_VIN_L3 5
#define PM_GPIO_VIN_L17 6
+/* vin_sel: Voltage Input select on PM8058 */
+#define PM8058_GPIO_VIN_VPH 0
+#define PM8058_GPIO_VIN_BB 1
+#define PM8058_GPIO_VIN_S3 2
+#define PM8058_GPIO_VIN_L3 3
+#define PM8058_GPIO_VIN_L7 4
+#define PM8058_GPIO_VIN_L6 5
+#define PM8058_GPIO_VIN_L5 6
+#define PM8058_GPIO_VIN_L2 7
+
+/* vin_sel: Voltage Input Select on PM8038*/
+#define PM8038_GPIO_VIN_VPH 0
+#define PM8038_GPIO_VIN_BB 1
+#define PM8038_GPIO_VIN_L11 2
+#define PM8038_GPIO_VIN_L15 3
+#define PM8038_GPIO_VIN_L4 4
+#define PM8038_GPIO_VIN_L3 5
+#define PM8038_GPIO_VIN_L17 6
+
/* out_strength */
#define PM_GPIO_STRENGTH_NO 0
#define PM_GPIO_STRENGTH_HIGH 1
diff --git a/include/linux/mfd/pm8xxx/irq.h b/include/linux/mfd/pm8xxx/irq.h
index 4e2570c..1e1fe6c 100644
--- a/include/linux/mfd/pm8xxx/irq.h
+++ b/include/linux/mfd/pm8xxx/irq.h
@@ -24,6 +24,7 @@
struct pm8xxx_irq_core_data {
u32 rev;
int nirqs;
+ unsigned int base_addr;
};
struct pm8xxx_irq_platform_data {
diff --git a/include/linux/mfd/pm8xxx/mpp.h b/include/linux/mfd/pm8xxx/mpp.h
index 7086b98..802948b 100644
--- a/include/linux/mfd/pm8xxx/mpp.h
+++ b/include/linux/mfd/pm8xxx/mpp.h
@@ -180,6 +180,14 @@
#define PM8018_MPP_DIG_LEVEL_L5 5
#define PM8018_MPP_DIG_LEVEL_VPH 7
+/* Digital Input/Output: level [PM8038] */
+#define PM8038_MPP_DIG_LEVEL_L20 0
+#define PM8038_MPP_DIG_LEVEL_L11 1
+#define PM8038_MPP_DIG_LEVEL_L5 2
+#define PM8038_MPP_DIG_LEVEL_L15 3
+#define PM8038_MPP_DIG_LEVEL_L17 4
+#define PM8038_MPP_DIG_LEVEL_VPH 7
+
/* Digital Input: control */
#define PM8XXX_MPP_DIN_TO_INT 0
#define PM8XXX_MPP_DIN_TO_DBUS1 1
diff --git a/include/linux/pmic8058-nfc.h b/include/linux/mfd/pm8xxx/nfc.h
similarity index 70%
rename from include/linux/pmic8058-nfc.h
rename to include/linux/mfd/pm8xxx/nfc.h
index 5b2d6cf..e58e0a9 100644
--- a/include/linux/pmic8058-nfc.h
+++ b/include/linux/mfd/pm8xxx/nfc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010,2011 Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -10,10 +10,12 @@
* GNU General Public License for more details.
*
*/
-#ifndef __PMIC8058_NFC_H__
-#define __PMIC8058_NFC_H__
+#ifndef __PM8XXX_NFC_H__
+#define __PM8XXX_NFC_H__
-struct pm8058_nfc_device;
+struct pm8xxx_nfc_device;
+
+#define PM8XXX_NFC_DEV_NAME "pm8xxx-nfc"
/* masks, flags and status */
#define PM_NFC_VDDLDO_MON_LEVEL 0x0003
@@ -46,32 +48,32 @@
PM_NFC_VDDLDO_OK_HIGH)
/*
- * pm8058_nfc_request - request a handle to access NFC device
+ * pm8xxx_nfc_request - request a handle to access NFC device
*/
-struct pm8058_nfc_device *pm8058_nfc_request(void);
+struct pm8xxx_nfc_device *pm8xxx_nfc_request(void);
/*
- * pm8058_nfc_config - configure NFC signals
+ * pm8xxx_nfc_config - configure NFC signals
*
* @nfcdev: the NFC device
* @mask: signal mask to configure
* @flags: control flags
*/
-int pm8058_nfc_config(struct pm8058_nfc_device *nfcdev, u32 mask, u32 flags);
+int pm8xxx_nfc_config(struct pm8xxx_nfc_device *nfcdev, u32 mask, u32 flags);
/*
- * pm8058_nfc_get_status - get NFC status
+ * pm8xxx_nfc_get_status - get NFC status
*
* @nfcdev: the NFC device
* @mask: of status mask to read
* @status: pointer to the status variable
*/
-int pm8058_nfc_get_status(struct pm8058_nfc_device *nfcdev,
+int pm8xxx_nfc_get_status(struct pm8xxx_nfc_device *nfcdev,
u32 mask, u32 *status);
/*
- * pm8058_nfc_free - free the NFC device
+ * pm8xxx_nfc_free - free the NFC device
*/
-void pm8058_nfc_free(struct pm8058_nfc_device *nfcdev);
+void pm8xxx_nfc_free(struct pm8xxx_nfc_device *nfcdev);
-#endif /* __PMIC8058_NFC_H__ */
+#endif /* __PM8XXX_NFC_H__ */
diff --git a/include/linux/mfd/pm8xxx/pm8038.h b/include/linux/mfd/pm8xxx/pm8038.h
new file mode 100644
index 0000000..2c2bb09
--- /dev/null
+++ b/include/linux/mfd/pm8xxx/pm8038.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ */
+/*
+ * Qualcomm PMIC 8038 driver header file
+ *
+ */
+
+#ifndef __MFD_PM8038_H
+#define __MFD_PM8038_H
+
+#include <linux/device.h>
+#include <linux/mfd/pm8xxx/irq.h>
+#include <linux/mfd/pm8xxx/gpio.h>
+#include <linux/mfd/pm8xxx/mpp.h>
+#include <linux/mfd/pm8xxx/pwm.h>
+#include <linux/mfd/pm8xxx/rtc.h>
+#include <linux/input/pmic8xxx-pwrkey.h>
+#include <linux/mfd/pm8xxx/misc.h>
+
+#define PM8038_CORE_DEV_NAME "pm8038-core"
+
+#define PM8038_NR_IRQS 256
+#define PM8038_NR_GPIOS 12
+#define PM8038_NR_MPPS 6
+
+#define PM8038_GPIO_BLOCK_START 24
+#define PM8038_MPP_BLOCK_START 16
+
+#define PM8038_IRQ_BLOCK_BIT(block, bit) ((block) * 8 + (bit))
+
+/* GPIO and MPPs [1,N] */
+#define PM8038_GPIO_IRQ(base, gpio) ((base) + \
+ PM8038_IRQ_BLOCK_BIT(PM8038_GPIO_BLOCK_START, (gpio)-1))
+#define PM8038_MPP_IRQ(base, mpp) ((base) + \
+ PM8038_IRQ_BLOCK_BIT(PM8038_MPP_BLOCK_START, (mpp)-1))
+
+/* PMIC Interrupts */
+#define PM8038_RTC_ALARM_IRQ PM8038_IRQ_BLOCK_BIT(4, 7)
+#define PM8038_PWRKEY_REL_IRQ PM8038_IRQ_BLOCK_BIT(6, 2)
+#define PM8038_PWRKEY_PRESS_IRQ PM8038_IRQ_BLOCK_BIT(6, 3)
+#define PM8038_KEYPAD_IRQ PM8038_IRQ_BLOCK_BIT(9, 2)
+#define PM8038_KEYSTUCK_IRQ PM8038_IRQ_BLOCK_BIT(9, 3)
+#define PM8038_USB_ID_IN_IRQ(base) (base + PM8921_IRQ_BLOCK_BIT(6, 1))
+
+#define PM8038_RESOUT_IRQ PM8038_IRQ_BLOCK_BIT(6, 4)
+
+struct pm8038_platform_data {
+ int irq_base;
+ struct pm8xxx_gpio_platform_data *gpio_pdata;
+ struct pm8xxx_irq_platform_data *irq_pdata;
+ struct pm8xxx_mpp_platform_data *mpp_pdata;
+ struct pm8xxx_rtc_platform_data *rtc_pdata;
+ struct pm8xxx_pwrkey_platform_data *pwrkey_pdata;
+ struct pm8xxx_misc_platform_data *misc_pdata;
+};
+
+#endif
diff --git a/include/linux/mfd/pm8xxx/pm8921-adc.h b/include/linux/mfd/pm8xxx/pm8921-adc.h
deleted file mode 100644
index c66ae84..0000000
--- a/include/linux/mfd/pm8xxx/pm8921-adc.h
+++ /dev/null
@@ -1,567 +0,0 @@
-/*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * 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.
- */
-/*
- * Qualcomm PMIC 8921 ADC driver header file
- *
- */
-
-#ifndef __PM8921_ADC_H
-#define __PM8921_ADC_H
-
-#include <linux/kernel.h>
-#include <linux/list.h>
-
-/**
- * enum pm8921_adc_channels - PM8921 AMUX arbiter channels
- * %CHANNEL_VCOIN: Backup voltage for certain register set
- * %CHANNEL_VBAT: Battery voltage
- * %CHANNEL_DCIN: Charger input voltage without internal OVP
- * %CHANNEL_ICHG: Charge-current monitor
- * %CHANNEL_VPH_PWR: Main system power
- * %CHANNEL_IBAT: Battery charge current
- * %CHANNEL_MPP_1: 16:1 pre-mux unity scale MPP input
- * %CHANNEL_MPP_2: 16:1 pre-mux 1/3 scale MPP input
- * %CHANNEL_BATT_THERM: Battery temperature
- * %CHANNEL_BATT_ID: Battery detection
- * %CHANNEL_USBIN: Charger input voltage with internal OVP
- * %CHANNEL_DIE_TEMP: Pmic_die temperature
- * %CHANNEL_625MV: 625mv reference channel
- * %CHANNEL_125V: 1.25v reference channel
- * %CHANNEL_CHG_TEMP: Charger temperature
- * %CHANNEL_MUXOFF: Channel to reduce input load on the mux
- * %CHANNEL_NONE: Do not use this channel
- */
-enum pm8921_adc_channels {
- CHANNEL_VCOIN = 0,
- CHANNEL_VBAT,
- CHANNEL_DCIN,
- CHANNEL_ICHG,
- CHANNEL_VPH_PWR,
- CHANNEL_IBAT,
- CHANNEL_MPP_1,
- CHANNEL_MPP_2,
- CHANNEL_BATT_THERM,
- CHANNEL_BATT_ID,
- CHANNEL_USBIN,
- CHANNEL_DIE_TEMP,
- CHANNEL_625MV,
- CHANNEL_125V,
- CHANNEL_CHG_TEMP,
- CHANNEL_MUXOFF,
- CHANNEL_NONE,
- ADC_MPP_1_ATEST_8 = 20,
- ADC_MPP_1_USB_SNS_DIV20,
- ADC_MPP_1_DCIN_SNS_DIV20,
- ADC_MPP_1_AMUX3,
- ADC_MPP_1_AMUX4,
- ADC_MPP_1_AMUX5,
- ADC_MPP_1_AMUX6,
- ADC_MPP_1_AMUX7,
- ADC_MPP_1_AMUX8,
- ADC_MPP_1_ATEST_1,
- ADC_MPP_1_ATEST_2,
- ADC_MPP_1_ATEST_3,
- ADC_MPP_1_ATEST_4,
- ADC_MPP_1_ATEST_5,
- ADC_MPP_1_ATEST_6,
- ADC_MPP_1_ATEST_7,
- ADC_MPP_1_CHANNEL_NONE,
- ADC_MPP_2_ATEST_8 = 40,
- ADC_MPP_2_USB_SNS_DIV20,
- ADC_MPP_2_DCIN_SNS_DIV20,
- ADC_MPP_2_AMUX3,
- ADC_MPP_2_AMUX4,
- ADC_MPP_2_AMUX5,
- ADC_MPP_2_AMUX6,
- ADC_MPP_2_AMUX7,
- ADC_MPP_2_AMUX8,
- ADC_MPP_2_ATEST_1,
- ADC_MPP_2_ATEST_2,
- ADC_MPP_2_ATEST_3,
- ADC_MPP_2_ATEST_4,
- ADC_MPP_2_ATEST_5,
- ADC_MPP_2_ATEST_6,
- ADC_MPP_2_ATEST_7,
- ADC_MPP_2_CHANNEL_NONE,
-};
-
-#define PM8921_ADC_PMIC_0 0x0
-
-#define PM8921_CHANNEL_ADC_625_MV 625
-#define PM8921_CHANNEL_MPP_SCALE1_IDX 20
-#define PM8921_CHANNEL_MPP_SCALE3_IDX 40
-
-#define PM8921_AMUX_MPP_3 0x3
-#define PM8921_AMUX_MPP_4 0x4
-#define PM8921_AMUX_MPP_5 0x5
-#define PM8921_AMUX_MPP_6 0x6
-#define PM8921_AMUX_MPP_7 0x7
-#define PM8921_AMUX_MPP_8 0x8
-
-#define PM8921_ADC_DEV_NAME "pm8921-adc"
-
-/**
- * enum pm8921_adc_decimation_type - Sampling rate supported
- * %ADC_DECIMATION_TYPE1: 512
- * %ADC_DECIMATION_TYPE2: 1K
- * %ADC_DECIMATION_TYPE3: 2K
- * %ADC_DECIMATION_TYPE4: 4k
- * %ADC_DECIMATION_NONE: Do not use this Sampling type
- *
- * The Sampling rate is specific to each channel of the PM8921 ADC arbiter.
- */
-enum pm8921_adc_decimation_type {
- ADC_DECIMATION_TYPE1 = 0,
- ADC_DECIMATION_TYPE2,
- ADC_DECIMATION_TYPE3,
- ADC_DECIMATION_TYPE4,
- ADC_DECIMATION_NONE,
-};
-
-/**
- * enum pm8921_adc_calib_type - PM8921 ADC Calibration type
- * %ADC_CALIB_ABSOLUTE: Use 625mV and 1.25V reference channels
- * %ADC_CALIB_RATIOMETRIC: Use reference Voltage/GND
- * %ADC_CALIB_CONFIG_NONE: Do not use this calibration type
- *
- * Use the input reference voltage depending on the calibration type
- * to calcluate the offset and gain parameters. The calibration is
- * specific to each channel of the PM8921 ADC.
- */
-enum pm8921_adc_calib_type {
- ADC_CALIB_ABSOLUTE = 0,
- ADC_CALIB_RATIOMETRIC,
- ADC_CALIB_NONE,
-};
-
-/**
- * enum pm8921_adc_channel_scaling_param - pre-scaling AMUX ratio
- * %CHAN_PATH_SCALING1: ratio of {1, 1}
- * %CHAN_PATH_SCALING2: ratio of {1, 3}
- * %CHAN_PATH_SCALING3: ratio of {1, 4}
- * %CHAN_PATH_SCALING4: ratio of {1, 6}
- * %CHAN_PATH_NONE: Do not use this pre-scaling ratio type
- *
- * The pre-scaling is applied for signals to be within the voltage range
- * of the ADC.
- */
-enum pm8921_adc_channel_scaling_param {
- CHAN_PATH_SCALING1 = 0,
- CHAN_PATH_SCALING2,
- CHAN_PATH_SCALING3,
- CHAN_PATH_SCALING4,
- CHAN_PATH_SCALING_NONE,
-};
-
-/**
- * enum pm8921_adc_amux_input_rsv - HK/XOADC reference voltage
- * %AMUX_RSV0: XO_IN/XOADC_GND
- * %AMUX_RSV1: PMIC_IN/XOADC_GND
- * %AMUX_RSV2: PMIC_IN/BMS_CSP
- * %AMUX_RSV3: not used
- * %AMUX_RSV4: XOADC_GND/XOADC_GND
- * %AMUX_RSV5: XOADC_VREF/XOADC_GND
- * %AMUX_NONE: Do not use this input reference voltage selection
- */
-enum pm8921_adc_amux_input_rsv {
- AMUX_RSV0 = 0,
- AMUX_RSV1,
- AMUX_RSV2,
- AMUX_RSV3,
- AMUX_RSV4,
- AMUX_RSV5,
- AMUX_NONE,
-};
-
-/**
- * enum pm8921_adc_premux_mpp_scale_type - 16:1 pre-mux scale ratio
- * %PREMUX_MPP_SCALE_0: No scaling to the input signal
- * %PREMUX_MPP_SCALE_1: Unity scaling selected by the user for MPP input
- * %PREMUX_MPP_SCALE_1_DIV3: 1/3 pre-scale to the input MPP signal
- * %PREMUX_MPP_NONE: Do not use this pre-scale mpp type
- */
-enum pm8921_adc_premux_mpp_scale_type {
- PREMUX_MPP_SCALE_0 = 0,
- PREMUX_MPP_SCALE_1,
- PREMUX_MPP_SCALE_1_DIV3,
- PREMUX_MPP_NONE,
-};
-
-/**
- * enum pm8921_adc_scale_fn_type - Scaling function for pm8921 pre calibrated
- * digital data relative to ADC reference
- * %ADC_SCALE_DEFAULT: Default scaling to convert raw adc code to voltage
- * %ADC_SCALE_BATT_THERM: Conversion to temperature based on btm parameters
- * %ADC_SCALE_PMIC_THERM: Returns result in milli degree's Centigrade
- * %ADC_SCALE_XTERN_CHGR_CUR: Returns current across 0.1 ohm resistor
- * %ADC_SCALE_XOTHERM: Returns XO thermistor voltage in degree's Centigrade
- * %ADC_SCALE_NONE: Do not use this scaling type
- */
-enum pm8921_adc_scale_fn_type {
- ADC_SCALE_DEFAULT = 0,
- ADC_SCALE_BATT_THERM,
- ADC_SCALE_PA_THERM,
- ADC_SCALE_PMIC_THERM,
- ADC_SCALE_XOTHERM,
- ADC_SCALE_NONE,
-};
-
-/**
- * struct pm8921_adc_linear_graph - Represent ADC characteristics
- * @offset: Offset with respect to the actual curve
- * @dy: Numerator slope to calculate the gain
- * @dx: Denominator slope to calculate the gain
- * @adc_vref: A/D word of the Voltage reference used for the channel
- * @adc_gnd: A/D word of the Ground reference used for the channel
- *
- * Each ADC device has different offset and gain parameters which are computed
- * to calibrate the device.
- */
-struct pm8921_adc_linear_graph {
- int32_t offset;
- int32_t dy;
- int32_t dx;
- int32_t adc_vref;
- int32_t adc_gnd;
-};
-
-/**
- * struct pm8921_adc_map_pt - Map the graph representation for ADC channel
- * @x: Represent the ADC digitized code
- * @y: Represent the physical data which can be temperature, voltage,
- * resistance
- */
-struct pm8921_adc_map_pt {
- int32_t x;
- int32_t y;
-};
-
-/**
- * struct pm8921_adc_scaling_ratio - Represent scaling ratio for adc input
- * @num: Numerator scaling parameter
- * @den: Denominator scaling parameter
- */
-struct pm8921_adc_scaling_ratio {
- int32_t num;
- int32_t den;
-};
-
-/**
- * struct pm8921_adc_properties - Represent the ADC properties
- * @adc_reference: Reference voltage for PM8921 ADC
- * @bitresolution: ADC bit resolution for PM8921 ADC
- * @biploar: Polarity for PM8921 ADC
- */
-struct pm8921_adc_properties {
- uint32_t adc_vdd_reference;
- uint32_t bitresolution;
- bool bipolar;
-};
-
-/**
- * struct pm8921_adc_chan_properties - Represent channel properties of the ADC
- * @offset_gain_numerator: The inverse numerator of the gain applied to the
- * input channel
- * @offset_gain_denominator: The inverse denominator of the gain applied to the
- * input channel
- * @adc_graph: ADC graph for the channel of struct type pm8921_adc_linear_graph
- */
-struct pm8921_adc_chan_properties {
- uint32_t offset_gain_numerator;
- uint32_t offset_gain_denominator;
- struct pm8921_adc_linear_graph adc_graph[2];
-};
-
-/**
- * struct pm8921_adc_chan_result - Represent the result of the PM8921 ADC
- * @chan: The channel number of the requested conversion
- * @adc_code: The pre-calibrated digital output of a given ADC relative to the
- * the ADC reference
- * @measurement: In units specific for a given ADC; most ADC uses reference
- * voltage but some ADC uses reference current. This measurement
- * here is a number relative to a reference of a given ADC
- * @physical: The data meaningful for each individual channel whether it is
- * voltage, current, temperature, etc.
- */
-struct pm8921_adc_chan_result {
- uint32_t chan;
- int32_t adc_code;
- int64_t measurement;
- int64_t physical;
-};
-
-#if defined(CONFIG_SENSORS_PM8921_ADC) \
- || defined(CONFIG_SENSORS_PM8921_ADC_MODULE)
-/**
- * pm8921_adc_scale_default() - Scales the pre-calibrated digital output
- * of an ADC to the ADC reference and compensates for the
- * gain and offset.
- * @adc_code: pre-calibrated digital ouput of the ADC.
- * @adc_prop: adc properties of the pm8921 adc such as bit resolution,
- * reference voltage.
- * @chan_prop: individual channel properties to compensate the i/p scaling,
- * slope and offset.
- * @chan_rslt: Physical result to be stored.
- */
-int32_t pm8921_adc_scale_default(int32_t adc_code,
- const struct pm8921_adc_properties *adc_prop,
- const struct pm8921_adc_chan_properties *chan_prop,
- struct pm8921_adc_chan_result *chan_rslt);
-/**
- * pm8921_adc_scale_tdkntcg_therm() - Scales the pre-calibrated digital output
- * of an ADC to the ADC reference and compensates for the
- * gain and offset. Returns the temperature of the xo therm in mili
- degC.
- * @adc_code: pre-calibrated digital ouput of the ADC.
- * @adc_prop: adc properties of the pm8921 adc such as bit resolution,
- * reference voltage.
- * @chan_prop: individual channel properties to compensate the i/p scaling,
- * slope and offset.
- * @chan_rslt: physical result to be stored.
- */
-int32_t pm8921_adc_tdkntcg_therm(int32_t adc_code,
- const struct pm8921_adc_properties *adc_prop,
- const struct pm8921_adc_chan_properties *chan_prop,
- struct pm8921_adc_chan_result *chan_rslt);
-/**
- * pm8921_adc_scale_batt_therm() - Scales the pre-calibrated digital output
- * of an ADC to the ADC reference and compensates for the
- * gain and offset. Returns the temperature in degC.
- * @adc_code: pre-calibrated digital ouput of the ADC.
- * @adc_prop: adc properties of the pm8921 adc such as bit resolution,
- * reference voltage.
- * @chan_prop: individual channel properties to compensate the i/p scaling,
- * slope and offset.
- * @chan_rslt: physical result to be stored.
- */
-int32_t pm8921_adc_scale_batt_therm(int32_t adc_code,
- const struct pm8921_adc_properties *adc_prop,
- const struct pm8921_adc_chan_properties *chan_prop,
- struct pm8921_adc_chan_result *chan_rslt);
-/**
- * pm8921_adc_scale_pa_therm() - Scales the pre-calibrated digital output
- * of an ADC to the ADC reference and compensates for the
- * gain and offset. Returns the temperature in degC.
- * @adc_code: pre-calibrated digital ouput of the ADC.
- * @adc_prop: adc properties of the pm8921 adc such as bit resolution,
- * reference voltage.
- * @chan_prop: individual channel properties to compensate the i/p scaling,
- * slope and offset.
- * @chan_rslt: physical result to be stored.
- */
-int32_t pm8921_adc_scale_pa_therm(int32_t adc_code,
- const struct pm8921_adc_properties *adc_prop,
- const struct pm8921_adc_chan_properties *chan_prop,
- struct pm8921_adc_chan_result *chan_rslt);
-/**
- * pm8921_adc_scale_pmic_therm() - Scales the pre-calibrated digital output
- * of an ADC to the ADC reference and compensates for the
- * gain and offset. Performs the AMUX out as 2mv/K and returns
- * the temperature in mili degC.
- * @adc_code: pre-calibrated digital ouput of the ADC.
- * @adc_prop: adc properties of the pm8921 adc such as bit resolution,
- * reference voltage.
- * @chan_prop: individual channel properties to compensate the i/p scaling,
- * slope and offset.
- * @chan_rslt: physical result to be stored.
- */
-int32_t pm8921_adc_scale_pmic_therm(int32_t adc_code,
- const struct pm8921_adc_properties *adc_prop,
- const struct pm8921_adc_chan_properties *chan_prop,
- struct pm8921_adc_chan_result *chan_rslt);
-#else
-static inline int32_t pm8921_adc_scale_default(int32_t adc_code,
- const struct pm8921_adc_properties *adc_prop,
- const struct pm8921_adc_chan_properties *chan_prop,
- struct pm8921_adc_chan_result *chan_rslt)
-{ return -ENXIO; }
-static inline int32_t pm8921_adc_tdkntcg_therm(int32_t adc_code,
- const struct pm8921_adc_properties *adc_prop,
- const struct pm8921_adc_chan_properties *chan_prop,
- struct pm8921_adc_chan_result *chan_rslt)
-{ return -ENXIO; }
-static inline int32_t pm8921_adc_scale_batt_therm(int32_t adc_code,
- const struct pm8921_adc_properties *adc_prop,
- const struct pm8921_adc_chan_properties *chan_prop,
- struct pm8921_adc_chan_result *chan_rslt)
-{ return -ENXIO; }
-static inline int32_t pm8921_adc_scale_pa_therm(int32_t adc_code,
- const struct pm8921_adc_properties *adc_prop,
- const struct pm8921_adc_chan_properties *chan_prop,
- struct pm8921_adc_chan_result *chan_rslt)
-{ return -ENXIO; }
-static inline int32_t pm8921_adc_scale_pmic_therm(int32_t adc_code,
- const struct pm8921_adc_properties *adc_prop,
- const struct pm8921_adc_chan_properties *chan_prop,
- struct pm8921_adc_chan_result *chan_rslt)
-{ return -ENXIO; }
-#endif
-
-/**
- * struct pm8921_adc_scale_fn - Scaling function prototype
- * @chan: Function pointer to one of the scaling functions
- * which takes the adc properties, channel properties,
- * and returns the physical result
- */
-struct pm8921_adc_scale_fn {
- int32_t (*chan) (int32_t,
- const struct pm8921_adc_properties *,
- const struct pm8921_adc_chan_properties *,
- struct pm8921_adc_chan_result *);
-};
-
-/**
- * struct pm8921_adc_amux - AMUX properties for individual channel
- * @name: Channel name
- * @channel_name: Channel in integer used from pm8921_adc_channels
- * @chan_path_prescaling: Channel scaling performed on the input signal
- * @adc_rsv: Input reference Voltage/GND selection to the ADC
- * @adc_decimation: Sampling rate desired for the channel
- * adc_scale_fn: Scaling function to convert to the data meaningful for
- * each individual channel whether it is voltage, current,
- * temperature, etc and compensates the channel properties
- */
-struct pm8921_adc_amux {
- char *name;
- enum pm8921_adc_channels channel_name;
- enum pm8921_adc_channel_scaling_param chan_path_prescaling;
- enum pm8921_adc_amux_input_rsv adc_rsv;
- enum pm8921_adc_decimation_type adc_decimation;
- enum pm8921_adc_scale_fn_type adc_scale_fn;
-};
-
-/**
- * struct pm8921_adc_arb_btm_param - PM8921 ADC BTM parameters to set threshold
- * temperature for client notification
- * @low_thr_temp: low temperature threshold request for notification
- * @high_thr_temp: high temperature threshold request for notification
- * @low_thr_voltage: low temperature converted to voltage by arbiter driver
- * @high_thr_voltage: high temperature converted to voltage by arbiter driver
- * @interval: Interval period to check for temperature notification
- * @btm_warm_fn: Remote function call for warm threshold.
- * @btm_cool_fn: Remote function call for cold threshold.
- *
- * BTM client passes the parameters to be set for the
- * temperature threshold notifications. The client is
- * responsible for setting the new threshold
- * levels once the thresholds are reached
- */
-struct pm8921_adc_arb_btm_param {
- int32_t low_thr_temp;
- int32_t high_thr_temp;
- uint64_t low_thr_voltage;
- uint64_t high_thr_voltage;
- int32_t interval;
- void (*btm_warm_fn) (bool);
- void (*btm_cool_fn) (bool);
-};
-
-int32_t pm8921_adc_batt_scaler(struct pm8921_adc_arb_btm_param *,
- const struct pm8921_adc_properties *adc_prop,
- const struct pm8921_adc_chan_properties *chan_prop);
-/**
- * struct pm8921_adc_platform_data - PM8921 ADC platform data
- * @adc_prop: ADC specific parameters, voltage and channel setup
- * @adc_channel: Channel properties of the ADC arbiter
- * @adc_num_board_channel: Number of channels added in the board file
- * @adc_mpp_base: PM8921 MPP0 base passed from board file. This is used
- * to offset the PM8921 MPP passed to configure the
- * the MPP to AMUX mapping.
- */
-struct pm8921_adc_platform_data {
- struct pm8921_adc_properties *adc_prop;
- struct pm8921_adc_amux *adc_channel;
- uint32_t adc_num_board_channel;
- uint32_t adc_mpp_base;
-};
-
-/* Public API */
-#if defined(CONFIG_SENSORS_PM8921_ADC) \
- || defined(CONFIG_SENSORS_PM8921_ADC_MODULE)
-/**
- * pm8921_adc_read() - Performs ADC read on the channel.
- * @channel: Input channel to perform the ADC read.
- * @result: Structure pointer of type adc_chan_result
- * in which the ADC read results are stored.
- */
-uint32_t pm8921_adc_read(enum pm8921_adc_channels channel,
- struct pm8921_adc_chan_result *result);
-/**
- * pm8921_adc_mpp_config_read() - Configure's the PM8921 MPP
- * to AMUX6 and performs an ADC read.
- * @mpp_num PM8921 MPP number to configure to AMUX6.
- * @channel: Input channel to perform the ADC read.
- * a) 'ADC_MPP_1_AMUX6' if the input voltage is less than 1.8V
- * b) 'ADC_MPP_2_AMUX6' if the input voltage is greater then 1.8V
- * the input voltage is pre-divided by 3 and passed to the ADC.
- * The appropriate scaling function needs to be selected to let
- * the driver know a post scaling is required before returning
- * the result.
- * @result: Structure pointer of type adc_chan_result
- * in which the ADC read results are stored.
- */
-uint32_t pm8921_adc_mpp_config_read(uint32_t mpp_num,
- enum pm8921_adc_channels channel,
- struct pm8921_adc_chan_result *result);
-/**
- * pm8921_adc_btm_start() - Configure the BTM registers and start
- monitoring the BATT_THERM channel for
- threshold warm/cold temperature set
- by the Battery client. The btm_start
- api is to be used after calling the
- pm8921_btm_configure() api which sets
- the temperature thresholds, interval
- and functions to call when warm/cold
- events are triggered.
- * @param: none.
- */
-uint32_t pm8921_adc_btm_start(void);
-
-/**
- * pm8921_adc_btm_end() - Configures the BTM registers to stop
- * monitoring the BATT_THERM channel for
- * warm/cold events and disables the
- * interval timer.
- * @param: none.
- */
-uint32_t pm8921_adc_btm_end(void);
-
-/**
- * pm8921_adc_btm_configure() - Configures the BATT_THERM channel
- * parameters for warm/cold thresholds.
- * Sets the interval timer for perfoming
- * reading the temperature done by the HW.
- * @btm_param: Structure pointer of type adc_arb_btm_param *
- * which client provides for threshold warm/cold,
- * interval and functions to call when warm/cold
- * events are triggered.
- */
-uint32_t pm8921_adc_btm_configure(struct pm8921_adc_arb_btm_param *);
-#else
-static inline uint32_t pm8921_adc_read(uint32_t channel,
- struct pm8921_adc_chan_result *result)
-{ return -ENXIO; }
-static inline uint32_t pm8921_adc_mpp_config_read(uint32_t mpp_num,
- enum pm8921_adc_channels channel,
- struct pm8921_adc_chan_result *result)
-{ return -ENXIO; }
-static inline uint32_t pm8921_adc_btm_start(void)
-{ return -ENXIO; }
-static inline uint32_t pm8921_adc_btm_end(void)
-{ return -ENXIO; }
-static inline uint32_t pm8921_adc_btm_configure(
- struct pm8921_adc_arb_btm_param *param)
-{ return -ENXIO; }
-#endif
-
-#endif /* PM8921_ADC_H */
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 73067b7..ef08c47 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -44,8 +44,8 @@
* @min_voltage: the voltage (mV) where charging method switches from
* trickle to fast. This is also the minimum voltage the
* system operates at
- * @resume_voltage: the voltage (mV) to wait for before resume charging
- * after the battery has been fully charged
+ * @resume_voltage_delta: the (mV) drop to wait for before resume charging
+ * after the battery has been fully charged
* @term_current: the charger current (mA) at which EOC happens
* @cool_temp: the temperature (degC) at which the battery is
* considered cool charging current and voltage is reduced
@@ -91,7 +91,7 @@
unsigned int update_time;
unsigned int max_voltage;
unsigned int min_voltage;
- unsigned int resume_voltage;
+ unsigned int resume_voltage_delta;
unsigned int term_current;
unsigned int cool_temp;
unsigned int warm_temp;
@@ -184,6 +184,18 @@
int pm8921_set_max_battery_charge_current(int ma);
/**
+ * pm8921_disable_input_current_limt - disable input current limit
+ *
+ * @disable: disable input curren_limit limit
+ *
+ * Disabling the charge current limit causes current
+ * current limits to have no monitoring. An adequate charger
+ * capable of supplying high current while sustaining VIN_MIN
+ * is required if input current limiting is disabled.
+ */
+int pm8921_disable_input_current_limit(bool disable);
+
+/**
* pm8921_disable_source_current - disable drawing current from source
* @disable: true to disable current drawing from source false otherwise
*
@@ -261,6 +273,10 @@
{
return -ENXIO;
}
+static inline int pm8921_disable_input_current_limit(bool disable)
+{
+ return -ENXIO;
+}
static inline int pm8921_set_max_battery_charge_current(int ma)
{
return -ENXIO;
diff --git a/include/linux/mfd/pm8xxx/pm8921.h b/include/linux/mfd/pm8xxx/pm8921.h
index 64bdab1..d4cdc3c 100644
--- a/include/linux/mfd/pm8xxx/pm8921.h
+++ b/include/linux/mfd/pm8xxx/pm8921.h
@@ -31,10 +31,11 @@
#include <linux/input/pmic8xxx-keypad.h>
#include <linux/regulator/pm8921-regulator.h>
#include <linux/mfd/pm8xxx/pm8921-charger.h>
-#include <linux/mfd/pm8xxx/pm8921-adc.h>
+#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
#include <linux/mfd/pm8xxx/pm8921-bms.h>
#include <linux/leds-pm8xxx.h>
#include <linux/mfd/pm8xxx/vibrator.h>
+#include <linux/mfd/pm8xxx/ccadc.h>
#define PM8921_NR_IRQS 256
@@ -125,9 +126,10 @@
struct pm8xxx_misc_platform_data *misc_pdata;
struct pm8921_regulator_platform_data *regulator_pdatas;
int num_regulators;
- struct pm8921_adc_platform_data *adc_pdata;
+ struct pm8xxx_adc_platform_data *adc_pdata;
struct pm8xxx_led_platform_data *leds_pdata;
struct pm8xxx_vibrator_platform_data *vibrator_pdata;
+ struct pm8xxx_ccadc_platform_data *ccadc_pdata;
};
#endif
diff --git a/include/linux/mfd/pm8xxx/tm.h b/include/linux/mfd/pm8xxx/tm.h
index 01edb97..6974754 100644
--- a/include/linux/mfd/pm8xxx/tm.h
+++ b/include/linux/mfd/pm8xxx/tm.h
@@ -24,7 +24,8 @@
enum pm8xxx_tm_adc_type {
PM8XXX_TM_ADC_NONE, /* Estimates temp based on overload level. */
- PM8XXX_TM_ADC_PM8921_ADC,
+ PM8XXX_TM_ADC_PM8058_ADC,
+ PM8XXX_TM_ADC_PM8XXX_ADC,
};
struct pm8xxx_tm_core_data {
diff --git a/include/linux/mfd/pm8xxx/upl.h b/include/linux/mfd/pm8xxx/upl.h
new file mode 100644
index 0000000..b0e94a9
--- /dev/null
+++ b/include/linux/mfd/pm8xxx/upl.h
@@ -0,0 +1,65 @@
+/* Copyright (c) 2010,2011 Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 __PM8XXX_UPL_H__
+#define __PM8XXX_UPL_H__
+
+struct pm8xxx_upl_device;
+
+#define PM8XXX_UPL_DEV_NAME "pm8xxx-upl"
+
+/* control masks and flags */
+#define PM8XXX_UPL_MOD_ENABLE_MASK (0x10)
+#define PM8XXX_UPL_MOD_ENABLE (0x10)
+#define PM8XXX_UPL_MOD_DISABLE (0x00)
+
+#define PM8XXX_UPL_OUT_DTEST_MASK (0xE0)
+#define PM8XXX_UPL_OUT_GPIO_ONLY (0x00)
+#define PM8XXX_UPL_OUT_DTEST_1 (0x80)
+#define PM8XXX_UPL_OUT_DTEST_2 (0xA0)
+#define PM8XXX_UPL_OUT_DTEST_3 (0xC0)
+#define PM8XXX_UPL_OUT_DTEST_4 (0xE0)
+
+#define PM8XXX_UPL_IN_A_MASK (0x01)
+#define PM8XXX_UPL_IN_A_GPIO (0x00)
+#define PM8XXX_UPL_IN_A_DTEST (0x01)
+#define PM8XXX_UPL_IN_B_MASK (0x02)
+#define PM8XXX_UPL_IN_B_GPIO (0x00)
+#define PM8XXX_UPL_IN_B_DTEST (0x02)
+#define PM8XXX_UPL_IN_C_MASK (0x04)
+#define PM8XXX_UPL_IN_C_GPIO (0x00)
+#define PM8XXX_UPL_IN_C_DTEST (0x04)
+#define PM8XXX_UPL_IN_D_MASK (0x08)
+#define PM8XXX_UPL_IN_D_GPIO (0x00)
+#define PM8XXX_UPL_IN_D_DTEST (0x08)
+
+/*
+ * pm8xxx_upl_request - request a handle to access UPL device
+ */
+struct pm8xxx_upl_device *pm8xxx_upl_request(void);
+
+int pm8xxx_upl_read_truthtable(struct pm8xxx_upl_device *upldev,
+ u16 *truthtable);
+
+int pm8xxx_upl_write_truthtable(struct pm8xxx_upl_device *upldev,
+ u16 truthtable);
+
+/*
+ * pm8xxx_upl_config - configure UPL I/O settings and UPL enable/disable
+ *
+ * @upldev: the UPL device
+ * @mask: setting mask to configure
+ * @flags: setting flags
+ */
+int pm8xxx_upl_config(struct pm8xxx_upl_device *upldev, u32 mask, u32 flags);
+
+#endif /* __PM8XXX_UPL_H__ */
diff --git a/include/linux/mfd/pm8xxx/vibrator.h b/include/linux/mfd/pm8xxx/vibrator.h
index 3a269a0..cfea1c9 100644
--- a/include/linux/mfd/pm8xxx/vibrator.h
+++ b/include/linux/mfd/pm8xxx/vibrator.h
@@ -15,10 +15,25 @@
#define PM8XXX_VIBRATOR_DEV_NAME "pm8xxx-vib"
+enum pm8xxx_vib_en_mode {
+ PM8XXX_VIB_MANUAL,
+ PM8XXX_VIB_DTEST1,
+ PM8XXX_VIB_DTEST2,
+ PM8XXX_VIB_DTEST3
+};
+
+struct pm8xxx_vib_config {
+ u16 drive_mV;
+ u8 active_low;
+ enum pm8xxx_vib_en_mode enable_mode;
+};
+
struct pm8xxx_vibrator_platform_data {
int initial_vibrate_ms;
int max_timeout_ms;
int level_mV;
};
+int pm8xxx_vibrator_config(struct pm8xxx_vib_config *vib_config);
+
#endif /* __PMIC8XXX_VIBRATOR_H__ */
diff --git a/include/linux/mfd/pmic8058.h b/include/linux/mfd/pmic8058.h
index 4d9f257..cf753b5d 100644
--- a/include/linux/mfd/pmic8058.h
+++ b/include/linux/mfd/pmic8058.h
@@ -15,12 +15,39 @@
*
*/
+#ifndef __MFD_PMIC8058_H__
+#define __MFD_PMIC8058_H__
+
#include <linux/irq.h>
#include <linux/mfd/core.h>
+#include <linux/mfd/pm8xxx/irq.h>
+#include <linux/mfd/pm8xxx/gpio.h>
+#include <linux/mfd/pm8xxx/mpp.h>
+#include <linux/mfd/pm8xxx/rtc.h>
+#include <linux/input/pmic8xxx-pwrkey.h>
+#include <linux/input/pmic8xxx-keypad.h>
+#include <linux/mfd/pm8xxx/vibrator.h>
+#include <linux/mfd/pm8xxx/nfc.h>
+#include <linux/mfd/pm8xxx/upl.h>
+#include <linux/mfd/pm8xxx/misc.h>
+#include <linux/mfd/pm8xxx/batt-alarm.h>
+#include <linux/leds-pmic8058.h>
+#include <linux/pmic8058-othc.h>
+#include <linux/mfd/pm8xxx/tm.h>
+#include <linux/pmic8058-xoadc.h>
+#include <linux/regulator/pmic8058-regulator.h>
+#include <linux/regulator/pm8058-xo.h>
+#include <linux/pwm.h>
+#include <linux/pmic8058-pwm.h>
#define PM8058_GPIOS 40
#define PM8058_MPPS 12
+#define PM8058_GPIO_BLOCK_START 24
+#define PM8058_MPP_BLOCK_START 16
+
+#define PM8058_NR_IRQS 256
+
#define PM8058_IRQ_BLOCK_BIT(block, bit) ((block) * 8 + (bit))
/* MPPs and GPIOs [0,N) */
@@ -29,146 +56,58 @@
#define PM8058_GPIO_IRQ(base, gpio) ((base) + \
PM8058_IRQ_BLOCK_BIT(24, (gpio)))
-#define PM8058_KEYPAD_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(9, 2))
-#define PM8058_KEYSTUCK_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(9, 3))
+/* PM8058 IRQ's */
+#define PM8058_VCP_IRQ PM8058_IRQ_BLOCK_BIT(1, 0)
+#define PM8058_CHGILIM_IRQ PM8058_IRQ_BLOCK_BIT(1, 3)
+#define PM8058_VBATDET_LOW_IRQ PM8058_IRQ_BLOCK_BIT(1, 4)
+#define PM8058_BATT_REPLACE_IRQ PM8058_IRQ_BLOCK_BIT(1, 5)
+#define PM8058_CHGINVAL_IRQ PM8058_IRQ_BLOCK_BIT(1, 6)
+#define PM8058_CHGVAL_IRQ PM8058_IRQ_BLOCK_BIT(1, 7)
+#define PM8058_CHG_END_IRQ PM8058_IRQ_BLOCK_BIT(2, 0)
+#define PM8058_FASTCHG_IRQ PM8058_IRQ_BLOCK_BIT(2, 1)
+#define PM8058_CHGSTATE_IRQ PM8058_IRQ_BLOCK_BIT(2, 3)
+#define PM8058_AUTO_CHGFAIL_IRQ PM8058_IRQ_BLOCK_BIT(2, 4)
+#define PM8058_AUTO_CHGDONE_IRQ PM8058_IRQ_BLOCK_BIT(2, 5)
+#define PM8058_ATCFAIL_IRQ PM8058_IRQ_BLOCK_BIT(2, 6)
+#define PM8058_ATC_DONE_IRQ PM8058_IRQ_BLOCK_BIT(2, 7)
+#define PM8058_OVP_OK_IRQ PM8058_IRQ_BLOCK_BIT(3, 0)
+#define PM8058_COARSE_DET_OVP_IRQ PM8058_IRQ_BLOCK_BIT(3, 1)
+#define PM8058_VCPMAJOR_IRQ PM8058_IRQ_BLOCK_BIT(3, 2)
+#define PM8058_CHG_GONE_IRQ PM8058_IRQ_BLOCK_BIT(3, 3)
+#define PM8058_CHGTLIMIT_IRQ PM8058_IRQ_BLOCK_BIT(3, 4)
+#define PM8058_CHGHOT_IRQ PM8058_IRQ_BLOCK_BIT(3, 5)
+#define PM8058_BATTTEMP_IRQ PM8058_IRQ_BLOCK_BIT(3, 6)
+#define PM8058_BATTCONNECT_IRQ PM8058_IRQ_BLOCK_BIT(3, 7)
+#define PM8058_BATFET_IRQ PM8058_IRQ_BLOCK_BIT(5, 4)
+#define PM8058_VBATDET_IRQ PM8058_IRQ_BLOCK_BIT(5, 5)
+#define PM8058_VBAT_IRQ PM8058_IRQ_BLOCK_BIT(5, 6)
-#define PM8058_VCP_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(1, 0))
-#define PM8058_CHGILIM_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(1, 3))
-#define PM8058_VBATDET_LOW_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(1, 4))
-#define PM8058_BATT_REPLACE_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(1, 5))
-#define PM8058_CHGINVAL_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(1, 6))
-#define PM8058_CHGVAL_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(1, 7))
-#define PM8058_CHG_END_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(2, 0))
-#define PM8058_FASTCHG_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(2, 1))
-#define PM8058_CHGSTATE_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(2, 3))
-#define PM8058_AUTO_CHGFAIL_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(2, 4))
-#define PM8058_AUTO_CHGDONE_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(2, 5))
-#define PM8058_ATCFAIL_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(2, 6))
-#define PM8058_ATC_DONE_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(2, 7))
-#define PM8058_OVP_OK_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(3, 0))
-#define PM8058_COARSE_DET_OVP_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(3, 1))
-#define PM8058_VCPMAJOR_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(3, 2))
-#define PM8058_CHG_GONE_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(3, 3))
-#define PM8058_CHGTLIMIT_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(3, 4))
-#define PM8058_CHGHOT_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(3, 5))
-#define PM8058_BATTTEMP_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(3, 6))
-#define PM8058_BATTCONNECT_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(3, 7))
-#define PM8058_BATFET_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(5, 4))
-#define PM8058_VBATDET_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(5, 5))
-#define PM8058_VBAT_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(5, 6))
-
-#define PM8058_CBLPWR_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(4, 3))
-
-#define PM8058_PWRKEY_REL_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(6, 2))
-#define PM8058_PWRKEY_PRESS_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(6, 3))
-#define PM8058_SW_0_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(7, 1))
-#define PM8058_IR_0_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(7, 0))
-#define PM8058_SW_1_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(7, 3))
-#define PM8058_IR_1_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(7, 2))
-#define PM8058_SW_2_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(7, 5))
-#define PM8058_IR_2_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(7, 4))
-#define PM8058_RTC_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(6, 5))
-#define PM8058_RTC_ALARM_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(4, 7))
-#define PM8058_ADC_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(9, 4))
-#define PM8058_TEMP_ALARM_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(6, 7))
-#define PM8058_OSCHALT_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(4, 6))
-#define PM8058_BATT_ALARM_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(5, 6))
-#define PM8058_RESOUT_IRQ(base) ((base) + PM8058_IRQ_BLOCK_BIT(6, 4))
-
-struct pm8058_chip;
-
-struct pm8058_platform_data {
- /* This table is only needed for misc interrupts. */
- int irq_base;
- int irq;
- int (*init)(struct pm8058_chip *pm_chip);
-
- int num_subdevs;
- struct mfd_cell *sub_devices;
- int irq_trigger_flags;
- struct mfd_cell *charger_sub_device;
-};
-
-struct pm8058_gpio_platform_data {
- int gpio_base;
- int irq_base;
- int (*init)(void);
-};
-
-/* GPIO parameters */
-/* direction */
-#define PM_GPIO_DIR_OUT 0x01
-#define PM_GPIO_DIR_IN 0x02
-#define PM_GPIO_DIR_BOTH (PM_GPIO_DIR_OUT | PM_GPIO_DIR_IN)
-
-/* output_buffer */
-#define PM_GPIO_OUT_BUF_OPEN_DRAIN 1
-#define PM_GPIO_OUT_BUF_CMOS 0
-
-/* pull */
-#define PM_GPIO_PULL_UP_30 0
-#define PM_GPIO_PULL_UP_1P5 1
-#define PM_GPIO_PULL_UP_31P5 2
-#define PM_GPIO_PULL_UP_1P5_30 3
-#define PM_GPIO_PULL_DN 4
-#define PM_GPIO_PULL_NO 5
-
-/* vin_sel: Voltage Input Select */
-#define PM_GPIO_VIN_VPH 0
-#define PM_GPIO_VIN_BB 1
-#define PM_GPIO_VIN_S3 2
-#define PM_GPIO_VIN_L3 3
-#define PM_GPIO_VIN_L7 4
-#define PM_GPIO_VIN_L6 5
-#define PM_GPIO_VIN_L5 6
-#define PM_GPIO_VIN_L2 7
-
-/* out_strength */
-#define PM_GPIO_STRENGTH_NO 0
-#define PM_GPIO_STRENGTH_HIGH 1
-#define PM_GPIO_STRENGTH_MED 2
-#define PM_GPIO_STRENGTH_LOW 3
-
-/* function */
-#define PM_GPIO_FUNC_NORMAL 0
-#define PM_GPIO_FUNC_PAIRED 1
-#define PM_GPIO_FUNC_1 2
-#define PM_GPIO_FUNC_2 3
-#define PM_GPIO_DTEST1 4
-#define PM_GPIO_DTEST2 5
-#define PM_GPIO_DTEST3 6
-#define PM_GPIO_DTEST4 7
-
-struct pm8058_gpio {
- int direction;
- int output_buffer;
- int output_value;
- int pull;
- int vin_sel; /* 0..7 */
- int out_strength;
- int function;
- int inv_int_pol; /* invert interrupt polarity */
- int disable_pin; /* disable pin and tri-state its pad */
-};
+#define PM8058_RTC_IRQ PM8058_IRQ_BLOCK_BIT(6, 5)
+#define PM8058_RTC_ALARM_IRQ PM8058_IRQ_BLOCK_BIT(4, 7)
+#define PM8058_PWRKEY_REL_IRQ PM8058_IRQ_BLOCK_BIT(6, 2)
+#define PM8058_PWRKEY_PRESS_IRQ PM8058_IRQ_BLOCK_BIT(6, 3)
+#define PM8058_KEYPAD_IRQ PM8058_IRQ_BLOCK_BIT(9, 2)
+#define PM8058_KEYSTUCK_IRQ PM8058_IRQ_BLOCK_BIT(9, 3)
+#define PM8058_BATT_ALARM_IRQ PM8058_IRQ_BLOCK_BIT(5, 6)
+#define PM8058_SW_0_IRQ PM8058_IRQ_BLOCK_BIT(7, 1)
+#define PM8058_IR_0_IRQ PM8058_IRQ_BLOCK_BIT(7, 0)
+#define PM8058_SW_1_IRQ PM8058_IRQ_BLOCK_BIT(7, 3)
+#define PM8058_IR_1_IRQ PM8058_IRQ_BLOCK_BIT(7, 2)
+#define PM8058_SW_2_IRQ PM8058_IRQ_BLOCK_BIT(7, 5)
+#define PM8058_IR_2_IRQ PM8058_IRQ_BLOCK_BIT(7, 4)
+#define PM8058_TEMPSTAT_IRQ PM8058_IRQ_BLOCK_BIT(6, 7)
+#define PM8058_OVERTEMP_IRQ PM8058_IRQ_BLOCK_BIT(4, 2)
+#define PM8058_ADC_IRQ PM8058_IRQ_BLOCK_BIT(9, 4)
+#define PM8058_OSCHALT_IRQ PM8058_IRQ_BLOCK_BIT(4, 6)
+#define PM8058_CBLPWR_IRQ PM8058_IRQ_BLOCK_BIT(4, 3)
+#define PM8058_RESOUT_IRQ PM8058_IRQ_BLOCK_BIT(6, 4)
struct pmic8058_charger_data {
unsigned int max_source_current;
int charger_type;
+ bool charger_data_valid;
};
-/* chip revision */
-#define PM_8058_REV_1p0 0xE1
-#define PM_8058_REV_2p0 0xE2
-#define PM_8058_REV_2p1 0xE3
-
-/* misc: control mask and flag */
-#define PM8058_UART_MUX_MASK 0x60
-
-#define PM8058_UART_MUX_NO 0x0
-#define PM8058_UART_MUX_1 0x20
-#define PM8058_UART_MUX_2 0x40
-#define PM8058_UART_MUX_3 0x60
-
enum pon_config{
DISABLE_HARD_RESET = 0,
SHUTDOWN_ON_HARD_RESET,
@@ -183,19 +122,27 @@
PM8058_SMPL_DELAY_2p0,
};
-/* Note -do not call pm8058_read and pm8058_write in an atomic context */
-int pm8058_read(struct pm8058_chip *pm_chip, u16 addr, u8 *values,
- unsigned int len);
-int pm8058_write(struct pm8058_chip *pm_chip, u16 addr, u8 *values,
- unsigned int len);
-
-int pm8058_gpio_config(int gpio, struct pm8058_gpio *param);
-
-int pm8058_rev(struct pm8058_chip *pm_chip);
-
-int pm8058_irq_get_rt_status(struct pm8058_chip *pm_chip, int irq);
-
-int pm8058_misc_control(struct pm8058_chip *pm_chip, int mask, int flag);
+struct pm8058_platform_data {
+ struct pm8xxx_mpp_platform_data *mpp_pdata;
+ struct pm8xxx_keypad_platform_data *keypad_pdata;
+ struct pm8xxx_gpio_platform_data *gpio_pdata;
+ struct pm8xxx_irq_platform_data *irq_pdata;
+ struct pm8xxx_rtc_platform_data *rtc_pdata;
+ struct pm8xxx_pwrkey_platform_data *pwrkey_pdata;
+ struct pm8xxx_vibrator_platform_data *vibrator_pdata;
+ struct pm8xxx_misc_platform_data *misc_pdata;
+ struct pmic8058_leds_platform_data *leds_pdata;
+ struct pmic8058_othc_config_pdata *othc0_pdata;
+ struct pmic8058_othc_config_pdata *othc1_pdata;
+ struct pmic8058_othc_config_pdata *othc2_pdata;
+ struct xoadc_platform_data *xoadc_pdata;
+ struct pm8058_pwm_pdata *pwm_pdata;
+ struct pm8058_vreg_pdata *regulator_pdatas;
+ int num_regulators;
+ struct pm8058_xo_pdata *xo_buffer_pdata;
+ int num_xo_buffers;
+ struct pmic8058_charger_data *charger_pdata;
+};
#ifdef CONFIG_PMIC8058
int pm8058_reset_pwr_off(int reset);
@@ -256,3 +203,5 @@
* RETURNS: an appropriate -ERRNO error value on error, or zero for success.
*/
int pm8058_stay_on(void);
+
+#endif /* __MFD_PMIC8058_H__ */
diff --git a/include/linux/mfd/pmic8901.h b/include/linux/mfd/pmic8901.h
index 8b628c5..5d23edc 100644
--- a/include/linux/mfd/pmic8901.h
+++ b/include/linux/mfd/pmic8901.h
@@ -38,6 +38,7 @@
struct pm8901_platform_data {
/* This table is only needed for misc interrupts. */
int irq_base;
+ int irq;
int num_subdevs;
struct mfd_cell *sub_devices;
diff --git a/include/linux/mfd/wcd9310/core.h b/include/linux/mfd/wcd9310/core.h
index 2d03c95..0eb875c 100644
--- a/include/linux/mfd/wcd9310/core.h
+++ b/include/linux/mfd/wcd9310/core.h
@@ -19,6 +19,9 @@
#define TABLA_SLIM_NUM_PORT_REG 3
+#define TABLA_INTERFACE_TYPE_SLIMBUS 0x00
+#define TABLA_INTERFACE_TYPE_I2C 0x01
+
enum {
TABLA_IRQ_SLIMBUS = 0,
TABLA_IRQ_MBHC_REMOVAL,
@@ -82,6 +85,7 @@
int tabla_irq_init(struct tabla *tabla);
void tabla_irq_exit(struct tabla *tabla);
int tabla_get_logical_addresses(u8 *pgd_la, u8 *inf_la);
+int tabla_get_intf_type(void);
static inline int tabla_request_irq(struct tabla *tabla, int irq,
irq_handler_t handler, const char *name,
diff --git a/include/linux/mfd/wm8994/pdata.h b/include/linux/mfd/wm8994/pdata.h
index d12f8d6..97cf4f2 100644
--- a/include/linux/mfd/wm8994/pdata.h
+++ b/include/linux/mfd/wm8994/pdata.h
@@ -26,7 +26,7 @@
struct regulator_init_data *init_data;
};
-#define WM8994_CONFIGURE_GPIO 0x8000
+#define WM8994_CONFIGURE_GPIO 0x10000
#define WM8994_DRC_REGS 5
#define WM8994_EQ_REGS 20
diff --git a/include/linux/mm.h b/include/linux/mm.h
index f821391..c73fdf8 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -28,6 +28,9 @@
extern unsigned long num_physpages;
extern unsigned long totalram_pages;
+#ifdef CONFIG_FIX_MOVABLE_ZONE
+extern unsigned long total_unmovable_pages;
+#endif
extern void * high_memory;
extern int page_cluster;
@@ -960,6 +963,8 @@
#ifdef CONFIG_MMU
extern int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long address, unsigned int flags);
+extern int fixup_user_fault(struct task_struct *tsk, struct mm_struct *mm,
+ unsigned long address, unsigned int fault_flags);
#else
static inline int handle_mm_fault(struct mm_struct *mm,
struct vm_area_struct *vma, unsigned long address,
@@ -969,6 +974,14 @@
BUG();
return VM_FAULT_SIGBUS;
}
+static inline int fixup_user_fault(struct task_struct *tsk,
+ struct mm_struct *mm, unsigned long address,
+ unsigned int fault_flags)
+{
+ /* should never happen if there's no MMU */
+ BUG();
+ return -EFAULT;
+}
#endif
extern int make_pages_present(unsigned long addr, unsigned long end);
@@ -986,8 +999,6 @@
int get_user_pages_fast(unsigned long start, int nr_pages, int write,
struct page **pages);
struct page *get_dump_page(unsigned long addr);
-extern int fixup_user_fault(struct task_struct *tsk, struct mm_struct *mm,
- unsigned long address, unsigned int fault_flags);
extern int try_to_release_page(struct page * page, gfp_t gfp_mask);
extern void do_invalidatepage(struct page *page, unsigned long offset);
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 312b17b..461192e 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -12,6 +12,7 @@
#include <linux/leds.h>
#include <linux/sched.h>
+#include <linux/wakelock.h>
#include <linux/mmc/core.h>
#include <linux/mmc/pm.h>
@@ -264,6 +265,7 @@
int claim_cnt; /* "claim" nesting count */
struct delayed_work detect;
+ struct wake_lock detect_wake_lock;
const struct mmc_bus_ops *bus_ops; /* current bus driver */
unsigned int bus_refs; /* reference counter */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index e10b278..53013f9 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -140,6 +140,16 @@
#define R1_SWITCH_ERROR (1 << 7) /* sx, c */
#define R1_APP_CMD (1 << 5) /* sr, c */
+#define R1_STATE_IDLE 0
+#define R1_STATE_READY 1
+#define R1_STATE_IDENT 2
+#define R1_STATE_STBY 3
+#define R1_STATE_TRAN 4
+#define R1_STATE_DATA 5
+#define R1_STATE_RCV 6
+#define R1_STATE_PRG 7
+#define R1_STATE_DIS 8
+
/*
* MMC/SD in SPI mode reports R1 status always, and R2 for SEND_STATUS
* R1 is the low order byte; R2 is the next highest byte, when present.
diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h
old mode 100755
new mode 100644
diff --git a/include/linux/msm_adc.h b/include/linux/msm_adc.h
index 5d5fb1b..51371a6 100644
--- a/include/linux/msm_adc.h
+++ b/include/linux/msm_adc.h
@@ -344,22 +344,24 @@
int32_t adc_channel_request_conv(void *h, struct completion *conv_complete_evt);
int32_t adc_channel_read_result(void *h, struct adc_chan_result *chan_result);
#else
-int32_t adc_channel_open(uint32_t channel, void **h)
+static int32_t adc_channel_open(uint32_t channel, void **h)
{
pr_err("%s.not supported.\n", __func__);
return -ENODEV;
}
-int32_t adc_channel_close(void *h)
+static int32_t adc_channel_close(void *h)
{
pr_err("%s.not supported.\n", __func__);
return -ENODEV;
}
-int32_t adc_channel_request_conv(void *h, struct completion *conv_complete_evt)
+static int32_t
+adc_channel_request_conv(void *h, struct completion *conv_complete_evt)
{
pr_err("%s.not supported.\n", __func__);
return -ENODEV;
}
-int32_t adc_channel_read_result(void *h, struct adc_chan_result *chan_result)
+static int32_t
+adc_channel_read_result(void *h, struct adc_chan_result *chan_result)
{
pr_err("%s.not supported.\n", __func__);
return -ENODEV;
diff --git a/include/linux/msm_audio_amrnb.h b/include/linux/msm_audio_amrnb.h
index 977335e..77a1258 100644
--- a/include/linux/msm_audio_amrnb.h
+++ b/include/linux/msm_audio_amrnb.h
@@ -1,21 +1,3 @@
-/* arch/arm/mach-msm/include/mach/msm_audio_amrnb.h
- *
- * Copyright (c) 2009, Code Aurora Forum. 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
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * See the GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, you can find it at http://www.fsf.org.
- *
- */
-
#ifndef __MSM_AUDIO_AMRNB_H
#define __MSM_AUDIO_AMRNB_H
diff --git a/include/linux/msm_audio_amrwb.h b/include/linux/msm_audio_amrwb.h
new file mode 100644
index 0000000..2383743
--- /dev/null
+++ b/include/linux/msm_audio_amrwb.h
@@ -0,0 +1,18 @@
+#ifndef __MSM_AUDIO_AMRWB_H
+#define __MSM_AUDIO_AMRWB_H
+
+#include <linux/msm_audio.h>
+
+#define AUDIO_GET_AMRWB_ENC_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), \
+ struct msm_audio_amrwb_enc_config)
+#define AUDIO_SET_AMRWB_ENC_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), \
+ struct msm_audio_amrwb_enc_config)
+
+struct msm_audio_amrwb_enc_config {
+ uint32_t band_mode;
+ uint32_t dtx_enable;
+ uint32_t frame_format;
+};
+#endif /* __MSM_AUDIO_AMRWB_H */
diff --git a/include/linux/msm_audio_mvs.h b/include/linux/msm_audio_mvs.h
index c934aee..2813c8f 100644
--- a/include/linux/msm_audio_mvs.h
+++ b/include/linux/msm_audio_mvs.h
@@ -108,10 +108,18 @@
#define MVS_MAX_VOC_PKT_SIZE 640
+struct gsm_header {
+ uint8_t bfi;
+ uint8_t sid;
+ uint8_t taf;
+ uint8_t ufi;
+};
+
struct q6_msm_audio_mvs_frame {
union {
uint32_t frame_type;
uint32_t packet_rate;
+ struct gsm_header gsm_frame_type;
} header;
uint32_t len;
uint8_t voc_pkt[MVS_MAX_VOC_PKT_SIZE];
diff --git a/include/linux/msm_audio_qcp.h b/include/linux/msm_audio_qcp.h
index c5e42cf..6e0c390 100644
--- a/include/linux/msm_audio_qcp.h
+++ b/include/linux/msm_audio_qcp.h
@@ -1,16 +1,3 @@
-/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * 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 __MSM_AUDIO_QCP_H
#define __MSM_AUDIO_QCP_H
diff --git a/include/linux/msm_audio_sbc.h b/include/linux/msm_audio_sbc.h
index 0a7602a..c1de751 100644
--- a/include/linux/msm_audio_sbc.h
+++ b/include/linux/msm_audio_sbc.h
@@ -1,16 +1,3 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * 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 __MSM_AUDIO_SBC_H
#define __MSM_AUDIO_SBC_H
diff --git a/include/linux/msm_audio_voicememo.h b/include/linux/msm_audio_voicememo.h
index 5cb1d65..d616c2e 100644
--- a/include/linux/msm_audio_voicememo.h
+++ b/include/linux/msm_audio_voicememo.h
@@ -1,16 +1,3 @@
-/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * 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 __MSM_AUDIO_VOICEMEMO_H
#define __MSM_AUDIO_VOICEMEMO_H
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index 9db6bc6..1f898b0 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -2,7 +2,7 @@
#define _MSM_KGSL_H
#define KGSL_VERSION_MAJOR 3
-#define KGSL_VERSION_MINOR 7
+#define KGSL_VERSION_MINOR 8
/*context flags */
#define KGSL_CONTEXT_SAVE_GMEM 1
@@ -25,6 +25,14 @@
#define KGSL_FLAGS_RESERVED2 0x00000080
#define KGSL_FLAGS_SOFT_RESET 0x00000100
+/* Clock flags to show which clocks should be controled by a given platform */
+#define KGSL_CLK_SRC 0x00000001
+#define KGSL_CLK_CORE 0x00000002
+#define KGSL_CLK_IFACE 0x00000004
+#define KGSL_CLK_MEM 0x00000008
+#define KGSL_CLK_MEM_IFACE 0x00000010
+#define KGSL_CLK_AXI 0x00000020
+
#define KGSL_MAX_PWRLEVELS 5
#define KGSL_CONVERT_TO_MBPS(val) \
@@ -130,30 +138,15 @@
#define KGSL_2D1_REG_MEMORY "kgsl_2d1_reg_memory"
#define KGSL_2D1_IRQ "kgsl_2d1_irq"
-struct kgsl_grp_clk_name {
- const char *clk;
- const char *pclk;
-};
-
-struct kgsl_device_pwr_data {
+struct kgsl_device_platform_data {
struct kgsl_pwrlevel pwrlevel[KGSL_MAX_PWRLEVELS];
int init_level;
int num_levels;
int (*set_grp_async)(void);
unsigned int idle_timeout;
unsigned int nap_allowed;
-};
-
-struct kgsl_clk_data {
- struct kgsl_grp_clk_name name;
+ unsigned int clk_map;
struct msm_bus_scale_pdata *bus_scale_table;
-};
-
-struct kgsl_device_platform_data {
- struct kgsl_device_pwr_data pwr_data;
- struct kgsl_clk_data clk;
- /* imem_clk_name is for 3d only, not used in 2d devices */
- struct kgsl_grp_clk_name imem_clk_name;
const char *iommu_user_ctx_name;
const char *iommu_priv_ctx_name;
};
@@ -427,6 +420,30 @@
#define IOCTL_KGSL_CFF_SYNCMEM \
_IOW(KGSL_IOC_TYPE, 0x30, struct kgsl_cff_syncmem)
+/*
+ * A timestamp event allows the user space to register an action following an
+ * expired timestamp.
+ */
+
+struct kgsl_timestamp_event {
+ int type; /* Type of event (see list below) */
+ unsigned int timestamp; /* Timestamp to trigger event on */
+ unsigned int context_id; /* Context for the timestamp */
+ void *priv; /* Pointer to the event specific blob */
+ size_t len; /* Size of the event specific blob */
+};
+
+#define IOCTL_KGSL_TIMESTAMP_EVENT \
+ _IOW(KGSL_IOC_TYPE, 0x31, struct kgsl_timestamp_event)
+
+/* A genlock timestamp event releases an existing lock on timestamp expire */
+
+#define KGSL_TIMESTAMP_EVENT_GENLOCK 1
+
+struct kgsl_timestamp_event_genlock {
+ int handle; /* Handle of the genlock lock to release */
+};
+
#ifdef __KERNEL__
#ifdef CONFIG_MSM_KGSL_DRM
int kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start,
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 5011229..0c09799 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -106,6 +106,14 @@
FB_IMG,
};
+enum {
+ HSIC_HUE = 0,
+ HSIC_SAT,
+ HSIC_INT,
+ HSIC_CON,
+ NUM_HSIC_PARAM,
+};
+
/* mdp_blit_req flag values */
#define MDP_ROT_NOP 0
#define MDP_FLIP_LR 0x1
@@ -131,7 +139,9 @@
#define MDP_DEINTERLACE_ODD 0x00400000
#define MDP_OV_PLAY_NOWAIT 0x00200000
#define MDP_SOURCE_ROTATED_90 0x00100000
+#define MDP_BORDERFILL_SUPPORTED 0x00010000
#define MDP_MEMORY_ID_TYPE_FB 0x00001000
+#define MDP_DPP_HSIC 0x00080000
#define MDP_TRANSP_NOP 0xffffffff
#define MDP_ALPHA_NOP 0xff
@@ -250,6 +260,7 @@
* smoothed picture.
*/
int8_t sharp_strength;
+ int8_t hsic_params[NUM_HSIC_PARAM];
};
struct mdp_overlay {
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index fc94089..473384b 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -55,6 +55,7 @@
PERF_COUNT_HW_BUS_CYCLES = 6,
PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 7,
PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 8,
+ PERF_COUNT_HW_L2_CYCLES = 9,
PERF_COUNT_HW_MAX, /* non-ABI */
};
@@ -219,8 +220,9 @@
precise_ip : 2, /* skid constraint */
mmap_data : 1, /* non-exec mmap data */
sample_id_all : 1, /* sample_type all events */
+ single_instance:1, /* per-cpu event if unset */
- __reserved_1 : 45;
+ __reserved_1:44;
union {
__u32 wakeup_events; /* wakeup every n events */
diff --git a/include/linux/personality.h b/include/linux/personality.h
index eec3bae..8fc7dd1a 100644
--- a/include/linux/personality.h
+++ b/include/linux/personality.h
@@ -22,6 +22,7 @@
* These occupy the top three bytes.
*/
enum {
+ UNAME26 = 0x0020000,
ADDR_NO_RANDOMIZE = 0x0040000, /* disable randomization of VA space */
FDPIC_FUNCPTRS = 0x0080000, /* userspace function ptrs point to descriptors
* (signal handling)
diff --git a/include/linux/platform_data/ram_console.h b/include/linux/platform_data/ram_console.h
new file mode 100644
index 0000000..9f1125c
--- /dev/null
+++ b/include/linux/platform_data/ram_console.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _INCLUDE_LINUX_PLATFORM_DATA_RAM_CONSOLE_H_
+#define _INCLUDE_LINUX_PLATFORM_DATA_RAM_CONSOLE_H_
+
+struct ram_console_platform_data {
+ const char *bootinfo;
+};
+
+#endif /* _INCLUDE_LINUX_PLATFORM_DATA_RAM_CONSOLE_H_ */
diff --git a/include/linux/pmic8058-upl.h b/include/linux/pmic8058-upl.h
deleted file mode 100644
index a8979f4..0000000
--- a/include/linux/pmic8058-upl.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * 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 __PMIC8058_UPL_H__
-#define __PMIC8058_UPL_H__
-
-struct pm8058_upl_device;
-
-/* control masks and flags */
-#define PM8058_UPL_MOD_ENABLE_MASK (0x10)
-#define PM8058_UPL_MOD_ENABLE (0x10)
-#define PM8058_UPL_MOD_DISABLE (0x00)
-
-#define PM8058_UPL_OUT_DTEST_MASK (0xE0)
-#define PM8058_UPL_OUT_GPIO_ONLY (0x00)
-#define PM8058_UPL_OUT_DTEST_1 (0x80)
-#define PM8058_UPL_OUT_DTEST_2 (0xA0)
-#define PM8058_UPL_OUT_DTEST_3 (0xC0)
-#define PM8058_UPL_OUT_DTEST_4 (0xE0)
-
-#define PM8058_UPL_IN_A_MASK (0x01)
-#define PM8058_UPL_IN_A_GPIO (0x00)
-#define PM8058_UPL_IN_A_DTEST (0x01)
-#define PM8058_UPL_IN_B_MASK (0x02)
-#define PM8058_UPL_IN_B_GPIO (0x00)
-#define PM8058_UPL_IN_B_DTEST (0x02)
-#define PM8058_UPL_IN_C_MASK (0x04)
-#define PM8058_UPL_IN_C_GPIO (0x00)
-#define PM8058_UPL_IN_C_DTEST (0x04)
-#define PM8058_UPL_IN_D_MASK (0x08)
-#define PM8058_UPL_IN_D_GPIO (0x00)
-#define PM8058_UPL_IN_D_DTEST (0x08)
-
-/*
- * pm8058_upl_request - request a handle to access UPL device
- */
-struct pm8058_upl_device *pm8058_upl_request(void);
-
-int pm8058_upl_read_truthtable(struct pm8058_upl_device *upldev,
- u16 *truthtable);
-
-int pm8058_upl_write_truthtable(struct pm8058_upl_device *upldev,
- u16 truthtable);
-
-/*
- * pm8058_upl_config - configure UPL I/O settings and UPL enable/disable
- *
- * @upldev: the UPL device
- * @mask: setting mask to configure
- * @flags: setting flags
- */
-int pm8058_upl_config(struct pm8058_upl_device *upldev, u32 mask, u32 flags);
-
-#endif /* __PMIC8058_UPL_H__ */
diff --git a/include/linux/pmic8058-xoadc.h b/include/linux/pmic8058-xoadc.h
index f72ad66..5163b65 100644
--- a/include/linux/pmic8058-xoadc.h
+++ b/include/linux/pmic8058-xoadc.h
@@ -12,8 +12,8 @@
* Qualcomm XOADC Driver header file
*/
-#ifndef _XOADC_H
-#define _XOADC_H_
+#ifndef _PMIC8058_XOADC_H_
+#define _PMIC8058_XOADC_H_
#include <linux/kernel.h>
#include <linux/list.h>
diff --git a/include/linux/power/ltc4088-charger.h b/include/linux/power/ltc4088-charger.h
new file mode 100644
index 0000000..7a0bacf
--- /dev/null
+++ b/include/linux/power/ltc4088-charger.h
@@ -0,0 +1,30 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 LTC4088_CHARGER_H_
+#define LTC4088_CHARGER_H_
+
+#define LTC4088_CHARGER_DEV_NAME "ltc4088-charger"
+
+/**
+ * struct ltc4088_charger_platform_data - platform data for LTC4088 charger
+ * @gpio_mode_select_d0: GPIO #pin for D0 charger line
+ * @gpio_mode_select_d1: GPIO #pin for D1 charger line
+ * @gpio_mode_select_d2: GPIO #pin for D2 charger line
+ */
+struct ltc4088_charger_platform_data {
+ unsigned int gpio_mode_select_d0;
+ unsigned int gpio_mode_select_d1;
+ unsigned int gpio_mode_select_d2;
+};
+
+#endif /* LTC4088_CHARGER_H_ */
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 2287c321..cab042b 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -157,6 +157,8 @@
enum power_supply_property psp);
void (*external_power_changed)(struct power_supply *psy);
void (*set_charged)(struct power_supply *psy);
+ int (*set_current_limit)(struct power_supply *psy, int limit);
+ int (*set_charging_by)(struct power_supply *psy, bool enable);
/* For APM emulation, think legacy userspace. */
int use_for_apm;
@@ -205,6 +207,8 @@
extern void power_supply_changed(struct power_supply *psy);
extern int power_supply_am_i_supplied(struct power_supply *psy);
extern int power_supply_set_battery_charged(struct power_supply *psy);
+extern int power_supply_set_current_limit(struct power_supply *psy, int limit);
+extern int power_supply_set_charging_by(struct power_supply *psy, bool enable);
#if defined(CONFIG_POWER_SUPPLY) || defined(CONFIG_POWER_SUPPLY_MODULE)
extern int power_supply_is_system_supplied(void);
diff --git a/include/linux/ptp_classify.h b/include/linux/ptp_classify.h
index e07e274..1dc420b 100644
--- a/include/linux/ptp_classify.h
+++ b/include/linux/ptp_classify.h
@@ -51,6 +51,7 @@
#define PTP_CLASS_V2_VLAN (PTP_CLASS_V2 | PTP_CLASS_VLAN)
#define PTP_EV_PORT 319
+#define PTP_GEN_BIT 0x08 /* indicates general message, if set in message type */
#define OFF_ETYPE 12
#define OFF_IHL 14
@@ -116,14 +117,20 @@
{OP_OR, 0, 0, PTP_CLASS_IPV6 }, /* */ \
{OP_RETA, 0, 0, 0 }, /* */ \
/*L3x*/ {OP_RETK, 0, 0, PTP_CLASS_NONE }, /* */ \
-/*L40*/ {OP_JEQ, 0, 6, ETH_P_8021Q }, /* f goto L50 */ \
+/*L40*/ {OP_JEQ, 0, 9, ETH_P_8021Q }, /* f goto L50 */ \
{OP_LDH, 0, 0, OFF_ETYPE + 4 }, /* */ \
- {OP_JEQ, 0, 9, ETH_P_1588 }, /* f goto L60 */ \
+ {OP_JEQ, 0, 15, ETH_P_1588 }, /* f goto L60 */ \
+ {OP_LDB, 0, 0, ETH_HLEN + VLAN_HLEN }, /* */ \
+ {OP_AND, 0, 0, PTP_GEN_BIT }, /* */ \
+ {OP_JEQ, 0, 12, 0 }, /* f goto L6x */ \
{OP_LDH, 0, 0, ETH_HLEN + VLAN_HLEN }, /* */ \
{OP_AND, 0, 0, PTP_CLASS_VMASK }, /* */ \
{OP_OR, 0, 0, PTP_CLASS_VLAN }, /* */ \
{OP_RETA, 0, 0, 0 }, /* */ \
-/*L50*/ {OP_JEQ, 0, 4, ETH_P_1588 }, /* f goto L61 */ \
+/*L50*/ {OP_JEQ, 0, 7, ETH_P_1588 }, /* f goto L61 */ \
+ {OP_LDB, 0, 0, ETH_HLEN }, /* */ \
+ {OP_AND, 0, 0, PTP_GEN_BIT }, /* */ \
+ {OP_JEQ, 0, 4, 0 }, /* f goto L6x */ \
{OP_LDH, 0, 0, ETH_HLEN }, /* */ \
{OP_AND, 0, 0, PTP_CLASS_VMASK }, /* */ \
{OP_OR, 0, 0, PTP_CLASS_L2 }, /* */ \
diff --git a/include/linux/random.h b/include/linux/random.h
index fb7ab9d..d13059f 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -57,17 +57,6 @@
extern void get_random_bytes(void *buf, int nbytes);
void generate_random_uuid(unsigned char uuid_out[16]);
-extern __u32 secure_ip_id(__be32 daddr);
-extern u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport);
-extern u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
- __be16 dport);
-extern __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
- __be16 sport, __be16 dport);
-extern __u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr,
- __be16 sport, __be16 dport);
-extern u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
- __be16 sport, __be16 dport);
-
#ifndef MODULE
extern const struct file_operations random_fops, urandom_fops;
#endif
diff --git a/include/linux/regulator/pm8058-xo.h b/include/linux/regulator/pm8058-xo.h
index 9b363c4..a2b8aeb 100644
--- a/include/linux/regulator/pm8058-xo.h
+++ b/include/linux/regulator/pm8058-xo.h
@@ -25,6 +25,7 @@
struct pm8058_xo_pdata {
struct regulator_init_data init_data;
+ int id;
};
#endif
diff --git a/include/linux/regulator/pmic8058-regulator.h b/include/linux/regulator/pmic8058-regulator.h
index 83d4412..3eeaa61 100644
--- a/include/linux/regulator/pmic8058-regulator.h
+++ b/include/linux/regulator/pmic8058-regulator.h
@@ -80,6 +80,7 @@
struct pm8058_vreg_pdata {
struct regulator_init_data init_data;
+ int id;
unsigned pull_down_enable;
unsigned pin_ctrl;
enum pm8058_vreg_pin_fn pin_fn;
diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h
index c6c6084..3d049ab 100644
--- a/include/linux/rfkill.h
+++ b/include/linux/rfkill.h
@@ -199,8 +199,11 @@
* NOTE: not necessary for suspend/resume -- in that case the
* core stops polling anyway
*/
+#ifdef CONFIG_RFKILL_PM
void rfkill_resume_polling(struct rfkill *rfkill);
-
+#else
+static inline void rfkill_resume_polling(struct rfkill *rfkill) { }
+#endif
/**
* rfkill_unregister - Unregister a rfkill structure.
diff --git a/include/linux/rio_regs.h b/include/linux/rio_regs.h
index 9026b30..218168a 100644
--- a/include/linux/rio_regs.h
+++ b/include/linux/rio_regs.h
@@ -36,12 +36,12 @@
#define RIO_PEF_PROCESSOR 0x20000000 /* [I] Processor */
#define RIO_PEF_SWITCH 0x10000000 /* [I] Switch */
#define RIO_PEF_MULTIPORT 0x08000000 /* [VI, 2.1] Multiport */
-#define RIO_PEF_INB_MBOX 0x00f00000 /* [II] Mailboxes */
-#define RIO_PEF_INB_MBOX0 0x00800000 /* [II] Mailbox 0 */
-#define RIO_PEF_INB_MBOX1 0x00400000 /* [II] Mailbox 1 */
-#define RIO_PEF_INB_MBOX2 0x00200000 /* [II] Mailbox 2 */
-#define RIO_PEF_INB_MBOX3 0x00100000 /* [II] Mailbox 3 */
-#define RIO_PEF_INB_DOORBELL 0x00080000 /* [II] Doorbells */
+#define RIO_PEF_INB_MBOX 0x00f00000 /* [II, <= 1.2] Mailboxes */
+#define RIO_PEF_INB_MBOX0 0x00800000 /* [II, <= 1.2] Mailbox 0 */
+#define RIO_PEF_INB_MBOX1 0x00400000 /* [II, <= 1.2] Mailbox 1 */
+#define RIO_PEF_INB_MBOX2 0x00200000 /* [II, <= 1.2] Mailbox 2 */
+#define RIO_PEF_INB_MBOX3 0x00100000 /* [II, <= 1.2] Mailbox 3 */
+#define RIO_PEF_INB_DOORBELL 0x00080000 /* [II, <= 1.2] Doorbells */
#define RIO_PEF_EXT_RT 0x00000200 /* [III, 1.3] Extended route table support */
#define RIO_PEF_STD_RT 0x00000100 /* [III, 1.3] Standard route table support */
#define RIO_PEF_CTLS 0x00000010 /* [III] CTLS */
@@ -102,7 +102,7 @@
#define RIO_SWITCH_RT_LIMIT 0x34 /* [III, 1.3] Switch Route Table Destination ID Limit CAR */
#define RIO_RT_MAX_DESTID 0x0000ffff
-#define RIO_MBOX_CSR 0x40 /* [II] Mailbox CSR */
+#define RIO_MBOX_CSR 0x40 /* [II, <= 1.2] Mailbox CSR */
#define RIO_MBOX0_AVAIL 0x80000000 /* [II] Mbox 0 avail */
#define RIO_MBOX0_FULL 0x40000000 /* [II] Mbox 0 full */
#define RIO_MBOX0_EMPTY 0x20000000 /* [II] Mbox 0 empty */
@@ -128,8 +128,8 @@
#define RIO_MBOX3_FAIL 0x00000008 /* [II] Mbox 3 fail */
#define RIO_MBOX3_ERROR 0x00000004 /* [II] Mbox 3 error */
-#define RIO_WRITE_PORT_CSR 0x44 /* [I] Write Port CSR */
-#define RIO_DOORBELL_CSR 0x44 /* [II] Doorbell CSR */
+#define RIO_WRITE_PORT_CSR 0x44 /* [I, <= 1.2] Write Port CSR */
+#define RIO_DOORBELL_CSR 0x44 /* [II, <= 1.2] Doorbell CSR */
#define RIO_DOORBELL_AVAIL 0x80000000 /* [II] Doorbell avail */
#define RIO_DOORBELL_FULL 0x40000000 /* [II] Doorbell full */
#define RIO_DOORBELL_EMPTY 0x20000000 /* [II] Doorbell empty */
diff --git a/include/linux/rtc.h b/include/linux/rtc.h
index b27ebea..93f4d03 100644
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -97,6 +97,9 @@
#define RTC_AF 0x20 /* Alarm interrupt */
#define RTC_UF 0x10 /* Update interrupt for 1Hz RTC */
+
+#define RTC_MAX_FREQ 8192
+
#ifdef __KERNEL__
#include <linux/types.h>
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 111588a..35895e3 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1940,7 +1940,6 @@
extern unsigned long long
task_sched_runtime(struct task_struct *task);
-extern unsigned long long thread_group_sched_runtime(struct task_struct *task);
/* sched_exec is called by processes performing an exec */
#ifdef CONFIG_SMP
diff --git a/include/linux/stop_machine.h b/include/linux/stop_machine.h
index 092dc9b..14d3524 100644
--- a/include/linux/stop_machine.h
+++ b/include/linux/stop_machine.h
@@ -27,6 +27,8 @@
struct cpu_stop_done *done;
};
+extern struct mutex stop_cpus_mutex;
+
int stop_one_cpu(unsigned int cpu, cpu_stop_fn_t fn, void *arg);
void stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg,
struct cpu_stop_work *work_buf);
diff --git a/include/linux/tty.h b/include/linux/tty.h
index d6f0529..6660c41 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -420,6 +420,8 @@
extern void tty_throttle(struct tty_struct *tty);
extern void tty_unthrottle(struct tty_struct *tty);
extern int tty_do_resize(struct tty_struct *tty, struct winsize *ws);
+extern void tty_driver_remove_tty(struct tty_driver *driver,
+ struct tty_struct *tty);
extern void tty_shutdown(struct tty_struct *tty);
extern void tty_free_termios(struct tty_struct *tty);
extern int is_current_pgrp_orphaned(void);
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 9deeac8..ecdaeb9 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -47,6 +47,9 @@
*
* This routine is called synchronously when a particular tty device
* is closed for the last time freeing up the resources.
+ * Note that tty_shutdown() is not called if ops->shutdown is defined.
+ * This means one is responsible to take care of calling ops->remove (e.g.
+ * via tty_driver_remove_tty) and releasing tty->termios.
*
*
* void (*cleanup)(struct tty_struct * tty);
diff --git a/include/linux/usb/ccid_desc.h b/include/linux/usb/ccid_desc.h
new file mode 100644
index 0000000..2d1ae74
--- /dev/null
+++ b/include/linux/usb/ccid_desc.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 __LINUX_USB_CCID_DESC_H
+#define __LINUX_USB_CCID_DESC_H
+
+/*CCID specification version 1.10*/
+#define CCID1_10 0x0110
+
+#define SMART_CARD_DEVICE_CLASS 0x0B
+/* Smart Card Device Class Descriptor Type */
+#define CCID_DECRIPTOR_TYPE 0x21
+
+/* Table 5.3-1 Summary of CCID Class Specific Request */
+#define CCIDGENERICREQ_ABORT 0x01
+#define CCIDGENERICREQ_GET_CLOCK_FREQUENCIES 0x02
+#define CCIDGENERICREQ_GET_DATA_RATES 0x03
+
+/* 6.1 Command Pipe, Bulk-OUT Messages */
+#define PC_TO_RDR_ICCPOWERON 0x62
+#define PC_TO_RDR_ICCPOWEROFF 0x63
+#define PC_TO_RDR_GETSLOTSTATUS 0x65
+#define PC_TO_RDR_XFRBLOCK 0x6F
+#define PC_TO_RDR_GETPARAMETERS 0x6C
+#define PC_TO_RDR_RESETPARAMETERS 0x6D
+#define PC_TO_RDR_SETPARAMETERS 0x61
+#define PC_TO_RDR_ESCAPE 0x6B
+#define PC_TO_RDR_ICCCLOCK 0x6E
+#define PC_TO_RDR_T0APDU 0x6A
+#define PC_TO_RDR_SECURE 0x69
+#define PC_TO_RDR_MECHANICAL 0x71
+#define PC_TO_RDR_ABORT 0x72
+#define PC_TO_RDR_SETDATARATEANDCLOCKFREQUENCY 0x73
+
+/* 6.2 Response Pipe, Bulk-IN Messages */
+#define RDR_TO_PC_DATABLOCK 0x80
+#define RDR_TO_PC_SLOTSTATUS 0x81
+#define RDR_TO_PC_PARAMETERS 0x82
+#define RDR_TO_PC_ESCAPE 0x83
+#define RDR_TO_PC_DATARATEANDCLOCKFREQUENCY 0x84
+
+/* 6.3 Interrupt-IN Messages */
+#define RDR_TO_PC_NOTIFYSLOTCHANGE 0x50
+#define RDR_TO_PC_HARDWAREERROR 0x51
+
+/* Table 6.2-2 Slot error register when bmCommandStatus = 1 */
+#define CMD_ABORTED 0xFF
+#define ICC_MUTE 0xFE
+#define XFR_PARITY_ERROR 0xFD
+#define XFR_OVERRUN 0xFC
+#define HW_ERROR 0xFB
+#define BAD_ATR_TS 0xF8
+#define BAD_ATR_TCK 0xF7
+#define ICC_PROTOCOL_NOT_SUPPORTED 0xF6
+#define ICC_CLASS_NOT_SUPPORTED 0xF5
+#define PROCEDURE_BYTE_CONFLICT 0xF4
+#define DEACTIVATED_PROTOCOL 0xF3
+#define BUSY_WITH_AUTO_SEQUENCE 0xF2
+#define PIN_TIMEOUT 0xF0
+#define PIN_CANCELLED 0xEF
+#define CMD_SLOT_BUSY 0xE0
+
+/* CCID rev 1.1, p.27 */
+#define VOLTS_AUTO 0x00
+#define VOLTS_5_0 0x01
+#define VOLTS_3_0 0x02
+#define VOLTS_1_8 0x03
+
+/* 6.3.1 RDR_to_PC_NotifySlotChange */
+#define ICC_NOT_PRESENT 0x00
+#define ICC_PRESENT 0x01
+#define ICC_CHANGE 0x02
+#define ICC_INSERTED_EVENT (ICC_PRESENT+ICC_CHANGE)
+
+/* Identifies the length of type of subordinate descriptors of a CCID device
+ * Table 5.1-1 Smart Card Device Class descriptors
+ */
+struct usb_ccid_class_descriptor {
+ unsigned char bLength;
+ unsigned char bDescriptorType;
+ unsigned short bcdCCID;
+ unsigned char bMaxSlotIndex;
+ unsigned char bVoltageSupport;
+ unsigned long dwProtocols;
+ unsigned long dwDefaultClock;
+ unsigned long dwMaximumClock;
+ unsigned char bNumClockSupported;
+ unsigned long dwDataRate;
+ unsigned long dwMaxDataRate;
+ unsigned char bNumDataRatesSupported;
+ unsigned long dwMaxIFSD;
+ unsigned long dwSynchProtocols;
+ unsigned long dwMechanical;
+ unsigned long dwFeatures;
+ unsigned long dwMaxCCIDMessageLength;
+ unsigned char bClassGetResponse;
+ unsigned char bClassEnvelope;
+ unsigned short wLcdLayout;
+ unsigned char bPINSupport;
+ unsigned char bMaxCCIDBusySlots;
+} __packed;
+#endif
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 2ee6632..a2251fe 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -155,7 +155,7 @@
enum usb_mode_type default_mode;
enum msm_usb_phy_type phy_type;
void (*setup_gpio)(enum usb_otg_state state);
- char *pclk_src_name;
+ const char *pclk_src_name;
int pmic_id_irq;
bool mhl_enable;
};
@@ -189,6 +189,7 @@
* connected.
* @mA_port: The amount of current drawn by the attached B-device.
* @id_timer: The timer used for polling ID line to detect ACA states.
+ * @xo_handle: TCXO buffer handle
*/
struct msm_otg {
struct otg_transceiver otg;
@@ -220,6 +221,7 @@
unsigned mA_port;
struct timer_list id_timer;
unsigned long caps;
+ struct msm_xo_voter *xo_handle;
/*
* Allowing PHY power collpase turns off the HSUSB 3.3v and 1.8v
* analog regulators while going to low power mode.
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index 9cb8356..fcd91da 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -51,6 +51,8 @@
#define ASYNC_INTR_CTRL (1 << 29) /* Enable async interrupt */
#define ULPI_STP_CTRL (1 << 30) /* Block communication with PHY */
#define PHY_RETEN (1 << 1) /* PHY retention enable/disable */
+#define PHY_IDHV_INTEN (1 << 8) /* PHY ID HV interrupt */
+#define PHY_OTGSESSVLDHV_INTEN (1 << 9) /* PHY Session Valid HV int. */
/* OTG definitions */
#define OTGSC_INTSTS_MASK (0x7f << 16)
diff --git a/include/linux/usb/otg_id.h b/include/linux/usb/otg_id.h
index 46a4463..f9f5189 100644
--- a/include/linux/usb/otg_id.h
+++ b/include/linux/usb/otg_id.h
@@ -52,5 +52,7 @@
void otg_id_unregister_notifier(struct otg_id_notifier_block *otg_id_nb);
void otg_id_notify(void);
+int otg_id_suspend(void);
+void otg_id_resume(void);
#endif /* __LINUX_USB_OTG_ID_H */
diff --git a/include/linux/wakelock.h b/include/linux/wakelock.h
old mode 100755
new mode 100644
index a096d24..024b913
--- a/include/linux/wakelock.h
+++ b/include/linux/wakelock.h
@@ -33,7 +33,6 @@
};
struct wake_lock {
-#ifdef CONFIG_HAS_WAKELOCK
struct list_head link;
int flags;
const char *name;
@@ -49,7 +48,6 @@
ktime_t last_time;
} stat;
#endif
-#endif
};
#ifdef CONFIG_HAS_WAKELOCK
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index 17e7ccc..3f6542c 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -47,6 +47,7 @@
unsigned encountered_congestion:1; /* An output: a queue is full */
unsigned for_kupdate:1; /* A kupdate writeback */
unsigned for_background:1; /* A background writeback */
+ unsigned tagged_writepages:1; /* tag-and-write to avoid livelock */
unsigned for_reclaim:1; /* Invoked from the page allocator */
unsigned range_cyclic:1; /* range_start is cyclic */
unsigned more_io:1; /* more io to be dispatched */
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 65ca534..4d5d697 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -156,6 +156,9 @@
#define MSM_CAM_IOCTL_RELEASE_FREE_FRAME \
_IOR(MSM_CAM_IOCTL_MAGIC, 46, struct msm_cam_evt_divert_frame *)
+#define MSM_CAM_IOCTL_PICT_PP_DIVERT_DONE \
+ _IOR(MSM_CAM_IOCTL_MAGIC, 47, struct msm_pp_frame *)
+
struct msm_mctl_pp_cmd {
int32_t id;
uint16_t length;
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index b4e1981..4694b78 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -203,7 +203,6 @@
#define MCTL_CMD_GET_FRAME_BUFFER 1 /* reserve a free frame buffer */
#define MCTL_CMD_PUT_FRAME_BUFFER 2 /* return the free frame buffer */
#define MCTL_CMD_DIVERT_FRAME_PP_PATH 3 /* divert frame for pp */
-#define MCTL_CMD_DIVERT_FRAME_PP_DONE 4 /* pp done. buf send to app */
/* event typese sending to MCTL PP module */
#define MCTL_PP_EVENT_NOTUSED 0
@@ -252,6 +251,7 @@
};
struct msm_mctl_pp_divert_pp {
int path;
+ int enable;
};
struct msm_vpe_clock_rate {
uint32_t rate;
diff --git a/include/media/radio-iris.h b/include/media/radio-iris.h
index d9687ba..489c248 100644
--- a/include/media/radio-iris.h
+++ b/include/media/radio-iris.h
@@ -198,6 +198,7 @@
#define HCI_FM_STATION_DBG_PARAM_CMD 12
#define HCI_FM_ENABLE_TRANS_CMD 13
#define HCI_FM_DISABLE_TRANS_CMD 14
+#define HCI_FM_GET_TX_CONFIG 15
/* Defines for FM TX*/
@@ -241,14 +242,6 @@
__u8 rt_data[TX_RT_DATA_LENGTH];
} __packed;
-struct hci_fm_get_trans_conf_rsp {
- __u8 status;
- __u8 emphasis;
- __u8 rds_std;
- __u32 band_low_limit;
- __u32 band_high_limit;
-} __packed;
-
struct hci_fm_mute_mode_req {
__u8 hard_mute;
__u8 soft_mute;
@@ -428,6 +421,10 @@
struct hci_fm_recv_conf_req recv_conf_rsp;
} __packed;
+struct hci_fm_get_trans_conf_rsp {
+ __u8 status;
+ struct hci_fm_trans_conf_req_struct trans_conf_rsp;
+} __packed;
struct hci_fm_sig_threshold_rsp {
__u8 status;
__u8 sig_threshold;
@@ -547,17 +544,18 @@
V4L2_CID_PRIVATE_IRIS_SSBI_POKE,
V4L2_CID_PRIVATE_IRIS_TX_TONE,
V4L2_CID_PRIVATE_IRIS_RDS_GRP_COUNTERS,
- V4L2_CID_PRIVATE_IRIS_SET_NOTCH_FILTER,/*0x8000028*/
- /*0x8000029 is used for tavarua specific ioctl*/
- V4L2_CID_PRIVATE_IRIS_DO_CALIBRATION = 0x800002a,
- V4L2_CID_PRIVATE_IRIS_READ_DEFAULT = 0x00980928,/*using private CIDs
- under userclass*/
+ V4L2_CID_PRIVATE_IRIS_SET_NOTCH_FILTER, /* 0x8000028 */
+ V4L2_CID_PRIVATE_IRIS_SET_AUDIO_PATH, /* TAVARUA specific command */
+ V4L2_CID_PRIVATE_IRIS_DO_CALIBRATION,
+ V4L2_CID_PRIVATE_IRIS_SRCH_ALGORITHM, /* TAVARUA specific command */
+
+ /*using private CIDs under userclass*/
+ V4L2_CID_PRIVATE_IRIS_READ_DEFAULT = 0x00980928,
V4L2_CID_PRIVATE_IRIS_WRITE_DEFAULT,
V4L2_CID_PRIVATE_IRIS_SET_CALIBRATION,
};
-
enum iris_evt_t {
IRIS_EVT_RADIO_READY,
IRIS_EVT_TUNE_SUCC,
@@ -727,13 +725,19 @@
#define RSB_CALIB_SIZE 4
#define CALIB_DATA_OFSET 2
#define CALIB_MODE_OFSET 1
-
#define MAX_CALIB_SIZE 75
-struct hci_fm_set_cal_req {
+struct hci_fm_set_cal_req_proc {
__u8 mode;
- /*Max calibration data size*/
- __u8 data[MAX_CALIB_SIZE];
+ /*Max process calibration data size*/
+ __u8 data[PROCS_CALIB_SIZE];
} __packed;
+
+struct hci_fm_set_cal_req_dc {
+ __u8 mode;
+ /*Max DC calibration data size*/
+ __u8 data[DC_CALIB_SIZE];
+} __packed;
+
struct hci_cc_do_calibration_rsp {
__u8 status;
__u8 mode;
diff --git a/include/media/tavarua.h b/include/media/tavarua.h
index aafa5d0..d40829e 100644
--- a/include/media/tavarua.h
+++ b/include/media/tavarua.h
@@ -41,6 +41,12 @@
#define MPX_DCC_PEEK_MSB_REG3 (0x88)
#define MPX_DCC_PEEK_LSB_REG3 (0xC4)
+#define ON_CHANNEL_TH_MSB (0x0B)
+#define ON_CHANNEL_TH_LSB (0xA8)
+
+#define OFF_CHANNEL_TH_MSB (0x0B)
+#define OFF_CHANNEL_TH_LSB (0xAC)
+
#define ENF_200Khz (1)
#define SRCH200KHZ_OFFSET (7)
#define SRCH_MASK (1 << SRCH200KHZ_OFFSET)
@@ -142,12 +148,20 @@
V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA,
V4L2_CID_PRIVATE_TAVARUA_HLSI,
/*
- * Here We have IOCTl's that are specifici to IRIS
- * (V4L2_CID_PRIVATE_BASE+0x1D--V4L2_CID_PRIVATE_BASE+0x27)
+ * Here we have IOCTl's that are specific to IRIS
+ * (V4L2_CID_PRIVATE_BASE + 0x1E to V4L2_CID_PRIVATE_BASE + 0x27)
*/
V4L2_CID_PRIVATE_TAVARUA_SET_NOTCH_FILTER =
- V4L2_CID_PRIVATE_BASE + 0x28,
- V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH
+ V4L2_CID_PRIVATE_BASE + 0x28, /* IRIS specific command */
+ V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH,
+ V4L2_CID_PRIVATE_TAVARUA_DO_CALIBRATION, /* IRIS specific command */
+ V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM,
+
+ V4L2_CID_PRIVATE_TAVARUA_ON_CHANNEL_THRESHOLD =
+ V4L2_CTRL_CLASS_USER + 0x92B,
+ V4L2_CID_PRIVATE_TAVARUA_OFF_CHANNEL_THRESHOLD =
+ V4L2_CTRL_CLASS_USER + 0x92C
+
};
enum tavarua_buf_t {
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h
index 008711e..32f67c3 100644
--- a/include/net/9p/9p.h
+++ b/include/net/9p/9p.h
@@ -278,6 +278,30 @@
P9_DMSETVTX = 0x00010000,
};
+/* 9p2000.L open flags */
+#define P9_DOTL_RDONLY 00000000
+#define P9_DOTL_WRONLY 00000001
+#define P9_DOTL_RDWR 00000002
+#define P9_DOTL_NOACCESS 00000003
+#define P9_DOTL_CREATE 00000100
+#define P9_DOTL_EXCL 00000200
+#define P9_DOTL_NOCTTY 00000400
+#define P9_DOTL_TRUNC 00001000
+#define P9_DOTL_APPEND 00002000
+#define P9_DOTL_NONBLOCK 00004000
+#define P9_DOTL_DSYNC 00010000
+#define P9_DOTL_FASYNC 00020000
+#define P9_DOTL_DIRECT 00040000
+#define P9_DOTL_LARGEFILE 00100000
+#define P9_DOTL_DIRECTORY 00200000
+#define P9_DOTL_NOFOLLOW 00400000
+#define P9_DOTL_NOATIME 01000000
+#define P9_DOTL_CLOEXEC 02000000
+#define P9_DOTL_SYNC 04000000
+
+/* 9p2000.L at flags */
+#define P9_DOTL_AT_REMOVEDIR 0x200
+
/**
* enum p9_qid_t - QID types
* @P9_QTDIR: directory
@@ -320,6 +344,11 @@
/* Room for readdir header */
#define P9_READDIRHDRSZ 24
+/* 9p2000.L lock type */
+#define P9_LOCK_TYPE_RDLCK 0
+#define P9_LOCK_TYPE_WRLCK 1
+#define P9_LOCK_TYPE_UNLCK 2
+
/**
* struct p9_str - length prefixed string type
* @len: length of the string
diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h
index 53fea37..0a2849a 100644
--- a/include/net/bluetooth/amp.h
+++ b/include/net/bluetooth/amp.h
@@ -45,9 +45,6 @@
__le16 reason;
} __packed;
-#define HCI_A2MP_ID(id) ((id)+0x10) /* convert HCI dev index to AMP ID */
-#define A2MP_HCI_ID(id) ((id)-0x10) /* convert AMP ID to HCI dev index */
-
struct a2mp_discover_req {
__le16 mtu;
__le16 ext_feat;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 74e14fb..ca15ed0 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -240,6 +240,9 @@
rwlock_t adv_entries_lock;
struct timer_list adv_timer;
+ struct timer_list disc_timer;
+ struct timer_list disc_le_timer;
+
struct hci_dev_stats stat;
struct sk_buff_head driver_init;
@@ -573,7 +576,7 @@
{
atomic_inc(&chan->refcnt);
}
-void hci_chan_put(struct hci_chan *chan);
+int hci_chan_put(struct hci_chan *chan);
struct hci_chan *hci_chan_accept(struct hci_conn *hcon,
struct hci_ext_fs *tx_fs,
@@ -1034,6 +1037,7 @@
int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name);
void mgmt_inquiry_started(u16 index);
void mgmt_inquiry_complete_evt(u16 index, u8 status);
+int mgmt_encrypt_change(u16 index, bdaddr_t *bdaddr, u8 status);
/* LE SMP Management interface */
int le_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, void *cp);
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index ce7ecf1..2d3028d 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -228,6 +228,12 @@
__le16 timeout_multiplier;
} __packed;
+#define MGMT_OP_ENCRYPT_LINK 0x0021
+struct mgmt_cp_encrypt_link {
+ bdaddr_t bdaddr;
+ __u8 enable;
+} __packed;
+
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
@@ -329,3 +335,10 @@
bdaddr_t bdaddr;
} __packed;
+#define MGMT_EV_ENCRYPT_CHANGE 0x0016
+struct mgmt_ev_encrypt_change {
+ bdaddr_t bdaddr;
+ __u8 status;
+} __packed;
+
+
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index c033ed0..c39121f 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -463,17 +463,7 @@
return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr));
}
-static __inline__ void ipv6_select_ident(struct frag_hdr *fhdr)
-{
- static u32 ipv6_fragmentation_id = 1;
- static DEFINE_SPINLOCK(ip6_id_lock);
-
- spin_lock_bh(&ip6_id_lock);
- fhdr->identification = htonl(ipv6_fragmentation_id);
- if (++ipv6_fragmentation_id == 0)
- ipv6_fragmentation_id = 1;
- spin_unlock_bh(&ip6_id_lock);
-}
+extern void ipv6_select_ident(struct frag_hdr *fhdr, struct in6_addr *addr);
/*
* Prototypes exported by ipv6
diff --git a/include/net/secure_seq.h b/include/net/secure_seq.h
new file mode 100644
index 0000000..d97f689
--- /dev/null
+++ b/include/net/secure_seq.h
@@ -0,0 +1,20 @@
+#ifndef _NET_SECURE_SEQ
+#define _NET_SECURE_SEQ
+
+#include <linux/types.h>
+
+extern __u32 secure_ip_id(__be32 daddr);
+extern __u32 secure_ipv6_id(const __be32 daddr[4]);
+extern u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport);
+extern u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
+ __be16 dport);
+extern __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
+ __be16 sport, __be16 dport);
+extern __u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr,
+ __be16 sport, __be16 dport);
+extern u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
+ __be16 sport, __be16 dport);
+extern u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
+ __be16 sport, __be16 dport);
+
+#endif /* _NET_SECURE_SEQ */
diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h
index 5271a74..45ce307 100644
--- a/include/net/transp_v6.h
+++ b/include/net/transp_v6.h
@@ -14,6 +14,8 @@
struct flowi6;
+extern void initialize_hashidentrnd(void);
+
/* extension headers */
extern int ipv6_exthdrs_init(void);
extern void ipv6_exthdrs_exit(void);
diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h
new file mode 100644
index 0000000..2fd1604
--- /dev/null
+++ b/include/sound/compress_driver.h
@@ -0,0 +1,150 @@
+/*
+ * compress_driver.h - compress offload driver definations
+ *
+ * Copyright (C) 2011 Intel Corporation
+ * Authors: Vinod Koul <vinod.koul@linux.intel.com>
+ * Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+#ifndef __COMPRESS_DRIVER_H
+#define __COMPRESS_DRIVER_H
+
+#include <sound/compress_offload.h>
+#include <sound/asound.h>
+#include <sound/pcm.h>
+
+struct snd_compr_ops;
+
+/**
+ * struct snd_compr_runtime: runtime stream description
+ * @state: stream state
+ * @ops: pointer to DSP callbacks
+ * @buffer: pointer to kernel buffer, valid only when not in mmap mode or
+ * DSP doesn't implement copy
+ * @buffer_size: size of the above buffer
+ * @fragment_size: size of buffer fragment in bytes
+ * @fragments: number of such fragments
+ * @hw_pointer: offset of last location in buffer where DSP copied data
+ * @app_pointer: offset of last location in buffer where app wrote data
+ * @sleep: poll sleep
+ */
+struct snd_compr_runtime {
+ snd_pcm_state_t state;
+ struct snd_compr_ops *ops;
+ void *buffer;
+ size_t buffer_size;
+ size_t fragment_size;
+ unsigned int fragments;
+ size_t hw_pointer;
+ size_t app_pointer;
+ wait_queue_head_t sleep;
+};
+
+/**
+ * struct snd_compr_stream: compressed stream
+ * @name: device name
+ * @ops: pointer to DSP callbacks
+ * @runtime: pointer to runtime structure
+ * @device: device pointer
+ * @direction: stream direction, playback/recording
+ * @private_data: pointer to DSP private data
+ */
+struct snd_compr_stream {
+ const char *name;
+ struct snd_compr_ops *ops;
+ struct snd_compr_runtime *runtime;
+ struct snd_compr *device;
+ unsigned int direction;
+ void *private_data;
+};
+
+/**
+ * struct snd_compr_ops: compressed path DSP operations
+ * @open: Open the compressed stream
+ * This callback is mandatory and shall keep dsp ready to receive the stream
+ * parameter
+ * @free: Close the compressed stream, mandatory
+ * @set_params: Sets the compressed stream parameters, mandatory
+ * This can be called in during stream creation only to set codec params
+ * and the stream properties
+ * @get_params: retrieve the codec parameters, mandatory
+ * @trigger: Trigger operations like start, pause, resume, drain, stop.
+ * This callback is mandatory
+ * @pointer: Retrieve current h/w pointer information. Mandatory
+ * @copy: Copy the compressed data to/from userspace, Optional
+ * Can't be implemented if DSP supports mmap
+ * @mmap: DSP mmap method to mmap DSP memory
+ * @ack: Ack for DSP when data is written to audio buffer, Optional
+ * Not valid if copy is implemented
+ * @get_caps: Retrieve DSP capabilities, mandatory
+ * @get_codec_caps: Retrieve capabilities for a specific codec, mandatory
+ */
+struct snd_compr_ops {
+ int (*open)(struct snd_compr_stream *stream);
+ int (*free)(struct snd_compr_stream *stream);
+ int (*set_params)(struct snd_compr_stream *stream,
+ struct snd_compr_params *params);
+ int (*get_params)(struct snd_compr_stream *stream,
+ struct snd_compr_params *params);
+ int (*trigger)(struct snd_compr_stream *stream, int cmd);
+ int (*pointer)(struct snd_compr_stream *stream,
+ struct snd_compr_tstamp *tstamp);
+ int (*copy)(struct snd_compr_stream *stream, const char __user *buf,
+ size_t count);
+ int (*mmap)(struct snd_compr_stream *stream,
+ struct vm_area_struct *vma);
+ int (*ack)(struct snd_compr_stream *stream);
+ int (*get_caps) (struct snd_compr_stream *stream,
+ struct snd_compr_caps *caps);
+ int (*get_codec_caps) (struct snd_compr_stream *stream,
+ struct snd_compr_codec_caps *codec);
+};
+
+/**
+ * struct snd_compr: Compressed device
+ * @name: DSP device name
+ * @dev: Device pointer
+ * @lock: device lock
+ * @ops: pointer to DSP callbacks
+ * @private_data: pointer to DSP pvt data
+ */
+struct snd_compr {
+ const char *name;
+ struct device *dev;
+ struct mutex lock;
+ struct snd_compr_ops *ops;
+ struct list_head list;
+ void *private_data;
+};
+
+/* compress device register APIs */
+int snd_compress_register(struct snd_compr *device);
+int snd_compress_deregister(struct snd_compr *device);
+
+/* dsp driver callback apis
+ * For playback: driver should call snd_compress_fragment_elapsed() to let the
+ * framework know that a fragment has been consumed from the ring buffer
+ * For recording: we may want to know when a frame is available or when
+ * at least one frame is available for userspace, a different
+ * snd_compress_frame_elapsed() callback should be used
+ */
+void snd_compr_fragment_elapsed(struct snd_compr_stream *stream);
+void snd_compr_frame_elapsed(struct snd_compr_stream *stream);
+
+#endif
diff --git a/include/sound/compress_offload.h b/include/sound/compress_offload.h
new file mode 100644
index 0000000..423264d
--- /dev/null
+++ b/include/sound/compress_offload.h
@@ -0,0 +1,137 @@
+/*
+ * compress_offload.h - compress offload header definations
+ *
+ * Copyright (C) 2011 Intel Corporation
+ * Authors: Vinod Koul <vinod.koul@linux.intel.com>
+ * Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+#ifndef __COMPRESS_OFFLOAD_H
+#define __COMPRESS_OFFLOAD_H
+
+#include <linux/types.h>
+/**
+ * struct snd_compressed_buffer:compressed buffer
+ * @fragment_size: size of buffer fragment in bytes
+ * @fragments: number of such fragments
+ */
+struct snd_compressed_buffer {
+ size_t fragment_size;
+ int fragments;
+};
+
+/* */
+struct snd_compr_params {
+ struct snd_compressed_buffer buffer;
+ struct snd_codec codec;
+};
+
+/**
+ * struct snd_compr_tstamp: timestamp descriptor
+ * @copied_bytes: Number of bytes offset in ring buffer to DSP
+ * @copied_total: Total number of bytes copied from ring buffer to DSP
+ * @decoded: Frames decoded by DSP
+ * @rendered: Frames rendered by DSP into a mixer or an audio output
+ * @sampling_rate: sampling rate of audio
+ */
+struct snd_compr_tstamp {
+ size_t copied_bytes;
+ size_t copied_total;
+ size_t decoded;
+ size_t rendered;
+ __u32 sampling_rate;
+};
+
+/**
+ * struct snd_compr_avail: avail descriptor
+ * @avail: Number of bytes available in ring buffer for writing/reading
+ * @tstamp: timestamp infomation
+ */
+struct snd_compr_avail {
+ size_t avail;
+ struct snd_compr_tstamp tstamp;
+};
+
+/**
+ * struct snd_compr_caps: caps descriptor
+ * @codecs: pointer to array of codecs
+ * @min_fragment_size: minimum fragment supported by DSP
+ * @max_fragment_size: maximum fragment supported by DSP
+ * @min_fragments: min fragments supported by DSP
+ * @max_fragments: max fragments supported by DSP
+ * @num_codecs: number of codecs supported
+ * @reserved: reserved field
+ */
+struct snd_compr_caps {
+ __u32 num_codecs;
+ __u32 min_fragment_size;
+ __u32 max_fragment_size;
+ __u32 min_fragments;
+ __u32 max_fragments;
+ __u32 codecs[MAX_NUM_CODECS];
+ __u32 reserved[11];
+};
+
+/**
+ * struct snd_compr_codec_caps: query capability of codec
+ * @codec: codec for which capability is queried
+ * @num_descriptors: number of codec descriptors
+ * @descriptor: array of codec capability descriptor
+ */
+struct snd_compr_codec_caps {
+ __u32 codec;
+ __u32 num_descriptors;
+ struct snd_codec_desc descriptor[MAX_NUM_CODEC_DESCRIPTORS];
+};
+
+/**
+ * compress path ioctl definitions
+ * SNDRV_COMPRESS_GET_CAPS: Query capability of DSP
+ * SNDRV_COMPRESS_GET_CODEC_CAPS: Query capability of a codec
+ * SNDRV_COMPRESS_SET_PARAMS: Set codec and stream parameters
+ * Note: only codec params can be changed runtime and stream params cant be
+ * SNDRV_COMPRESS_GET_PARAMS: Query codec and stream params
+ * SNDRV_COMPRESS_TSTAMP: get the current timestamp value
+ * SNDRV_COMPRESS_AVAIL: get the current buffer avail value.
+ * This also queries the tstamp properties
+ * SNDRV_COMPRESS_PAUSE: Pause the running stream
+ * SNDRV_COMPRESS_RESUME: resume a paused stream
+ * SNDRV_COMPRESS_START: Start a stream
+ * SNDRV_COMPRESS_STOP: stop a running stream, discarding ring buffer content
+ * and the buffers currently with DSP
+ * SNDRV_COMPRESS_DRAIN: Play till end of buffers and stop after that
+ */
+#define SNDRV_COMPRESS_GET_CAPS _IOWR('C', 0x00, struct snd_compr_caps *)
+#define SNDRV_COMPRESS_GET_CODEC_CAPS _IOWR('C', 0x01, struct snd_compr_codec_caps *)
+#define SNDRV_COMPRESS_SET_PARAMS _IOW('C', 0x02, struct snd_compr_params *)
+#define SNDRV_COMPRESS_GET_PARAMS _IOR('C', 0x03, struct snd_compr_params *)
+#define SNDRV_COMPRESS_TSTAMP _IOR('C', 0x10, struct snd_compr_tstamp *)
+#define SNDRV_COMPRESS_AVAIL _IOR('C', 0x11, struct snd_compr_avail *)
+#define SNDRV_COMPRESS_PAUSE _IO('C', 0x20)
+#define SNDRV_COMPRESS_RESUME _IO('C', 0x21)
+#define SNDRV_COMPRESS_START _IO('C', 0x22)
+#define SNDRV_COMPRESS_STOP _IO('C', 0x23)
+#define SNDRV_COMPRESS_DRAIN _IO('C', 0x24)
+/*
+ * TODO
+ * 1. add mmap support
+ *
+ */
+#define SND_COMPR_TRIGGER_DRAIN 7 /*FIXME move this to pcm.h */
+#endif
diff --git a/include/sound/snd_compress_params.h b/include/sound/snd_compress_params.h
new file mode 100644
index 0000000..5080e13
--- /dev/null
+++ b/include/sound/snd_compress_params.h
@@ -0,0 +1,392 @@
+/*
+ * snd_compress_params.h - codec types and parameters for compressed data
+ * streaming interface
+ *
+ * Copyright (C) 2011 Intel Corporation
+ * Authors: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+ * Vinod Koul <vinod.koul@linux.intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * The definitions in this file are derived from the OpenMAX AL version 1.1
+ * and OpenMAX IL v 1.1.2 header files which contain the copyright notice below.
+ *
+ * Copyright (c) 2007-2010 The Khronos Group Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and/or associated documentation files (the
+ * "Materials "), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ */
+
+
+/* AUDIO CODECS SUPPORTED */
+#define MAX_NUM_CODECS 32
+#define MAX_NUM_CODEC_DESCRIPTORS 32
+#define MAX_NUM_BITRATES 32
+
+/* Codecs are listed linearly to allow for extensibility */
+#define SND_AUDIOCODEC_PCM ((__u32) 0x00000001)
+#define SND_AUDIOCODEC_MP3 ((__u32) 0x00000002)
+#define SND_AUDIOCODEC_AMR ((__u32) 0x00000003)
+#define SND_AUDIOCODEC_AMRWB ((__u32) 0x00000004)
+#define SND_AUDIOCODEC_AMRWBPLUS ((__u32) 0x00000005)
+#define SND_AUDIOCODEC_AAC ((__u32) 0x00000006)
+#define SND_AUDIOCODEC_WMA ((__u32) 0x00000007)
+#define SND_AUDIOCODEC_REAL ((__u32) 0x00000008)
+#define SND_AUDIOCODEC_VORBIS ((__u32) 0x00000009)
+#define SND_AUDIOCODEC_FLAC ((__u32) 0x0000000A)
+#define SND_AUDIOCODEC_IEC61937 ((__u32) 0x0000000B)
+#define SND_AUDIOCODEC_G723_1 ((__u32) 0x0000000C)
+#define SND_AUDIOCODEC_G729 ((__u32) 0x0000000D)
+
+/*
+ * Profile and modes are listed with bit masks. This allows for a
+ * more compact representation of fields that will not evolve
+ * (in contrast to the list of codecs)
+ */
+
+#define SND_AUDIOPROFILE_PCM ((__u32) 0x00000001)
+
+/* MP3 modes are only useful for encoders */
+#define SND_AUDIOCHANMODE_MP3_MONO ((__u32) 0x00000001)
+#define SND_AUDIOCHANMODE_MP3_STEREO ((__u32) 0x00000002)
+#define SND_AUDIOCHANMODE_MP3_JOINTSTEREO ((__u32) 0x00000004)
+#define SND_AUDIOCHANMODE_MP3_DUAL ((__u32) 0x00000008)
+
+#define SND_AUDIOPROFILE_AMR ((__u32) 0x00000001)
+
+/* AMR modes are only useful for encoders */
+#define SND_AUDIOMODE_AMR_DTX_OFF ((__u32) 0x00000001)
+#define SND_AUDIOMODE_AMR_VAD1 ((__u32) 0x00000002)
+#define SND_AUDIOMODE_AMR_VAD2 ((__u32) 0x00000004)
+
+#define SND_AUDIOSTREAMFORMAT_UNDEFINED ((__u32) 0x00000000)
+#define SND_AUDIOSTREAMFORMAT_CONFORMANCE ((__u32) 0x00000001)
+#define SND_AUDIOSTREAMFORMAT_IF1 ((__u32) 0x00000002)
+#define SND_AUDIOSTREAMFORMAT_IF2 ((__u32) 0x00000004)
+#define SND_AUDIOSTREAMFORMAT_FSF ((__u32) 0x00000008)
+#define SND_AUDIOSTREAMFORMAT_RTPPAYLOAD ((__u32) 0x00000010)
+#define SND_AUDIOSTREAMFORMAT_ITU ((__u32) 0x00000020)
+
+#define SND_AUDIOPROFILE_AMRWB ((__u32) 0x00000001)
+
+/* AMRWB modes are only useful for encoders */
+#define SND_AUDIOMODE_AMRWB_DTX_OFF ((__u32) 0x00000001)
+#define SND_AUDIOMODE_AMRWB_VAD1 ((__u32) 0x00000002)
+#define SND_AUDIOMODE_AMRWB_VAD2 ((__u32) 0x00000004)
+
+#define SND_AUDIOPROFILE_AMRWBPLUS ((__u32) 0x00000001)
+
+#define SND_AUDIOPROFILE_AAC ((__u32) 0x00000001)
+
+/* AAC modes are required for encoders and decoders */
+#define SND_AUDIOMODE_AAC_MAIN ((__u32) 0x00000001)
+#define SND_AUDIOMODE_AAC_LC ((__u32) 0x00000002)
+#define SND_AUDIOMODE_AAC_SSR ((__u32) 0x00000004)
+#define SND_AUDIOMODE_AAC_LTP ((__u32) 0x00000008)
+#define SND_AUDIOMODE_AAC_HE ((__u32) 0x00000010)
+#define SND_AUDIOMODE_AAC_SCALABLE ((__u32) 0x00000020)
+#define SND_AUDIOMODE_AAC_ERLC ((__u32) 0x00000040)
+#define SND_AUDIOMODE_AAC_LD ((__u32) 0x00000080)
+#define SND_AUDIOMODE_AAC_HE_PS ((__u32) 0x00000100)
+#define SND_AUDIOMODE_AAC_HE_MPS ((__u32) 0x00000200)
+
+/* AAC formats are required for encoders and decoders */
+#define SND_AUDIOSTREAMFORMAT_MP2ADTS ((__u32) 0x00000001)
+#define SND_AUDIOSTREAMFORMAT_MP4ADTS ((__u32) 0x00000002)
+#define SND_AUDIOSTREAMFORMAT_MP4LOAS ((__u32) 0x00000004)
+#define SND_AUDIOSTREAMFORMAT_MP4LATM ((__u32) 0x00000008)
+#define SND_AUDIOSTREAMFORMAT_ADIF ((__u32) 0x00000010)
+#define SND_AUDIOSTREAMFORMAT_MP4FF ((__u32) 0x00000020)
+#define SND_AUDIOSTREAMFORMAT_RAW ((__u32) 0x00000040)
+
+#define SND_AUDIOPROFILE_WMA7 ((__u32) 0x00000001)
+#define SND_AUDIOPROFILE_WMA8 ((__u32) 0x00000002)
+#define SND_AUDIOPROFILE_WMA9 ((__u32) 0x00000004)
+#define SND_AUDIOPROFILE_WMA10 ((__u32) 0x00000008)
+
+#define SND_AUDIOMODE_WMA_LEVEL1 ((__u32) 0x00000001)
+#define SND_AUDIOMODE_WMA_LEVEL2 ((__u32) 0x00000002)
+#define SND_AUDIOMODE_WMA_LEVEL3 ((__u32) 0x00000004)
+#define SND_AUDIOMODE_WMA_LEVEL4 ((__u32) 0x00000008)
+#define SND_AUDIOMODE_WMAPRO_LEVELM0 ((__u32) 0x00000010)
+#define SND_AUDIOMODE_WMAPRO_LEVELM1 ((__u32) 0x00000020)
+#define SND_AUDIOMODE_WMAPRO_LEVELM2 ((__u32) 0x00000040)
+#define SND_AUDIOMODE_WMAPRO_LEVELM3 ((__u32) 0x00000080)
+
+#define SND_AUDIOSTREAMFORMAT_WMA_ASF ((__u32) 0x00000001)
+/*
+ * Some implementations strip the ASF header and only send ASF packets
+ * to the DSP
+ */
+#define SND_AUDIOSTREAMFORMAT_WMA_NOASF_HDR ((__u32) 0x00000002)
+
+#define SND_AUDIOPROFILE_REALAUDIO ((__u32) 0x00000001)
+
+#define SND_AUDIOMODE_REALAUDIO_G2 ((__u32) 0x00000001)
+#define SND_AUDIOMODE_REALAUDIO_8 ((__u32) 0x00000002)
+#define SND_AUDIOMODE_REALAUDIO_10 ((__u32) 0x00000004)
+#define SND_AUDIOMODE_REALAUDIO_SURROUND ((__u32) 0x00000008)
+
+#define SND_AUDIOPROFILE_VORBIS ((__u32) 0x00000001)
+
+#define SND_AUDIOMODE_VORBIS ((__u32) 0x00000001)
+
+#define SND_AUDIOPROFILE_FLAC ((__u32) 0x00000001)
+
+/*
+ * Define quality levels for FLAC encoders, from LEVEL0 (fast)
+ * to LEVEL8 (best)
+ */
+#define SND_AUDIOMODE_FLAC_LEVEL0 ((__u32) 0x00000001)
+#define SND_AUDIOMODE_FLAC_LEVEL1 ((__u32) 0x00000002)
+#define SND_AUDIOMODE_FLAC_LEVEL2 ((__u32) 0x00000004)
+#define SND_AUDIOMODE_FLAC_LEVEL3 ((__u32) 0x00000008)
+#define SND_AUDIOMODE_FLAC_LEVEL4 ((__u32) 0x00000010)
+#define SND_AUDIOMODE_FLAC_LEVEL5 ((__u32) 0x00000020)
+#define SND_AUDIOMODE_FLAC_LEVEL6 ((__u32) 0x00000040)
+#define SND_AUDIOMODE_FLAC_LEVEL7 ((__u32) 0x00000080)
+#define SND_AUDIOMODE_FLAC_LEVEL8 ((__u32) 0x00000100)
+
+#define SND_AUDIOSTREAMFORMAT_FLAC ((__u32) 0x00000001)
+#define SND_AUDIOSTREAMFORMAT_FLAC_OGG ((__u32) 0x00000002)
+
+/* IEC61937 payloads without CUVP and preambles */
+#define SND_AUDIOPROFILE_IEC61937 ((__u32) 0x00000001)
+/* IEC61937 with S/PDIF preambles+CUVP bits in 32-bit containers */
+#define SND_AUDIOPROFILE_IEC61937_SPDIF ((__u32) 0x00000002)
+
+/*
+ * IEC modes are mandatory for decoders. Format autodetection
+ * will only happen on the DSP side with mode 0. The PCM mode should
+ * not be used, the PCM codec should be used instead.
+ */
+#define SND_AUDIOMODE_IEC_REF_STREAM_HEADER ((__u32) 0x00000000)
+#define SND_AUDIOMODE_IEC_LPCM ((__u32) 0x00000001)
+#define SND_AUDIOMODE_IEC_AC3 ((__u32) 0x00000002)
+#define SND_AUDIOMODE_IEC_MPEG1 ((__u32) 0x00000004)
+#define SND_AUDIOMODE_IEC_MP3 ((__u32) 0x00000008)
+#define SND_AUDIOMODE_IEC_MPEG2 ((__u32) 0x00000010)
+#define SND_AUDIOMODE_IEC_AACLC ((__u32) 0x00000020)
+#define SND_AUDIOMODE_IEC_DTS ((__u32) 0x00000040)
+#define SND_AUDIOMODE_IEC_ATRAC ((__u32) 0x00000080)
+#define SND_AUDIOMODE_IEC_SACD ((__u32) 0x00000100)
+#define SND_AUDIOMODE_IEC_EAC3 ((__u32) 0x00000200)
+#define SND_AUDIOMODE_IEC_DTS_HD ((__u32) 0x00000400)
+#define SND_AUDIOMODE_IEC_MLP ((__u32) 0x00000800)
+#define SND_AUDIOMODE_IEC_DST ((__u32) 0x00001000)
+#define SND_AUDIOMODE_IEC_WMAPRO ((__u32) 0x00002000)
+#define SND_AUDIOMODE_IEC_REF_CXT ((__u32) 0x00004000)
+#define SND_AUDIOMODE_IEC_HE_AAC ((__u32) 0x00008000)
+#define SND_AUDIOMODE_IEC_HE_AAC2 ((__u32) 0x00010000)
+#define SND_AUDIOMODE_IEC_MPEG_SURROUND ((__u32) 0x00020000)
+
+#define SND_AUDIOPROFILE_G723_1 ((__u32) 0x00000001)
+
+#define SND_AUDIOMODE_G723_1_ANNEX_A ((__u32) 0x00000001)
+#define SND_AUDIOMODE_G723_1_ANNEX_B ((__u32) 0x00000002)
+#define SND_AUDIOMODE_G723_1_ANNEX_C ((__u32) 0x00000004)
+
+#define SND_AUDIOPROFILE_G729 ((__u32) 0x00000001)
+
+#define SND_AUDIOMODE_G729_ANNEX_A ((__u32) 0x00000001)
+#define SND_AUDIOMODE_G729_ANNEX_B ((__u32) 0x00000002)
+
+/* <FIXME: multichannel encoders aren't supported for now. Would need
+ an additional definition of channel arrangement> */
+
+/* VBR/CBR definitions */
+#define SND_RATECONTROLMODE_CONSTANTBITRATE ((__u32) 0x00000001)
+#define SND_RATECONTROLMODE_VARIABLEBITRATE ((__u32) 0x00000002)
+
+/* Encoder options */
+
+struct snd_enc_wma {
+ __u32 super_block_align; /* WMA Type-specific data */
+};
+
+
+/**
+ * struct snd_enc_vorbis
+ * @quality: Sets encoding quality to n, between -1 (low) and 10 (high).
+ * In the default mode of operation, the quality level is 3.
+ * Normal quality range is 0 - 10.
+ * @managed: Boolean. Set bitrate management mode. This turns off the
+ * normal VBR encoding, but allows hard or soft bitrate constraints to be
+ * enforced by the encoder. This mode can be slower, and may also be
+ * lower quality. It is primarily useful for streaming.
+ * @max_bit_rate: Enabled only if managed is TRUE
+ * @min_bit_rate: Enabled only if managed is TRUE
+ * @downmix: Boolean. Downmix input from stereo to mono (has no effect on
+ * non-stereo streams). Useful for lower-bitrate encoding.
+ *
+ * These options were extracted from the OpenMAX IL spec and Gstreamer vorbisenc
+ * properties
+ *
+ * For best quality users should specify VBR mode and set quality levels.
+ */
+
+struct snd_enc_vorbis {
+ int quality;
+ __u32 managed;
+ __u32 max_bit_rate;
+ __u32 min_bit_rate;
+ __u32 downmix;
+};
+
+
+/**
+ * struct snd_enc_real
+ * @quant_bits: number of coupling quantization bits in the stream
+ * @start_region: coupling start region in the stream
+ * @num_regions: number of regions value
+ *
+ * These options were extracted from the OpenMAX IL spec
+ */
+
+struct snd_enc_real {
+ __u32 quant_bits;
+ __u32 start_region;
+ __u32 num_regions;
+};
+
+/**
+ * struct snd_enc_flac
+ * @num: serial number, valid only for OGG formats
+ * needs to be set by application
+ * @gain: Add replay gain tags
+ *
+ * These options were extracted from the FLAC online documentation
+ * at http://flac.sourceforge.net/documentation_tools_flac.html
+ *
+ * To make the API simpler, it is assumed that the user will select quality
+ * profiles. Additional options that affect encoding quality and speed can
+ * be added at a later stage if needed.
+ *
+ * By default the Subset format is used by encoders.
+ *
+ * TAGS such as pictures, etc, cannot be handled by an offloaded encoder and are
+ * not supported in this API.
+ */
+
+struct snd_enc_flac {
+ __u32 num;
+ __u32 gain;
+};
+
+struct snd_enc_generic {
+ __u32 bw; /* encoder bandwidth */
+ int reserved[15];
+};
+
+union snd_codec_options {
+ struct snd_enc_wma wma;
+ struct snd_enc_vorbis vorbis;
+ struct snd_enc_real real;
+ struct snd_enc_flac flac;
+ struct snd_enc_generic generic;
+};
+
+/** struct snd_codec_desc - description of codec capabilities
+ * @max_ch: Maximum number of audio channels
+ * @sample_rates: Sampling rates in Hz, use SNDRV_PCM_RATE_xxx for this
+ * @bit_rate: Indexed array containing supported bit rates
+ * @num_bitrates: Number of valid values in bit_rate array
+ * @rate_control: value is specified by SND_RATECONTROLMODE defines.
+ * @profiles: Supported profiles. See SND_AUDIOPROFILE defines.
+ * @modes: Supported modes. See SND_AUDIOMODE defines
+ * @formats: Supported formats. See SND_AUDIOSTREAMFORMAT defines
+ * @reserved: reserved for future use
+ *
+ * This structure provides a scalar value for profiles, modes and stream
+ * format fields.
+ * If an implementation supports multiple combinations, they will be listed as
+ * codecs with different descriptors, for example there would be 2 descriptors
+ * for AAC-RAW and AAC-ADTS.
+ * This entails some redundancy but makes it easier to avoid invalid
+ * configurations.
+ *
+ */
+
+struct snd_codec_desc {
+ __u32 max_ch;
+ __u32 sample_rates;
+ __u32 bit_rate[MAX_NUM_BITRATES];
+ __u32 num_bitrates;
+ __u32 rate_control;
+ __u32 profiles;
+ __u32 modes;
+ __u32 formats;
+ __u32 reserved[16];
+};
+
+/** struct snd_codec
+ * @id: Identifies the supported audio encoder/decoder.
+ * See SND_AUDIOCODEC macros.
+ * @ch_in: Number of input audio channels
+ * @ch_out: Number of output channels. In case of contradiction between
+ * this field and the channelMode field, the channelMode field
+ * overrides.
+ * @sample_rate: Audio sample rate of input data
+ * @bit_rate: Bitrate of encoded data. May be ignored by decoders
+ * @rate_control: Encoding rate control. See SND_RATECONTROLMODE defines.
+ * Encoders may rely on profiles for quality levels.
+ * May be ignored by decoders.
+ * @profile: Mandatory for encoders, can be mandatory for specific
+ * decoders as well. See SND_AUDIOPROFILE defines.
+ * @level: Supported level (Only used by WMA at the moment)
+ * @ch_mode: Channel mode for encoder. See SND_AUDIOCHANMODE defines
+ * @format: Format of encoded bistream. Mandatory when defined.
+ * See SND_AUDIOSTREAMFORMAT defines.
+ * @align: Block alignment in bytes of an audio sample.
+ * Only required for PCM or IEC formats.
+ * @options: encoder-specific settings
+ * @reserved: reserved for future use
+ */
+
+struct snd_codec {
+ __u32 id;
+ __u32 ch_in;
+ __u32 ch_out;
+ __u32 sample_rate;
+ __u32 bit_rate;
+ __u32 rate_control;
+ __u32 profile;
+ __u32 level;
+ __u32 ch_mode;
+ __u32 format;
+ __u32 align;
+ union snd_codec_options options;
+ __u32 reserved[3];
+};
diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h
index 70213b4..6acd9ce 100644
--- a/include/xen/interface/xen.h
+++ b/include/xen/interface/xen.h
@@ -450,6 +450,45 @@
int8_t cmd_line[MAX_GUEST_CMDLINE];
};
+struct dom0_vga_console_info {
+ uint8_t video_type;
+#define XEN_VGATYPE_TEXT_MODE_3 0x03
+#define XEN_VGATYPE_VESA_LFB 0x23
+
+ union {
+ struct {
+ /* Font height, in pixels. */
+ uint16_t font_height;
+ /* Cursor location (column, row). */
+ uint16_t cursor_x, cursor_y;
+ /* Number of rows and columns (dimensions in characters). */
+ uint16_t rows, columns;
+ } text_mode_3;
+
+ struct {
+ /* Width and height, in pixels. */
+ uint16_t width, height;
+ /* Bytes per scan line. */
+ uint16_t bytes_per_line;
+ /* Bits per pixel. */
+ uint16_t bits_per_pixel;
+ /* LFB physical address, and size (in units of 64kB). */
+ uint32_t lfb_base;
+ uint32_t lfb_size;
+ /* RGB mask offsets and sizes, as defined by VBE 1.2+ */
+ uint8_t red_pos, red_size;
+ uint8_t green_pos, green_size;
+ uint8_t blue_pos, blue_size;
+ uint8_t rsvd_pos, rsvd_size;
+
+ /* VESA capabilities (offset 0xa, VESA command 0x4f00). */
+ uint32_t gbl_caps;
+ /* Mode attributes (offset 0x0, VESA command 0x4f01). */
+ uint16_t mode_attrs;
+ } vesa_lfb;
+ } u;
+};
+
/* These flags are passed in the 'flags' field of start_info_t. */
#define SIF_PRIVILEGED (1<<0) /* Is the domain privileged? */
#define SIF_INITDOMAIN (1<<1) /* Is this the initial control domain? */
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 14fb6d6..ed049ea 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -113,72 +113,75 @@
{
struct user_struct *u = current_user();
struct inode *inode;
+ int ret = -ENOMEM;
inode = new_inode(sb);
- if (inode) {
- inode->i_ino = get_next_ino();
- inode->i_mode = mode;
- inode->i_uid = current_fsuid();
- inode->i_gid = current_fsgid();
- inode->i_mtime = inode->i_ctime = inode->i_atime =
- CURRENT_TIME;
+ if (!inode)
+ goto err;
- if (S_ISREG(mode)) {
- struct mqueue_inode_info *info;
- struct task_struct *p = current;
- unsigned long mq_bytes, mq_msg_tblsz;
+ inode->i_ino = get_next_ino();
+ inode->i_mode = mode;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
+ inode->i_mtime = inode->i_ctime = inode->i_atime = CURRENT_TIME;
- inode->i_fop = &mqueue_file_operations;
- inode->i_size = FILENT_SIZE;
- /* mqueue specific info */
- info = MQUEUE_I(inode);
- spin_lock_init(&info->lock);
- init_waitqueue_head(&info->wait_q);
- INIT_LIST_HEAD(&info->e_wait_q[0].list);
- INIT_LIST_HEAD(&info->e_wait_q[1].list);
- info->notify_owner = NULL;
- info->qsize = 0;
- info->user = NULL; /* set when all is ok */
- memset(&info->attr, 0, sizeof(info->attr));
- info->attr.mq_maxmsg = ipc_ns->mq_msg_max;
- info->attr.mq_msgsize = ipc_ns->mq_msgsize_max;
- if (attr) {
- info->attr.mq_maxmsg = attr->mq_maxmsg;
- info->attr.mq_msgsize = attr->mq_msgsize;
- }
- mq_msg_tblsz = info->attr.mq_maxmsg * sizeof(struct msg_msg *);
- info->messages = kmalloc(mq_msg_tblsz, GFP_KERNEL);
- if (!info->messages)
- goto out_inode;
+ if (S_ISREG(mode)) {
+ struct mqueue_inode_info *info;
+ struct task_struct *p = current;
+ unsigned long mq_bytes, mq_msg_tblsz;
- mq_bytes = (mq_msg_tblsz +
- (info->attr.mq_maxmsg * info->attr.mq_msgsize));
-
- spin_lock(&mq_lock);
- if (u->mq_bytes + mq_bytes < u->mq_bytes ||
- u->mq_bytes + mq_bytes >
- task_rlimit(p, RLIMIT_MSGQUEUE)) {
- spin_unlock(&mq_lock);
- /* mqueue_evict_inode() releases info->messages */
- goto out_inode;
- }
- u->mq_bytes += mq_bytes;
- spin_unlock(&mq_lock);
-
- /* all is ok */
- info->user = get_uid(u);
- } else if (S_ISDIR(mode)) {
- inc_nlink(inode);
- /* Some things misbehave if size == 0 on a directory */
- inode->i_size = 2 * DIRENT_SIZE;
- inode->i_op = &mqueue_dir_inode_operations;
- inode->i_fop = &simple_dir_operations;
+ inode->i_fop = &mqueue_file_operations;
+ inode->i_size = FILENT_SIZE;
+ /* mqueue specific info */
+ info = MQUEUE_I(inode);
+ spin_lock_init(&info->lock);
+ init_waitqueue_head(&info->wait_q);
+ INIT_LIST_HEAD(&info->e_wait_q[0].list);
+ INIT_LIST_HEAD(&info->e_wait_q[1].list);
+ info->notify_owner = NULL;
+ info->qsize = 0;
+ info->user = NULL; /* set when all is ok */
+ memset(&info->attr, 0, sizeof(info->attr));
+ info->attr.mq_maxmsg = ipc_ns->mq_msg_max;
+ info->attr.mq_msgsize = ipc_ns->mq_msgsize_max;
+ if (attr) {
+ info->attr.mq_maxmsg = attr->mq_maxmsg;
+ info->attr.mq_msgsize = attr->mq_msgsize;
}
+ mq_msg_tblsz = info->attr.mq_maxmsg * sizeof(struct msg_msg *);
+ info->messages = kmalloc(mq_msg_tblsz, GFP_KERNEL);
+ if (!info->messages)
+ goto out_inode;
+
+ mq_bytes = (mq_msg_tblsz +
+ (info->attr.mq_maxmsg * info->attr.mq_msgsize));
+
+ spin_lock(&mq_lock);
+ if (u->mq_bytes + mq_bytes < u->mq_bytes ||
+ u->mq_bytes + mq_bytes > task_rlimit(p, RLIMIT_MSGQUEUE)) {
+ spin_unlock(&mq_lock);
+ /* mqueue_evict_inode() releases info->messages */
+ ret = -EMFILE;
+ goto out_inode;
+ }
+ u->mq_bytes += mq_bytes;
+ spin_unlock(&mq_lock);
+
+ /* all is ok */
+ info->user = get_uid(u);
+ } else if (S_ISDIR(mode)) {
+ inc_nlink(inode);
+ /* Some things misbehave if size == 0 on a directory */
+ inode->i_size = 2 * DIRENT_SIZE;
+ inode->i_op = &mqueue_dir_inode_operations;
+ inode->i_fop = &simple_dir_operations;
}
+
return inode;
out_inode:
iput(inode);
- return NULL;
+err:
+ return ERR_PTR(ret);
}
static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
@@ -194,8 +197,8 @@
inode = mqueue_get_inode(sb, ns, S_IFDIR | S_ISVTX | S_IRWXUGO,
NULL);
- if (!inode) {
- error = -ENOMEM;
+ if (IS_ERR(inode)) {
+ error = PTR_ERR(inode);
goto out;
}
@@ -315,8 +318,8 @@
spin_unlock(&mq_lock);
inode = mqueue_get_inode(dir->i_sb, ipc_ns, mode, attr);
- if (!inode) {
- error = -ENOMEM;
+ if (IS_ERR(inode)) {
+ error = PTR_ERR(inode);
spin_lock(&mq_lock);
ipc_ns->mq_queues_count--;
goto out_unlock;
diff --git a/kernel/Makefile b/kernel/Makefile
index d06467f..63bf7a5 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -101,6 +101,7 @@
obj-$(CONFIG_TRACEPOINTS) += trace/
obj-$(CONFIG_SMP) += sched_cpupri.o
obj-$(CONFIG_IRQ_WORK) += irq_work.o
+obj-$(CONFIG_CPU_PM) += cpu_pm.o
obj-$(CONFIG_PERF_EVENTS) += events/
diff --git a/kernel/cpu_pm.c b/kernel/cpu_pm.c
new file mode 100644
index 0000000..1cd23b8
--- /dev/null
+++ b/kernel/cpu_pm.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Author:
+ * Colin Cross <ccross <at> android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/cpu_pm.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/spinlock.h>
+
+static DEFINE_RWLOCK(cpu_pm_notifier_lock);
+static RAW_NOTIFIER_HEAD(cpu_pm_notifier_chain);
+
+int cpu_pm_register_notifier(struct notifier_block *nb)
+{
+ unsigned long flags;
+ int ret;
+
+ write_lock_irqsave(&cpu_pm_notifier_lock, flags);
+ ret = raw_notifier_chain_register(&cpu_pm_notifier_chain, nb);
+ write_unlock_irqrestore(&cpu_pm_notifier_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cpu_pm_register_notifier);
+
+int cpu_pm_unregister_notifier(struct notifier_block *nb)
+{
+ unsigned long flags;
+ int ret;
+
+ write_lock_irqsave(&cpu_pm_notifier_lock, flags);
+ ret = raw_notifier_chain_unregister(&cpu_pm_notifier_chain, nb);
+ write_unlock_irqrestore(&cpu_pm_notifier_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cpu_pm_unregister_notifier);
+
+static int cpu_pm_notify(enum cpu_pm_event event, int nr_to_call, int *nr_calls)
+{
+ int ret;
+
+ ret = __raw_notifier_call_chain(&cpu_pm_notifier_chain, event, NULL,
+ nr_to_call, nr_calls);
+
+ return notifier_to_errno(ret);
+}
+
+int cpu_pm_enter(void)
+{
+ int nr_calls;
+ int ret = 0;
+
+ read_lock(&cpu_pm_notifier_lock);
+ ret = cpu_pm_notify(CPU_PM_ENTER, -1, &nr_calls);
+ if (ret)
+ cpu_pm_notify(CPU_PM_ENTER_FAILED, nr_calls - 1, NULL);
+ read_unlock(&cpu_pm_notifier_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cpu_pm_enter);
+
+int cpu_pm_exit(void)
+{
+ int ret;
+
+ read_lock(&cpu_pm_notifier_lock);
+ ret = cpu_pm_notify(CPU_PM_EXIT, -1, NULL);
+ read_unlock(&cpu_pm_notifier_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cpu_pm_exit);
+
+int cpu_cluster_pm_enter(void)
+{
+ int nr_calls;
+ int ret = 0;
+
+ read_lock(&cpu_pm_notifier_lock);
+ ret = cpu_pm_notify(CPU_CLUSTER_PM_ENTER, -1, &nr_calls);
+ if (ret)
+ cpu_pm_notify(CPU_CLUSTER_PM_ENTER_FAILED, nr_calls - 1, NULL);
+ read_unlock(&cpu_pm_notifier_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cpu_cluster_pm_enter);
+
+int cpu_cluster_pm_exit(void)
+{
+ int ret;
+
+ read_lock(&cpu_pm_notifier_lock);
+ ret = cpu_pm_notify(CPU_CLUSTER_PM_EXIT, -1, NULL);
+ read_unlock(&cpu_pm_notifier_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cpu_cluster_pm_exit);
diff --git a/kernel/futex.c b/kernel/futex.c
index 0a30897..11cbe05 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -218,6 +218,8 @@
* @uaddr: virtual address of the futex
* @fshared: 0 for a PROCESS_PRIVATE futex, 1 for PROCESS_SHARED
* @key: address where result is stored.
+ * @rw: mapping needs to be read/write (values: VERIFY_READ,
+ * VERIFY_WRITE)
*
* Returns a negative error code or 0
* The key words are stored in *key on success.
@@ -229,12 +231,12 @@
* lock_page() might sleep, the caller should not hold a spinlock.
*/
static int
-get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key)
+get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw)
{
unsigned long address = (unsigned long)uaddr;
struct mm_struct *mm = current->mm;
struct page *page, *page_head;
- int err;
+ int err, ro = 0;
/*
* The futex address must be "naturally" aligned.
@@ -262,8 +264,18 @@
again:
err = get_user_pages_fast(address, 1, 1, &page);
+ /*
+ * If write access is not required (eg. FUTEX_WAIT), try
+ * and get read-only access.
+ */
+ if (err == -EFAULT && rw == VERIFY_READ) {
+ err = get_user_pages_fast(address, 1, 0, &page);
+ ro = 1;
+ }
if (err < 0)
return err;
+ else
+ err = 0;
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
page_head = page;
@@ -305,6 +317,13 @@
if (!page_head->mapping) {
unlock_page(page_head);
put_page(page_head);
+ /*
+ * ZERO_PAGE pages don't have a mapping. Avoid a busy loop
+ * trying to find one. RW mapping would have COW'd (and thus
+ * have a mapping) so this page is RO and won't ever change.
+ */
+ if ((page_head == ZERO_PAGE(address)))
+ return -EFAULT;
goto again;
}
@@ -316,6 +335,15 @@
* the object not the particular process.
*/
if (PageAnon(page_head)) {
+ /*
+ * A RO anonymous page will never change and thus doesn't make
+ * sense for futex operations.
+ */
+ if (ro) {
+ err = -EFAULT;
+ goto out;
+ }
+
key->both.offset |= FUT_OFF_MMSHARED; /* ref taken on mm */
key->private.mm = mm;
key->private.address = address;
@@ -327,9 +355,10 @@
get_futex_key_refs(key);
+out:
unlock_page(page_head);
put_page(page_head);
- return 0;
+ return err;
}
static inline void put_futex_key(union futex_key *key)
@@ -940,7 +969,7 @@
if (!bitset)
return -EINVAL;
- ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key);
+ ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, VERIFY_READ);
if (unlikely(ret != 0))
goto out;
@@ -986,10 +1015,10 @@
int ret, op_ret;
retry:
- ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1);
+ ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, VERIFY_READ);
if (unlikely(ret != 0))
goto out;
- ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2);
+ ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2, VERIFY_WRITE);
if (unlikely(ret != 0))
goto out_put_key1;
@@ -1243,10 +1272,11 @@
pi_state = NULL;
}
- ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1);
+ ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, VERIFY_READ);
if (unlikely(ret != 0))
goto out;
- ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2);
+ ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2,
+ requeue_pi ? VERIFY_WRITE : VERIFY_READ);
if (unlikely(ret != 0))
goto out_put_key1;
@@ -1790,7 +1820,7 @@
* while the syscall executes.
*/
retry:
- ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q->key);
+ ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q->key, VERIFY_READ);
if (unlikely(ret != 0))
return ret;
@@ -1941,7 +1971,7 @@
}
retry:
- ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q.key);
+ ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q.key, VERIFY_WRITE);
if (unlikely(ret != 0))
goto out;
@@ -2060,7 +2090,7 @@
if ((uval & FUTEX_TID_MASK) != vpid)
return -EPERM;
- ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key);
+ ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, VERIFY_WRITE);
if (unlikely(ret != 0))
goto out;
@@ -2249,7 +2279,7 @@
debug_rt_mutex_init_waiter(&rt_waiter);
rt_waiter.task = NULL;
- ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2);
+ ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2, VERIFY_WRITE);
if (unlikely(ret != 0))
goto out;
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index a9205e3..2043c08 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -885,10 +885,13 @@
struct hrtimer_clock_base *base,
unsigned long newstate, int reprogram)
{
+ struct timerqueue_node *next_timer;
if (!(timer->state & HRTIMER_STATE_ENQUEUED))
goto out;
- if (&timer->node == timerqueue_getnext(&base->active)) {
+ next_timer = timerqueue_getnext(&base->active);
+ timerqueue_del(&base->active, &timer->node);
+ if (&timer->node == next_timer) {
#ifdef CONFIG_HIGH_RES_TIMERS
/* Reprogram the clock event device. if enabled */
if (reprogram && hrtimer_hres_active()) {
@@ -901,7 +904,6 @@
}
#endif
}
- timerqueue_del(&base->active, &timer->node);
if (!timerqueue_getnext(&base->active))
base->cpu_base->active_bases &= ~(1 << base->index);
out:
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 45e149c..2adc6b5 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -178,7 +178,7 @@
desc->depth = 1;
if (desc->irq_data.chip->irq_shutdown)
desc->irq_data.chip->irq_shutdown(&desc->irq_data);
- if (desc->irq_data.chip->irq_disable)
+ else if (desc->irq_data.chip->irq_disable)
desc->irq_data.chip->irq_disable(&desc->irq_data);
else
desc->irq_data.chip->irq_mask(&desc->irq_data);
diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c
index 3a2cab4..e38544d 100644
--- a/kernel/irq/generic-chip.c
+++ b/kernel/irq/generic-chip.c
@@ -246,7 +246,7 @@
gc->mask_cache = irq_reg_readl(gc->reg_base + ct->regs.mask);
for (i = gc->irq_base; msk; msk >>= 1, i++) {
- if (!msk & 0x01)
+ if (!(msk & 0x01))
continue;
if (flags & IRQ_GC_INIT_NESTED_LOCK)
@@ -301,7 +301,7 @@
raw_spin_unlock(&gc_lock);
for (; msk; msk >>= 1, i++) {
- if (!msk & 0x01)
+ if (!(msk & 0x01))
continue;
/* Remove handler first. That will mask the irq line */
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c
index 58f405b..640ded8 100644
--- a/kernel/posix-cpu-timers.c
+++ b/kernel/posix-cpu-timers.c
@@ -250,7 +250,7 @@
do {
times->utime = cputime_add(times->utime, t->utime);
times->stime = cputime_add(times->stime, t->stime);
- times->sum_exec_runtime += t->se.sum_exec_runtime;
+ times->sum_exec_runtime += task_sched_runtime(t);
} while_each_thread(tsk, t);
out:
rcu_read_unlock();
@@ -274,9 +274,7 @@
struct task_cputime sum;
unsigned long flags;
- spin_lock_irqsave(&cputimer->lock, flags);
if (!cputimer->running) {
- cputimer->running = 1;
/*
* The POSIX timer interface allows for absolute time expiry
* values through the TIMER_ABSTIME flag, therefore we have
@@ -284,8 +282,11 @@
* it.
*/
thread_group_cputime(tsk, &sum);
+ spin_lock_irqsave(&cputimer->lock, flags);
+ cputimer->running = 1;
update_gt_cputime(&cputimer->cputime, &sum);
- }
+ } else
+ spin_lock_irqsave(&cputimer->lock, flags);
*times = cputimer->cputime;
spin_unlock_irqrestore(&cputimer->lock, flags);
}
@@ -312,7 +313,8 @@
cpu->cpu = cputime.utime;
break;
case CPUCLOCK_SCHED:
- cpu->sched = thread_group_sched_runtime(p);
+ thread_group_cputime(p, &cputime);
+ cpu->sched = cputime.sum_exec_runtime;
break;
}
return 0;
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index b90fb99..ac4641e 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -24,6 +24,10 @@
config HAS_EARLYSUSPEND
bool
+config CPU_PM
+ def_bool y
+ depends on SUSPEND || CPU_IDLE
+
config WAKELOCK
bool "Wake lock"
depends on PM && RTC_CLASS
diff --git a/kernel/power/earlysuspend.c b/kernel/power/earlysuspend.c
index b15f02e..5a6b2fa 100644
--- a/kernel/power/earlysuspend.c
+++ b/kernel/power/earlysuspend.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/rtc.h>
-#include <linux/syscalls.h> /* sys_sync */
#include <linux/wakelock.h>
#include <linux/workqueue.h>
@@ -103,10 +102,7 @@
}
mutex_unlock(&early_suspend_lock);
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("early_suspend: sync\n");
-
- sys_sync();
+ suspend_sys_sync_queue();
abort:
spin_lock_irqsave(&state_lock, irqflags);
if (state == SUSPEND_REQUESTED_AND_SUSPENDED)
diff --git a/kernel/power/power.h b/kernel/power/power.h
index b6b9006..2d57e79 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -251,6 +251,11 @@
extern struct workqueue_struct *suspend_work_queue;
extern struct wake_lock main_wake_lock;
extern suspend_state_t requested_suspend_state;
+extern void suspend_sys_sync_queue(void);
+extern int suspend_sys_sync_wait(void);
+#else
+static inline void suspend_sys_sync_queue(void) {}
+static inline int suspend_sys_sync_wait(void) { return 0; }
#endif
#ifdef CONFIG_USER_WAKELOCK
diff --git a/kernel/power/process.c b/kernel/power/process.c
index 31338cd..6c8c925 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -17,6 +17,7 @@
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/wakelock.h>
+#include "power.h"
/*
* Timeout for stopping processes
@@ -158,6 +159,10 @@
goto Exit;
printk("done.\n");
+ error = suspend_sys_sync_wait();
+ if (error)
+ goto Exit;
+
printk("Freezing remaining freezable tasks ... ");
error = try_to_freeze_tasks(false);
if (error)
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 6799c42..9046443 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -276,7 +276,7 @@
if (!mutex_trylock(&pm_mutex))
return -EBUSY;
- sys_sync();
+ suspend_sys_sync_queue();
pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
error = suspend_prepare();
diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c
index 892e3ec..2583856 100644
--- a/kernel/power/wakelock.c
+++ b/kernel/power/wakelock.c
@@ -52,6 +52,12 @@
struct wake_lock main_wake_lock;
suspend_state_t requested_suspend_state = PM_SUSPEND_MEM;
static struct wake_lock unknown_wakeup;
+static struct wake_lock suspend_backoff_lock;
+
+#define SUSPEND_BACKOFF_THRESHOLD 10
+#define SUSPEND_BACKOFF_INTERVAL 10000
+
+static unsigned suspend_short_count;
#ifdef CONFIG_WAKELOCK_STAT
static struct wake_lock deleted_wake_locks;
@@ -323,10 +329,18 @@
return 0;
}
+static void suspend_backoff(void)
+{
+ pr_info("suspend: too many immediate wakeups, back off\n");
+ wake_lock_timeout(&suspend_backoff_lock,
+ msecs_to_jiffies(SUSPEND_BACKOFF_INTERVAL));
+}
+
static void suspend(struct work_struct *work)
{
int ret;
int entry_event_num;
+ struct timespec ts_entry, ts_exit;
if (has_wake_lock(WAKE_LOCK_SUSPEND)) {
if (debug_mask & DEBUG_SUSPEND)
@@ -335,20 +349,33 @@
}
entry_event_num = current_event_num;
- sys_sync();
+ suspend_sys_sync_queue();
if (debug_mask & DEBUG_SUSPEND)
pr_info("suspend: enter suspend\n");
+ getnstimeofday(&ts_entry);
ret = pm_suspend(requested_suspend_state);
+ getnstimeofday(&ts_exit);
+
if (debug_mask & DEBUG_EXIT_SUSPEND) {
- struct timespec ts;
struct rtc_time tm;
- getnstimeofday(&ts);
- rtc_time_to_tm(ts.tv_sec, &tm);
+ rtc_time_to_tm(ts_exit.tv_sec, &tm);
pr_info("suspend: exit suspend, ret = %d "
"(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
+ tm.tm_hour, tm.tm_min, tm.tm_sec, ts_exit.tv_nsec);
}
+
+ if (ts_exit.tv_sec - ts_entry.tv_sec <= 1) {
+ ++suspend_short_count;
+
+ if (suspend_short_count == SUSPEND_BACKOFF_THRESHOLD) {
+ suspend_backoff();
+ suspend_short_count = 0;
+ }
+ } else {
+ suspend_short_count = 0;
+ }
+
if (current_event_num == entry_event_num) {
if (debug_mask & DEBUG_SUSPEND)
pr_info("suspend: pm_suspend returned with no event\n");
@@ -615,6 +642,8 @@
wake_lock_init(&main_wake_lock, WAKE_LOCK_SUSPEND, "main");
wake_lock(&main_wake_lock);
wake_lock_init(&unknown_wakeup, WAKE_LOCK_SUSPEND, "unknown_wakeups");
+ wake_lock_init(&suspend_backoff_lock, WAKE_LOCK_SUSPEND,
+ "suspend_backoff");
ret = platform_device_register(&power_device);
if (ret) {
@@ -627,6 +656,14 @@
goto err_platform_driver_register;
}
+ INIT_COMPLETION(suspend_sys_sync_comp);
+ suspend_sys_sync_work_queue =
+ create_singlethread_workqueue("suspend_sys_sync");
+ if (suspend_sys_sync_work_queue == NULL) {
+ ret = -ENOMEM;
+ goto err_suspend_sys_sync_work_queue;
+ }
+
suspend_work_queue = create_singlethread_workqueue("suspend");
if (suspend_work_queue == NULL) {
ret = -ENOMEM;
@@ -640,10 +677,12 @@
return 0;
err_suspend_work_queue:
+err_suspend_sys_sync_work_queue:
platform_driver_unregister(&power_driver);
err_platform_driver_register:
platform_device_unregister(&power_device);
err_platform_device_register:
+ wake_lock_destroy(&suspend_backoff_lock);
wake_lock_destroy(&unknown_wakeup);
wake_lock_destroy(&main_wake_lock);
#ifdef CONFIG_WAKELOCK_STAT
@@ -658,8 +697,10 @@
remove_proc_entry("wakelocks", NULL);
#endif
destroy_workqueue(suspend_work_queue);
+ destroy_workqueue(suspend_sys_sync_work_queue);
platform_driver_unregister(&power_driver);
platform_device_unregister(&power_device);
+ wake_lock_destroy(&suspend_backoff_lock);
wake_lock_destroy(&unknown_wakeup);
wake_lock_destroy(&main_wake_lock);
#ifdef CONFIG_WAKELOCK_STAT
diff --git a/kernel/printk.c b/kernel/printk.c
index bddd32b..b790764 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -1653,7 +1653,7 @@
struct console *con;
for_each_console(con) {
- if (con->flags & CON_BOOT) {
+ if (!keep_bootcon && con->flags & CON_BOOT) {
printk(KERN_INFO "turn off boot console %s%d\n",
con->name, con->index);
unregister_console(con);
diff --git a/kernel/sched.c b/kernel/sched.c
index 8388f03..232c1c0 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -3714,30 +3714,6 @@
}
/*
- * Return sum_exec_runtime for the thread group.
- * In case the task is currently running, return the sum plus current's
- * pending runtime that have not been accounted yet.
- *
- * Note that the thread group might have other running tasks as well,
- * so the return value not includes other pending runtime that other
- * running tasks might have.
- */
-unsigned long long thread_group_sched_runtime(struct task_struct *p)
-{
- struct task_cputime totals;
- unsigned long flags;
- struct rq *rq;
- u64 ns;
-
- rq = task_rq_lock(p, &flags);
- thread_group_cputime(p, &totals);
- ns = totals.sum_exec_runtime + do_task_delta_exec(p, rq);
- task_rq_unlock(rq, p, &flags);
-
- return ns;
-}
-
-/*
* Account user cpu time to a process.
* @p: the process that the cpu time gets accounted to
* @cputime: the cpu time spent in user space since the last update
@@ -4243,9 +4219,9 @@
}
/*
- * schedule() is the main scheduler function.
+ * __schedule() is the main scheduler function.
*/
-asmlinkage void __sched schedule(void)
+static void __sched __schedule(void)
{
struct task_struct *prev, *next;
unsigned long *switch_count;
@@ -4286,16 +4262,6 @@
if (to_wakeup)
try_to_wake_up_local(to_wakeup);
}
-
- /*
- * If we are going to sleep and we have plugged IO
- * queued, make sure to submit it to avoid deadlocks.
- */
- if (blk_needs_flush_plug(prev)) {
- raw_spin_unlock(&rq->lock);
- blk_schedule_flush_plug(prev);
- raw_spin_lock(&rq->lock);
- }
}
switch_count = &prev->nvcsw;
}
@@ -4333,6 +4299,26 @@
if (need_resched())
goto need_resched;
}
+
+static inline void sched_submit_work(struct task_struct *tsk)
+{
+ if (!tsk->state)
+ return;
+ /*
+ * If we are going to sleep and we have plugged IO queued,
+ * make sure to submit it to avoid deadlocks.
+ */
+ if (blk_needs_flush_plug(tsk))
+ blk_schedule_flush_plug(tsk);
+}
+
+asmlinkage void __sched schedule(void)
+{
+ struct task_struct *tsk = current;
+
+ sched_submit_work(tsk);
+ __schedule();
+}
EXPORT_SYMBOL(schedule);
#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
@@ -4406,7 +4392,7 @@
do {
add_preempt_count_notrace(PREEMPT_ACTIVE);
- schedule();
+ __schedule();
sub_preempt_count_notrace(PREEMPT_ACTIVE);
/*
@@ -4434,7 +4420,7 @@
do {
add_preempt_count(PREEMPT_ACTIVE);
local_irq_enable();
- schedule();
+ __schedule();
local_irq_disable();
sub_preempt_count(PREEMPT_ACTIVE);
@@ -5576,7 +5562,7 @@
static void __cond_resched(void)
{
add_preempt_count(PREEMPT_ACTIVE);
- schedule();
+ __schedule();
sub_preempt_count(PREEMPT_ACTIVE);
}
@@ -7432,6 +7418,7 @@
struct sched_domain *sd = *per_cpu_ptr(sdd->sd, j);
if (sd && (sd->flags & SD_OVERLAP))
free_sched_groups(sd->groups, 0);
+ kfree(*per_cpu_ptr(sdd->sd, j));
kfree(*per_cpu_ptr(sdd->sg, j));
kfree(*per_cpu_ptr(sdd->sgp, j));
}
diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c
index 10d0182..17f2319 100644
--- a/kernel/sched_rt.c
+++ b/kernel/sched_rt.c
@@ -1038,7 +1038,7 @@
*/
if (curr && unlikely(rt_task(curr)) &&
(curr->rt.nr_cpus_allowed < 2 ||
- curr->prio < p->prio) &&
+ curr->prio <= p->prio) &&
(p->rt.nr_cpus_allowed > 1)) {
int target = find_lowest_rq(p);
@@ -1569,7 +1569,7 @@
p->rt.nr_cpus_allowed > 1 &&
rt_task(rq->curr) &&
(rq->curr->rt.nr_cpus_allowed < 2 ||
- rq->curr->prio < p->prio))
+ rq->curr->prio <= p->prio))
push_rt_tasks(rq);
}
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
index e3516b2..0cae1cc 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -132,8 +132,8 @@
cpu_stop_queue_work(&per_cpu(cpu_stopper, cpu), work_buf);
}
+DEFINE_MUTEX(stop_cpus_mutex);
/* static data for stop_cpus */
-static DEFINE_MUTEX(stop_cpus_mutex);
static DEFINE_PER_CPU(struct cpu_stop_work, stop_cpus_work);
int __stop_cpus(const struct cpumask *cpumask, cpu_stop_fn_t fn, void *arg)
diff --git a/kernel/sys.c b/kernel/sys.c
index e4128b2..f88dadc 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -38,6 +38,8 @@
#include <linux/fs_struct.h>
#include <linux/gfp.h>
#include <linux/syscore_ops.h>
+#include <linux/version.h>
+#include <linux/ctype.h>
#include <linux/compat.h>
#include <linux/syscalls.h>
@@ -45,6 +47,8 @@
#include <linux/user_namespace.h>
#include <linux/kmsg_dump.h>
+/* Move somewhere else to avoid recompiling? */
+#include <generated/utsrelease.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -1124,6 +1128,34 @@
#define override_architecture(name) 0
#endif
+/*
+ * Work around broken programs that cannot handle "Linux 3.0".
+ * Instead we map 3.x to 2.6.40+x, so e.g. 3.0 would be 2.6.40
+ */
+static int override_release(char __user *release, int len)
+{
+ int ret = 0;
+ char buf[65];
+
+ if (current->personality & UNAME26) {
+ char *rest = UTS_RELEASE;
+ int ndots = 0;
+ unsigned v;
+
+ while (*rest) {
+ if (*rest == '.' && ++ndots >= 3)
+ break;
+ if (!isdigit(*rest) && *rest != '.')
+ break;
+ rest++;
+ }
+ v = ((LINUX_VERSION_CODE >> 8) & 0xff) + 40;
+ snprintf(buf, len, "2.6.%u%s", v, rest);
+ ret = copy_to_user(release, buf, len);
+ }
+ return ret;
+}
+
SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
{
int errno = 0;
@@ -1133,6 +1165,8 @@
errno = -EFAULT;
up_read(&uts_sem);
+ if (!errno && override_release(name->release, sizeof(name->release)))
+ errno = -EFAULT;
if (!errno && override_architecture(name))
errno = -EFAULT;
return errno;
@@ -1154,6 +1188,8 @@
error = -EFAULT;
up_read(&uts_sem);
+ if (!error && override_release(name->release, sizeof(name->release)))
+ error = -EFAULT;
if (!error && override_architecture(name))
error = -EFAULT;
return error;
@@ -1188,6 +1224,8 @@
if (!error && override_architecture(name))
error = -EFAULT;
+ if (!error && override_release(name->release, sizeof(name->release)))
+ error = -EFAULT;
return error ? -EFAULT : 0;
}
#endif
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c
index 59f369f..ea5e1a9 100644
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -441,6 +441,8 @@
static void alarm_timer_get(struct k_itimer *timr,
struct itimerspec *cur_setting)
{
+ memset(cur_setting, 0, sizeof(struct itimerspec));
+
cur_setting->it_interval =
ktime_to_timespec(timr->it.alarmtimer.period);
cur_setting->it_value =
@@ -479,11 +481,17 @@
if (!rtcdev)
return -ENOTSUPP;
- /* Save old values */
- old_setting->it_interval =
- ktime_to_timespec(timr->it.alarmtimer.period);
- old_setting->it_value =
- ktime_to_timespec(timr->it.alarmtimer.node.expires);
+ /*
+ * XXX HACK! Currently we can DOS a system if the interval
+ * period on alarmtimers is too small. Cap the interval here
+ * to 100us and solve this properly in a future patch! -jstultz
+ */
+ if ((new_setting->it_interval.tv_sec == 0) &&
+ (new_setting->it_interval.tv_nsec < 100000))
+ new_setting->it_interval.tv_nsec = 100000;
+
+ if (old_setting)
+ alarm_timer_get(timr, old_setting);
/* If the timer was already set, cancel it */
alarm_cancel(&timr->it.alarmtimer);
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 2480d18..e54ba63 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -646,8 +646,6 @@
next = ktime_add(next, tick_period);
}
local_irq_enable();
-
- printk(KERN_INFO "Switched to NOHz mode on CPU #%d\n", smp_processor_id());
}
/*
@@ -857,10 +855,8 @@
}
#ifdef CONFIG_NO_HZ
- if (tick_nohz_enabled) {
+ if (tick_nohz_enabled)
ts->nohz_mode = NOHZ_MODE_HIGHRES;
- printk(KERN_INFO "Switched to NOHz mode on CPU #%d\n", smp_processor_id());
- }
#endif
}
#endif /* HIGH_RES_TIMERS */
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 908038f..ef9271b 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1744,10 +1744,36 @@
static unsigned long ftrace_update_cnt;
unsigned long ftrace_update_tot_cnt;
+static int ops_traces_mod(struct ftrace_ops *ops)
+{
+ struct ftrace_hash *hash;
+
+ hash = ops->filter_hash;
+ return !!(!hash || !hash->count);
+}
+
static int ftrace_update_code(struct module *mod)
{
struct dyn_ftrace *p;
cycle_t start, stop;
+ unsigned long ref = 0;
+
+ /*
+ * When adding a module, we need to check if tracers are
+ * currently enabled and if they are set to trace all functions.
+ * If they are, we need to enable the module functions as well
+ * as update the reference counts for those function records.
+ */
+ if (mod) {
+ struct ftrace_ops *ops;
+
+ for (ops = ftrace_ops_list;
+ ops != &ftrace_list_end; ops = ops->next) {
+ if (ops->flags & FTRACE_OPS_FL_ENABLED &&
+ ops_traces_mod(ops))
+ ref++;
+ }
+ }
start = ftrace_now(raw_smp_processor_id());
ftrace_update_cnt = 0;
@@ -1760,7 +1786,7 @@
p = ftrace_new_addrs;
ftrace_new_addrs = p->newlist;
- p->flags = 0L;
+ p->flags = ref;
/*
* Do the initial record conversion from mcount jump
@@ -1783,7 +1809,7 @@
* conversion puts the module to the correct state, thus
* passing the ftrace_make_call check.
*/
- if (ftrace_start_up) {
+ if (ftrace_start_up && ref) {
int failed = __ftrace_replace_code(p, 1);
if (failed) {
ftrace_bug(failed, p->ip);
@@ -2407,10 +2433,9 @@
*/
static int
-ftrace_mod_callback(char *func, char *cmd, char *param, int enable)
+ftrace_mod_callback(struct ftrace_hash *hash,
+ char *func, char *cmd, char *param, int enable)
{
- struct ftrace_ops *ops = &global_ops;
- struct ftrace_hash *hash;
char *mod;
int ret = -EINVAL;
@@ -2430,11 +2455,6 @@
if (!strlen(mod))
return ret;
- if (enable)
- hash = ops->filter_hash;
- else
- hash = ops->notrace_hash;
-
ret = ftrace_match_module_records(hash, func, mod);
if (!ret)
ret = -EINVAL;
@@ -2760,7 +2780,7 @@
mutex_lock(&ftrace_cmd_mutex);
list_for_each_entry(p, &ftrace_commands, list) {
if (strcmp(p->name, command) == 0) {
- ret = p->func(func, command, next, enable);
+ ret = p->func(hash, func, command, next, enable);
goto out_unlock;
}
}
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index 8d0e1cc..c7b0c6a 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -324,7 +324,8 @@
}
static int
-ftrace_trace_onoff_callback(char *glob, char *cmd, char *param, int enable)
+ftrace_trace_onoff_callback(struct ftrace_hash *hash,
+ char *glob, char *cmd, char *param, int enable)
{
struct ftrace_probe_ops *ops;
void *count = (void *)-1;
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 0400553..aec02b6 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -3026,8 +3026,13 @@
for_each_cwq_cpu(cpu, wq) {
struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
+ bool drained;
- if (!cwq->nr_active && list_empty(&cwq->delayed_works))
+ spin_lock_irq(&cwq->gcwq->lock);
+ drained = !cwq->nr_active && list_empty(&cwq->delayed_works);
+ spin_unlock_irq(&cwq->gcwq->lock);
+
+ if (drained)
continue;
if (++flush_cnt == 10 ||
diff --git a/lib/Makefile b/lib/Makefile
index d1f8ea2..4a93f55 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -10,7 +10,7 @@
lib-y := ctype.o string.o vsprintf.o cmdline.o \
rbtree.o radix-tree.o dump_stack.o timerqueue.o\
idr.o int_sqrt.o extable.o prio_tree.o \
- sha1.o irq_regs.o reciprocal_div.o argv_split.o \
+ sha1.o md5.o irq_regs.o reciprocal_div.o argv_split.o \
proportions.o prio_heap.o ratelimit.o show_mem.o \
is_single_threaded.o plist.o decompress.o find_next_bit.o memory_alloc.o
diff --git a/lib/md5.c b/lib/md5.c
new file mode 100644
index 0000000..c777180
--- /dev/null
+++ b/lib/md5.c
@@ -0,0 +1,95 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/cryptohash.h>
+
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+#define MD5STEP(f, w, x, y, z, in, s) \
+ (w += f(x, y, z) + in, w = (w<<s | w>>(32-s)) + x)
+
+void md5_transform(__u32 *hash, __u32 const *in)
+{
+ u32 a, b, c, d;
+
+ a = hash[0];
+ b = hash[1];
+ c = hash[2];
+ d = hash[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ hash[0] += a;
+ hash[1] += b;
+ hash[2] += c;
+ hash[3] += d;
+}
+EXPORT_SYMBOL(md5_transform);
diff --git a/lib/xz/xz_dec_bcj.c b/lib/xz/xz_dec_bcj.c
index e51e255..a768e6d 100644
--- a/lib/xz/xz_dec_bcj.c
+++ b/lib/xz/xz_dec_bcj.c
@@ -441,8 +441,12 @@
* next filter in the chain. Apply the BCJ filter on the new data
* in the output buffer. If everything cannot be filtered, copy it
* to temp and rewind the output buffer position accordingly.
+ *
+ * This needs to be always run when temp.size == 0 to handle a special
+ * case where the output buffer is full and the next filter has no
+ * more output coming but hasn't returned XZ_STREAM_END yet.
*/
- if (s->temp.size < b->out_size - b->out_pos) {
+ if (s->temp.size < b->out_size - b->out_pos || s->temp.size == 0) {
out_start = b->out_pos;
memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size);
b->out_pos += s->temp.size;
@@ -465,16 +469,25 @@
s->temp.size = b->out_pos - out_start;
b->out_pos -= s->temp.size;
memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size);
+
+ /*
+ * If there wasn't enough input to the next filter to fill
+ * the output buffer with unfiltered data, there's no point
+ * to try decoding more data to temp.
+ */
+ if (b->out_pos + s->temp.size < b->out_size)
+ return XZ_OK;
}
/*
- * If we have unfiltered data in temp, try to fill by decoding more
- * data from the next filter. Apply the BCJ filter on temp. Then we
- * hopefully can fill the actual output buffer by copying filtered
- * data from temp. A mix of filtered and unfiltered data may be left
- * in temp; it will be taken care on the next call to this function.
+ * We have unfiltered data in temp. If the output buffer isn't full
+ * yet, try to fill the temp buffer by decoding more data from the
+ * next filter. Apply the BCJ filter on temp. Then we hopefully can
+ * fill the actual output buffer by copying filtered data from temp.
+ * A mix of filtered and unfiltered data may be left in temp; it will
+ * be taken care on the next call to this function.
*/
- if (s->temp.size > 0) {
+ if (b->out_pos < b->out_size) {
/* Make b->out{,_pos,_size} temporarily point to s->temp. */
s->out = b->out;
s->out_pos = b->out_pos;
diff --git a/mm/Kconfig b/mm/Kconfig
index 8ca47a5..9f30530 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -136,7 +136,7 @@
bool "Allow for memory hot-add"
depends on SPARSEMEM || X86_64_ACPI_NUMA
depends on HOTPLUG && ARCH_ENABLE_MEMORY_HOTPLUG
- depends on (IA64 || X86 || PPC_BOOK3S_64 || SUPERH || S390)
+ depends on (IA64 || X86 || PPC_BOOK3S_64 || SUPERH || S390 || ARM)
config MEMORY_HOTPLUG_SPARSE
def_bool y
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 8487c49..70ea0df 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -379,6 +379,10 @@
unsigned long pfn = page_to_pfn(page);
totalram_pages++;
+#ifdef CONFIG_FIX_MOVABLE_ZONE
+ if (zone_idx(page_zone(page)) != ZONE_MOVABLE)
+ total_unmovable_pages++;
+#endif
if (pfn >= num_physpages)
num_physpages = pfn + 1;
@@ -753,7 +757,8 @@
hotremove_migrate_alloc(struct page *page, unsigned long private, int **x)
{
/* This should be improooooved!! */
- return alloc_page(GFP_HIGHUSER_MOVABLE);
+ return alloc_page(GFP_HIGHUSER_MOVABLE | __GFP_NORETRY | __GFP_NOWARN |
+ __GFP_NOMEMALLOC);
}
#define NR_OFFLINE_AT_ONCE_PAGES (256)
@@ -957,10 +962,17 @@
/* reset pagetype flags and makes migrate type to be MOVABLE */
undo_isolate_page_range(start_pfn, end_pfn);
/* removal success */
- zone->present_pages -= offlined_pages;
+ if (offlined_pages > zone->present_pages)
+ zone->present_pages = 0;
+ else
+ zone->present_pages -= offlined_pages;
zone->zone_pgdat->node_present_pages -= offlined_pages;
totalram_pages -= offlined_pages;
+#ifdef CONFIG_FIX_MOVABLE_ZONE
+ if (zone_idx(zone) != ZONE_MOVABLE)
+ total_unmovable_pages -= offlined_pages;
+#endif
init_per_zone_wmark_min();
if (!node_present_pages(node)) {
diff --git a/mm/migrate.c b/mm/migrate.c
index 666e4e6..14d0a6a 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -120,10 +120,10 @@
ptep = pte_offset_map(pmd, addr);
- if (!is_swap_pte(*ptep)) {
- pte_unmap(ptep);
- goto out;
- }
+ /*
+ * Peek to check is_swap_pte() before taking ptlock? No, we
+ * can race mremap's move_ptes(), which skips anon_vma lock.
+ */
ptl = pte_lockptr(mm, pmd);
}
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 31f6988..955fe35 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -892,12 +892,12 @@
range_whole = 1;
cycled = 1; /* ignore range_cyclic tests */
}
- if (wbc->sync_mode == WB_SYNC_ALL)
+ if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages)
tag = PAGECACHE_TAG_TOWRITE;
else
tag = PAGECACHE_TAG_DIRTY;
retry:
- if (wbc->sync_mode == WB_SYNC_ALL)
+ if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages)
tag_pages_for_writeback(mapping, index, end);
done_index = index;
while (!done && (index <= end)) {
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 18f239c..60ad5e9 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -96,6 +96,9 @@
unsigned long totalram_pages __read_mostly;
unsigned long totalreserve_pages __read_mostly;
+#ifdef CONFIG_FIX_MOVABLE_ZONE
+unsigned long total_unmovable_pages __read_mostly;
+#endif
int percpu_pagelist_fraction;
gfp_t gfp_allowed_mask __read_mostly = GFP_BOOT_MASK;
@@ -127,6 +130,20 @@
saved_gfp_mask = gfp_allowed_mask;
gfp_allowed_mask &= ~GFP_IOFS;
}
+
+static bool pm_suspending(void)
+{
+ if ((gfp_allowed_mask & GFP_IOFS) == GFP_IOFS)
+ return false;
+ return true;
+}
+
+#else
+
+static bool pm_suspending(void)
+{
+ return false;
+}
#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_HUGETLB_PAGE_SIZE_VARIABLE
@@ -160,6 +177,9 @@
};
EXPORT_SYMBOL(totalram_pages);
+#ifdef CONFIG_FIX_MOVABLE_ZONE
+EXPORT_SYMBOL(total_unmovable_pages);
+#endif
static char * const zone_names[MAX_NR_ZONES] = {
#ifdef CONFIG_ZONE_DMA
@@ -1471,8 +1491,9 @@
static bool __zone_watermark_ok(struct zone *z, int order, unsigned long mark,
int classzone_idx, int alloc_flags, long free_pages)
{
- /* free_pages my go negative - that's OK */
+ /* free_pages may go negative - that's OK */
long min = mark;
+ long lowmem_reserve = z->lowmem_reserve[classzone_idx];
int o;
free_pages -= (1 << order) + 1;
@@ -1481,7 +1502,7 @@
if (alloc_flags & ALLOC_HARDER)
min -= min / 4;
- if (free_pages <= min + z->lowmem_reserve[classzone_idx])
+ if (free_pages <= min + lowmem_reserve)
return false;
for (o = 0; o < order; o++) {
/* At the next order, this order's pages become unavailable */
@@ -1617,6 +1638,21 @@
set_bit(i, zlc->fullzones);
}
+/*
+ * clear all zones full, called after direct reclaim makes progress so that
+ * a zone that was recently full is not skipped over for up to a second
+ */
+static void zlc_clear_zones_full(struct zonelist *zonelist)
+{
+ struct zonelist_cache *zlc; /* cached zonelist speedup info */
+
+ zlc = zonelist->zlcache_ptr;
+ if (!zlc)
+ return;
+
+ bitmap_zero(zlc->fullzones, MAX_ZONES_PER_ZONELIST);
+}
+
#else /* CONFIG_NUMA */
static nodemask_t *zlc_setup(struct zonelist *zonelist, int alloc_flags)
@@ -1633,6 +1669,10 @@
static void zlc_mark_zone_full(struct zonelist *zonelist, struct zoneref *z)
{
}
+
+static void zlc_clear_zones_full(struct zonelist *zonelist)
+{
+}
#endif /* CONFIG_NUMA */
/*
@@ -1665,7 +1705,7 @@
continue;
if ((alloc_flags & ALLOC_CPUSET) &&
!cpuset_zone_allowed_softwall(zone, gfp_mask))
- goto try_next_zone;
+ continue;
BUILD_BUG_ON(ALLOC_NO_WATERMARKS < NR_WMARK);
if (!(alloc_flags & ALLOC_NO_WATERMARKS)) {
@@ -1677,17 +1717,36 @@
classzone_idx, alloc_flags))
goto try_this_zone;
+ if (NUMA_BUILD && !did_zlc_setup && nr_online_nodes > 1) {
+ /*
+ * we do zlc_setup if there are multiple nodes
+ * and before considering the first zone allowed
+ * by the cpuset.
+ */
+ allowednodes = zlc_setup(zonelist, alloc_flags);
+ zlc_active = 1;
+ did_zlc_setup = 1;
+ }
+
if (zone_reclaim_mode == 0)
goto this_zone_full;
+ /*
+ * As we may have just activated ZLC, check if the first
+ * eligible zone has failed zone_reclaim recently.
+ */
+ if (NUMA_BUILD && zlc_active &&
+ !zlc_zone_worth_trying(zonelist, z, allowednodes))
+ continue;
+
ret = zone_reclaim(zone, gfp_mask, order);
switch (ret) {
case ZONE_RECLAIM_NOSCAN:
/* did not scan */
- goto try_next_zone;
+ continue;
case ZONE_RECLAIM_FULL:
/* scanned but unreclaimable */
- goto this_zone_full;
+ continue;
default:
/* did we reclaim enough */
if (!zone_watermark_ok(zone, order, mark,
@@ -1704,16 +1763,6 @@
this_zone_full:
if (NUMA_BUILD)
zlc_mark_zone_full(zonelist, z);
-try_next_zone:
- if (NUMA_BUILD && !did_zlc_setup && nr_online_nodes > 1) {
- /*
- * we do zlc_setup after the first zone is tried but only
- * if there are multiple nodes make it worthwhile
- */
- allowednodes = zlc_setup(zonelist, alloc_flags);
- zlc_active = 1;
- did_zlc_setup = 1;
- }
}
if (unlikely(NUMA_BUILD && page == NULL && zlc_active)) {
@@ -1955,6 +2004,10 @@
if (unlikely(!(*did_some_progress)))
return NULL;
+ /* After successful reclaim, reconsider all zones for allocation */
+ if (NUMA_BUILD)
+ zlc_clear_zones_full(zonelist);
+
retry:
page = get_page_from_freelist(gfp_mask, nodemask, order,
zonelist, high_zoneidx,
@@ -2194,6 +2247,14 @@
goto restart;
}
+
+ /*
+ * Suspend converts GFP_KERNEL to __GFP_WAIT which can
+ * prevent reclaim making forward progress without
+ * invoking OOM. Bail if we are suspending
+ */
+ if (pm_suspending())
+ goto nopage;
}
/* Check if we should retry the allocation */
diff --git a/mm/slub.c b/mm/slub.c
index adf609e..03bc30b 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -27,6 +27,7 @@
#include <linux/memory.h>
#include <linux/math64.h>
#include <linux/fault-inject.h>
+#include <linux/stacktrace.h>
#include <trace/events/kmem.h>
@@ -191,8 +192,12 @@
/*
* Tracking user of a slab.
*/
+#define TRACK_ADDRS_COUNT 16
struct track {
unsigned long addr; /* Called from address */
+#ifdef CONFIG_STACKTRACE
+ unsigned long addrs[TRACK_ADDRS_COUNT]; /* Called from address */
+#endif
int cpu; /* Was running on cpu */
int pid; /* Pid context */
unsigned long when; /* When did the operation occur */
@@ -420,6 +425,24 @@
struct track *p = get_track(s, object, alloc);
if (addr) {
+#ifdef CONFIG_STACKTRACE
+ struct stack_trace trace;
+ int i;
+
+ trace.nr_entries = 0;
+ trace.max_entries = TRACK_ADDRS_COUNT;
+ trace.entries = p->addrs;
+ trace.skip = 3;
+ save_stack_trace(&trace);
+
+ /* See rant in lockdep.c */
+ if (trace.nr_entries != 0 &&
+ trace.entries[trace.nr_entries - 1] == ULONG_MAX)
+ trace.nr_entries--;
+
+ for (i = trace.nr_entries; i < TRACK_ADDRS_COUNT; i++)
+ p->addrs[i] = 0;
+#endif
p->addr = addr;
p->cpu = smp_processor_id();
p->pid = current->pid;
@@ -444,6 +467,16 @@
printk(KERN_ERR "INFO: %s in %pS age=%lu cpu=%u pid=%d\n",
s, (void *)t->addr, jiffies - t->when, t->cpu, t->pid);
+#ifdef CONFIG_STACKTRACE
+ {
+ int i;
+ for (i = 0; i < TRACK_ADDRS_COUNT; i++)
+ if (t->addrs[i])
+ printk(KERN_ERR "\t%pS\n", (void *)t->addrs[i]);
+ else
+ break;
+ }
+#endif
}
static void print_tracking(struct kmem_cache *s, void *object)
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 1d34d75..c33d2ae 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -732,9 +732,10 @@
#define VMAP_BBMAP_BITS_MIN (VMAP_MAX_ALLOC*2)
#define VMAP_MIN(x, y) ((x) < (y) ? (x) : (y)) /* can't use min() */
#define VMAP_MAX(x, y) ((x) > (y) ? (x) : (y)) /* can't use max() */
-#define VMAP_BBMAP_BITS VMAP_MIN(VMAP_BBMAP_BITS_MAX, \
- VMAP_MAX(VMAP_BBMAP_BITS_MIN, \
- VMALLOC_PAGES / NR_CPUS / 16))
+#define VMAP_BBMAP_BITS \
+ VMAP_MIN(VMAP_BBMAP_BITS_MAX, \
+ VMAP_MAX(VMAP_BBMAP_BITS_MIN, \
+ VMALLOC_PAGES / roundup_pow_of_two(NR_CPUS) / 16))
#define VMAP_BLOCK_SIZE (VMAP_BBMAP_BITS * PAGE_SIZE)
@@ -1610,9 +1611,14 @@
struct vm_struct *area;
void *addr;
unsigned long real_size = size;
+#ifdef CONFIG_FIX_MOVABLE_ZONE
+ unsigned long total_pages = total_unmovable_pages;
+#else
+ unsigned long total_pages = totalram_pages;
+#endif
size = PAGE_ALIGN(size);
- if (!size || (size >> PAGE_SHIFT) > totalram_pages)
+ if (!size || (size >> PAGE_SHIFT) > total_pages)
return NULL;
area = __get_vm_area_node(size, align, VM_ALLOC, start, end, node,
@@ -2153,6 +2159,14 @@
return NULL;
}
+ /*
+ * If the allocated address space is passed to a hypercall
+ * before being used then we cannot rely on a page fault to
+ * trigger an update of the page tables. So sync all the page
+ * tables here.
+ */
+ vmalloc_sync_all();
+
return area;
}
EXPORT_SYMBOL_GPL(alloc_vm_area);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index d036e59..6072d74 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1748,6 +1748,7 @@
enum lru_list l;
int noswap = 0;
int force_scan = 0;
+ unsigned long nr_force_scan[2];
anon = zone_nr_lru_pages(zone, sc, LRU_ACTIVE_ANON) +
@@ -1770,6 +1771,8 @@
fraction[0] = 0;
fraction[1] = 1;
denominator = 1;
+ nr_force_scan[0] = 0;
+ nr_force_scan[1] = SWAP_CLUSTER_MAX;
goto out;
}
@@ -1781,6 +1784,8 @@
fraction[0] = 1;
fraction[1] = 0;
denominator = 1;
+ nr_force_scan[0] = SWAP_CLUSTER_MAX;
+ nr_force_scan[1] = 0;
goto out;
}
}
@@ -1829,6 +1834,11 @@
fraction[0] = ap;
fraction[1] = fp;
denominator = ap + fp + 1;
+ if (force_scan) {
+ unsigned long scan = SWAP_CLUSTER_MAX;
+ nr_force_scan[0] = div64_u64(scan * ap, denominator);
+ nr_force_scan[1] = div64_u64(scan * fp, denominator);
+ }
out:
for_each_evictable_lru(l) {
int file = is_file_lru(l);
@@ -1849,12 +1859,8 @@
* memcg, priority drop can cause big latency. So, it's better
* to scan small amount. See may_noscan above.
*/
- if (!scan && force_scan) {
- if (file)
- scan = SWAP_CLUSTER_MAX;
- else if (!noswap)
- scan = SWAP_CLUSTER_MAX;
- }
+ if (!scan && force_scan)
+ scan = nr_force_scan[file];
nr[l] = scan;
}
}
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index fcc6846..27263fb 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -171,6 +171,8 @@
if (unlikely(!skb))
goto err_free;
+ skb_reset_network_header(skb);
+ skb_reset_transport_header(skb);
return skb;
err_free:
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 6e82148..5b4f51d 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -694,7 +694,7 @@
ether_setup(dev);
dev->priv_flags |= IFF_802_1Q_VLAN;
- dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
+ dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);
dev->tx_queue_len = 0;
dev->netdev_ops = &vlan_netdev_ops;
diff --git a/net/9p/client.c b/net/9p/client.c
index 9e3b0e6..5532710 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -280,7 +280,8 @@
* buffer to read the data into */
tag++;
- BUG_ON(tag >= c->max_tag);
+ if(tag >= c->max_tag)
+ return NULL;
row = tag / P9_ROW_MAXTAG;
col = tag % P9_ROW_MAXTAG;
@@ -821,8 +822,8 @@
if (err)
goto destroy_fidpool;
- if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize)
- clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ;
+ if (clnt->msize > clnt->trans_mod->maxsize)
+ clnt->msize = clnt->trans_mod->maxsize;
err = p9_client_version(clnt);
if (err)
@@ -1249,9 +1250,11 @@
P9_DPRINTK(P9_DEBUG_9P, "<<< RCLUNK fid %d\n", fid->fid);
p9_free_req(clnt, req);
- p9_fid_destroy(fid);
-
error:
+ /*
+ * Fid is not valid even after a failed clunk
+ */
+ p9_fid_destroy(fid);
return err;
}
EXPORT_SYMBOL(p9_client_clunk);
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index 244e707..e317583 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -263,7 +263,6 @@
{
int in, out, inp, outp;
struct virtio_chan *chan = client->trans;
- char *rdata = (char *)req->rc+sizeof(struct p9_fcall);
unsigned long flags;
size_t pdata_off = 0;
struct trans_rpage_info *rpinfo = NULL;
@@ -346,7 +345,8 @@
* Arrange in such a way that server places header in the
* alloced memory and payload onto the user buffer.
*/
- inp = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, rdata, 11);
+ inp = pack_sg_list(chan->sg, out,
+ VIRTQUEUE_NUM, req->rc->sdata, 11);
/*
* Running executables in the filesystem may result in
* a read request with kernel buffer as opposed to user buffer.
@@ -366,8 +366,8 @@
}
in += inp;
} else {
- in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, rdata,
- client->msize);
+ in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM,
+ req->rc->sdata, req->rc->capacity);
}
err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc);
@@ -592,7 +592,14 @@
.close = p9_virtio_close,
.request = p9_virtio_request,
.cancel = p9_virtio_cancel,
- .maxsize = PAGE_SIZE*16,
+
+ /*
+ * We leave one entry for input and one entry for response
+ * headers. We also skip one more entry to accomodate, address
+ * that are not at page boundary, that can result in an extra
+ * page in zero copy.
+ */
+ .maxsize = PAGE_SIZE * (VIRTQUEUE_NUM - 3),
.pref = P9_TRANS_PREF_PAYLOAD_SEP,
.def = 0,
.owner = THIS_MODULE,
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
index 2252c20..d07223c 100644
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -242,8 +242,6 @@
if (brdev->payload == p_bridged) {
skb_push(skb, 2);
memset(skb->data, 0, 2);
- } else { /* p_routed */
- skb_pull(skb, ETH_HLEN);
}
}
skb_debug(skb);
@@ -560,12 +558,13 @@
spin_unlock_irqrestore(&rq->lock, flags);
skb_queue_walk_safe(&queue, skb, tmp) {
- struct net_device *dev = skb->dev;
+ struct net_device *dev;
+
+ br2684_push(atmvcc, skb);
+ dev = skb->dev;
dev->stats.rx_bytes -= skb->len;
dev->stats.rx_packets--;
-
- br2684_push(atmvcc, skb);
}
/* initialize netdev carrier state */
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c
index cb43a9c..4918caa 100644
--- a/net/bluetooth/amp.c
+++ b/net/bluetooth/amp.c
@@ -51,20 +51,20 @@
{
BT_DBG("mgr %p", mgr);
- write_lock_bh(&_mgr_list_lock);
+ write_lock(&_mgr_list_lock);
list_del(&mgr->list);
- write_unlock_bh(&_mgr_list_lock);
+ write_unlock(&_mgr_list_lock);
- read_lock_bh(&mgr->ctx_list_lock);
+ read_lock(&mgr->ctx_list_lock);
while (!list_empty(&mgr->ctx_list)) {
struct amp_ctx *ctx;
ctx = list_first_entry(&mgr->ctx_list, struct amp_ctx, list);
- read_unlock_bh(&mgr->ctx_list_lock);
+ read_unlock(&mgr->ctx_list_lock);
BT_DBG("kill ctx %p", ctx);
kill_ctx(ctx);
- read_lock_bh(&mgr->ctx_list_lock);
+ read_lock(&mgr->ctx_list_lock);
}
- read_unlock_bh(&mgr->ctx_list_lock);
+ read_unlock(&mgr->ctx_list_lock);
kfree(mgr->ctrls);
@@ -76,14 +76,14 @@
struct amp_mgr *mgr;
struct amp_mgr *found = NULL;
- read_lock_bh(&_mgr_list_lock);
+ read_lock(&_mgr_list_lock);
list_for_each_entry(mgr, &_mgr_list, list) {
if ((mgr->a2mp_sock) && (mgr->a2mp_sock->sk == sk)) {
found = mgr;
break;
}
}
- read_unlock_bh(&_mgr_list_lock);
+ read_unlock(&_mgr_list_lock);
return found;
}
@@ -92,17 +92,19 @@
{
struct amp_mgr *mgr;
- write_lock_bh(&_mgr_list_lock);
+ write_lock(&_mgr_list_lock);
list_for_each_entry(mgr, &_mgr_list, list) {
if (mgr->l2cap_conn == conn) {
BT_DBG("conn %p found %p", conn, mgr);
+ write_unlock(&_mgr_list_lock);
goto gc_finished;
}
}
+ write_unlock(&_mgr_list_lock);
mgr = kzalloc(sizeof(*mgr), GFP_ATOMIC);
if (!mgr)
- goto gc_finished;
+ return NULL;
mgr->l2cap_conn = conn;
mgr->next_ident = 1;
@@ -113,12 +115,13 @@
mgr->a2mp_sock = open_fixed_channel(conn->src, conn->dst);
if (!mgr->a2mp_sock) {
kfree(mgr);
- goto gc_finished;
+ return NULL;
}
+ write_lock(&_mgr_list_lock);
list_add(&(mgr->list), &_mgr_list);
+ write_unlock(&_mgr_list_lock);
gc_finished:
- write_unlock_bh(&_mgr_list_lock);
return mgr;
}
@@ -169,9 +172,9 @@
static inline void start_ctx(struct amp_mgr *mgr, struct amp_ctx *ctx)
{
BT_DBG("ctx %p", ctx);
- write_lock_bh(&mgr->ctx_list_lock);
+ write_lock(&mgr->ctx_list_lock);
list_add(&ctx->list, &mgr->ctx_list);
- write_unlock_bh(&mgr->ctx_list_lock);
+ write_unlock(&mgr->ctx_list_lock);
ctx->mgr = mgr;
execute_ctx(ctx, AMP_INIT, 0);
}
@@ -182,9 +185,9 @@
BT_DBG("ctx %p deferred %p", ctx, ctx->deferred);
del_timer(&ctx->timer);
- write_lock_bh(&mgr->ctx_list_lock);
+ write_lock(&mgr->ctx_list_lock);
list_del(&ctx->list);
- write_unlock_bh(&mgr->ctx_list_lock);
+ write_unlock(&mgr->ctx_list_lock);
if (ctx->deferred)
execute_ctx(ctx->deferred, AMP_INIT, 0);
kfree(ctx);
@@ -195,14 +198,14 @@
struct amp_ctx *fnd = NULL;
struct amp_ctx *ctx;
- read_lock_bh(&mgr->ctx_list_lock);
+ read_lock(&mgr->ctx_list_lock);
list_for_each_entry(ctx, &mgr->ctx_list, list) {
if (ctx->type == type) {
fnd = ctx;
break;
}
}
- read_unlock_bh(&mgr->ctx_list_lock);
+ read_unlock(&mgr->ctx_list_lock);
return fnd;
}
@@ -212,14 +215,14 @@
struct amp_ctx *fnd = NULL;
struct amp_ctx *ctx;
- read_lock_bh(&mgr->ctx_list_lock);
+ read_lock(&mgr->ctx_list_lock);
list_for_each_entry(ctx, &mgr->ctx_list, list) {
if ((ctx->type == type) && (ctx != cur)) {
fnd = ctx;
break;
}
}
- read_unlock_bh(&mgr->ctx_list_lock);
+ read_unlock(&mgr->ctx_list_lock);
return fnd;
}
@@ -228,7 +231,7 @@
struct amp_ctx *fnd = NULL;
struct amp_ctx *ctx;
- read_lock_bh(&mgr->ctx_list_lock);
+ read_lock(&mgr->ctx_list_lock);
list_for_each_entry(ctx, &mgr->ctx_list, list) {
if ((ctx->evt_type & AMP_A2MP_RSP) &&
(ctx->rsp_ident == ident)) {
@@ -236,7 +239,7 @@
break;
}
}
- read_unlock_bh(&mgr->ctx_list_lock);
+ read_unlock(&mgr->ctx_list_lock);
return fnd;
}
@@ -246,13 +249,13 @@
struct amp_mgr *mgr;
struct amp_ctx *fnd = NULL;
- read_lock_bh(&_mgr_list_lock);
+ read_lock(&_mgr_list_lock);
list_for_each_entry(mgr, &_mgr_list, list) {
struct amp_ctx *ctx;
- read_lock_bh(&mgr->ctx_list_lock);
+ read_lock(&mgr->ctx_list_lock);
list_for_each_entry(ctx, &mgr->ctx_list, list) {
struct hci_dev *ctx_hdev;
- ctx_hdev = hci_dev_get(A2MP_HCI_ID(ctx->id));
+ ctx_hdev = hci_dev_get(ctx->id);
if ((ctx_hdev == hdev) && (ctx->evt_type & evt_type)) {
switch (evt_type) {
case AMP_HCI_CMD_STATUS:
@@ -272,9 +275,9 @@
if (fnd)
break;
}
- read_unlock_bh(&mgr->ctx_list_lock);
+ read_unlock(&mgr->ctx_list_lock);
}
- read_unlock_bh(&_mgr_list_lock);
+ read_unlock(&_mgr_list_lock);
return fnd;
}
@@ -353,7 +356,7 @@
if (hdev) {
if ((hdev->amp_type != HCI_BREDR) &&
test_bit(HCI_UP, &hdev->flags)) {
- (cl + num_ctrls)->id = HCI_A2MP_ID(hdev->id);
+ (cl + num_ctrls)->id = hdev->id;
(cl + num_ctrls)->type = hdev->amp_type;
(cl + num_ctrls)->status = hdev->amp_status;
++num_ctrls;
@@ -371,13 +374,13 @@
{
struct amp_mgr *mgr;
- read_lock_bh(&_mgr_list_lock);
+ read_lock(&_mgr_list_lock);
list_for_each_entry(mgr, &_mgr_list, list) {
if (mgr->discovered)
send_a2mp_cl(mgr, next_ident(mgr),
A2MP_CHANGE_NOTIFY, 0, NULL);
}
- read_unlock_bh(&_mgr_list_lock);
+ read_unlock(&_mgr_list_lock);
}
static inline int discover_req(struct amp_mgr *mgr, struct sk_buff *skb)
@@ -456,7 +459,7 @@
rsp.status = 1;
BT_DBG("id %d", id);
- hdev = hci_dev_get(A2MP_HCI_ID(id));
+ hdev = hci_dev_get(id);
if (hdev && hdev->amp_type != HCI_BREDR) {
rsp.status = 0;
@@ -507,14 +510,14 @@
int result = -EINVAL;
BT_DBG("lcon %p", lcon);
+ hdev = hci_dev_get(id);
+ if (!hdev)
+ goto ap_finished;
+ BT_DBG("hdev %p", hdev);
mgr = get_create_amp_mgr(lcon, NULL);
if (!mgr)
goto ap_finished;
BT_DBG("mgr %p", mgr);
- hdev = hci_dev_get(A2MP_HCI_ID(id));
- if (!hdev)
- goto ap_finished;
- BT_DBG("hdev %p", hdev);
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
&mgr->l2cap_conn->hcon->dst);
if (conn) {
@@ -531,6 +534,8 @@
return;
ap_finished:
+ if (hdev)
+ hci_dev_put(hdev);
l2cap_amp_physical_complete(result, id, remote_id, sk);
}
@@ -550,7 +555,7 @@
return -ENOMEM;
ctx->id = req->id;
ctx->d.gaa.req_ident = hdr->ident;
- ctx->hdev = hci_dev_get(A2MP_HCI_ID(ctx->id));
+ ctx->hdev = hci_dev_get(ctx->id);
if (ctx->hdev)
ctx->d.gaa.assoc = kmalloc(ctx->hdev->amp_assoc_size,
GFP_ATOMIC);
@@ -823,7 +828,7 @@
ctx->d.apl.len_so_far = 0;
ctx->d.apl.rem_len = skb->len;
skb_pull(skb, skb->len);
- ctx->hdev = hci_dev_get(A2MP_HCI_ID(ctx->id));
+ ctx->hdev = hci_dev_get(ctx->id);
start_ctx(mgr, ctx);
return 0;
}
@@ -1119,7 +1124,7 @@
if (hdev) {
struct hci_conn *conn;
ctx->hdev = hdev;
- ctx->id = HCI_A2MP_ID(hdev->id);
+ ctx->id = hdev->id;
ctx->d.cpl.remote_id = cl->id;
conn = hci_conn_hash_lookup_ba(hdev,
ACL_LINK,
@@ -1422,7 +1427,7 @@
rsp.status = 0;
BT_DBG("local_id %d remote_id %d",
(int) rsp.local_id, (int) rsp.remote_id);
- hdev = hci_dev_get(A2MP_HCI_ID(rsp.local_id));
+ hdev = hci_dev_get(rsp.local_id);
if (!hdev) {
rsp.status = 1; /* Invalid Controller ID */
goto dpl_finished;
@@ -1517,10 +1522,10 @@
struct amp_ctx *ctx = NULL;
BT_DBG("mgr %p", mgr);
- read_lock_bh(&mgr->ctx_list_lock);
+ read_lock(&mgr->ctx_list_lock);
if (!list_empty(&mgr->ctx_list))
ctx = list_first_entry(&mgr->ctx_list, struct amp_ctx, list);
- read_unlock_bh(&mgr->ctx_list_lock);
+ read_unlock(&mgr->ctx_list_lock);
BT_DBG("ctx %p", ctx);
if (ctx)
execute_ctx(ctx, AMP_INIT, NULL);
@@ -1549,7 +1554,7 @@
/* L2CAP-A2MP interface */
-void a2mp_receive(struct sock *sk, struct sk_buff *skb)
+static void a2mp_receive(struct sock *sk, struct sk_buff *skb)
{
struct a2mp_cmd_hdr *hdr = (struct a2mp_cmd_hdr *) skb->data;
int len;
diff --git a/net/bluetooth/bnep/bnep.h b/net/bluetooth/bnep/bnep.h
index 8e6c061..e7ee531 100644
--- a/net/bluetooth/bnep/bnep.h
+++ b/net/bluetooth/bnep/bnep.h
@@ -155,6 +155,7 @@
unsigned int role;
unsigned long state;
unsigned long flags;
+ atomic_t terminate;
struct task_struct *task;
struct ethhdr eh;
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index dfadb65..61c946c 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -484,9 +484,11 @@
init_waitqueue_entry(&wait, current);
add_wait_queue(sk_sleep(sk), &wait);
- while (!kthread_should_stop()) {
+ while (1) {
set_current_state(TASK_INTERRUPTIBLE);
+ if (atomic_read(&s->terminate))
+ break;
/* RX */
while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
skb_orphan(skb);
@@ -643,9 +645,10 @@
down_read(&bnep_session_sem);
s = __bnep_get_session(req->dst);
- if (s)
- kthread_stop(s->task);
- else
+ if (s) {
+ atomic_inc(&s->terminate);
+ wake_up_process(s->task);
+ } else
err = -ENOENT;
up_read(&bnep_session_sem);
diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c
index 8c100c9..d4f5dff 100644
--- a/net/bluetooth/bnep/netdev.c
+++ b/net/bluetooth/bnep/netdev.c
@@ -231,6 +231,7 @@
dev->addr_len = ETH_ALEN;
ether_setup(dev);
+ dev->priv_flags &= ~IFF_TX_SKB_SHARING;
dev->netdev_ops = &bnep_netdev_ops;
dev->watchdog_timeo = HZ * 2;
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 5e67829..95718bb 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -505,13 +505,13 @@
return 0;
}
-void hci_chan_put(struct hci_chan *chan)
+int hci_chan_put(struct hci_chan *chan)
{
struct hci_cp_disconn_logical_link cp;
BT_DBG("chan %p refcnt %d", chan, atomic_read(&chan->refcnt));
if (!atomic_dec_and_test(&chan->refcnt))
- return;
+ return 0;
BT_DBG("chan->conn->state %d", chan->conn->state);
if (chan->conn->state == BT_CONNECTED) {
@@ -520,6 +520,8 @@
sizeof(cp), &cp);
} else
hci_chan_del(chan);
+
+ return 1;
}
EXPORT_SYMBOL(hci_chan_put);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index b7bbe02..e1a90f8 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -581,8 +581,11 @@
set_bit(HCI_UP, &hdev->flags);
hci_notify(hdev, HCI_DEV_UP);
if (!test_bit(HCI_SETUP, &hdev->flags) &&
- hdev->dev_type == HCI_BREDR)
+ hdev->dev_type == HCI_BREDR) {
+ hci_dev_lock_bh(hdev);
mgmt_powered(hdev->id, 1);
+ hci_dev_unlock_bh(hdev);
+ }
} else {
/* Init failed, cleanup */
tasklet_kill(&hdev->rx_task);
@@ -612,6 +615,8 @@
static int hci_dev_do_close(struct hci_dev *hdev)
{
+ unsigned long keepflags = 0;
+
BT_DBG("%s %p", hdev->name, hdev);
hci_req_cancel(hdev, ENODEV);
@@ -666,11 +671,21 @@
* and no tasks are scheduled. */
hdev->close(hdev);
- if (hdev->dev_type == HCI_BREDR)
+ if (hdev->dev_type == HCI_BREDR) {
+ hci_dev_lock_bh(hdev);
mgmt_powered(hdev->id, 0);
+ hci_dev_unlock_bh(hdev);
+ }
- /* Clear flags */
- hdev->flags = 0;
+ /* Clear only non-persistent flags */
+ if (test_bit(HCI_MGMT, &hdev->flags))
+ set_bit(HCI_MGMT, &keepflags);
+ if (test_bit(HCI_LINK_KEYS, &hdev->flags))
+ set_bit(HCI_LINK_KEYS, &keepflags);
+ if (test_bit(HCI_DEBUG_KEYS, &hdev->flags))
+ set_bit(HCI_DEBUG_KEYS, &keepflags);
+
+ hdev->flags = keepflags;
hci_req_unlock(hdev);
@@ -1538,8 +1553,11 @@
if (!test_bit(HCI_INIT, &hdev->flags) &&
!test_bit(HCI_SETUP, &hdev->flags) &&
- hdev->dev_type == HCI_BREDR)
+ hdev->dev_type == HCI_BREDR) {
+ hci_dev_lock_bh(hdev);
mgmt_index_removed(hdev->id);
+ hci_dev_unlock_bh(hdev);
+ }
if (!IS_ERR(hdev->tfm))
crypto_free_blkcipher(hdev->tfm);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index a6e3485..13d9b71 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -223,12 +223,13 @@
sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME);
if (!sent)
return;
-
+ hci_dev_lock(hdev);
if (!status)
memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_set_local_name_complete(hdev->id, sent, status);
+ hci_dev_unlock(hdev);
}
static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
@@ -303,6 +304,7 @@
if (!status) {
__u8 param = *((__u8 *) sent);
int old_pscan, old_iscan;
+ hci_dev_lock(hdev);
old_pscan = test_and_clear_bit(HCI_PSCAN, &hdev->flags);
old_iscan = test_and_clear_bit(HCI_ISCAN, &hdev->flags);
@@ -320,6 +322,7 @@
mgmt_connectable(hdev->id, 1);
} else if (old_pscan)
mgmt_connectable(hdev->id, 0);
+ hci_dev_unlock(hdev);
}
hci_req_complete(hdev, HCI_OP_WRITE_SCAN_ENABLE, status);
@@ -859,20 +862,23 @@
struct hci_conn *conn;
BT_DBG("%s status 0x%x", hdev->name, rp->status);
+ hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_pin_code_reply_complete(hdev->id, &rp->bdaddr, rp->status);
if (rp->status != 0)
- return;
+ goto unlock;
cp = hci_sent_cmd_data(hdev, HCI_OP_PIN_CODE_REPLY);
if (!cp)
- return;
+ goto unlock;
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
if (conn)
conn->pin_length = cp->pin_len;
+unlock:
+ hci_dev_unlock(hdev);
}
static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
@@ -880,10 +886,12 @@
struct hci_rp_pin_code_neg_reply *rp = (void *) skb->data;
BT_DBG("%s status 0x%x", hdev->name, rp->status);
+ hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_pin_code_neg_reply_complete(hdev->id, &rp->bdaddr,
rp->status);
+ hci_dev_unlock(hdev);
}
static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
struct sk_buff *skb)
@@ -910,10 +918,12 @@
struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
BT_DBG("%s status 0x%x", hdev->name, rp->status);
+ hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_user_confirm_reply_complete(hdev->id, &rp->bdaddr,
rp->status);
+ hci_dev_unlock(hdev);
}
static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
@@ -922,10 +932,12 @@
struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
BT_DBG("%s status 0x%x", hdev->name, rp->status);
+ hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_user_confirm_neg_reply_complete(hdev->id, &rp->bdaddr,
rp->status);
+ hci_dev_unlock(hdev);
}
static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
@@ -934,9 +946,11 @@
struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
BT_DBG("%s status 0x%x", hdev->name, rp->status);
+ hci_dev_lock(hdev);
mgmt_read_local_oob_data_reply_complete(hdev->id, rp->hash,
rp->randomizer, rp->status);
+ hci_dev_unlock(hdev);
}
static void hci_cc_le_ltk_reply(struct hci_dev *hdev, struct sk_buff *skb)
@@ -995,8 +1009,10 @@
hci_conn_check_pending(hdev);
} else {
set_bit(HCI_INQUIRY, &hdev->flags);
+ hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_inquiry_started(hdev->id);
+ hci_dev_unlock(hdev);
}
}
@@ -1506,9 +1522,11 @@
clear_bit(HCI_INQUIRY, &hdev->flags);
hci_req_complete(hdev, HCI_OP_INQUIRY, status);
+ hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_inquiry_complete_evt(hdev->id, status);
+ hci_dev_unlock(hdev);
if (!lmp_le_capable(hdev))
hci_conn_check_pending(hdev);
@@ -1709,7 +1727,9 @@
BT_DBG("%s status %d", hdev->name, ev->status);
if (ev->status) {
+ hci_dev_lock(hdev);
mgmt_disconnect_failed(hdev->id);
+ hci_dev_unlock(hdev);
return;
}
@@ -1860,6 +1880,9 @@
hci_conn_put(conn);
} else
hci_encrypt_cfm(conn, ev->status, ev->encrypt);
+
+ if (test_bit(HCI_MGMT, &hdev->flags))
+ mgmt_encrypt_change(hdev->id, &conn->dst, ev->status);
}
hci_dev_unlock(hdev);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index abc3ef7..a3f3563 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -549,8 +549,7 @@
l2cap_pi(sk)->ampcon->l2cap_data = NULL;
l2cap_pi(sk)->ampcon = NULL;
if (l2cap_pi(sk)->ampchan) {
- hci_chan_put(l2cap_pi(sk)->ampchan);
- if (atomic_read(&l2cap_pi(sk)->ampchan->refcnt))
+ if (!hci_chan_put(l2cap_pi(sk)->ampchan))
l2cap_deaggregate(l2cap_pi(sk)->ampchan,
l2cap_pi(sk));
}
@@ -1445,6 +1444,9 @@
*/
tx_skb = skb_clone(skb, GFP_ATOMIC);
+ if (!tx_skb)
+ break;
+
sock_hold(sk);
tx_skb->sk = sk;
tx_skb->destructor = l2cap_skb_destructor;
@@ -3084,8 +3086,9 @@
if (new->sdu_arr_time)
new_rate = div_u64(new_rate, new->sdu_arr_time);
cur_rate = cur_rate + new_rate;
- agg->sdu_arr_time = div64_u64(agg->max_sdu * 1000000ULL,
- cur_rate);
+ if (cur_rate)
+ agg->sdu_arr_time = div64_u64(
+ agg->max_sdu * 1000000ULL, cur_rate);
}
}
}
@@ -3126,8 +3129,9 @@
if (old->sdu_arr_time)
old_rate = div_u64(old_rate, old->sdu_arr_time);
cur_rate = cur_rate - old_rate;
- agg->sdu_arr_time = div64_u64(agg->max_sdu * 1000000ULL,
- cur_rate);
+ if (cur_rate)
+ agg->sdu_arr_time = div64_u64(
+ agg->max_sdu * 1000000ULL, cur_rate);
}
}
@@ -3158,21 +3162,23 @@
struct hci_conn *hcon;
struct hci_chan *chan;
- hdev = hci_dev_get(A2MP_HCI_ID(amp_id));
+ hdev = hci_dev_get(amp_id);
if (!hdev)
return NULL;
BT_DBG("hdev %s", hdev->name);
hcon = hci_conn_hash_lookup_ba(hdev, ACL_LINK, pi->conn->dst);
- if (!hcon)
- return NULL;
+ if (!hcon) {
+ chan = NULL;
+ goto done;
+ }
chan = hci_chan_list_lookup_id(hdev, hcon->handle);
if (chan) {
l2cap_aggregate(chan, pi);
hci_chan_hold(chan);
- return chan;
+ goto done;
}
if (bt_sk(pi)->parent) {
@@ -3186,6 +3192,8 @@
(struct hci_ext_fs *) &pi->local_fs,
(struct hci_ext_fs *) &pi->remote_fs);
}
+done:
+ hci_dev_put(hdev);
return chan;
}
@@ -3743,6 +3751,12 @@
BT_DBG("sk %p, rsp %p, len %d, req %p", sk, rsp, len, data);
+ /* Initialize rfc in case no rfc option is received */
+ rfc.mode = pi->mode;
+ rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
+ rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
+ rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
+
while (len >= L2CAP_CONF_OPT_SIZE) {
len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
@@ -3837,6 +3851,12 @@
BT_DBG("sk %p, rsp %p, len %d", sk, rsp, len);
+ /* Initialize rfc in case no rfc option is received */
+ rfc.mode = pi->mode;
+ rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
+ rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
+ rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
+
if ((pi->mode != L2CAP_MODE_ERTM) && (pi->mode != L2CAP_MODE_STREAMING))
return;
@@ -4727,7 +4747,7 @@
struct hci_dev *hdev;
/* Validate AMP controller id */
- hdev = hci_dev_get(A2MP_HCI_ID(req->amp_id));
+ hdev = hci_dev_get(req->amp_id);
if (!hdev || !test_bit(HCI_UP, &hdev->flags)) {
struct l2cap_create_chan_rsp rsp;
@@ -4805,7 +4825,7 @@
if (req->dest_amp_id) {
struct hci_dev *hdev;
- hdev = hci_dev_get(A2MP_HCI_ID(req->dest_amp_id));
+ hdev = hci_dev_get(req->dest_amp_id);
if (!hdev || !test_bit(HCI_UP, &hdev->flags)) {
if (hdev)
hci_dev_put(hdev);
@@ -4813,6 +4833,7 @@
result = L2CAP_MOVE_CHAN_REFUSED_CONTROLLER;
goto send_move_response;
}
+ hci_dev_put(hdev);
}
if (((pi->amp_move_state != L2CAP_AMP_STATE_STABLE &&
@@ -5039,8 +5060,7 @@
if ((!l2cap_pi(sk)->amp_id) &&
(l2cap_pi(sk)->ampchan)) {
/* Have moved off of AMP, free the channel */
- hci_chan_put(l2cap_pi(sk)->ampchan);
- if (atomic_read(&l2cap_pi(sk)->ampchan->refcnt))
+ if (!hci_chan_put(l2cap_pi(sk)->ampchan))
l2cap_deaggregate(l2cap_pi(sk)->ampchan,
l2cap_pi(sk));
l2cap_pi(sk)->ampchan = NULL;
@@ -5098,8 +5118,7 @@
/* Have moved off of AMP, free the channel */
l2cap_pi(sk)->ampcon = NULL;
if (l2cap_pi(sk)->ampchan) {
- hci_chan_put(l2cap_pi(sk)->ampchan);
- if (atomic_read(&l2cap_pi(sk)->ampchan->refcnt))
+ if (!hci_chan_put(l2cap_pi(sk)->ampchan))
l2cap_deaggregate(l2cap_pi(sk)->ampchan,
l2cap_pi(sk));
}
@@ -5477,6 +5496,7 @@
/* TODO MM/PK - What to do if connection is LOCAL_BUSY? */
if (l2cap_pi(sk)->ampchan == chan) {
l2cap_pi(sk)->ampchan = NULL;
+ l2cap_pi(sk)->ampcon = NULL;
l2cap_amp_move_init(sk);
}
bh_unlock_sock(sk);
@@ -5813,6 +5833,11 @@
tx_skb = skb_clone(skb, GFP_ATOMIC);
}
+ if (!tx_skb) {
+ l2cap_seq_list_clear(&pi->retrans_list);
+ break;
+ }
+
/* Update skb contents */
if (pi->extended_control) {
put_unaligned_le32(__pack_extended_control(&control),
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 094bfdb..b413a9c 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -41,8 +41,6 @@
};
struct disco_interleave {
- struct timer_list timer;
- struct timer_list le_timer;
u16 index;
enum scan_mode mode;
int int_phase;
@@ -208,7 +206,7 @@
hci_del_off_timer(hdev);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
set_bit(HCI_MGMT, &hdev->flags);
@@ -237,7 +235,7 @@
memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
@@ -377,7 +375,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
up = test_bit(HCI_UP, &hdev->flags);
if ((cp->val && up) || (!cp->val && !up)) {
@@ -404,7 +402,7 @@
err = 0;
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
}
@@ -467,7 +465,7 @@
return cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
@@ -521,7 +519,7 @@
mgmt_pending_remove(cmd);
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -547,7 +545,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
@@ -582,7 +580,7 @@
mgmt_pending_remove(cmd);
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -608,7 +606,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
@@ -642,7 +640,7 @@
mgmt_pending_remove(cmd);
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -703,7 +701,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
if (cp->val)
set_bit(HCI_PAIRABLE, &hdev->flags);
@@ -719,7 +717,7 @@
err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -887,7 +885,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
if (!uuid) {
@@ -911,7 +909,7 @@
err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -936,7 +934,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
err = hci_uuids_clear(hdev);
@@ -971,7 +969,7 @@
err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
unlock:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -995,7 +993,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
hdev->major_class &= ~MGMT_MAJOR_CLASS_MASK;
hdev->major_class |= cp->major & MGMT_MAJOR_CLASS_MASK;
@@ -1006,7 +1004,7 @@
if (err == 0)
err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1028,7 +1026,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
BT_DBG("hci%u enable %d", index, cp->enable);
@@ -1046,7 +1044,7 @@
err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
0);
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1080,7 +1078,7 @@
BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
key_count);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
hci_link_keys_clear(hdev);
@@ -1118,7 +1116,7 @@
err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0);
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1140,7 +1138,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
err = hci_remove_link_key(hdev, &cp->bdaddr);
if (err < 0) {
@@ -1163,7 +1161,7 @@
}
unlock:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1189,7 +1187,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
@@ -1225,7 +1223,7 @@
mgmt_pending_remove(cmd);
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1246,7 +1244,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
count = 0;
list_for_each(p, &hdev->conn_hash.list) {
@@ -1277,7 +1275,7 @@
unlock:
kfree(rp);
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
}
@@ -1302,7 +1300,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
@@ -1324,12 +1322,70 @@
mgmt_pending_remove(cmd);
failed:
+ hci_dev_unlock_bh(hdev);
+ hci_dev_put(hdev);
+
+ return err;
+}
+
+static int encrypt_link(struct sock *sk, u16 index, unsigned char *data,
+ u16 len)
+{
+ struct hci_dev *hdev;
+ struct mgmt_cp_encrypt_link *cp;
+ struct hci_cp_set_conn_encrypt enc;
+ struct hci_conn *conn;
+ int err = 0;
+
+ BT_DBG("");
+
+ cp = (void *) data;
+
+ if (len != sizeof(*cp))
+ return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, EINVAL);
+
+ hdev = hci_dev_get(index);
+ if (!hdev)
+ return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENODEV);
+
+ hci_dev_lock(hdev);
+
+ if (!test_bit(HCI_UP, &hdev->flags)) {
+ err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENETDOWN);
+ goto failed;
+ }
+
+ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
+ &cp->bdaddr);
+ if (!conn)
+ return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENOTCONN);
+
+ if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
+ return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, EINPROGRESS);
+
+ if (conn->link_mode & HCI_LM_AUTH) {
+ enc.handle = cpu_to_le16(conn->handle);
+ enc.encrypt = cp->enable;
+ err = hci_send_cmd(hdev,
+ HCI_OP_SET_CONN_ENCRYPT, sizeof(enc), &enc);
+ } else {
+ conn->auth_initiator = 1;
+ if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
+ struct hci_cp_auth_requested cp;
+ cp.handle = cpu_to_le16(conn->handle);
+ err = hci_send_cmd(conn->hdev,
+ HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
+ }
+ }
+
+failed:
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return err;
}
+
static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
u16 len)
{
@@ -1351,7 +1407,7 @@
return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
@@ -1372,7 +1428,7 @@
mgmt_pending_remove(cmd);
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1395,14 +1451,14 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
hdev->io_capability = cp->io_capability;
BT_DBG("%s IO capability set to 0x%02x", hdev->name,
hdev->io_capability);
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
@@ -1507,12 +1563,19 @@
static void discovery_terminated(struct pending_cmd *cmd, void *data)
{
+ struct hci_dev *hdev;
struct mgmt_mode ev = {0};
- struct disco_interleave *ilp = cmd->param;
BT_DBG("");
- del_timer_sync(&ilp->le_timer);
- del_timer_sync(&ilp->timer);
+ hdev = hci_dev_get(cmd->index);
+ if (!hdev)
+ goto not_found;
+
+ del_timer_sync(&hdev->disc_le_timer);
+ del_timer_sync(&hdev->disc_timer);
+ hci_dev_put(hdev);
+
+not_found:
mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
list_del(&cmd->list);
@@ -1542,7 +1605,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
BT_DBG("SSP Cap is %d", cp->ssp_cap);
io_cap = cp->io_cap;
@@ -1597,7 +1660,7 @@
err = 0;
unlock:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1627,7 +1690,7 @@
if (!hdev)
return cmd_status(sk, index, mgmt_op, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, mgmt_op, ENETDOWN);
@@ -1653,7 +1716,7 @@
mgmt_pending_remove(cmd);
done:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1677,7 +1740,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
cmd = mgmt_pending_add(sk, MGMT_OP_RESOLVE_NAME, index, data, len);
if (!cmd) {
@@ -1693,7 +1756,7 @@
mgmt_pending_remove(cmd);
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1718,7 +1781,7 @@
return cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
if (!conn) {
@@ -1735,7 +1798,7 @@
err = cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS, 0);
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1759,7 +1822,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
if (!cmd) {
@@ -1774,7 +1837,7 @@
mgmt_pending_remove(cmd);
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1793,10 +1856,12 @@
cmd_complete(cmd->sk, cmd->index, MGMT_OP_STOP_DISCOVERY,
NULL, 0);
if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
- struct disco_interleave *ilp = cmd->param;
-
- del_timer_sync(&ilp->le_timer);
- del_timer_sync(&ilp->timer);
+ struct hci_dev *hdev = hci_dev_get(cmd->index);
+ if (hdev) {
+ del_timer_sync(&hdev->disc_le_timer);
+ del_timer_sync(&hdev->disc_timer);
+ hci_dev_put(hdev);
+ }
}
}
@@ -1825,9 +1890,6 @@
hdev = hci_dev_get(index);
- if (hdev)
- hci_dev_lock(hdev);
-
if (!hdev || !lmp_le_capable(hdev)) {
struct mgmt_mode cp = {0};
@@ -1848,8 +1910,8 @@
err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
sizeof(le_cp), &le_cp);
- if (err >= 0) {
- mod_timer(&ilp->le_timer, jiffies +
+ if (err >= 0 && hdev) {
+ mod_timer(&hdev->disc_le_timer, jiffies +
msecs_to_jiffies(ilp->int_phase * 1000));
ilp->mode = SCAN_LE;
} else
@@ -1861,7 +1923,6 @@
discovery_terminated, NULL);
done:
- hci_dev_unlock(hdev);
hci_dev_put(hdev);
}
@@ -1873,11 +1934,11 @@
BT_DBG("hci%d", ilp->index);
- del_timer_sync(&ilp->le_timer);
hdev = hci_dev_get(ilp->index);
if (hdev) {
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
+ del_timer_sync(&hdev->disc_le_timer);
cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
@@ -1902,7 +1963,7 @@
mgmt_pending_remove(cmd);
}
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
}
}
@@ -1919,7 +1980,7 @@
hdev = hci_dev_get(ilp->index);
if (hdev) {
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
@@ -1938,7 +1999,7 @@
} else
ilp->mode = SCAN_IDLE;
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
}
}
@@ -1956,7 +2017,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
if (!cmd) {
@@ -2002,16 +2063,17 @@
cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
if (cmd) {
ilp = cmd->param;
- setup_timer(&ilp->le_timer, disco_le_to,
+ setup_timer(&hdev->disc_le_timer, disco_le_to,
(unsigned long) ilp);
- setup_timer(&ilp->timer, disco_to, (unsigned long) ilp);
- mod_timer(&ilp->timer,
+ setup_timer(&hdev->disc_timer, disco_to,
+ (unsigned long) ilp);
+ mod_timer(&hdev->disc_timer,
jiffies + msecs_to_jiffies(20000));
}
}
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -2032,7 +2094,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
if (lmp_le_capable(hdev)) {
cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
@@ -2056,8 +2118,8 @@
if (ilp) {
ilp->mode = SCAN_IDLE;
- del_timer_sync(&ilp->le_timer);
- del_timer_sync(&ilp->timer);
+ del_timer_sync(&hdev->disc_le_timer);
+ del_timer_sync(&hdev->disc_timer);
}
if (err < 0 && cmd)
@@ -2066,7 +2128,7 @@
mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
if (err < 0)
@@ -2088,7 +2150,7 @@
return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
@@ -2118,7 +2180,7 @@
mgmt_pending_remove(cmd);
unlock:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -2142,7 +2204,7 @@
return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
cp->randomizer);
@@ -2152,7 +2214,7 @@
err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
0);
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -2176,7 +2238,7 @@
return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
if (err < 0)
@@ -2186,7 +2248,7 @@
err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
NULL, 0);
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -2317,6 +2379,9 @@
err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
len);
break;
+ case MGMT_OP_ENCRYPT_LINK:
+ err = encrypt_link(sk, index, buf + sizeof(*hdr), len);
+ break;
default:
BT_DBG("Unknown op %u", opcode);
@@ -2608,7 +2673,10 @@
loc_mitm = conn->auth_type & 0x01;
rem_mitm = conn->remote_auth & 0x01;
- if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03))
+ if ((conn->auth_type & HCI_AT_DEDICATED_BONDING) &&
+ conn->auth_initiator && rem_cap == 0x03)
+ ev.auto_confirm = 1;
+ else if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03))
goto no_auto_confirm;
@@ -2701,9 +2769,7 @@
hdev = hci_dev_get(index);
if (hdev) {
- hci_dev_lock_bh(hdev);
update_eir(hdev);
- hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
}
@@ -2801,7 +2867,7 @@
hci_send_cmd(hdev, HCI_OP_INQUIRY,
sizeof(cp), &cp);
ilp->mode = SCAN_BR;
- del_timer_sync(&ilp->le_timer);
+ del_timer_sync(&hdev->disc_le_timer);
}
}
@@ -2825,3 +2891,17 @@
return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
}
+
+int mgmt_encrypt_change(u16 index, bdaddr_t *bdaddr, u8 status)
+{
+ struct mgmt_ev_encrypt_change ev;
+
+ BT_DBG("hci%u", index);
+
+ bacpy(&ev.bdaddr, bdaddr);
+ ev.status = status;
+
+ return mgmt_event(MGMT_EV_ENCRYPT_CHANGE, index, &ev, sizeof(ev),
+ NULL);
+}
+
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 16bb5ea..c4b9950 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -1203,6 +1203,7 @@
if (list_empty(&s->dlcs)) {
s->state = BT_DISCONN;
rfcomm_send_disc(s, 0);
+ rfcomm_session_clear_timer(s);
}
break;
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index a88f4a5..e301edf 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -1020,12 +1020,16 @@
*keydist &= ~SMP_DIST_SIGN;
}
- if (hcon->out || rsp->resp_key_dist) {
+ if (hcon->out) {
if (hcon->disconn_cfm_cb)
hcon->disconn_cfm_cb(hcon, 0);
-
del_timer(&hcon->smp_timer);
clear_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
+ hci_conn_put(hcon);
+ } else if (rsp->resp_key_dist) {
+ if (hcon->disconn_cfm_cb)
+ hcon->disconn_cfm_cb(hcon, SMP_UNSPECIFIED);
+ clear_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
mgmt_auth_failed(hcon->hdev->id, conn->dst, SMP_UNSPECIFIED);
hci_conn_put(hcon);
}
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 32b8f9f..a9dd166 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -38,16 +38,17 @@
}
#endif
- u64_stats_update_begin(&brstats->syncp);
- brstats->tx_packets++;
- brstats->tx_bytes += skb->len;
- u64_stats_update_end(&brstats->syncp);
-
BR_INPUT_SKB_CB(skb)->brdev = dev;
skb_reset_mac_header(skb);
skb_pull(skb, ETH_HLEN);
+ u64_stats_update_begin(&brstats->syncp);
+ brstats->tx_packets++;
+ /* Exclude ETH_HLEN from byte stats for consistency with Rx chain */
+ brstats->tx_bytes += skb->len;
+ u64_stats_update_end(&brstats->syncp);
+
rcu_read_lock();
if (is_broadcast_ether_addr(dest))
br_flood_deliver(br, skb);
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 1bacca4..6f156c1 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -231,6 +231,7 @@
int br_add_bridge(struct net *net, const char *name)
{
struct net_device *dev;
+ int res;
dev = alloc_netdev(sizeof(struct net_bridge), name,
br_dev_setup);
@@ -240,7 +241,10 @@
dev_net_set(dev, net);
- return register_netdev(dev);
+ res = register_netdev(dev);
+ if (res)
+ free_netdev(dev);
+ return res;
}
int br_del_bridge(struct net *net, const char *name)
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 2d85ca7..995cbe0 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1456,7 +1456,7 @@
{
struct sk_buff *skb2;
const struct ipv6hdr *ip6h;
- struct icmp6hdr *icmp6h;
+ u8 icmp6_type;
u8 nexthdr;
unsigned len;
int offset;
@@ -1502,9 +1502,9 @@
__skb_pull(skb2, offset);
skb_reset_transport_header(skb2);
- icmp6h = icmp6_hdr(skb2);
+ icmp6_type = icmp6_hdr(skb2)->icmp6_type;
- switch (icmp6h->icmp6_type) {
+ switch (icmp6_type) {
case ICMPV6_MGM_QUERY:
case ICMPV6_MGM_REPORT:
case ICMPV6_MGM_REDUCTION:
@@ -1520,16 +1520,23 @@
err = pskb_trim_rcsum(skb2, len);
if (err)
goto out;
+ err = -EINVAL;
}
+ ip6h = ipv6_hdr(skb2);
+
switch (skb2->ip_summed) {
case CHECKSUM_COMPLETE:
- if (!csum_fold(skb2->csum))
+ if (!csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, skb2->len,
+ IPPROTO_ICMPV6, skb2->csum))
break;
/*FALLTHROUGH*/
case CHECKSUM_NONE:
- skb2->csum = 0;
- if (skb_checksum_complete(skb2))
+ skb2->csum = ~csum_unfold(csum_ipv6_magic(&ip6h->saddr,
+ &ip6h->daddr,
+ skb2->len,
+ IPPROTO_ICMPV6, 0));
+ if (__skb_checksum_complete(skb2))
goto out;
}
@@ -1537,7 +1544,7 @@
BR_INPUT_SKB_CB(skb)->igmp = 1;
- switch (icmp6h->icmp6_type) {
+ switch (icmp6_type) {
case ICMPV6_MGM_REPORT:
{
struct mld_msg *mld;
diff --git a/net/core/Makefile b/net/core/Makefile
index 8a04dd2..0d357b1 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -3,7 +3,7 @@
#
obj-y := sock.o request_sock.o skbuff.o iovec.o datagram.o stream.o scm.o \
- gen_stats.o gen_estimator.o net_namespace.o
+ gen_stats.o gen_estimator.o net_namespace.o secure_seq.o
obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index 008dc70..f39ef5c 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -384,8 +384,8 @@
*/
list_for_each_entry(r, &ops->rules_list, list) {
if (r->action == FR_ACT_GOTO &&
- r->target == rule->pref) {
- BUG_ON(rtnl_dereference(r->ctarget) != NULL);
+ r->target == rule->pref &&
+ rtnl_dereference(r->ctarget) == NULL) {
rcu_assign_pointer(r->ctarget, rule);
if (--ops->unresolved_rules == 0)
break;
diff --git a/net/core/link_watch.c b/net/core/link_watch.c
index a7b3421..357bd4e 100644
--- a/net/core/link_watch.c
+++ b/net/core/link_watch.c
@@ -126,7 +126,7 @@
return;
/* It's already running which is good enough. */
- if (!cancel_delayed_work(&linkwatch_work))
+ if (!__cancel_delayed_work(&linkwatch_work))
return;
/* Otherwise we reschedule it again for immediate execution. */
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 799f06e..16db887 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1383,11 +1383,15 @@
if (tdif <= 0) {
struct net_device *dev = skb->dev;
+
__skb_unlink(skb, &tbl->proxy_queue);
- if (tbl->proxy_redo && netif_running(dev))
+ if (tbl->proxy_redo && netif_running(dev)) {
+ rcu_read_lock();
tbl->proxy_redo(skb);
- else
+ rcu_read_unlock();
+ } else {
kfree_skb(skb);
+ }
dev_put(dev);
} else if (!sched_next || tdif < sched_next)
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index f76079c..e35a6fb 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -1070,7 +1070,9 @@
len = num_arg(&user_buffer[i], 10, &value);
if (len < 0)
return len;
-
+ if ((value > 0) &&
+ (!(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING)))
+ return -ENOTSUPP;
i += len;
pkt_dev->clone_skb = value;
@@ -3555,7 +3557,6 @@
pkt_dev->min_pkt_size = ETH_ZLEN;
pkt_dev->max_pkt_size = ETH_ZLEN;
pkt_dev->nfrags = 0;
- pkt_dev->clone_skb = pg_clone_skb_d;
pkt_dev->delay = pg_delay_d;
pkt_dev->count = pg_count_d;
pkt_dev->sofar = 0;
@@ -3563,7 +3564,6 @@
pkt_dev->udp_src_max = 9;
pkt_dev->udp_dst_min = 9;
pkt_dev->udp_dst_max = 9;
-
pkt_dev->vlan_p = 0;
pkt_dev->vlan_cfi = 0;
pkt_dev->vlan_id = 0xffff;
@@ -3575,6 +3575,8 @@
err = pktgen_setup_dev(pkt_dev, ifname);
if (err)
goto out1;
+ if (pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING)
+ pkt_dev->clone_skb = pg_clone_skb_d;
pkt_dev->entry = proc_create_data(ifname, 0600, pg_proc_dir,
&pktgen_if_fops, pkt_dev);
diff --git a/net/core/scm.c b/net/core/scm.c
index 4c1ef02..811b53f 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -192,7 +192,7 @@
goto error;
cred->uid = cred->euid = p->creds.uid;
- cred->gid = cred->egid = p->creds.uid;
+ cred->gid = cred->egid = p->creds.gid;
put_cred(p->cred);
p->cred = cred;
}
diff --git a/net/core/secure_seq.c b/net/core/secure_seq.c
new file mode 100644
index 0000000..45329d7
--- /dev/null
+++ b/net/core/secure_seq.c
@@ -0,0 +1,184 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/cryptohash.h>
+#include <linux/module.h>
+#include <linux/cache.h>
+#include <linux/random.h>
+#include <linux/hrtimer.h>
+#include <linux/ktime.h>
+#include <linux/string.h>
+
+#include <net/secure_seq.h>
+
+static u32 net_secret[MD5_MESSAGE_BYTES / 4] ____cacheline_aligned;
+
+static int __init net_secret_init(void)
+{
+ get_random_bytes(net_secret, sizeof(net_secret));
+ return 0;
+}
+late_initcall(net_secret_init);
+
+static u32 seq_scale(u32 seq)
+{
+ /*
+ * As close as possible to RFC 793, which
+ * suggests using a 250 kHz clock.
+ * Further reading shows this assumes 2 Mb/s networks.
+ * For 10 Mb/s Ethernet, a 1 MHz clock is appropriate.
+ * For 10 Gb/s Ethernet, a 1 GHz clock should be ok, but
+ * we also need to limit the resolution so that the u32 seq
+ * overlaps less than one time per MSL (2 minutes).
+ * Choosing a clock of 64 ns period is OK. (period of 274 s)
+ */
+ return seq + (ktime_to_ns(ktime_get_real()) >> 6);
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+__u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr,
+ __be16 sport, __be16 dport)
+{
+ u32 secret[MD5_MESSAGE_BYTES / 4];
+ u32 hash[MD5_DIGEST_WORDS];
+ u32 i;
+
+ memcpy(hash, saddr, 16);
+ for (i = 0; i < 4; i++)
+ secret[i] = net_secret[i] + daddr[i];
+ secret[4] = net_secret[4] +
+ (((__force u16)sport << 16) + (__force u16)dport);
+ for (i = 5; i < MD5_MESSAGE_BYTES / 4; i++)
+ secret[i] = net_secret[i];
+
+ md5_transform(hash, secret);
+
+ return seq_scale(hash[0]);
+}
+EXPORT_SYMBOL(secure_tcpv6_sequence_number);
+
+u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
+ __be16 dport)
+{
+ u32 secret[MD5_MESSAGE_BYTES / 4];
+ u32 hash[MD5_DIGEST_WORDS];
+ u32 i;
+
+ memcpy(hash, saddr, 16);
+ for (i = 0; i < 4; i++)
+ secret[i] = net_secret[i] + (__force u32) daddr[i];
+ secret[4] = net_secret[4] + (__force u32)dport;
+ for (i = 5; i < MD5_MESSAGE_BYTES / 4; i++)
+ secret[i] = net_secret[i];
+
+ md5_transform(hash, secret);
+
+ return hash[0];
+}
+#endif
+
+#ifdef CONFIG_INET
+__u32 secure_ip_id(__be32 daddr)
+{
+ u32 hash[MD5_DIGEST_WORDS];
+
+ hash[0] = (__force __u32) daddr;
+ hash[1] = net_secret[13];
+ hash[2] = net_secret[14];
+ hash[3] = net_secret[15];
+
+ md5_transform(hash, net_secret);
+
+ return hash[0];
+}
+
+__u32 secure_ipv6_id(const __be32 daddr[4])
+{
+ __u32 hash[4];
+
+ memcpy(hash, daddr, 16);
+ md5_transform(hash, net_secret);
+
+ return hash[0];
+}
+
+__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
+ __be16 sport, __be16 dport)
+{
+ u32 hash[MD5_DIGEST_WORDS];
+
+ hash[0] = (__force u32)saddr;
+ hash[1] = (__force u32)daddr;
+ hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
+ hash[3] = net_secret[15];
+
+ md5_transform(hash, net_secret);
+
+ return seq_scale(hash[0]);
+}
+
+u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport)
+{
+ u32 hash[MD5_DIGEST_WORDS];
+
+ hash[0] = (__force u32)saddr;
+ hash[1] = (__force u32)daddr;
+ hash[2] = (__force u32)dport ^ net_secret[14];
+ hash[3] = net_secret[15];
+
+ md5_transform(hash, net_secret);
+
+ return hash[0];
+}
+EXPORT_SYMBOL_GPL(secure_ipv4_port_ephemeral);
+#endif
+
+#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE)
+u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
+ __be16 sport, __be16 dport)
+{
+ u32 hash[MD5_DIGEST_WORDS];
+ u64 seq;
+
+ hash[0] = (__force u32)saddr;
+ hash[1] = (__force u32)daddr;
+ hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
+ hash[3] = net_secret[15];
+
+ md5_transform(hash, net_secret);
+
+ seq = hash[0] | (((u64)hash[1]) << 32);
+ seq += ktime_to_ns(ktime_get_real());
+ seq &= (1ull << 48) - 1;
+
+ return seq;
+}
+EXPORT_SYMBOL(secure_dccp_sequence_number);
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
+ __be16 sport, __be16 dport)
+{
+ u32 secret[MD5_MESSAGE_BYTES / 4];
+ u32 hash[MD5_DIGEST_WORDS];
+ u64 seq;
+ u32 i;
+
+ memcpy(hash, saddr, 16);
+ for (i = 0; i < 4; i++)
+ secret[i] = net_secret[i] + daddr[i];
+ secret[4] = net_secret[4] +
+ (((__force u16)sport << 16) + (__force u16)dport);
+ for (i = 5; i < MD5_MESSAGE_BYTES / 4; i++)
+ secret[i] = net_secret[i];
+
+ md5_transform(hash, secret);
+
+ seq = hash[0] | (((u64)hash[1]) << 32);
+ seq += ktime_to_ns(ktime_get_real());
+ seq &= (1ull << 48) - 1;
+
+ return seq;
+}
+EXPORT_SYMBOL(secure_dccpv6_sequence_number);
+#endif
+#endif
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 8c36adf..332639b 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -26,6 +26,7 @@
#include <net/timewait_sock.h>
#include <net/tcp_states.h>
#include <net/xfrm.h>
+#include <net/secure_seq.h>
#include "ackvec.h"
#include "ccid.h"
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 8dc4348..b74f761 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -29,6 +29,7 @@
#include <net/transp_v6.h>
#include <net/ip6_checksum.h>
#include <net/xfrm.h>
+#include <net/secure_seq.h>
#include "dccp.h"
#include "ipv6.h"
@@ -69,13 +70,7 @@
dh->dccph_checksum = dccp_v6_csum_finish(skb, &np->saddr, &np->daddr);
}
-static inline __u32 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
- __be16 sport, __be16 dport )
-{
- return secure_tcpv6_sequence_number(saddr, daddr, sport, dport);
-}
-
-static inline __u32 dccp_v6_init_sequence(struct sk_buff *skb)
+static inline __u64 dccp_v6_init_sequence(struct sk_buff *skb)
{
return secure_dccpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
ipv6_hdr(skb)->saddr.s6_addr32,
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index 44d2b42..2780e9b 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -340,6 +340,7 @@
dev->addr_len = ETH_ALEN;
dev->tx_queue_len = 1000; /* Ethernet wants good queues */
dev->flags = IFF_BROADCAST|IFF_MULTICAST;
+ dev->priv_flags = IFF_TX_SKB_SHARING;
memset(dev->broadcast, 0xFF, ETH_ALEN);
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index a829824..66439a7 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1140,15 +1140,15 @@
struct in_device *in_dev)
{
- struct in_ifaddr *ifa = in_dev->ifa_list;
+ struct in_ifaddr *ifa;
- if (!ifa)
- return;
-
- arp_send(ARPOP_REQUEST, ETH_P_ARP,
- ifa->ifa_local, dev,
- ifa->ifa_local, NULL,
- dev->dev_addr, NULL);
+ for (ifa = in_dev->ifa_list; ifa;
+ ifa = ifa->ifa_next) {
+ arp_send(ARPOP_REQUEST, ETH_P_ARP,
+ ifa->ifa_local, dev,
+ ifa->ifa_local, NULL,
+ dev->dev_addr, NULL);
+ }
}
/* Called only under RTNL semaphore */
diff --git a/net/ipv4/gre.c b/net/ipv4/gre.c
index c6933f2..3e3f75d 100644
--- a/net/ipv4/gre.c
+++ b/net/ipv4/gre.c
@@ -15,6 +15,7 @@
#include <linux/kmod.h>
#include <linux/skbuff.h>
#include <linux/in.h>
+#include <linux/ip.h>
#include <linux/netdevice.h>
#include <linux/version.h>
#include <linux/spinlock.h>
@@ -97,27 +98,17 @@
static void gre_err(struct sk_buff *skb, u32 info)
{
const struct gre_protocol *proto;
- u8 ver;
+ const struct iphdr *iph = (const struct iphdr *)skb->data;
+ u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f;
- if (!pskb_may_pull(skb, 12))
- goto drop;
-
- ver = skb->data[1]&0x7f;
if (ver >= GREPROTO_MAX)
- goto drop;
+ return;
rcu_read_lock();
proto = rcu_dereference(gre_proto[ver]);
- if (!proto || !proto->err_handler)
- goto drop_unlock;
- proto->err_handler(skb, info);
+ if (proto && proto->err_handler)
+ proto->err_handler(skb, info);
rcu_read_unlock();
- return;
-
-drop_unlock:
- rcu_read_unlock();
-drop:
- kfree_skb(skb);
}
static const struct net_protocol net_gre_protocol = {
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 5395e45..23ef31b 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -380,6 +380,7 @@
struct icmp_bxm *param)
{
struct rtable *rt, *rt2;
+ struct flowi4 fl4_dec;
int err;
memset(fl4, 0, sizeof(*fl4));
@@ -408,19 +409,19 @@
} else
return rt;
- err = xfrm_decode_session_reverse(skb_in, flowi4_to_flowi(fl4), AF_INET);
+ err = xfrm_decode_session_reverse(skb_in, flowi4_to_flowi(&fl4_dec), AF_INET);
if (err)
goto relookup_failed;
- if (inet_addr_type(net, fl4->saddr) == RTN_LOCAL) {
- rt2 = __ip_route_output_key(net, fl4);
+ if (inet_addr_type(net, fl4_dec.saddr) == RTN_LOCAL) {
+ rt2 = __ip_route_output_key(net, &fl4_dec);
if (IS_ERR(rt2))
err = PTR_ERR(rt2);
} else {
struct flowi4 fl4_2 = {};
unsigned long orefdst;
- fl4_2.daddr = fl4->saddr;
+ fl4_2.daddr = fl4_dec.saddr;
rt2 = ip_route_output_key(net, &fl4_2);
if (IS_ERR(rt2)) {
err = PTR_ERR(rt2);
@@ -428,7 +429,7 @@
}
/* Ugh! */
orefdst = skb_in->_skb_refdst; /* save old refdst */
- err = ip_route_input(skb_in, fl4->daddr, fl4->saddr,
+ err = ip_route_input(skb_in, fl4_dec.daddr, fl4_dec.saddr,
RT_TOS(tos), rt2->dst.dev);
dst_release(&rt2->dst);
@@ -440,10 +441,11 @@
goto relookup_failed;
rt2 = (struct rtable *) xfrm_lookup(net, &rt2->dst,
- flowi4_to_flowi(fl4), NULL,
+ flowi4_to_flowi(&fl4_dec), NULL,
XFRM_LOOKUP_ICMP);
if (!IS_ERR(rt2)) {
dst_release(&rt->dst);
+ memcpy(fl4, &fl4_dec, sizeof(*fl4));
rt = rt2;
} else if (PTR_ERR(rt2) == -EPERM) {
if (rt)
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index f1d27f6..d577199 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -767,7 +767,7 @@
break;
for (i=0; i<nsrcs; i++) {
/* skip inactive filters */
- if (pmc->sfcount[MCAST_INCLUDE] ||
+ if (psf->sf_count[MCAST_INCLUDE] ||
pmc->sfcount[MCAST_EXCLUDE] !=
psf->sf_count[MCAST_EXCLUDE])
continue;
@@ -1718,7 +1718,7 @@
pmc->sfcount[sfmode]--;
for (j=0; j<i; j++)
- (void) ip_mc_del1_src(pmc, sfmode, &psfsrc[i]);
+ (void) ip_mc_del1_src(pmc, sfmode, &psfsrc[j]);
} else if (isexclude != (pmc->sfcount[MCAST_EXCLUDE] != 0)) {
#ifdef CONFIG_IP_MULTICAST
struct ip_sf_list *psf;
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index 3c0369a..984ec65 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -21,6 +21,7 @@
#include <net/inet_connection_sock.h>
#include <net/inet_hashtables.h>
+#include <net/secure_seq.h>
#include <net/ip.h>
/*
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index ce616d9..6877645 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -19,6 +19,7 @@
#include <linux/net.h>
#include <net/ip.h>
#include <net/inetpeer.h>
+#include <net/secure_seq.h>
/*
* Theory of operations.
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 84f26e8..0c99db4 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -734,7 +734,7 @@
int getfrag(void *from, char *to, int offset, int len,
int odd, struct sk_buff *skb),
void *from, int length, int hh_len, int fragheaderlen,
- int transhdrlen, int mtu, unsigned int flags)
+ int transhdrlen, int maxfraglen, unsigned int flags)
{
struct sk_buff *skb;
int err;
@@ -767,7 +767,7 @@
skb->csum = 0;
/* specify the length of each IP datagram fragment */
- skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
+ skb_shinfo(skb)->gso_size = maxfraglen - fragheaderlen;
skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
__skb_queue_tail(queue, skb);
}
@@ -831,7 +831,7 @@
(rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len) {
err = ip_ufo_append_data(sk, queue, getfrag, from, length,
hh_len, fragheaderlen, transhdrlen,
- mtu, flags);
+ maxfraglen, flags);
if (err)
goto error;
return 0;
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 30a7763..f81af8d 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1796,7 +1796,7 @@
struct flowi4 fl4 = {
.daddr = iph->daddr,
.saddr = iph->saddr,
- .flowi4_tos = iph->tos,
+ .flowi4_tos = RT_TOS(iph->tos),
.flowi4_oif = rt->rt_oif,
.flowi4_iif = rt->rt_iif,
.flowi4_mark = rt->rt_mark,
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index 2e97e3e..929b27b 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -18,17 +18,15 @@
struct rtable *rt;
struct flowi4 fl4 = {};
__be32 saddr = iph->saddr;
- __u8 flags = 0;
+ __u8 flags = skb->sk ? inet_sk_flowi_flags(skb->sk) : 0;
unsigned int hh_len;
- if (!skb->sk && addr_type != RTN_LOCAL) {
- if (addr_type == RTN_UNSPEC)
- addr_type = inet_addr_type(net, saddr);
- if (addr_type == RTN_LOCAL || addr_type == RTN_UNICAST)
- flags |= FLOWI_FLAG_ANYSRC;
- else
- saddr = 0;
- }
+ if (addr_type == RTN_UNSPEC)
+ addr_type = inet_addr_type(net, saddr);
+ if (addr_type == RTN_LOCAL || addr_type == RTN_UNICAST)
+ flags |= FLOWI_FLAG_ANYSRC;
+ else
+ saddr = 0;
/* some non-standard hacks like ipt_REJECT.c:send_reset() can cause
* packets with foreign saddr to appear on the NF_INET_LOCAL_OUT hook.
@@ -38,7 +36,7 @@
fl4.flowi4_tos = RT_TOS(iph->tos);
fl4.flowi4_oif = skb->sk ? skb->sk->sk_bound_dev_if : 0;
fl4.flowi4_mark = skb->mark;
- fl4.flowi4_flags = skb->sk ? inet_sk_flowi_flags(skb->sk) : flags;
+ fl4.flowi4_flags = flags;
rt = ip_route_output_key(net, &fl4);
if (IS_ERR(rt))
return -1;
diff --git a/net/ipv4/netfilter/nf_nat_proto_common.c b/net/ipv4/netfilter/nf_nat_proto_common.c
index 3e61faf..f52d41e 100644
--- a/net/ipv4/netfilter/nf_nat_proto_common.c
+++ b/net/ipv4/netfilter/nf_nat_proto_common.c
@@ -12,6 +12,7 @@
#include <linux/ip.h>
#include <linux/netfilter.h>
+#include <net/secure_seq.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_core.h>
#include <net/netfilter/nf_nat_rule.h>
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index aa13ef1..75ef66f 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -108,6 +108,7 @@
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
#endif
+#include <net/secure_seq.h>
#define RT_FL_TOS(oldflp4) \
((u32)(oldflp4->flowi4_tos & (IPTOS_RT_MASK | RTO_ONLINK)))
@@ -716,7 +717,7 @@
{
return ((((__force u32)rt1->rt_key_dst ^ (__force u32)rt2->rt_key_dst) |
((__force u32)rt1->rt_key_src ^ (__force u32)rt2->rt_key_src) |
- (rt1->rt_iif ^ rt2->rt_iif)) == 0);
+ (rt1->rt_route_iif ^ rt2->rt_route_iif)) == 0);
}
static inline int compare_keys(struct rtable *rt1, struct rtable *rt2)
@@ -725,8 +726,8 @@
((__force u32)rt1->rt_key_src ^ (__force u32)rt2->rt_key_src) |
(rt1->rt_mark ^ rt2->rt_mark) |
(rt1->rt_key_tos ^ rt2->rt_key_tos) |
- (rt1->rt_oif ^ rt2->rt_oif) |
- (rt1->rt_iif ^ rt2->rt_iif)) == 0;
+ (rt1->rt_route_iif ^ rt2->rt_route_iif) |
+ (rt1->rt_oif ^ rt2->rt_oif)) == 0;
}
static inline int compare_netns(struct rtable *rt1, struct rtable *rt2)
@@ -1703,7 +1704,7 @@
memset(&fl4, 0, sizeof(fl4));
fl4.daddr = iph->daddr;
fl4.saddr = iph->saddr;
- fl4.flowi4_tos = iph->tos;
+ fl4.flowi4_tos = RT_TOS(iph->tos);
fl4.flowi4_oif = rt->dst.dev->ifindex;
fl4.flowi4_iif = skb->dev->ifindex;
fl4.flowi4_mark = skb->mark;
@@ -2280,8 +2281,7 @@
rth = rcu_dereference(rth->dst.rt_next)) {
if ((((__force u32)rth->rt_key_dst ^ (__force u32)daddr) |
((__force u32)rth->rt_key_src ^ (__force u32)saddr) |
- (rth->rt_iif ^ iif) |
- rth->rt_oif |
+ (rth->rt_route_iif ^ iif) |
(rth->rt_key_tos ^ tos)) == 0 &&
rth->rt_mark == skb->mark &&
net_eq(dev_net(rth->dst.dev), net) &&
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 2646149..4382629 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -276,7 +276,7 @@
int mss;
struct rtable *rt;
__u8 rcv_wscale;
- bool ecn_ok;
+ bool ecn_ok = false;
if (!sysctl_tcp_syncookies || !th->ack || th->rst)
goto out;
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index e5f1113..2dec205 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -273,6 +273,8 @@
#include <net/xfrm.h>
#include <net/ip.h>
#include <net/ip6_route.h>
+#include <net/ipv6.h>
+#include <net/transp_v6.h>
#include <net/netdma.h>
#include <net/sock.h>
@@ -3383,8 +3385,16 @@
sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[bucket].chain) {
struct inet_sock *inet = inet_sk(sk);
+ if (sysctl_ip_dynaddr && sk->sk_state == TCP_SYN_SENT)
+ continue;
+ if (sock_flag(sk, SOCK_DEAD))
+ continue;
+
if (family == AF_INET) {
__be32 s4 = inet->inet_rcv_saddr;
+ if (s4 == LOOPBACK4_IPV6)
+ continue;
+
if (in->s_addr != s4 &&
!(in->s_addr == INADDR_ANY &&
!tcp_is_local(net, s4)))
@@ -3396,7 +3406,11 @@
struct in6_addr *s6;
if (!inet->pinet6)
continue;
+
s6 = &inet->pinet6->rcv_saddr;
+ if (ipv6_addr_type(s6) == IPV6_ADDR_MAPPED)
+ continue;
+
if (!ipv6_addr_equal(in6, s6) &&
!(ipv6_addr_equal(in6, &in6addr_any) &&
!tcp_is_local6(net, s6)))
@@ -3404,11 +3418,6 @@
}
#endif
- if (sysctl_ip_dynaddr && sk->sk_state == TCP_SYN_SENT)
- continue;
- if (sock_flag(sk, SOCK_DEAD))
- continue;
-
sock_hold(sk);
spin_unlock_bh(lock);
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index bef9f04..b6771f9 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1115,7 +1115,7 @@
return 0;
/* ...Then it's D-SACK, and must reside below snd_una completely */
- if (!after(end_seq, tp->snd_una))
+ if (after(end_seq, tp->snd_una))
return 0;
if (!before(start_seq, tp->undo_marker))
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 378ddf9..33ffa13 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -72,6 +72,7 @@
#include <net/timewait_sock.h>
#include <net/xfrm.h>
#include <net/netdma.h>
+#include <net/secure_seq.h>
#include <linux/inet.h>
#include <linux/ipv6.h>
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index ab86578..7e8340e 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -1112,6 +1112,8 @@
goto out;
}
+ initialize_hashidentrnd();
+
err = proto_register(&tcpv6_prot, 1);
if (err)
goto out;
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index b531972..73f1a00 100644
--- a/net/ipv6/inet6_hashtables.c
+++ b/net/ipv6/inet6_hashtables.c
@@ -20,6 +20,7 @@
#include <net/inet_connection_sock.h>
#include <net/inet_hashtables.h>
#include <net/inet6_hashtables.h>
+#include <net/secure_seq.h>
#include <net/ip.h>
int __inet6_hash(struct sock *sk, struct inet_timewait_sock *tw)
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 77b1a28..79d6e82 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -597,6 +597,35 @@
return offset;
}
+static u32 hashidentrnd __read_mostly;
+#define FID_HASH_SZ 16
+static u32 ipv6_fragmentation_id[FID_HASH_SZ];
+
+void __init initialize_hashidentrnd(void)
+{
+ get_random_bytes(&hashidentrnd, sizeof(hashidentrnd));
+}
+
+static u32 __ipv6_select_ident(const struct in6_addr *addr)
+{
+ u32 newid, oldid, hash = jhash2((u32 *)addr, 4, hashidentrnd);
+ u32 *pid = &ipv6_fragmentation_id[hash % FID_HASH_SZ];
+
+ do {
+ oldid = *pid;
+ newid = oldid + 1;
+ if (!(hash + newid))
+ newid++;
+ } while (cmpxchg(pid, oldid, newid) != oldid);
+
+ return hash + newid;
+}
+
+void ipv6_select_ident(struct frag_hdr *fhdr, struct in6_addr *addr)
+{
+ fhdr->identification = htonl(__ipv6_select_ident(addr));
+}
+
int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
{
struct sk_buff *frag;
@@ -681,7 +710,7 @@
skb_reset_network_header(skb);
memcpy(skb_network_header(skb), tmp_hdr, hlen);
- ipv6_select_ident(fh);
+ ipv6_select_ident(fh, &rt->rt6i_dst.addr);
fh->nexthdr = nexthdr;
fh->reserved = 0;
fh->frag_off = htons(IP6_MF);
@@ -827,7 +856,7 @@
fh->nexthdr = nexthdr;
fh->reserved = 0;
if (!frag_id) {
- ipv6_select_ident(fh);
+ ipv6_select_ident(fh, &rt->rt6i_dst.addr);
frag_id = fh->identification;
} else
fh->identification = frag_id;
@@ -1073,7 +1102,8 @@
int getfrag(void *from, char *to, int offset, int len,
int odd, struct sk_buff *skb),
void *from, int length, int hh_len, int fragheaderlen,
- int transhdrlen, int mtu,unsigned int flags)
+ int transhdrlen, int mtu,unsigned int flags,
+ struct rt6_info *rt)
{
struct sk_buff *skb;
@@ -1117,7 +1147,7 @@
skb_shinfo(skb)->gso_size = (mtu - fragheaderlen -
sizeof(struct frag_hdr)) & ~7;
skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
- ipv6_select_ident(&fhdr);
+ ipv6_select_ident(&fhdr, &rt->rt6i_dst.addr);
skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
__skb_queue_tail(&sk->sk_write_queue, skb);
@@ -1283,7 +1313,7 @@
err = ip6_ufo_append_data(sk, getfrag, from, length,
hh_len, fragheaderlen,
- transhdrlen, mtu, flags);
+ transhdrlen, mtu, flags, rt);
if (err)
goto error;
return 0;
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 9cb191e..147ede38 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -913,7 +913,7 @@
}
static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
- char __user *optval, int __user *optlen)
+ char __user *optval, int __user *optlen, unsigned flags)
{
struct ipv6_pinfo *np = inet6_sk(sk);
int len;
@@ -962,7 +962,7 @@
msg.msg_control = optval;
msg.msg_controllen = len;
- msg.msg_flags = 0;
+ msg.msg_flags = flags;
lock_sock(sk);
skb = np->pktoptions;
@@ -1222,7 +1222,7 @@
if(level != SOL_IPV6)
return -ENOPROTOOPT;
- err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
+ err = do_ipv6_getsockopt(sk, level, optname, optval, optlen, 0);
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default case */
if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) {
@@ -1264,7 +1264,8 @@
return compat_mc_getsockopt(sk, level, optname, optval, optlen,
ipv6_getsockopt);
- err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
+ err = do_ipv6_getsockopt(sk, level, optname, optval, optlen,
+ MSG_CMSG_COMPAT);
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default case */
if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) {
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 3e6ebcd..ee7839f 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -1059,7 +1059,7 @@
break;
for (i=0; i<nsrcs; i++) {
/* skip inactive filters */
- if (pmc->mca_sfcount[MCAST_INCLUDE] ||
+ if (psf->sf_count[MCAST_INCLUDE] ||
pmc->mca_sfcount[MCAST_EXCLUDE] !=
psf->sf_count[MCAST_EXCLUDE])
continue;
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 94874b0..14cb310 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -2292,16 +2292,15 @@
* "No next header".
*
* If target header is found, its offset is set in *offset and return protocol
- * number. Otherwise, return -1.
+ * number. Otherwise, return -ENOENT or -EBADMSG.
*
* If the first fragment doesn't contain the final protocol header or
* NEXTHDR_NONE it is considered invalid.
*
* Note that non-1st fragment is special case that "the protocol number
* of last header" is "next header" field in Fragment header. In this case,
- * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
- * isn't NULL.
- *
+ * *offset is meaningless. If fragoff is not NULL, the fragment offset is
+ * stored in *fragoff; if it is NULL, return -EINVAL.
*/
int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
int target, unsigned short *fragoff)
@@ -2342,9 +2341,12 @@
if (target < 0 &&
((!ipv6_ext_hdr(hp->nexthdr)) ||
hp->nexthdr == NEXTHDR_NONE)) {
- if (fragoff)
+ if (fragoff) {
*fragoff = _frag_off;
- return hp->nexthdr;
+ return hp->nexthdr;
+ } else {
+ return -EINVAL;
+ }
}
return -ENOENT;
}
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 8b9644a..14b8339 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -165,7 +165,7 @@
int mss;
struct dst_entry *dst;
__u8 rcv_wscale;
- bool ecn_ok;
+ bool ecn_ok = false;
if (!sysctl_tcp_syncookies || !th->ack || th->rst)
goto out;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 87551ca..7c43e86 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -61,6 +61,7 @@
#include <net/timewait_sock.h>
#include <net/netdma.h>
#include <net/inet_common.h>
+#include <net/secure_seq.h>
#include <asm/uaccess.h>
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 328985c..0d920c5 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1309,6 +1309,7 @@
u8 frag_hdr_sz = sizeof(struct frag_hdr);
int offset;
__wsum csum;
+ struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
mss = skb_shinfo(skb)->gso_size;
if (unlikely(skb->len <= mss))
@@ -1359,7 +1360,8 @@
fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
fptr->nexthdr = nexthdr;
fptr->reserved = 0;
- ipv6_select_ident(fptr);
+ ipv6_select_ident(fptr,
+ rt ? &rt->rt6i_dst.addr : &ipv6_hdr(skb)->daddr);
/* Fragment the skb. ipv6 header and the remaining fields of the
* fragment header are updated in ipv6_gso_segment()
diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c
index a8193f5..d2726a7 100644
--- a/net/l2tp/l2tp_eth.c
+++ b/net/l2tp/l2tp_eth.c
@@ -103,7 +103,7 @@
static void l2tp_eth_dev_setup(struct net_device *dev)
{
ether_setup(dev);
-
+ dev->priv_flags &= ~IFF_TX_SKB_SHARING;
dev->netdev_ops = &l2tp_eth_netdev_ops;
dev->destructor = free_netdev;
}
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index dee30ae..895eec1 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -699,6 +699,7 @@
static void ieee80211_if_setup(struct net_device *dev)
{
ether_setup(dev);
+ dev->priv_flags &= ~IFF_TX_SKB_SHARING;
dev->netdev_ops = &ieee80211_dataif_ops;
dev->destructor = free_netdev;
}
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index b83870b..ca7bf10 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -669,7 +669,7 @@
BUG_ON(!sdata->bss);
atomic_dec(&sdata->bss->num_sta_ps);
- __sta_info_clear_tim_bit(sdata->bss, sta);
+ sta_info_clear_tim_bit(sta);
}
local->num_sta--;
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 8b658ef..6d91717 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -95,7 +95,7 @@
obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o
obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o
obj-$(CONFIG_NETFILTER_XT_MATCH_POLICY) += xt_policy.o
-obj-$(CONFIG_NETFILTER_XT_MATCH_QTAGUID) += xt_qtaguid.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_QTAGUID) += xt_qtaguid_print.o xt_qtaguid.o
obj-$(CONFIG_NETFILTER_XT_MATCH_QUOTA) += xt_quota.o
obj-$(CONFIG_NETFILTER_XT_MATCH_QUOTA2) += xt_quota2.o
obj-$(CONFIG_NETFILTER_XT_MATCH_RATEEST) += xt_rateest.o
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 699c79a..a178cb3 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -3771,6 +3771,7 @@
void ip_vs_control_cleanup(void)
{
EnterFunction(2);
+ unregister_netdevice_notifier(&ip_vs_dst_notifier);
ip_vs_genl_unregister();
nf_unregister_sockopt(&ip_vs_sockopts);
LeaveFunction(2);
diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c
index 80b5990..08086d6 100644
--- a/net/netfilter/xt_qtaguid.c
+++ b/net/netfilter/xt_qtaguid.c
@@ -8,36 +8,11 @@
* published by the Free Software Foundation.
*/
-/* #define DEBUG */
-/* #define IDEBUG */
-/* #define MDEBUG */
-/* #define RDEBUG */
-/* #define CDEBUG */
-
-/* Iface handling */
-#ifdef IDEBUG
-#define IF_DEBUG(...) pr_debug(__VA_ARGS__)
-#else
-#define IF_DEBUG(...) no_printk(__VA_ARGS__)
-#endif
-/* Iptable Matching */
-#ifdef MDEBUG
-#define MT_DEBUG(...) pr_debug(__VA_ARGS__)
-#else
-#define MT_DEBUG(...) no_printk(__VA_ARGS__)
-#endif
-/* Red-black tree handling */
-#ifdef RDEBUG
-#define RB_DEBUG(...) pr_debug(__VA_ARGS__)
-#else
-#define RB_DEBUG(...) no_printk(__VA_ARGS__)
-#endif
-/* procfs ctrl/stats handling */
-#ifdef CDEBUG
-#define CT_DEBUG(...) pr_debug(__VA_ARGS__)
-#else
-#define CT_DEBUG(...) no_printk(__VA_ARGS__)
-#endif
+/*
+ * There are run-time debug flags enabled via the debug_mask module param, or
+ * via the DEFAULT_DEBUG_MASK. See xt_qtaguid_internal.h.
+ */
+#define DEBUG
#include <linux/file.h>
#include <linux/inetdevice.h>
@@ -52,6 +27,9 @@
#include <net/udp.h>
#include <linux/netfilter/xt_socket.h>
+#include "xt_qtaguid_internal.h"
+#include "xt_qtaguid_print.h"
+
/*
* We only use the xt_socket funcs within a similar context to avoid unexpected
* return values.
@@ -93,201 +71,181 @@
S_IRUGO | S_IWUSR);
/*
+ * Limit the number of active tags (via socket tags) for a given UID.
+ * Multiple processes could share the UID.
+ */
+static int max_sock_tags = DEFAULT_MAX_SOCK_TAGS;
+module_param(max_sock_tags, int, S_IRUGO | S_IWUSR);
+
+/*
* After the kernel has initiallized this module, it is still possible
- * to make it passive:
- * - do not register it via iptables.
- * the matching code will not be invoked.
- * - set passive to 0
- * the iface stats handling will not be act on notifications.
+ * to make it passive.
+ * Setting passive to Y:
+ * - the iface stats handling will not act on notifications.
+ * - iptables matches will never match.
+ * - ctrl commands silently succeed.
+ * - stats are always empty.
* This is mostly usefull when a bug is suspected.
*/
static bool module_passive;
module_param_named(passive, module_passive, bool, S_IRUGO | S_IWUSR);
-/*---------------------------------------------------------------------------*/
/*
- * Tags:
- *
- * They represent what the data usage counters will be tracked against.
- * By default a tag is just based on the UID.
- * The UID is used as the base for policying, and can not be ignored.
- * So a tag will always at least represent a UID (uid_tag).
- *
- * A tag can be augmented with an "accounting tag" which is associated
- * with a UID.
- * User space can set the acct_tag portion of the tag which is then used
- * with sockets: all data belong to that socket will be counted against the
- * tag. The policing is then based on the tag's uid_tag portion,
- * and stats are collected for the acct_tag portion seperately.
- *
- * There could be
- * a: {acct_tag=1, uid_tag=10003}
- * b: {acct_tag=2, uid_tag=10003}
- * c: {acct_tag=3, uid_tag=10003}
- * d: {acct_tag=0, uid_tag=10003}
- * (a, b, and c represent tags associated with specific sockets.
- * d is for the totals for that uid, including all untagged traffic.
- * Typically d is used with policing/quota rules.
- *
- * We want tag_t big enough to distinguish uid_t and acct_tag.
- * It might become a struct if needed.
- * Nothing should be using it as an int.
+ * Control how qtaguid data is tracked per proc/uid.
+ * Setting tag_tracking_passive to Y:
+ * - don't create proc specific structs to track tags
+ * - don't check that active tag stats exceed some limits.
+ * - don't clean up socket tags on process exits.
+ * This is mostly usefull when a bug is suspected.
*/
-typedef uint64_t tag_t; /* Only used via accessors */
+static bool qtu_proc_handling_passive;
+module_param_named(tag_tracking_passive, qtu_proc_handling_passive, bool,
+ S_IRUGO | S_IWUSR);
+#define QTU_DEV_NAME "xt_qtaguid"
+
+uint qtaguid_debug_mask = DEFAULT_DEBUG_MASK;
+module_param_named(debug_mask, qtaguid_debug_mask, uint, S_IRUGO | S_IWUSR);
+
+/*---------------------------------------------------------------------------*/
static const char *iface_stat_procdirname = "iface_stat";
static struct proc_dir_entry *iface_stat_procdir;
-
+static const char *iface_stat_all_procfilename = "iface_stat_all";
+static struct proc_dir_entry *iface_stat_all_procfile;
/*
- * For now we only track 2 sets of counters.
- * The default set is 0.
- * Userspace can activate another set for a given uid being tracked.
+ * Ordering of locks:
+ * outer locks:
+ * iface_stat_list_lock
+ * sock_tag_list_lock
+ * inner locks:
+ * uid_tag_data_tree_lock
+ * tag_counter_set_list_lock
+ * Notice how sock_tag_list_lock is held sometimes when uid_tag_data_tree_lock
+ * is acquired.
+ *
+ * Call tree with all lock holders as of 2011-09-25:
+ *
+ * iface_stat_all_proc_read()
+ * iface_stat_list_lock
+ * (struct iface_stat)
+ *
+ * qtaguid_ctrl_proc_read()
+ * sock_tag_list_lock
+ * (sock_tag_tree)
+ * (struct proc_qtu_data->sock_tag_list)
+ * prdebug_full_state()
+ * sock_tag_list_lock
+ * (sock_tag_tree)
+ * uid_tag_data_tree_lock
+ * (uid_tag_data_tree)
+ * (proc_qtu_data_tree)
+ * iface_stat_list_lock
+ *
+ * qtaguid_stats_proc_read()
+ * iface_stat_list_lock
+ * struct iface_stat->tag_stat_list_lock
+ *
+ * qtudev_open()
+ * uid_tag_data_tree_lock
+ *
+ * qtudev_release()
+ * sock_tag_data_list_lock
+ * uid_tag_data_tree_lock
+ * prdebug_full_state()
+ * sock_tag_list_lock
+ * uid_tag_data_tree_lock
+ * iface_stat_list_lock
+ *
+ * iface_netdev_event_handler()
+ * iface_stat_create()
+ * iface_stat_list_lock
+ * iface_stat_update()
+ * iface_stat_list_lock
+ *
+ * iface_inetaddr_event_handler()
+ * iface_stat_create()
+ * iface_stat_list_lock
+ * iface_stat_update()
+ * iface_stat_list_lock
+ *
+ * iface_inet6addr_event_handler()
+ * iface_stat_create_ipv6()
+ * iface_stat_list_lock
+ * iface_stat_update()
+ * iface_stat_list_lock
+ *
+ * qtaguid_mt()
+ * account_for_uid()
+ * if_tag_stat_update()
+ * get_sock_stat()
+ * sock_tag_list_lock
+ * struct iface_stat->tag_stat_list_lock
+ * tag_stat_update()
+ * get_active_counter_set()
+ * tag_counter_set_list_lock
+ * tag_stat_update()
+ * get_active_counter_set()
+ * tag_counter_set_list_lock
+ *
+ *
+ * qtaguid_ctrl_parse()
+ * ctrl_cmd_delete()
+ * sock_tag_list_lock
+ * tag_counter_set_list_lock
+ * iface_stat_list_lock
+ * struct iface_stat->tag_stat_list_lock
+ * uid_tag_data_tree_lock
+ * ctrl_cmd_counter_set()
+ * tag_counter_set_list_lock
+ * ctrl_cmd_tag()
+ * sock_tag_list_lock
+ * (sock_tag_tree)
+ * get_tag_ref()
+ * uid_tag_data_tree_lock
+ * (uid_tag_data_tree)
+ * uid_tag_data_tree_lock
+ * (proc_qtu_data_tree)
+ * ctrl_cmd_untag()
+ * sock_tag_list_lock
+ * uid_tag_data_tree_lock
+ *
*/
-#define IFS_MAX_COUNTER_SETS 2
-
-enum ifs_tx_rx {
- IFS_TX,
- IFS_RX,
- IFS_MAX_DIRECTIONS
-};
-
-/* For now, TCP, UDP, the rest */
-enum ifs_proto {
- IFS_TCP,
- IFS_UDP,
- IFS_PROTO_OTHER,
- IFS_MAX_PROTOS
-};
-
-struct byte_packet_counters {
- uint64_t bytes;
- uint64_t packets;
-};
-
-struct data_counters {
- struct byte_packet_counters bpc[IFS_MAX_COUNTER_SETS][IFS_MAX_DIRECTIONS][IFS_MAX_PROTOS];
-};
-
-/* Generic tag based node used as a base for rb_tree ops. */
-struct tag_node {
- struct rb_node node;
- tag_t tag;
-};
-
-struct tag_stat {
- struct tag_node tn;
- struct data_counters counters;
- /*
- * If this tag is acct_tag based, we need to count against the
- * matching parent uid_tag.
- */
- struct data_counters *parent_counters;
-};
-
-struct iface_stat {
- struct list_head list;
- char *ifname;
- uint64_t rx_bytes;
- uint64_t rx_packets;
- uint64_t tx_bytes;
- uint64_t tx_packets;
- bool active;
- struct proc_dir_entry *proc_ptr;
-
- struct rb_root tag_stat_tree;
- spinlock_t tag_stat_list_lock;
-};
-
static LIST_HEAD(iface_stat_list);
static DEFINE_SPINLOCK(iface_stat_list_lock);
-/* This is needed to create proc_dir_entries from atomic context. */
-struct iface_stat_work {
- struct work_struct iface_work;
- struct iface_stat *iface_entry;
-};
-
-/*
- * Track tag that this socket is transferring data for, and not necessarily
- * the uid that owns the socket.
- * This is the tag against which tag_stat.counters will be billed.
- */
-struct sock_tag {
- struct rb_node sock_node;
- struct sock *sk; /* Only used as a number, never dereferenced */
- /* The socket is needed for sockfd_put() */
- struct socket *socket;
-
- tag_t tag;
-};
-
-struct qtaguid_event_counts {
- /* Various successful events */
- atomic64_t sockets_tagged;
- atomic64_t sockets_untagged;
- atomic64_t counter_set_changes;
- atomic64_t delete_cmds;
- atomic64_t iface_events; /* Number of NETDEV_* events handled */
- /*
- * match_found_sk_*: numbers related to the netfilter matching
- * function finding a sock for the sk_buff.
- */
- atomic64_t match_found_sk; /* An sk was already in the sk_buff. */
- /* The connection tracker had the sk. */
- atomic64_t match_found_sk_in_ct;
- /*
- * No sk could be found. No apparent owner. Could happen with
- * unsolicited traffic.
- */
- atomic64_t match_found_sk_none;
-};
-static struct qtaguid_event_counts qtu_events;
-
static struct rb_root sock_tag_tree = RB_ROOT;
static DEFINE_SPINLOCK(sock_tag_list_lock);
-/* Track the set active_set for the given tag. */
-struct tag_counter_set {
- struct tag_node tn;
- int active_set;
-};
-
static struct rb_root tag_counter_set_tree = RB_ROOT;
static DEFINE_SPINLOCK(tag_counter_set_list_lock);
-static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par);
+static struct rb_root uid_tag_data_tree = RB_ROOT;
+static DEFINE_SPINLOCK(uid_tag_data_tree_lock);
+static struct rb_root proc_qtu_data_tree = RB_ROOT;
+/* No proc_qtu_data_tree_lock; use uid_tag_data_tree_lock */
+
+static struct qtaguid_event_counts qtu_events;
/*----------------------------------------------*/
-static inline int tag_compare(tag_t t1, tag_t t2)
+static bool can_manipulate_uids(void)
{
- return t1 < t2 ? -1 : t1 == t2 ? 0 : 1;
+ /* root pwnd */
+ return unlikely(!current_fsuid()) || unlikely(!proc_ctrl_write_gid)
+ || in_egroup_p(proc_ctrl_write_gid);
}
-static inline tag_t combine_atag_with_uid(tag_t acct_tag, uid_t uid)
+static bool can_impersonate_uid(uid_t uid)
{
- return acct_tag | uid;
-}
-static inline tag_t make_tag_from_uid(uid_t uid)
-{
- return uid;
-}
-static inline uid_t get_uid_from_tag(tag_t tag)
-{
- return tag & 0xFFFFFFFFULL;
-}
-static inline tag_t get_utag_from_tag(tag_t tag)
-{
- return tag & 0xFFFFFFFFULL;
-}
-static inline tag_t get_atag_from_tag(tag_t tag)
-{
- return tag & ~0xFFFFFFFFULL;
+ return uid == current_fsuid() || can_manipulate_uids();
}
-static inline bool valid_atag(tag_t tag)
+static bool can_read_other_uid_stats(uid_t uid)
{
- return !(tag & 0xFFFFFFFFULL);
+ /* root pwnd */
+ return unlikely(!current_fsuid()) || uid == current_fsuid()
+ || unlikely(!proc_stats_readall_gid)
+ || in_egroup_p(proc_stats_readall_gid);
}
static inline void dc_add_byte_packets(struct data_counters *counters, int set,
@@ -324,12 +282,13 @@
while (node) {
struct tag_node *data = rb_entry(node, struct tag_node, node);
- int result = tag_compare(tag, data->tag);
- RB_DEBUG("qtaguid: tag_node_tree_search(): tag=0x%llx"
- " (uid=%d)\n",
- data->tag,
- get_uid_from_tag(data->tag));
-
+ int result;
+ RB_DEBUG("qtaguid: tag_node_tree_search(0x%llx): "
+ " node=%p data=%p\n", tag, node, data);
+ result = tag_compare(tag, data->tag);
+ RB_DEBUG("qtaguid: tag_node_tree_search(0x%llx): "
+ " data.tag=0x%llx (uid=%u) res=%d\n",
+ tag, data->tag, get_uid_from_tag(data->tag), result);
if (result < 0)
node = node->rb_left;
else if (result > 0)
@@ -349,8 +308,8 @@
struct tag_node *this = rb_entry(*new, struct tag_node,
node);
int result = tag_compare(data->tag, this->tag);
- RB_DEBUG("qtaguid: tag_node_tree_insert(): tag=0x%llx"
- " (uid=%d)\n",
+ RB_DEBUG("qtaguid: %s(): tag=0x%llx"
+ " (uid=%u)\n", __func__,
this->tag,
get_uid_from_tag(this->tag));
parent = *new;
@@ -396,6 +355,19 @@
}
+static void tag_ref_tree_insert(struct tag_ref *data, struct rb_root *root)
+{
+ tag_node_tree_insert(&data->tn, root);
+}
+
+static struct tag_ref *tag_ref_tree_search(struct rb_root *root, tag_t tag)
+{
+ struct tag_node *node = tag_node_tree_search(root, tag);
+ if (!node)
+ return NULL;
+ return rb_entry(&node->node, struct tag_ref, tn.node);
+}
+
static struct sock_tag *sock_tag_tree_search(struct rb_root *root,
const struct sock *sk)
{
@@ -404,10 +376,9 @@
while (node) {
struct sock_tag *data = rb_entry(node, struct sock_tag,
sock_node);
- ptrdiff_t result = sk - data->sk;
- if (result < 0)
+ if (sk < data->sk)
node = node->rb_left;
- else if (result > 0)
+ else if (sk > data->sk)
node = node->rb_right;
else
return data;
@@ -423,11 +394,10 @@
while (*new) {
struct sock_tag *this = rb_entry(*new, struct sock_tag,
sock_node);
- ptrdiff_t result = data->sk - this->sk;
parent = *new;
- if (result < 0)
+ if (data->sk < this->sk)
new = &((*new)->rb_left);
- else if (result > 0)
+ else if (data->sk > this->sk)
new = &((*new)->rb_right);
else
BUG();
@@ -438,6 +408,295 @@
rb_insert_color(&data->sock_node, root);
}
+static void sock_tag_tree_erase(struct rb_root *st_to_free_tree)
+{
+ struct rb_node *node;
+ struct sock_tag *st_entry;
+
+ node = rb_first(st_to_free_tree);
+ while (node) {
+ st_entry = rb_entry(node, struct sock_tag, sock_node);
+ node = rb_next(node);
+ CT_DEBUG("qtaguid: %s(): "
+ "erase st: sk=%p tag=0x%llx (uid=%u)\n", __func__,
+ st_entry->sk,
+ st_entry->tag,
+ get_uid_from_tag(st_entry->tag));
+ rb_erase(&st_entry->sock_node, st_to_free_tree);
+ sockfd_put(st_entry->socket);
+ kfree(st_entry);
+ }
+}
+
+static struct proc_qtu_data *proc_qtu_data_tree_search(struct rb_root *root,
+ const pid_t pid)
+{
+ struct rb_node *node = root->rb_node;
+
+ while (node) {
+ struct proc_qtu_data *data = rb_entry(node,
+ struct proc_qtu_data,
+ node);
+ if (pid < data->pid)
+ node = node->rb_left;
+ else if (pid > data->pid)
+ node = node->rb_right;
+ else
+ return data;
+ }
+ return NULL;
+}
+
+static void proc_qtu_data_tree_insert(struct proc_qtu_data *data,
+ struct rb_root *root)
+{
+ struct rb_node **new = &(root->rb_node), *parent = NULL;
+
+ /* Figure out where to put new node */
+ while (*new) {
+ struct proc_qtu_data *this = rb_entry(*new,
+ struct proc_qtu_data,
+ node);
+ parent = *new;
+ if (data->pid < this->pid)
+ new = &((*new)->rb_left);
+ else if (data->pid > this->pid)
+ new = &((*new)->rb_right);
+ else
+ BUG();
+ }
+
+ /* Add new node and rebalance tree. */
+ rb_link_node(&data->node, parent, new);
+ rb_insert_color(&data->node, root);
+}
+
+static void uid_tag_data_tree_insert(struct uid_tag_data *data,
+ struct rb_root *root)
+{
+ struct rb_node **new = &(root->rb_node), *parent = NULL;
+
+ /* Figure out where to put new node */
+ while (*new) {
+ struct uid_tag_data *this = rb_entry(*new,
+ struct uid_tag_data,
+ node);
+ parent = *new;
+ if (data->uid < this->uid)
+ new = &((*new)->rb_left);
+ else if (data->uid > this->uid)
+ new = &((*new)->rb_right);
+ else
+ BUG();
+ }
+
+ /* Add new node and rebalance tree. */
+ rb_link_node(&data->node, parent, new);
+ rb_insert_color(&data->node, root);
+}
+
+static struct uid_tag_data *uid_tag_data_tree_search(struct rb_root *root,
+ uid_t uid)
+{
+ struct rb_node *node = root->rb_node;
+
+ while (node) {
+ struct uid_tag_data *data = rb_entry(node,
+ struct uid_tag_data,
+ node);
+ if (uid < data->uid)
+ node = node->rb_left;
+ else if (uid > data->uid)
+ node = node->rb_right;
+ else
+ return data;
+ }
+ return NULL;
+}
+
+/*
+ * Allocates a new uid_tag_data struct if needed.
+ * Returns a pointer to the found or allocated uid_tag_data.
+ * Returns a PTR_ERR on failures, and lock is not held.
+ * If found is not NULL:
+ * sets *found to true if not allocated.
+ * sets *found to false if allocated.
+ */
+struct uid_tag_data *get_uid_data(uid_t uid, bool *found_res)
+{
+ struct uid_tag_data *utd_entry;
+
+ /* Look for top level uid_tag_data for the UID */
+ utd_entry = uid_tag_data_tree_search(&uid_tag_data_tree, uid);
+ DR_DEBUG("qtaguid: get_uid_data(%u) utd=%p\n", uid, utd_entry);
+
+ if (found_res)
+ *found_res = utd_entry;
+ if (utd_entry)
+ return utd_entry;
+
+ utd_entry = kzalloc(sizeof(*utd_entry), GFP_ATOMIC);
+ if (!utd_entry) {
+ pr_err("qtaguid: get_uid_data(%u): "
+ "tag data alloc failed\n", uid);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ utd_entry->uid = uid;
+ utd_entry->tag_ref_tree = RB_ROOT;
+ uid_tag_data_tree_insert(utd_entry, &uid_tag_data_tree);
+ DR_DEBUG("qtaguid: get_uid_data(%u) new utd=%p\n", uid, utd_entry);
+ return utd_entry;
+}
+
+/* Never returns NULL. Either PTR_ERR or a valid ptr. */
+static struct tag_ref *new_tag_ref(tag_t new_tag,
+ struct uid_tag_data *utd_entry)
+{
+ struct tag_ref *tr_entry;
+ int res;
+
+ if (utd_entry->num_active_tags + 1 > max_sock_tags) {
+ pr_info("qtaguid: new_tag_ref(0x%llx): "
+ "tag ref alloc quota exceeded. max=%d\n",
+ new_tag, max_sock_tags);
+ res = -EMFILE;
+ goto err_res;
+
+ }
+
+ tr_entry = kzalloc(sizeof(*tr_entry), GFP_ATOMIC);
+ if (!tr_entry) {
+ pr_err("qtaguid: new_tag_ref(0x%llx): "
+ "tag ref alloc failed\n",
+ new_tag);
+ res = -ENOMEM;
+ goto err_res;
+ }
+ tr_entry->tn.tag = new_tag;
+ /* tr_entry->num_sock_tags handled by caller */
+ utd_entry->num_active_tags++;
+ tag_ref_tree_insert(tr_entry, &utd_entry->tag_ref_tree);
+ DR_DEBUG("qtaguid: new_tag_ref(0x%llx): "
+ " inserted new tag ref %p\n",
+ new_tag, tr_entry);
+ return tr_entry;
+
+err_res:
+ return ERR_PTR(res);
+}
+
+static struct tag_ref *lookup_tag_ref(tag_t full_tag,
+ struct uid_tag_data **utd_res)
+{
+ struct uid_tag_data *utd_entry;
+ struct tag_ref *tr_entry;
+ bool found_utd;
+ uid_t uid = get_uid_from_tag(full_tag);
+
+ DR_DEBUG("qtaguid: lookup_tag_ref(tag=0x%llx (uid=%u))\n",
+ full_tag, uid);
+
+ utd_entry = get_uid_data(uid, &found_utd);
+ if (IS_ERR_OR_NULL(utd_entry)) {
+ if (utd_res)
+ *utd_res = utd_entry;
+ return NULL;
+ }
+
+ tr_entry = tag_ref_tree_search(&utd_entry->tag_ref_tree, full_tag);
+ if (utd_res)
+ *utd_res = utd_entry;
+ DR_DEBUG("qtaguid: lookup_tag_ref(0x%llx) utd_entry=%p tr_entry=%p\n",
+ full_tag, utd_entry, tr_entry);
+ return tr_entry;
+}
+
+/* Never returns NULL. Either PTR_ERR or a valid ptr. */
+static struct tag_ref *get_tag_ref(tag_t full_tag,
+ struct uid_tag_data **utd_res)
+{
+ struct uid_tag_data *utd_entry;
+ struct tag_ref *tr_entry;
+
+ DR_DEBUG("qtaguid: get_tag_ref(0x%llx)\n",
+ full_tag);
+ spin_lock_bh(&uid_tag_data_tree_lock);
+ tr_entry = lookup_tag_ref(full_tag, &utd_entry);
+ BUG_ON(IS_ERR_OR_NULL(utd_entry));
+ if (!tr_entry)
+ tr_entry = new_tag_ref(full_tag, utd_entry);
+
+ spin_unlock_bh(&uid_tag_data_tree_lock);
+ if (utd_res)
+ *utd_res = utd_entry;
+ DR_DEBUG("qtaguid: get_tag_ref(0x%llx) utd=%p tr=%p\n",
+ full_tag, utd_entry, tr_entry);
+ return tr_entry;
+}
+
+/* Checks and maybe frees the UID Tag Data entry */
+static void put_utd_entry(struct uid_tag_data *utd_entry)
+{
+ /* Are we done with the UID tag data entry? */
+ if (RB_EMPTY_ROOT(&utd_entry->tag_ref_tree) &&
+ !utd_entry->num_pqd) {
+ DR_DEBUG("qtaguid: %s(): "
+ "erase utd_entry=%p uid=%u "
+ "by pid=%u tgid=%u uid=%u\n", __func__,
+ utd_entry, utd_entry->uid,
+ current->pid, current->tgid, current_fsuid());
+ BUG_ON(utd_entry->num_active_tags);
+ rb_erase(&utd_entry->node, &uid_tag_data_tree);
+ kfree(utd_entry);
+ } else {
+ DR_DEBUG("qtaguid: %s(): "
+ "utd_entry=%p still has %d tags %d proc_qtu_data\n",
+ __func__, utd_entry, utd_entry->num_active_tags,
+ utd_entry->num_pqd);
+ BUG_ON(!(utd_entry->num_active_tags ||
+ utd_entry->num_pqd));
+ }
+}
+
+/*
+ * If no sock_tags are using this tag_ref,
+ * decrements refcount of utd_entry, removes tr_entry
+ * from utd_entry->tag_ref_tree and frees.
+ */
+static void free_tag_ref_from_utd_entry(struct tag_ref *tr_entry,
+ struct uid_tag_data *utd_entry)
+{
+ DR_DEBUG("qtaguid: %s(): %p tag=0x%llx (uid=%u)\n", __func__,
+ tr_entry, tr_entry->tn.tag,
+ get_uid_from_tag(tr_entry->tn.tag));
+ if (!tr_entry->num_sock_tags) {
+ BUG_ON(!utd_entry->num_active_tags);
+ utd_entry->num_active_tags--;
+ rb_erase(&tr_entry->tn.node, &utd_entry->tag_ref_tree);
+ DR_DEBUG("qtaguid: %s(): erased %p\n", __func__, tr_entry);
+ kfree(tr_entry);
+ }
+}
+
+static void put_tag_ref_tree(tag_t full_tag, struct uid_tag_data *utd_entry)
+{
+ struct rb_node *node;
+ struct tag_ref *tr_entry;
+ tag_t acct_tag;
+
+ DR_DEBUG("qtaguid: %s(tag=0x%llx (uid=%u))\n", __func__,
+ full_tag, get_uid_from_tag(full_tag));
+ acct_tag = get_atag_from_tag(full_tag);
+ node = rb_first(&utd_entry->tag_ref_tree);
+ while (node) {
+ tr_entry = rb_entry(node, struct tag_ref, tn.node);
+ node = rb_next(node);
+ if (!acct_tag || tr_entry->tn.tag == full_tag)
+ free_tag_ref_from_utd_entry(tr_entry, utd_entry);
+ }
+}
+
static int read_proc_u64(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
@@ -518,6 +777,72 @@
return iface_entry;
}
+static int iface_stat_all_proc_read(char *page, char **num_items_returned,
+ off_t items_to_skip, int char_count,
+ int *eof, void *data)
+{
+ char *outp = page;
+ int item_index = 0;
+ int len;
+ struct iface_stat *iface_entry;
+ struct rtnl_link_stats64 dev_stats, *stats;
+ struct rtnl_link_stats64 no_dev_stats = {0};
+
+ if (unlikely(module_passive)) {
+ *eof = 1;
+ return 0;
+ }
+
+ CT_DEBUG("qtaguid:proc iface_stat_all "
+ "page=%p *num_items_returned=%p off=%ld "
+ "char_count=%d *eof=%d\n", page, *num_items_returned,
+ items_to_skip, char_count, *eof);
+
+ if (*eof)
+ return 0;
+
+ /*
+ * This lock will prevent iface_stat_update() from changing active,
+ * and in turn prevent an interface from unregistering itself.
+ */
+ spin_lock_bh(&iface_stat_list_lock);
+ list_for_each_entry(iface_entry, &iface_stat_list, list) {
+ if (item_index++ < items_to_skip)
+ continue;
+
+ if (iface_entry->active) {
+ stats = dev_get_stats(iface_entry->net_dev,
+ &dev_stats);
+ } else {
+ stats = &no_dev_stats;
+ }
+ len = snprintf(outp, char_count,
+ "%s %d "
+ "%llu %llu %llu %llu "
+ "%llu %llu %llu %llu\n",
+ iface_entry->ifname,
+ iface_entry->active,
+ iface_entry->totals[IFS_RX].bytes,
+ iface_entry->totals[IFS_RX].packets,
+ iface_entry->totals[IFS_TX].bytes,
+ iface_entry->totals[IFS_TX].packets,
+ stats->rx_bytes, stats->rx_packets,
+ stats->tx_bytes, stats->tx_packets);
+ if (len >= char_count) {
+ spin_unlock_bh(&iface_stat_list_lock);
+ *outp = '\0';
+ return outp - page;
+ }
+ outp += len;
+ char_count -= len;
+ (*num_items_returned)++;
+ }
+ spin_unlock_bh(&iface_stat_list_lock);
+
+ *eof = 1;
+ return outp - page;
+}
+
static void iface_create_proc_worker(struct work_struct *work)
{
struct proc_dir_entry *proc_entry;
@@ -536,13 +861,13 @@
new_iface->proc_ptr = proc_entry;
create_proc_read_entry("tx_bytes", proc_iface_perms, proc_entry,
- read_proc_u64, &new_iface->tx_bytes);
+ read_proc_u64, &new_iface->totals[IFS_TX].bytes);
create_proc_read_entry("rx_bytes", proc_iface_perms, proc_entry,
- read_proc_u64, &new_iface->rx_bytes);
+ read_proc_u64, &new_iface->totals[IFS_RX].bytes);
create_proc_read_entry("tx_packets", proc_iface_perms, proc_entry,
- read_proc_u64, &new_iface->tx_packets);
+ read_proc_u64, &new_iface->totals[IFS_TX].packets);
create_proc_read_entry("rx_packets", proc_iface_perms, proc_entry,
- read_proc_u64, &new_iface->rx_packets);
+ read_proc_u64, &new_iface->totals[IFS_RX].packets);
create_proc_read_entry("active", proc_iface_perms, proc_entry,
read_proc_bool, &new_iface->active);
@@ -551,8 +876,34 @@
kfree(isw);
}
+/*
+ * Will set the entry's active state, and
+ * update the net_dev accordingly also.
+ */
+static void _iface_stat_set_active(struct iface_stat *entry,
+ struct net_device *net_dev,
+ bool activate)
+{
+ if (activate) {
+ entry->net_dev = net_dev;
+ entry->active = true;
+ IF_DEBUG("qtaguid: %s(%s): "
+ "enable tracking. rfcnt=%d\n", __func__,
+ entry->ifname,
+ percpu_read(*net_dev->pcpu_refcnt));
+ } else {
+ entry->active = false;
+ entry->net_dev = NULL;
+ IF_DEBUG("qtaguid: %s(%s): "
+ "disable tracking. rfcnt=%d\n", __func__,
+ entry->ifname,
+ percpu_read(*net_dev->pcpu_refcnt));
+
+ }
+}
+
/* Caller must hold iface_stat_list_lock */
-static struct iface_stat *iface_alloc(const char *ifname)
+static struct iface_stat *iface_alloc(struct net_device *net_dev)
{
struct iface_stat *new_iface;
struct iface_stat_work *isw;
@@ -560,19 +911,19 @@
new_iface = kzalloc(sizeof(*new_iface), GFP_ATOMIC);
if (new_iface == NULL) {
pr_err("qtaguid: iface_stat: create(%s): "
- "iface_stat alloc failed\n", ifname);
+ "iface_stat alloc failed\n", net_dev->name);
return NULL;
}
- new_iface->ifname = kstrdup(ifname, GFP_ATOMIC);
+ new_iface->ifname = kstrdup(net_dev->name, GFP_ATOMIC);
if (new_iface->ifname == NULL) {
pr_err("qtaguid: iface_stat: create(%s): "
- "ifname alloc failed\n", ifname);
+ "ifname alloc failed\n", net_dev->name);
kfree(new_iface);
return NULL;
}
spin_lock_init(&new_iface->tag_stat_list_lock);
- new_iface->active = true;
new_iface->tag_stat_tree = RB_ROOT;
+ _iface_stat_set_active(new_iface, net_dev, true);
/*
* ipv6 notifier chains are atomic :(
@@ -582,6 +933,7 @@
if (!isw) {
pr_err("qtaguid: iface_stat: create(%s): "
"work alloc failed\n", new_iface->ifname);
+ _iface_stat_set_active(new_iface, net_dev, false);
kfree(new_iface->ifname);
kfree(new_iface);
return NULL;
@@ -593,13 +945,53 @@
return new_iface;
}
+static void iface_check_stats_reset_and_adjust(struct net_device *net_dev,
+ struct iface_stat *iface)
+{
+ struct rtnl_link_stats64 dev_stats, *stats;
+ bool stats_rewound;
+
+ stats = dev_get_stats(net_dev, &dev_stats);
+ /* No empty packets */
+ stats_rewound =
+ (stats->rx_bytes < iface->last_known[IFS_RX].bytes)
+ || (stats->tx_bytes < iface->last_known[IFS_TX].bytes);
+
+ IF_DEBUG("qtaguid: %s(%s): iface=%p netdev=%p "
+ "bytes rx/tx=%llu/%llu "
+ "active=%d last_known=%d "
+ "stats_rewound=%d\n", __func__,
+ net_dev ? net_dev->name : "?",
+ iface, net_dev,
+ stats->rx_bytes, stats->tx_bytes,
+ iface->active, iface->last_known_valid, stats_rewound);
+
+ if (iface->active && iface->last_known_valid && stats_rewound) {
+ pr_warn_once("qtaguid: iface_stat: %s(%s): "
+ "iface reset its stats unexpectedly\n", __func__,
+ net_dev->name);
+
+ iface->totals[IFS_TX].bytes += iface->last_known[IFS_TX].bytes;
+ iface->totals[IFS_TX].packets +=
+ iface->last_known[IFS_TX].packets;
+ iface->totals[IFS_RX].bytes += iface->last_known[IFS_RX].bytes;
+ iface->totals[IFS_RX].packets +=
+ iface->last_known[IFS_RX].packets;
+ iface->last_known_valid = false;
+ IF_DEBUG("qtaguid: %s(%s): iface=%p "
+ "used last known bytes rx/tx=%llu/%llu\n", __func__,
+ iface->ifname, iface, iface->last_known[IFS_RX].bytes,
+ iface->last_known[IFS_TX].bytes);
+ }
+}
+
/*
* Create a new entry for tracking the specified interface.
* Do nothing if the entry already exists.
* Called when an interface is configured with a valid IP address.
*/
-void iface_stat_create(const struct net_device *net_dev,
- struct in_ifaddr *ifa)
+static void iface_stat_create(struct net_device *net_dev,
+ struct in_ifaddr *ifa)
{
struct in_device *in_dev = NULL;
const char *ifname;
@@ -645,19 +1037,14 @@
spin_lock_bh(&iface_stat_list_lock);
entry = get_iface_entry(ifname);
if (entry != NULL) {
+ bool activate = !ipv4_is_loopback(ipaddr);
IF_DEBUG("qtaguid: iface_stat: create(%s): entry=%p\n",
ifname, entry);
- if (ipv4_is_loopback(ipaddr)) {
- entry->active = false;
- IF_DEBUG("qtaguid: iface_stat: create(%s): "
- "disable tracking of loopback dev\n",
- ifname);
- } else {
- entry->active = true;
- IF_DEBUG("qtaguid: iface_stat: create(%s): "
- "enable tracking. ip=%pI4\n",
- ifname, &ipaddr);
- }
+ iface_check_stats_reset_and_adjust(net_dev, entry);
+ _iface_stat_set_active(entry, net_dev, activate);
+ IF_DEBUG("qtaguid: %s(%s): "
+ "tracking now %d on ip=%pI4\n", __func__,
+ entry->ifname, activate, &ipaddr);
goto done_unlock_put;
} else if (ipv4_is_loopback(ipaddr)) {
IF_DEBUG("qtaguid: iface_stat: create(%s): "
@@ -665,10 +1052,9 @@
goto done_unlock_put;
}
- new_iface = iface_alloc(ifname);
+ new_iface = iface_alloc(net_dev);
IF_DEBUG("qtaguid: iface_stat: create(%s): done "
"entry=%p ip=%pI4\n", ifname, new_iface, &ipaddr);
-
done_unlock_put:
spin_unlock_bh(&iface_stat_list_lock);
done_put:
@@ -676,8 +1062,8 @@
in_dev_put(in_dev);
}
-void iface_stat_create_ipv6(const struct net_device *net_dev,
- struct inet6_ifaddr *ifa)
+static void iface_stat_create_ipv6(struct net_device *net_dev,
+ struct inet6_ifaddr *ifa)
{
struct in_device *in_dev;
const char *ifname;
@@ -713,28 +1099,23 @@
spin_lock_bh(&iface_stat_list_lock);
entry = get_iface_entry(ifname);
if (entry != NULL) {
- IF_DEBUG("qtaguid: iface_stat: create6(%s): entry=%p\n",
+ bool activate = !(addr_type & IPV6_ADDR_LOOPBACK);
+ IF_DEBUG("qtaguid: %s(%s): entry=%p\n", __func__,
ifname, entry);
- if (addr_type & IPV6_ADDR_LOOPBACK) {
- entry->active = false;
- IF_DEBUG("qtaguid: iface_stat: create6(%s): "
- "disable tracking of loopback dev\n",
- ifname);
- } else {
- entry->active = true;
- IF_DEBUG("qtaguid: iface_stat: create6(%s): "
- "enable tracking. ip=%pI6c\n",
- ifname, &ifa->addr);
- }
+ iface_check_stats_reset_and_adjust(net_dev, entry);
+ _iface_stat_set_active(entry, net_dev, activate);
+ IF_DEBUG("qtaguid: %s(%s): "
+ "tracking now %d on ip=%pI6c\n", __func__,
+ entry->ifname, activate, &ifa->addr);
goto done_unlock_put;
} else if (addr_type & IPV6_ADDR_LOOPBACK) {
- IF_DEBUG("qtaguid: iface_stat: create6(%s): "
- "ignore loopback dev. ip=%pI6c\n",
+ IF_DEBUG("qtaguid: %s(%s): "
+ "ignore loopback dev. ip=%pI6c\n", __func__,
ifname, &ifa->addr);
goto done_unlock_put;
}
- new_iface = iface_alloc(ifname);
+ new_iface = iface_alloc(net_dev);
IF_DEBUG("qtaguid: iface_stat: create6(%s): done "
"entry=%p ip=%pI6c\n", ifname, new_iface, &ifa->addr);
@@ -786,35 +1167,52 @@
* does not exist (when a device was never configured with an IP address).
* Called when an device is being unregistered.
*/
-static void iface_stat_update(struct net_device *dev)
+static void iface_stat_update(struct net_device *net_dev, bool stash_only)
{
struct rtnl_link_stats64 dev_stats, *stats;
struct iface_stat *entry;
- stats = dev_get_stats(dev, &dev_stats);
+ stats = dev_get_stats(net_dev, &dev_stats);
spin_lock_bh(&iface_stat_list_lock);
- entry = get_iface_entry(dev->name);
+ entry = get_iface_entry(net_dev->name);
if (entry == NULL) {
IF_DEBUG("qtaguid: iface_stat: update(%s): not tracked\n",
- dev->name);
+ net_dev->name);
spin_unlock_bh(&iface_stat_list_lock);
return;
}
- IF_DEBUG("qtaguid: iface_stat: update(%s): entry=%p\n",
- dev->name, entry);
- if (entry->active) {
- entry->tx_bytes += stats->tx_bytes;
- entry->tx_packets += stats->tx_packets;
- entry->rx_bytes += stats->rx_bytes;
- entry->rx_packets += stats->rx_packets;
- entry->active = false;
- IF_DEBUG("qtaguid: iface_stat: update(%s): "
- " disable tracking. rx/tx=%llu/%llu\n",
- dev->name, stats->rx_bytes, stats->tx_bytes);
- } else {
- IF_DEBUG("qtaguid: iface_stat: update(%s): disabled\n",
- dev->name);
+
+ IF_DEBUG("qtaguid: %s(%s): entry=%p\n", __func__,
+ net_dev->name, entry);
+ if (!entry->active) {
+ IF_DEBUG("qtaguid: %s(%s): already disabled\n", __func__,
+ net_dev->name);
+ spin_unlock_bh(&iface_stat_list_lock);
+ return;
}
+
+ if (stash_only) {
+ entry->last_known[IFS_TX].bytes = stats->tx_bytes;
+ entry->last_known[IFS_TX].packets = stats->tx_packets;
+ entry->last_known[IFS_RX].bytes = stats->rx_bytes;
+ entry->last_known[IFS_RX].packets = stats->rx_packets;
+ entry->last_known_valid = true;
+ IF_DEBUG("qtaguid: %s(%s): "
+ "dev stats stashed rx/tx=%llu/%llu\n", __func__,
+ net_dev->name, stats->rx_bytes, stats->tx_bytes);
+ spin_unlock_bh(&iface_stat_list_lock);
+ return;
+ }
+ entry->totals[IFS_TX].bytes += stats->tx_bytes;
+ entry->totals[IFS_TX].packets += stats->tx_packets;
+ entry->totals[IFS_RX].bytes += stats->rx_bytes;
+ entry->totals[IFS_RX].packets += stats->rx_packets;
+ /* We don't need the last_known[] anymore */
+ entry->last_known_valid = false;
+ _iface_stat_set_active(entry, net_dev, false);
+ IF_DEBUG("qtaguid: %s(%s): "
+ "disable tracking. rx/tx=%llu/%llu\n", __func__,
+ net_dev->name, stats->rx_bytes, stats->tx_bytes);
spin_unlock_bh(&iface_stat_list_lock);
}
@@ -843,8 +1241,8 @@
tag_t tag)
{
struct tag_stat *new_tag_stat_entry = NULL;
- IF_DEBUG("qtaguid: iface_stat: create_if_tag_stat(): ife=%p tag=0x%llx"
- " (uid=%u)\n",
+ IF_DEBUG("qtaguid: iface_stat: %s(): ife=%p tag=0x%llx"
+ " (uid=%u)\n", __func__,
iface_entry, tag, get_uid_from_tag(tag));
new_tag_stat_entry = kzalloc(sizeof(*new_tag_stat_entry), GFP_ATOMIC);
if (!new_tag_stat_entry) {
@@ -894,9 +1292,9 @@
acct_tag = get_atag_from_tag(tag);
uid_tag = get_utag_from_tag(tag);
} else {
- uid_tag = make_tag_from_uid(uid);
- acct_tag = 0;
+ acct_tag = make_atag_from_value(0);
tag = combine_atag_with_uid(acct_tag, uid);
+ uid_tag = make_tag_from_uid(uid);
}
MT_DEBUG("qtaguid: iface_stat: stat_update(): "
" looking for tag=0x%llx (uid=%u) in ife=%p\n",
@@ -935,8 +1333,8 @@
new_tag_stat = create_if_tag_stat(iface_entry, tag);
new_tag_stat->parent_counters = uid_tag_counters;
}
- spin_unlock_bh(&iface_entry->tag_stat_list_lock);
tag_stat_update(new_tag_stat, direction, proto, bytes);
+ spin_unlock_bh(&iface_entry->tag_stat_list_lock);
}
static int iface_netdev_event_handler(struct notifier_block *nb,
@@ -947,15 +1345,18 @@
return NOTIFY_DONE;
IF_DEBUG("qtaguid: iface_stat: netdev_event(): "
- "ev=0x%lx netdev=%p->name=%s\n",
- event, dev, dev ? dev->name : "");
+ "ev=0x%lx/%s netdev=%p->name=%s\n",
+ event, netdev_evt_str(event), dev, dev ? dev->name : "");
switch (event) {
case NETDEV_UP:
iface_stat_create(dev, NULL);
+ atomic64_inc(&qtu_events.iface_events);
break;
case NETDEV_DOWN:
- iface_stat_update(dev);
+ case NETDEV_UNREGISTER:
+ iface_stat_update(dev, event == NETDEV_DOWN);
+ atomic64_inc(&qtu_events.iface_events);
break;
}
return NOTIFY_DONE;
@@ -971,8 +1372,8 @@
return NOTIFY_DONE;
IF_DEBUG("qtaguid: iface_stat: inet6addr_event(): "
- "ev=0x%lx ifa=%p\n",
- event, ifa);
+ "ev=0x%lx/%s ifa=%p\n",
+ event, netdev_evt_str(event), ifa);
switch (event) {
case NETDEV_UP:
@@ -982,9 +1383,10 @@
atomic64_inc(&qtu_events.iface_events);
break;
case NETDEV_DOWN:
+ case NETDEV_UNREGISTER:
BUG_ON(!ifa || !ifa->idev);
dev = (struct net_device *)ifa->idev->dev;
- iface_stat_update(dev);
+ iface_stat_update(dev, event == NETDEV_DOWN);
atomic64_inc(&qtu_events.iface_events);
break;
}
@@ -1001,8 +1403,8 @@
return NOTIFY_DONE;
IF_DEBUG("qtaguid: iface_stat: inetaddr_event(): "
- "ev=0x%lx ifa=%p\n",
- event, ifa);
+ "ev=0x%lx/%s ifa=%p\n",
+ event, netdev_evt_str(event), ifa);
switch (event) {
case NETDEV_UP:
@@ -1012,9 +1414,10 @@
atomic64_inc(&qtu_events.iface_events);
break;
case NETDEV_DOWN:
+ case NETDEV_UNREGISTER:
BUG_ON(!ifa || !ifa->ifa_dev);
dev = ifa->ifa_dev->dev;
- iface_stat_update(dev);
+ iface_stat_update(dev, event == NETDEV_DOWN);
atomic64_inc(&qtu_events.iface_events);
break;
}
@@ -1043,11 +1446,24 @@
err = -1;
goto err;
}
+
+ iface_stat_all_procfile = create_proc_entry(iface_stat_all_procfilename,
+ proc_iface_perms,
+ parent_procdir);
+ if (!iface_stat_all_procfile) {
+ pr_err("qtaguid: iface_stat: init "
+ " failed to create stat_all proc entry\n");
+ err = -1;
+ goto err_zap_entry;
+ }
+ iface_stat_all_procfile->read_proc = iface_stat_all_proc_read;
+
+
err = register_netdevice_notifier(&iface_netdev_notifier_blk);
if (err) {
pr_err("qtaguid: iface_stat: init "
"failed to register dev event handler\n");
- goto err_zap_entry;
+ goto err_zap_all_stats_entry;
}
err = register_inetaddr_notifier(&iface_inetaddr_notifier_blk);
if (err) {
@@ -1068,6 +1484,8 @@
unregister_inetaddr_notifier(&iface_inetaddr_notifier_blk);
err_unreg_nd:
unregister_netdevice_notifier(&iface_netdev_notifier_blk);
+err_zap_all_stats_entry:
+ remove_proc_entry(iface_stat_all_procfilename, parent_procdir);
err_zap_entry:
remove_proc_entry(iface_stat_procdirname, parent_procdir);
err:
@@ -1170,6 +1588,7 @@
MT_DEBUG("qtaguid[%d]: entered skb=%p par->in=%p/out=%p fam=%d\n",
par->hooknum, skb, par->in, par->out, par->family);
+ atomic64_inc(&qtu_events.match_calls);
if (skb == NULL) {
res = (info->match ^ info->invert) == 0;
goto ret_res;
@@ -1190,6 +1609,8 @@
got_sock = sk;
if (sk)
atomic64_inc(&qtu_events.match_found_sk_in_ct);
+ else
+ atomic64_inc(&qtu_events.match_found_no_sk_in_ct);
} else {
atomic64_inc(&qtu_events.match_found_sk);
}
@@ -1221,7 +1642,7 @@
par->hooknum,
sk ? sk->sk_socket : NULL);
res = (info->match ^ info->invert) == 0;
- atomic64_inc(&qtu_events.match_found_sk_none);
+ atomic64_inc(&qtu_events.match_no_sk);
goto put_sock_ret_res;
} else if (info->match & info->invert & XT_QTAGUID_SOCKET) {
res = false;
@@ -1230,8 +1651,10 @@
filp = sk->sk_socket->file;
if (filp == NULL) {
MT_DEBUG("qtaguid[%d]: leaving filp=NULL\n", par->hooknum);
+ account_for_uid(skb, sk, 0, par);
res = ((info->match ^ info->invert) &
(XT_QTAGUID_UID | XT_QTAGUID_GID)) == 0;
+ atomic64_inc(&qtu_events.match_no_sk_file);
goto put_sock_ret_res;
}
sock_uid = filp->f_cred->fsuid;
@@ -1278,6 +1701,50 @@
return res;
}
+#ifdef DDEBUG
+/* This function is not in xt_qtaguid_print.c because of locks visibility */
+static void prdebug_full_state(int indent_level, const char *fmt, ...)
+{
+ va_list args;
+ char *fmt_buff;
+ char *buff;
+
+ if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
+ return;
+
+ fmt_buff = kasprintf(GFP_ATOMIC,
+ "qtaguid: %s(): %s {\n", __func__, fmt);
+ BUG_ON(!fmt_buff);
+ va_start(args, fmt);
+ buff = kvasprintf(GFP_ATOMIC,
+ fmt_buff, args);
+ BUG_ON(!buff);
+ pr_debug("%s", buff);
+ kfree(fmt_buff);
+ kfree(buff);
+ va_end(args);
+
+ spin_lock_bh(&sock_tag_list_lock);
+ prdebug_sock_tag_tree(indent_level, &sock_tag_tree);
+ spin_unlock_bh(&sock_tag_list_lock);
+
+ spin_lock_bh(&sock_tag_list_lock);
+ spin_lock_bh(&uid_tag_data_tree_lock);
+ prdebug_uid_tag_data_tree(indent_level, &uid_tag_data_tree);
+ prdebug_proc_qtu_data_tree(indent_level, &proc_qtu_data_tree);
+ spin_unlock_bh(&uid_tag_data_tree_lock);
+ spin_unlock_bh(&sock_tag_list_lock);
+
+ spin_lock_bh(&iface_stat_list_lock);
+ prdebug_iface_stat_list(indent_level, &iface_stat_list);
+ spin_unlock_bh(&iface_stat_list_lock);
+
+ pr_debug("qtaguid: %s(): }\n", __func__);
+}
+#else
+static void prdebug_full_state(int indent_level, const char *fmt, ...) {}
+#endif
+
/*
* Procfs reader to get all active socket tags using style "1)" as described in
* fs/proc/generic.c
@@ -1289,22 +1756,23 @@
char *outp = page;
int len;
uid_t uid;
- struct sock_tag *sock_tag_entry;
struct rb_node *node;
+ struct sock_tag *sock_tag_entry;
int item_index = 0;
+ int indent_level = 0;
+ long f_count;
if (unlikely(module_passive)) {
*eof = 1;
return 0;
}
- /* TODO: support skipping num_items_returned on entry. */
- CT_DEBUG("qtaguid: proc ctrl page=%p off=%ld char_count=%d *eof=%d\n",
- page, items_to_skip, char_count, *eof);
-
if (*eof)
return 0;
+ CT_DEBUG("qtaguid: proc ctrl page=%p off=%ld char_count=%d *eof=%d\n",
+ page, items_to_skip, char_count, *eof);
+
spin_lock_bh(&sock_tag_list_lock);
for (node = rb_first(&sock_tag_tree);
node;
@@ -1313,14 +1781,21 @@
continue;
sock_tag_entry = rb_entry(node, struct sock_tag, sock_node);
uid = get_uid_from_tag(sock_tag_entry->tag);
- CT_DEBUG("qtaguid: proc_read(): sk=%p tag=0x%llx (uid=%u)\n",
+ CT_DEBUG("qtaguid: proc_read(): sk=%p tag=0x%llx (uid=%u) "
+ "pid=%u\n",
sock_tag_entry->sk,
sock_tag_entry->tag,
- uid
+ uid,
+ sock_tag_entry->pid
);
+ f_count = atomic_long_read(
+ &sock_tag_entry->socket->file->f_count);
len = snprintf(outp, char_count,
- "sock=%p tag=0x%llx (uid=%u)\n",
- sock_tag_entry->sk, sock_tag_entry->tag, uid);
+ "sock=%p tag=0x%llx (uid=%u) pid=%u "
+ "f_count=%lu\n",
+ sock_tag_entry->sk,
+ sock_tag_entry->tag, uid,
+ sock_tag_entry->pid, f_count);
if (len >= char_count) {
spin_unlock_bh(&sock_tag_list_lock);
*outp = '\0';
@@ -1339,17 +1814,24 @@
"counter_set_changes=%llu "
"delete_cmds=%llu "
"iface_events=%llu "
+ "match_calls=%llu "
"match_found_sk=%llu "
"match_found_sk_in_ct=%llu "
- "match_found_sk_none=%llu\n",
+ "match_found_no_sk_in_ct=%llu "
+ "match_no_sk=%llu "
+ "match_no_sk_file=%llu\n",
atomic64_read(&qtu_events.sockets_tagged),
atomic64_read(&qtu_events.sockets_untagged),
atomic64_read(&qtu_events.counter_set_changes),
atomic64_read(&qtu_events.delete_cmds),
atomic64_read(&qtu_events.iface_events),
+ atomic64_read(&qtu_events.match_calls),
atomic64_read(&qtu_events.match_found_sk),
atomic64_read(&qtu_events.match_found_sk_in_ct),
- atomic64_read(&qtu_events.match_found_sk_none));
+ atomic64_read(
+ &qtu_events.match_found_no_sk_in_ct),
+ atomic64_read(&qtu_events.match_no_sk),
+ atomic64_read(&qtu_events.match_no_sk_file));
if (len >= char_count) {
*outp = '\0';
return outp - page;
@@ -1359,30 +1841,15 @@
(*num_items_returned)++;
}
+ /* Count the following as part of the last item_index */
+ if (item_index > items_to_skip) {
+ prdebug_full_state(indent_level, "proc ctrl");
+ }
+
*eof = 1;
return outp - page;
}
-static bool can_manipulate_uids(void)
-{
- /* root pwnd */
- return unlikely(!current_fsuid()) || unlikely(!proc_ctrl_write_gid)
- || in_egroup_p(proc_ctrl_write_gid);
-}
-
-static bool can_impersonate_uid(uid_t uid)
-{
- return uid == current_fsuid() || can_manipulate_uids();
-}
-
-static bool can_read_other_uid_stats(uid_t uid)
-{
- /* root pwnd */
- return unlikely(!current_fsuid()) || uid == current_fsuid()
- || unlikely(!proc_stats_readall_gid)
- || in_egroup_p(proc_stats_readall_gid);
-}
-
/*
* Delete socket tags, and stat tags associated with a given
* accouting tag and uid.
@@ -1401,6 +1868,8 @@
struct rb_root st_to_free_tree = RB_ROOT;
struct tag_stat *ts_entry;
struct tag_counter_set *tcs_entry;
+ struct tag_ref *tr_entry;
+ struct uid_tag_data *utd_entry;
argc = sscanf(input, "%c %llu %u", &cmd, &acct_tag, &uid);
CT_DEBUG("qtaguid: ctrl_delete(%s): argc=%d cmd=%c "
@@ -1419,12 +1888,17 @@
uid = current_fsuid();
} else if (!can_impersonate_uid(uid)) {
pr_info("qtaguid: ctrl_delete(%s): "
- "insufficient priv from pid=%u uid=%u\n",
- input, current->pid, current_fsuid());
+ "insufficient priv from pid=%u tgid=%u uid=%u\n",
+ input, current->pid, current->tgid, current_fsuid());
res = -EPERM;
goto err;
}
+ tag = combine_atag_with_uid(acct_tag, uid);
+ CT_DEBUG("qtaguid: ctrl_delete(%s): "
+ "looking for tag=0x%llx (uid=%u)\n",
+ input, tag, uid);
+
/* Delete socket tags */
spin_lock_bh(&sock_tag_list_lock);
node = rb_first(&sock_tag_tree);
@@ -1435,36 +1909,39 @@
if (entry_uid != uid)
continue;
+ CT_DEBUG("qtaguid: ctrl_delete(%s): st tag=0x%llx (uid=%u)\n",
+ input, st_entry->tag, entry_uid);
+
if (!acct_tag || st_entry->tag == tag) {
rb_erase(&st_entry->sock_node, &sock_tag_tree);
/* Can't sockfd_put() within spinlock, do it later. */
sock_tag_tree_insert(st_entry, &st_to_free_tree);
+ tr_entry = lookup_tag_ref(st_entry->tag, NULL);
+ BUG_ON(tr_entry->num_sock_tags <= 0);
+ tr_entry->num_sock_tags--;
+ /*
+ * TODO: remove if, and start failing.
+ * This is a hack to work around the fact that in some
+ * places we have "if (IS_ERR_OR_NULL(pqd_entry))"
+ * and are trying to work around apps
+ * that didn't open the /dev/xt_qtaguid.
+ */
+ if (st_entry->list.next && st_entry->list.prev)
+ list_del(&st_entry->list);
}
}
spin_unlock_bh(&sock_tag_list_lock);
- node = rb_first(&st_to_free_tree);
- while (node) {
- st_entry = rb_entry(node, struct sock_tag, sock_node);
- node = rb_next(node);
- CT_DEBUG("qtaguid: ctrl_delete(): "
- "erase st: sk=%p tag=0x%llx (uid=%u)\n",
- st_entry->sk,
- st_entry->tag,
- entry_uid);
- rb_erase(&st_entry->sock_node, &st_to_free_tree);
- sockfd_put(st_entry->socket);
- kfree(st_entry);
- }
-
- tag = combine_atag_with_uid(acct_tag, uid);
+ sock_tag_tree_erase(&st_to_free_tree);
/* Delete tag counter-sets */
spin_lock_bh(&tag_counter_set_list_lock);
+ /* Counter sets are only on the uid tag, not full tag */
tcs_entry = tag_counter_set_tree_search(&tag_counter_set_tree, tag);
if (tcs_entry) {
- CT_DEBUG("qtaguid: ctrl_delete(): "
+ CT_DEBUG("qtaguid: ctrl_delete(%s): "
"erase tcs: tag=0x%llx (uid=%u) set=%d\n",
+ input,
tcs_entry->tn.tag,
get_uid_from_tag(tcs_entry->tn.tag),
tcs_entry->active_set);
@@ -1485,12 +1962,17 @@
ts_entry = rb_entry(node, struct tag_stat, tn.node);
entry_uid = get_uid_from_tag(ts_entry->tn.tag);
node = rb_next(node);
+
+ CT_DEBUG("qtaguid: ctrl_delete(%s): "
+ "ts tag=0x%llx (uid=%u)\n",
+ input, ts_entry->tn.tag, entry_uid);
+
if (entry_uid != uid)
continue;
if (!acct_tag || ts_entry->tn.tag == tag) {
- CT_DEBUG("qtaguid: ctrl_delete(): "
+ CT_DEBUG("qtaguid: ctrl_delete(%s): "
"erase ts: %s 0x%llx %u\n",
- iface_entry->ifname,
+ input, iface_entry->ifname,
get_atag_from_tag(ts_entry->tn.tag),
entry_uid);
rb_erase(&ts_entry->tn.node,
@@ -1501,6 +1983,30 @@
spin_unlock_bh(&iface_entry->tag_stat_list_lock);
}
spin_unlock_bh(&iface_stat_list_lock);
+
+ /* Cleanup the uid_tag_data */
+ spin_lock_bh(&uid_tag_data_tree_lock);
+ node = rb_first(&uid_tag_data_tree);
+ while (node) {
+ utd_entry = rb_entry(node, struct uid_tag_data, node);
+ entry_uid = utd_entry->uid;
+ node = rb_next(node);
+
+ CT_DEBUG("qtaguid: ctrl_delete(%s): "
+ "utd uid=%u\n",
+ input, entry_uid);
+
+ if (entry_uid != uid)
+ continue;
+ /*
+ * Go over the tag_refs, and those that don't have
+ * sock_tags using them are freed.
+ */
+ put_tag_ref_tree(tag, utd_entry);
+ put_utd_entry(utd_entry);
+ }
+ spin_unlock_bh(&uid_tag_data_tree_lock);
+
atomic64_inc(&qtu_events.delete_cmds);
res = 0;
@@ -1533,8 +2039,8 @@
}
if (!can_manipulate_uids()) {
pr_info("qtaguid: ctrl_counterset(%s): "
- "insufficient priv from pid=%u uid=%u\n",
- input, current->pid, current_fsuid());
+ "insufficient priv from pid=%u tgid=%u uid=%u\n",
+ input, current->pid, current->tgid, current_fsuid());
res = -EPERM;
goto err;
}
@@ -1572,11 +2078,14 @@
char cmd;
int sock_fd = 0;
uid_t uid = 0;
- tag_t acct_tag = 0;
+ tag_t acct_tag = make_atag_from_value(0);
+ tag_t full_tag;
struct socket *el_socket;
- int refcnt = -1;
int res, argc;
struct sock_tag *sock_tag_entry;
+ struct tag_ref *tag_ref_entry;
+ struct uid_tag_data *uid_tag_data_entry;
+ struct proc_qtu_data *pqd_entry;
/* Unassigned args will get defaulted later. */
argc = sscanf(input, "%c %d %llu %u", &cmd, &sock_fd, &acct_tag, &uid);
@@ -1593,44 +2102,66 @@
" sock_fd=%d err=%d\n", input, sock_fd, res);
goto err;
}
- refcnt = atomic_read(&el_socket->file->f_count);
- CT_DEBUG("qtaguid: ctrl_tag(%s): socket->...->f_count=%d\n",
- input, refcnt);
+ CT_DEBUG("qtaguid: ctrl_tag(%s): socket->...->f_count=%ld ->sk=%p\n",
+ input, atomic_long_read(&el_socket->file->f_count),
+ el_socket->sk);
if (argc < 3) {
- acct_tag = 0;
+ acct_tag = make_atag_from_value(0);
} else if (!valid_atag(acct_tag)) {
pr_info("qtaguid: ctrl_tag(%s): invalid tag\n", input);
res = -EINVAL;
goto err_put;
}
CT_DEBUG("qtaguid: ctrl_tag(%s): "
- "uid=%u euid=%u fsuid=%u "
+ "pid=%u tgid=%u uid=%u euid=%u fsuid=%u "
"in_group=%d in_egroup=%d\n",
- input, current_uid(), current_euid(), current_fsuid(),
- in_group_p(proc_stats_readall_gid),
- in_egroup_p(proc_stats_readall_gid));
+ input, current->pid, current->tgid, current_uid(),
+ current_euid(), current_fsuid(),
+ in_group_p(proc_ctrl_write_gid),
+ in_egroup_p(proc_ctrl_write_gid));
if (argc < 4) {
uid = current_fsuid();
} else if (!can_impersonate_uid(uid)) {
pr_info("qtaguid: ctrl_tag(%s): "
- "insufficient priv from pid=%u uid=%u\n",
- input, current->pid, current_fsuid());
+ "insufficient priv from pid=%u tgid=%u uid=%u\n",
+ input, current->pid, current->tgid, current_fsuid());
res = -EPERM;
goto err_put;
}
+ full_tag = combine_atag_with_uid(acct_tag, uid);
spin_lock_bh(&sock_tag_list_lock);
sock_tag_entry = get_sock_stat_nl(el_socket->sk);
+ tag_ref_entry = get_tag_ref(full_tag, &uid_tag_data_entry);
+ if (IS_ERR(tag_ref_entry)) {
+ res = PTR_ERR(tag_ref_entry);
+ spin_unlock_bh(&sock_tag_list_lock);
+ goto err_put;
+ }
+ tag_ref_entry->num_sock_tags++;
if (sock_tag_entry) {
+ struct tag_ref *prev_tag_ref_entry;
+
+ CT_DEBUG("qtaguid: ctrl_tag(%s): retag for sk=%p "
+ "st@%p ...->f_count=%ld\n",
+ input, el_socket->sk, sock_tag_entry,
+ atomic_long_read(&el_socket->file->f_count));
/*
* This is a re-tagging, so release the sock_fd that was
* locked at the time of the 1st tagging.
+ * There is still the ref from this call's sockfd_lookup() so
+ * it can be done within the spinlock.
*/
sockfd_put(sock_tag_entry->socket);
- refcnt--;
- sock_tag_entry->tag = combine_atag_with_uid(acct_tag,
- uid);
+ prev_tag_ref_entry = lookup_tag_ref(sock_tag_entry->tag,
+ &uid_tag_data_entry);
+ BUG_ON(IS_ERR_OR_NULL(prev_tag_ref_entry));
+ BUG_ON(prev_tag_ref_entry->num_sock_tags <= 0);
+ prev_tag_ref_entry->num_sock_tags--;
+ sock_tag_entry->tag = full_tag;
} else {
+ CT_DEBUG("qtaguid: ctrl_tag(%s): newtag for sk=%p\n",
+ input, el_socket->sk);
sock_tag_entry = kzalloc(sizeof(*sock_tag_entry),
GFP_ATOMIC);
if (!sock_tag_entry) {
@@ -1639,29 +2170,56 @@
input);
spin_unlock_bh(&sock_tag_list_lock);
res = -ENOMEM;
- goto err_put;
+ goto err_tag_unref_put;
}
sock_tag_entry->sk = el_socket->sk;
sock_tag_entry->socket = el_socket;
+ sock_tag_entry->pid = current->tgid;
sock_tag_entry->tag = combine_atag_with_uid(acct_tag,
uid);
+ spin_lock_bh(&uid_tag_data_tree_lock);
+ pqd_entry = proc_qtu_data_tree_search(
+ &proc_qtu_data_tree, current->tgid);
+ /*
+ * TODO: remove if, and start failing.
+ * At first, we want to catch user-space code that is not
+ * opening the /dev/xt_qtaguid.
+ */
+ if (IS_ERR_OR_NULL(pqd_entry))
+ pr_warn_once(
+ "qtaguid: %s(): "
+ "User space forgot to open /dev/xt_qtaguid? "
+ "pid=%u tgid=%u uid=%u\n", __func__,
+ current->pid, current->tgid,
+ current_fsuid());
+ else
+ list_add(&sock_tag_entry->list,
+ &pqd_entry->sock_tag_list);
+ spin_unlock_bh(&uid_tag_data_tree_lock);
+
sock_tag_tree_insert(sock_tag_entry, &sock_tag_tree);
atomic64_inc(&qtu_events.sockets_tagged);
}
spin_unlock_bh(&sock_tag_list_lock);
/* We keep the ref to the socket (file) until it is untagged */
- CT_DEBUG("qtaguid: ctrl_tag(%s): done. socket->...->f_count=%d\n",
- input,
- el_socket ? atomic_read(&el_socket->file->f_count) : -1);
+ CT_DEBUG("qtaguid: ctrl_tag(%s): done st@%p ...->f_count=%ld\n",
+ input, sock_tag_entry,
+ atomic_long_read(&el_socket->file->f_count));
return 0;
+err_tag_unref_put:
+ BUG_ON(tag_ref_entry->num_sock_tags <= 0);
+ tag_ref_entry->num_sock_tags--;
+ free_tag_ref_from_utd_entry(tag_ref_entry, uid_tag_data_entry);
err_put:
+ CT_DEBUG("qtaguid: ctrl_tag(%s): done. ...->f_count=%ld\n",
+ input, atomic_long_read(&el_socket->file->f_count) - 1);
/* Release the sock_fd that was grabbed by sockfd_lookup(). */
sockfd_put(el_socket);
- refcnt--;
+ return res;
+
err:
- CT_DEBUG("qtaguid: ctrl_tag(%s): done. socket->...->f_count=%d\n",
- input, refcnt);
+ CT_DEBUG("qtaguid: ctrl_tag(%s): done.\n", input);
return res;
}
@@ -1670,9 +2228,11 @@
char cmd;
int sock_fd = 0;
struct socket *el_socket;
- int refcnt = -1;
int res, argc;
struct sock_tag *sock_tag_entry;
+ struct tag_ref *tag_ref_entry;
+ struct uid_tag_data *utd_entry;
+ struct proc_qtu_data *pqd_entry;
argc = sscanf(input, "%c %d", &cmd, &sock_fd);
CT_DEBUG("qtaguid: ctrl_untag(%s): argc=%d cmd=%c sock_fd=%d\n",
@@ -1687,9 +2247,9 @@
" sock_fd=%d err=%d\n", input, sock_fd, res);
goto err;
}
- refcnt = atomic_read(&el_socket->file->f_count);
- CT_DEBUG("qtaguid: ctrl_untag(%s): socket->...->f_count=%d\n",
- input, refcnt);
+ CT_DEBUG("qtaguid: ctrl_untag(%s): socket->...->f_count=%ld ->sk=%p\n",
+ input, atomic_long_read(&el_socket->file->f_count),
+ el_socket->sk);
spin_lock_bh(&sock_tag_list_lock);
sock_tag_entry = get_sock_stat_nl(el_socket->sk);
if (!sock_tag_entry) {
@@ -1703,28 +2263,55 @@
*/
rb_erase(&sock_tag_entry->sock_node, &sock_tag_tree);
+ tag_ref_entry = lookup_tag_ref(sock_tag_entry->tag, &utd_entry);
+ BUG_ON(!tag_ref_entry);
+ BUG_ON(tag_ref_entry->num_sock_tags <= 0);
+ spin_lock_bh(&uid_tag_data_tree_lock);
+ pqd_entry = proc_qtu_data_tree_search(
+ &proc_qtu_data_tree, current->tgid);
+ /*
+ * TODO: remove if, and start failing.
+ * At first, we want to catch user-space code that is not
+ * opening the /dev/xt_qtaguid.
+ */
+ if (IS_ERR_OR_NULL(pqd_entry))
+ pr_warn_once("qtaguid: %s(): "
+ "User space forgot to open /dev/xt_qtaguid? "
+ "pid=%u tgid=%u uid=%u\n", __func__,
+ current->pid, current->tgid, current_fsuid());
+ else
+ list_del(&sock_tag_entry->list);
+ spin_unlock_bh(&uid_tag_data_tree_lock);
+ /*
+ * We don't free tag_ref from the utd_entry here,
+ * only during a cmd_delete().
+ */
+ tag_ref_entry->num_sock_tags--;
+ spin_unlock_bh(&sock_tag_list_lock);
/*
* Release the sock_fd that was grabbed at tag time,
* and once more for the sockfd_lookup() here.
*/
sockfd_put(sock_tag_entry->socket);
- spin_unlock_bh(&sock_tag_list_lock);
+ CT_DEBUG("qtaguid: ctrl_untag(%s): done. st@%p ...->f_count=%ld\n",
+ input, sock_tag_entry,
+ atomic_long_read(&el_socket->file->f_count) - 1);
sockfd_put(el_socket);
- refcnt -= 2;
+
kfree(sock_tag_entry);
atomic64_inc(&qtu_events.sockets_untagged);
- CT_DEBUG("qtaguid: ctrl_untag(%s): done. socket->...->f_count=%d\n",
- input, refcnt);
return 0;
err_put:
+ CT_DEBUG("qtaguid: ctrl_untag(%s): done. socket->...->f_count=%ld\n",
+ input, atomic_long_read(&el_socket->file->f_count) - 1);
/* Release the sock_fd that was grabbed by sockfd_lookup(). */
sockfd_put(el_socket);
- refcnt--;
+ return res;
+
err:
- CT_DEBUG("qtaguid: ctrl_untag(%s): done. socket->...->f_count=%d\n",
- input, refcnt);
+ CT_DEBUG("qtaguid: ctrl_untag(%s): done.\n", input);
return res;
}
@@ -1788,6 +2375,7 @@
struct iface_stat *iface_entry;
struct tag_stat *ts_entry;
int item_index;
+ int items_to_skip;
int char_count;
};
@@ -1795,29 +2383,35 @@
{
int len;
struct data_counters *cnts;
+
if (!ppi->item_index) {
+ if (ppi->item_index++ < ppi->items_to_skip)
+ return 0;
len = snprintf(ppi->outp, ppi->char_count,
"idx iface acct_tag_hex uid_tag_int cnt_set "
"rx_bytes rx_packets "
"tx_bytes tx_packets "
- "rx_tcp_packets rx_tcp_bytes "
- "rx_udp_packets rx_udp_bytes "
- "rx_other_packets rx_other_bytes "
- "tx_tcp_packets tx_tcp_bytes "
- "tx_udp_packets tx_udp_bytes "
- "tx_other_packets tx_other_bytes\n");
+ "rx_tcp_bytes rx_tcp_packets "
+ "rx_udp_bytes rx_udp_packets "
+ "rx_other_bytes rx_other_packets "
+ "tx_tcp_bytes tx_tcp_packets "
+ "tx_udp_bytes tx_udp_packets "
+ "tx_other_bytes tx_other_packets\n");
} else {
tag_t tag = ppi->ts_entry->tn.tag;
uid_t stat_uid = get_uid_from_tag(tag);
+
if (!can_read_other_uid_stats(stat_uid)) {
CT_DEBUG("qtaguid: stats line: "
- "%s 0x%llx %u: "
- "insufficient priv from pid=%u uid=%u\n",
+ "%s 0x%llx %u: insufficient priv "
+ "from pid=%u tgid=%u uid=%u\n",
ppi->iface_entry->ifname,
get_atag_from_tag(tag), stat_uid,
- current->pid, current_fsuid());
+ current->pid, current->tgid, current_fsuid());
return 0;
}
+ if (ppi->item_index++ < ppi->items_to_skip)
+ return 0;
cnts = &ppi->ts_entry->counters;
len = snprintf(
ppi->outp, ppi->char_count,
@@ -1855,7 +2449,7 @@
return len;
}
-bool pp_sets(struct proc_print_info *ppi)
+static bool pp_sets(struct proc_print_info *ppi)
{
int len;
int counter_set;
@@ -1891,11 +2485,13 @@
ppi.item_index = 0;
ppi.char_count = char_count;
ppi.num_items_returned = num_items_returned;
+ ppi.items_to_skip = items_to_skip;
if (unlikely(module_passive)) {
len = pp_stats_line(&ppi, 0);
/* The header should always be shorter than the buffer. */
- WARN_ON(len >= ppi.char_count);
+ BUG_ON(len >= ppi.char_count);
+ (*num_items_returned)++;
*eof = 1;
return len;
}
@@ -1907,16 +2503,17 @@
if (*eof)
return 0;
- if (!items_to_skip) {
- /* The idx is there to help debug when things go belly up. */
- len = pp_stats_line(&ppi, 0);
- /* Don't advance the outp unless the whole line was printed */
- if (len >= ppi.char_count) {
- *ppi.outp = '\0';
- return ppi.outp - page;
- }
+ /* The idx is there to help debug when things go belly up. */
+ len = pp_stats_line(&ppi, 0);
+ /* Don't advance the outp unless the whole line was printed */
+ if (len >= ppi.char_count) {
+ *ppi.outp = '\0';
+ return ppi.outp - page;
+ }
+ if (len) {
ppi.outp += len;
ppi.char_count -= len;
+ (*num_items_returned)++;
}
spin_lock_bh(&iface_stat_list_lock);
@@ -1927,8 +2524,6 @@
node;
node = rb_next(node)) {
ppi.ts_entry = rb_entry(node, struct tag_stat, tn.node);
- if (ppi.item_index++ < items_to_skip)
- continue;
if (!pp_sets(&ppi)) {
spin_unlock_bh(
&ppi.iface_entry->tag_stat_list_lock);
@@ -1945,6 +2540,168 @@
}
/*------------------------------------------*/
+static int qtudev_open(struct inode *inode, struct file *file)
+{
+ struct uid_tag_data *utd_entry;
+ struct proc_qtu_data *pqd_entry;
+ struct proc_qtu_data *new_pqd_entry;
+ int res;
+ bool utd_entry_found;
+
+ if (unlikely(qtu_proc_handling_passive))
+ return 0;
+
+ DR_DEBUG("qtaguid: qtudev_open(): pid=%u tgid=%u uid=%u\n",
+ current->pid, current->tgid, current_fsuid());
+
+ spin_lock_bh(&uid_tag_data_tree_lock);
+
+ /* Look for existing uid data, or alloc one. */
+ utd_entry = get_uid_data(current_fsuid(), &utd_entry_found);
+ if (IS_ERR_OR_NULL(utd_entry)) {
+ res = PTR_ERR(utd_entry);
+ goto err;
+ }
+
+ /* Look for existing PID based proc_data */
+ pqd_entry = proc_qtu_data_tree_search(&proc_qtu_data_tree,
+ current->tgid);
+ if (pqd_entry) {
+ pr_err("qtaguid: qtudev_open(): %u/%u %u "
+ "%s already opened\n",
+ current->pid, current->tgid, current_fsuid(),
+ QTU_DEV_NAME);
+ res = -EBUSY;
+ goto err_unlock_free_utd;
+ }
+
+ new_pqd_entry = kzalloc(sizeof(*new_pqd_entry), GFP_ATOMIC);
+ if (!new_pqd_entry) {
+ pr_err("qtaguid: qtudev_open(): %u/%u %u: "
+ "proc data alloc failed\n",
+ current->pid, current->tgid, current_fsuid());
+ res = -ENOMEM;
+ goto err_unlock_free_utd;
+ }
+ new_pqd_entry->pid = current->tgid;
+ INIT_LIST_HEAD(&new_pqd_entry->sock_tag_list);
+ new_pqd_entry->parent_tag_data = utd_entry;
+ utd_entry->num_pqd++;
+
+ proc_qtu_data_tree_insert(new_pqd_entry,
+ &proc_qtu_data_tree);
+
+ spin_unlock_bh(&uid_tag_data_tree_lock);
+ DR_DEBUG("qtaguid: tracking data for uid=%u in pqd=%p\n",
+ current_fsuid(), new_pqd_entry);
+ file->private_data = new_pqd_entry;
+ return 0;
+
+err_unlock_free_utd:
+ if (!utd_entry_found) {
+ rb_erase(&utd_entry->node, &uid_tag_data_tree);
+ kfree(utd_entry);
+ }
+ spin_unlock_bh(&uid_tag_data_tree_lock);
+err:
+ return res;
+}
+
+static int qtudev_release(struct inode *inode, struct file *file)
+{
+ struct proc_qtu_data *pqd_entry = file->private_data;
+ struct uid_tag_data *utd_entry = pqd_entry->parent_tag_data;
+ struct sock_tag *st_entry;
+ struct rb_root st_to_free_tree = RB_ROOT;
+ struct list_head *entry, *next;
+ struct tag_ref *tr;
+
+ if (unlikely(qtu_proc_handling_passive))
+ return 0;
+
+ /*
+ * Do not trust the current->pid, it might just be a kworker cleaning
+ * up after a dead proc.
+ */
+ DR_DEBUG("qtaguid: qtudev_release(): "
+ "pid=%u tgid=%u uid=%u "
+ "pqd_entry=%p->pid=%u utd_entry=%p->active_tags=%d\n",
+ current->pid, current->tgid, pqd_entry->parent_tag_data->uid,
+ pqd_entry, pqd_entry->pid, utd_entry,
+ utd_entry->num_active_tags);
+
+ spin_lock_bh(&sock_tag_list_lock);
+ spin_lock_bh(&uid_tag_data_tree_lock);
+
+ list_for_each_safe(entry, next, &pqd_entry->sock_tag_list) {
+ st_entry = list_entry(entry, struct sock_tag, list);
+ DR_DEBUG("qtaguid: %s(): "
+ "erase sock_tag=%p->sk=%p pid=%u tgid=%u uid=%u\n",
+ __func__,
+ st_entry, st_entry->sk,
+ current->pid, current->tgid,
+ pqd_entry->parent_tag_data->uid);
+
+ utd_entry = uid_tag_data_tree_search(
+ &uid_tag_data_tree,
+ get_uid_from_tag(st_entry->tag));
+ BUG_ON(IS_ERR_OR_NULL(utd_entry));
+ DR_DEBUG("qtaguid: %s(): "
+ "looking for tag=0x%llx in utd_entry=%p\n", __func__,
+ st_entry->tag, utd_entry);
+ tr = tag_ref_tree_search(&utd_entry->tag_ref_tree,
+ st_entry->tag);
+ BUG_ON(!tr);
+ BUG_ON(tr->num_sock_tags <= 0);
+ tr->num_sock_tags--;
+ free_tag_ref_from_utd_entry(tr, utd_entry);
+
+ rb_erase(&st_entry->sock_node, &sock_tag_tree);
+ list_del(&st_entry->list);
+ /* Can't sockfd_put() within spinlock, do it later. */
+ sock_tag_tree_insert(st_entry, &st_to_free_tree);
+
+ /*
+ * Try to free the utd_entry if no other proc_qtu_data is
+ * using it (num_pqd is 0) and it doesn't have active tags
+ * (num_active_tags is 0).
+ */
+ put_utd_entry(utd_entry);
+ }
+
+ rb_erase(&pqd_entry->node, &proc_qtu_data_tree);
+ BUG_ON(pqd_entry->parent_tag_data->num_pqd < 1);
+ pqd_entry->parent_tag_data->num_pqd--;
+ put_utd_entry(pqd_entry->parent_tag_data);
+ kfree(pqd_entry);
+ file->private_data = NULL;
+
+ spin_unlock_bh(&uid_tag_data_tree_lock);
+ spin_unlock_bh(&sock_tag_list_lock);
+
+
+ sock_tag_tree_erase(&st_to_free_tree);
+
+ prdebug_full_state(0, "%s(): pid=%u tgid=%u", __func__,
+ current->pid, current->tgid);
+ return 0;
+}
+
+/*------------------------------------------*/
+static const struct file_operations qtudev_fops = {
+ .owner = THIS_MODULE,
+ .open = qtudev_open,
+ .release = qtudev_release,
+};
+
+static struct miscdevice qtu_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = QTU_DEV_NAME,
+ .fops = &qtudev_fops,
+ /* How sad it doesn't allow for defaults: .mode = S_IRUGO | S_IWUSR */
+};
+
+/*------------------------------------------*/
static int __init qtaguid_proc_register(struct proc_dir_entry **res_procdir)
{
int ret;
@@ -2006,7 +2763,8 @@
{
if (qtaguid_proc_register(&xt_qtaguid_procdir)
|| iface_stat_init(xt_qtaguid_procdir)
- || xt_register_match(&qtaguid_mt_reg))
+ || xt_register_match(&qtaguid_mt_reg)
+ || misc_register(&qtu_device))
return -1;
return 0;
}
diff --git a/net/netfilter/xt_qtaguid_internal.h b/net/netfilter/xt_qtaguid_internal.h
new file mode 100644
index 0000000..02479d6
--- /dev/null
+++ b/net/netfilter/xt_qtaguid_internal.h
@@ -0,0 +1,330 @@
+/*
+ * Kernel iptables module to track stats for packets based on user tags.
+ *
+ * (C) 2011 Google, Inc
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+#ifndef __XT_QTAGUID_INTERNAL_H__
+#define __XT_QTAGUID_INTERNAL_H__
+
+#include <linux/types.h>
+#include <linux/rbtree.h>
+#include <linux/spinlock_types.h>
+#include <linux/workqueue.h>
+
+/* Iface handling */
+#define IDEBUG_MASK (1<<0)
+/* Iptable Matching. Per packet. */
+#define MDEBUG_MASK (1<<1)
+/* Red-black tree handling. Per packet. */
+#define RDEBUG_MASK (1<<2)
+/* procfs ctrl/stats handling */
+#define CDEBUG_MASK (1<<3)
+/* dev and resource tracking */
+#define DDEBUG_MASK (1<<4)
+
+/* E.g (IDEBUG_MASK | CDEBUG_MASK | DDEBUG_MASK) */
+#define DEFAULT_DEBUG_MASK 0
+
+/*
+ * (Un)Define these *DEBUG to compile out/in the pr_debug calls.
+ * All undef: text size ~ 0x3030; all def: ~ 0x4404.
+ */
+#define IDEBUG
+#define MDEBUG
+#define RDEBUG
+#define CDEBUG
+#define DDEBUG
+
+#define MSK_DEBUG(mask, ...) do { \
+ if (unlikely(qtaguid_debug_mask & (mask))) \
+ pr_debug(__VA_ARGS__); \
+ } while (0)
+#ifdef IDEBUG
+#define IF_DEBUG(...) MSK_DEBUG(IDEBUG_MASK, __VA_ARGS__)
+#else
+#define IF_DEBUG(...) no_printk(__VA_ARGS__)
+#endif
+#ifdef MDEBUG
+#define MT_DEBUG(...) MSK_DEBUG(MDEBUG_MASK, __VA_ARGS__)
+#else
+#define MT_DEBUG(...) no_printk(__VA_ARGS__)
+#endif
+#ifdef RDEBUG
+#define RB_DEBUG(...) MSK_DEBUG(RDEBUG_MASK, __VA_ARGS__)
+#else
+#define RB_DEBUG(...) no_printk(__VA_ARGS__)
+#endif
+#ifdef CDEBUG
+#define CT_DEBUG(...) MSK_DEBUG(CDEBUG_MASK, __VA_ARGS__)
+#else
+#define CT_DEBUG(...) no_printk(__VA_ARGS__)
+#endif
+#ifdef DDEBUG
+#define DR_DEBUG(...) MSK_DEBUG(DDEBUG_MASK, __VA_ARGS__)
+#else
+#define DR_DEBUG(...) no_printk(__VA_ARGS__)
+#endif
+
+extern uint qtaguid_debug_mask;
+
+/*---------------------------------------------------------------------------*/
+/*
+ * Tags:
+ *
+ * They represent what the data usage counters will be tracked against.
+ * By default a tag is just based on the UID.
+ * The UID is used as the base for policing, and can not be ignored.
+ * So a tag will always at least represent a UID (uid_tag).
+ *
+ * A tag can be augmented with an "accounting tag" which is associated
+ * with a UID.
+ * User space can set the acct_tag portion of the tag which is then used
+ * with sockets: all data belonging to that socket will be counted against the
+ * tag. The policing is then based on the tag's uid_tag portion,
+ * and stats are collected for the acct_tag portion separately.
+ *
+ * There could be
+ * a: {acct_tag=1, uid_tag=10003}
+ * b: {acct_tag=2, uid_tag=10003}
+ * c: {acct_tag=3, uid_tag=10003}
+ * d: {acct_tag=0, uid_tag=10003}
+ * a, b, and c represent tags associated with specific sockets.
+ * d is for the totals for that uid, including all untagged traffic.
+ * Typically d is used with policing/quota rules.
+ *
+ * We want tag_t big enough to distinguish uid_t and acct_tag.
+ * It might become a struct if needed.
+ * Nothing should be using it as an int.
+ */
+typedef uint64_t tag_t; /* Only used via accessors */
+
+#define TAG_UID_MASK 0xFFFFFFFFULL
+#define TAG_ACCT_MASK (~0xFFFFFFFFULL)
+
+static inline int tag_compare(tag_t t1, tag_t t2)
+{
+ return t1 < t2 ? -1 : t1 == t2 ? 0 : 1;
+}
+
+static inline tag_t combine_atag_with_uid(tag_t acct_tag, uid_t uid)
+{
+ return acct_tag | uid;
+}
+static inline tag_t make_tag_from_uid(uid_t uid)
+{
+ return uid;
+}
+static inline uid_t get_uid_from_tag(tag_t tag)
+{
+ return tag & TAG_UID_MASK;
+}
+static inline tag_t get_utag_from_tag(tag_t tag)
+{
+ return tag & TAG_UID_MASK;
+}
+static inline tag_t get_atag_from_tag(tag_t tag)
+{
+ return tag & TAG_ACCT_MASK;
+}
+
+static inline bool valid_atag(tag_t tag)
+{
+ return !(tag & TAG_UID_MASK);
+}
+static inline tag_t make_atag_from_value(uint32_t value)
+{
+ return (uint64_t)value << 32;
+}
+/*---------------------------------------------------------------------------*/
+
+/*
+ * Maximum number of socket tags that a UID is allowed to have active.
+ * Multiple processes belonging to the same UID contribute towards this limit.
+ * Special UIDs that can impersonate a UID also contribute (e.g. download
+ * manager, ...)
+ */
+#define DEFAULT_MAX_SOCK_TAGS 1024
+
+/*
+ * For now we only track 2 sets of counters.
+ * The default set is 0.
+ * Userspace can activate another set for a given uid being tracked.
+ */
+#define IFS_MAX_COUNTER_SETS 2
+
+enum ifs_tx_rx {
+ IFS_TX,
+ IFS_RX,
+ IFS_MAX_DIRECTIONS
+};
+
+/* For now, TCP, UDP, the rest */
+enum ifs_proto {
+ IFS_TCP,
+ IFS_UDP,
+ IFS_PROTO_OTHER,
+ IFS_MAX_PROTOS
+};
+
+struct byte_packet_counters {
+ uint64_t bytes;
+ uint64_t packets;
+};
+
+struct data_counters {
+ struct byte_packet_counters bpc[IFS_MAX_COUNTER_SETS][IFS_MAX_DIRECTIONS][IFS_MAX_PROTOS];
+};
+
+/* Generic X based nodes used as a base for rb_tree ops */
+struct tag_node {
+ struct rb_node node;
+ tag_t tag;
+};
+
+struct tag_stat {
+ struct tag_node tn;
+ struct data_counters counters;
+ /*
+ * If this tag is acct_tag based, we need to count against the
+ * matching parent uid_tag.
+ */
+ struct data_counters *parent_counters;
+};
+
+struct iface_stat {
+ struct list_head list; /* in iface_stat_list */
+ char *ifname;
+ bool active;
+ /* net_dev is only valid for active iface_stat */
+ struct net_device *net_dev;
+
+ struct byte_packet_counters totals[IFS_MAX_DIRECTIONS];
+ /*
+ * We keep the last_known, because some devices reset their counters
+ * just before NETDEV_UP, while some will reset just before
+ * NETDEV_REGISTER (which is more normal).
+ * So now, if the device didn't do a NETDEV_UNREGISTER and we see
+ * its current dev stats smaller that what was previously known, we
+ * assume an UNREGISTER and just use the last_known.
+ */
+ struct byte_packet_counters last_known[IFS_MAX_DIRECTIONS];
+ /* last_known is usable when last_known_valid is true */
+ bool last_known_valid;
+
+ struct proc_dir_entry *proc_ptr;
+
+ struct rb_root tag_stat_tree;
+ spinlock_t tag_stat_list_lock;
+};
+
+/* This is needed to create proc_dir_entries from atomic context. */
+struct iface_stat_work {
+ struct work_struct iface_work;
+ struct iface_stat *iface_entry;
+};
+
+/*
+ * Track tag that this socket is transferring data for, and not necessarily
+ * the uid that owns the socket.
+ * This is the tag against which tag_stat.counters will be billed.
+ * These structs need to be looked up by sock and pid.
+ */
+struct sock_tag {
+ struct rb_node sock_node;
+ struct sock *sk; /* Only used as a number, never dereferenced */
+ /* The socket is needed for sockfd_put() */
+ struct socket *socket;
+ /* Used to associate with a given pid */
+ struct list_head list; /* in proc_qtu_data.sock_tag_list */
+ pid_t pid;
+
+ tag_t tag;
+};
+
+struct qtaguid_event_counts {
+ /* Various successful events */
+ atomic64_t sockets_tagged;
+ atomic64_t sockets_untagged;
+ atomic64_t counter_set_changes;
+ atomic64_t delete_cmds;
+ atomic64_t iface_events; /* Number of NETDEV_* events handled */
+
+ atomic64_t match_calls; /* Number of times iptables called mt */
+ /*
+ * match_found_sk_*: numbers related to the netfilter matching
+ * function finding a sock for the sk_buff.
+ * Total skbs processed is sum(match_found*).
+ */
+ atomic64_t match_found_sk; /* An sk was already in the sk_buff. */
+ /* The connection tracker had or didn't have the sk. */
+ atomic64_t match_found_sk_in_ct;
+ atomic64_t match_found_no_sk_in_ct;
+ /*
+ * No sk could be found. No apparent owner. Could happen with
+ * unsolicited traffic.
+ */
+ atomic64_t match_no_sk;
+ /*
+ * The file ptr in the sk_socket wasn't there.
+ * This might happen for traffic while the socket is being closed.
+ */
+ atomic64_t match_no_sk_file;
+};
+
+/* Track the set active_set for the given tag. */
+struct tag_counter_set {
+ struct tag_node tn;
+ int active_set;
+};
+
+/*----------------------------------------------*/
+/*
+ * The qtu uid data is used to track resources that are created directly or
+ * indirectly by processes (uid tracked).
+ * It is shared by the processes with the same uid.
+ * Some of the resource will be counted to prevent further rogue allocations,
+ * some will need freeing once the owner process (uid) exits.
+ */
+struct uid_tag_data {
+ struct rb_node node;
+ uid_t uid;
+
+ /*
+ * For the uid, how many accounting tags have been set.
+ */
+ int num_active_tags;
+ /* Track the number of proc_qtu_data that reference it */
+ int num_pqd;
+ struct rb_root tag_ref_tree;
+ /* No tag_node_tree_lock; use uid_tag_data_tree_lock */
+};
+
+struct tag_ref {
+ struct tag_node tn;
+
+ /*
+ * This tracks the number of active sockets that have a tag on them
+ * which matches this tag_ref.tn.tag.
+ * A tag ref can live on after the sockets are untagged.
+ * A tag ref can only be removed during a tag delete command.
+ */
+ int num_sock_tags;
+};
+
+struct proc_qtu_data {
+ struct rb_node node;
+ pid_t pid;
+
+ struct uid_tag_data *parent_tag_data;
+
+ /* Tracks the sock_tags that need freeing upon this proc's death */
+ struct list_head sock_tag_list;
+ /* No spinlock_t sock_tag_list_lock; use the global one. */
+};
+
+/*----------------------------------------------*/
+#endif /* ifndef __XT_QTAGUID_INTERNAL_H__ */
diff --git a/net/netfilter/xt_qtaguid_print.c b/net/netfilter/xt_qtaguid_print.c
new file mode 100644
index 0000000..3917678
--- /dev/null
+++ b/net/netfilter/xt_qtaguid_print.c
@@ -0,0 +1,556 @@
+/*
+ * Pretty printing Support for iptables xt_qtaguid module.
+ *
+ * (C) 2011 Google, Inc
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * Most of the functions in this file just waste time if DEBUG is not defined.
+ * The matching xt_qtaguid_print.h will static inline empty funcs if the needed
+ * debug flags ore not defined.
+ * Those funcs that fail to allocate memory will panic as there is no need to
+ * hobble allong just pretending to do the requested work.
+ */
+
+#define DEBUG
+
+#include <linux/fs.h>
+#include <linux/gfp.h>
+#include <linux/net.h>
+#include <linux/rbtree.h>
+#include <linux/slab.h>
+#include <linux/spinlock_types.h>
+
+
+#include "xt_qtaguid_internal.h"
+#include "xt_qtaguid_print.h"
+
+#ifdef DDEBUG
+
+static void _bug_on_err_or_null(void *ptr)
+{
+ if (IS_ERR_OR_NULL(ptr)) {
+ pr_err("qtaguid: kmalloc failed\n");
+ BUG();
+ }
+}
+
+char *pp_tag_t(tag_t *tag)
+{
+ char *res;
+
+ if (!tag)
+ res = kasprintf(GFP_ATOMIC, "tag_t@null{}");
+ else
+ res = kasprintf(GFP_ATOMIC,
+ "tag_t@%p{tag=0x%llx, uid=%u}",
+ tag, *tag, get_uid_from_tag(*tag));
+ _bug_on_err_or_null(res);
+ return res;
+}
+
+char *pp_data_counters(struct data_counters *dc, bool showValues)
+{
+ char *res;
+
+ if (!dc)
+ res = kasprintf(GFP_ATOMIC, "data_counters@null{}");
+ else if (showValues)
+ res = kasprintf(
+ GFP_ATOMIC, "data_counters@%p{"
+ "set0{"
+ "rx{"
+ "tcp{b=%llu, p=%llu}, "
+ "udp{b=%llu, p=%llu},"
+ "other{b=%llu, p=%llu}}, "
+ "tx{"
+ "tcp{b=%llu, p=%llu}, "
+ "udp{b=%llu, p=%llu},"
+ "other{b=%llu, p=%llu}}}, "
+ "set1{"
+ "rx{"
+ "tcp{b=%llu, p=%llu}, "
+ "udp{b=%llu, p=%llu},"
+ "other{b=%llu, p=%llu}}, "
+ "tx{"
+ "tcp{b=%llu, p=%llu}, "
+ "udp{b=%llu, p=%llu},"
+ "other{b=%llu, p=%llu}}}}",
+ dc,
+ dc->bpc[0][IFS_RX][IFS_TCP].bytes,
+ dc->bpc[0][IFS_RX][IFS_TCP].packets,
+ dc->bpc[0][IFS_RX][IFS_UDP].bytes,
+ dc->bpc[0][IFS_RX][IFS_UDP].packets,
+ dc->bpc[0][IFS_RX][IFS_PROTO_OTHER].bytes,
+ dc->bpc[0][IFS_RX][IFS_PROTO_OTHER].packets,
+ dc->bpc[0][IFS_TX][IFS_TCP].bytes,
+ dc->bpc[0][IFS_TX][IFS_TCP].packets,
+ dc->bpc[0][IFS_TX][IFS_UDP].bytes,
+ dc->bpc[0][IFS_TX][IFS_UDP].packets,
+ dc->bpc[0][IFS_TX][IFS_PROTO_OTHER].bytes,
+ dc->bpc[0][IFS_TX][IFS_PROTO_OTHER].packets,
+ dc->bpc[1][IFS_RX][IFS_TCP].bytes,
+ dc->bpc[1][IFS_RX][IFS_TCP].packets,
+ dc->bpc[1][IFS_RX][IFS_UDP].bytes,
+ dc->bpc[1][IFS_RX][IFS_UDP].packets,
+ dc->bpc[1][IFS_RX][IFS_PROTO_OTHER].bytes,
+ dc->bpc[1][IFS_RX][IFS_PROTO_OTHER].packets,
+ dc->bpc[1][IFS_TX][IFS_TCP].bytes,
+ dc->bpc[1][IFS_TX][IFS_TCP].packets,
+ dc->bpc[1][IFS_TX][IFS_UDP].bytes,
+ dc->bpc[1][IFS_TX][IFS_UDP].packets,
+ dc->bpc[1][IFS_TX][IFS_PROTO_OTHER].bytes,
+ dc->bpc[1][IFS_TX][IFS_PROTO_OTHER].packets);
+ else
+ res = kasprintf(GFP_ATOMIC, "data_counters@%p{...}", dc);
+ _bug_on_err_or_null(res);
+ return res;
+}
+
+char *pp_tag_node(struct tag_node *tn)
+{
+ char *tag_str;
+ char *res;
+
+ if (!tn) {
+ res = kasprintf(GFP_ATOMIC, "tag_node@null{}");
+ _bug_on_err_or_null(res);
+ return res;
+ }
+ tag_str = pp_tag_t(&tn->tag);
+ res = kasprintf(GFP_ATOMIC,
+ "tag_node@%p{tag=%s}",
+ tn, tag_str);
+ _bug_on_err_or_null(res);
+ kfree(tag_str);
+ return res;
+}
+
+char *pp_tag_ref(struct tag_ref *tr)
+{
+ char *tn_str;
+ char *res;
+
+ if (!tr) {
+ res = kasprintf(GFP_ATOMIC, "tag_ref@null{}");
+ _bug_on_err_or_null(res);
+ return res;
+ }
+ tn_str = pp_tag_node(&tr->tn);
+ res = kasprintf(GFP_ATOMIC,
+ "tag_ref@%p{%s, num_sock_tags=%d}",
+ tr, tn_str, tr->num_sock_tags);
+ _bug_on_err_or_null(res);
+ kfree(tn_str);
+ return res;
+}
+
+char *pp_tag_stat(struct tag_stat *ts)
+{
+ char *tn_str;
+ char *counters_str;
+ char *parent_counters_str;
+ char *res;
+
+ if (!ts) {
+ res = kasprintf(GFP_ATOMIC, "tag_stat@null{}");
+ _bug_on_err_or_null(res);
+ return res;
+ }
+ tn_str = pp_tag_node(&ts->tn);
+ counters_str = pp_data_counters(&ts->counters, true);
+ parent_counters_str = pp_data_counters(ts->parent_counters, false);
+ res = kasprintf(GFP_ATOMIC,
+ "tag_stat@%p{%s, counters=%s, parent_counters=%s}",
+ ts, tn_str, counters_str, parent_counters_str);
+ _bug_on_err_or_null(res);
+ kfree(tn_str);
+ kfree(counters_str);
+ kfree(parent_counters_str);
+ return res;
+}
+
+char *pp_iface_stat(struct iface_stat *is)
+{
+ char *res;
+ if (!is)
+ res = kasprintf(GFP_ATOMIC, "iface_stat@null{}");
+ else
+ res = kasprintf(GFP_ATOMIC, "iface_stat@%p{"
+ "list=list_head{...}, "
+ "ifname=%s, "
+ "total={rx={bytes=%llu, "
+ "packets=%llu}, "
+ "tx={bytes=%llu, "
+ "packets=%llu}}, "
+ "last_known_valid=%d, "
+ "last_known={rx={bytes=%llu, "
+ "packets=%llu}, "
+ "tx={bytes=%llu, "
+ "packets=%llu}}, "
+ "active=%d, "
+ "net_dev=%p, "
+ "proc_ptr=%p, "
+ "tag_stat_tree=rb_root{...}}",
+ is,
+ is->ifname,
+ is->totals[IFS_RX].bytes,
+ is->totals[IFS_RX].packets,
+ is->totals[IFS_TX].bytes,
+ is->totals[IFS_TX].packets,
+ is->last_known_valid,
+ is->last_known[IFS_RX].bytes,
+ is->last_known[IFS_RX].packets,
+ is->last_known[IFS_TX].bytes,
+ is->last_known[IFS_TX].packets,
+ is->active,
+ is->net_dev,
+ is->proc_ptr);
+ _bug_on_err_or_null(res);
+ return res;
+}
+
+char *pp_sock_tag(struct sock_tag *st)
+{
+ char *tag_str;
+ char *res;
+
+ if (!st) {
+ res = kasprintf(GFP_ATOMIC, "sock_tag@null{}");
+ _bug_on_err_or_null(res);
+ return res;
+ }
+ tag_str = pp_tag_t(&st->tag);
+ res = kasprintf(GFP_ATOMIC, "sock_tag@%p{"
+ "sock_node=rb_node{...}, "
+ "sk=%p socket=%p (f_count=%lu), list=list_head{...}, "
+ "pid=%u, tag=%s}",
+ st, st->sk, st->socket, atomic_long_read(
+ &st->socket->file->f_count),
+ st->pid, tag_str);
+ _bug_on_err_or_null(res);
+ kfree(tag_str);
+ return res;
+}
+
+char *pp_uid_tag_data(struct uid_tag_data *utd)
+{
+ char *res;
+
+ if (!utd)
+ res = kasprintf(GFP_ATOMIC, "uid_tag_data@null{}");
+ else
+ res = kasprintf(GFP_ATOMIC, "uid_tag_data@%p{"
+ "uid=%u, num_active_acct_tags=%d, "
+ "num_pqd=%d, "
+ "tag_node_tree=rb_root{...}, "
+ "proc_qtu_data_tree=rb_root{...}}",
+ utd, utd->uid,
+ utd->num_active_tags, utd->num_pqd);
+ _bug_on_err_or_null(res);
+ return res;
+}
+
+char *pp_proc_qtu_data(struct proc_qtu_data *pqd)
+{
+ char *parent_tag_data_str;
+ char *res;
+
+ if (!pqd) {
+ res = kasprintf(GFP_ATOMIC, "proc_qtu_data@null{}");
+ _bug_on_err_or_null(res);
+ return res;
+ }
+ parent_tag_data_str = pp_uid_tag_data(pqd->parent_tag_data);
+ res = kasprintf(GFP_ATOMIC, "proc_qtu_data@%p{"
+ "node=rb_node{...}, pid=%u, "
+ "parent_tag_data=%s, "
+ "sock_tag_list=list_head{...}}",
+ pqd, pqd->pid, parent_tag_data_str
+ );
+ _bug_on_err_or_null(res);
+ kfree(parent_tag_data_str);
+ return res;
+}
+
+/*------------------------------------------*/
+void prdebug_sock_tag_tree(int indent_level,
+ struct rb_root *sock_tag_tree)
+{
+ struct rb_node *node;
+ struct sock_tag *sock_tag_entry;
+ char *str;
+
+ if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
+ return;
+
+ if (RB_EMPTY_ROOT(sock_tag_tree)) {
+ str = "sock_tag_tree=rb_root{}";
+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
+ return;
+ }
+
+ str = "sock_tag_tree=rb_root{";
+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
+ indent_level++;
+ for (node = rb_first(sock_tag_tree);
+ node;
+ node = rb_next(node)) {
+ sock_tag_entry = rb_entry(node, struct sock_tag, sock_node);
+ str = pp_sock_tag(sock_tag_entry);
+ pr_debug("%*d: %s,\n", indent_level*2, indent_level, str);
+ kfree(str);
+ }
+ indent_level--;
+ str = "}";
+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
+}
+
+void prdebug_sock_tag_list(int indent_level,
+ struct list_head *sock_tag_list)
+{
+ struct sock_tag *sock_tag_entry;
+ char *str;
+
+ if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
+ return;
+
+ if (list_empty(sock_tag_list)) {
+ str = "sock_tag_list=list_head{}";
+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
+ return;
+ }
+
+ str = "sock_tag_list=list_head{";
+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
+ indent_level++;
+ list_for_each_entry(sock_tag_entry, sock_tag_list, list) {
+ str = pp_sock_tag(sock_tag_entry);
+ pr_debug("%*d: %s,\n", indent_level*2, indent_level, str);
+ kfree(str);
+ }
+ indent_level--;
+ str = "}";
+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
+}
+
+void prdebug_proc_qtu_data_tree(int indent_level,
+ struct rb_root *proc_qtu_data_tree)
+{
+ char *str;
+ struct rb_node *node;
+ struct proc_qtu_data *proc_qtu_data_entry;
+
+ if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
+ return;
+
+ if (RB_EMPTY_ROOT(proc_qtu_data_tree)) {
+ str = "proc_qtu_data_tree=rb_root{}";
+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
+ return;
+ }
+
+ str = "proc_qtu_data_tree=rb_root{";
+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
+ indent_level++;
+ for (node = rb_first(proc_qtu_data_tree);
+ node;
+ node = rb_next(node)) {
+ proc_qtu_data_entry = rb_entry(node,
+ struct proc_qtu_data,
+ node);
+ str = pp_proc_qtu_data(proc_qtu_data_entry);
+ pr_debug("%*d: %s,\n", indent_level*2, indent_level,
+ str);
+ kfree(str);
+ indent_level++;
+ prdebug_sock_tag_list(indent_level,
+ &proc_qtu_data_entry->sock_tag_list);
+ indent_level--;
+
+ }
+ indent_level--;
+ str = "}";
+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
+}
+
+void prdebug_tag_ref_tree(int indent_level, struct rb_root *tag_ref_tree)
+{
+ char *str;
+ struct rb_node *node;
+ struct tag_ref *tag_ref_entry;
+
+ if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
+ return;
+
+ if (RB_EMPTY_ROOT(tag_ref_tree)) {
+ str = "tag_ref_tree{}";
+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
+ return;
+ }
+
+ str = "tag_ref_tree{";
+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
+ indent_level++;
+ for (node = rb_first(tag_ref_tree);
+ node;
+ node = rb_next(node)) {
+ tag_ref_entry = rb_entry(node,
+ struct tag_ref,
+ tn.node);
+ str = pp_tag_ref(tag_ref_entry);
+ pr_debug("%*d: %s,\n", indent_level*2, indent_level,
+ str);
+ kfree(str);
+ }
+ indent_level--;
+ str = "}";
+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
+}
+
+void prdebug_uid_tag_data_tree(int indent_level,
+ struct rb_root *uid_tag_data_tree)
+{
+ char *str;
+ struct rb_node *node;
+ struct uid_tag_data *uid_tag_data_entry;
+
+ if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
+ return;
+
+ if (RB_EMPTY_ROOT(uid_tag_data_tree)) {
+ str = "uid_tag_data_tree=rb_root{}";
+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
+ return;
+ }
+
+ str = "uid_tag_data_tree=rb_root{";
+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
+ indent_level++;
+ for (node = rb_first(uid_tag_data_tree);
+ node;
+ node = rb_next(node)) {
+ uid_tag_data_entry = rb_entry(node, struct uid_tag_data,
+ node);
+ str = pp_uid_tag_data(uid_tag_data_entry);
+ pr_debug("%*d: %s,\n", indent_level*2, indent_level, str);
+ kfree(str);
+ if (!RB_EMPTY_ROOT(&uid_tag_data_entry->tag_ref_tree)) {
+ indent_level++;
+ prdebug_tag_ref_tree(indent_level,
+ &uid_tag_data_entry->tag_ref_tree);
+ indent_level--;
+ }
+ }
+ indent_level--;
+ str = "}";
+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
+}
+
+void prdebug_tag_stat_tree(int indent_level,
+ struct rb_root *tag_stat_tree)
+{
+ char *str;
+ struct rb_node *node;
+ struct tag_stat *ts_entry;
+
+ if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
+ return;
+
+ if (RB_EMPTY_ROOT(tag_stat_tree)) {
+ str = "tag_stat_tree{}";
+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
+ return;
+ }
+
+ str = "tag_stat_tree{";
+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
+ indent_level++;
+ for (node = rb_first(tag_stat_tree);
+ node;
+ node = rb_next(node)) {
+ ts_entry = rb_entry(node, struct tag_stat, tn.node);
+ str = pp_tag_stat(ts_entry);
+ pr_debug("%*d: %s\n", indent_level*2, indent_level,
+ str);
+ kfree(str);
+ }
+ indent_level--;
+ str = "}";
+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
+}
+
+void prdebug_iface_stat_list(int indent_level,
+ struct list_head *iface_stat_list)
+{
+ char *str;
+ struct iface_stat *iface_entry;
+
+ if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
+ return;
+
+ if (list_empty(iface_stat_list)) {
+ str = "iface_stat_list=list_head{}";
+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
+ return;
+ }
+
+ str = "iface_stat_list=list_head{";
+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
+ indent_level++;
+ list_for_each_entry(iface_entry, iface_stat_list, list) {
+ str = pp_iface_stat(iface_entry);
+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
+ kfree(str);
+
+ spin_lock_bh(&iface_entry->tag_stat_list_lock);
+ if (!RB_EMPTY_ROOT(&iface_entry->tag_stat_tree)) {
+ indent_level++;
+ prdebug_tag_stat_tree(indent_level,
+ &iface_entry->tag_stat_tree);
+ indent_level--;
+ }
+ spin_unlock_bh(&iface_entry->tag_stat_list_lock);
+ }
+ indent_level--;
+ str = "}";
+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
+}
+
+#endif /* ifdef DDEBUG */
+/*------------------------------------------*/
+static const char * const netdev_event_strings[] = {
+ "netdev_unknown",
+ "NETDEV_UP",
+ "NETDEV_DOWN",
+ "NETDEV_REBOOT",
+ "NETDEV_CHANGE",
+ "NETDEV_REGISTER",
+ "NETDEV_UNREGISTER",
+ "NETDEV_CHANGEMTU",
+ "NETDEV_CHANGEADDR",
+ "NETDEV_GOING_DOWN",
+ "NETDEV_CHANGENAME",
+ "NETDEV_FEAT_CHANGE",
+ "NETDEV_BONDING_FAILOVER",
+ "NETDEV_PRE_UP",
+ "NETDEV_PRE_TYPE_CHANGE",
+ "NETDEV_POST_TYPE_CHANGE",
+ "NETDEV_POST_INIT",
+ "NETDEV_UNREGISTER_BATCH",
+ "NETDEV_RELEASE",
+ "NETDEV_NOTIFY_PEERS",
+ "NETDEV_JOIN",
+};
+
+const char *netdev_evt_str(int netdev_event)
+{
+ if (netdev_event < 0
+ || netdev_event >= ARRAY_SIZE(netdev_event_strings))
+ return "bad event num";
+ return netdev_event_strings[netdev_event];
+}
diff --git a/net/netfilter/xt_qtaguid_print.h b/net/netfilter/xt_qtaguid_print.h
new file mode 100644
index 0000000..b63871a
--- /dev/null
+++ b/net/netfilter/xt_qtaguid_print.h
@@ -0,0 +1,120 @@
+/*
+ * Pretty printing Support for iptables xt_qtaguid module.
+ *
+ * (C) 2011 Google, Inc
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+#ifndef __XT_QTAGUID_PRINT_H__
+#define __XT_QTAGUID_PRINT_H__
+
+#include "xt_qtaguid_internal.h"
+
+#ifdef DDEBUG
+
+char *pp_tag_t(tag_t *tag);
+char *pp_data_counters(struct data_counters *dc, bool showValues);
+char *pp_tag_node(struct tag_node *tn);
+char *pp_tag_ref(struct tag_ref *tr);
+char *pp_tag_stat(struct tag_stat *ts);
+char *pp_iface_stat(struct iface_stat *is);
+char *pp_sock_tag(struct sock_tag *st);
+char *pp_uid_tag_data(struct uid_tag_data *qtd);
+char *pp_proc_qtu_data(struct proc_qtu_data *pqd);
+
+/*------------------------------------------*/
+void prdebug_sock_tag_list(int indent_level,
+ struct list_head *sock_tag_list);
+void prdebug_sock_tag_tree(int indent_level,
+ struct rb_root *sock_tag_tree);
+void prdebug_proc_qtu_data_tree(int indent_level,
+ struct rb_root *proc_qtu_data_tree);
+void prdebug_tag_ref_tree(int indent_level, struct rb_root *tag_ref_tree);
+void prdebug_uid_tag_data_tree(int indent_level,
+ struct rb_root *uid_tag_data_tree);
+void prdebug_tag_stat_tree(int indent_level,
+ struct rb_root *tag_stat_tree);
+void prdebug_iface_stat_list(int indent_level,
+ struct list_head *iface_stat_list);
+
+#else
+
+/*------------------------------------------*/
+static inline char *pp_tag_t(tag_t *tag)
+{
+ return NULL;
+}
+static inline char *pp_data_counters(struct data_counters *dc, bool showValues)
+{
+ return NULL;
+}
+static inline char *pp_tag_node(struct tag_node *tn)
+{
+ return NULL;
+}
+static inline char *pp_tag_ref(struct tag_ref *tr)
+{
+ return NULL;
+}
+static inline char *pp_tag_stat(struct tag_stat *ts)
+{
+ return NULL;
+}
+static inline char *pp_iface_stat(struct iface_stat *is)
+{
+ return NULL;
+}
+static inline char *pp_sock_tag(struct sock_tag *st)
+{
+ return NULL;
+}
+static inline char *pp_uid_tag_data(struct uid_tag_data *qtd)
+{
+ return NULL;
+}
+static inline char *pp_proc_qtu_data(struct proc_qtu_data *pqd)
+{
+ return NULL;
+}
+
+/*------------------------------------------*/
+static inline
+void prdebug_sock_tag_list(int indent_level,
+ struct list_head *sock_tag_list)
+{
+}
+static inline
+void prdebug_sock_tag_tree(int indent_level,
+ struct rb_root *sock_tag_tree)
+{
+}
+static inline
+void prdebug_proc_qtu_data_tree(int indent_level,
+ struct rb_root *proc_qtu_data_tree)
+{
+}
+static inline
+void prdebug_tag_ref_tree(int indent_level, struct rb_root *tag_ref_tree)
+{
+}
+static inline
+void prdebug_uid_tag_data_tree(int indent_level,
+ struct rb_root *uid_tag_data_tree)
+{
+}
+static inline
+void prdebug_tag_stat_tree(int indent_level,
+ struct rb_root *tag_stat_tree)
+{
+}
+static inline
+void prdebug_iface_stat_list(int indent_level,
+ struct list_head *iface_stat_list)
+{
+}
+#endif
+/*------------------------------------------*/
+const char *netdev_evt_str(int netdev_event);
+#endif /* ifndef __XT_QTAGUID_PRINT_H__ */
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index 5cea020..8129d97 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -119,7 +119,7 @@
for (prio = 0; prio < q->bands; prio++) {
struct Qdisc *qdisc = q->queues[prio];
- struct sk_buff *skb = qdisc->dequeue(qdisc);
+ struct sk_buff *skb = qdisc_dequeue_peeked(qdisc);
if (skb) {
qdisc_bstats_update(sch, skb);
sch->q.qlen--;
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index b6ea6af..69400e3 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -410,7 +410,12 @@
/* Return Congestion Notification only if we dropped a packet
* from this flow.
*/
- return (qlen != slot->qlen) ? NET_XMIT_CN : NET_XMIT_SUCCESS;
+ if (qlen != slot->qlen)
+ return NET_XMIT_CN;
+
+ /* As we dropped a packet, better let upper stack know this */
+ qdisc_tree_decrease_qlen(sch, 1);
+ return NET_XMIT_SUCCESS;
}
static struct sk_buff *
diff --git a/net/socket.c b/net/socket.c
index 02dc82d..1ad42d3 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1871,8 +1871,14 @@
#define COMPAT_NAMELEN(msg) COMPAT_MSG(msg, msg_namelen)
#define COMPAT_FLAGS(msg) COMPAT_MSG(msg, msg_flags)
+struct used_address {
+ struct sockaddr_storage name;
+ unsigned int name_len;
+};
+
static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
- struct msghdr *msg_sys, unsigned flags, int nosec)
+ struct msghdr *msg_sys, unsigned flags,
+ struct used_address *used_address)
{
struct compat_msghdr __user *msg_compat =
(struct compat_msghdr __user *)msg;
@@ -1953,8 +1959,30 @@
if (sock->file->f_flags & O_NONBLOCK)
msg_sys->msg_flags |= MSG_DONTWAIT;
- err = (nosec ? sock_sendmsg_nosec : sock_sendmsg)(sock, msg_sys,
- total_len);
+ /*
+ * If this is sendmmsg() and current destination address is same as
+ * previously succeeded address, omit asking LSM's decision.
+ * used_address->name_len is initialized to UINT_MAX so that the first
+ * destination address never matches.
+ */
+ if (used_address && msg_sys->msg_name &&
+ used_address->name_len == msg_sys->msg_namelen &&
+ !memcmp(&used_address->name, msg_sys->msg_name,
+ used_address->name_len)) {
+ err = sock_sendmsg_nosec(sock, msg_sys, total_len);
+ goto out_freectl;
+ }
+ err = sock_sendmsg(sock, msg_sys, total_len);
+ /*
+ * If this is sendmmsg() and sending to current destination address was
+ * successful, remember it.
+ */
+ if (used_address && err >= 0) {
+ used_address->name_len = msg_sys->msg_namelen;
+ if (msg_sys->msg_name)
+ memcpy(&used_address->name, msg_sys->msg_name,
+ used_address->name_len);
+ }
out_freectl:
if (ctl_buf != ctl)
@@ -1979,7 +2007,7 @@
if (!sock)
goto out;
- err = __sys_sendmsg(sock, msg, &msg_sys, flags, 0);
+ err = __sys_sendmsg(sock, msg, &msg_sys, flags, NULL);
fput_light(sock->file, fput_needed);
out:
@@ -1998,6 +2026,10 @@
struct mmsghdr __user *entry;
struct compat_mmsghdr __user *compat_entry;
struct msghdr msg_sys;
+ struct used_address used_address;
+
+ if (vlen > UIO_MAXIOV)
+ vlen = UIO_MAXIOV;
datagrams = 0;
@@ -2005,27 +2037,22 @@
if (!sock)
return err;
- err = sock_error(sock->sk);
- if (err)
- goto out_put;
-
+ used_address.name_len = UINT_MAX;
entry = mmsg;
compat_entry = (struct compat_mmsghdr __user *)mmsg;
+ err = 0;
while (datagrams < vlen) {
- /*
- * No need to ask LSM for more than the first datagram.
- */
if (MSG_CMSG_COMPAT & flags) {
err = __sys_sendmsg(sock, (struct msghdr __user *)compat_entry,
- &msg_sys, flags, datagrams);
+ &msg_sys, flags, &used_address);
if (err < 0)
break;
err = __put_user(err, &compat_entry->msg_len);
++compat_entry;
} else {
err = __sys_sendmsg(sock, (struct msghdr __user *)entry,
- &msg_sys, flags, datagrams);
+ &msg_sys, flags, &used_address);
if (err < 0)
break;
err = put_user(err, &entry->msg_len);
@@ -2037,30 +2064,12 @@
++datagrams;
}
-out_put:
fput_light(sock->file, fput_needed);
- if (err == 0)
+ /* We only return an error if no datagrams were able to be sent */
+ if (datagrams != 0)
return datagrams;
- if (datagrams != 0) {
- /*
- * We may send less entries than requested (vlen) if the
- * sock is non blocking...
- */
- if (err != -EAGAIN) {
- /*
- * ... or if sendmsg returns an error after we
- * send some datagrams, where we record the
- * error to return on the next call or if the
- * app asks about it using getsockopt(SO_ERROR).
- */
- sock->sk->sk_err = -err;
- }
-
- return datagrams;
- }
-
return err;
}
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index 1f1ef70..8e2a668 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -159,3 +159,14 @@
from lib80211.
If unsure, say N.
+
+config CFG80211_ALLOW_RECONNECT
+ bool "Allow reconnect while already connected"
+ depends on CFG80211
+ default n
+ help
+ cfg80211 stack doesn't allow to connect if you are already
+ connected. This option allows to make a connection in this case.
+
+ Select this option ONLY for wlan drivers that are specifically
+ built for such purposes.
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index cea3381..584a7cd 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -92,7 +92,7 @@
[NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
[NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
[NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
- [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
+ [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
[NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 },
[NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
@@ -183,7 +183,7 @@
[NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
[NL80211_KEY_IDX] = { .type = NLA_U8 },
[NL80211_KEY_CIPHER] = { .type = NLA_U32 },
- [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
+ [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
[NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
[NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
[NL80211_KEY_TYPE] = { .type = NLA_U32 },
@@ -3878,7 +3878,8 @@
cipher == WLAN_CIPHER_SUITE_WEP104 ||
cipher == WLAN_CIPHER_SUITE_TKIP ||
cipher == WLAN_CIPHER_SUITE_CCMP ||
- cipher == WLAN_CIPHER_SUITE_AES_CMAC;
+ cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
+ cipher == WLAN_CIPHER_SUITE_SMS4;
}
@@ -4044,9 +4045,12 @@
if (len % sizeof(u32))
return -EINVAL;
+ if (settings->n_akm_suites > NL80211_MAX_NR_AKM_SUITES)
+ return -EINVAL;
+
memcpy(settings->akm_suites, data, len);
- for (i = 0; i < settings->n_ciphers_pairwise; i++)
+ for (i = 0; i < settings->n_akm_suites; i++)
if (!nl80211_valid_akm_suite(settings->akm_suites[i]))
return -EINVAL;
}
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 4453eb7..379574c 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -852,6 +852,7 @@
return;
}
+ chan->beacon_found = false;
chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags);
chan->max_antenna_gain = min(chan->orig_mag,
(int) MBI_TO_DBI(power_rule->max_antenna_gain));
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index ae0c225..cbbc927 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -17,7 +17,7 @@
#include "nl80211.h"
#include "wext-compat.h"
-#define IEEE80211_SCAN_RESULT_EXPIRE (15 * HZ)
+#define IEEE80211_SCAN_RESULT_EXPIRE (3 * HZ)
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
{
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index b7b6ff8..cf4be21 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -659,8 +659,10 @@
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
return;
+#ifndef CONFIG_CFG80211_ALLOW_RECONNECT
if (wdev->sme_state != CFG80211_SME_CONNECTED)
return;
+#endif
if (wdev->current_bss) {
cfg80211_unhold_bss(wdev->current_bss);
@@ -758,10 +760,14 @@
ASSERT_WDEV_LOCK(wdev);
+#ifndef CONFIG_CFG80211_ALLOW_RECONNECT
if (wdev->sme_state != CFG80211_SME_IDLE)
return -EALREADY;
if (WARN_ON(wdev->connect_keys)) {
+#else
+ if (wdev->connect_keys) {
+#endif
kfree(wdev->connect_keys);
wdev->connect_keys = NULL;
}
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 4d7b83f..c00a511 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -199,6 +199,10 @@
if (params->key_len != WLAN_KEY_LEN_AES_CMAC)
return -EINVAL;
break;
+ case WLAN_CIPHER_SUITE_SMS4:
+ if (params->key_len != WLAN_KEY_LEN_WAPI_SMS4)
+ return -EINVAL;
+ break;
default:
/*
* We don't know anything about this algorithm,
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index 4680b1e..373e14f 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -295,7 +295,8 @@
* Found a listening socket, now check the incoming
* call user data vs this sockets call user data
*/
- if(skb->len > 0 && x25_sk(s)->cudmatchlength > 0) {
+ if (x25_sk(s)->cudmatchlength > 0 &&
+ skb->len >= x25_sk(s)->cudmatchlength) {
if((memcmp(x25_sk(s)->calluserdata.cuddata,
skb->data,
x25_sk(s)->cudmatchlength)) == 0) {
diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c
index 58064d9..791ab2e 100644
--- a/net/xfrm/xfrm_algo.c
+++ b/net/xfrm/xfrm_algo.c
@@ -462,8 +462,8 @@
.desc = {
.sadb_alg_id = SADB_X_EALG_AESCTR,
.sadb_alg_ivlen = 8,
- .sadb_alg_minbits = 128,
- .sadb_alg_maxbits = 256
+ .sadb_alg_minbits = 160,
+ .sadb_alg_maxbits = 288
}
},
};
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index a026b0e..54a0dc2 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -212,6 +212,11 @@
/* only the first xfrm gets the encap type */
encap_type = 0;
+ if (async && x->repl->check(x, skb, seq)) {
+ XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR);
+ goto drop_unlock;
+ }
+
x->repl->advance(x, seq);
x->curlft.bytes += skb->len;
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index de6f8e1..1f4b2f8 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -2784,6 +2784,13 @@
$herecurr);
}
+# MSM - check if a non board-gpiomux file has any gpiomux declarations
+ if ($realfile =~ /\/mach-msm\/board-[0-9]+/ &&
+ $realfile !~ /camera/ && $realfile !~ /gpiomux/ &&
+ $line =~ /\s*struct msm_gpiomux_config\s*/ ) {
+ WARN("Non gpiomux board file cannot have a gpiomux config declarations. Please declare gpiomux configs in board-*-gpiomux.c file.\n" . $herecurr);
+ }
+
# unbounded string functions are overflow risks
my %str_fns = (
"sprintf" => "snprintf",
diff --git a/sound/compress_offload/core.c b/sound/compress_offload/core.c
new file mode 100644
index 0000000..987594a
--- /dev/null
+++ b/sound/compress_offload/core.c
@@ -0,0 +1,658 @@
+/*
+ * core.c - compress offload core
+ *
+ * Copyright (C) 2011 Intel Corporation
+ * Authors: Vinod Koul <vinod.koul@linux.intel.com>
+ * Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/uio.h>
+#include <linux/uaccess.h>
+#include <sound/snd_compress_params.h>
+#include <sound/compress_offload.h>
+#include <sound/compress_driver.h>
+
+/* TODO:
+ * - Integrate with alsa, compressed devices should register as alsa devices
+ * as /dev/snd_compr_xxx
+ * - Integrate with ASoC:
+ * Opening compressed path should also start the codec dai
+ * TBD how the cpu dai will be viewed and started.
+ * ASoC should always be optional part
+ * (we should be able to use this framework in non asoc systems
+ * - Multiple node representation
+ * driver should be able to register multiple nodes
+ * - Version numbering for API
+ */
+
+static DEFINE_MUTEX(device_mutex);
+static LIST_HEAD(device_list);
+static LIST_HEAD(misc_list);
+
+/*
+ * currently we are using misc device for registration and exposing ioctls
+ * this is temporary and will be moved to snd
+ * the device should be registered as /dev/snd_compr.....
+ */
+
+struct snd_compr_misc {
+ struct miscdevice misc;
+ struct list_head list;
+ struct snd_compr *compr;
+};
+
+struct snd_ioctl_data {
+ struct snd_compr_misc *misc;
+ unsigned long caps;
+ unsigned int minor;
+ struct snd_compr_stream stream;
+};
+
+static struct snd_compr_misc *snd_compr_get_device(unsigned int minor)
+{
+ struct snd_compr_misc *misc;
+
+ list_for_each_entry(misc, &misc_list, list) {
+ if (minor == misc->misc.minor)
+ return misc;
+ }
+ return NULL;
+}
+
+static int snd_compr_open(struct inode *inode, struct file *f)
+{
+ unsigned int minor = iminor(inode);
+ struct snd_compr_misc *misc = snd_compr_get_device(minor);
+ struct snd_ioctl_data *data;
+ struct snd_compr_runtime *runtime;
+ unsigned int direction;
+ int ret;
+
+ mutex_lock(&device_mutex);
+ if (f->f_flags & O_WRONLY)
+ direction = SNDRV_PCM_STREAM_PLAYBACK;
+ else {
+ ret = -ENXIO;
+ goto out;
+ }
+ /* curently only encoded playback is supported, above needs to be
+ * removed once we have recording support */
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ data->misc = misc;
+ data->minor = minor;
+ data->stream.ops = misc->compr->ops;
+ data->stream.direction = direction;
+ data->stream.private_data = misc->compr->private_data;
+ data->stream.device = misc->compr;
+ runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
+ if (!runtime) {
+ ret = -ENOMEM;
+ kfree(data);
+ goto out;
+ }
+ runtime->state = SNDRV_PCM_STATE_OPEN;
+ init_waitqueue_head(&runtime->sleep);
+ data->stream.runtime = runtime;
+ f->private_data = (void *)data;
+ ret = misc->compr->ops->open(&data->stream);
+ if (ret) {
+ kfree(runtime);
+ kfree(data);
+ goto out;
+ }
+out:
+ mutex_unlock(&device_mutex);
+ return ret;
+}
+
+static int snd_compr_free(struct inode *inode, struct file *f)
+{
+ struct snd_ioctl_data *data = f->private_data;
+ mutex_lock(&device_mutex);
+ data->stream.ops->free(&data->stream);
+ kfree(data->stream.runtime->buffer);
+ kfree(data->stream.runtime);
+ kfree(data);
+ mutex_unlock(&device_mutex);
+ return 0;
+}
+
+static void snd_compr_update_tstamp(struct snd_compr_stream *stream,
+ struct snd_compr_tstamp *tstamp)
+{
+ stream->ops->pointer(stream, tstamp);
+ stream->runtime->hw_pointer = tstamp->copied_bytes;
+}
+
+static size_t snd_compr_calc_avail(struct snd_compr_stream *stream,
+ struct snd_compr_avail *avail)
+{
+ size_t avail_calc;
+
+ snd_compr_update_tstamp(stream, &avail->tstamp);
+ avail_calc = stream->runtime->app_pointer - stream->runtime->hw_pointer;
+ if (avail_calc < 0)
+ avail_calc = stream->runtime->buffer_size + avail_calc;
+ avail->avail = avail_calc;
+ return avail_calc;
+}
+
+static size_t snd_compr_get_avail(struct snd_compr_stream *stream)
+{
+ struct snd_compr_avail avail;
+
+ return snd_compr_calc_avail(stream, &avail);
+}
+
+static int
+snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg)
+{
+ struct snd_compr_avail ioctl_avail;
+
+ snd_compr_calc_avail(stream, &ioctl_avail);
+
+ if (copy_to_user((unsigned long __user *)arg, &ioctl_avail, sizeof(ioctl_avail)))
+ return -EFAULT;
+ return 0;
+}
+
+static int snd_compr_write_data(struct snd_compr_stream *stream,
+ const char __user *buf, size_t count)
+{
+ void *dstn;
+ size_t copy;
+
+ dstn = stream->runtime->buffer + stream->runtime->app_pointer;
+ if (count < stream->runtime->buffer_size - stream->runtime->app_pointer) {
+ if (copy_from_user(dstn, buf, count))
+ return -EFAULT;
+ stream->runtime->app_pointer += count;
+ } else {
+ copy = stream->runtime->buffer_size - stream->runtime->app_pointer;
+ if (copy_from_user(dstn, buf, copy))
+ return -EFAULT;
+ if (copy_from_user(stream->runtime->buffer, buf + copy, count - copy))
+ return -EFAULT;
+ stream->runtime->app_pointer = count - copy;
+ }
+ /* if DSP cares, let it know data has been written */
+ if (stream->ops->ack)
+ stream->ops->ack(stream);
+ return count;
+}
+
+static ssize_t snd_compr_write(struct file *f, const char __user *buf,
+ size_t count, loff_t *offset)
+{
+ struct snd_ioctl_data *data = f->private_data;
+ struct snd_compr_stream *stream;
+ size_t avail;
+ int retval;
+
+ BUG_ON(!data);
+ stream = &data->stream;
+ mutex_lock(&stream->device->lock);
+ /* write is allowed when stream is running or has been steup */
+ if (stream->runtime->state != SNDRV_PCM_STATE_SETUP &&
+ stream->runtime->state != SNDRV_PCM_STATE_RUNNING) {
+ mutex_unlock(&stream->device->lock);
+ return -EPERM;
+ }
+
+ avail = snd_compr_get_avail(stream);
+ /* calculate how much we can write to buffer */
+ if (avail > count)
+ avail = count;
+
+ if (stream->ops->copy)
+ retval = stream->ops->copy(stream, buf, avail);
+ else
+ retval = snd_compr_write_data(stream, buf, avail);
+
+ /* while initiating the stream, write should be called before START
+ * call, so in setup move state */
+ if (stream->runtime->state == SNDRV_PCM_STATE_SETUP)
+ stream->runtime->state = SNDRV_PCM_STATE_PREPARED;
+
+ mutex_unlock(&stream->device->lock);
+ return retval;
+}
+
+
+static ssize_t snd_compr_read(struct file *f, char __user *buf,
+ size_t count, loff_t *offset)
+{
+ return -ENXIO;
+}
+
+static int snd_compr_mmap(struct file *f, struct vm_area_struct *vma)
+{
+ return -ENXIO;
+}
+
+unsigned int snd_compr_poll(struct file *f, poll_table *wait)
+{
+ struct snd_ioctl_data *data = f->private_data;
+ struct snd_compr_stream *stream;
+ int retval = 0;
+
+ BUG_ON(!data);
+ stream = &data->stream;
+
+ mutex_lock(&stream->device->lock);
+ if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING) {
+ retval = -ENXIO;
+ goto out;
+ }
+ poll_wait(f, &stream->runtime->sleep, wait);
+
+ /* this would change after read is implemented, we would need to
+ * check for direction here */
+ if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING)
+ retval = POLLOUT | POLLWRNORM;
+out:
+ mutex_unlock(&stream->device->lock);
+ return retval;
+}
+
+void snd_compr_fragment_elapsed(struct snd_compr_stream *stream)
+{
+ size_t avail;
+
+ if (stream->direction != SNDRV_PCM_STREAM_PLAYBACK)
+ return;
+ avail = snd_compr_get_avail(stream);
+ if (avail >= stream->runtime->fragment_size)
+ wake_up(&stream->runtime->sleep);
+}
+EXPORT_SYMBOL_GPL(snd_compr_fragment_elapsed);
+
+void snd_compr_frame_elapsed(struct snd_compr_stream *stream)
+{
+ size_t avail;
+
+ if (stream->direction != SNDRV_PCM_STREAM_CAPTURE)
+ return;
+ avail = snd_compr_get_avail(stream);
+ if (avail)
+ wake_up(&stream->runtime->sleep);
+}
+EXPORT_SYMBOL_GPL(snd_compr_frame_elapsed);
+
+static int snd_compr_get_caps(struct snd_compr_stream *stream, unsigned long arg)
+{
+ int retval;
+ struct snd_compr_caps caps;
+
+ if (!stream->ops->get_caps)
+ return -ENXIO;
+
+ retval = stream->ops->get_caps(stream, &caps);
+ if (retval)
+ goto out;
+ if (copy_to_user((void __user *)arg, &caps, sizeof(caps)))
+ retval = -EFAULT;
+out:
+ return retval;
+}
+
+static int snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg)
+{
+ int retval;
+ struct snd_compr_codec_caps *caps;
+
+ if (!stream->ops->get_codec_caps)
+ return -ENXIO;
+
+ caps = kmalloc(sizeof(*caps), GFP_KERNEL);
+ if (!caps)
+ return -ENOMEM;
+
+ retval = stream->ops->get_codec_caps(stream, caps);
+ if (retval)
+ goto out;
+ if (copy_to_user((void __user *)arg, caps, sizeof(*caps)))
+ retval = -EFAULT;
+
+out:
+ kfree(caps);
+ return retval;
+}
+
+/* revisit this with snd_pcm_preallocate_xxx */
+static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
+ struct snd_compr_params *params)
+{
+ unsigned int buffer_size;
+ void *buffer;
+
+ buffer_size = params->buffer.fragment_size * params->buffer.fragments;
+ if (stream->ops->copy) {
+ buffer = NULL;
+ /* if copy is defined the driver will be required to copy
+ * the data from core
+ */
+ } else {
+ buffer = kmalloc(buffer_size, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+ }
+ stream->runtime->fragment_size = params->buffer.fragment_size;
+ stream->runtime->fragments = params->buffer.fragments;
+ stream->runtime->buffer = buffer;
+ stream->runtime->buffer_size = buffer_size;
+ return 0;
+}
+
+static int snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
+{
+ struct snd_compr_params *params;
+ int retval;
+
+ if (stream->runtime->state == SNDRV_PCM_STATE_OPEN) {
+ /*
+ * we should allow parameter change only when stream has been
+ * opened not in other cases
+ */
+ params = kmalloc(sizeof(*params), GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+ if (copy_from_user(params, (void __user *)arg, sizeof(*params)))
+ return -EFAULT;
+ retval = snd_compr_allocate_buffer(stream, params);
+ if (retval) {
+ kfree(params);
+ return -ENOMEM;
+ }
+ retval = stream->ops->set_params(stream, params);
+ if (retval)
+ goto out;
+ stream->runtime->state = SNDRV_PCM_STATE_SETUP;
+ } else
+ return -EPERM;
+out:
+ kfree(params);
+ return retval;
+}
+
+static int snd_compr_get_params(struct snd_compr_stream *stream, unsigned long arg)
+{
+ struct snd_compr_params *params;
+ int retval;
+
+ if (!stream->ops->get_params)
+ return -ENXIO;
+
+ params = kmalloc(sizeof(*params), GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+ retval = stream->ops->get_params(stream, params);
+ if (retval)
+ goto out;
+ if (copy_to_user((char __user *)arg, params, sizeof(*params)))
+ retval = -EFAULT;
+
+out:
+ kfree(params);
+ return retval;
+}
+
+static int snd_compr_tstamp(struct snd_compr_stream *stream, unsigned long arg)
+{
+ struct snd_compr_tstamp tstamp;
+
+ snd_compr_update_tstamp(stream, &tstamp);
+ if (copy_to_user((struct snd_compr_tstamp __user *)arg, &tstamp, sizeof(tstamp)))
+ return -EFAULT;
+ return 0;
+}
+
+static int snd_compr_pause(struct snd_compr_stream *stream)
+{
+ int retval;
+
+ if (stream->runtime->state == SNDRV_PCM_STATE_PAUSED)
+ return 0;
+ retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_PUSH);
+ if (!retval) {
+ stream->runtime->state = SNDRV_PCM_STATE_PAUSED;
+ wake_up(&stream->runtime->sleep);
+ }
+ return retval;
+}
+
+static int snd_compr_resume(struct snd_compr_stream *stream)
+{
+ int retval;
+
+ if (stream->runtime->state != SNDRV_PCM_STATE_PAUSED)
+ return -EPERM;
+ retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_RELEASE);
+ if (!retval)
+ stream->runtime->state = SNDRV_PCM_STATE_RUNNING;
+ return retval;
+}
+
+static int snd_compr_start(struct snd_compr_stream *stream)
+{
+ int retval;
+
+ if (stream->runtime->state != SNDRV_PCM_STATE_PREPARED)
+ return -EPERM;
+ retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_START);
+ if (!retval)
+ stream->runtime->state = SNDRV_PCM_STATE_RUNNING;
+ return retval;
+}
+
+static int snd_compr_stop(struct snd_compr_stream *stream)
+{
+ int retval;
+
+ if (stream->runtime->state != SNDRV_PCM_STATE_PREPARED)
+ return -EPERM;
+ retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);
+ if (!retval) {
+ stream->runtime->state = SNDRV_PCM_STATE_SETUP;
+ wake_up(&stream->runtime->sleep);
+ }
+ return retval;
+}
+
+static int snd_compr_drain(struct snd_compr_stream *stream)
+{
+ int retval;
+
+ if (stream->runtime->state != SNDRV_PCM_STATE_PREPARED ||
+ stream->runtime->state != SNDRV_PCM_STATE_PAUSED)
+ return -EPERM;
+ retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_DRAIN);
+ if (!retval) {
+ stream->runtime->state = SNDRV_PCM_STATE_SETUP;
+ wake_up(&stream->runtime->sleep);
+ }
+ return retval;
+}
+
+static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
+{
+ struct snd_ioctl_data *data = f->private_data;
+ struct snd_compr_stream *stream;
+ int retval = -ENOTTY;
+
+ BUG_ON(!data);
+ stream = &data->stream;
+ mutex_lock(&stream->device->lock);
+ switch (_IOC_NR(cmd)) {
+ case _IOC_NR(SNDRV_COMPRESS_GET_CAPS):
+ retval = snd_compr_get_caps(stream, arg);
+ break;
+ case _IOC_NR(SNDRV_COMPRESS_GET_CODEC_CAPS):
+ retval = snd_compr_get_codec_caps(stream, arg);
+ break;
+ case _IOC_NR(SNDRV_COMPRESS_SET_PARAMS):
+ retval = snd_compr_set_params(stream, arg);
+ break;
+ case _IOC_NR(SNDRV_COMPRESS_GET_PARAMS):
+ retval = snd_compr_get_params(stream, arg);
+ break;
+ case _IOC_NR(SNDRV_COMPRESS_TSTAMP):
+ retval = snd_compr_tstamp(stream, arg);
+ break;
+ case _IOC_NR(SNDRV_COMPRESS_AVAIL):
+ retval = snd_compr_ioctl_avail(stream, arg);
+ case _IOC_NR(SNDRV_COMPRESS_PAUSE):
+ retval = snd_compr_pause(stream);
+ break;
+ case _IOC_NR(SNDRV_COMPRESS_RESUME):
+ retval = snd_compr_resume(stream);
+ break;
+ case _IOC_NR(SNDRV_COMPRESS_START):
+ retval = snd_compr_start(stream);
+ break;
+ case _IOC_NR(SNDRV_COMPRESS_STOP):
+ retval = snd_compr_stop(stream);
+ break;
+ case _IOC_NR(SNDRV_COMPRESS_DRAIN):
+ cmd = SND_COMPR_TRIGGER_DRAIN;
+ retval = snd_compr_drain(stream);
+ break;
+ }
+ mutex_unlock(&stream->device->lock);
+ return retval;
+}
+
+static const struct file_operations snd_comp_file = {
+ .owner = THIS_MODULE,
+ .open = snd_compr_open,
+ .release = snd_compr_free,
+ .read = snd_compr_read,
+ .write = snd_compr_write,
+ .unlocked_ioctl = snd_compr_ioctl,
+ .mmap = snd_compr_mmap,
+ .poll = snd_compr_poll,
+};
+
+static int snd_compress_add_device(struct snd_compr *device)
+{
+ int ret;
+
+ struct snd_compr_misc *misc = kzalloc(sizeof(*misc), GFP_KERNEL);
+
+ misc->misc.name = device->name;
+ misc->misc.fops = &snd_comp_file;
+ misc->misc.minor = MISC_DYNAMIC_MINOR;
+ misc->compr = device;
+ ret = misc_register(&misc->misc);
+ if (ret) {
+ pr_err("couldn't register misc device\n");
+ kfree(misc);
+ } else {
+ pr_debug("Got minor %d\n", misc->misc.minor);
+ list_add_tail(&misc->list, &misc_list);
+ }
+ return ret;
+}
+
+static int snd_compress_remove_device(struct snd_compr *device)
+{
+ struct snd_compr_misc *misc, *__misc;
+
+ list_for_each_entry_safe(misc, __misc, &misc_list, list) {
+ if (device == misc->compr) {
+ misc_deregister(&misc->misc);
+ list_del(&device->list);
+ kfree(misc);
+ }
+ }
+ return 0;
+}
+/**
+ * snd_compress_register - register compressed device
+ *
+ * @device: compressed device to register
+ */
+int snd_compress_register(struct snd_compr *device)
+{
+ int retval;
+
+ if (device->name == NULL || device->dev == NULL || device->ops == NULL)
+ return -EINVAL;
+ BUG_ON(!device->ops->open);
+ BUG_ON(!device->ops->free);
+ BUG_ON(!device->ops->set_params);
+ BUG_ON(!device->ops->get_params);
+ BUG_ON(!device->ops->trigger);
+ BUG_ON(!device->ops->pointer);
+ BUG_ON(!device->ops->get_caps);
+ BUG_ON(!device->ops->get_codec_caps);
+
+ INIT_LIST_HEAD(&device->list);
+ /* todo register the compressed streams */
+ /* todo integrate with asoc */
+
+ /* register a compressed card TBD if this needs change */
+
+ pr_debug("Registering compressed device %s\n", device->name);
+ mutex_lock(&device_mutex);
+ /* register a msic device for now */
+ retval = snd_compress_add_device(device);
+ if (!retval)
+ list_add_tail(&device->list, &device_list);
+ mutex_unlock(&device_mutex);
+ return retval;
+}
+EXPORT_SYMBOL_GPL(snd_compress_register);
+
+int snd_compress_deregister(struct snd_compr *device)
+{
+ pr_debug("Removing compressed device %s\n", device->name);
+ mutex_lock(&device_mutex);
+ snd_compress_remove_device(device);
+ list_del(&device->list);
+ mutex_unlock(&device_mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_compress_deregister);
+
+static int __init snd_compress_init(void)
+{
+ return 0;
+}
+
+static void __exit snd_compress_exit(void)
+{
+}
+
+module_init(snd_compress_init);
+module_exit(snd_compress_exit);
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 50f6e07..7cb3486 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -1757,6 +1757,10 @@
snd_pcm_uframes_t avail = 0;
long wait_time, tout;
+ init_waitqueue_entry(&wait, current);
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&runtime->tsleep, &wait);
+
if (runtime->no_period_wakeup)
wait_time = MAX_SCHEDULE_TIMEOUT;
else {
@@ -1767,16 +1771,32 @@
}
wait_time = msecs_to_jiffies(wait_time * 1000);
}
- init_waitqueue_entry(&wait, current);
- add_wait_queue(&runtime->tsleep, &wait);
+
for (;;) {
if (signal_pending(current)) {
err = -ERESTARTSYS;
break;
}
+
+ /*
+ * We need to check if space became available already
+ * (and thus the wakeup happened already) first to close
+ * the race of space already having become available.
+ * This check must happen after been added to the waitqueue
+ * and having current state be INTERRUPTIBLE.
+ */
+ if (is_playback)
+ avail = snd_pcm_playback_avail(runtime);
+ else
+ avail = snd_pcm_capture_avail(runtime);
+ if (avail >= runtime->twake)
+ break;
snd_pcm_stream_unlock_irq(substream);
- tout = schedule_timeout_interruptible(wait_time);
+
+ tout = schedule_timeout(wait_time);
+
snd_pcm_stream_lock_irq(substream);
+ set_current_state(TASK_INTERRUPTIBLE);
switch (runtime->status->state) {
case SNDRV_PCM_STATE_SUSPENDED:
err = -ESTRPIPE;
@@ -1802,14 +1822,9 @@
err = -EIO;
break;
}
- if (is_playback)
- avail = snd_pcm_playback_avail(runtime);
- else
- avail = snd_pcm_capture_avail(runtime);
- if (avail >= runtime->twake)
- break;
}
_endloop:
+ set_current_state(TASK_RUNNING);
remove_wait_queue(&runtime->tsleep, &wait);
*availp = avail;
return err;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 34712cb..6dd815d 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -27,6 +27,8 @@
#include <linux/dma-mapping.h>
#include <sound/core.h>
#include <sound/control.h>
+#include <sound/snd_compress_params.h>
+#include <sound/compress_offload.h>
#include <sound/info.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -1519,6 +1521,21 @@
return result;
}
+static int snd_compressed_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;
+ if (runtime->status->state != SNDRV_PCM_STATE_OPEN)
+ return -EBADFD;
+ pr_err("%s called with cmd = %d\n", __func__, cmd);
+ err = substream->ops->ioctl(substream, cmd, arg);
+ return err;
+}
/*
* drop ioctl
*
@@ -2573,6 +2590,12 @@
snd_pcm_stream_unlock_irq(substream);
return res;
}
+ case SNDRV_COMPRESS_GET_CAPS:
+ case SNDRV_COMPRESS_GET_CODEC_CAPS:
+ case SNDRV_COMPRESS_SET_PARAMS:
+ case SNDRV_COMPRESS_GET_PARAMS:
+ case SNDRV_COMPRESS_TSTAMP:
+ return snd_compressed_ioctl(substream, cmd, arg);
}
snd_printd("unknown ioctl = 0x%x\n", cmd);
return -ENOTTY;
@@ -2745,7 +2768,7 @@
pcm_file = file->private_data;
- if (((cmd >> 8) & 0xff) != 'A')
+ if ((((cmd >> 8) & 0xff) != 'A') && (((cmd >> 8) & 0xff) != 'C'))
return -ENOTTY;
return snd_pcm_playback_ioctl1(file, pcm_file->substream, cmd,
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 7c1cbf0..950eed0 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -531,6 +531,8 @@
if (err < 0)
return err;
timer = timeri->timer;
+ if (!timer)
+ return -EINVAL;
spin_lock_irqsave(&timer->lock, flags);
timeri->cticks = timeri->ticks;
timeri->pticks = 0;
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index 200c9a1..a872d0a 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -1909,6 +1909,7 @@
0x103c0944, /* HP nc6220 */
0x103c0934, /* HP nc8220 */
0x103c006d, /* HP nx9105 */
+ 0x103c300d, /* HP Compaq dc5100 SFF(PT003AW) */
0x17340088, /* FSC Scenic-W */
0 /* end */
};
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index a7ec703..ecce948 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -68,6 +68,7 @@
module_param_array(tea575x_tuner, int, NULL, 0444);
MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (0 = auto, 1 = SF256-PCS, 2=SF256-PCP, 3=SF64-PCR, 8=disable, +16=tuner-only).");
+#define TUNER_DISABLED (1<<3)
#define TUNER_ONLY (1<<4)
#define TUNER_TYPE_MASK (~TUNER_ONLY & 0xFFFF)
@@ -1150,7 +1151,8 @@
__end_hw:
#ifdef CONFIG_SND_FM801_TEA575X_BOOL
- snd_tea575x_exit(&chip->tea);
+ if (!(chip->tea575x_tuner & TUNER_DISABLED))
+ snd_tea575x_exit(&chip->tea);
#endif
if (chip->irq >= 0)
free_irq(chip->irq, chip);
@@ -1236,7 +1238,6 @@
(tea575x_tuner & TUNER_TYPE_MASK) < 4) {
if (snd_tea575x_init(&chip->tea)) {
snd_printk(KERN_ERR "TEA575x radio not found\n");
- snd_fm801_free(chip);
return -ENODEV;
}
} else if ((tea575x_tuner & TUNER_TYPE_MASK) == 0) {
@@ -1251,11 +1252,15 @@
}
if (tea575x_tuner == 4) {
snd_printk(KERN_ERR "TEA575x radio not found\n");
- snd_fm801_free(chip);
- return -ENODEV;
+ chip->tea575x_tuner = TUNER_DISABLED;
}
}
- strlcpy(chip->tea.card, snd_fm801_tea575x_gpios[(tea575x_tuner & TUNER_TYPE_MASK) - 1].name, sizeof(chip->tea.card));
+ if (!(chip->tea575x_tuner & TUNER_DISABLED)) {
+ strlcpy(chip->tea.card,
+ snd_fm801_tea575x_gpios[(tea575x_tuner &
+ TUNER_TYPE_MASK) - 1].name,
+ sizeof(chip->tea.card));
+ }
#endif
*rchip = chip;
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 486f6de..981b6fd 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -2352,6 +2352,7 @@
SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB),
+ SND_PCI_QUIRK(0x1028, 0x02c6, "Dell Inspiron 1010", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1028, 0x0470, "Dell Inspiron 1120", POS_FIX_LPIB),
SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 26a15210..fb6fbe4 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -508,7 +508,7 @@
int index, unsigned int pval, int dir,
struct snd_kcontrol **kctlp)
{
- char tmp[32];
+ char tmp[44];
struct snd_kcontrol_new knew =
HDA_CODEC_VOLUME_IDX(tmp, index, 0, 0, HDA_OUTPUT);
knew.private_value = pval;
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 7bbc5f2..cf1fa36 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -3097,6 +3097,7 @@
SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS),
SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD),
+ SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520 & W520", CXT5066_AUTO),
SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT5066_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS),
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 524ff26..4c7cd6b 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -397,7 +397,7 @@
unsigned int auto_mic:1;
unsigned int automute:1; /* HP automute enabled */
unsigned int detect_line:1; /* Line-out detection enabled */
- unsigned int automute_lines:1; /* automute line-out as well */
+ unsigned int automute_lines:1; /* automute line-out as well; NOP when automute_hp_lo isn't set */
unsigned int automute_hp_lo:1; /* both HP and LO available */
/* other flags */
@@ -1161,7 +1161,7 @@
if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] ||
spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0])
return;
- if (!spec->automute_lines || !spec->automute)
+ if (!spec->automute || (spec->automute_hp_lo && !spec->automute_lines))
on = 0;
else
on = spec->jack_present;
@@ -1494,7 +1494,7 @@
unsigned int val;
if (!spec->automute)
val = 0;
- else if (!spec->automute_lines)
+ else if (!spec->automute_hp_lo || !spec->automute_lines)
val = 1;
else
val = 2;
@@ -1515,7 +1515,8 @@
spec->automute = 0;
break;
case 1:
- if (spec->automute && !spec->automute_lines)
+ if (spec->automute &&
+ (!spec->automute_hp_lo || !spec->automute_lines))
return 0;
spec->automute = 1;
spec->automute_lines = 0;
@@ -1858,7 +1859,9 @@
* 15 : 1 --> enable the function "Mute internal speaker
* when the external headphone out jack is plugged"
*/
- if (!spec->autocfg.hp_pins[0]) {
+ if (!spec->autocfg.hp_pins[0] &&
+ !(spec->autocfg.line_out_pins[0] &&
+ spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)) {
hda_nid_t nid;
tmp = (ass >> 11) & 0x3; /* HP to chassis */
if (tmp == 0)
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 7f81cc2..5c42f3e 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -5470,6 +5470,7 @@
switch (codec->vendor_id) {
case 0x111d76d1:
case 0x111d76d9:
+ case 0x111d76df:
case 0x111d76e5:
case 0x111d7666:
case 0x111d7667:
@@ -6399,6 +6400,7 @@
{ .id = 0x111d76cc, .name = "92HD89F3", .patch = patch_stac92hd73xx },
{ .id = 0x111d76cd, .name = "92HD89F2", .patch = patch_stac92hd73xx },
{ .id = 0x111d76ce, .name = "92HD89F1", .patch = patch_stac92hd73xx },
+ { .id = 0x111d76df, .name = "92HD93BXX", .patch = patch_stac92hd83xxx},
{ .id = 0x111d76e0, .name = "92HD91BXX", .patch = patch_stac92hd83xxx},
{ .id = 0x111d76e3, .name = "92HD98BXX", .patch = patch_stac92hd83xxx},
{ .id = 0x111d76e5, .name = "92HD99BXX", .patch = patch_stac92hd83xxx},
diff --git a/sound/soc/blackfin/bf5xx-ad193x.c b/sound/soc/blackfin/bf5xx-ad193x.c
index d6651c0..2f0f836 100644
--- a/sound/soc/blackfin/bf5xx-ad193x.c
+++ b/sound/soc/blackfin/bf5xx-ad193x.c
@@ -103,7 +103,7 @@
.cpu_dai_name = "bfin-tdm.0",
.codec_dai_name ="ad193x-hifi",
.platform_name = "bfin-tdm-pcm-audio",
- .codec_name = "ad193x.5",
+ .codec_name = "spi0.5",
.ops = &bf5xx_ad193x_ops,
},
{
@@ -112,7 +112,7 @@
.cpu_dai_name = "bfin-tdm.1",
.codec_dai_name ="ad193x-hifi",
.platform_name = "bfin-tdm-pcm-audio",
- .codec_name = "ad193x.5",
+ .codec_name = "spi0.5",
.ops = &bf5xx_ad193x_ops,
},
};
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index 2374ca5..f1a8be5 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -307,7 +307,8 @@
snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, reg);
reg = snd_soc_read(codec, AD193X_DAC_CTRL2);
- reg = (reg & (~AD193X_DAC_WORD_LEN_MASK)) | word_len;
+ reg = (reg & (~AD193X_DAC_WORD_LEN_MASK))
+ | (word_len << AD193X_DAC_WORD_LEN_SHFT);
snd_soc_write(codec, AD193X_DAC_CTRL2, reg);
reg = snd_soc_read(codec, AD193X_ADC_CTRL1);
diff --git a/sound/soc/codecs/ad193x.h b/sound/soc/codecs/ad193x.h
index 9747b54..cccc2e8 100644
--- a/sound/soc/codecs/ad193x.h
+++ b/sound/soc/codecs/ad193x.h
@@ -34,7 +34,8 @@
#define AD193X_DAC_LEFT_HIGH (1 << 3)
#define AD193X_DAC_BCLK_INV (1 << 7)
#define AD193X_DAC_CTRL2 0x804
-#define AD193X_DAC_WORD_LEN_MASK 0xC
+#define AD193X_DAC_WORD_LEN_SHFT 3
+#define AD193X_DAC_WORD_LEN_MASK 0x18
#define AD193X_DAC_MASTER_MUTE 1
#define AD193X_DAC_CHNL_MUTE 0x805
#define AD193X_DACL1_MUTE 0
@@ -63,7 +64,7 @@
#define AD193X_ADC_CTRL1 0x80f
#define AD193X_ADC_SERFMT_MASK 0x60
#define AD193X_ADC_SERFMT_STEREO (0 << 5)
-#define AD193X_ADC_SERFMT_TDM (1 << 2)
+#define AD193X_ADC_SERFMT_TDM (1 << 5)
#define AD193X_ADC_SERFMT_AUX (2 << 5)
#define AD193X_ADC_WORD_LEN_MASK 0x3
#define AD193X_ADC_CTRL2 0x810
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index ff29380..c49317c 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -33,73 +33,31 @@
#define SGTL5000_DAP_REG_OFFSET 0x0100
#define SGTL5000_MAX_REG_OFFSET 0x013A
-/* default value of sgtl5000 registers except DAP */
-static const u16 sgtl5000_regs[SGTL5000_MAX_REG_OFFSET >> 1] = {
- 0xa011, /* 0x0000, CHIP_ID. 11 stand for revison 17 */
- 0x0000, /* 0x0002, CHIP_DIG_POWER. */
- 0x0008, /* 0x0004, CHIP_CKL_CTRL */
- 0x0010, /* 0x0006, CHIP_I2S_CTRL */
- 0x0000, /* 0x0008, reserved */
- 0x0008, /* 0x000A, CHIP_SSS_CTRL */
- 0x0000, /* 0x000C, reserved */
- 0x020c, /* 0x000E, CHIP_ADCDAC_CTRL */
- 0x3c3c, /* 0x0010, CHIP_DAC_VOL */
- 0x0000, /* 0x0012, reserved */
- 0x015f, /* 0x0014, CHIP_PAD_STRENGTH */
- 0x0000, /* 0x0016, reserved */
- 0x0000, /* 0x0018, reserved */
- 0x0000, /* 0x001A, reserved */
- 0x0000, /* 0x001E, reserved */
- 0x0000, /* 0x0020, CHIP_ANA_ADC_CTRL */
- 0x1818, /* 0x0022, CHIP_ANA_HP_CTRL */
- 0x0111, /* 0x0024, CHIP_ANN_CTRL */
- 0x0000, /* 0x0026, CHIP_LINREG_CTRL */
- 0x0000, /* 0x0028, CHIP_REF_CTRL */
- 0x0000, /* 0x002A, CHIP_MIC_CTRL */
- 0x0000, /* 0x002C, CHIP_LINE_OUT_CTRL */
- 0x0404, /* 0x002E, CHIP_LINE_OUT_VOL */
- 0x7060, /* 0x0030, CHIP_ANA_POWER */
- 0x5000, /* 0x0032, CHIP_PLL_CTRL */
- 0x0000, /* 0x0034, CHIP_CLK_TOP_CTRL */
- 0x0000, /* 0x0036, CHIP_ANA_STATUS */
- 0x0000, /* 0x0038, reserved */
- 0x0000, /* 0x003A, CHIP_ANA_TEST2 */
- 0x0000, /* 0x003C, CHIP_SHORT_CTRL */
- 0x0000, /* reserved */
-};
-
-/* default value of dap registers */
-static const u16 sgtl5000_dap_regs[] = {
- 0x0000, /* 0x0100, DAP_CONTROL */
- 0x0000, /* 0x0102, DAP_PEQ */
- 0x0040, /* 0x0104, DAP_BASS_ENHANCE */
- 0x051f, /* 0x0106, DAP_BASS_ENHANCE_CTRL */
- 0x0000, /* 0x0108, DAP_AUDIO_EQ */
- 0x0040, /* 0x010A, DAP_SGTL_SURROUND */
- 0x0000, /* 0x010C, DAP_FILTER_COEF_ACCESS */
- 0x0000, /* 0x010E, DAP_COEF_WR_B0_MSB */
- 0x0000, /* 0x0110, DAP_COEF_WR_B0_LSB */
- 0x0000, /* 0x0112, reserved */
- 0x0000, /* 0x0114, reserved */
- 0x002f, /* 0x0116, DAP_AUDIO_EQ_BASS_BAND0 */
- 0x002f, /* 0x0118, DAP_AUDIO_EQ_BAND0 */
- 0x002f, /* 0x011A, DAP_AUDIO_EQ_BAND2 */
- 0x002f, /* 0x011C, DAP_AUDIO_EQ_BAND3 */
- 0x002f, /* 0x011E, DAP_AUDIO_EQ_TREBLE_BAND4 */
- 0x8000, /* 0x0120, DAP_MAIN_CHAN */
- 0x0000, /* 0x0122, DAP_MIX_CHAN */
- 0x0510, /* 0x0124, DAP_AVC_CTRL */
- 0x1473, /* 0x0126, DAP_AVC_THRESHOLD */
- 0x0028, /* 0x0128, DAP_AVC_ATTACK */
- 0x0050, /* 0x012A, DAP_AVC_DECAY */
- 0x0000, /* 0x012C, DAP_COEF_WR_B1_MSB */
- 0x0000, /* 0x012E, DAP_COEF_WR_B1_LSB */
- 0x0000, /* 0x0130, DAP_COEF_WR_B2_MSB */
- 0x0000, /* 0x0132, DAP_COEF_WR_B2_LSB */
- 0x0000, /* 0x0134, DAP_COEF_WR_A1_MSB */
- 0x0000, /* 0x0136, DAP_COEF_WR_A1_LSB */
- 0x0000, /* 0x0138, DAP_COEF_WR_A2_MSB */
- 0x0000, /* 0x013A, DAP_COEF_WR_A2_LSB */
+/* default value of sgtl5000 registers */
+static const u16 sgtl5000_regs[SGTL5000_MAX_REG_OFFSET] = {
+ [SGTL5000_CHIP_CLK_CTRL] = 0x0008,
+ [SGTL5000_CHIP_I2S_CTRL] = 0x0010,
+ [SGTL5000_CHIP_SSS_CTRL] = 0x0008,
+ [SGTL5000_CHIP_DAC_VOL] = 0x3c3c,
+ [SGTL5000_CHIP_PAD_STRENGTH] = 0x015f,
+ [SGTL5000_CHIP_ANA_HP_CTRL] = 0x1818,
+ [SGTL5000_CHIP_ANA_CTRL] = 0x0111,
+ [SGTL5000_CHIP_LINE_OUT_VOL] = 0x0404,
+ [SGTL5000_CHIP_ANA_POWER] = 0x7060,
+ [SGTL5000_CHIP_PLL_CTRL] = 0x5000,
+ [SGTL5000_DAP_BASS_ENHANCE] = 0x0040,
+ [SGTL5000_DAP_BASS_ENHANCE_CTRL] = 0x051f,
+ [SGTL5000_DAP_SURROUND] = 0x0040,
+ [SGTL5000_DAP_EQ_BASS_BAND0] = 0x002f,
+ [SGTL5000_DAP_EQ_BASS_BAND1] = 0x002f,
+ [SGTL5000_DAP_EQ_BASS_BAND2] = 0x002f,
+ [SGTL5000_DAP_EQ_BASS_BAND3] = 0x002f,
+ [SGTL5000_DAP_EQ_BASS_BAND4] = 0x002f,
+ [SGTL5000_DAP_MAIN_CHAN] = 0x8000,
+ [SGTL5000_DAP_AVC_CTRL] = 0x0510,
+ [SGTL5000_DAP_AVC_THRESHOLD] = 0x1473,
+ [SGTL5000_DAP_AVC_ATTACK] = 0x0028,
+ [SGTL5000_DAP_AVC_DECAY] = 0x0050,
};
/* regulator supplies for sgtl5000, VDDD is an optional external supply */
@@ -1022,12 +980,10 @@
static int sgtl5000_restore_regs(struct snd_soc_codec *codec)
{
u16 *cache = codec->reg_cache;
- int i;
- int regular_regs = SGTL5000_CHIP_SHORT_CTRL >> 1;
+ u16 reg;
/* restore regular registers */
- for (i = 0; i < regular_regs; i++) {
- int reg = i << 1;
+ for (reg = 0; reg <= SGTL5000_CHIP_SHORT_CTRL; reg += 2) {
/* this regs depends on the others */
if (reg == SGTL5000_CHIP_ANA_POWER ||
@@ -1037,35 +993,31 @@
reg == SGTL5000_CHIP_CLK_CTRL)
continue;
- snd_soc_write(codec, reg, cache[i]);
+ snd_soc_write(codec, reg, cache[reg]);
}
/* restore dap registers */
- for (i = SGTL5000_DAP_REG_OFFSET >> 1;
- i < SGTL5000_MAX_REG_OFFSET >> 1; i++) {
- int reg = i << 1;
-
- snd_soc_write(codec, reg, cache[i]);
- }
+ for (reg = SGTL5000_DAP_REG_OFFSET; reg < SGTL5000_MAX_REG_OFFSET; reg += 2)
+ snd_soc_write(codec, reg, cache[reg]);
/*
* restore power and other regs according
* to set_power() and set_clock()
*/
snd_soc_write(codec, SGTL5000_CHIP_LINREG_CTRL,
- cache[SGTL5000_CHIP_LINREG_CTRL >> 1]);
+ cache[SGTL5000_CHIP_LINREG_CTRL]);
snd_soc_write(codec, SGTL5000_CHIP_ANA_POWER,
- cache[SGTL5000_CHIP_ANA_POWER >> 1]);
+ cache[SGTL5000_CHIP_ANA_POWER]);
snd_soc_write(codec, SGTL5000_CHIP_CLK_CTRL,
- cache[SGTL5000_CHIP_CLK_CTRL >> 1]);
+ cache[SGTL5000_CHIP_CLK_CTRL]);
snd_soc_write(codec, SGTL5000_CHIP_REF_CTRL,
- cache[SGTL5000_CHIP_REF_CTRL >> 1]);
+ cache[SGTL5000_CHIP_REF_CTRL]);
snd_soc_write(codec, SGTL5000_CHIP_LINE_OUT_CTRL,
- cache[SGTL5000_CHIP_LINE_OUT_CTRL >> 1]);
+ cache[SGTL5000_CHIP_LINE_OUT_CTRL]);
return 0;
}
@@ -1460,16 +1412,6 @@
if (!sgtl5000)
return -ENOMEM;
- /*
- * copy DAP default values to default value array.
- * sgtl5000 register space has a big hole, merge it
- * at init phase makes life easy.
- * FIXME: should we drop 'const' of sgtl5000_regs?
- */
- memcpy((void *)(&sgtl5000_regs[0] + (SGTL5000_DAP_REG_OFFSET >> 1)),
- sgtl5000_dap_regs,
- SGTL5000_MAX_REG_OFFSET - SGTL5000_DAP_REG_OFFSET);
-
i2c_set_clientdata(client, sgtl5000);
ret = snd_soc_register_codec(&client->dev,
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index 84f4ad5..9801cd7 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -431,7 +431,8 @@
static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- u16 reg = snd_soc_read(codec, SSM2602_PWR) & 0xff7f;
+ u16 reg = snd_soc_read(codec, SSM2602_PWR);
+ reg &= ~(PWR_POWER_OFF | PWR_OSC_PDN);
switch (level) {
case SND_SOC_BIAS_ON:
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 7f7bdc9..5003ab5 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -14,12 +14,15 @@
#include <linux/firmware.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
+#include <linux/device.h>
#include <linux/printk.h>
#include <linux/ratelimit.h>
#include <linux/debugfs.h>
#include <linux/mfd/wcd9310/core.h>
#include <linux/mfd/wcd9310/registers.h>
#include <linux/mfd/wcd9310/pdata.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
#include <sound/jack.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
@@ -36,9 +39,13 @@
#define BITS_PER_REG 8
#define TABLA_RX_DAI_ID 1
#define TABLA_TX_DAI_ID 2
+#define TABLA_CFILT_FAST_MODE 0x00
+#define TABLA_CFILT_SLOW_MODE 0x40
#define TABLA_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
+#define TABLA_I2S_MASTER_MODE_MASK 0x08
+
static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
@@ -55,6 +62,23 @@
u16 mbhc_reg;
u16 int_rbias;
u16 ctl_reg;
+ u8 cfilt_sel;
+};
+
+/* Codec supports 2 IIR filters */
+enum {
+ IIR1 = 0,
+ IIR2,
+ IIR_MAX,
+};
+/* Codec supports 5 bands */
+enum {
+ BAND1 = 0,
+ BAND2,
+ BAND3,
+ BAND4,
+ BAND5,
+ BAND_MAX,
};
struct tabla_priv {
@@ -69,6 +93,7 @@
bool clock_active;
bool config_mode_active;
bool mbhc_polling_active;
+ bool fake_insert_context;
int buttons_pressed;
struct tabla_mbhc_calibration *calibration;
@@ -87,6 +112,9 @@
u8 cfilt_k_value;
bool mbhc_micbias_switched;
+ /*track tabla interface type*/
+ u8 intf_type;
+
u32 hph_status; /* track headhpone status */
/* define separate work for left and right headphone OCP to avoid
* additional checking on which OCP event to report so no locking
@@ -196,6 +224,173 @@
return 0;
}
+static int tabla_get_iir_enable_audio_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int iir_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->reg;
+ int band_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+
+ ucontrol->value.integer.value[0] =
+ snd_soc_read(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx)) &
+ (1 << band_idx);
+
+ pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
+ iir_idx, band_idx,
+ (uint32_t)ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int tabla_put_iir_enable_audio_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int iir_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->reg;
+ int band_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+ int value = ucontrol->value.integer.value[0];
+
+ /* Mask first 5 bits, 6-8 are reserved */
+ snd_soc_update_bits(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx),
+ (1 << band_idx), (value << band_idx));
+
+ pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
+ iir_idx, band_idx, value);
+ return 0;
+}
+static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
+ int iir_idx, int band_idx,
+ int coeff_idx)
+{
+ /* Address does not automatically update if reading */
+ snd_soc_update_bits(codec,
+ (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+ 0x1F, band_idx * BAND_MAX + coeff_idx);
+
+ /* Mask bits top 2 bits since they are reserved */
+ return ((snd_soc_read(codec,
+ (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
+ (snd_soc_read(codec,
+ (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
+ (snd_soc_read(codec,
+ (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
+ (snd_soc_read(codec,
+ (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
+ 0x3FFFFFFF;
+}
+
+static int tabla_get_iir_band_audio_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int iir_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->reg;
+ int band_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+
+ ucontrol->value.integer.value[0] =
+ get_iir_band_coeff(codec, iir_idx, band_idx, 0);
+ ucontrol->value.integer.value[1] =
+ get_iir_band_coeff(codec, iir_idx, band_idx, 1);
+ ucontrol->value.integer.value[2] =
+ get_iir_band_coeff(codec, iir_idx, band_idx, 2);
+ ucontrol->value.integer.value[3] =
+ get_iir_band_coeff(codec, iir_idx, band_idx, 3);
+ ucontrol->value.integer.value[4] =
+ get_iir_band_coeff(codec, iir_idx, band_idx, 4);
+
+ pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
+ "%s: IIR #%d band #%d b1 = 0x%x\n"
+ "%s: IIR #%d band #%d b2 = 0x%x\n"
+ "%s: IIR #%d band #%d a1 = 0x%x\n"
+ "%s: IIR #%d band #%d a2 = 0x%x\n",
+ __func__, iir_idx, band_idx,
+ (uint32_t)ucontrol->value.integer.value[0],
+ __func__, iir_idx, band_idx,
+ (uint32_t)ucontrol->value.integer.value[1],
+ __func__, iir_idx, band_idx,
+ (uint32_t)ucontrol->value.integer.value[2],
+ __func__, iir_idx, band_idx,
+ (uint32_t)ucontrol->value.integer.value[3],
+ __func__, iir_idx, band_idx,
+ (uint32_t)ucontrol->value.integer.value[4]);
+ return 0;
+}
+
+static void set_iir_band_coeff(struct snd_soc_codec *codec,
+ int iir_idx, int band_idx,
+ int coeff_idx, uint32_t value)
+{
+ /* Mask top 3 bits, 6-8 are reserved */
+ /* Update address manually each time */
+ snd_soc_update_bits(codec,
+ (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+ 0x1F, band_idx * BAND_MAX + coeff_idx);
+
+ /* Mask top 2 bits, 7-8 are reserved */
+ snd_soc_update_bits(codec,
+ (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
+ 0x3F, (value >> 24) & 0x3F);
+
+ /* Isolate 8bits at a time */
+ snd_soc_update_bits(codec,
+ (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
+ 0xFF, (value >> 16) & 0xFF);
+
+ snd_soc_update_bits(codec,
+ (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
+ 0xFF, (value >> 8) & 0xFF);
+
+ snd_soc_update_bits(codec,
+ (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
+ 0xFF, value & 0xFF);
+}
+
+static int tabla_put_iir_band_audio_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int iir_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->reg;
+ int band_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+
+ set_iir_band_coeff(codec, iir_idx, band_idx, 0,
+ ucontrol->value.integer.value[0]);
+ set_iir_band_coeff(codec, iir_idx, band_idx, 1,
+ ucontrol->value.integer.value[1]);
+ set_iir_band_coeff(codec, iir_idx, band_idx, 2,
+ ucontrol->value.integer.value[2]);
+ set_iir_band_coeff(codec, iir_idx, band_idx, 3,
+ ucontrol->value.integer.value[3]);
+ set_iir_band_coeff(codec, iir_idx, band_idx, 4,
+ ucontrol->value.integer.value[4]);
+
+ pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
+ "%s: IIR #%d band #%d b1 = 0x%x\n"
+ "%s: IIR #%d band #%d b2 = 0x%x\n"
+ "%s: IIR #%d band #%d a1 = 0x%x\n"
+ "%s: IIR #%d band #%d a2 = 0x%x\n",
+ __func__, iir_idx, band_idx,
+ get_iir_band_coeff(codec, iir_idx, band_idx, 0),
+ __func__, iir_idx, band_idx,
+ get_iir_band_coeff(codec, iir_idx, band_idx, 1),
+ __func__, iir_idx, band_idx,
+ get_iir_band_coeff(codec, iir_idx, band_idx, 2),
+ __func__, iir_idx, band_idx,
+ get_iir_band_coeff(codec, iir_idx, band_idx, 3),
+ __func__, iir_idx, band_idx,
+ get_iir_band_coeff(codec, iir_idx, band_idx, 4));
+ return 0;
+}
+
static const char *tabla_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
static const struct soc_enum tabla_ear_pa_gain_enum[] = {
SOC_ENUM_SINGLE_EXT(2, tabla_ear_pa_gain_text),
@@ -273,13 +468,6 @@
SOC_SINGLE_TLV("LINEOUT5 Volume", TABLA_A_RX_LINE_5_GAIN, 0, 12, 1,
line_gain),
- SOC_SINGLE("RX1 CHAIN INVERT Switch", TABLA_A_CDC_RX1_B6_CTL, 4, 1, 0),
- SOC_SINGLE("RX2 CHAIN INVERT Switch", TABLA_A_CDC_RX2_B6_CTL, 4, 1, 0),
- SOC_SINGLE("RX3 CHAIN INVERT Switch", TABLA_A_CDC_RX3_B6_CTL, 4, 1, 0),
- SOC_SINGLE("RX4 CHAIN INVERT Switch", TABLA_A_CDC_RX4_B6_CTL, 4, 1, 0),
- SOC_SINGLE("RX5 CHAIN INVERT Switch", TABLA_A_CDC_RX5_B6_CTL, 4, 1, 0),
- SOC_SINGLE("RX6 CHAIN INVERT Switch", TABLA_A_CDC_RX6_B6_CTL, 4, 1, 0),
-
SOC_SINGLE_TLV("HPHL Volume", TABLA_A_RX_HPH_L_GAIN, 0, 12, 1,
line_gain),
SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
@@ -334,6 +522,7 @@
SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
+ SOC_SINGLE("MICBIAS2 CAPLESS Switch", TABLA_A_MICB_2_CTL, 4, 1, 1),
SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_A_MICB_4_CTL, 4, 1, 1),
@@ -376,6 +565,48 @@
SOC_ENUM("RX5 HPF cut off", cf_rxmix5_enum),
SOC_ENUM("RX6 HPF cut off", cf_rxmix6_enum),
SOC_ENUM("RX7 HPF cut off", cf_rxmix7_enum),
+
+ SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
+ tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
+ tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
+ tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
+ tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
+ tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
+ tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
+ tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
+ tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
+ tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
+ tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
+
+ SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
+ tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
+ tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
+ tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
+ tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
+ tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
+ tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
+ tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
+ tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
+ tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
+ tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
};
static const char *rx_mix1_text[] = {
@@ -383,6 +614,10 @@
"RX5", "RX6", "RX7"
};
+static const char *rx_dsm_text[] = {
+ "CIC_OUT", "DSM_INV"
+};
+
static const char *sb_tx1_mux_text[] = {
"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
"DEC1"
@@ -500,6 +735,12 @@
static const struct soc_enum rx7_mix1_inp2_chain_enum =
SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 4, 12, rx_mix1_text);
+static const struct soc_enum rx4_dsm_enum =
+ SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B6_CTL, 4, 2, rx_dsm_text);
+
+static const struct soc_enum rx6_dsm_enum =
+ SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B6_CTL, 4, 2, rx_dsm_text);
+
static const struct soc_enum sb_tx5_mux_enum =
SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
@@ -601,6 +842,12 @@
static const struct snd_kcontrol_new rx7_mix1_inp2_mux =
SOC_DAPM_ENUM("RX7 MIX1 INP2 Mux", rx7_mix1_inp2_chain_enum);
+static const struct snd_kcontrol_new rx4_dsm_mux =
+ SOC_DAPM_ENUM("RX4 DSM MUX Mux", rx4_dsm_enum);
+
+static const struct snd_kcontrol_new rx6_dsm_mux =
+ SOC_DAPM_ENUM("RX6 DSM MUX Mux", rx6_dsm_enum);
+
static const struct snd_kcontrol_new sb_tx5_mux =
SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
@@ -663,24 +910,12 @@
static const struct snd_kcontrol_new hphl_switch[] = {
SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
};
-static const struct snd_kcontrol_new hphr_switch[] = {
- SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_R_DAC_CTL, 6, 1, 0)
-};
-static const struct snd_kcontrol_new lineout1_switch[] = {
- SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_1_DAC_CTL, 6, 1, 0)
-};
-static const struct snd_kcontrol_new lineout2_switch[] = {
- SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_2_DAC_CTL, 6, 1, 0)
-};
-static const struct snd_kcontrol_new lineout3_switch[] = {
- SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0)
-};
-static const struct snd_kcontrol_new lineout4_switch[] = {
- SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0)
-};
-static const struct snd_kcontrol_new lineout5_switch[] = {
- SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_5_DAC_CTL, 6, 1, 0)
-};
+
+static const struct snd_kcontrol_new lineout3_ground_switch =
+ SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
+
+static const struct snd_kcontrol_new lineout4_ground_switch =
+ SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
int enable)
@@ -950,41 +1185,6 @@
return 0;
}
-static void tabla_codec_update_cfilt_usage(struct snd_soc_codec *codec,
- u8 cfilt_sel, int inc)
-{
- struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
- u32 *cfilt_cnt_ptr = NULL;
- u16 micb_cfilt_reg;
-
- switch (cfilt_sel) {
- case TABLA_CFILT1_SEL:
- cfilt_cnt_ptr = &tabla->cfilt1_cnt;
- micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
- break;
- case TABLA_CFILT2_SEL:
- cfilt_cnt_ptr = &tabla->cfilt2_cnt;
- micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
- break;
- case TABLA_CFILT3_SEL:
- cfilt_cnt_ptr = &tabla->cfilt3_cnt;
- micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
- break;
- default:
- return; /* should not happen */
- }
-
- if (inc) {
- if (!(*cfilt_cnt_ptr)++)
- snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
- } else {
- /* check if count not zero, decrement
- * then check if zero, go ahead disable cfilter
- */
- if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr))
- snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
- }
-}
static void tabla_codec_disable_button_presses(struct snd_soc_codec *codec)
{
@@ -1022,6 +1222,84 @@
}
}
+static void tabla_codec_switch_cfilt_mode(struct snd_soc_codec *codec,
+ int mode)
+{
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+ u8 reg_mode_val, cur_mode_val;
+ bool mbhc_was_polling = false;
+
+ if (mode)
+ reg_mode_val = TABLA_CFILT_FAST_MODE;
+ else
+ reg_mode_val = TABLA_CFILT_SLOW_MODE;
+
+ cur_mode_val = snd_soc_read(codec,
+ tabla->mbhc_bias_regs.cfilt_ctl) & 0x40;
+
+ if (cur_mode_val != reg_mode_val) {
+ if (tabla->mbhc_polling_active) {
+ tabla_codec_pause_hs_polling(codec);
+ mbhc_was_polling = true;
+ }
+ snd_soc_update_bits(codec,
+ tabla->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
+ if (mbhc_was_polling)
+ tabla_codec_start_hs_polling(codec);
+ pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
+ cur_mode_val, reg_mode_val);
+ } else {
+ pr_debug("%s: CFILT Value is already %x\n",
+ __func__, cur_mode_val);
+ }
+}
+
+static void tabla_codec_update_cfilt_usage(struct snd_soc_codec *codec,
+ u8 cfilt_sel, int inc)
+{
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+ u32 *cfilt_cnt_ptr = NULL;
+ u16 micb_cfilt_reg;
+
+ switch (cfilt_sel) {
+ case TABLA_CFILT1_SEL:
+ cfilt_cnt_ptr = &tabla->cfilt1_cnt;
+ micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
+ break;
+ case TABLA_CFILT2_SEL:
+ cfilt_cnt_ptr = &tabla->cfilt2_cnt;
+ micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
+ break;
+ case TABLA_CFILT3_SEL:
+ cfilt_cnt_ptr = &tabla->cfilt3_cnt;
+ micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
+ break;
+ default:
+ return; /* should not happen */
+ }
+
+ if (inc) {
+ if (!(*cfilt_cnt_ptr)++) {
+ /* Switch CFILT to slow mode if MBHC CFILT being used */
+ if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
+ tabla_codec_switch_cfilt_mode(codec, 0);
+
+ snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
+ }
+ } else {
+ /* check if count not zero, decrement
+ * then check if zero, go ahead disable cfilter
+ */
+ if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
+ snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
+
+ /* Switch CFILT to fast mode if MBHC CFILT being used */
+ if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
+ tabla_codec_switch_cfilt_mode(codec, 1);
+ }
+ }
+}
+
static int tabla_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
{
int rc = -EINVAL;
@@ -1075,10 +1353,13 @@
{
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
int cfilt_k_val;
+ bool mbhc_was_polling = false;
switch (vddio_switch) {
case 1:
if (tabla->mbhc_polling_active) {
+
+ tabla_codec_pause_hs_polling(codec);
/* Enable Mic Bias switch to VDDIO */
tabla->cfilt_k_value = snd_soc_read(codec,
tabla->mbhc_bias_regs.cfilt_val);
@@ -1092,6 +1373,7 @@
tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x80);
snd_soc_update_bits(codec,
tabla->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
+ tabla_codec_start_hs_polling(codec);
tabla->mbhc_micbias_switched = true;
pr_debug("%s: Enabled MBHC Mic bias to VDDIO Switch\n",
@@ -1101,6 +1383,10 @@
case 0:
if (tabla->mbhc_micbias_switched) {
+ if (tabla->mbhc_polling_active) {
+ tabla_codec_pause_hs_polling(codec);
+ mbhc_was_polling = true;
+ }
/* Disable Mic Bias switch to VDDIO */
if (tabla->cfilt_k_value != 0)
snd_soc_update_bits(codec,
@@ -1111,6 +1397,9 @@
snd_soc_update_bits(codec,
tabla->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
+ if (mbhc_was_polling)
+ tabla_codec_start_hs_polling(codec);
+
tabla->mbhc_micbias_switched = false;
pr_debug("%s: Disabled MBHC Mic bias to VDDIO Switch\n",
__func__);
@@ -1236,6 +1525,8 @@
{
struct snd_soc_codec *codec = w->codec;
+ pr_debug("%s %d %s\n", __func__, event, w->name);
+
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
@@ -1294,6 +1585,23 @@
}
return 0;
}
+static int tabla_hphr_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+
+ pr_debug("%s %s %d\n", __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
+ break;
+ }
+ return 0;
+}
static void hphocp_off_report(struct tabla_priv *tabla,
u32 jack_status, int irq)
@@ -1411,6 +1719,8 @@
pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
}
+ micbias_regs->cfilt_sel = cfilt;
+
switch (cfilt) {
case TABLA_CFILT1_SEL:
micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_1_VAL;
@@ -1426,6 +1736,31 @@
break;
}
}
+static const struct snd_soc_dapm_widget tabla_dapm_i2s_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", TABLA_A_CDC_CLK_RX_I2S_CTL,
+ 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", TABLA_A_CDC_CLK_TX_I2S_CTL, 4,
+ 0, NULL, 0),
+};
+
+static int tabla_lineout_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+
+ pr_debug("%s %s %d\n", __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
+ break;
+ }
+ return 0;
+}
static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
/*RX stuff */
@@ -1438,6 +1773,8 @@
SND_SOC_DAPM_AIF_IN("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIM RX4", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
/* Headphone */
SND_SOC_DAPM_OUTPUT("HEADPHONE"),
@@ -1450,8 +1787,10 @@
SND_SOC_DAPM_PGA_E("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MIXER("HPHR DAC", TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
- hphr_switch, ARRAY_SIZE(hphr_switch)),
+
+ SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
+ tabla_hphr_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
/* Speaker */
SND_SOC_DAPM_OUTPUT("LINEOUT1"),
@@ -1476,16 +1815,25 @@
tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MIXER("LINEOUT1 DAC", TABLA_A_RX_LINE_1_DAC_CTL, 7, 0,
- lineout1_switch, ARRAY_SIZE(lineout1_switch)),
- SND_SOC_DAPM_MIXER("LINEOUT2 DAC", TABLA_A_RX_LINE_2_DAC_CTL, 7, 0,
- lineout2_switch, ARRAY_SIZE(lineout2_switch)),
- SND_SOC_DAPM_MIXER("LINEOUT3 DAC", TABLA_A_RX_LINE_3_DAC_CTL, 7, 0,
- lineout3_switch, ARRAY_SIZE(lineout3_switch)),
- SND_SOC_DAPM_MIXER("LINEOUT4 DAC", TABLA_A_RX_LINE_4_DAC_CTL, 7, 0,
- lineout4_switch, ARRAY_SIZE(lineout4_switch)),
- SND_SOC_DAPM_MIXER("LINEOUT5 DAC", TABLA_A_RX_LINE_5_DAC_CTL, 7, 0,
- lineout5_switch, ARRAY_SIZE(lineout5_switch)),
+ SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TABLA_A_RX_LINE_1_DAC_CTL, 7, 0
+ , tabla_lineout_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TABLA_A_RX_LINE_2_DAC_CTL, 7, 0
+ , tabla_lineout_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("LINEOUT3 DAC", NULL, TABLA_A_RX_LINE_3_DAC_CTL, 7, 0
+ , tabla_lineout_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SWITCH("LINEOUT3 DAC GROUND", SND_SOC_NOPM, 0, 0,
+ &lineout3_ground_switch),
+ SND_SOC_DAPM_DAC_E("LINEOUT4 DAC", NULL, TABLA_A_RX_LINE_4_DAC_CTL, 7, 0
+ , tabla_lineout_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SWITCH("LINEOUT4 DAC GROUND", SND_SOC_NOPM, 0, 0,
+ &lineout4_ground_switch),
+ SND_SOC_DAPM_DAC_E("LINEOUT5 DAC", NULL, TABLA_A_RX_LINE_5_DAC_CTL, 7, 0
+ , tabla_lineout_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MIXER_E("RX1 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
@@ -1502,6 +1850,15 @@
SND_SOC_DAPM_MIXER_E("RX7 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0,
+ &rx4_dsm_mux, tabla_codec_reset_interpolator,
+ SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0,
+ &rx6_dsm_mux, tabla_codec_reset_interpolator,
+ SND_SOC_DAPM_PRE_PMU),
+
SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
@@ -1701,6 +2058,19 @@
SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
};
+static const struct snd_soc_dapm_route audio_i2s_map[] = {
+ {"RX_I2S_CLK", NULL, "CDC_CONN"},
+ {"SLIM RX1", NULL, "RX_I2S_CLK"},
+ {"SLIM RX2", NULL, "RX_I2S_CLK"},
+ {"SLIM RX3", NULL, "RX_I2S_CLK"},
+ {"SLIM RX4", NULL, "RX_I2S_CLK"},
+
+ {"SLIM TX7", NULL, "TX_I2S_CLK"},
+ {"SLIM TX8", NULL, "TX_I2S_CLK"},
+ {"SLIM TX9", NULL, "TX_I2S_CLK"},
+ {"SLIM TX10", NULL, "TX_I2S_CLK"},
+};
+
static const struct snd_soc_dapm_route audio_map[] = {
/* SLIMBUS Connections */
@@ -1767,7 +2137,7 @@
{"DAC1", "Switch", "RX1 CHAIN"},
{"HPHL DAC", "Switch", "RX1 CHAIN"},
- {"HPHR DAC", "Switch", "RX2 CHAIN"},
+ {"HPHR DAC", NULL, "RX2 CHAIN"},
{"LINEOUT1", NULL, "LINEOUT1 PA"},
{"LINEOUT2", NULL, "LINEOUT2 PA"},
@@ -1781,21 +2151,20 @@
{"LINEOUT4 PA", NULL, "LINEOUT4 DAC"},
{"LINEOUT5 PA", NULL, "LINEOUT5 DAC"},
+ {"LINEOUT1 DAC", NULL, "RX3 MIX1"},
+ {"LINEOUT5 DAC", NULL, "RX7 MIX1"},
+
{"RX1 CHAIN", NULL, "RX1 MIX1"},
{"RX2 CHAIN", NULL, "RX2 MIX1"},
{"RX1 CHAIN", NULL, "ANC"},
{"RX2 CHAIN", NULL, "ANC"},
- {"LINEOUT1 DAC", "Switch", "RX3 MIX1"},
- {"LINEOUT2 DAC", "Switch", "RX4 MIX1"},
- {"LINEOUT3 DAC", "Switch", "RX3 MIX1"},
- {"LINEOUT4 DAC", "Switch", "RX4 MIX1"},
- {"LINEOUT5 DAC", "Switch", "RX7 MIX1"},
{"CP", NULL, "RX_BIAS"},
{"LINEOUT1 DAC", NULL, "RX_BIAS"},
{"LINEOUT2 DAC", NULL, "RX_BIAS"},
{"LINEOUT3 DAC", NULL, "RX_BIAS"},
{"LINEOUT4 DAC", NULL, "RX_BIAS"},
+ {"LINEOUT5 DAC", NULL, "RX_BIAS"},
{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
{"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
@@ -1814,45 +2183,73 @@
{"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
{"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
+ {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
{"RX1 MIX1 INP1", "IIR1", "IIR1"},
{"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
{"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
+ {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
{"RX1 MIX1 INP2", "IIR1", "IIR1"},
{"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
{"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
+ {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
{"RX2 MIX1 INP1", "IIR1", "IIR1"},
{"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
{"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
+ {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
{"RX2 MIX1 INP2", "IIR1", "IIR1"},
{"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
{"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
+ {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
{"RX3 MIX1 INP1", "IIR1", "IIR1"},
{"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
{"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
+ {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
{"RX3 MIX1 INP2", "IIR1", "IIR1"},
{"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
{"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
+ {"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
{"RX4 MIX1 INP1", "IIR1", "IIR1"},
{"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
{"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
+ {"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
{"RX4 MIX1 INP2", "IIR1", "IIR1"},
{"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
{"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
+ {"RX5 MIX1 INP1", "RX4", "SLIM RX4"},
{"RX5 MIX1 INP1", "IIR1", "IIR1"},
{"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
{"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
+ {"RX5 MIX1 INP2", "RX4", "SLIM RX4"},
{"RX5 MIX1 INP2", "IIR1", "IIR1"},
{"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
{"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
+ {"RX6 MIX1 INP1", "RX4", "SLIM RX4"},
{"RX6 MIX1 INP1", "IIR1", "IIR1"},
{"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
{"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
+ {"RX6 MIX1 INP2", "RX4", "SLIM RX4"},
{"RX6 MIX1 INP2", "IIR1", "IIR1"},
{"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
{"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
+ {"RX7 MIX1 INP1", "RX4", "SLIM RX4"},
{"RX7 MIX1 INP1", "IIR1", "IIR1"},
{"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
{"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
+ {"RX7 MIX1 INP2", "RX4", "SLIM RX4"},
{"RX7 MIX1 INP2", "IIR1", "IIR1"},
/* Decimator Inputs */
@@ -1917,6 +2314,41 @@
{"MIC BIAS4 External", NULL, "LDO_H"},
};
+static const struct snd_soc_dapm_route tabla_1_x_lineout_2_to_4_map[] = {
+
+ {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
+ {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
+
+ {"LINEOUT2 DAC", NULL, "RX4 DSM MUX"},
+
+ {"LINEOUT3 DAC", NULL, "RX5 MIX1"},
+ {"LINEOUT3 DAC GROUND", "Switch", "RX3 MIX1"},
+ {"LINEOUT3 DAC", NULL, "LINEOUT3 DAC GROUND"},
+
+ {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
+ {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
+
+ {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
+ {"LINEOUT4 DAC GROUND", "Switch", "RX4 DSM MUX"},
+ {"LINEOUT4 DAC", NULL, "LINEOUT4 DAC GROUND"},
+};
+
+
+static const struct snd_soc_dapm_route tabla_2_x_lineout_2_to_4_map[] = {
+
+ {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
+ {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
+
+ {"LINEOUT3 DAC", NULL, "RX4 DSM MUX"},
+
+ {"LINEOUT2 DAC", NULL, "RX5 MIX1"},
+
+ {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
+ {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
+
+ {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
+};
+
static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
{
return tabla_reg_readable[reg];
@@ -1931,6 +2363,11 @@
if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
return 1;
+ /* IIR Coeff registers are not cacheable */
+ if ((reg >= TABLA_A_CDC_IIR1_COEF_B1_CTL) &&
+ (reg <= TABLA_A_CDC_IIR2_COEF_B5_CTL))
+ return 1;
+
return 0;
}
@@ -1939,12 +2376,10 @@
unsigned int value)
{
int ret;
- pr_debug("%s: write reg %x val %x\n", __func__, reg, value);
BUG_ON(reg > TABLA_MAX_REGISTER);
if (!tabla_volatile(codec, reg)) {
- pr_debug("writing to cache\n");
ret = snd_soc_cache_write(codec, reg, value);
if (ret != 0)
dev_err(codec->dev, "Cache write to %x failed: %d\n",
@@ -1963,10 +2398,8 @@
if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
reg < codec->driver->reg_cache_size) {
- pr_debug("reading from cache\n");
ret = snd_soc_cache_read(codec, reg, &val);
if (ret >= 0) {
- pr_debug("register %x, value %x\n", reg, val);
return val;
} else
dev_err(codec->dev, "Cache read from %x failed: %d\n",
@@ -1974,7 +2407,6 @@
}
val = tabla_reg_read(codec->control_data, reg);
- pr_debug("%s: read reg %x val %x\n", __func__, reg, val);
return val;
}
@@ -2111,7 +2543,7 @@
snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL, 0xFF);
snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL, 0x20);
- snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x08);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0xF8);
snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0xEE);
snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL, 0xFC);
snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL, 0xCE);
@@ -2191,7 +2623,39 @@
static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
+ u8 val = 0;
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
+
pr_debug("%s\n", __func__);
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* CPU is master */
+ if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+ if (dai->id == TABLA_TX_DAI_ID)
+ snd_soc_update_bits(dai->codec,
+ TABLA_A_CDC_CLK_TX_I2S_CTL,
+ TABLA_I2S_MASTER_MODE_MASK, 0);
+ else if (dai->id == TABLA_RX_DAI_ID)
+ snd_soc_update_bits(dai->codec,
+ TABLA_A_CDC_CLK_RX_I2S_CTL,
+ TABLA_I2S_MASTER_MODE_MASK, 0);
+ }
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* CPU is slave */
+ if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+ val = TABLA_I2S_MASTER_MODE_MASK;
+ if (dai->id == TABLA_TX_DAI_ID)
+ snd_soc_update_bits(dai->codec,
+ TABLA_A_CDC_CLK_TX_I2S_CTL, val, val);
+ else if (dai->id == TABLA_RX_DAI_ID)
+ snd_soc_update_bits(dai->codec,
+ TABLA_A_CDC_CLK_RX_I2S_CTL, val, val);
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
return 0;
}
@@ -2200,6 +2664,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
u8 path, shift;
u16 tx_fs_reg, rx_fs_reg;
u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
@@ -2255,6 +2720,25 @@
0x03, tx_fs_rate);
}
}
+ if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ snd_soc_update_bits(codec,
+ TABLA_A_CDC_CLK_TX_I2S_CTL,
+ 0x20, 0x20);
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ snd_soc_update_bits(codec,
+ TABLA_A_CDC_CLK_TX_I2S_CTL,
+ 0x20, 0x00);
+ break;
+ default:
+ pr_err("invalid format\n");
+ break;
+ }
+ snd_soc_update_bits(codec, TABLA_A_CDC_CLK_TX_I2S_CTL,
+ 0x03, tx_fs_rate);
+ }
}
/**
@@ -2281,6 +2765,25 @@
0xE0, rx_fs_rate);
}
}
+ if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ snd_soc_update_bits(codec,
+ TABLA_A_CDC_CLK_RX_I2S_CTL,
+ 0x20, 0x20);
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ snd_soc_update_bits(codec,
+ TABLA_A_CDC_CLK_RX_I2S_CTL,
+ 0x20, 0x00);
+ break;
+ default:
+ pr_err("invalid format\n");
+ break;
+ }
+ snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_I2S_CTL,
+ 0x03, (rx_fs_rate >> 0x05));
+ }
}
return 0;
@@ -2324,6 +2827,37 @@
.ops = &tabla_dai_ops,
},
};
+
+static struct snd_soc_dai_driver tabla_i2s_dai[] = {
+ {
+ .name = "tabla_i2s_rx1",
+ .id = 1,
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .rates = WCD9310_RATES,
+ .formats = TABLA_FORMATS,
+ .rate_max = 48000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &tabla_dai_ops,
+ },
+ {
+ .name = "tabla_i2s_tx1",
+ .id = 2,
+ .capture = {
+ .stream_name = "AIF1 Capture",
+ .rates = WCD9310_RATES,
+ .formats = TABLA_FORMATS,
+ .rate_max = 48000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &tabla_dai_ops,
+ },
+};
static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
{
u8 bias_msb, bias_lsb;
@@ -2379,6 +2913,7 @@
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
struct tabla_mbhc_calibration *calibration = tabla->calibration;
short bias_value;
+ u8 cfilt_mode;
if (!calibration) {
pr_err("Error, no tabla calibration\n");
@@ -2397,9 +2932,11 @@
snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
-
- snd_soc_update_bits(codec,
- tabla->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
+ /* Make sure CFILT is in fast mode, save current mode */
+ cfilt_mode = snd_soc_read(codec,
+ tabla->mbhc_bias_regs.cfilt_ctl);
+ snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
+ 0x70, 0x00);
snd_soc_update_bits(codec,
tabla->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
@@ -2422,7 +2959,7 @@
bias_value = tabla_codec_measure_micbias_voltage(codec, 0);
snd_soc_update_bits(codec,
- tabla->mbhc_bias_regs.cfilt_ctl, 0x40, 0x40);
+ tabla->mbhc_bias_regs.cfilt_ctl, 0x40, cfilt_mode);
snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
return bias_value;
@@ -2434,6 +2971,7 @@
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
struct tabla_mbhc_calibration *calibration = tabla->calibration;
int central_bias_enabled = 0;
+ u8 wg_time;
if (!calibration) {
pr_err("Error, no tabla calibration\n");
@@ -2450,20 +2988,28 @@
0x81, 0x01);
snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
0x90, 0x00);
+ wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
+ wg_time += 1;
/* Enable HPH Schmitt Trigger */
- snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x13);
+ snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x11, 0x11);
snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x0C,
calibration->hph_current << 2);
- /* Turn off HPH PAs during insertion detection to avoid false
- * insertion interrupts
+ /* Turn off HPH PAs and DAC's during insertion detection to
+ * avoid false insertion interrupts
*/
if (tabla->mbhc_micbias_switched)
tabla_codec_switch_micbias(codec, 0);
snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
+ snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_DAC_CTL,
+ 0xC0, 0x00);
+ snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_DAC_CTL,
+ 0xC0, 0x00);
+ usleep_range(wg_time * 1000, wg_time * 1000);
/* setup for insetion detection */
+ snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x02, 0x02);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
} else {
/* Make sure the HPH schmitt trigger is OFF */
@@ -2563,6 +3109,10 @@
tabla->calibration = calibration;
tabla_get_mbhc_micbias_regs(codec, &tabla->mbhc_bias_regs);
+ /* Put CFILT in fast mode by default */
+ snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
+ 0x40, TABLA_CFILT_FAST_MODE);
+
INIT_DELAYED_WORK(&tabla->btn0_dwork, btn0_lpress_fn);
INIT_WORK(&tabla->hphlocp_work, hphlocp_off_report);
INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
@@ -2603,7 +3153,6 @@
*/
priv->buttons_pressed |= SND_JACK_BTN_0;
- snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x09);
msleep(100);
schedule_delayed_work(&priv->btn0_dwork, msecs_to_jiffies(400));
@@ -2663,7 +3212,6 @@
priv->buttons_pressed &= ~SND_JACK_BTN_0;
}
- snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x08);
tabla_codec_start_hs_polling(codec);
return IRQ_HANDLED;
@@ -2774,6 +3322,16 @@
0x90, 0x00);
snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
+ if (priv->fake_insert_context) {
+ pr_debug("%s: fake context interrupt, reset insertion\n",
+ __func__);
+ priv->fake_insert_context = false;
+ tabla_codec_shutdown_hs_polling(codec);
+ tabla_codec_enable_hs_detect(codec, 1);
+ return IRQ_HANDLED;
+ }
+
+
ldo_h_on = snd_soc_read(codec, TABLA_A_LDO_H_MODE_1) & 0x80;
micb_cfilt_on = snd_soc_read(codec,
priv->mbhc_bias_regs.cfilt_ctl) & 0x80;
@@ -2800,7 +3358,7 @@
*/
if (priv->mbhc_micbias_switched)
tabla_codec_switch_micbias(codec, 0);
- priv->hph_status &= ~SND_JACK_HEADSET;
+ priv->hph_status &= ~SND_JACK_HEADPHONE;
if (priv->headset_jack) {
pr_debug("%s: Reporting removal\n", __func__);
snd_soc_jack_report(priv->headset_jack,
@@ -2816,7 +3374,25 @@
if (mic_voltage > threshold_fake_insert) {
pr_debug("%s: Fake insertion interrupt, mic_voltage = %x\n",
__func__, mic_voltage);
- tabla_codec_enable_hs_detect(codec, 1);
+
+ /* Disable HPH trigger and enable MIC line trigger */
+ snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
+
+ snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x60,
+ priv->calibration->mic_current << 5);
+ snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
+ 0x80, 0x80);
+ usleep_range(priv->calibration->mic_pid,
+ priv->calibration->mic_pid);
+ snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
+ 0x10, 0x10);
+
+ /* Setup for insertion detection */
+ snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
+ priv->fake_insert_context = true;
+ tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+ snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
+
} else if (mic_voltage < threshold_no_mic) {
pr_debug("%s: Headphone Detected, mic_voltage = %x\n",
__func__, mic_voltage);
@@ -3160,6 +3736,7 @@
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret = 0;
int i;
+ u8 tabla_version;
codec->control_data = dev_get_drvdata(codec->dev->parent);
control = codec->control_data;
@@ -3183,9 +3760,11 @@
tabla->clock_active = false;
tabla->config_mode_active = false;
tabla->mbhc_polling_active = false;
+ tabla->fake_insert_context = false;
tabla->no_mic_headset_override = false;
tabla->codec = codec;
tabla->pdata = dev_get_platdata(codec->dev->parent);
+ tabla->intf_type = tabla_get_intf_type();
tabla_update_reg_defaults(codec);
tabla_codec_init_reg(codec);
@@ -3204,7 +3783,34 @@
ARRAY_SIZE(tabla_snd_controls));
snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
ARRAY_SIZE(tabla_dapm_widgets));
+ if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+ snd_soc_dapm_new_controls(dapm, tabla_dapm_i2s_widgets,
+ ARRAY_SIZE(tabla_dapm_i2s_widgets));
+ snd_soc_dapm_add_routes(dapm, audio_i2s_map,
+ ARRAY_SIZE(audio_i2s_map));
+ }
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+
+ tabla_version = snd_soc_read(codec, TABLA_A_CHIP_VERSION);
+ pr_info("%s : Tabla version reg 0x%2x\n", __func__, (u32)tabla_version);
+
+ tabla_version &= 0x1F;
+ pr_info("%s : Tabla version %u\n", __func__, (u32)tabla_version);
+
+ if ((tabla_version == TABLA_VERSION_1_0) ||
+ (tabla_version == TABLA_VERSION_1_1)) {
+ snd_soc_dapm_add_routes(dapm, tabla_1_x_lineout_2_to_4_map,
+ ARRAY_SIZE(tabla_1_x_lineout_2_to_4_map));
+
+ } else if (tabla_version == TABLA_VERSION_2_0) {
+ snd_soc_dapm_add_routes(dapm, tabla_2_x_lineout_2_to_4_map,
+ ARRAY_SIZE(tabla_2_x_lineout_2_to_4_map));
+ } else {
+ pr_err("%s : ERROR. Unsupported Tabla version 0x%2x\n",
+ __func__, (u32)tabla_version);
+ goto err_pdata;
+ }
+
snd_soc_dapm_sync(dapm);
ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
@@ -3362,13 +3968,19 @@
static int __devinit tabla_probe(struct platform_device *pdev)
{
+ int ret = 0;
#ifdef CONFIG_DEBUG_FS
debugfs_poke = debugfs_create_file("TRRS",
S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
#endif
- return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
- tabla_dai, ARRAY_SIZE(tabla_dai));
+ if (tabla_get_intf_type() == TABLA_INTERFACE_TYPE_SLIMBUS)
+ ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
+ tabla_dai, ARRAY_SIZE(tabla_dai));
+ else if (tabla_get_intf_type() == TABLA_INTERFACE_TYPE_I2C)
+ ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
+ tabla_i2s_dai, ARRAY_SIZE(tabla_i2s_dai));
+ return ret;
}
static int __devexit tabla_remove(struct platform_device *pdev)
{
diff --git a/sound/soc/codecs/wcd9310.h b/sound/soc/codecs/wcd9310.h
index 8c6555b..32fc48f 100644
--- a/sound/soc/codecs/wcd9310.h
+++ b/sound/soc/codecs/wcd9310.h
@@ -12,6 +12,10 @@
#include <sound/soc.h>
+#define TABLA_VERSION_1_0 0
+#define TABLA_VERSION_1_1 1
+#define TABLA_VERSION_2_0 2
+
#define TABLA_NUM_REGISTERS 0x400
#define TABLA_MAX_REGISTER (TABLA_NUM_REGISTERS-1)
#define TABLA_CACHE_SIZE TABLA_NUM_REGISTERS
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index ffa2ffe..aa091a0 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -1454,8 +1454,8 @@
/* set the update bits */
snd_soc_update_bits(codec, WM8753_LDAC, 0x0100, 0x0100);
snd_soc_update_bits(codec, WM8753_RDAC, 0x0100, 0x0100);
- snd_soc_update_bits(codec, WM8753_LDAC, 0x0100, 0x0100);
- snd_soc_update_bits(codec, WM8753_RDAC, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8753_LADC, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8753_RADC, 0x0100, 0x0100);
snd_soc_update_bits(codec, WM8753_LOUT1V, 0x0100, 0x0100);
snd_soc_update_bits(codec, WM8753_ROUT1V, 0x0100, 0x0100);
snd_soc_update_bits(codec, WM8753_LOUT2V, 0x0100, 0x0100);
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
index 19ad0c1..61d2ecc 100644
--- a/sound/soc/fsl/mpc5200_dma.c
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -369,7 +369,7 @@
.pcm_free = &psc_dma_free,
};
-static int mpc5200_hpcd_probe(struct of_device *op)
+static int mpc5200_hpcd_probe(struct platform_device *op)
{
phys_addr_t fifo;
struct psc_dma *psc_dma;
@@ -487,7 +487,7 @@
return ret;
}
-static int mpc5200_hpcd_remove(struct of_device *op)
+static int mpc5200_hpcd_remove(struct platform_device *op)
{
struct psc_dma *psc_dma = dev_get_drvdata(&op->dev);
@@ -519,7 +519,7 @@
static struct platform_driver mpc5200_hpcd_of_driver = {
.probe = mpc5200_hpcd_probe,
.remove = mpc5200_hpcd_remove,
- .dev = {
+ .driver = {
.owner = THIS_MODULE,
.name = "mpc5200-pcm-audio",
.of_match_table = mpc5200_hpcd_match,
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index ced46de..9e0549b 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -113,8 +113,8 @@
To add support for MSM QDSP6 Soc Audio.
config SND_SOC_MSM8960
- tristate "SoC Machine driver for MSM8960 boards"
- depends on ARCH_MSM8960
+ tristate "SoC Machine driver for MSM8960 and APQ8064 boards"
+ depends on ARCH_MSM8960 || ARCH_APQ8064
select SND_SOC_VOICE
select SND_SOC_QDSP6
select SND_SOC_MSM_STUB
@@ -122,7 +122,7 @@
select SND_SOC_MSM_HOSTLESS_PCM
default n
help
- To add support for SoC audio on MSM8960 boards
+ To add support for SoC audio on MSM8960 and APQ8064 boards
config SND_SOC_MSM8660_APQ
tristate "Soc Machine driver for APQ8060 WM8903 codec"
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index 568fd40..3b257a6 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -56,7 +56,7 @@
obj-$(CONFIG_SND_SOC_MSM_QDSP6_INTF) += qdsp6/
-snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-pcm-routing.o msm-dai-fe.o
+snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o
obj-$(CONFIG_SND_SOC_VOICE) += msm-pcm-voice.o msm-pcm-voip.o
snd-soc-qdsp6-objs += msm-pcm-lpa.o msm-pcm-afe.o
obj-$(CONFIG_SND_SOC_QDSP6) += snd-soc-qdsp6.o
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
new file mode 100644
index 0000000..cf6f1e7
--- /dev/null
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -0,0 +1,567 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+#include <linux/android_pmem.h>
+
+#include "msm-compr-q6.h"
+#include "msm-pcm-routing.h"
+
+static struct audio_locks the_locks;
+
+static struct snd_pcm_hardware msm_compr_hardware_playback = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = 1200 * 1024 * 2,
+ .period_bytes_min = 60 * 1024,
+ .period_bytes_max = 1200 * 1024,
+ .periods_min = 2,
+ .periods_max = 40,
+ .fifo_size = 0,
+};
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+ .count = ARRAY_SIZE(supported_sample_rates),
+ .list = supported_sample_rates,
+ .mask = 0,
+};
+
+static void compr_event_handler(uint32_t opcode,
+ uint32_t token, uint32_t *payload, void *priv)
+{
+ struct compr_audio *compr = priv;
+ struct msm_audio *prtd = &compr->prtd;
+ struct snd_pcm_substream *substream = prtd->substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct audio_aio_write_param param;
+ struct audio_buffer *buf = NULL;
+ int i = 0;
+
+ pr_debug("%s opcode =%08x\n", __func__, opcode);
+ switch (opcode) {
+ case ASM_DATA_EVENT_WRITE_DONE: {
+ uint32_t *ptrmem = (uint32_t *)¶m;
+ pr_debug("ASM_DATA_EVENT_WRITE_DONE\n");
+ pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
+ prtd->pcm_irq_pos += prtd->pcm_count;
+ if (atomic_read(&prtd->start))
+ snd_pcm_period_elapsed(substream);
+ atomic_inc(&prtd->out_count);
+ wake_up(&the_locks.write_wait);
+ if (!atomic_read(&prtd->start)) {
+ prtd->pending_buffer = 1;
+ break;
+ } else
+ prtd->pending_buffer = 0;
+
+ if (runtime->status->hw_ptr >= runtime->control->appl_ptr)
+ break;
+ buf = prtd->audio_client->port[IN].buf;
+ pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
+ __func__, prtd->pcm_count, prtd->out_head);
+ pr_debug("%s:writing buffer[%d] from 0x%08x\n",
+ __func__, prtd->out_head,
+ ((unsigned int)buf[0].phys
+ + (prtd->out_head * prtd->pcm_count)));
+
+ param.paddr = (unsigned long)buf[0].phys
+ + (prtd->out_head * prtd->pcm_count);
+ param.len = prtd->pcm_count;
+ param.msw_ts = 0;
+ param.lsw_ts = 0;
+ param.flags = NO_TIMESTAMP;
+ param.uid = (unsigned long)buf[0].phys
+ + (prtd->out_head * prtd->pcm_count);
+ for (i = 0; i < sizeof(struct audio_aio_write_param)/4;
+ i++, ++ptrmem)
+ pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
+ if (q6asm_async_write(prtd->audio_client,
+ ¶m) < 0)
+ pr_err("%s:q6asm_async_write failed\n",
+ __func__);
+ else
+ prtd->out_head =
+ (prtd->out_head + 1) & (runtime->periods - 1);
+ break;
+ }
+ case ASM_DATA_CMDRSP_EOS:
+ pr_debug("ASM_DATA_CMDRSP_EOS\n");
+ prtd->cmd_ack = 1;
+ wake_up(&the_locks.eos_wait);
+ break;
+ case APR_BASIC_RSP_RESULT: {
+ switch (payload[0]) {
+ case ASM_SESSION_CMD_RUN: {
+ if (!prtd->pending_buffer &&
+ !atomic_read(&prtd->start))
+ break;
+ pr_debug("%s:writing %d bytes"
+ " of buffer[%d] to dsp\n",
+ __func__, prtd->pcm_count, prtd->out_head);
+ buf = prtd->audio_client->port[IN].buf;
+ pr_debug("%s:writing buffer[%d] from 0x%08x\n",
+ __func__, prtd->out_head,
+ ((unsigned int)buf[0].phys
+ + (prtd->out_head * prtd->pcm_count)));
+ param.paddr = (unsigned long)buf[prtd->out_head].phys;
+ param.len = prtd->pcm_count;
+ param.msw_ts = 0;
+ param.lsw_ts = 0;
+ param.flags = NO_TIMESTAMP;
+ param.uid = (unsigned long)buf[prtd->out_head].phys;
+ if (q6asm_async_write(prtd->audio_client,
+ ¶m) < 0)
+ pr_err("%s:q6asm_async_write failed\n",
+ __func__);
+ else
+ prtd->out_head =
+ (prtd->out_head + 1)
+ & (runtime->periods - 1);
+ }
+ break;
+ case ASM_STREAM_CMD_FLUSH:
+ pr_debug("ASM_STREAM_CMD_FLUSH\n");
+ prtd->cmd_ack = 1;
+ wake_up(&the_locks.eos_wait);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
+ break;
+ }
+}
+
+static int msm_compr_playback_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct compr_audio *compr = runtime->private_data;
+ struct msm_audio *prtd = &compr->prtd;
+ int ret;
+
+ pr_debug("%s\n", __func__);
+ prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+ prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+ prtd->pcm_irq_pos = 0;
+ /* rate and channels are sent to audio driver */
+ prtd->samp_rate = runtime->rate;
+ prtd->channel_mode = runtime->channels;
+ prtd->out_head = 0;
+ if (prtd->enabled)
+ return 0;
+
+ ret = q6asm_media_format_block(prtd->audio_client, compr->codec);
+ if (ret < 0)
+ pr_info("%s: CMD Format block failed\n", __func__);
+
+ atomic_set(&prtd->out_count, runtime->periods);
+
+ prtd->enabled = 1;
+ prtd->cmd_ack = 0;
+
+ return 0;
+}
+
+static int msm_compr_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct compr_audio *compr = runtime->private_data;
+ struct msm_audio *prtd = &compr->prtd;
+
+ pr_debug("%s\n", __func__);
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ prtd->pcm_irq_pos = 0;
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ pr_debug("%s: Trigger start\n", __func__);
+ q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+ atomic_set(&prtd->start, 1);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+ atomic_set(&prtd->start, 0);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
+ q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+ atomic_set(&prtd->start, 0);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static void populate_codec_list(struct compr_audio *compr,
+ struct snd_pcm_runtime *runtime)
+{
+ pr_debug("%s\n", __func__);
+ /* MP3 Block */
+ compr->info.compr_cap.num_codecs = 1;
+ compr->info.compr_cap.min_fragment_size = runtime->hw.period_bytes_min;
+ compr->info.compr_cap.max_fragment_size = runtime->hw.period_bytes_max;
+ compr->info.compr_cap.min_fragments = runtime->hw.periods_min;
+ compr->info.compr_cap.max_fragments = runtime->hw.periods_max;
+ compr->info.compr_cap.codecs[0] = SND_AUDIOCODEC_MP3;
+ /* Add new codecs here */
+}
+
+static int msm_compr_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+ struct compr_audio *compr;
+ struct msm_audio *prtd;
+ int ret = 0;
+
+ /* Capture path */
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ return -EINVAL;
+
+ pr_debug("%s\n", __func__);
+ compr = kzalloc(sizeof(struct compr_audio), GFP_KERNEL);
+ if (compr == NULL) {
+ pr_err("Failed to allocate memory for msm_audio\n");
+ return -ENOMEM;
+ }
+ prtd = &compr->prtd;
+ prtd->substream = substream;
+ prtd->audio_client = q6asm_audio_client_alloc(
+ (app_cb)compr_event_handler, compr);
+ if (!prtd->audio_client) {
+ pr_info("%s: Could not allocate memory\n", __func__);
+ kfree(prtd);
+ return -ENOMEM;
+ }
+ runtime->hw = msm_compr_hardware_playback;
+
+ pr_info("%s: session ID %d\n", __func__, prtd->audio_client->session);
+
+ prtd->session_id = prtd->audio_client->session;
+ msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+ prtd->session_id, substream->stream);
+
+ prtd->cmd_ack = 1;
+
+ ret = snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_sample_rates);
+ if (ret < 0)
+ pr_info("snd_pcm_hw_constraint_list failed\n");
+ /* Ensure that buffer size is a multiple of period size */
+ ret = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0)
+ pr_info("snd_pcm_hw_constraint_integer failed\n");
+
+ prtd->dsp_cnt = 0;
+ prtd->pending_buffer = 1;
+ compr->codec = FORMAT_MP3;
+ populate_codec_list(compr, runtime);
+ runtime->private_data = compr;
+
+ return 0;
+}
+
+static int msm_compr_playback_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+ struct compr_audio *compr = runtime->private_data;
+ struct msm_audio *prtd = &compr->prtd;
+ int dir = 0;
+
+ pr_debug("%s\n", __func__);
+
+ dir = IN;
+
+ q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+ q6asm_audio_client_buf_free_contiguous(dir,
+ prtd->audio_client);
+
+ msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ q6asm_audio_client_free(prtd->audio_client);
+ kfree(prtd);
+ return 0;
+}
+
+static int msm_compr_close(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = msm_compr_playback_close(substream);
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ret = EINVAL;
+ return ret;
+}
+static int msm_compr_prepare(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = msm_compr_playback_prepare(substream);
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ret = EINVAL;
+ return ret;
+}
+
+static snd_pcm_uframes_t msm_compr_pointer(struct snd_pcm_substream *substream)
+{
+
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct compr_audio *compr = runtime->private_data;
+ struct msm_audio *prtd = &compr->prtd;
+
+ if (prtd->pcm_irq_pos >= prtd->pcm_size)
+ prtd->pcm_irq_pos = 0;
+
+ pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
+ return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+}
+
+static int msm_compr_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ int result = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct compr_audio *compr = runtime->private_data;
+ struct msm_audio *prtd = &compr->prtd;
+
+ pr_debug("%s\n", __func__);
+ prtd->mmap_flag = 1;
+ if (runtime->dma_addr && runtime->dma_bytes) {
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ result = remap_pfn_range(vma, vma->vm_start,
+ runtime->dma_addr >> PAGE_SHIFT,
+ runtime->dma_bytes,
+ vma->vm_page_prot);
+ } else {
+ pr_err("Physical address or size of buf is NULL");
+ return -EINVAL;
+ }
+ return result;
+}
+
+static int msm_compr_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct compr_audio *compr = runtime->private_data;
+ struct msm_audio *prtd = &compr->prtd;
+ struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+ struct audio_buffer *buf;
+ int dir, ret;
+
+ pr_debug("%s\n", __func__);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dir = IN;
+ else
+ return -EINVAL;
+
+ ret = q6asm_open_write(prtd->audio_client, compr->codec);
+ if (ret < 0) {
+ pr_err("%s: Session out open failed\n", __func__);
+ return -ENOMEM;
+ }
+ ret = q6asm_set_io_mode(prtd->audio_client, ASYNC_IO_MODE);
+ if (ret < 0) {
+ pr_err("%s: Set IO mode failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ ret = q6asm_audio_client_buf_alloc_contiguous(dir,
+ prtd->audio_client,
+ runtime->hw.period_bytes_min,
+ runtime->hw.periods_max);
+ if (ret < 0) {
+ pr_err("Audio Start: Buffer Allocation failed "
+ "rc = %d\n", ret);
+ return -ENOMEM;
+ }
+ buf = prtd->audio_client->port[dir].buf;
+
+ pr_debug("%s:buf = %p\n", __func__, buf);
+ dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ dma_buf->dev.dev = substream->pcm->card->dev;
+ dma_buf->private_data = NULL;
+ dma_buf->area = buf[0].data;
+ dma_buf->addr = buf[0].phys;
+ dma_buf->bytes = runtime->hw.buffer_bytes_max;
+ if (!dma_buf->area)
+ return -ENOMEM;
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+ return 0;
+}
+
+static int msm_compr_ioctl(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
+{
+ int rc = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct compr_audio *compr = runtime->private_data;
+ struct msm_audio *prtd = &compr->prtd;
+
+ switch (cmd) {
+ case SNDRV_COMPRESS_GET_CAPS:
+ pr_debug("SNDRV_COMPRESS_GET_CAPS\n");
+ if (copy_to_user((void *) arg, &compr->info.compr_cap,
+ sizeof(struct snd_compr_caps))) {
+ rc = -EFAULT;
+ pr_err("%s: ERROR: copy to user\n", __func__);
+ return rc;
+ }
+ return 0;
+ case SNDRV_COMPRESS_SET_PARAMS:
+ pr_debug("SNDRV_COMPRESS_SET_PARAMS: ");
+ if (copy_from_user(&compr->info.codec_param, (void *) arg,
+ sizeof(struct snd_compr_params))) {
+ rc = -EFAULT;
+ pr_err("%s: ERROR: copy from user\n", __func__);
+ return rc;
+ }
+ switch (compr->info.codec_param.codec.id) {
+ case SND_AUDIOCODEC_MP3:
+ /* For MP3 we dont need any other parameter */
+ pr_debug("SND_AUDIOCODEC_MP3\n");
+ compr->codec = FORMAT_MP3;
+ break;
+ default:
+ pr_debug("FORMAT_LINEAR_PCM\n");
+ compr->codec = FORMAT_LINEAR_PCM;
+ break;
+ }
+ return 0;
+ case SNDRV_PCM_IOCTL1_RESET:
+ prtd->cmd_ack = 0;
+ rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
+ if (rc < 0)
+ pr_err("%s: flush cmd failed rc=%d\n", __func__, rc);
+ rc = wait_event_timeout(the_locks.eos_wait,
+ prtd->cmd_ack, 5 * HZ);
+ if (rc < 0)
+ pr_err("Flush cmd timeout\n");
+ prtd->pcm_irq_pos = 0;
+ break;
+ default:
+ break;
+ }
+ return snd_pcm_lib_ioctl(substream, cmd, arg);
+}
+
+static struct snd_pcm_ops msm_compr_ops = {
+ .open = msm_compr_open,
+ .hw_params = msm_compr_hw_params,
+ .close = msm_compr_close,
+ .ioctl = msm_compr_ioctl,
+ .prepare = msm_compr_prepare,
+ .trigger = msm_compr_trigger,
+ .pointer = msm_compr_pointer,
+ .mmap = msm_compr_mmap,
+};
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_card *card = rtd->card->snd_card;
+ int ret = 0;
+
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+ .ops = &msm_compr_ops,
+ .pcm_new = msm_asoc_pcm_new,
+};
+
+static __devinit int msm_compr_probe(struct platform_device *pdev)
+{
+ pr_info("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+ return snd_soc_register_platform(&pdev->dev,
+ &msm_soc_platform);
+}
+
+static int msm_compr_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver msm_compr_driver = {
+ .driver = {
+ .name = "msm-compr-dsp",
+ .owner = THIS_MODULE,
+ },
+ .probe = msm_compr_probe,
+ .remove = __devexit_p(msm_compr_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+ init_waitqueue_head(&the_locks.enable_wait);
+ init_waitqueue_head(&the_locks.eos_wait);
+ init_waitqueue_head(&the_locks.write_wait);
+ init_waitqueue_head(&the_locks.read_wait);
+
+ return platform_driver_register(&msm_compr_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+ platform_driver_unregister(&msm_compr_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-compr-q6.h b/sound/soc/msm/msm-compr-q6.h
new file mode 100644
index 0000000..6dfbcce
--- /dev/null
+++ b/sound/soc/msm/msm-compr-q6.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 _MSM_COMPR_H
+#define _MSM_COMPR_H
+#include <sound/apr_audio.h>
+#include <sound/q6asm.h>
+#include <sound/snd_compress_params.h>
+#include <sound/compress_offload.h>
+#include <sound/compress_driver.h>
+
+#include "msm-pcm-q6.h"
+
+struct compr_info {
+ struct snd_compr_caps compr_cap;
+ struct snd_compr_codec_caps codec_caps;
+ struct snd_compr_params codec_param;
+};
+
+struct compr_audio {
+ struct msm_audio prtd;
+ struct compr_info info;
+ uint32_t codec;
+};
+
+#endif /*_MSM_COMPR_H*/
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 401c1a9..16d149e 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -151,6 +151,20 @@
.ops = &msm_fe_Multimedia_dai_ops,
.name = "MultiMedia3",
},
+ {
+ .playback = {
+ .stream_name = "MultiMedia4 Playback",
+ .rates = (SNDRV_PCM_RATE_8000_48000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .name = "MultiMedia4",
+ },
/* FE DAIs created for hostless operation purpose */
{
.playback = {
diff --git a/sound/soc/msm/msm-pcm-lpa.c b/sound/soc/msm/msm-pcm-lpa.c
index 29f89ce..f644722 100644
--- a/sound/soc/msm/msm-pcm-lpa.c
+++ b/sound/soc/msm/msm-pcm-lpa.c
@@ -131,7 +131,8 @@
case APR_BASIC_RSP_RESULT: {
switch (payload[0]) {
case ASM_SESSION_CMD_RUN: {
- if (!prtd->pending_buffer)
+ if (!prtd->pending_buffer &&
+ !atomic_read(&prtd->start))
break;
pr_debug("%s:writing %d bytes"
" of buffer to dsp\n",
diff --git a/sound/soc/msm/msm-pcm-q6.c b/sound/soc/msm/msm-pcm-q6.c
index 67e342e..738e024 100644
--- a/sound/soc/msm/msm-pcm-q6.c
+++ b/sound/soc/msm/msm-pcm-q6.c
@@ -51,9 +51,9 @@
.rate_max = 48000,
.channels_min = 1,
.channels_max = 2,
- .buffer_bytes_max = 512 * 8,
- .period_bytes_min = 512,
- .period_bytes_max = 512,
+ .buffer_bytes_max = 320 * 8,
+ .period_bytes_min = 320,
+ .period_bytes_max = 320,
.periods_min = 8,
.periods_max = 8,
.fifo_size = 0,
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 97d0760..3573169 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -125,6 +125,8 @@
{INVALID_SESSION, INVALID_SESSION},
/* MULTIMEDIA3 */
{INVALID_SESSION, INVALID_SESSION},
+ /* MULTIMEDIA4 */
+ {INVALID_SESSION, INVALID_SESSION},
};
static void msm_pcm_routing_build_matrix(int fedai_id, int dspst_id,
@@ -615,6 +617,9 @@
SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = {
@@ -627,6 +632,9 @@
SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SLIMBUS_0_RX,
MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
@@ -639,6 +647,9 @@
SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new int_bt_sco_rx_mixer_controls[] = {
@@ -651,6 +662,9 @@
SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_INT_BT_SCO_RX,
MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = {
@@ -663,6 +677,9 @@
SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_INT_FM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = {
@@ -675,6 +692,9 @@
SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = {
@@ -687,6 +707,9 @@
SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new mmul1_mixer_controls[] = {
@@ -1014,6 +1037,7 @@
SND_SOC_DAPM_AIF_IN("MM_DL1", "MultiMedia1 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL4", "MultiMedia4 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VOIP_DL", "VoIP Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
@@ -1111,16 +1135,19 @@
{"PRI_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"PRI_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"PRI_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"PRI_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"PRI_I2S_RX", NULL, "PRI_RX Audio Mixer"},
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Audio Mixer"},
{"HDMI Mixer", "MultiMedia1", "MM_DL1"},
{"HDMI Mixer", "MultiMedia2", "MM_DL2"},
{"HDMI Mixer", "MultiMedia3", "MM_DL3"},
+ {"HDMI Mixer", "MultiMedia4", "MM_DL4"},
{"HDMI", NULL, "HDMI Mixer"},
{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
@@ -1130,16 +1157,19 @@
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"INT_FM_RX", NULL, "INTERNAL_FM_RX Audio Mixer"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"PCM_RX", NULL, "AFE_PCM_RX Audio Mixer"},
{"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
@@ -1153,6 +1183,7 @@
{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"},
{"PRI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index db7552d..b7fc82a 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -31,6 +31,7 @@
MSM_FRONTEND_DAI_MULTIMEDIA1 = 0,
MSM_FRONTEND_DAI_MULTIMEDIA2,
MSM_FRONTEND_DAI_MULTIMEDIA3,
+ MSM_FRONTEND_DAI_MULTIMEDIA4,
MSM_FRONTEND_DAI_CS_VOICE,
MSM_FRONTEND_DAI_VOIP,
MSM_FRONTEND_DAI_AFE_RX,
diff --git a/sound/soc/msm/msm8660-apq-wm8903.c b/sound/soc/msm/msm8660-apq-wm8903.c
index af72872..a163006 100644
--- a/sound/soc/msm/msm8660-apq-wm8903.c
+++ b/sound/soc/msm/msm8660-apq-wm8903.c
@@ -9,8 +9,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- *TODO:
- * - Audio stream capture support
*/
#include <linux/clk.h>
@@ -34,11 +32,11 @@
#define MSM_GPIO_CLASS_D0_EN 80
#define MSM_GPIO_CLASS_D1_EN 81
-#define MSM8660_SPK_ON 1
-#define MSM8660_SPK_OFF 0
#define MSM_CDC_MIC_I2S_MCLK 108
static int msm8660_spk_func;
+static int msm8660_headset_func;
+static int msm8660_headphone_func;
static struct clk *mic_bit_clk;
static struct clk *spkr_osr_clk;
@@ -56,6 +54,11 @@
NONE
};
+enum {
+ FUNC_OFF,
+ FUNC_ON,
+};
+
static struct wm8903_vdd {
struct regulator *reg_id;
const char *name;
@@ -295,23 +298,19 @@
/* config WM8903 in Mater mode */
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_CBM_CFM |
SND_SOC_DAIFMT_I2S);
- mic_bit_clk = clk_get(NULL, "i2s_mic_bit_clk");
- if (IS_ERR(mic_bit_clk)) {
- pr_err("Failed to get i2s_mic_bit_clk\n");
- return PTR_ERR(mic_bit_clk);
- }
- clk_set_rate(mic_bit_clk, 0);
- ret = clk_enable(mic_bit_clk);
if (ret != 0) {
- pr_err("Unable to enable i2s_mic_bit_clk\n");
- clk_put(mic_bit_clk);
+ pr_err("codec_dai set_fmt error\n");
+ return ret;
+ }
+ /* config CPU in SLAVE mode */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM);
+ if (ret != 0) {
+ pr_err("cpu_dai set_fmt error\n");
return ret;
}
spkr_osr_clk = clk_get(NULL, "i2s_spkr_osr_clk");
if (IS_ERR(spkr_osr_clk)) {
pr_err("Failed to get i2s_spkr_osr_clk\n");
- clk_disable(mic_bit_clk);
- clk_put(mic_bit_clk);
return PTR_ERR(spkr_osr_clk);
}
clk_set_rate(spkr_osr_clk, 48000 * 256);
@@ -319,8 +318,6 @@
if (ret != 0) {
pr_err("Unable to enable i2s_spkr_osr_clk\n");
clk_put(spkr_osr_clk);
- clk_disable(mic_bit_clk);
- clk_put(mic_bit_clk);
return ret;
}
spkr_bit_clk = clk_get(NULL, "i2s_spkr_bit_clk");
@@ -328,8 +325,6 @@
pr_err("Failed to get i2s_spkr_bit_clk\n");
clk_disable(spkr_osr_clk);
clk_put(spkr_osr_clk);
- clk_disable(mic_bit_clk);
- clk_put(mic_bit_clk);
return PTR_ERR(spkr_bit_clk);
}
clk_set_rate(spkr_bit_clk, 0);
@@ -338,15 +333,24 @@
pr_err("Unable to enable i2s_spkr_bit_clk\n");
clk_disable(spkr_osr_clk);
clk_put(spkr_osr_clk);
- clk_disable(mic_bit_clk);
- clk_put(mic_bit_clk);
clk_put(spkr_bit_clk);
return ret;
}
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ /* config WM8903 in Mater mode */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_CBM_CFM |
+ SND_SOC_DAIFMT_I2S);
+ if (ret != 0) {
+ pr_err("codec_dai set_fmt error\n");
+ return ret;
+ }
/* config CPU in SLAVE mode */
ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM);
- /* End of platform specific logic */
- } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (ret != 0) {
+ pr_err("codec_dai set_fmt error\n");
+ return ret;
+ }
+
mic_bit_clk = clk_get(NULL, "i2s_mic_bit_clk");
if (IS_ERR(mic_bit_clk)) {
pr_err("Failed to get i2s_mic_bit_clk\n");
@@ -359,7 +363,6 @@
clk_put(mic_bit_clk);
return ret;
}
- msleep(30);
}
return ret;
}
@@ -367,7 +370,9 @@
static void msm8660_i2s_shutdown(struct snd_pcm_substream *substream)
{
pr_debug("Enter %s\n", __func__);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+ substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ tx_hw_param_status = 0;
rx_hw_param_status = 0;
if (spkr_bit_clk) {
clk_disable(spkr_bit_clk);
@@ -384,25 +389,29 @@
clk_put(mic_bit_clk);
mic_bit_clk = NULL;
}
- } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- tx_hw_param_status = 0;
- msleep(30);
- if (mic_bit_clk) {
- clk_disable(mic_bit_clk);
- clk_put(mic_bit_clk);
- mic_bit_clk = NULL;
- }
}
}
static void msm8660_ext_control(struct snd_soc_codec *codec)
{
/* set the enpoints to their new connetion states */
- if (msm8660_spk_func == MSM8660_SPK_ON)
+ if (msm8660_spk_func == FUNC_ON)
snd_soc_dapm_enable_pin(&codec->dapm, "Ext Spk");
else
snd_soc_dapm_disable_pin(&codec->dapm, "Ext Spk");
+ /* set the enpoints to their new connetion states */
+ if (msm8660_headset_func == FUNC_ON)
+ snd_soc_dapm_enable_pin(&codec->dapm, "Headset Jack");
+ else
+ snd_soc_dapm_disable_pin(&codec->dapm, "Headset Jack");
+
+ /* set the enpoints to their new connetion states */
+ if (msm8660_headphone_func == FUNC_ON)
+ snd_soc_dapm_enable_pin(&codec->dapm, "Headphone Jack");
+ else
+ snd_soc_dapm_disable_pin(&codec->dapm, "Headphone Jack");
+
/* signal a DAPM event */
snd_soc_dapm_sync(&codec->dapm);
}
@@ -428,6 +437,48 @@
return 1;
}
+static int msm8660_get_hs(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm8660_headset_func;
+ return 0;
+}
+
+static int msm8660_set_hs(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ pr_debug("%s()\n", __func__);
+ if (msm8660_headset_func == ucontrol->value.integer.value[0])
+ return 0;
+
+ msm8660_headset_func = ucontrol->value.integer.value[0];
+ msm8660_ext_control(codec);
+ return 1;
+}
+
+static int msm8660_get_hph(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm8660_headphone_func;
+ return 0;
+}
+
+static int msm8660_set_hph(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ pr_debug("%s()\n", __func__);
+ if (msm8660_headphone_func == ucontrol->value.integer.value[0])
+ return 0;
+
+ msm8660_headphone_func = ucontrol->value.integer.value[0];
+ msm8660_ext_control(codec);
+ return 1;
+}
+
static int msm8660_spkramp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
@@ -446,22 +497,42 @@
static const struct snd_soc_dapm_widget msm8660_dapm_widgets[] = {
SND_SOC_DAPM_SPK("Ext Spk", msm8660_spkramp_event),
+ SND_SOC_DAPM_MIC("Headset Jack", NULL),
+ SND_SOC_DAPM_MIC("Headphone Jack", NULL),
+ /* to fix a bug in wm8903.c, where audio doesn't function
+ * after suspend/resume
+ */
+ SND_SOC_DAPM_SUPPLY("CLK_SYS_ENA", WM8903_CLOCK_RATES_2, 2, 0, NULL, 0),
};
static const struct snd_soc_dapm_route audio_map[] = {
/* Match with wm8903 codec line out pin */
{"Ext Spk", NULL, "LINEOUTL"},
{"Ext Spk", NULL, "LINEOUTR"},
+ /* Headset connects to IN3L with Bias */
+ {"IN3L", NULL, "Mic Bias"},
+ {"Mic Bias", NULL, "Headset Jack"},
+ /* Headphone connects to IN3R with Bias */
+ {"IN3R", NULL, "Mic Bias"},
+ {"Mic Bias", NULL, "Headphone Jack"},
+ {"ADCL", NULL, "CLK_SYS_ENA"},
+ {"ADCR", NULL, "CLK_SYS_ENA"},
+ {"DACL", NULL, "CLK_SYS_ENA"},
+ {"DACR", NULL, "CLK_SYS_ENA"},
};
-static const char *spk_function[] = {"Off", "On"};
+static const char *cmn_status[] = {"Off", "On"};
static const struct soc_enum msm8660_enum[] = {
- SOC_ENUM_SINGLE_EXT(2, spk_function),
+ SOC_ENUM_SINGLE_EXT(2, cmn_status),
};
static const struct snd_kcontrol_new wm8903_msm8660_controls[] = {
SOC_ENUM_EXT("Speaker Function", msm8660_enum[0], msm8660_get_spk,
msm8660_set_spk),
+ SOC_ENUM_EXT("Headset Function", msm8660_enum[0], msm8660_get_hs,
+ msm8660_set_hs),
+ SOC_ENUM_EXT("Headphone Function", msm8660_enum[0], msm8660_get_hph,
+ msm8660_set_hph),
};
static int msm8660_audrx_init(struct snd_soc_pcm_runtime *rtd)
@@ -470,6 +541,7 @@
int err;
snd_soc_dapm_disable_pin(&codec->dapm, "Ext Spk");
+ snd_soc_dapm_enable_pin(&codec->dapm, "CLK_SYS_ENA");
err = snd_soc_add_controls(codec, wm8903_msm8660_controls,
ARRAY_SIZE(wm8903_msm8660_controls));
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index 0082339..bfc004e 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -919,6 +919,15 @@
.platform_name = "msm-pcm-afe",
.ignore_suspend = 1,
},
+ {
+ .name = "MSM8960 Compr",
+ .stream_name = "COMPR",
+ .cpu_dai_name = "MultiMedia4",
+ .platform_name = "msm-compr-dsp",
+ .dynamic = 1,
+ .dsp_link = &lpa_fe_media,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
+ },
/* Backend DAI Links */
{
.name = LPASS_BE_SLIMBUS_0_RX,
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 268d2e5..ab7f9f7 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -1202,6 +1202,9 @@
case FORMAT_WMA_V10PRO:
open.format = WMA_V10PRO;
break;
+ case FORMAT_MP3:
+ open.format = MP3;
+ break;
default:
pr_err("%s: Invalid format[%d]\n", __func__, format);
goto fail_cmd;
@@ -1865,7 +1868,26 @@
q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FORMAT_UPDATE;
- fmt.format = format;
+ switch (format) {
+ case FORMAT_V13K:
+ fmt.format = V13K_FS;
+ break;
+ case FORMAT_EVRC:
+ fmt.format = EVRC_FS;
+ break;
+ case FORMAT_AMRWB:
+ fmt.format = AMRWB_FS;
+ break;
+ case FORMAT_AMRNB:
+ fmt.format = AMRNB_FS;
+ break;
+ case FORMAT_MP3:
+ fmt.format = MP3;
+ break;
+ default:
+ pr_err("Invalid format[%d]\n", format);
+ goto fail_cmd;
+ }
fmt.cfg_size = 0;
rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 07b7723..4b82290 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -516,6 +516,12 @@
struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
int err = 0;
+ if (mcbsp_data->active)
+ if (freq == mcbsp_data->in_freq)
+ return 0;
+ else
+ return -EBUSY;
+
/* The McBSP signal muxing functions are only available on McBSP1 */
if (clk_id == OMAP_MCBSP_CLKR_SRC_CLKR ||
clk_id == OMAP_MCBSP_CLKR_SRC_CLKX ||
diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c
index b644575..2b8350b 100644
--- a/sound/soc/pxa/zylonite.c
+++ b/sound/soc/pxa/zylonite.c
@@ -196,20 +196,20 @@
if (clk_pout) {
pout = clk_get(NULL, "CLK_POUT");
if (IS_ERR(pout)) {
- dev_err(&pdev->dev, "Unable to obtain CLK_POUT: %ld\n",
+ dev_err(card->dev, "Unable to obtain CLK_POUT: %ld\n",
PTR_ERR(pout));
return PTR_ERR(pout);
}
ret = clk_enable(pout);
if (ret != 0) {
- dev_err(&pdev->dev, "Unable to enable CLK_POUT: %d\n",
+ dev_err(card->dev, "Unable to enable CLK_POUT: %d\n",
ret);
clk_put(pout);
return ret;
}
- dev_dbg(&pdev->dev, "MCLK enabled at %luHz\n",
+ dev_dbg(card->dev, "MCLK enabled at %luHz\n",
clk_get_rate(pout));
}
@@ -241,7 +241,7 @@
if (clk_pout) {
ret = clk_enable(pout);
if (ret != 0)
- dev_err(&pdev->dev, "Unable to enable CLK_POUT: %d\n",
+ dev_err(card->dev, "Unable to enable CLK_POUT: %d\n",
ret);
}
diff --git a/sound/soc/samsung/jive_wm8750.c b/sound/soc/samsung/jive_wm8750.c
index 3b53ad5..14eb6ea 100644
--- a/sound/soc/samsung/jive_wm8750.c
+++ b/sound/soc/samsung/jive_wm8750.c
@@ -131,7 +131,7 @@
.cpu_dai_name = "s3c2412-i2s",
.codec_dai_name = "wm8750-hifi",
.platform_name = "samsung-audio",
- .codec_name = "wm8750-codec.0-0x1a",
+ .codec_name = "wm8750-codec.0-001a",
.init = jive_wm8750_init,
.ops = &jive_ops,
};
diff --git a/sound/soc/soc-dsp.c b/sound/soc/soc-dsp.c
index bef84a1..706954b 100644
--- a/sound/soc/soc-dsp.c
+++ b/sound/soc/soc-dsp.c
@@ -482,6 +482,9 @@
struct snd_pcm_substream *be_substream =
snd_soc_dsp_get_substream(dsp_params->be, stream);
+ if (dsp_params->state != SND_SOC_DSP_LINK_STATE_FREE)
+ continue;
+
/* is this op for this BE ? */
if (fe->dsp[stream].runtime_update &&
!dsp_params->be->dsp[stream].runtime_update)
@@ -490,9 +493,6 @@
if (--dsp_params->be->dsp[stream].users != 0)
continue;
- if (dsp_params->state != SND_SOC_DSP_LINK_STATE_FREE)
- continue;
-
dev_dbg(&dsp_params->be->dev, "dsp: close BE %s\n",
dsp_params->fe->dai_link->name);
@@ -627,6 +627,10 @@
struct snd_soc_dsp_params *dsp_params;
int ret = 0;
+ if ((cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE) ||
+ (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH))
+ return ret;
+
list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
struct snd_pcm_substream *be_substream =
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index 7c17b98..fa31d9c 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -105,7 +105,7 @@
snd_soc_dapm_sync(dapm);
- snd_jack_report(jack->jack, status);
+ snd_jack_report(jack->jack, jack->status);
out:
mutex_unlock(&codec->mutex);
@@ -327,7 +327,7 @@
IRQF_TRIGGER_FALLING,
gpios[i].name,
&gpios[i]);
- if (ret)
+ if (ret < 0)
goto err;
if (gpios[i].wake) {
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index 3c271f9..6201710 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -309,9 +309,14 @@
static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream)
{
- struct snd_pcm_substream *substream = pcm->streams[stream].substream;
- struct snd_dma_buffer *buf = &substream->dma_buffer;
+ struct snd_pcm_substream *substream;
+ struct snd_dma_buffer *buf;
+ substream = pcm->streams[stream].substream;
+ if (!substream)
+ return;
+
+ buf = &substream->dma_buffer;
if (!buf->area)
return;
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index 0d6738a..7766478 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -56,6 +56,7 @@
#define GPIO_HP_MUTE BIT(1)
#define GPIO_INT_MIC_EN BIT(2)
#define GPIO_EXT_MIC_EN BIT(3)
+#define GPIO_HP_DET BIT(4)
struct tegra_wm8903 {
struct tegra_asoc_utils_data util_data;
@@ -304,6 +305,7 @@
snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack,
1,
&tegra_wm8903_hp_jack_gpio);
+ machine->gpio_requested |= GPIO_HP_DET;
}
snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
@@ -429,10 +431,10 @@
struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
struct tegra_wm8903_platform_data *pdata = machine->pdata;
- snd_soc_unregister_card(card);
-
- tegra_asoc_utils_fini(&machine->util_data);
-
+ if (machine->gpio_requested & GPIO_HP_DET)
+ snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack,
+ 1,
+ &tegra_wm8903_hp_jack_gpio);
if (machine->gpio_requested & GPIO_EXT_MIC_EN)
gpio_free(pdata->gpio_ext_mic_en);
if (machine->gpio_requested & GPIO_INT_MIC_EN)
@@ -441,6 +443,11 @@
gpio_free(pdata->gpio_hp_mute);
if (machine->gpio_requested & GPIO_SPKR_EN)
gpio_free(pdata->gpio_spkr_en);
+ machine->gpio_requested = 0;
+
+ snd_soc_unregister_card(card);
+
+ tegra_asoc_utils_fini(&machine->util_data);
kfree(machine);
diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c
index d0d493c..2cf87f5 100644
--- a/sound/usb/caiaq/audio.c
+++ b/sound/usb/caiaq/audio.c
@@ -139,8 +139,12 @@
for (i = 0; i < N_URBS; i++) {
usb_kill_urb(dev->data_urbs_in[i]);
- usb_kill_urb(dev->data_urbs_out[i]);
+
+ if (test_bit(i, &dev->outurb_active_mask))
+ usb_kill_urb(dev->data_urbs_out[i]);
}
+
+ dev->outurb_active_mask = 0;
}
static int snd_usb_caiaq_substream_open(struct snd_pcm_substream *substream)
@@ -612,8 +616,9 @@
{
struct snd_usb_caiaq_cb_info *info = urb->context;
struct snd_usb_caiaqdev *dev;
- struct urb *out;
- int frame, len, send_it = 0, outframe = 0;
+ struct urb *out = NULL;
+ int i, frame, len, send_it = 0, outframe = 0;
+ size_t offset = 0;
if (urb->status || !info)
return;
@@ -623,7 +628,17 @@
if (!dev->streaming)
return;
- out = dev->data_urbs_out[info->index];
+ /* find an unused output urb that is unused */
+ for (i = 0; i < N_URBS; i++)
+ if (test_and_set_bit(i, &dev->outurb_active_mask) == 0) {
+ out = dev->data_urbs_out[i];
+ break;
+ }
+
+ if (!out) {
+ log("Unable to find an output urb to use\n");
+ goto requeue;
+ }
/* read the recently received packet and send back one which has
* the same layout */
@@ -634,7 +649,8 @@
len = urb->iso_frame_desc[outframe].actual_length;
out->iso_frame_desc[outframe].length = len;
out->iso_frame_desc[outframe].actual_length = 0;
- out->iso_frame_desc[outframe].offset = BYTES_PER_FRAME * frame;
+ out->iso_frame_desc[outframe].offset = offset;
+ offset += len;
if (len > 0) {
spin_lock(&dev->spinlock);
@@ -650,11 +666,15 @@
}
if (send_it) {
- out->number_of_packets = FRAMES_PER_URB;
+ out->number_of_packets = outframe;
out->transfer_flags = URB_ISO_ASAP;
usb_submit_urb(out, GFP_ATOMIC);
+ } else {
+ struct snd_usb_caiaq_cb_info *oinfo = out->context;
+ clear_bit(oinfo->index, &dev->outurb_active_mask);
}
+requeue:
/* re-submit inbound urb */
for (frame = 0; frame < FRAMES_PER_URB; frame++) {
urb->iso_frame_desc[frame].offset = BYTES_PER_FRAME * frame;
@@ -676,6 +696,8 @@
dev->output_running = 1;
wake_up(&dev->prepare_wait_queue);
}
+
+ clear_bit(info->index, &dev->outurb_active_mask);
}
static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret)
@@ -827,6 +849,9 @@
if (!dev->data_cb_info)
return -ENOMEM;
+ dev->outurb_active_mask = 0;
+ BUILD_BUG_ON(N_URBS > (sizeof(dev->outurb_active_mask) * 8));
+
for (i = 0; i < N_URBS; i++) {
dev->data_cb_info[i].dev = dev;
dev->data_cb_info[i].index = i;
diff --git a/sound/usb/caiaq/device.h b/sound/usb/caiaq/device.h
index b2b3101..3f9c633 100644
--- a/sound/usb/caiaq/device.h
+++ b/sound/usb/caiaq/device.h
@@ -96,6 +96,7 @@
int input_panic, output_panic, warned;
char *audio_in_buf, *audio_out_buf;
unsigned int samplerates, bpp;
+ unsigned long outurb_active_mask;
struct snd_pcm_substream *sub_playback[MAX_STREAMS];
struct snd_pcm_substream *sub_capture[MAX_STREAMS];
diff --git a/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c
index 4432ef7..a213813 100644
--- a/sound/usb/caiaq/input.c
+++ b/sound/usb/caiaq/input.c
@@ -30,7 +30,7 @@
static unsigned short keycode_rk2[] = { KEY_1, KEY_2, KEY_3, KEY_4,
KEY_5, KEY_6, KEY_7 };
static unsigned short keycode_rk3[] = { KEY_1, KEY_2, KEY_3, KEY_4,
- KEY_5, KEY_6, KEY_7, KEY_5, KEY_6 };
+ KEY_5, KEY_6, KEY_7, KEY_8, KEY_9 };
static unsigned short keycode_kore[] = {
KEY_FN_F1, /* "menu" */
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 220c616..57a8e2d 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -529,8 +529,11 @@
return chip;
__error:
- if (chip && !chip->num_interfaces)
- snd_card_free(chip->card);
+ if (chip) {
+ if (!chip->num_interfaces)
+ snd_card_free(chip->card);
+ chip->probing = 0;
+ }
mutex_unlock(®ister_mutex);
__err_val:
return NULL;
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index b0ef9f5..05842c8 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -352,7 +352,7 @@
continue;
}
if (((protocol == UAC_VERSION_1) && (fmt->bLength < 8)) ||
- ((protocol == UAC_VERSION_2) && (fmt->bLength != 6))) {
+ ((protocol == UAC_VERSION_2) && (fmt->bLength < 6))) {
snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n",
dev->devnum, iface_no, altno);
continue;
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index c22fa76..cdd19d7 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -152,6 +152,7 @@
if (p && p->dB) {
cval->dBmin = p->dB->min;
cval->dBmax = p->dB->max;
+ cval->initialized = 1;
}
}
@@ -1092,7 +1093,7 @@
" Switch" : " Volume");
if (control == UAC_FU_VOLUME) {
check_mapped_dB(map, cval);
- if (cval->dBmin < cval->dBmax) {
+ if (cval->dBmin < cval->dBmax || !cval->initialized) {
kctl->tlv.c = mixer_vol_tlv;
kctl->vd[0].access |=
SNDRV_CTL_ELEM_ACCESS_TLV_READ |
@@ -1191,6 +1192,11 @@
if (state->mixer->protocol == UAC_VERSION_1) {
csize = hdr->bControlSize;
+ if (!csize) {
+ snd_printdd(KERN_ERR "usbaudio: unit %u: "
+ "invalid bControlSize == 0\n", unitid);
+ return -EINVAL;
+ }
channels = (hdr->bLength - 7) / csize - 1;
bmaControls = hdr->bmaControls;
} else {
@@ -1934,15 +1940,13 @@
struct mixer_build state;
int err;
const struct usbmix_ctl_map *map;
- struct usb_host_interface *hostif;
void *p;
- hostif = mixer->chip->ctrl_intf;
memset(&state, 0, sizeof(state));
state.chip = mixer->chip;
state.mixer = mixer;
- state.buffer = hostif->extra;
- state.buflen = hostif->extralen;
+ state.buffer = mixer->hostif->extra;
+ state.buflen = mixer->hostif->extralen;
/* check the mapping table */
for (map = usbmix_ctl_maps; map->id; map++) {
@@ -1955,7 +1959,8 @@
}
p = NULL;
- while ((p = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, p, UAC_OUTPUT_TERMINAL)) != NULL) {
+ while ((p = snd_usb_find_csint_desc(mixer->hostif->extra, mixer->hostif->extralen,
+ p, UAC_OUTPUT_TERMINAL)) != NULL) {
if (mixer->protocol == UAC_VERSION_1) {
struct uac1_output_terminal_descriptor *desc = p;
@@ -2162,17 +2167,15 @@
/* create the handler for the optional status interrupt endpoint */
static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer)
{
- struct usb_host_interface *hostif;
struct usb_endpoint_descriptor *ep;
void *transfer_buffer;
int buffer_length;
unsigned int epnum;
- hostif = mixer->chip->ctrl_intf;
/* we need one interrupt input endpoint */
- if (get_iface_desc(hostif)->bNumEndpoints < 1)
+ if (get_iface_desc(mixer->hostif)->bNumEndpoints < 1)
return 0;
- ep = get_endpoint(hostif, 0);
+ ep = get_endpoint(mixer->hostif, 0);
if (!usb_endpoint_dir_in(ep) || !usb_endpoint_xfer_int(ep))
return 0;
@@ -2202,7 +2205,6 @@
};
struct usb_mixer_interface *mixer;
struct snd_info_entry *entry;
- struct usb_host_interface *host_iface;
int err;
strcpy(chip->card->mixername, "USB Mixer");
@@ -2219,8 +2221,8 @@
return -ENOMEM;
}
- host_iface = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0];
- switch (get_iface_desc(host_iface)->bInterfaceProtocol) {
+ mixer->hostif = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0];
+ switch (get_iface_desc(mixer->hostif)->bInterfaceProtocol) {
case UAC_VERSION_1:
default:
mixer->protocol = UAC_VERSION_1;
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index ae1a14d..81b2d8a 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -3,6 +3,7 @@
struct usb_mixer_interface {
struct snd_usb_audio *chip;
+ struct usb_host_interface *hostif;
struct list_head list;
unsigned int ignore_ctl_error;
struct urb *urb;
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index c168366..225b292 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -366,6 +366,7 @@
BUILTIN_OBJS += $(OUTPUT)builtin-record.o
BUILTIN_OBJS += $(OUTPUT)builtin-report.o
BUILTIN_OBJS += $(OUTPUT)builtin-stat.o
+BUILTIN_OBJS += $(OUTPUT)builtin-periodic.o
BUILTIN_OBJS += $(OUTPUT)builtin-timechart.o
BUILTIN_OBJS += $(OUTPUT)builtin-top.o
BUILTIN_OBJS += $(OUTPUT)builtin-script.o
diff --git a/tools/perf/builtin-periodic.c b/tools/perf/builtin-periodic.c
new file mode 100644
index 0000000..70a0e2b
--- /dev/null
+++ b/tools/perf/builtin-periodic.c
@@ -0,0 +1,483 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ */
+
+/*
+ * A very simple perf program to periodically print the performance
+ * counter reqested on the command line to standard out at the rate
+ * specified.
+ *
+ * This is valuable for showing the output in a simple plot or
+ * exporting the counter data for post processing. No attempt
+ * to process the data is made.
+ *
+ * Scaling is not supported, use only as many counters as are
+ * provided by the hardware.
+ *
+ * Math functions are support to combine counter results by using
+ * the -m flag.
+ *
+ * The -r -w flags supports user signalling for input. This assumes
+ * that a pipe/fifo is needed so the -rw cmd line arg is a string
+ * that is the name of the named pipe to open for read/write. User
+ * sends data on the read pipe to the process to collect a sample.
+ * Commands are also supported on the pipe.
+ *
+ */
+
+#include "perf.h"
+#include "builtin.h"
+#include "util/util.h"
+#include "util/parse-options.h"
+#include "util/parse-events.h"
+#include "util/event.h"
+#include "util/evsel.h"
+#include "util/evlist.h"
+#include "util/debug.h"
+#include "util/header.h"
+#include "util/cpumap.h"
+#include "util/thread.h"
+#include <signal.h>
+#include <sys/types.h>
+
+#define PERF_PERIODIC_ERROR -1
+
+/* number of pieces of data on each read. */
+#define DATA_SIZE 2
+
+#define DEFAULT_FIFO_NAME "xxbadFiFo"
+#define MAX_NAMELEN 50
+
+struct perf_evlist *evsel_list;
+
+/*
+ * command line variables and settings
+ * Default to current process, no_inherit, process
+ */
+static pid_t target_pid = -1; /* all */
+static bool system_wide;
+static int cpumask = -1; /* all */
+static int ncounts;
+static int ms_sleep = 1000; /* 1 second */
+static char const *operations = "nnnnnnnnnnnnnnnn"; /* nop */
+static bool math_enabled;
+static bool calc_delta;
+static double old_accum, accum;
+static int math_op_index;
+static char const *wfifo_name = DEFAULT_FIFO_NAME;
+static char const *rfifo_name = DEFAULT_FIFO_NAME;
+static bool use_fifo;
+static bool is_ratio;
+static FILE *fd_in, *fd_out;
+
+static FILE *tReadFifo, *tWriteFifo;
+
+/*
+ * Raw results from perf, we track the current value and
+ * the old value.
+ */
+struct perf_raw_results_s {
+ u64 values;
+ u64 old_value;
+};
+
+/*
+ * Everything we need to support a perf counter across multiple
+ * CPUs. We need to support multiple file descriptors (perf_fd)
+ * because perf requires a fd per counter, so 1 per core enabled.
+ *
+ * Raw results values are calculated across all the cores as they
+ * are read.
+ */
+struct perf_setup_s {
+ int event_index;
+ struct perf_event_attr *attr;
+ int perf_fd[MAX_NR_CPUS];
+ pid_t pid;
+ int cpu;
+ int flags;
+ int group;
+ struct perf_raw_results_s data;
+ struct perf_raw_results_s totals;
+ struct perf_raw_results_s output;
+};
+
+static void do_cleanup(void)
+{
+ if (fd_in) {
+ if (0 != fclose(fd_in))
+ error("Error closing fd_in\n");
+ }
+ if (fd_out) {
+ if (0 != fclose(fd_out))
+ error("Error closing fd_out\n");
+ }
+ if (use_fifo) {
+ if (0 != unlink(rfifo_name))
+ error("Error unlinking rfifo\n");
+ if (0 != unlink(wfifo_name))
+ error("Error unlinking wfifo\n");
+ }
+}
+
+/*
+ * Unexpected signal for error indication, cleanup
+ */
+static int sig_dummy;
+static void sig_do_cleanup(int sig)
+{
+ sig_dummy = sig;
+ do_cleanup();
+ exit(0);
+}
+
+#define PERIODIC_MAX_STRLEN 100
+/*
+ * Delay for either a timed period or the wait on the read_fifo
+ */
+static void delay(unsigned long milli)
+{
+ char tmp_stg[PERIODIC_MAX_STRLEN];
+ int done;
+ int ret;
+
+ if (use_fifo) {
+ do {
+ done = true;
+ ret = fscanf(tReadFifo, "%s", tmp_stg);
+ if (ret == 0)
+ return;
+ /*
+ * Look for a command request, and if we get a command
+ * Need to process and then wait again w/o sending data.
+ */
+ if (strncmp(tmp_stg, "PID", strnlen(tmp_stg,
+ PERIODIC_MAX_STRLEN)) == 0) {
+ fprintf(fd_out, " %u\n", getpid());
+ fflush(fd_out);
+ done = false;
+ } else if (strncmp(tmp_stg, "EXIT",
+ strnlen(tmp_stg, PERIODIC_MAX_STRLEN))
+ == 0) {
+ do_cleanup();
+ exit(0);
+ }
+
+ } while (done != true);
+ } else
+ usleep(milli*1000);
+}
+
+/*
+ * Create a perf counter event.
+ * Some interesting behaviour that is not documented anywhere else:
+ * the CPU will not work if out of range.
+ * The CPU will only work for a single CPU, so to collect the counts
+ * on the system in SMP based systems a counter needs to be created
+ * for each CPU.
+ */
+static int create_perf_counter(struct perf_setup_s *p)
+{
+ struct cpu_map *cpus;
+ int cpu;
+
+ cpus = cpu_map__new(NULL);
+ if (p == NULL)
+ return PERF_PERIODIC_ERROR;
+ for (cpu = 0; cpu < cpus->nr; cpu++) {
+ p->perf_fd[cpu] = sys_perf_event_open(p->attr, target_pid, cpu,
+ -1, 0);
+ if (p->perf_fd[cpu] < 0)
+ return PERF_PERIODIC_ERROR;
+ }
+ return 0;
+}
+
+/*
+ * Perf init setup
+ */
+static int perf_setup_init(struct perf_setup_s *p)
+{
+ if (p == NULL)
+ return PERF_PERIODIC_ERROR;
+
+ bzero(p, sizeof(struct perf_setup_s));
+ p->group = -1;
+ p->flags = 0;
+
+ p->output.values = 0;
+ p->output.old_value = 0;
+ p->data.values = 0;
+ p->data.old_value = 0;
+ p->totals.old_value = 0;
+ p->totals.values = 0;
+
+ return 0;
+}
+
+/*
+ * Read in ALL the performance counters configured for the CPU,
+ * one performance monitor per core that was configured during
+ * "all" mode
+ */
+static int perf_setup_read(struct perf_setup_s *p)
+{
+ u64 data[DATA_SIZE];
+ int i, status;
+
+ p->totals.values = 0;
+ p->data.values = 0;
+ for (i = 0; i < MAX_NR_CPUS; i++) {
+ if (p->perf_fd[i] == 0)
+ continue;
+ status = read(p->perf_fd[i], &data, sizeof(data));
+ p->data.values += data[0];
+ p->totals.values += data[0];
+ }
+
+ /*
+ * Normally we show totals, we want to support
+ * showing deltas from the previous value so external apps do not have
+ * to do this...
+ */
+ if (calc_delta) {
+ p->output.values = p->data.values - p->data.old_value;
+ p->data.old_value = p->data.values;
+ } else
+ p->output.values = p->totals.values;
+ return 0;
+}
+
+static int perf_setup_show(struct perf_setup_s *p)
+{
+ if (p == NULL)
+ return PERF_PERIODIC_ERROR;
+ fprintf(fd_out, " %llu", p->output.values);
+ return 0;
+}
+
+
+static const char * const periodic_usage[] = {
+ "perf periodic [<options>]",
+ NULL
+};
+
+static const struct option options[] = {
+ OPT_CALLBACK('e', "event", &evsel_list, "event",
+ "event selector. use 'perf list' to list available events",
+ parse_events),
+ OPT_STRING('m', "math-operations", &operations, "nnnnnn",
+ "math operation to perform on values collected asmd in order"),
+ OPT_STRING('r', "readpipe", &rfifo_name, "xxbadFiFo",
+ "wait for a user input fifo - will be created"),
+ OPT_STRING('w', "writepipe", &wfifo_name, "xxbadFifo",
+ "write data out on this pipe - pipe is created"),
+ OPT_INTEGER('i', "increment", &ncounts,
+ "number of times periods to count/iterate (default 0-forever)"),
+ OPT_INTEGER('p', "pid", &target_pid,
+ "stat events on existing process id"),
+ OPT_INTEGER('c', "cpumask", &cpumask,
+ "cpumask to enable counters, default all (-1)"),
+ OPT_INTEGER('s', "sleep", &ms_sleep,
+ "how long to sleep in ms between each sample (default 1000)"),
+ OPT_BOOLEAN('a', "all-cpus", &system_wide,
+ "system-wide collection from all CPUs overrides cpumask"),
+ OPT_BOOLEAN('d', "delta", &calc_delta,
+ "calculate and display the delta values math funcs will use delta"),
+ OPT_INCR('v', "verbose", &verbose,
+ "be more verbose (show counter open errors, etc)"),
+ OPT_END()
+};
+
+/*
+ * After every period we reset any math that was performed.
+ */
+static void reset_math(void)
+{
+ math_op_index = 0;
+ old_accum = accum;
+ accum = 0;
+}
+
+static void do_math_op(struct perf_setup_s *p)
+{
+ if (!math_enabled)
+ return;
+ switch (operations[math_op_index++]) {
+ case 'm':
+ accum *= (double)p->output.values; break;
+ case 'a':
+ accum += (double)p->output.values; break;
+ case 's':
+ accum -= (double)p->output.values; break;
+ case 'd':
+ accum /= (double)p->output.values; break;
+ case 'z':
+ accum = 0; break;
+ case 't':
+ accum = (double)p->output.values; break; /*transfer*/
+ case 'T':
+ accum += old_accum; break; /*total*/
+ case 'i': /* ignore */
+ default:
+ break;
+ }
+}
+
+int cmd_periodic(int argc, const char **argv, const char *prefix __used)
+{
+ int status = 0;
+ int c, i;
+ struct perf_setup_s *p[MAX_COUNTERS];
+ struct perf_evsel *counter;
+ FILE *fp;
+ int nr_counters = 0;
+
+ evsel_list = perf_evlist__new(NULL, NULL);
+ if (evsel_list == NULL)
+ return -ENOMEM;
+
+ argc = parse_options(argc, argv, options, periodic_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+
+ if (system_wide)
+ cpumask = -1;
+
+ /*
+ * The r & w option redirects stdout to a newly created pipe and
+ * waits for input on the read pipe before continuing
+ */
+ fd_in = stdin;
+ fd_out = stdout;
+ if (strncmp(rfifo_name, DEFAULT_FIFO_NAME,
+ strnlen(rfifo_name, MAX_NAMELEN))) {
+ fp = fopen(rfifo_name, "r");
+ if (fp != NULL) {
+ fclose(fp);
+ remove(rfifo_name);
+ }
+ if (mkfifo(rfifo_name, 0777) == -1) {
+ error("Could not open read fifo\n");
+ do_cleanup();
+ return PERF_PERIODIC_ERROR;
+ }
+ tReadFifo = fopen(rfifo_name, "r+");
+ if (tReadFifo == 0) {
+ do_cleanup();
+ error("Could not open read fifo file\n");
+ return PERF_PERIODIC_ERROR;
+ }
+ use_fifo = true;
+ }
+ if (strncmp(wfifo_name, DEFAULT_FIFO_NAME,
+ strnlen(wfifo_name, MAX_NAMELEN))) {
+ fp = fopen(wfifo_name, "r");
+ if (fp != NULL) {
+ fclose(fp);
+ remove(wfifo_name);
+ }
+ if (mkfifo(wfifo_name, 0777) == -1) {
+ do_cleanup();
+ error("Could not open write fifo\n");
+ return PERF_PERIODIC_ERROR;
+ }
+ fd_out = fopen(wfifo_name, "w+");
+ if (fd_out == 0) {
+ do_cleanup();
+ error("Could not open write fifo file\n");
+ return PERF_PERIODIC_ERROR;
+ }
+ tWriteFifo = fd_out;
+ }
+
+ math_enabled = (operations[0] != 'n');
+
+ /*
+ * If we don't ignore SIG_PIPE then when the other side
+ * of a pipe closes we shutdown too...
+ */
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGINT, sig_do_cleanup);
+ signal(SIGQUIT, sig_do_cleanup);
+ signal(SIGKILL, sig_do_cleanup);
+ signal(SIGTERM, sig_do_cleanup);
+
+ i = 0;
+ list_for_each_entry(counter, &evsel_list->entries, node) {
+ p[i] = malloc(sizeof(struct perf_setup_s));
+ if (p[i] == NULL) {
+ error("Error allocating perf_setup_s\n");
+ do_cleanup();
+ return PERF_PERIODIC_ERROR;
+ }
+ bzero(p[i], sizeof(struct perf_setup_s));
+ perf_setup_init(p[i]);
+ p[i]->attr = &(counter->attr);
+ p[i]->event_index = counter->idx;
+ if (create_perf_counter(p[i]) < 0) {
+ do_cleanup();
+ die("Not all events could be opened.\n");
+ return PERF_PERIODIC_ERROR;
+ }
+ i++;
+ nr_counters++;
+ }
+ i = 0;
+ while (1) {
+
+ /*
+ * Wait first otherwise single sample will print w/o signal
+ * when using the -u (user signal) flag
+ */
+ delay(ms_sleep);
+
+ /*
+ * Do the collection, read and then perform any math operations
+ */
+ for (c = 0; c < nr_counters; c++) {
+ status = perf_setup_read(p[c]);
+ do_math_op(p[c]);
+ }
+
+ /*
+ * After all collection and math, we perform one last math
+ * to allow totaling, if enabled etc, then either printout
+ * a single float value when the math is enabled or ...
+ */
+ if (math_enabled) {
+ do_math_op(p[c]);
+ if (is_ratio)
+ fprintf(fd_out, "%#f\n", accum*100);
+ else
+ fprintf(fd_out, "%#f\n", accum);
+ } else {
+ /*
+ * ... print out one integer value for each counter
+ */
+ for (c = 0; c < nr_counters; c++)
+ status = perf_setup_show(p[c]);
+ fprintf(fd_out, "\n");
+ }
+
+ /*
+ * Did the user give us an iteration count?
+ */
+ if ((ncounts != 0) && (++i >= ncounts))
+ break;
+ reset_math();
+ fflush(fd_out); /* make sure data is flushed out the pipe*/
+ }
+
+ do_cleanup();
+
+ return status;
+}
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index 4702e24..889ff68 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -26,6 +26,7 @@
extern int cmd_record(int argc, const char **argv, const char *prefix);
extern int cmd_report(int argc, const char **argv, const char *prefix);
extern int cmd_stat(int argc, const char **argv, const char *prefix);
+extern int cmd_periodic(int argc, const char **argv, const char *prefix);
extern int cmd_timechart(int argc, const char **argv, const char *prefix);
extern int cmd_top(int argc, const char **argv, const char *prefix);
extern int cmd_script(int argc, const char **argv, const char *prefix);
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index ec635b7..32f6673 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -320,6 +320,7 @@
{ "report", cmd_report, 0 },
{ "bench", cmd_bench, 0 },
{ "stat", cmd_stat, 0 },
+ { "periodic", cmd_periodic, 0 },
{ "timechart", cmd_timechart, 0 },
{ "top", cmd_top, 0 },
{ "annotate", cmd_annotate, 0 },
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index e02d78c..6c86eca 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -399,7 +399,6 @@
int perf_config(config_fn_t fn, void *data)
{
int ret = 0, found = 0;
- char *repo_config = NULL;
const char *home = NULL;
/* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
@@ -421,12 +420,6 @@
free(user_config);
}
- repo_config = perf_pathdup("config");
- if (!access(repo_config, R_OK)) {
- ret += perf_config_from_file(fn, repo_config, data);
- found += 1;
- }
- free(repo_config);
if (found == 0)
return -1;
return ret;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index eec1963..40fd1c7 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1111,6 +1111,8 @@
}
opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx);
+ if (opdshdr.sh_type != SHT_PROGBITS)
+ opdsec = NULL;
if (opdsec)
opddata = elf_rawdata(opdsec, NULL);