Merge branch 'topic/hda' into for-linus
diff --git a/CREDITS b/CREDITS
index 72b4878..41d8e63 100644
--- a/CREDITS
+++ b/CREDITS
@@ -3554,12 +3554,12 @@
D: portions of the Linux Security Module (LSM) framework and security modules
N: Petr Vandrovec
-E: vandrove@vc.cvut.cz
+E: petr@vandrovec.name
D: Small contributions to ncpfs
D: Matrox framebuffer driver
-S: Chudenicka 8
-S: 10200 Prague 10, Hostivar
-S: Czech Republic
+S: 21513 Conradia Ct
+S: Cupertino, CA 95014
+S: USA
N: Thibaut Varene
E: T-Bone@parisc-linux.org
diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface
index ff45d1f..48ceabe 100644
--- a/Documentation/hwmon/sysfs-interface
+++ b/Documentation/hwmon/sysfs-interface
@@ -91,12 +91,11 @@
I2C devices get this attribute created automatically.
RO
-update_rate The rate at which the chip will update readings.
+update_interval The interval at which the chip will update readings.
Unit: millisecond
RW
- Some devices have a variable update rate. This attribute
- can be used to change the update rate to the desired
- frequency.
+ Some devices have a variable update rate or interval.
+ This attribute can be used to change it to the desired value.
************
diff --git a/Documentation/networking/e1000.txt b/Documentation/networking/e1000.txt
index 2df7186..d9271e7 100644
--- a/Documentation/networking/e1000.txt
+++ b/Documentation/networking/e1000.txt
@@ -1,82 +1,35 @@
Linux* Base Driver for the Intel(R) PRO/1000 Family of Adapters
===============================================================
-September 26, 2006
-
+Intel Gigabit Linux driver.
+Copyright(c) 1999 - 2010 Intel Corporation.
Contents
========
-- In This Release
- Identifying Your Adapter
-- Building and Installation
- Command Line Parameters
- Speed and Duplex Configuration
- Additional Configurations
-- Known Issues
- Support
-
-In This Release
-===============
-
-This file describes the Linux* Base Driver for the Intel(R) PRO/1000 Family
-of Adapters. This driver includes support for Itanium(R)2-based systems.
-
-For questions related to hardware requirements, refer to the documentation
-supplied with your Intel PRO/1000 adapter. All hardware requirements listed
-apply to use with Linux.
-
-The following features are now available in supported kernels:
- - Native VLANs
- - Channel Bonding (teaming)
- - SNMP
-
-Channel Bonding documentation can be found in the Linux kernel source:
-/Documentation/networking/bonding.txt
-
-The driver information previously displayed in the /proc filesystem is not
-supported in this release. Alternatively, you can use ethtool (version 1.6
-or later), lspci, and ifconfig to obtain the same information.
-
-Instructions on updating ethtool can be found in the section "Additional
-Configurations" later in this document.
-
-NOTE: The Intel(R) 82562v 10/100 Network Connection only provides 10/100
-support.
-
-
Identifying Your Adapter
========================
For more information on how to identify your adapter, go to the Adapter &
Driver ID Guide at:
- http://support.intel.com/support/network/adapter/pro100/21397.htm
+ http://support.intel.com/support/go/network/adapter/idguide.htm
For the latest Intel network drivers for Linux, refer to the following
website. In the search field, enter your adapter name or type, or use the
networking link on the left to search for your adapter:
- http://downloadfinder.intel.com/scripts-df/support_intel.asp
-
+ http://support.intel.com/support/go/network/adapter/home.htm
Command Line Parameters
=======================
-If the driver is built as a module, the following optional parameters
-are used by entering them on the command line with the modprobe command
-using this syntax:
-
- modprobe e1000 [<option>=<VAL1>,<VAL2>,...]
-
-For example, with two PRO/1000 PCI adapters, entering:
-
- modprobe e1000 TxDescriptors=80,128
-
-loads the e1000 driver with 80 TX descriptors for the first adapter and
-128 TX descriptors for the second adapter.
-
The default value for each parameter is generally the recommended setting,
unless otherwise noted.
@@ -89,10 +42,6 @@
parameters, see the application note at:
http://www.intel.com/design/network/applnots/ap450.htm
- A descriptor describes a data buffer and attributes related to
- the data buffer. This information is accessed by the hardware.
-
-
AutoNeg
-------
(Supported only on adapters with copper connections)
@@ -106,7 +55,6 @@
NOTE: Refer to the Speed and Duplex section of this readme for more
information on the AutoNeg parameter.
-
Duplex
------
(Supported only on adapters with copper connections)
@@ -119,7 +67,6 @@
link partner is forced (either full or half), Duplex defaults to half-
duplex.
-
FlowControl
-----------
Valid Range: 0-3 (0=none, 1=Rx only, 2=Tx only, 3=Rx&Tx)
@@ -128,16 +75,16 @@
This parameter controls the automatic generation(Tx) and response(Rx)
to Ethernet PAUSE frames.
-
InterruptThrottleRate
---------------------
(not supported on Intel(R) 82542, 82543 or 82544-based adapters)
-Valid Range: 0,1,3,100-100000 (0=off, 1=dynamic, 3=dynamic conservative)
+Valid Range: 0,1,3,4,100-100000 (0=off, 1=dynamic, 3=dynamic conservative,
+ 4=simplified balancing)
Default Value: 3
The driver can limit the amount of interrupts per second that the adapter
-will generate for incoming packets. It does this by writing a value to the
-adapter that is based on the maximum amount of interrupts that the adapter
+will generate for incoming packets. It does this by writing a value to the
+adapter that is based on the maximum amount of interrupts that the adapter
will generate per second.
Setting InterruptThrottleRate to a value greater or equal to 100
@@ -146,37 +93,43 @@
load on the system and can lower CPU utilization under heavy load,
but will increase latency as packets are not processed as quickly.
-The default behaviour of the driver previously assumed a static
-InterruptThrottleRate value of 8000, providing a good fallback value for
-all traffic types,but lacking in small packet performance and latency.
-The hardware can handle many more small packets per second however, and
+The default behaviour of the driver previously assumed a static
+InterruptThrottleRate value of 8000, providing a good fallback value for
+all traffic types,but lacking in small packet performance and latency.
+The hardware can handle many more small packets per second however, and
for this reason an adaptive interrupt moderation algorithm was implemented.
Since 7.3.x, the driver has two adaptive modes (setting 1 or 3) in which
-it dynamically adjusts the InterruptThrottleRate value based on the traffic
+it dynamically adjusts the InterruptThrottleRate value based on the traffic
that it receives. After determining the type of incoming traffic in the last
-timeframe, it will adjust the InterruptThrottleRate to an appropriate value
+timeframe, it will adjust the InterruptThrottleRate to an appropriate value
for that traffic.
The algorithm classifies the incoming traffic every interval into
-classes. Once the class is determined, the InterruptThrottleRate value is
-adjusted to suit that traffic type the best. There are three classes defined:
+classes. Once the class is determined, the InterruptThrottleRate value is
+adjusted to suit that traffic type the best. There are three classes defined:
"Bulk traffic", for large amounts of packets of normal size; "Low latency",
for small amounts of traffic and/or a significant percentage of small
-packets; and "Lowest latency", for almost completely small packets or
+packets; and "Lowest latency", for almost completely small packets or
minimal traffic.
-In dynamic conservative mode, the InterruptThrottleRate value is set to 4000
-for traffic that falls in class "Bulk traffic". If traffic falls in the "Low
-latency" or "Lowest latency" class, the InterruptThrottleRate is increased
+In dynamic conservative mode, the InterruptThrottleRate value is set to 4000
+for traffic that falls in class "Bulk traffic". If traffic falls in the "Low
+latency" or "Lowest latency" class, the InterruptThrottleRate is increased
stepwise to 20000. This default mode is suitable for most applications.
For situations where low latency is vital such as cluster or
grid computing, the algorithm can reduce latency even more when
InterruptThrottleRate is set to mode 1. In this mode, which operates
-the same as mode 3, the InterruptThrottleRate will be increased stepwise to
+the same as mode 3, the InterruptThrottleRate will be increased stepwise to
70000 for traffic in class "Lowest latency".
+In simplified mode the interrupt rate is based on the ratio of Tx and
+Rx traffic. If the bytes per second rate is approximately equal, the
+interrupt rate will drop as low as 2000 interrupts per second. If the
+traffic is mostly transmit or mostly receive, the interrupt rate could
+be as high as 8000.
+
Setting InterruptThrottleRate to 0 turns off any interrupt moderation
and may improve small packet latency, but is generally not suitable
for bulk throughput traffic.
@@ -212,8 +165,6 @@
be platform-specific. If CPU utilization is not a concern, use
RX_POLLING (NAPI) and default driver settings.
-
-
RxDescriptors
-------------
Valid Range: 80-256 for 82542 and 82543-based adapters
@@ -225,15 +176,14 @@
incoming packets, at the expense of increased system memory utilization.
Each descriptor is 16 bytes. A receive buffer is also allocated for each
-descriptor and can be either 2048, 4096, 8192, or 16384 bytes, depending
+descriptor and can be either 2048, 4096, 8192, or 16384 bytes, depending
on the MTU setting. The maximum MTU size is 16110.
-NOTE: MTU designates the frame size. It only needs to be set for Jumbo
- Frames. Depending on the available system resources, the request
- for a higher number of receive descriptors may be denied. In this
+NOTE: MTU designates the frame size. It only needs to be set for Jumbo
+ Frames. Depending on the available system resources, the request
+ for a higher number of receive descriptors may be denied. In this
case, use a lower number.
-
RxIntDelay
----------
Valid Range: 0-65535 (0=off)
@@ -254,7 +204,6 @@
restoring the network connection. To eliminate the potential
for the hang ensure that RxIntDelay is set to 0.
-
RxAbsIntDelay
-------------
(This parameter is supported only on 82540, 82545 and later adapters.)
@@ -268,7 +217,6 @@
along with RxIntDelay, may improve traffic throughput in specific network
conditions.
-
Speed
-----
(This parameter is supported only on adapters with copper connections.)
@@ -280,7 +228,6 @@
partner is set to auto-negotiate, the board will auto-detect the correct
speed. Duplex should also be set when Speed is set to either 10 or 100.
-
TxDescriptors
-------------
Valid Range: 80-256 for 82542 and 82543-based adapters
@@ -295,6 +242,36 @@
higher number of transmit descriptors may be denied. In this case,
use a lower number.
+TxDescriptorStep
+----------------
+Valid Range: 1 (use every Tx Descriptor)
+ 4 (use every 4th Tx Descriptor)
+
+Default Value: 1 (use every Tx Descriptor)
+
+On certain non-Intel architectures, it has been observed that intense TX
+traffic bursts of short packets may result in an improper descriptor
+writeback. If this occurs, the driver will report a "TX Timeout" and reset
+the adapter, after which the transmit flow will restart, though data may
+have stalled for as much as 10 seconds before it resumes.
+
+The improper writeback does not occur on the first descriptor in a system
+memory cache-line, which is typically 32 bytes, or 4 descriptors long.
+
+Setting TxDescriptorStep to a value of 4 will ensure that all TX descriptors
+are aligned to the start of a system memory cache line, and so this problem
+will not occur.
+
+NOTES: Setting TxDescriptorStep to 4 effectively reduces the number of
+ TxDescriptors available for transmits to 1/4 of the normal allocation.
+ This has a possible negative performance impact, which may be
+ compensated for by allocating more descriptors using the TxDescriptors
+ module parameter.
+
+ There are other conditions which may result in "TX Timeout", which will
+ not be resolved by the use of the TxDescriptorStep parameter. As the
+ issue addressed by this parameter has never been observed on Intel
+ Architecture platforms, it should not be used on Intel platforms.
TxIntDelay
----------
@@ -307,7 +284,6 @@
system is reporting dropped transmits, this value may be set too high
causing the driver to run out of available transmit descriptors.
-
TxAbsIntDelay
-------------
(This parameter is supported only on 82540, 82545 and later adapters.)
@@ -330,6 +306,35 @@
A value of '1' indicates that the driver should enable IP checksum
offload for received packets (both UDP and TCP) to the adapter hardware.
+Copybreak
+---------
+Valid Range: 0-xxxxxxx (0=off)
+Default Value: 256
+Usage: insmod e1000.ko copybreak=128
+
+Driver copies all packets below or equaling this size to a fresh Rx
+buffer before handing it up the stack.
+
+This parameter is different than other parameters, in that it is a
+single (not 1,1,1 etc.) parameter applied to all driver instances and
+it is also available during runtime at
+/sys/module/e1000/parameters/copybreak
+
+SmartPowerDownEnable
+--------------------
+Valid Range: 0-1
+Default Value: 0 (disabled)
+
+Allows PHY to turn off in lower power states. The user can turn off
+this parameter in supported chipsets.
+
+KumeranLockLoss
+---------------
+Valid Range: 0-1
+Default Value: 1 (enabled)
+
+This workaround skips resetting the PHY at shutdown for the initial
+silicon releases of ICH8 systems.
Speed and Duplex Configuration
==============================
@@ -385,40 +390,9 @@
parameter should not be used. Instead, use the Speed and Duplex parameters
previously mentioned to force the adapter to the same speed and duplex.
-
Additional Configurations
=========================
- Configuring the Driver on Different Distributions
- -------------------------------------------------
- Configuring a network driver to load properly when the system is started
- is distribution dependent. Typically, the configuration process involves
- adding an alias line to /etc/modules.conf or /etc/modprobe.conf as well
- as editing other system startup scripts and/or configuration files. Many
- popular Linux distributions ship with tools to make these changes for you.
- To learn the proper way to configure a network device for your system,
- refer to your distribution documentation. If during this process you are
- asked for the driver or module name, the name for the Linux Base Driver
- for the Intel(R) PRO/1000 Family of Adapters is e1000.
-
- As an example, if you install the e1000 driver for two PRO/1000 adapters
- (eth0 and eth1) and set the speed and duplex to 10full and 100half, add
- the following to modules.conf or or modprobe.conf:
-
- alias eth0 e1000
- alias eth1 e1000
- options e1000 Speed=10,100 Duplex=2,1
-
- Viewing Link Messages
- ---------------------
- Link messages will not be displayed to the console if the distribution is
- restricting system messages. In order to see network driver link messages
- on your console, set dmesg to eight by entering the following:
-
- dmesg -n 8
-
- NOTE: This setting is not saved across reboots.
-
Jumbo Frames
------------
Jumbo Frames support is enabled by changing the MTU to a value larger than
@@ -437,9 +411,11 @@
setting in a different location.
Notes:
-
- - To enable Jumbo Frames, increase the MTU size on the interface beyond
- 1500.
+ Degradation in throughput performance may be observed in some Jumbo frames
+ environments. If this is observed, increasing the application's socket buffer
+ size and/or increasing the /proc/sys/net/ipv4/tcp_*mem entry values may help.
+ See the specific application manual and /usr/src/linux*/Documentation/
+ networking/ip-sysctl.txt for more details.
- The maximum MTU setting for Jumbo Frames is 16110. This value coincides
with the maximum Jumbo Frames size of 16128.
@@ -447,40 +423,11 @@
- Using Jumbo Frames at 10 or 100 Mbps may result in poor performance or
loss of link.
- - Some Intel gigabit adapters that support Jumbo Frames have a frame size
- limit of 9238 bytes, with a corresponding MTU size limit of 9216 bytes.
- The adapters with this limitation are based on the Intel(R) 82571EB,
- 82572EI, 82573L and 80003ES2LAN controller. These correspond to the
- following product names:
- Intel(R) PRO/1000 PT Server Adapter
- Intel(R) PRO/1000 PT Desktop Adapter
- Intel(R) PRO/1000 PT Network Connection
- Intel(R) PRO/1000 PT Dual Port Server Adapter
- Intel(R) PRO/1000 PT Dual Port Network Connection
- Intel(R) PRO/1000 PF Server Adapter
- Intel(R) PRO/1000 PF Network Connection
- Intel(R) PRO/1000 PF Dual Port Server Adapter
- Intel(R) PRO/1000 PB Server Connection
- Intel(R) PRO/1000 PL Network Connection
- Intel(R) PRO/1000 EB Network Connection with I/O Acceleration
- Intel(R) PRO/1000 EB Backplane Connection with I/O Acceleration
- Intel(R) PRO/1000 PT Quad Port Server Adapter
-
- Adapters based on the Intel(R) 82542 and 82573V/E controller do not
support Jumbo Frames. These correspond to the following product names:
Intel(R) PRO/1000 Gigabit Server Adapter
Intel(R) PRO/1000 PM Network Connection
- - The following adapters do not support Jumbo Frames:
- Intel(R) 82562V 10/100 Network Connection
- Intel(R) 82566DM Gigabit Network Connection
- Intel(R) 82566DC Gigabit Network Connection
- Intel(R) 82566MM Gigabit Network Connection
- Intel(R) 82566MC Gigabit Network Connection
- Intel(R) 82562GT 10/100 Network Connection
- Intel(R) 82562G 10/100 Network Connection
-
-
Ethtool
-------
The driver utilizes the ethtool interface for driver configuration and
@@ -490,142 +437,14 @@
The latest release of ethtool can be found from
http://sourceforge.net/projects/gkernel.
- NOTE: Ethtool 1.6 only supports a limited set of ethtool options. Support
- for a more complete ethtool feature set can be enabled by upgrading
- ethtool to ethtool-1.8.1.
-
Enabling Wake on LAN* (WoL)
---------------------------
- WoL is configured through the Ethtool* utility. Ethtool is included with
- all versions of Red Hat after Red Hat 7.2. For other Linux distributions,
- download and install Ethtool from the following website:
- http://sourceforge.net/projects/gkernel.
-
- For instructions on enabling WoL with Ethtool, refer to the website listed
- above.
+ WoL is configured through the Ethtool* utility.
WoL will be enabled on the system during the next shut down or reboot.
For this driver version, in order to enable WoL, the e1000 driver must be
loaded when shutting down or rebooting the system.
- Wake On LAN is only supported on port A for the following devices:
- Intel(R) PRO/1000 PT Dual Port Network Connection
- Intel(R) PRO/1000 PT Dual Port Server Connection
- Intel(R) PRO/1000 PT Dual Port Server Adapter
- Intel(R) PRO/1000 PF Dual Port Server Adapter
- Intel(R) PRO/1000 PT Quad Port Server Adapter
-
- NAPI
- ----
- NAPI (Rx polling mode) is enabled in the e1000 driver.
-
- See www.cyberus.ca/~hadi/usenix-paper.tgz for more information on NAPI.
-
-
-Known Issues
-============
-
-Dropped Receive Packets on Half-duplex 10/100 Networks
-------------------------------------------------------
-If you have an Intel PCI Express adapter running at 10mbps or 100mbps, half-
-duplex, you may observe occasional dropped receive packets. There are no
-workarounds for this problem in this network configuration. The network must
-be updated to operate in full-duplex, and/or 1000mbps only.
-
-Jumbo Frames System Requirement
--------------------------------
-Memory allocation failures have been observed on Linux systems with 64 MB
-of RAM or less that are running Jumbo Frames. If you are using Jumbo
-Frames, your system may require more than the advertised minimum
-requirement of 64 MB of system memory.
-
-Performance Degradation with Jumbo Frames
------------------------------------------
-Degradation in throughput performance may be observed in some Jumbo frames
-environments. If this is observed, increasing the application's socket
-buffer size and/or increasing the /proc/sys/net/ipv4/tcp_*mem entry values
-may help. See the specific application manual and
-/usr/src/linux*/Documentation/
-networking/ip-sysctl.txt for more details.
-
-Jumbo Frames on Foundry BigIron 8000 switch
--------------------------------------------
-There is a known issue using Jumbo frames when connected to a Foundry
-BigIron 8000 switch. This is a 3rd party limitation. If you experience
-loss of packets, lower the MTU size.
-
-Allocating Rx Buffers when Using Jumbo Frames
----------------------------------------------
-Allocating Rx buffers when using Jumbo Frames on 2.6.x kernels may fail if
-the available memory is heavily fragmented. This issue may be seen with PCI-X
-adapters or with packet split disabled. This can be reduced or eliminated
-by changing the amount of available memory for receive buffer allocation, by
-increasing /proc/sys/vm/min_free_kbytes.
-
-Multiple Interfaces on Same Ethernet Broadcast Network
-------------------------------------------------------
-Due to the default ARP behavior on Linux, it is not possible to have
-one system on two IP networks in the same Ethernet broadcast domain
-(non-partitioned switch) behave as expected. All Ethernet interfaces
-will respond to IP traffic for any IP address assigned to the system.
-This results in unbalanced receive traffic.
-
-If you have multiple interfaces in a server, either turn on ARP
-filtering by entering:
-
- echo 1 > /proc/sys/net/ipv4/conf/all/arp_filter
-(this only works if your kernel's version is higher than 2.4.5),
-
-NOTE: This setting is not saved across reboots. The configuration
-change can be made permanent by adding the line:
- net.ipv4.conf.all.arp_filter = 1
-to the file /etc/sysctl.conf
-
- or,
-
-install the interfaces in separate broadcast domains (either in
-different switches or in a switch partitioned to VLANs).
-
-82541/82547 can't link or are slow to link with some link partners
------------------------------------------------------------------
-There is a known compatibility issue with 82541/82547 and some
-low-end switches where the link will not be established, or will
-be slow to establish. In particular, these switches are known to
-be incompatible with 82541/82547:
-
- Planex FXG-08TE
- I-O Data ETG-SH8
-
-To workaround this issue, the driver can be compiled with an override
-of the PHY's master/slave setting. Forcing master or forcing slave
-mode will improve time-to-link.
-
- # make CFLAGS_EXTRA=-DE1000_MASTER_SLAVE=<n>
-
-Where <n> is:
-
- 0 = Hardware default
- 1 = Master mode
- 2 = Slave mode
- 3 = Auto master/slave
-
-Disable rx flow control with ethtool
-------------------------------------
-In order to disable receive flow control using ethtool, you must turn
-off auto-negotiation on the same command line.
-
-For example:
-
- ethtool -A eth? autoneg off rx off
-
-Unplugging network cable while ethtool -p is running
-----------------------------------------------------
-In kernel versions 2.5.50 and later (including 2.6 kernel), unplugging
-the network cable while ethtool -p is running will cause the system to
-become unresponsive to keyboard commands, except for control-alt-delete.
-Restarting the system appears to be the only remedy.
-
-
Support
=======
diff --git a/Documentation/networking/e1000e.txt b/Documentation/networking/e1000e.txt
new file mode 100644
index 0000000..6aa048b
--- /dev/null
+++ b/Documentation/networking/e1000e.txt
@@ -0,0 +1,302 @@
+Linux* Driver for Intel(R) Network Connection
+===============================================================
+
+Intel Gigabit Linux driver.
+Copyright(c) 1999 - 2010 Intel Corporation.
+
+Contents
+========
+
+- Identifying Your Adapter
+- Command Line Parameters
+- Additional Configurations
+- Support
+
+Identifying Your Adapter
+========================
+
+The e1000e driver supports all PCI Express Intel(R) Gigabit Network
+Connections, except those that are 82575, 82576 and 82580-based*.
+
+* NOTE: The Intel(R) PRO/1000 P Dual Port Server Adapter is supported by
+ the e1000 driver, not the e1000e driver due to the 82546 part being used
+ behind a PCI Express bridge.
+
+For more information on how to identify your adapter, go to the Adapter &
+Driver ID Guide at:
+
+ http://support.intel.com/support/go/network/adapter/idguide.htm
+
+For the latest Intel network drivers for Linux, refer to the following
+website. In the search field, enter your adapter name or type, or use the
+networking link on the left to search for your adapter:
+
+ http://support.intel.com/support/go/network/adapter/home.htm
+
+Command Line Parameters
+=======================
+
+The default value for each parameter is generally the recommended setting,
+unless otherwise noted.
+
+NOTES: For more information about the InterruptThrottleRate,
+ RxIntDelay, TxIntDelay, RxAbsIntDelay, and TxAbsIntDelay
+ parameters, see the application note at:
+ http://www.intel.com/design/network/applnots/ap450.htm
+
+InterruptThrottleRate
+---------------------
+Valid Range: 0,1,3,4,100-100000 (0=off, 1=dynamic, 3=dynamic conservative,
+ 4=simplified balancing)
+Default Value: 3
+
+The driver can limit the amount of interrupts per second that the adapter
+will generate for incoming packets. It does this by writing a value to the
+adapter that is based on the maximum amount of interrupts that the adapter
+will generate per second.
+
+Setting InterruptThrottleRate to a value greater or equal to 100
+will program the adapter to send out a maximum of that many interrupts
+per second, even if more packets have come in. This reduces interrupt
+load on the system and can lower CPU utilization under heavy load,
+but will increase latency as packets are not processed as quickly.
+
+The driver has two adaptive modes (setting 1 or 3) in which
+it dynamically adjusts the InterruptThrottleRate value based on the traffic
+that it receives. After determining the type of incoming traffic in the last
+timeframe, it will adjust the InterruptThrottleRate to an appropriate value
+for that traffic.
+
+The algorithm classifies the incoming traffic every interval into
+classes. Once the class is determined, the InterruptThrottleRate value is
+adjusted to suit that traffic type the best. There are three classes defined:
+"Bulk traffic", for large amounts of packets of normal size; "Low latency",
+for small amounts of traffic and/or a significant percentage of small
+packets; and "Lowest latency", for almost completely small packets or
+minimal traffic.
+
+In dynamic conservative mode, the InterruptThrottleRate value is set to 4000
+for traffic that falls in class "Bulk traffic". If traffic falls in the "Low
+latency" or "Lowest latency" class, the InterruptThrottleRate is increased
+stepwise to 20000. This default mode is suitable for most applications.
+
+For situations where low latency is vital such as cluster or
+grid computing, the algorithm can reduce latency even more when
+InterruptThrottleRate is set to mode 1. In this mode, which operates
+the same as mode 3, the InterruptThrottleRate will be increased stepwise to
+70000 for traffic in class "Lowest latency".
+
+In simplified mode the interrupt rate is based on the ratio of Tx and
+Rx traffic. If the bytes per second rate is approximately equal the
+interrupt rate will drop as low as 2000 interrupts per second. If the
+traffic is mostly transmit or mostly receive, the interrupt rate could
+be as high as 8000.
+
+Setting InterruptThrottleRate to 0 turns off any interrupt moderation
+and may improve small packet latency, but is generally not suitable
+for bulk throughput traffic.
+
+NOTE: InterruptThrottleRate takes precedence over the TxAbsIntDelay and
+ RxAbsIntDelay parameters. In other words, minimizing the receive
+ and/or transmit absolute delays does not force the controller to
+ generate more interrupts than what the Interrupt Throttle Rate
+ allows.
+
+NOTE: When e1000e is loaded with default settings and multiple adapters
+ are in use simultaneously, the CPU utilization may increase non-
+ linearly. In order to limit the CPU utilization without impacting
+ the overall throughput, we recommend that you load the driver as
+ follows:
+
+ modprobe e1000e InterruptThrottleRate=3000,3000,3000
+
+ This sets the InterruptThrottleRate to 3000 interrupts/sec for
+ the first, second, and third instances of the driver. The range
+ of 2000 to 3000 interrupts per second works on a majority of
+ systems and is a good starting point, but the optimal value will
+ be platform-specific. If CPU utilization is not a concern, use
+ RX_POLLING (NAPI) and default driver settings.
+
+RxIntDelay
+----------
+Valid Range: 0-65535 (0=off)
+Default Value: 0
+
+This value delays the generation of receive interrupts in units of 1.024
+microseconds. Receive interrupt reduction can improve CPU efficiency if
+properly tuned for specific network traffic. Increasing this value adds
+extra latency to frame reception and can end up decreasing the throughput
+of TCP traffic. If the system is reporting dropped receives, this value
+may be set too high, causing the driver to run out of available receive
+descriptors.
+
+CAUTION: When setting RxIntDelay to a value other than 0, adapters may
+ hang (stop transmitting) under certain network conditions. If
+ this occurs a NETDEV WATCHDOG message is logged in the system
+ event log. In addition, the controller is automatically reset,
+ restoring the network connection. To eliminate the potential
+ for the hang ensure that RxIntDelay is set to 0.
+
+RxAbsIntDelay
+-------------
+Valid Range: 0-65535 (0=off)
+Default Value: 8
+
+This value, in units of 1.024 microseconds, limits the delay in which a
+receive interrupt is generated. Useful only if RxIntDelay is non-zero,
+this value ensures that an interrupt is generated after the initial
+packet is received within the set amount of time. Proper tuning,
+along with RxIntDelay, may improve traffic throughput in specific network
+conditions.
+
+TxIntDelay
+----------
+Valid Range: 0-65535 (0=off)
+Default Value: 8
+
+This value delays the generation of transmit interrupts in units of
+1.024 microseconds. Transmit interrupt reduction can improve CPU
+efficiency if properly tuned for specific network traffic. If the
+system is reporting dropped transmits, this value may be set too high
+causing the driver to run out of available transmit descriptors.
+
+TxAbsIntDelay
+-------------
+Valid Range: 0-65535 (0=off)
+Default Value: 32
+
+This value, in units of 1.024 microseconds, limits the delay in which a
+transmit interrupt is generated. Useful only if TxIntDelay is non-zero,
+this value ensures that an interrupt is generated after the initial
+packet is sent on the wire within the set amount of time. Proper tuning,
+along with TxIntDelay, may improve traffic throughput in specific
+network conditions.
+
+Copybreak
+---------
+Valid Range: 0-xxxxxxx (0=off)
+Default Value: 256
+
+Driver copies all packets below or equaling this size to a fresh Rx
+buffer before handing it up the stack.
+
+This parameter is different than other parameters, in that it is a
+single (not 1,1,1 etc.) parameter applied to all driver instances and
+it is also available during runtime at
+/sys/module/e1000e/parameters/copybreak
+
+SmartPowerDownEnable
+--------------------
+Valid Range: 0-1
+Default Value: 0 (disabled)
+
+Allows PHY to turn off in lower power states. The user can set this parameter
+in supported chipsets.
+
+KumeranLockLoss
+---------------
+Valid Range: 0-1
+Default Value: 1 (enabled)
+
+This workaround skips resetting the PHY at shutdown for the initial
+silicon releases of ICH8 systems.
+
+IntMode
+-------
+Valid Range: 0-2 (0=legacy, 1=MSI, 2=MSI-X)
+Default Value: 2
+
+Allows changing the interrupt mode at module load time, without requiring a
+recompile. If the driver load fails to enable a specific interrupt mode, the
+driver will try other interrupt modes, from least to most compatible. The
+interrupt order is MSI-X, MSI, Legacy. If specifying MSI (IntMode=1)
+interrupts, only MSI and Legacy will be attempted.
+
+CrcStripping
+------------
+Valid Range: 0-1
+Default Value: 1 (enabled)
+
+Strip the CRC from received packets before sending up the network stack. If
+you have a machine with a BMC enabled but cannot receive IPMI traffic after
+loading or enabling the driver, try disabling this feature.
+
+WriteProtectNVM
+---------------
+Valid Range: 0-1
+Default Value: 1 (enabled)
+
+Set the hardware to ignore all write/erase cycles to the GbE region in the
+ICHx NVM (non-volatile memory). This feature can be disabled by the
+WriteProtectNVM module parameter (enabled by default) only after a hardware
+reset, but the machine must be power cycled before trying to enable writes.
+
+Note: the kernel boot option iomem=relaxed may need to be set if the kernel
+config option CONFIG_STRICT_DEVMEM=y, if the root user wants to write the
+NVM from user space via ethtool.
+
+Additional Configurations
+=========================
+
+ Jumbo Frames
+ ------------
+ Jumbo Frames support is enabled by changing the MTU to a value larger than
+ the default of 1500. Use the ifconfig command to increase the MTU size.
+ For example:
+
+ ifconfig eth<x> mtu 9000 up
+
+ This setting is not saved across reboots.
+
+ Notes:
+
+ - The maximum MTU setting for Jumbo Frames is 9216. This value coincides
+ with the maximum Jumbo Frames size of 9234 bytes.
+
+ - Using Jumbo Frames at 10 or 100 Mbps is not supported and may result in
+ poor performance or loss of link.
+
+ - Some adapters limit Jumbo Frames sized packets to a maximum of
+ 4096 bytes and some adapters do not support Jumbo Frames.
+
+
+ Ethtool
+ -------
+ The driver utilizes the ethtool interface for driver configuration and
+ diagnostics, as well as displaying statistical information. We
+ strongly recommend downloading the latest version of Ethtool at:
+
+ http://sourceforge.net/projects/gkernel.
+
+ Speed and Duplex
+ ----------------
+ Speed and Duplex are configured through the Ethtool* utility. For
+ instructions, refer to the Ethtool man page.
+
+ Enabling Wake on LAN* (WoL)
+ ---------------------------
+ WoL is configured through the Ethtool* utility. For instructions on
+ enabling WoL with Ethtool, refer to the Ethtool man page.
+
+ WoL will be enabled on the system during the next shut down or reboot.
+ For this driver version, in order to enable WoL, the e1000e driver must be
+ loaded when shutting down or rebooting the system.
+
+ In most cases Wake On LAN is only supported on port A for multiple port
+ adapters. To verify if a port supports Wake on LAN run ethtool eth<X>.
+
+
+Support
+=======
+
+For general information, go to the Intel support website at:
+
+ www.intel.com/support/
+
+or the Intel Wired Networking project hosted by Sourceforge at:
+
+ http://sourceforge.net/projects/e1000
+
+If an issue is identified with the released source code on the supported
+kernel with a supported adapter, email the specific information related
+to the issue to e1000-devel@lists.sf.net
diff --git a/Documentation/networking/ixgbevf.txt b/Documentation/networking/ixgbevf.txt
old mode 100755
new mode 100644
index 19015de..21dd5d1
--- a/Documentation/networking/ixgbevf.txt
+++ b/Documentation/networking/ixgbevf.txt
@@ -1,19 +1,16 @@
Linux* Base Driver for Intel(R) Network Connection
==================================================
-November 24, 2009
+Intel Gigabit Linux driver.
+Copyright(c) 1999 - 2010 Intel Corporation.
Contents
========
-- In This Release
- Identifying Your Adapter
- Known Issues/Troubleshooting
- Support
-In This Release
-===============
-
This file describes the ixgbevf Linux* Base Driver for Intel Network
Connection.
@@ -33,7 +30,7 @@
For more information on how to identify your adapter, go to the Adapter &
Driver ID Guide at:
- http://support.intel.com/support/network/sb/CS-008441.htm
+ http://support.intel.com/support/go/network/adapter/idguide.htm
Known Issues/Troubleshooting
============================
@@ -57,34 +54,3 @@
If an issue is identified with the released source code on the supported
kernel with a supported adapter, email the specific information related
to the issue to e1000-devel@lists.sf.net
-
-License
-=======
-
-Intel 10 Gigabit Linux driver.
-Copyright(c) 1999 - 2009 Intel Corporation.
-
-This program is free software; you can redistribute it and/or modify it
-under the terms and conditions of the GNU General Public License,
-version 2, as published by the Free Software Foundation.
-
-This program is distributed in the hope 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.,
-51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-The full GNU General Public License is included in this distribution in
-the file called "COPYING".
-
-Trademarks
-==========
-
-Intel, Itanium, and Pentium are trademarks or registered trademarks of
-Intel Corporation or its subsidiaries in the United States and other
-countries.
-
-* Other names and brands may be claimed as the property of others.
diff --git a/Documentation/power/regulator/overview.txt b/Documentation/power/regulator/overview.txt
index 9363e05..8ed1758 100644
--- a/Documentation/power/regulator/overview.txt
+++ b/Documentation/power/regulator/overview.txt
@@ -13,7 +13,7 @@
current limit is controllable).
(C) 2008 Wolfson Microelectronics PLC.
-Author: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Author: Liam Girdwood <lrg@slimlogic.co.uk>
Nomenclature
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 7f4dceb..d0eb696 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -300,6 +300,74 @@
control correctly. If you have problems regarding this, try
another ALSA compliant mixer (alsamixer works).
+ Module snd-azt1605
+ ------------------
+
+ Module for Aztech Sound Galaxy soundcards based on the Aztech AZT1605
+ chipset.
+
+ port - port # for BASE (0x220,0x240,0x260,0x280)
+ wss_port - port # for WSS (0x530,0x604,0xe80,0xf40)
+ irq - IRQ # for WSS (7,9,10,11)
+ dma1 - DMA # for WSS playback (0,1,3)
+ dma2 - DMA # for WSS capture (0,1), -1 = disabled (default)
+ mpu_port - port # for MPU-401 UART (0x300,0x330), -1 = disabled (default)
+ mpu_irq - IRQ # for MPU-401 UART (3,5,7,9), -1 = disabled (default)
+ fm_port - port # for OPL3 (0x388), -1 = disabled (default)
+
+ This module supports multiple cards. It does not support autoprobe: port,
+ wss_port, irq and dma1 have to be specified. The other values are
+ optional.
+
+ "port" needs to match the BASE ADDRESS jumper on the card (0x220 or 0x240)
+ or the value stored in the card's EEPROM for cards that have an EEPROM and
+ their "CONFIG MODE" jumper set to "EEPROM SETTING". The other values can
+ be choosen freely from the options enumerated above.
+
+ If dma2 is specified and different from dma1, the card will operate in
+ full-duplex mode. When dma1=3, only dma2=0 is valid and the only way to
+ enable capture since only channels 0 and 1 are available for capture.
+
+ Generic settings are "port=0x220 wss_port=0x530 irq=10 dma1=1 dma2=0
+ mpu_port=0x330 mpu_irq=9 fm_port=0x388".
+
+ Whatever IRQ and DMA channels you pick, be sure to reserve them for
+ legacy ISA in your BIOS.
+
+ Module snd-azt2316
+ ------------------
+
+ Module for Aztech Sound Galaxy soundcards based on the Aztech AZT2316
+ chipset.
+
+ port - port # for BASE (0x220,0x240,0x260,0x280)
+ wss_port - port # for WSS (0x530,0x604,0xe80,0xf40)
+ irq - IRQ # for WSS (7,9,10,11)
+ dma1 - DMA # for WSS playback (0,1,3)
+ dma2 - DMA # for WSS capture (0,1), -1 = disabled (default)
+ mpu_port - port # for MPU-401 UART (0x300,0x330), -1 = disabled (default)
+ mpu_irq - IRQ # for MPU-401 UART (5,7,9,10), -1 = disabled (default)
+ fm_port - port # for OPL3 (0x388), -1 = disabled (default)
+
+ This module supports multiple cards. It does not support autoprobe: port,
+ wss_port, irq and dma1 have to be specified. The other values are
+ optional.
+
+ "port" needs to match the BASE ADDRESS jumper on the card (0x220 or 0x240)
+ or the value stored in the card's EEPROM for cards that have an EEPROM and
+ their "CONFIG MODE" jumper set to "EEPROM SETTING". The other values can
+ be choosen freely from the options enumerated above.
+
+ If dma2 is specified and different from dma1, the card will operate in
+ full-duplex mode. When dma1=3, only dma2=0 is valid and the only way to
+ enable capture since only channels 0 and 1 are available for capture.
+
+ Generic settings are "port=0x220 wss_port=0x530 irq=10 dma1=1 dma2=0
+ mpu_port=0x330 mpu_irq=9 fm_port=0x388".
+
+ Whatever IRQ and DMA channels you pick, be sure to reserve them for
+ legacy ISA in your BIOS.
+
Module snd-aw2
--------------
@@ -1641,20 +1709,6 @@
This card is also known as Audio Excel DSP 16 or Zoltrix AV302.
- Module snd-sgalaxy
- ------------------
-
- Module for Aztech Sound Galaxy sound card.
-
- sbport - Port # for SB16 interface (0x220,0x240)
- wssport - Port # for WSS interface (0x530,0xe80,0xf40,0x604)
- irq - IRQ # (7,9,10,11)
- dma1 - DMA #
-
- This module supports multiple cards.
-
- The power-management is supported.
-
Module snd-sscape
-----------------
diff --git a/Documentation/vm/page-types.c b/Documentation/vm/page-types.c
index ccd951f..cc96ee2 100644
--- a/Documentation/vm/page-types.c
+++ b/Documentation/vm/page-types.c
@@ -478,7 +478,7 @@
}
if (opt_unpoison && !hwpoison_forget_fd) {
- sprintf(buf, "%s/renew-pfn", hwpoison_debug_fs);
+ sprintf(buf, "%s/unpoison-pfn", hwpoison_debug_fs);
hwpoison_forget_fd = checked_open(buf, O_WRONLY);
}
}
diff --git a/Documentation/workqueue.txt b/Documentation/workqueue.txt
new file mode 100644
index 0000000..e4498a2
--- /dev/null
+++ b/Documentation/workqueue.txt
@@ -0,0 +1,380 @@
+
+Concurrency Managed Workqueue (cmwq)
+
+September, 2010 Tejun Heo <tj@kernel.org>
+ Florian Mickler <florian@mickler.org>
+
+CONTENTS
+
+1. Introduction
+2. Why cmwq?
+3. The Design
+4. Application Programming Interface (API)
+5. Example Execution Scenarios
+6. Guidelines
+
+
+1. Introduction
+
+There are many cases where an asynchronous process execution context
+is needed and the workqueue (wq) API is the most commonly used
+mechanism for such cases.
+
+When such an asynchronous execution context is needed, a work item
+describing which function to execute is put on a queue. An
+independent thread serves as the asynchronous execution context. The
+queue is called workqueue and the thread is called worker.
+
+While there are work items on the workqueue the worker executes the
+functions associated with the work items one after the other. When
+there is no work item left on the workqueue the worker becomes idle.
+When a new work item gets queued, the worker begins executing again.
+
+
+2. Why cmwq?
+
+In the original wq implementation, a multi threaded (MT) wq had one
+worker thread per CPU and a single threaded (ST) wq had one worker
+thread system-wide. A single MT wq needed to keep around the same
+number of workers as the number of CPUs. The kernel grew a lot of MT
+wq users over the years and with the number of CPU cores continuously
+rising, some systems saturated the default 32k PID space just booting
+up.
+
+Although MT wq wasted a lot of resource, the level of concurrency
+provided was unsatisfactory. The limitation was common to both ST and
+MT wq albeit less severe on MT. Each wq maintained its own separate
+worker pool. A MT wq could provide only one execution context per CPU
+while a ST wq one for the whole system. Work items had to compete for
+those very limited execution contexts leading to various problems
+including proneness to deadlocks around the single execution context.
+
+The tension between the provided level of concurrency and resource
+usage also forced its users to make unnecessary tradeoffs like libata
+choosing to use ST wq for polling PIOs and accepting an unnecessary
+limitation that no two polling PIOs can progress at the same time. As
+MT wq don't provide much better concurrency, users which require
+higher level of concurrency, like async or fscache, had to implement
+their own thread pool.
+
+Concurrency Managed Workqueue (cmwq) is a reimplementation of wq with
+focus on the following goals.
+
+* Maintain compatibility with the original workqueue API.
+
+* Use per-CPU unified worker pools shared by all wq to provide
+ flexible level of concurrency on demand without wasting a lot of
+ resource.
+
+* Automatically regulate worker pool and level of concurrency so that
+ the API users don't need to worry about such details.
+
+
+3. The Design
+
+In order to ease the asynchronous execution of functions a new
+abstraction, the work item, is introduced.
+
+A work item is a simple struct that holds a pointer to the function
+that is to be executed asynchronously. Whenever a driver or subsystem
+wants a function to be executed asynchronously it has to set up a work
+item pointing to that function and queue that work item on a
+workqueue.
+
+Special purpose threads, called worker threads, execute the functions
+off of the queue, one after the other. If no work is queued, the
+worker threads become idle. These worker threads are managed in so
+called thread-pools.
+
+The cmwq design differentiates between the user-facing workqueues that
+subsystems and drivers queue work items on and the backend mechanism
+which manages thread-pool and processes the queued work items.
+
+The backend is called gcwq. There is one gcwq for each possible CPU
+and one gcwq to serve work items queued on unbound workqueues.
+
+Subsystems and drivers can create and queue work items through special
+workqueue API functions as they see fit. They can influence some
+aspects of the way the work items are executed by setting flags on the
+workqueue they are putting the work item on. These flags include
+things like CPU locality, reentrancy, concurrency limits and more. To
+get a detailed overview refer to the API description of
+alloc_workqueue() below.
+
+When a work item is queued to a workqueue, the target gcwq is
+determined according to the queue parameters and workqueue attributes
+and appended on the shared worklist of the gcwq. For example, unless
+specifically overridden, a work item of a bound workqueue will be
+queued on the worklist of exactly that gcwq that is associated to the
+CPU the issuer is running on.
+
+For any worker pool implementation, managing the concurrency level
+(how many execution contexts are active) is an important issue. cmwq
+tries to keep the concurrency at a minimal but sufficient level.
+Minimal to save resources and sufficient in that the system is used at
+its full capacity.
+
+Each gcwq bound to an actual CPU implements concurrency management by
+hooking into the scheduler. The gcwq is notified whenever an active
+worker wakes up or sleeps and keeps track of the number of the
+currently runnable workers. Generally, work items are not expected to
+hog a CPU and consume many cycles. That means maintaining just enough
+concurrency to prevent work processing from stalling should be
+optimal. As long as there are one or more runnable workers on the
+CPU, the gcwq doesn't start execution of a new work, but, when the
+last running worker goes to sleep, it immediately schedules a new
+worker so that the CPU doesn't sit idle while there are pending work
+items. This allows using a minimal number of workers without losing
+execution bandwidth.
+
+Keeping idle workers around doesn't cost other than the memory space
+for kthreads, so cmwq holds onto idle ones for a while before killing
+them.
+
+For an unbound wq, the above concurrency management doesn't apply and
+the gcwq for the pseudo unbound CPU tries to start executing all work
+items as soon as possible. The responsibility of regulating
+concurrency level is on the users. There is also a flag to mark a
+bound wq to ignore the concurrency management. Please refer to the
+API section for details.
+
+Forward progress guarantee relies on that workers can be created when
+more execution contexts are necessary, which in turn is guaranteed
+through the use of rescue workers. All work items which might be used
+on code paths that handle memory reclaim are required to be queued on
+wq's that have a rescue-worker reserved for execution under memory
+pressure. Else it is possible that the thread-pool deadlocks waiting
+for execution contexts to free up.
+
+
+4. Application Programming Interface (API)
+
+alloc_workqueue() allocates a wq. The original create_*workqueue()
+functions are deprecated and scheduled for removal. alloc_workqueue()
+takes three arguments - @name, @flags and @max_active. @name is the
+name of the wq and also used as the name of the rescuer thread if
+there is one.
+
+A wq no longer manages execution resources but serves as a domain for
+forward progress guarantee, flush and work item attributes. @flags
+and @max_active control how work items are assigned execution
+resources, scheduled and executed.
+
+@flags:
+
+ WQ_NON_REENTRANT
+
+ By default, a wq guarantees non-reentrance only on the same
+ CPU. A work item may not be executed concurrently on the same
+ CPU by multiple workers but is allowed to be executed
+ concurrently on multiple CPUs. This flag makes sure
+ non-reentrance is enforced across all CPUs. Work items queued
+ to a non-reentrant wq are guaranteed to be executed by at most
+ one worker system-wide at any given time.
+
+ WQ_UNBOUND
+
+ Work items queued to an unbound wq are served by a special
+ gcwq which hosts workers which are not bound to any specific
+ CPU. This makes the wq behave as a simple execution context
+ provider without concurrency management. The unbound gcwq
+ tries to start execution of work items as soon as possible.
+ Unbound wq sacrifices locality but is useful for the following
+ cases.
+
+ * Wide fluctuation in the concurrency level requirement is
+ expected and using bound wq may end up creating large number
+ of mostly unused workers across different CPUs as the issuer
+ hops through different CPUs.
+
+ * Long running CPU intensive workloads which can be better
+ managed by the system scheduler.
+
+ WQ_FREEZEABLE
+
+ A freezeable wq participates in the freeze phase of the system
+ suspend operations. Work items on the wq are drained and no
+ new work item starts execution until thawed.
+
+ WQ_RESCUER
+
+ All wq which might be used in the memory reclaim paths _MUST_
+ have this flag set. This reserves one worker exclusively for
+ the execution of this wq under memory pressure.
+
+ WQ_HIGHPRI
+
+ Work items of a highpri wq are queued at the head of the
+ worklist of the target gcwq and start execution regardless of
+ the current concurrency level. In other words, highpri work
+ items will always start execution as soon as execution
+ resource is available.
+
+ Ordering among highpri work items is preserved - a highpri
+ work item queued after another highpri work item will start
+ execution after the earlier highpri work item starts.
+
+ Although highpri work items are not held back by other
+ runnable work items, they still contribute to the concurrency
+ level. Highpri work items in runnable state will prevent
+ non-highpri work items from starting execution.
+
+ This flag is meaningless for unbound wq.
+
+ WQ_CPU_INTENSIVE
+
+ Work items of a CPU intensive wq do not contribute to the
+ concurrency level. In other words, runnable CPU intensive
+ work items will not prevent other work items from starting
+ execution. This is useful for bound work items which are
+ expected to hog CPU cycles so that their execution is
+ regulated by the system scheduler.
+
+ Although CPU intensive work items don't contribute to the
+ concurrency level, start of their executions is still
+ regulated by the concurrency management and runnable
+ non-CPU-intensive work items can delay execution of CPU
+ intensive work items.
+
+ This flag is meaningless for unbound wq.
+
+ WQ_HIGHPRI | WQ_CPU_INTENSIVE
+
+ This combination makes the wq avoid interaction with
+ concurrency management completely and behave as a simple
+ per-CPU execution context provider. Work items queued on a
+ highpri CPU-intensive wq start execution as soon as resources
+ are available and don't affect execution of other work items.
+
+@max_active:
+
+@max_active determines the maximum number of execution contexts per
+CPU which can be assigned to the work items of a wq. For example,
+with @max_active of 16, at most 16 work items of the wq can be
+executing at the same time per CPU.
+
+Currently, for a bound wq, the maximum limit for @max_active is 512
+and the default value used when 0 is specified is 256. For an unbound
+wq, the limit is higher of 512 and 4 * num_possible_cpus(). These
+values are chosen sufficiently high such that they are not the
+limiting factor while providing protection in runaway cases.
+
+The number of active work items of a wq is usually regulated by the
+users of the wq, more specifically, by how many work items the users
+may queue at the same time. Unless there is a specific need for
+throttling the number of active work items, specifying '0' is
+recommended.
+
+Some users depend on the strict execution ordering of ST wq. The
+combination of @max_active of 1 and WQ_UNBOUND is used to achieve this
+behavior. Work items on such wq are always queued to the unbound gcwq
+and only one work item can be active at any given time thus achieving
+the same ordering property as ST wq.
+
+
+5. Example Execution Scenarios
+
+The following example execution scenarios try to illustrate how cmwq
+behave under different configurations.
+
+ Work items w0, w1, w2 are queued to a bound wq q0 on the same CPU.
+ w0 burns CPU for 5ms then sleeps for 10ms then burns CPU for 5ms
+ again before finishing. w1 and w2 burn CPU for 5ms then sleep for
+ 10ms.
+
+Ignoring all other tasks, works and processing overhead, and assuming
+simple FIFO scheduling, the following is one highly simplified version
+of possible sequences of events with the original wq.
+
+ TIME IN MSECS EVENT
+ 0 w0 starts and burns CPU
+ 5 w0 sleeps
+ 15 w0 wakes up and burns CPU
+ 20 w0 finishes
+ 20 w1 starts and burns CPU
+ 25 w1 sleeps
+ 35 w1 wakes up and finishes
+ 35 w2 starts and burns CPU
+ 40 w2 sleeps
+ 50 w2 wakes up and finishes
+
+And with cmwq with @max_active >= 3,
+
+ TIME IN MSECS EVENT
+ 0 w0 starts and burns CPU
+ 5 w0 sleeps
+ 5 w1 starts and burns CPU
+ 10 w1 sleeps
+ 10 w2 starts and burns CPU
+ 15 w2 sleeps
+ 15 w0 wakes up and burns CPU
+ 20 w0 finishes
+ 20 w1 wakes up and finishes
+ 25 w2 wakes up and finishes
+
+If @max_active == 2,
+
+ TIME IN MSECS EVENT
+ 0 w0 starts and burns CPU
+ 5 w0 sleeps
+ 5 w1 starts and burns CPU
+ 10 w1 sleeps
+ 15 w0 wakes up and burns CPU
+ 20 w0 finishes
+ 20 w1 wakes up and finishes
+ 20 w2 starts and burns CPU
+ 25 w2 sleeps
+ 35 w2 wakes up and finishes
+
+Now, let's assume w1 and w2 are queued to a different wq q1 which has
+WQ_HIGHPRI set,
+
+ TIME IN MSECS EVENT
+ 0 w1 and w2 start and burn CPU
+ 5 w1 sleeps
+ 10 w2 sleeps
+ 10 w0 starts and burns CPU
+ 15 w0 sleeps
+ 15 w1 wakes up and finishes
+ 20 w2 wakes up and finishes
+ 25 w0 wakes up and burns CPU
+ 30 w0 finishes
+
+If q1 has WQ_CPU_INTENSIVE set,
+
+ TIME IN MSECS EVENT
+ 0 w0 starts and burns CPU
+ 5 w0 sleeps
+ 5 w1 and w2 start and burn CPU
+ 10 w1 sleeps
+ 15 w2 sleeps
+ 15 w0 wakes up and burns CPU
+ 20 w0 finishes
+ 20 w1 wakes up and finishes
+ 25 w2 wakes up and finishes
+
+
+6. Guidelines
+
+* Do not forget to use WQ_RESCUER if a wq may process work items which
+ are used during memory reclaim. Each wq with WQ_RESCUER set has one
+ rescuer thread reserved for it. If there is dependency among
+ multiple work items used during memory reclaim, they should be
+ queued to separate wq each with WQ_RESCUER.
+
+* Unless strict ordering is required, there is no need to use ST wq.
+
+* Unless there is a specific need, using 0 for @max_active is
+ recommended. In most use cases, concurrency level usually stays
+ well under the default limit.
+
+* A wq serves as a domain for forward progress guarantee (WQ_RESCUER),
+ flush and work item attributes. Work items which are not involved
+ in memory reclaim and don't need to be flushed as a part of a group
+ of work items, and don't require any special attribute, can use one
+ of the system wq. There is no difference in execution
+ characteristics between using a dedicated wq and a system wq.
+
+* Unless work items are expected to consume a huge amount of CPU
+ cycles, using a bound wq is usually beneficial due to the increased
+ level of locality in wq operations and work item execution.
diff --git a/MAINTAINERS b/MAINTAINERS
index e7c528f..f2a2b8e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -962,6 +962,23 @@
S: Maintained
F: arch/arm/mach-s3c6410/
+ARM/S5P ARM ARCHITECTURES
+M: Kukjin Kim <kgene.kim@samsung.com>
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
+S: Maintained
+F: arch/arm/mach-s5p*/
+
+ARM/SAMSUNG S5P SERIES FIMC SUPPORT
+M: Kyungmin Park <kyungmin.park@samsung.com>
+M: Sylwester Nawrocki <s.nawrocki@samsung.com>
+L: linux-arm-kernel@lists.infradead.org
+L: linux-media@vger.kernel.org
+S: Maintained
+F: arch/arm/plat-s5p/dev-fimc*
+F: arch/arm/plat-samsung/include/plat/*fimc*
+F: drivers/media/video/s5p-fimc/
+
ARM/SHMOBILE ARM ARCHITECTURE
M: Paul Mundt <lethal@linux-sh.org>
M: Magnus Damm <magnus.damm@gmail.com>
@@ -1135,7 +1152,7 @@
M: Jay Cliburn <jcliburn@gmail.com>
M: Chris Snook <chris.snook@gmail.com>
M: Jie Yang <jie.yang@atheros.com>
-L: atl1-devel@lists.sourceforge.net
+L: netdev@vger.kernel.org
W: http://sourceforge.net/projects/atl1
W: http://atl1.sourceforge.net
S: Maintained
@@ -1220,7 +1237,7 @@
F: include/linux/cfag12864b.h
AVR32 ARCHITECTURE
-M: Haavard Skinnemoen <hskinnemoen@atmel.com>
+M: Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>
W: http://www.atmel.com/products/AVR32/
W: http://avr32linux.org/
W: http://avrfreaks.net/
@@ -1228,7 +1245,7 @@
F: arch/avr32/
AVR32/AT32AP MACHINE SUPPORT
-M: Haavard Skinnemoen <hskinnemoen@atmel.com>
+M: Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>
S: Supported
F: arch/avr32/mach-at32ap/
@@ -2199,6 +2216,12 @@
S: Maintained
F: drivers/platform/x86/eeepc-laptop.c
+EFIFB FRAMEBUFFER DRIVER
+L: linux-fbdev@vger.kernel.org
+M: Peter Jones <pjones@redhat.com>
+S: Maintained
+F: drivers/video/efifb.c
+
EFS FILESYSTEM
W: http://aeschi.ch.eu.org/efs/
S: Orphan
@@ -2522,7 +2545,7 @@
F: drivers/scsi/gdt*
GENERIC GPIO I2C DRIVER
-M: Haavard Skinnemoen <hskinnemoen@atmel.com>
+M: Haavard Skinnemoen <hskinnemoen@gmail.com>
S: Supported
F: drivers/i2c/busses/i2c-gpio.c
F: include/linux/i2c-gpio.h
@@ -2657,9 +2680,14 @@
F: drivers/media/video/gspca/
HARDWARE MONITORING
+M: Jean Delvare <khali@linux-fr.org>
+M: Guenter Roeck <guenter.roeck@ericsson.com>
L: lm-sensors@lm-sensors.org
W: http://www.lm-sensors.org/
-S: Orphan
+T: quilt kernel.org/pub/linux/kernel/people/jdelvare/linux-2.6/jdelvare-hwmon/
+T: quilt kernel.org/pub/linux/kernel/people/groeck/linux-staging/
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
+S: Maintained
F: Documentation/hwmon/
F: drivers/hwmon/
F: include/linux/hwmon*.h
@@ -3045,16 +3073,27 @@
S: Maintained
F: drivers/net/ixp2000/
-INTEL ETHERNET DRIVERS (e100/e1000/e1000e/igb/igbvf/ixgb/ixgbe)
+INTEL ETHERNET DRIVERS (e100/e1000/e1000e/igb/igbvf/ixgb/ixgbe/ixgbevf)
M: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
M: Jesse Brandeburg <jesse.brandeburg@intel.com>
M: Bruce Allan <bruce.w.allan@intel.com>
-M: Alex Duyck <alexander.h.duyck@intel.com>
+M: Carolyn Wyborny <carolyn.wyborny@intel.com>
+M: Don Skidmore <donald.c.skidmore@intel.com>
+M: Greg Rose <gregory.v.rose@intel.com>
M: PJ Waskiewicz <peter.p.waskiewicz.jr@intel.com>
+M: Alex Duyck <alexander.h.duyck@intel.com>
M: John Ronciak <john.ronciak@intel.com>
L: e1000-devel@lists.sourceforge.net
W: http://e1000.sourceforge.net/
S: Supported
+F: Documentation/networking/e100.txt
+F: Documentation/networking/e1000.txt
+F: Documentation/networking/e1000e.txt
+F: Documentation/networking/igb.txt
+F: Documentation/networking/igbvf.txt
+F: Documentation/networking/ixgb.txt
+F: Documentation/networking/ixgbe.txt
+F: Documentation/networking/ixgbevf.txt
F: drivers/net/e100.c
F: drivers/net/e1000/
F: drivers/net/e1000e/
@@ -3062,6 +3101,7 @@
F: drivers/net/igbvf/
F: drivers/net/ixgb/
F: drivers/net/ixgbe/
+F: drivers/net/ixgbevf/
INTEL PRO/WIRELESS 2100 NETWORK CONNECTION SUPPORT
L: linux-wireless@vger.kernel.org
@@ -3122,7 +3162,7 @@
IOC3 SERIAL DRIVER
M: Pat Gefre <pfg@sgi.com>
-L: linux-mips@linux-mips.org
+L: linux-serial@vger.kernel.org
S: Maintained
F: drivers/serial/ioc3_serial.c
@@ -3770,9 +3810,8 @@
S: Supported
MATROX FRAMEBUFFER DRIVER
-M: Petr Vandrovec <vandrove@vc.cvut.cz>
L: linux-fbdev@vger.kernel.org
-S: Maintained
+S: Orphan
F: drivers/video/matrox/matroxfb_*
F: include/linux/matroxfb.h
@@ -3896,10 +3935,8 @@
F: drivers/char/mxser.*
MSI LAPTOP SUPPORT
-M: Lennart Poettering <mzxreary@0pointer.de>
+M: Lee, Chun-Yi <jlee@novell.com>
L: platform-driver-x86@vger.kernel.org
-W: https://tango.0pointer.de/mailman/listinfo/s270-linux
-W: http://0pointer.de/lennart/tchibo.html
S: Maintained
F: drivers/platform/x86/msi-laptop.c
@@ -3916,8 +3953,10 @@
F: drivers/mfd/
MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
-S: Orphan
+M: Chris Ball <cjb@laptop.org>
L: linux-mmc@vger.kernel.org
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc.git
+S: Maintained
F: drivers/mmc/
F: include/linux/mmc/
@@ -3939,7 +3978,7 @@
F: include/linux/isicom.h
MUSB MULTIPOINT HIGH SPEED DUAL-ROLE CONTROLLER
-M: Felipe Balbi <felipe.balbi@nokia.com>
+M: Felipe Balbi <balbi@ti.com>
L: linux-usb@vger.kernel.org
T: git git://gitorious.org/usb/usb.git
S: Maintained
@@ -3959,8 +3998,8 @@
F: drivers/net/natsemi.c
NCP FILESYSTEM
-M: Petr Vandrovec <vandrove@vc.cvut.cz>
-S: Maintained
+M: Petr Vandrovec <petr@vandrovec.name>
+S: Odd Fixes
F: fs/ncpfs/
NCR DUAL 700 SCSI DRIVER (MICROCHANNEL)
@@ -4237,7 +4276,7 @@
F: drivers/char/hw_random/omap-rng.c
OMAP USB SUPPORT
-M: Felipe Balbi <felipe.balbi@nokia.com>
+M: Felipe Balbi <balbi@ti.com>
M: David Brownell <dbrownell@users.sourceforge.net>
L: linux-usb@vger.kernel.org
L: linux-omap@vger.kernel.org
@@ -4991,6 +5030,12 @@
F: drivers/media/video/*7146*
F: include/media/*7146*
+SAMSUNG AUDIO (ASoC) DRIVERS
+M: Jassi Brar <jassi.brar@samsung.com>
+L: alsa-devel@alsa-project.org (moderated for non-subscribers)
+S: Supported
+F: sound/soc/s3c24xx
+
TLG2300 VIDEO4LINUX-2 DRIVER
M: Huang Shijie <shijie8@gmail.com>
M: Kang Yong <kangyong@telegent.com>
@@ -5088,8 +5133,10 @@
F: drivers/mmc/host/sdricoh_cs.c
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) DRIVER
-S: Orphan
+M: Chris Ball <cjb@laptop.org>
L: linux-mmc@vger.kernel.org
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc.git
+S: Maintained
F: drivers/mmc/host/sdhci.*
SECURE DIGITAL HOST CONTROLLER INTERFACE, OPEN FIRMWARE BINDINGS (SDHCI-OF)
@@ -6431,8 +6478,10 @@
WOLFSON MICROELECTRONICS DRIVERS
M: Mark Brown <broonie@opensource.wolfsonmicro.com>
M: Ian Lartey <ian@opensource.wolfsonmicro.com>
+M: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+T: git git://opensource.wolfsonmicro.com/linux-2.6-asoc
T: git git://opensource.wolfsonmicro.com/linux-2.6-audioplus
-W: http://opensource.wolfsonmicro.com/node/8
+W: http://opensource.wolfsonmicro.com/content/linux-drivers-wolfson-devices
S: Supported
F: Documentation/hwmon/wm83??
F: drivers/leds/leds-wm83*.c
diff --git a/Makefile b/Makefile
index 92ab33f..860c26a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 36
-EXTRAVERSION = -rc4
-NAME = Sheep on Meth
+EXTRAVERSION =
+NAME = Flesh-Eating Bats with Fangs
# *DOCUMENTATION*
# To see a list of typical targets execute "make help"
diff --git a/arch/Kconfig b/arch/Kconfig
index 4877a8c..fe48fc7 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -32,8 +32,9 @@
config KPROBES
bool "Kprobes"
- depends on KALLSYMS && MODULES
+ depends on MODULES
depends on HAVE_KPROBES
+ select KALLSYMS
help
Kprobes allows you to trap at almost any kernel address and
execute a callback function. register_kprobe() establishes
@@ -45,7 +46,6 @@
def_bool y
depends on KPROBES && HAVE_OPTPROBES
depends on !PREEMPT
- select KALLSYMS_ALL
config HAVE_EFFICIENT_UNALIGNED_ACCESS
bool
diff --git a/arch/alpha/include/asm/cacheflush.h b/arch/alpha/include/asm/cacheflush.h
index 01d71e1..012f124 100644
--- a/arch/alpha/include/asm/cacheflush.h
+++ b/arch/alpha/include/asm/cacheflush.h
@@ -43,6 +43,8 @@
/* ??? Ought to use this in arch/alpha/kernel/signal.c too. */
#ifndef CONFIG_SMP
+#include <linux/sched.h>
+
extern void __load_new_mm_context(struct mm_struct *);
static inline void
flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
diff --git a/arch/alpha/include/asm/unistd.h b/arch/alpha/include/asm/unistd.h
index 804e531..058937b 100644
--- a/arch/alpha/include/asm/unistd.h
+++ b/arch/alpha/include/asm/unistd.h
@@ -449,10 +449,13 @@
#define __NR_pwritev 491
#define __NR_rt_tgsigqueueinfo 492
#define __NR_perf_event_open 493
+#define __NR_fanotify_init 494
+#define __NR_fanotify_mark 495
+#define __NR_prlimit64 496
#ifdef __KERNEL__
-#define NR_SYSCALLS 494
+#define NR_SYSCALLS 497
#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR
@@ -463,6 +466,7 @@
#define __ARCH_WANT_SYS_OLD_GETRLIMIT
#define __ARCH_WANT_SYS_OLDUMOUNT
#define __ARCH_WANT_SYS_SIGPENDING
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
/* "Conditional" syscalls. What we want is
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index b45d913..6d159ce 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -73,8 +73,6 @@
ldq $20, HAE_REG($19); \
stq $21, HAE_CACHE($19); \
stq $21, 0($20); \
- ldq $0, 0($sp); \
- ldq $1, 8($sp); \
99:; \
ldq $19, 72($sp); \
ldq $20, 80($sp); \
@@ -316,19 +314,24 @@
cmovne $26, 0, $19 /* $19 = 0 => non-restartable */
ldq $0, SP_OFF($sp)
and $0, 8, $0
- beq $0, restore_all
-ret_from_reschedule:
+ beq $0, ret_to_kernel
+ret_to_user:
/* Make sure need_resched and sigpending don't change between
sampling and the rti. */
lda $16, 7
call_pal PAL_swpipl
ldl $5, TI_FLAGS($8)
and $5, _TIF_WORK_MASK, $2
- bne $5, work_pending
+ bne $2, work_pending
restore_all:
RESTORE_ALL
call_pal PAL_rti
+ret_to_kernel:
+ lda $16, 7
+ call_pal PAL_swpipl
+ br restore_all
+
.align 3
$syscall_error:
/*
@@ -363,7 +366,7 @@
* $8: current.
* $19: The old syscall number, or zero if this is not a return
* from a syscall that errored and is possibly restartable.
- * $20: Error indication.
+ * $20: The old a3 value
*/
.align 4
@@ -392,12 +395,18 @@
$work_notifysig:
mov $sp, $16
- br $1, do_switch_stack
+ bsr $1, do_switch_stack
mov $sp, $17
mov $5, $18
+ mov $19, $9 /* save old syscall number */
+ mov $20, $10 /* save old a3 */
+ and $5, _TIF_SIGPENDING, $2
+ cmovne $2, 0, $9 /* we don't want double syscall restarts */
jsr $26, do_notify_resume
+ mov $9, $19
+ mov $10, $20
bsr $1, undo_switch_stack
- br restore_all
+ br ret_to_user
.end work_pending
/*
@@ -430,6 +439,7 @@
beq $1, 1f
ldq $27, 0($2)
1: jsr $26, ($27), sys_gettimeofday
+ret_from_straced:
ldgp $gp, 0($26)
/* check return.. */
@@ -650,7 +660,7 @@
/* We don't actually care for a3 success widgetry in the kernel.
Not for positive errno values. */
stq $0, 0($sp) /* $0 */
- br restore_all
+ br ret_to_kernel
.end kernel_thread
/*
@@ -757,11 +767,15 @@
.ent sys_sigreturn
sys_sigreturn:
.prologue 0
+ lda $9, ret_from_straced
+ cmpult $26, $9, $9
mov $sp, $17
lda $18, -SWITCH_STACK_SIZE($sp)
lda $sp, -SWITCH_STACK_SIZE($sp)
jsr $26, do_sigreturn
- br $1, undo_switch_stack
+ bne $9, 1f
+ jsr $26, syscall_trace
+1: br $1, undo_switch_stack
br ret_from_sys_call
.end sys_sigreturn
@@ -770,47 +784,19 @@
.ent sys_rt_sigreturn
sys_rt_sigreturn:
.prologue 0
+ lda $9, ret_from_straced
+ cmpult $26, $9, $9
mov $sp, $17
lda $18, -SWITCH_STACK_SIZE($sp)
lda $sp, -SWITCH_STACK_SIZE($sp)
jsr $26, do_rt_sigreturn
- br $1, undo_switch_stack
+ bne $9, 1f
+ jsr $26, syscall_trace
+1: br $1, undo_switch_stack
br ret_from_sys_call
.end sys_rt_sigreturn
.align 4
- .globl sys_sigsuspend
- .ent sys_sigsuspend
-sys_sigsuspend:
- .prologue 0
- mov $sp, $17
- br $1, do_switch_stack
- mov $sp, $18
- subq $sp, 16, $sp
- stq $26, 0($sp)
- jsr $26, do_sigsuspend
- ldq $26, 0($sp)
- lda $sp, SWITCH_STACK_SIZE+16($sp)
- ret
-.end sys_sigsuspend
-
- .align 4
- .globl sys_rt_sigsuspend
- .ent sys_rt_sigsuspend
-sys_rt_sigsuspend:
- .prologue 0
- mov $sp, $18
- br $1, do_switch_stack
- mov $sp, $19
- subq $sp, 16, $sp
- stq $26, 0($sp)
- jsr $26, do_rt_sigsuspend
- ldq $26, 0($sp)
- lda $sp, SWITCH_STACK_SIZE+16($sp)
- ret
-.end sys_rt_sigsuspend
-
- .align 4
.globl sys_sethae
.ent sys_sethae
sys_sethae:
@@ -929,15 +915,6 @@
.end sys_execve
.align 4
- .globl osf_sigprocmask
- .ent osf_sigprocmask
-osf_sigprocmask:
- .prologue 0
- mov $sp, $18
- jmp $31, sys_osf_sigprocmask
-.end osf_sigprocmask
-
- .align 4
.globl alpha_ni_syscall
.ent alpha_ni_syscall
alpha_ni_syscall:
diff --git a/arch/alpha/kernel/err_ev6.c b/arch/alpha/kernel/err_ev6.c
index 8ca6345..253cf1a 100644
--- a/arch/alpha/kernel/err_ev6.c
+++ b/arch/alpha/kernel/err_ev6.c
@@ -90,11 +90,13 @@
ev6_parse_cbox(u64 c_addr, u64 c1_syn, u64 c2_syn,
u64 c_stat, u64 c_sts, int print)
{
- char *sourcename[] = { "UNKNOWN", "UNKNOWN", "UNKNOWN",
- "MEMORY", "BCACHE", "DCACHE",
- "BCACHE PROBE", "BCACHE PROBE" };
- char *streamname[] = { "D", "I" };
- char *bitsname[] = { "SINGLE", "DOUBLE" };
+ static const char * const sourcename[] = {
+ "UNKNOWN", "UNKNOWN", "UNKNOWN",
+ "MEMORY", "BCACHE", "DCACHE",
+ "BCACHE PROBE", "BCACHE PROBE"
+ };
+ static const char * const streamname[] = { "D", "I" };
+ static const char * const bitsname[] = { "SINGLE", "DOUBLE" };
int status = MCHK_DISPOSITION_REPORT;
int source = -1, stream = -1, bits = -1;
diff --git a/arch/alpha/kernel/err_marvel.c b/arch/alpha/kernel/err_marvel.c
index 5c905aa..648ae88 100644
--- a/arch/alpha/kernel/err_marvel.c
+++ b/arch/alpha/kernel/err_marvel.c
@@ -589,22 +589,23 @@
static void
marvel_print_pox_trans_sum(u64 trans_sum)
{
- char *pcix_cmd[] = { "Interrupt Acknowledge",
- "Special Cycle",
- "I/O Read",
- "I/O Write",
- "Reserved",
- "Reserved / Device ID Message",
- "Memory Read",
- "Memory Write",
- "Reserved / Alias to Memory Read Block",
- "Reserved / Alias to Memory Write Block",
- "Configuration Read",
- "Configuration Write",
- "Memory Read Multiple / Split Completion",
- "Dual Address Cycle",
- "Memory Read Line / Memory Read Block",
- "Memory Write and Invalidate / Memory Write Block"
+ static const char * const pcix_cmd[] = {
+ "Interrupt Acknowledge",
+ "Special Cycle",
+ "I/O Read",
+ "I/O Write",
+ "Reserved",
+ "Reserved / Device ID Message",
+ "Memory Read",
+ "Memory Write",
+ "Reserved / Alias to Memory Read Block",
+ "Reserved / Alias to Memory Write Block",
+ "Configuration Read",
+ "Configuration Write",
+ "Memory Read Multiple / Split Completion",
+ "Dual Address Cycle",
+ "Memory Read Line / Memory Read Block",
+ "Memory Write and Invalidate / Memory Write Block"
};
#define IO7__POX_TRANSUM__PCI_ADDR__S (0)
diff --git a/arch/alpha/kernel/err_titan.c b/arch/alpha/kernel/err_titan.c
index f7ed97c..c3b3781 100644
--- a/arch/alpha/kernel/err_titan.c
+++ b/arch/alpha/kernel/err_titan.c
@@ -75,8 +75,12 @@
int status = MCHK_DISPOSITION_REPORT;
#ifdef CONFIG_VERBOSE_MCHECK
- char *serror_src[] = {"GPCI", "APCI", "AGP HP", "AGP LP"};
- char *serror_cmd[] = {"DMA Read", "DMA RMW", "SGTE Read", "Reserved"};
+ static const char * const serror_src[] = {
+ "GPCI", "APCI", "AGP HP", "AGP LP"
+ };
+ static const char * const serror_cmd[] = {
+ "DMA Read", "DMA RMW", "SGTE Read", "Reserved"
+ };
#endif /* CONFIG_VERBOSE_MCHECK */
#define TITAN__PCHIP_SERROR__LOST_UECC (1UL << 0)
@@ -140,14 +144,15 @@
int status = MCHK_DISPOSITION_REPORT;
#ifdef CONFIG_VERBOSE_MCHECK
- char *perror_cmd[] = { "Interrupt Acknowledge", "Special Cycle",
- "I/O Read", "I/O Write",
- "Reserved", "Reserved",
- "Memory Read", "Memory Write",
- "Reserved", "Reserved",
- "Configuration Read", "Configuration Write",
- "Memory Read Multiple", "Dual Address Cycle",
- "Memory Read Line","Memory Write and Invalidate"
+ static const char * const perror_cmd[] = {
+ "Interrupt Acknowledge", "Special Cycle",
+ "I/O Read", "I/O Write",
+ "Reserved", "Reserved",
+ "Memory Read", "Memory Write",
+ "Reserved", "Reserved",
+ "Configuration Read", "Configuration Write",
+ "Memory Read Multiple", "Dual Address Cycle",
+ "Memory Read Line", "Memory Write and Invalidate"
};
#endif /* CONFIG_VERBOSE_MCHECK */
@@ -273,11 +278,11 @@
int cmd, len;
unsigned long addr;
- char *agperror_cmd[] = { "Read (low-priority)", "Read (high-priority)",
- "Write (low-priority)",
- "Write (high-priority)",
- "Reserved", "Reserved",
- "Flush", "Fence"
+ static const char * const agperror_cmd[] = {
+ "Read (low-priority)", "Read (high-priority)",
+ "Write (low-priority)", "Write (high-priority)",
+ "Reserved", "Reserved",
+ "Flush", "Fence"
};
#endif /* CONFIG_VERBOSE_MCHECK */
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 5d1e6d6..547e8b8 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -15,7 +15,6 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/syscalls.h>
#include <linux/unistd.h>
@@ -69,7 +68,6 @@
{
struct mm_struct *mm;
- lock_kernel();
mm = current->mm;
mm->end_code = bss_start + bss_len;
mm->start_brk = bss_start + bss_len;
@@ -78,7 +76,6 @@
printk("set_program_attributes(%lx %lx %lx %lx)\n",
text_start, text_len, bss_start, bss_len);
#endif
- unlock_kernel();
return 0;
}
@@ -517,7 +514,6 @@
long error;
int __user *min_buf_size_ptr;
- lock_kernel();
switch (code) {
case PL_SET:
if (get_user(error, &args->set.nbytes))
@@ -547,7 +543,6 @@
error = -EOPNOTSUPP;
break;
};
- unlock_kernel();
return error;
}
@@ -594,7 +589,7 @@
SYSCALL_DEFINE3(osf_sysinfo, int, command, char __user *, buf, long, count)
{
- char *sysinfo_table[] = {
+ const char *sysinfo_table[] = {
utsname()->sysname,
utsname()->nodename,
utsname()->release,
@@ -606,7 +601,7 @@
"dummy", /* secure RPC domain */
};
unsigned long offset;
- char *res;
+ const char *res;
long len, err = -EINVAL;
offset = command-1;
diff --git a/arch/alpha/kernel/pci-sysfs.c b/arch/alpha/kernel/pci-sysfs.c
index 738fc82..b899e95 100644
--- a/arch/alpha/kernel/pci-sysfs.c
+++ b/arch/alpha/kernel/pci-sysfs.c
@@ -66,7 +66,7 @@
{
struct pci_dev *pdev = to_pci_dev(container_of(kobj,
struct device, kobj));
- struct resource *res = (struct resource *)attr->private;
+ struct resource *res = attr->private;
enum pci_mmap_state mmap_type;
struct pci_bus_region bar;
int i;
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index 842dba3..3ec3506 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -356,7 +356,7 @@
dest[27] = pt->r27;
dest[28] = pt->r28;
dest[29] = pt->gp;
- dest[30] = rdusp();
+ dest[30] = ti == current_thread_info() ? rdusp() : ti->pcb.usp;
dest[31] = pt->pc;
/* Once upon a time this was the PS value. Which is stupid
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index 0932dbb..6f7feb5 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -41,46 +41,20 @@
/*
* The OSF/1 sigprocmask calling sequence is different from the
* C sigprocmask() sequence..
- *
- * how:
- * 1 - SIG_BLOCK
- * 2 - SIG_UNBLOCK
- * 3 - SIG_SETMASK
- *
- * We change the range to -1 .. 1 in order to let gcc easily
- * use the conditional move instructions.
- *
- * Note that we don't need to acquire the kernel lock for SMP
- * operation, as all of this is local to this thread.
*/
-SYSCALL_DEFINE3(osf_sigprocmask, int, how, unsigned long, newmask,
- struct pt_regs *, regs)
+SYSCALL_DEFINE2(osf_sigprocmask, int, how, unsigned long, newmask)
{
- unsigned long oldmask = -EINVAL;
+ sigset_t oldmask;
+ sigset_t mask;
+ unsigned long res;
- if ((unsigned long)how-1 <= 2) {
- long sign = how-2; /* -1 .. 1 */
- unsigned long block, unblock;
-
- newmask &= _BLOCKABLE;
- spin_lock_irq(¤t->sighand->siglock);
- oldmask = current->blocked.sig[0];
-
- unblock = oldmask & ~newmask;
- block = oldmask | newmask;
- if (!sign)
- block = unblock;
- if (sign <= 0)
- newmask = block;
- if (_NSIG_WORDS > 1 && sign > 0)
- sigemptyset(¤t->blocked);
- current->blocked.sig[0] = newmask;
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
-
- regs->r0 = 0; /* special no error return */
+ siginitset(&mask, newmask & _BLOCKABLE);
+ res = sigprocmask(how, &mask, &oldmask);
+ if (!res) {
+ force_successful_syscall_return();
+ res = oldmask.sig[0];
}
- return oldmask;
+ return res;
}
SYSCALL_DEFINE3(osf_sigaction, int, sig,
@@ -94,9 +68,9 @@
old_sigset_t mask;
if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
__get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_flags, &act->sa_flags))
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
+ __get_user(mask, &act->sa_mask))
return -EFAULT;
- __get_user(mask, &act->sa_mask);
siginitset(&new_ka.sa.sa_mask, mask);
new_ka.ka_restorer = NULL;
}
@@ -106,9 +80,9 @@
if (!ret && oact) {
if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
__put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags))
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
return -EFAULT;
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
}
return ret;
@@ -144,8 +118,7 @@
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
-asmlinkage int
-do_sigsuspend(old_sigset_t mask, struct pt_regs *regs, struct switch_stack *sw)
+SYSCALL_DEFINE1(sigsuspend, old_sigset_t, mask)
{
mask &= _BLOCKABLE;
spin_lock_irq(¤t->sighand->siglock);
@@ -154,41 +127,6 @@
recalc_sigpending();
spin_unlock_irq(¤t->sighand->siglock);
- /* Indicate EINTR on return from any possible signal handler,
- which will not come back through here, but via sigreturn. */
- regs->r0 = EINTR;
- regs->r19 = 1;
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
- return -ERESTARTNOHAND;
-}
-
-asmlinkage int
-do_rt_sigsuspend(sigset_t __user *uset, size_t sigsetsize,
- struct pt_regs *regs, struct switch_stack *sw)
-{
- sigset_t set;
-
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(sigset_t))
- return -EINVAL;
- if (copy_from_user(&set, uset, sizeof(set)))
- return -EFAULT;
-
- sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(¤t->sighand->siglock);
- current->saved_sigmask = current->blocked;
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
-
- /* Indicate EINTR on return from any possible signal handler,
- which will not come back through here, but via sigreturn. */
- regs->r0 = EINTR;
- regs->r19 = 1;
-
current->state = TASK_INTERRUPTIBLE;
schedule();
set_thread_flag(TIF_RESTORE_SIGMASK);
@@ -239,6 +177,8 @@
unsigned long usp;
long i, err = __get_user(regs->pc, &sc->sc_pc);
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
sw->r26 = (unsigned long) ret_from_sys_call;
err |= __get_user(regs->r0, sc->sc_regs+0);
@@ -591,7 +531,6 @@
regs->pc -= 4;
break;
case ERESTART_RESTARTBLOCK:
- current_thread_info()->restart_block.fn = do_no_restart_syscall;
regs->r0 = EINTR;
break;
}
diff --git a/arch/alpha/kernel/srm_env.c b/arch/alpha/kernel/srm_env.c
index 4afc1a1..f0df3fb 100644
--- a/arch/alpha/kernel/srm_env.c
+++ b/arch/alpha/kernel/srm_env.c
@@ -87,7 +87,7 @@
srm_env_t *entry;
char *page;
- entry = (srm_env_t *)m->private;
+ entry = m->private;
page = (char *)__get_free_page(GFP_USER);
if (!page)
return -ENOMEM;
diff --git a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S
index 09acb78..a6a1de9 100644
--- a/arch/alpha/kernel/systbls.S
+++ b/arch/alpha/kernel/systbls.S
@@ -58,7 +58,7 @@
.quad sys_open /* 45 */
.quad alpha_ni_syscall
.quad sys_getxgid
- .quad osf_sigprocmask
+ .quad sys_osf_sigprocmask
.quad alpha_ni_syscall
.quad alpha_ni_syscall /* 50 */
.quad sys_acct
@@ -512,6 +512,9 @@
.quad sys_pwritev
.quad sys_rt_tgsigqueueinfo
.quad sys_perf_event_open
+ .quad sys_fanotify_init
+ .quad sys_fanotify_mark /* 495 */
+ .quad sys_prlimit64
.size sys_call_table, . - sys_call_table
.type sys_call_table, @object
diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c
index eacceb2..396af17 100644
--- a/arch/alpha/kernel/time.c
+++ b/arch/alpha/kernel/time.c
@@ -191,16 +191,16 @@
write_sequnlock(&xtime_lock);
-#ifndef CONFIG_SMP
- while (nticks--)
- update_process_times(user_mode(get_irq_regs()));
-#endif
-
if (test_perf_event_pending()) {
clear_perf_event_pending();
perf_event_do_pending();
}
+#ifndef CONFIG_SMP
+ while (nticks--)
+ update_process_times(user_mode(get_irq_regs()));
+#endif
+
return IRQ_HANDLED;
}
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
index b14f015..0414e02 100644
--- a/arch/alpha/kernel/traps.c
+++ b/arch/alpha/kernel/traps.c
@@ -13,7 +13,6 @@
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/delay.h>
-#include <linux/smp_lock.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kallsyms.h>
@@ -623,7 +622,6 @@
return;
}
- lock_kernel();
printk("Bad unaligned kernel access at %016lx: %p %lx %lu\n",
pc, va, opcode, reg);
do_exit(SIGSEGV);
@@ -646,7 +644,6 @@
* Yikes! No one to forward the exception to.
* Since the registers are in a weird format, dump them ourselves.
*/
- lock_kernel();
printk("%s(%d): unhandled unaligned exception\n",
current->comm, task_pid_nr(current));
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 553b7cf..9c26ba7 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -271,7 +271,6 @@
bool "Atmel AT91"
select ARCH_REQUIRE_GPIOLIB
select HAVE_CLK
- select ARCH_USES_GETTIMEOFFSET
help
This enables support for systems based on the Atmel AT91RM9200,
AT91SAM9 and AT91CAP9 processors.
@@ -1051,6 +1050,32 @@
ACTLR register. Note that setting specific bits in the ACTLR register
may not be available in non-secure mode.
+config ARM_ERRATA_742230
+ bool "ARM errata: DMB operation may be faulty"
+ depends on CPU_V7 && SMP
+ help
+ This option enables the workaround for the 742230 Cortex-A9
+ (r1p0..r2p2) erratum. Under rare circumstances, a DMB instruction
+ between two write operations may not ensure the correct visibility
+ ordering of the two writes. This workaround sets a specific bit in
+ the diagnostic register of the Cortex-A9 which causes the DMB
+ instruction to behave as a DSB, ensuring the correct behaviour of
+ the two writes.
+
+config ARM_ERRATA_742231
+ bool "ARM errata: Incorrect hazard handling in the SCU may lead to data corruption"
+ depends on CPU_V7 && SMP
+ help
+ This option enables the workaround for the 742231 Cortex-A9
+ (r2p0..r2p2) erratum. Under certain conditions, specific to the
+ Cortex-A9 MPCore micro-architecture, two CPUs working in SMP mode,
+ accessing some data located in the same cache line, may get corrupted
+ data due to bad handling of the address hazard when the line gets
+ replaced from one of the CPUs at the same time as another CPU is
+ accessing it. This workaround sets specific bits in the diagnostic
+ register of the Cortex-A9 which reduces the linefill issuing
+ capabilities of the processor.
+
config PL310_ERRATA_588369
bool "Clean & Invalidate maintenance operations do not invalidate clean lines"
depends on CACHE_L2X0 && ARCH_OMAP4
@@ -1076,6 +1101,20 @@
invalidated are not, resulting in an incoherency in the system page
tables. The workaround changes the TLB flushing routines to invalidate
entries regardless of the ASID.
+
+config ARM_ERRATA_743622
+ bool "ARM errata: Faulty hazard checking in the Store Buffer may lead to data corruption"
+ depends on CPU_V7
+ help
+ This option enables the workaround for the 743622 Cortex-A9
+ (r2p0..r2p2) erratum. Under very rare conditions, a faulty
+ optimisation in the Cortex-A9 Store Buffer may lead to data
+ corruption. This workaround sets a specific bit in the diagnostic
+ register of the Cortex-A9 which disables the Store Buffer
+ optimisation, preventing the defect from occurring. This has no
+ visible impact on the overall performance or power consumption of the
+ processor.
+
endmenu
source "arch/arm/common/Kconfig"
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index b23f6bc..65a7c1c 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -116,5 +116,5 @@
$(obj)/font.c: $(FONTC)
$(call cmd,shipped)
-$(obj)/vmlinux.lds: $(obj)/vmlinux.lds.in arch/arm/boot/Makefile .config
+$(obj)/vmlinux.lds: $(obj)/vmlinux.lds.in arch/arm/boot/Makefile $(KCONFIG_CONFIG)
@sed "$(SEDFLAGS)" < $< > $@
diff --git a/arch/arm/common/it8152.c b/arch/arm/common/it8152.c
index 7974baa..1bec96e 100644
--- a/arch/arm/common/it8152.c
+++ b/arch/arm/common/it8152.c
@@ -271,6 +271,14 @@
((dma_addr + size - PHYS_OFFSET) >= SZ_64M);
}
+int dma_set_coherent_mask(struct device *dev, u64 mask)
+{
+ if (mask >= PHYS_OFFSET + SZ_64M - 1)
+ return 0;
+
+ return -EIO;
+}
+
int __init it8152_pci_setup(int nr, struct pci_sys_data *sys)
{
it8152_io.start = IT8152_IO_BASE + 0x12000;
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index ab68cf1..e90b167 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -317,6 +317,10 @@
#ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE
#define pgprot_dmacoherent(prot) \
__pgprot_modify(prot, L_PTE_MT_MASK|L_PTE_EXEC, L_PTE_MT_BUFFERABLE)
+#define __HAVE_PHYS_MEM_ACCESS_PROT
+struct file;
+extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
+ unsigned long size, pgprot_t vma_prot);
#else
#define pgprot_dmacoherent(prot) \
__pgprot_modify(prot, L_PTE_MT_MASK|L_PTE_EXEC, L_PTE_MT_UNCACHED)
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index f05a35a..7885722 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -48,6 +48,8 @@
beq no_work_pending
mov r0, sp @ 'regs'
mov r2, why @ 'syscall'
+ tst r1, #_TIF_SIGPENDING @ delivering a signal?
+ movne why, #0 @ prevent further restarts
bl do_notify_resume
b ret_slow_syscall @ Check work again
@@ -418,11 +420,13 @@
sys_sigreturn_wrapper:
add r0, sp, #S_OFF
+ mov why, #0 @ prevent syscall restart handling
b sys_sigreturn
ENDPROC(sys_sigreturn_wrapper)
sys_rt_sigreturn_wrapper:
add r0, sp, #S_OFF
+ mov why, #0 @ prevent syscall restart handling
b sys_rt_sigreturn
ENDPROC(sys_rt_sigreturn_wrapper)
diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c
index 8bccbfa..2c1f005 100644
--- a/arch/arm/kernel/kprobes-decode.c
+++ b/arch/arm/kernel/kprobes-decode.c
@@ -1162,11 +1162,12 @@
{
/*
* MSR : cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx
- * Undef : cccc 0011 0x00 xxxx xxxx xxxx xxxx xxxx
+ * Undef : cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx
* ALU op with S bit and Rd == 15 :
* cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx
*/
- if ((insn & 0x0f900000) == 0x03200000 || /* MSR & Undef */
+ if ((insn & 0x0fb00000) == 0x03200000 || /* MSR */
+ (insn & 0x0ff00000) == 0x03400000 || /* Undef */
(insn & 0x0e10f000) == 0x0210f000) /* ALU s-bit, R15 */
return INSN_REJECTED;
@@ -1177,7 +1178,7 @@
* *S (bit 20) updates condition codes
* ADC/SBC/RSC reads the C flag
*/
- insn &= 0xfff00fff; /* Rn = r0, Rd = r0 */
+ insn &= 0xffff0fff; /* Rd = r0 */
asi->insn[0] = insn;
asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */
emulate_alu_imm_rwflags : emulate_alu_imm_rflags;
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
index 5e71ccd..1276bab 100644
--- a/arch/arm/mach-at91/at91sam9g45_devices.c
+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
@@ -426,7 +426,7 @@
.sda_is_open_drain = 1,
.scl_pin = AT91_PIN_PA21,
.scl_is_open_drain = 1,
- .udelay = 2, /* ~100 kHz */
+ .udelay = 5, /* ~100 kHz */
};
static struct platform_device at91sam9g45_twi0_device = {
@@ -440,7 +440,7 @@
.sda_is_open_drain = 1,
.scl_pin = AT91_PIN_PB11,
.scl_is_open_drain = 1,
- .udelay = 2, /* ~100 kHz */
+ .udelay = 5, /* ~100 kHz */
};
static struct platform_device at91sam9g45_twi1_device = {
diff --git a/arch/arm/mach-at91/include/mach/system.h b/arch/arm/mach-at91/include/mach/system.h
index c80e090..ee8db15 100644
--- a/arch/arm/mach-at91/include/mach/system.h
+++ b/arch/arm/mach-at91/include/mach/system.h
@@ -28,17 +28,16 @@
static inline void arch_idle(void)
{
-#ifndef CONFIG_DEBUG_KERNEL
/*
* Disable the processor clock. The processor will be automatically
* re-enabled by an interrupt or by a reset.
*/
at91_sys_write(AT91_PMC_SCDR, AT91_PMC_PCK);
-#else
+#ifndef CONFIG_CPU_ARM920T
/*
* Set the processor (CP15) into 'Wait for Interrupt' mode.
- * Unlike disabling the processor clock via the PMC (above)
- * this allows the processor to be woken via JTAG.
+ * Post-RM9200 processors need this in conjunction with the above
+ * to save power when idle.
*/
cpu_do_idle();
#endif
diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c
index 8b7201e..de40e9c 100644
--- a/arch/arm/mach-davinci/devices.c
+++ b/arch/arm/mach-davinci/devices.c
@@ -295,6 +295,18 @@
/*-------------------------------------------------------------------------*/
+struct platform_device davinci_pcm_device = {
+ .name = "davinci-pcm-audio",
+ .id = -1,
+};
+
+static void davinci_init_pcm(void)
+{
+ platform_device_register(&davinci_pcm_device);
+}
+
+/*-------------------------------------------------------------------------*/
+
struct davinci_timer_instance davinci_timer_instance[2] = {
{
.base = DAVINCI_TIMER0_BASE,
@@ -315,6 +327,7 @@
/* please keep these calls, and their implementations above,
* in alphabetical order so they're easier to sort through.
*/
+ davinci_init_pcm();
davinci_init_wdt();
return 0;
diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c
index 3d996b6..9be261b 100644
--- a/arch/arm/mach-davinci/dm355.c
+++ b/arch/arm/mach-davinci/dm355.c
@@ -769,8 +769,7 @@
.virtual = SRAM_VIRT,
.pfn = __phys_to_pfn(0x00010000),
.length = SZ_32K,
- /* MT_MEMORY_NONCACHED requires supersection alignment */
- .type = MT_DEVICE,
+ .type = MT_MEMORY_NONCACHED,
},
};
diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c
index 6b6f4c6..7781e35 100644
--- a/arch/arm/mach-davinci/dm365.c
+++ b/arch/arm/mach-davinci/dm365.c
@@ -969,8 +969,7 @@
.virtual = SRAM_VIRT,
.pfn = __phys_to_pfn(0x00010000),
.length = SZ_32K,
- /* MT_MEMORY_NONCACHED requires supersection alignment */
- .type = MT_DEVICE,
+ .type = MT_MEMORY_NONCACHED,
},
};
diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c
index 40fec31..5e5b0a7 100644
--- a/arch/arm/mach-davinci/dm644x.c
+++ b/arch/arm/mach-davinci/dm644x.c
@@ -653,8 +653,7 @@
.virtual = SRAM_VIRT,
.pfn = __phys_to_pfn(0x00008000),
.length = SZ_16K,
- /* MT_MEMORY_NONCACHED requires supersection alignment */
- .type = MT_DEVICE,
+ .type = MT_MEMORY_NONCACHED,
},
};
diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c
index e4a3df1..26e8a9c 100644
--- a/arch/arm/mach-davinci/dm646x.c
+++ b/arch/arm/mach-davinci/dm646x.c
@@ -737,8 +737,7 @@
.virtual = SRAM_VIRT,
.pfn = __phys_to_pfn(0x00010000),
.length = SZ_32K,
- /* MT_MEMORY_NONCACHED requires supersection alignment */
- .type = MT_DEVICE,
+ .type = MT_MEMORY_NONCACHED,
},
};
diff --git a/arch/arm/mach-dove/include/mach/io.h b/arch/arm/mach-dove/include/mach/io.h
index 3b3e472..eb4936f 100644
--- a/arch/arm/mach-dove/include/mach/io.h
+++ b/arch/arm/mach-dove/include/mach/io.h
@@ -13,8 +13,8 @@
#define IO_SPACE_LIMIT 0xffffffff
-#define __io(a) ((void __iomem *)(((a) - DOVE_PCIE0_IO_PHYS_BASE) +\
- DOVE_PCIE0_IO_VIRT_BASE))
-#define __mem_pci(a) (a)
+#define __io(a) ((void __iomem *)(((a) - DOVE_PCIE0_IO_BUS_BASE) + \
+ DOVE_PCIE0_IO_VIRT_BASE))
+#define __mem_pci(a) (a)
#endif
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 4cb55d3..ffdf87b 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -776,9 +776,15 @@
.resource = ep93xx_i2s_resource,
};
+static struct platform_device ep93xx_pcm_device = {
+ .name = "ep93xx-pcm-audio",
+ .id = -1,
+};
+
void __init ep93xx_register_i2s(void)
{
platform_device_register(&ep93xx_i2s_device);
+ platform_device_register(&ep93xx_pcm_device);
}
#define EP93XX_SYSCON_DEVCFG_I2S_MASK (EP93XX_SYSCON_DEVCFG_I2SONSSP | \
@@ -826,6 +832,40 @@
}
EXPORT_SYMBOL(ep93xx_i2s_release);
+/*************************************************************************
+ * EP93xx AC97 audio peripheral handling
+ *************************************************************************/
+static struct resource ep93xx_ac97_resources[] = {
+ {
+ .start = EP93XX_AAC_PHYS_BASE,
+ .end = EP93XX_AAC_PHYS_BASE + 0xb0 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_EP93XX_AACINTR,
+ .end = IRQ_EP93XX_AACINTR,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device ep93xx_ac97_device = {
+ .name = "ep93xx-ac97",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(ep93xx_ac97_resources),
+ .resource = ep93xx_ac97_resources,
+};
+
+void __init ep93xx_register_ac97(void)
+{
+ /*
+ * Make sure that the AC97 pins are not used by I2S.
+ */
+ ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2SONAC97);
+
+ platform_device_register(&ep93xx_ac97_device);
+ platform_device_register(&ep93xx_pcm_device);
+}
+
extern void ep93xx_gpio_init(void);
void __init ep93xx_init_devices(void)
diff --git a/arch/arm/mach-ep93xx/dma-m2p.c b/arch/arm/mach-ep93xx/dma-m2p.c
index 8904ca4..a696d35 100644
--- a/arch/arm/mach-ep93xx/dma-m2p.c
+++ b/arch/arm/mach-ep93xx/dma-m2p.c
@@ -276,7 +276,7 @@
v &= ~(M2P_CONTROL_STALL_IRQ_EN | M2P_CONTROL_NFB_IRQ_EN);
m2p_set_control(ch, v);
- while (m2p_channel_state(ch) == STATE_ON)
+ while (m2p_channel_state(ch) >= STATE_ON)
cpu_relax();
m2p_set_control(ch, 0x0);
diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
index c54b3e5..9ac4d10 100644
--- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
+++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
@@ -105,6 +105,7 @@
#define EP93XX_GPIO_B_INT_STATUS EP93XX_GPIO_REG(0xbc)
#define EP93XX_GPIO_EEDRIVE EP93XX_GPIO_REG(0xc8)
+#define EP93XX_AAC_PHYS_BASE EP93XX_APB_PHYS(0x00080000)
#define EP93XX_AAC_BASE EP93XX_APB_IOMEM(0x00080000)
#define EP93XX_SPI_PHYS_BASE EP93XX_APB_PHYS(0x000a0000)
diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
index 3330b36..5066045 100644
--- a/arch/arm/mach-ep93xx/include/mach/platform.h
+++ b/arch/arm/mach-ep93xx/include/mach/platform.h
@@ -61,6 +61,7 @@
void ep93xx_register_i2s(void);
int ep93xx_i2s_acquire(unsigned i2s_pins, unsigned i2s_config);
void ep93xx_i2s_release(void);
+void ep93xx_register_ac97(void);
void ep93xx_init_devices(void);
extern struct sys_timer ep93xx_timer;
diff --git a/arch/arm/mach-ep93xx/simone.c b/arch/arm/mach-ep93xx/simone.c
index 5dded58..f5f81f9 100644
--- a/arch/arm/mach-ep93xx/simone.c
+++ b/arch/arm/mach-ep93xx/simone.c
@@ -61,6 +61,7 @@
ep93xx_register_fb(&simone_fb_info);
ep93xx_register_i2c(&simone_i2c_gpio_data, simone_i2c_board_info,
ARRAY_SIZE(simone_i2c_board_info));
+ ep93xx_register_ac97();
}
MACHINE_START(SIM_ONE, "Simplemachines Sim.One Board")
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index c5c0369..2f7e272 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -122,6 +122,7 @@
select IMX_HAVE_PLATFORM_IMX_I2C
select IMX_HAVE_PLATFORM_IMX_UART
select IMX_HAVE_PLATFORM_MXC_NAND
+ select MXC_ULPI if USB_ULPI
help
Include support for Eukrea CPUIMX27 platform. This includes
specific configurations for the module and its peripherals.
diff --git a/arch/arm/mach-imx/mach-cpuimx27.c b/arch/arm/mach-imx/mach-cpuimx27.c
index 339150a..6830afd 100644
--- a/arch/arm/mach-imx/mach-cpuimx27.c
+++ b/arch/arm/mach-imx/mach-cpuimx27.c
@@ -259,7 +259,7 @@
i2c_register_board_info(0, eukrea_cpuimx27_i2c_devices,
ARRAY_SIZE(eukrea_cpuimx27_i2c_devices));
- imx27_add_i2c_imx1(&cpuimx27_i2c1_data);
+ imx27_add_i2c_imx0(&cpuimx27_i2c1_data);
platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c
index 61cd4d6..24498a9 100644
--- a/arch/arm/mach-ixp4xx/common-pci.c
+++ b/arch/arm/mach-ixp4xx/common-pci.c
@@ -503,6 +503,14 @@
return pci_scan_bus(sys->busnr, &ixp4xx_ops, sys);
}
+int dma_set_coherent_mask(struct device *dev, u64 mask)
+{
+ if (mask >= SZ_64M - 1)
+ return 0;
+
+ return -EIO;
+}
+
EXPORT_SYMBOL(ixp4xx_pci_read);
EXPORT_SYMBOL(ixp4xx_pci_write);
diff --git a/arch/arm/mach-ixp4xx/include/mach/hardware.h b/arch/arm/mach-ixp4xx/include/mach/hardware.h
index f91ca6d..8138371 100644
--- a/arch/arm/mach-ixp4xx/include/mach/hardware.h
+++ b/arch/arm/mach-ixp4xx/include/mach/hardware.h
@@ -26,6 +26,8 @@
#define PCIBIOS_MAX_MEM 0x4BFFFFFF
#endif
+#define ARCH_HAS_DMA_SET_COHERENT_MASK
+
#define pcibios_assign_all_busses() 1
/* Register locations and bits */
diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c
index 1c82d42..51ff23b 100644
--- a/arch/arm/mach-kirkwood/common.c
+++ b/arch/arm/mach-kirkwood/common.c
@@ -903,10 +903,16 @@
},
};
+static struct platform_device kirkwood_pcm_device = {
+ .name = "kirkwood-pcm-audio",
+ .id = -1,
+};
+
void __init kirkwood_audio_init(void)
{
kirkwood_clk_ctrl |= CGC_AUDIO;
platform_device_register(&kirkwood_i2s_device);
+ platform_device_register(&kirkwood_pcm_device);
}
/*****************************************************************************
diff --git a/arch/arm/mach-kirkwood/include/mach/kirkwood.h b/arch/arm/mach-kirkwood/include/mach/kirkwood.h
index 93fc2ec..6e924b3 100644
--- a/arch/arm/mach-kirkwood/include/mach/kirkwood.h
+++ b/arch/arm/mach-kirkwood/include/mach/kirkwood.h
@@ -38,7 +38,7 @@
#define KIRKWOOD_PCIE1_IO_PHYS_BASE 0xf3000000
#define KIRKWOOD_PCIE1_IO_VIRT_BASE 0xfef00000
-#define KIRKWOOD_PCIE1_IO_BUS_BASE 0x00000000
+#define KIRKWOOD_PCIE1_IO_BUS_BASE 0x00100000
#define KIRKWOOD_PCIE1_IO_SIZE SZ_1M
#define KIRKWOOD_PCIE_IO_PHYS_BASE 0xf2000000
diff --git a/arch/arm/mach-kirkwood/pcie.c b/arch/arm/mach-kirkwood/pcie.c
index 55e7f00..513ad31 100644
--- a/arch/arm/mach-kirkwood/pcie.c
+++ b/arch/arm/mach-kirkwood/pcie.c
@@ -117,7 +117,7 @@
* IORESOURCE_IO
*/
pp->res[0].name = "PCIe 0 I/O Space";
- pp->res[0].start = KIRKWOOD_PCIE_IO_PHYS_BASE;
+ pp->res[0].start = KIRKWOOD_PCIE_IO_BUS_BASE;
pp->res[0].end = pp->res[0].start + KIRKWOOD_PCIE_IO_SIZE - 1;
pp->res[0].flags = IORESOURCE_IO;
@@ -139,7 +139,7 @@
* IORESOURCE_IO
*/
pp->res[0].name = "PCIe 1 I/O Space";
- pp->res[0].start = KIRKWOOD_PCIE1_IO_PHYS_BASE;
+ pp->res[0].start = KIRKWOOD_PCIE1_IO_BUS_BASE;
pp->res[0].end = pp->res[0].start + KIRKWOOD_PCIE1_IO_SIZE - 1;
pp->res[0].flags = IORESOURCE_IO;
diff --git a/arch/arm/mach-mmp/include/mach/system.h b/arch/arm/mach-mmp/include/mach/system.h
index 4f5b0e0..1a8a25e 100644
--- a/arch/arm/mach-mmp/include/mach/system.h
+++ b/arch/arm/mach-mmp/include/mach/system.h
@@ -9,6 +9,8 @@
#ifndef __ASM_MACH_SYSTEM_H
#define __ASM_MACH_SYSTEM_H
+#include <mach/cputype.h>
+
static inline void arch_idle(void)
{
cpu_do_idle();
@@ -16,6 +18,9 @@
static inline void arch_reset(char mode, const char *cmd)
{
- cpu_reset(0);
+ if (cpu_is_pxa168())
+ cpu_reset(0xffff0000);
+ else
+ cpu_reset(0);
}
#endif /* __ASM_MACH_SYSTEM_H */
diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c
index aa07256..b583121 100644
--- a/arch/arm/mach-omap1/devices.c
+++ b/arch/arm/mach-omap1/devices.c
@@ -25,6 +25,7 @@
#include <mach/gpio.h>
#include <plat/mmc.h>
#include <plat/omap7xx.h>
+#include <plat/mcbsp.h>
/*-------------------------------------------------------------------------*/
@@ -195,6 +196,30 @@
static inline void omap_init_sti(void) {}
+#if defined(CONFIG_SND_SOC) || defined(CONFIG_SND_SOC_MODULE)
+
+static struct platform_device omap_pcm = {
+ .name = "omap-pcm-audio",
+ .id = -1,
+};
+
+OMAP_MCBSP_PLATFORM_DEVICE(1);
+OMAP_MCBSP_PLATFORM_DEVICE(2);
+OMAP_MCBSP_PLATFORM_DEVICE(3);
+
+static void omap_init_audio(void)
+{
+ platform_device_register(&omap_mcbsp1);
+ platform_device_register(&omap_mcbsp2);
+ if (!cpu_is_omap7xx())
+ platform_device_register(&omap_mcbsp3);
+ platform_device_register(&omap_pcm);
+}
+
+#else
+static inline void omap_init_audio(void) {}
+#endif
+
/*-------------------------------------------------------------------------*/
/*
@@ -227,6 +252,7 @@
omap_init_rtc();
omap_init_spi100k();
omap_init_sti();
+ omap_init_audio();
return 0;
}
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index 9a5eb87..11ce4b2 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -23,6 +23,7 @@
#include <linux/gpio.h>
#include <linux/gpio_keys.h>
#include <linux/mmc/host.h>
+#include <sound/tlv320aic3x.h>
#include <plat/mcspi.h>
#include <plat/board.h>
@@ -689,7 +690,6 @@
};
-
static struct twl4030_platform_data rx51_twldata __initdata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
@@ -710,10 +710,6 @@
.vio = &rx51_vio,
};
-static struct aic3x_pdata rx51_aic3x_data __initdata = {
- .gpio_reset = 60,
-};
-
static struct tpa6130a2_platform_data rx51_tpa6130a2_data __initdata = {
.id = TPA6130A2,
.power_gpio = 98,
@@ -728,6 +724,17 @@
},
};
+/* Audio setup data */
+static struct aic3x_setup_data rx51_aic34_setup = {
+ .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
+ .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
+};
+
+static struct aic3x_pdata rx51_aic3x_data = {
+ .setup = &rx51_aic34_setup,
+ .gpio_reset = 60,
+};
+
static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_2[] = {
{
I2C_BOARD_INFO("tlv320aic3x", 0x18),
diff --git a/arch/arm/mach-omap2/board-zoom-peripherals.c b/arch/arm/mach-omap2/board-zoom-peripherals.c
index 6b39849..3c65304 100644
--- a/arch/arm/mach-omap2/board-zoom-peripherals.c
+++ b/arch/arm/mach-omap2/board-zoom-peripherals.c
@@ -24,6 +24,8 @@
#include <plat/common.h>
#include <plat/usb.h>
+#include <mach/board-zoom.h>
+
#include "mux.h"
#include "hsmmc.h"
@@ -188,6 +190,11 @@
return 0;
}
+/* EXTMUTE callback function */
+void zoom2_set_hs_extmute(int mute)
+{
+ gpio_set_value(ZOOM2_HEADSET_EXTMUTE_GPIO, mute);
+}
static int zoom_batt_table[] = {
/* 0 C*/
@@ -257,6 +264,11 @@
static int __init omap_i2c_init(void)
{
+ if (machine_is_omap_zoom2()) {
+ zoom_audio_data.ramp_delay_value = 3; /* 161 ms */
+ zoom_audio_data.hs_extmute = 1;
+ zoom_audio_data.set_hs_extmute = zoom2_set_hs_extmute;
+ }
omap_register_i2c_bus(1, 2400, zoom_i2c_boardinfo,
ARRAY_SIZE(zoom_i2c_boardinfo));
omap_register_i2c_bus(2, 400, NULL, 0);
diff --git a/arch/arm/mach-omap2/board-zoom2.c b/arch/arm/mach-omap2/board-zoom2.c
index 3ad9ecf..00c8f83 100644
--- a/arch/arm/mach-omap2/board-zoom2.c
+++ b/arch/arm/mach-omap2/board-zoom2.c
@@ -14,6 +14,7 @@
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/gpio.h>
+#include <linux/i2c/twl.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -34,41 +35,6 @@
omap_gpio_init();
}
-/* REVISIT: These audio entries can be removed once MFD code is merged */
-#if 0
-
-static struct twl4030_madc_platform_data zoom2_madc_data = {
- .irq_line = 1,
-};
-
-static struct twl4030_codec_audio_data zoom2_audio_data = {
- .audio_mclk = 26000000,
-};
-
-static struct twl4030_codec_data zoom2_codec_data = {
- .audio_mclk = 26000000,
- .audio = &zoom2_audio_data,
-};
-
-static struct twl4030_platform_data zoom2_twldata = {
- .irq_base = TWL4030_IRQ_BASE,
- .irq_end = TWL4030_IRQ_END,
-
- /* platform_data for children goes here */
- .bci = &zoom2_bci_data,
- .madc = &zoom2_madc_data,
- .usb = &zoom2_usb_data,
- .gpio = &zoom2_gpio_data,
- .keypad = &zoom2_kp_twl4030_data,
- .codec = &zoom2_codec_data,
- .vmmc1 = &zoom2_vmmc1,
- .vmmc2 = &zoom2_vmmc2,
- .vsim = &zoom2_vsim,
-
-};
-
-#endif
-
#ifdef CONFIG_OMAP_MUX
static struct omap_board_mux board_mux[] __initdata = {
/* WLAN IRQ - GPIO 162 */
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 2dbb265..512ae46 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -25,6 +25,7 @@
#include <plat/control.h>
#include <plat/tc.h>
#include <plat/board.h>
+#include <plat/mcbsp.h>
#include <mach/gpio.h>
#include <plat/mmc.h>
#include <plat/dma.h>
@@ -235,6 +236,43 @@
static inline void omap_init_sti(void) {}
+#if defined(CONFIG_SND_SOC) || defined(CONFIG_SND_SOC_MODULE)
+
+static struct platform_device omap_pcm = {
+ .name = "omap-pcm-audio",
+ .id = -1,
+};
+
+/*
+ * OMAP2420 has 2 McBSP ports
+ * OMAP2430 has 5 McBSP ports
+ * OMAP3 has 5 McBSP ports
+ * OMAP4 has 4 McBSP ports
+ */
+OMAP_MCBSP_PLATFORM_DEVICE(1);
+OMAP_MCBSP_PLATFORM_DEVICE(2);
+OMAP_MCBSP_PLATFORM_DEVICE(3);
+OMAP_MCBSP_PLATFORM_DEVICE(4);
+OMAP_MCBSP_PLATFORM_DEVICE(5);
+
+static void omap_init_audio(void)
+{
+ platform_device_register(&omap_mcbsp1);
+ platform_device_register(&omap_mcbsp2);
+ if (cpu_is_omap243x() || cpu_is_omap34xx() || cpu_is_omap44xx()) {
+ platform_device_register(&omap_mcbsp3);
+ platform_device_register(&omap_mcbsp4);
+ }
+ if (cpu_is_omap243x() || cpu_is_omap34xx())
+ platform_device_register(&omap_mcbsp5);
+
+ platform_device_register(&omap_pcm);
+}
+
+#else
+static inline void omap_init_audio(void) {}
+#endif
+
#if defined(CONFIG_SPI_OMAP24XX) || defined(CONFIG_SPI_OMAP24XX_MODULE)
#include <plat/mcspi.h>
@@ -847,6 +885,7 @@
* in alphabetical order so they're easier to sort through.
*/
omap_hsmmc_reset();
+ omap_init_audio();
omap_init_camera();
omap_init_mbox();
omap_init_mcspi();
diff --git a/arch/arm/mach-omap2/include/mach/board-zoom.h b/arch/arm/mach-omap2/include/mach/board-zoom.h
index 3af69d2..80591fd 100644
--- a/arch/arm/mach-omap2/include/mach/board-zoom.h
+++ b/arch/arm/mach-omap2/include/mach/board-zoom.h
@@ -9,3 +9,5 @@
extern void __init board_nand_init(struct mtd_partition *, u8 nr_parts, u8 cs);
extern int __init zoom_debugboard_init(void);
extern void __init zoom_peripherals_init(void);
+
+#define ZOOM2_HEADSET_EXTMUTE_GPIO 153
diff --git a/arch/arm/mach-pxa/cpufreq-pxa2xx.c b/arch/arm/mach-pxa/cpufreq-pxa2xx.c
index 50d5939..58093d9 100644
--- a/arch/arm/mach-pxa/cpufreq-pxa2xx.c
+++ b/arch/arm/mach-pxa/cpufreq-pxa2xx.c
@@ -312,8 +312,7 @@
freqs.cpu = policy->cpu;
if (freq_debug)
- pr_debug(KERN_INFO "Changing CPU frequency to %d Mhz, "
- "(SDRAM %d Mhz)\n",
+ pr_debug("Changing CPU frequency to %d Mhz, (SDRAM %d Mhz)\n",
freqs.new / 1000, (pxa_freq_settings[idx].div2) ?
(new_freq_mem / 2000) : (new_freq_mem / 1000));
diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c
index 65447dc..6d84544 100644
--- a/arch/arm/mach-pxa/devices.c
+++ b/arch/arm/mach-pxa/devices.c
@@ -354,6 +354,31 @@
.num_resources = ARRAY_SIZE(pxai2s_resources),
};
+struct platform_device pxa_device_asoc_ssp1 = {
+ .name = "pxa-ssp-dai",
+ .id = 0,
+};
+
+struct platform_device pxa_device_asoc_ssp2= {
+ .name = "pxa-ssp-dai",
+ .id = 1,
+};
+
+struct platform_device pxa_device_asoc_ssp3 = {
+ .name = "pxa-ssp-dai",
+ .id = 2,
+};
+
+struct platform_device pxa_device_asoc_ssp4 = {
+ .name = "pxa-ssp-dai",
+ .id = 3,
+};
+
+struct platform_device pxa_device_asoc_platform = {
+ .name = "pxa-pcm-audio",
+ .id = -1,
+};
+
static u64 pxaficp_dmamask = ~(u32)0;
struct platform_device pxa_device_ficp = {
diff --git a/arch/arm/mach-pxa/devices.h b/arch/arm/mach-pxa/devices.h
index 50353ea..491a27a 100644
--- a/arch/arm/mach-pxa/devices.h
+++ b/arch/arm/mach-pxa/devices.h
@@ -38,4 +38,10 @@
extern struct platform_device pxa3xx_device_gcu;
+extern struct platform_device pxa_device_asoc_platform;
+extern struct platform_device pxa_device_asoc_ssp1;
+extern struct platform_device pxa_device_asoc_ssp2;
+extern struct platform_device pxa_device_asoc_ssp3;
+extern struct platform_device pxa_device_asoc_ssp4;
+
void __init pxa_register_device(struct platform_device *dev, void *data);
diff --git a/arch/arm/mach-pxa/include/mach/hardware.h b/arch/arm/mach-pxa/include/mach/hardware.h
index 7f64d24..814f145 100644
--- a/arch/arm/mach-pxa/include/mach/hardware.h
+++ b/arch/arm/mach-pxa/include/mach/hardware.h
@@ -264,23 +264,35 @@
* <= 0x2 for pxa21x/pxa25x/pxa26x/pxa27x
* == 0x3 for pxa300/pxa310/pxa320
*/
+#if defined(CONFIG_PXA25x) || defined(CONFIG_PXA27x)
#define __cpu_is_pxa2xx(id) \
({ \
unsigned int _id = (id) >> 13 & 0x7; \
_id <= 0x2; \
})
+#else
+#define __cpu_is_pxa2xx(id) (0)
+#endif
+#ifdef CONFIG_PXA3xx
#define __cpu_is_pxa3xx(id) \
({ \
unsigned int _id = (id) >> 13 & 0x7; \
_id == 0x3; \
})
+#else
+#define __cpu_is_pxa3xx(id) (0)
+#endif
+#if defined(CONFIG_CPU_PXA930) || defined(CONFIG_CPU_PXA935)
#define __cpu_is_pxa93x(id) \
({ \
unsigned int _id = (id) >> 4 & 0xfff; \
_id == 0x683 || _id == 0x693; \
})
+#else
+#define __cpu_is_pxa93x(id) (0)
+#endif
#define cpu_is_pxa2xx() \
({ \
@@ -309,7 +321,7 @@
#define PCIBIOS_MIN_IO 0
#define PCIBIOS_MIN_MEM 0
#define pcibios_assign_all_busses() 1
+#define ARCH_HAS_DMA_SET_COHERENT_MASK
#endif
-
#endif /* _ASM_ARCH_HARDWARE_H */
diff --git a/arch/arm/mach-pxa/include/mach/io.h b/arch/arm/mach-pxa/include/mach/io.h
index 262691f..fdca3be 100644
--- a/arch/arm/mach-pxa/include/mach/io.h
+++ b/arch/arm/mach-pxa/include/mach/io.h
@@ -6,6 +6,8 @@
#ifndef __ASM_ARM_ARCH_IO_H
#define __ASM_ARM_ARCH_IO_H
+#include <mach/hardware.h>
+
#define IO_SPACE_LIMIT 0xffffffff
/*
diff --git a/arch/arm/mach-pxa/palm27x.c b/arch/arm/mach-pxa/palm27x.c
index 77ad6d3..405b92a 100644
--- a/arch/arm/mach-pxa/palm27x.c
+++ b/arch/arm/mach-pxa/palm27x.c
@@ -469,9 +469,13 @@
},
};
+static struct i2c_pxa_platform_data palm27x_i2c_power_info = {
+ .use_pio = 1,
+};
+
void __init palm27x_pmic_init(void)
{
i2c_register_board_info(1, ARRAY_AND_SIZE(palm27x_pi2c_board_info));
- pxa27x_set_i2c_power_info(NULL);
+ pxa27x_set_i2c_power_info(&palm27x_i2c_power_info);
}
#endif
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index 12e5b9f..d1fbf29 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -385,6 +385,10 @@
&pxa27x_device_udc,
&pxa_device_pmu,
&pxa_device_i2s,
+ &pxa_device_asoc_ssp1,
+ &pxa_device_asoc_ssp2,
+ &pxa_device_asoc_ssp3,
+ &pxa_device_asoc_platform,
&sa1100_device_rtc,
&pxa_device_rtc,
&pxa27x_device_ssp1,
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index fa00148..90974e6 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -610,6 +610,11 @@
&pxa27x_device_udc,
&pxa_device_pmu,
&pxa_device_i2s,
+ &pxa_device_asoc_ssp1,
+ &pxa_device_asoc_ssp2,
+ &pxa_device_asoc_ssp3,
+ &pxa_device_asoc_ssp4,
+ &pxa_device_asoc_platform,
&sa1100_device_rtc,
&pxa_device_rtc,
&pxa27x_device_ssp1,
diff --git a/arch/arm/mach-pxa/vpac270.c b/arch/arm/mach-pxa/vpac270.c
index c9b747c..37d6173 100644
--- a/arch/arm/mach-pxa/vpac270.c
+++ b/arch/arm/mach-pxa/vpac270.c
@@ -240,6 +240,7 @@
#if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE)
static struct pxamci_platform_data vpac270_mci_platform_data = {
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
+ .gpio_power = -1,
.gpio_card_detect = GPIO53_VPAC270_SD_DETECT_N,
.gpio_card_ro = GPIO52_VPAC270_SD_READONLY,
.detect_delay_ms = 200,
diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c
index c479cbe..5ba9d99 100644
--- a/arch/arm/mach-pxa/zylonite.c
+++ b/arch/arm/mach-pxa/zylonite.c
@@ -45,6 +45,16 @@
int lcd_id;
int lcd_orientation;
+struct platform_device pxa_device_wm9713_audio = {
+ .name = "wm9713-codec",
+ .id = -1,
+};
+
+static void __init zylonite_init_wm9713_audio(void)
+{
+ platform_device_register(&pxa_device_wm9713_audio);
+}
+
static struct resource smc91x_resources[] = {
[0] = {
.start = ZYLONITE_ETH_PHYS + 0x300,
@@ -408,6 +418,7 @@
zylonite_init_nand();
zylonite_init_leds();
zylonite_init_ohci();
+ zylonite_init_wm9713_audio();
}
MACHINE_START(ZYLONITE, "PXA3xx Platform Development Kit (aka Zylonite)")
diff --git a/arch/arm/mach-s3c64xx/dev-audio.c b/arch/arm/mach-s3c64xx/dev-audio.c
index 9648fbc..3838335 100644
--- a/arch/arm/mach-s3c64xx/dev-audio.c
+++ b/arch/arm/mach-s3c64xx/dev-audio.c
@@ -43,8 +43,10 @@
s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_I2S1_LRCLK);
s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_I2S1_DI);
s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_I2S1_D0);
+ break;
default:
- printk(KERN_DEBUG "Invalid I2S Controller number!");
+ printk(KERN_DEBUG "Invalid I2S Controller number: %d\n",
+ pdev->id);
return -EINVAL;
}
@@ -184,7 +186,8 @@
s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_PCM1_SOUT);
break;
default:
- printk(KERN_DEBUG "Invalid PCM Controller number!");
+ printk(KERN_DEBUG "Invalid PCM Controller number: %d\n",
+ pdev->id);
return -EINVAL;
}
@@ -333,3 +336,16 @@
else
s3c_ac97_pdata.cfg_gpio = s3c64xx_ac97_cfg_gpe;
}
+
+static u64 s3c_device_audio_dmamask = 0xffffffffUL;
+
+struct platform_device s3c_device_pcm = {
+ .name = "s3c24xx-pcm-audio",
+ .id = -1,
+ .dev = {
+ .dma_mask = &s3c_device_audio_dmamask,
+ .coherent_dma_mask = 0xffffffffUL
+ }
+};
+EXPORT_SYMBOL(s3c_device_pcm);
+
diff --git a/arch/arm/mach-s3c64xx/dev-spi.c b/arch/arm/mach-s3c64xx/dev-spi.c
index a492b98..405e621 100644
--- a/arch/arm/mach-s3c64xx/dev-spi.c
+++ b/arch/arm/mach-s3c64xx/dev-spi.c
@@ -18,10 +18,11 @@
#include <mach/map.h>
#include <mach/gpio-bank-c.h>
#include <mach/spi-clocks.h>
+#include <mach/irqs.h>
#include <plat/s3c64xx-spi.h>
#include <plat/gpio-cfg.h>
-#include <plat/irqs.h>
+#include <plat/devs.h>
static char *spi_src_clks[] = {
[S3C64XX_SPI_SRCCLK_PCLK] = "pclk",
diff --git a/arch/arm/mach-s3c64xx/mach-real6410.c b/arch/arm/mach-s3c64xx/mach-real6410.c
index 5c07d01..e130379 100644
--- a/arch/arm/mach-s3c64xx/mach-real6410.c
+++ b/arch/arm/mach-s3c64xx/mach-real6410.c
@@ -30,73 +30,73 @@
#include <plat/devs.h>
#include <plat/regs-serial.h>
-#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
-#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
-#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+#define UCON (S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK)
+#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB)
+#define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE)
static struct s3c2410_uartcfg real6410_uartcfgs[] __initdata = {
[0] = {
- .hwport = 0,
- .flags = 0,
- .ucon = UCON,
- .ulcon = ULCON,
- .ufcon = UFCON,
+ .hwport = 0,
+ .flags = 0,
+ .ucon = UCON,
+ .ulcon = ULCON,
+ .ufcon = UFCON,
},
[1] = {
- .hwport = 1,
- .flags = 0,
- .ucon = UCON,
- .ulcon = ULCON,
- .ufcon = UFCON,
+ .hwport = 1,
+ .flags = 0,
+ .ucon = UCON,
+ .ulcon = ULCON,
+ .ufcon = UFCON,
},
[2] = {
- .hwport = 2,
- .flags = 0,
- .ucon = UCON,
- .ulcon = ULCON,
- .ufcon = UFCON,
+ .hwport = 2,
+ .flags = 0,
+ .ucon = UCON,
+ .ulcon = ULCON,
+ .ufcon = UFCON,
},
[3] = {
- .hwport = 3,
- .flags = 0,
- .ucon = UCON,
- .ulcon = ULCON,
- .ufcon = UFCON,
+ .hwport = 3,
+ .flags = 0,
+ .ucon = UCON,
+ .ulcon = ULCON,
+ .ufcon = UFCON,
},
};
/* DM9000AEP 10/100 ethernet controller */
static struct resource real6410_dm9k_resource[] = {
- [0] = {
- .start = S3C64XX_PA_XM0CSN1,
- .end = S3C64XX_PA_XM0CSN1 + 1,
- .flags = IORESOURCE_MEM
- },
- [1] = {
- .start = S3C64XX_PA_XM0CSN1 + 4,
- .end = S3C64XX_PA_XM0CSN1 + 5,
- .flags = IORESOURCE_MEM
- },
- [2] = {
- .start = S3C_EINT(7),
- .end = S3C_EINT(7),
- .flags = IORESOURCE_IRQ,
- }
+ [0] = {
+ .start = S3C64XX_PA_XM0CSN1,
+ .end = S3C64XX_PA_XM0CSN1 + 1,
+ .flags = IORESOURCE_MEM
+ },
+ [1] = {
+ .start = S3C64XX_PA_XM0CSN1 + 4,
+ .end = S3C64XX_PA_XM0CSN1 + 5,
+ .flags = IORESOURCE_MEM
+ },
+ [2] = {
+ .start = S3C_EINT(7),
+ .end = S3C_EINT(7),
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL
+ }
};
static struct dm9000_plat_data real6410_dm9k_pdata = {
- .flags = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),
+ .flags = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),
};
static struct platform_device real6410_device_eth = {
- .name = "dm9000",
- .id = -1,
- .num_resources = ARRAY_SIZE(real6410_dm9k_resource),
- .resource = real6410_dm9k_resource,
- .dev = {
- .platform_data = &real6410_dm9k_pdata,
- },
+ .name = "dm9000",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(real6410_dm9k_resource),
+ .resource = real6410_dm9k_resource,
+ .dev = {
+ .platform_data = &real6410_dm9k_pdata,
+ },
};
static struct platform_device *real6410_devices[] __initdata = {
@@ -129,12 +129,12 @@
/* set timing for nCS1 suitable for ethernet chip */
__raw_writel((0 << S3C64XX_SROM_BCX__PMC__SHIFT) |
- (6 << S3C64XX_SROM_BCX__TACP__SHIFT) |
- (4 << S3C64XX_SROM_BCX__TCAH__SHIFT) |
- (1 << S3C64XX_SROM_BCX__TCOH__SHIFT) |
- (13 << S3C64XX_SROM_BCX__TACC__SHIFT) |
- (4 << S3C64XX_SROM_BCX__TCOS__SHIFT) |
- (0 << S3C64XX_SROM_BCX__TACS__SHIFT), S3C64XX_SROM_BC1);
+ (6 << S3C64XX_SROM_BCX__TACP__SHIFT) |
+ (4 << S3C64XX_SROM_BCX__TCAH__SHIFT) |
+ (1 << S3C64XX_SROM_BCX__TCOH__SHIFT) |
+ (13 << S3C64XX_SROM_BCX__TACC__SHIFT) |
+ (4 << S3C64XX_SROM_BCX__TCOS__SHIFT) |
+ (0 << S3C64XX_SROM_BCX__TACS__SHIFT), S3C64XX_SROM_BC1);
platform_add_devices(real6410_devices, ARRAY_SIZE(real6410_devices));
}
diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c
index d498219..ecbddd3 100644
--- a/arch/arm/mach-s3c64xx/mach-smdk6410.c
+++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c
@@ -283,6 +283,7 @@
&s3c_device_fb,
&s3c_device_ohci,
&s3c_device_usb_hsotg,
+ &s3c_device_pcm,
&s3c64xx_device_iisv4,
&samsung_device_keypad,
diff --git a/arch/arm/mach-s5p6440/cpu.c b/arch/arm/mach-s5p6440/cpu.c
index 526f33a..ec592e8 100644
--- a/arch/arm/mach-s5p6440/cpu.c
+++ b/arch/arm/mach-s5p6440/cpu.c
@@ -19,6 +19,7 @@
#include <linux/sysdev.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>
+#include <linux/sched.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
diff --git a/arch/arm/mach-s5p6442/cpu.c b/arch/arm/mach-s5p6442/cpu.c
index a48fb55..70ac681 100644
--- a/arch/arm/mach-s5p6442/cpu.c
+++ b/arch/arm/mach-s5p6442/cpu.c
@@ -19,6 +19,7 @@
#include <linux/sysdev.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>
+#include <linux/sched.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
diff --git a/arch/arm/mach-s5pc100/cpu.c b/arch/arm/mach-s5pc100/cpu.c
index 251c92a..cd1afbc 100644
--- a/arch/arm/mach-s5pc100/cpu.c
+++ b/arch/arm/mach-s5pc100/cpu.c
@@ -21,6 +21,7 @@
#include <linux/sysdev.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>
+#include <linux/sched.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
diff --git a/arch/arm/mach-s5pv210/clock.c b/arch/arm/mach-s5pv210/clock.c
index af91fef..d562670 100644
--- a/arch/arm/mach-s5pv210/clock.c
+++ b/arch/arm/mach-s5pv210/clock.c
@@ -173,11 +173,6 @@
return s5p_gatectrl(S5P_CLKGATE_IP3, clk, enable);
}
-static int s5pv210_clk_ip4_ctrl(struct clk *clk, int enable)
-{
- return s5p_gatectrl(S5P_CLKGATE_IP4, clk, enable);
-}
-
static int s5pv210_clk_mask0_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(S5P_CLK_SRC_MASK0, clk, enable);
@@ -281,6 +276,24 @@
.enable = s5pv210_clk_ip0_ctrl,
.ctrlbit = (1<<29),
}, {
+ .name = "fimc",
+ .id = 0,
+ .parent = &clk_hclk_dsys.clk,
+ .enable = s5pv210_clk_ip0_ctrl,
+ .ctrlbit = (1 << 24),
+ }, {
+ .name = "fimc",
+ .id = 1,
+ .parent = &clk_hclk_dsys.clk,
+ .enable = s5pv210_clk_ip0_ctrl,
+ .ctrlbit = (1 << 25),
+ }, {
+ .name = "fimc",
+ .id = 2,
+ .parent = &clk_hclk_dsys.clk,
+ .enable = s5pv210_clk_ip0_ctrl,
+ .ctrlbit = (1 << 26),
+ }, {
.name = "otg",
.id = -1,
.parent = &clk_hclk_psys.clk,
@@ -357,7 +370,7 @@
.id = 1,
.parent = &clk_pclk_psys.clk,
.enable = s5pv210_clk_ip3_ctrl,
- .ctrlbit = (1<<8),
+ .ctrlbit = (1 << 10),
}, {
.name = "i2c",
.id = 2,
diff --git a/arch/arm/mach-s5pv210/cpu.c b/arch/arm/mach-s5pv210/cpu.c
index b9f4d67..245b82b 100644
--- a/arch/arm/mach-s5pv210/cpu.c
+++ b/arch/arm/mach-s5pv210/cpu.c
@@ -19,6 +19,7 @@
#include <linux/io.h>
#include <linux/sysdev.h>
#include <linux/platform_device.h>
+#include <linux/sched.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -47,7 +48,7 @@
{
.virtual = (unsigned long)S5P_VA_SYSTIMER,
.pfn = __phys_to_pfn(S5PV210_PA_SYSTIMER),
- .length = SZ_1M,
+ .length = SZ_4K,
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)VA_VIC2,
diff --git a/arch/arm/mach-u300/include/mach/gpio.h b/arch/arm/mach-u300/include/mach/gpio.h
index 7b1fc98..d5a71ab 100644
--- a/arch/arm/mach-u300/include/mach/gpio.h
+++ b/arch/arm/mach-u300/include/mach/gpio.h
@@ -273,6 +273,9 @@
extern int gpio_get_value(unsigned gpio);
extern void gpio_set_value(unsigned gpio, int value);
+#define gpio_get_value_cansleep gpio_get_value
+#define gpio_set_value_cansleep gpio_set_value
+
/* wrappers to sleep-enable the previous two functions */
static inline unsigned gpio_to_irq(unsigned gpio)
{
diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c
index 577df6c..71fb173 100644
--- a/arch/arm/mach-vexpress/ct-ca9x4.c
+++ b/arch/arm/mach-vexpress/ct-ca9x4.c
@@ -68,7 +68,7 @@
}
#if 0
-static void ct_ca9x4_timer_init(void)
+static void __init ct_ca9x4_timer_init(void)
{
writel(0, MMIO_P2V(CT_CA9X4_TIMER0) + TIMER_CTRL);
writel(0, MMIO_P2V(CT_CA9X4_TIMER1) + TIMER_CTRL);
@@ -222,12 +222,18 @@
.resource = pmu_resources,
};
-static void ct_ca9x4_init(void)
+static void __init ct_ca9x4_init(void)
{
int i;
#ifdef CONFIG_CACHE_L2X0
- l2x0_init(MMIO_P2V(CT_CA9X4_L2CC), 0x00000000, 0xfe0fffff);
+ void __iomem *l2x0_base = MMIO_P2V(CT_CA9X4_L2CC);
+
+ /* set RAM latencies to 1 cycle for this core tile. */
+ writel(0, l2x0_base + L2X0_TAG_LATENCY_CTRL);
+ writel(0, l2x0_base + L2X0_DATA_LATENCY_CTRL);
+
+ l2x0_init(l2x0_base, 0x00400000, 0xfe0fffff);
#endif
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c
index 817f0ad..7eaa232 100644
--- a/arch/arm/mach-vexpress/v2m.c
+++ b/arch/arm/mach-vexpress/v2m.c
@@ -48,7 +48,7 @@
}
-static void v2m_timer_init(void)
+static void __init v2m_timer_init(void)
{
writel(0, MMIO_P2V(V2M_TIMER0) + TIMER_CTRL);
writel(0, MMIO_P2V(V2M_TIMER1) + TIMER_CTRL);
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index d073b64..724ba3b 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -885,8 +885,23 @@
if (ai_usermode & UM_SIGNAL)
force_sig(SIGBUS, current);
- else
- set_cr(cr_no_alignment);
+ else {
+ /*
+ * We're about to disable the alignment trap and return to
+ * user space. But if an interrupt occurs before actually
+ * reaching user space, then the IRQ vector entry code will
+ * notice that we were still in kernel space and therefore
+ * the alignment trap won't be re-enabled in that case as it
+ * is presumed to be always on from kernel space.
+ * Let's prevent that race by disabling interrupts here (they
+ * are disabled on the way back to user space anyway in
+ * entry-common.S) and disable the alignment trap only if
+ * there is no work pending for this thread.
+ */
+ raw_local_irq_disable();
+ if (!(current_thread_info()->flags & _TIF_WORK_MASK))
+ set_cr(cr_no_alignment);
+ }
return 0;
}
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index ab50627..17e7b0b 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -204,8 +204,12 @@
/*
* Don't allow RAM to be mapped - this causes problems with ARMv6+
*/
- if (WARN_ON(pfn_valid(pfn)))
- return NULL;
+ if (pfn_valid(pfn)) {
+ printk(KERN_WARNING "BUG: Your driver calls ioremap() on system memory. This leads\n"
+ KERN_WARNING "to architecturally unpredictable behaviour on ARMv6+, and ioremap()\n"
+ KERN_WARNING "will fail in the next kernel release. Please fix your driver.\n");
+ WARN_ON(1);
+ }
type = get_mem_type(mtype);
if (!type)
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 6e1c4f6..e8ed9dc 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -15,6 +15,7 @@
#include <linux/nodemask.h>
#include <linux/memblock.h>
#include <linux/sort.h>
+#include <linux/fs.h>
#include <asm/cputype.h>
#include <asm/sections.h>
@@ -246,6 +247,9 @@
.domain = DOMAIN_USER,
},
[MT_MEMORY] = {
+ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+ L_PTE_WRITE | L_PTE_EXEC,
+ .prot_l1 = PMD_TYPE_TABLE,
.prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
.domain = DOMAIN_KERNEL,
},
@@ -254,6 +258,9 @@
.domain = DOMAIN_KERNEL,
},
[MT_MEMORY_NONCACHED] = {
+ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+ L_PTE_WRITE | L_PTE_EXEC | L_PTE_MT_BUFFERABLE,
+ .prot_l1 = PMD_TYPE_TABLE,
.prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
.domain = DOMAIN_KERNEL,
},
@@ -411,9 +418,12 @@
* Enable CPU-specific coherency if supported.
* (Only available on XSC3 at the moment.)
*/
- if (arch_is_coherent() && cpu_is_xsc3())
+ if (arch_is_coherent() && cpu_is_xsc3()) {
mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S;
-
+ mem_types[MT_MEMORY].prot_pte |= L_PTE_SHARED;
+ mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_S;
+ mem_types[MT_MEMORY_NONCACHED].prot_pte |= L_PTE_SHARED;
+ }
/*
* ARMv6 and above have extended page tables.
*/
@@ -438,7 +448,9 @@
mem_types[MT_DEVICE_CACHED].prot_sect |= PMD_SECT_S;
mem_types[MT_DEVICE_CACHED].prot_pte |= L_PTE_SHARED;
mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S;
+ mem_types[MT_MEMORY].prot_pte |= L_PTE_SHARED;
mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_S;
+ mem_types[MT_MEMORY_NONCACHED].prot_pte |= L_PTE_SHARED;
#endif
}
@@ -475,6 +487,8 @@
mem_types[MT_LOW_VECTORS].prot_l1 |= ecc_mask;
mem_types[MT_HIGH_VECTORS].prot_l1 |= ecc_mask;
mem_types[MT_MEMORY].prot_sect |= ecc_mask | cp->pmd;
+ mem_types[MT_MEMORY].prot_pte |= kern_pgprot;
+ mem_types[MT_MEMORY_NONCACHED].prot_sect |= ecc_mask;
mem_types[MT_ROM].prot_sect |= cp->pmd;
switch (cp->pmd) {
@@ -498,6 +512,19 @@
}
}
+#ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE
+pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
+ unsigned long size, pgprot_t vma_prot)
+{
+ if (!pfn_valid(pfn))
+ return pgprot_noncached(vma_prot);
+ else if (file->f_flags & O_SYNC)
+ return pgprot_writecombine(vma_prot);
+ return vma_prot;
+}
+EXPORT_SYMBOL(phys_mem_access_prot);
+#endif
+
#define vectors_base() (vectors_high() ? 0xffff0000 : 0)
static void __init *early_alloc(unsigned long sz)
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index 6a8506d..197f21b 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -186,13 +186,14 @@
* It is assumed that:
* - cache type register is implemented
*/
-__v7_setup:
+__v7_ca9mp_setup:
#ifdef CONFIG_SMP
mrc p15, 0, r0, c1, c0, 1
tst r0, #(1 << 6) @ SMP/nAMP mode enabled?
orreq r0, r0, #(1 << 6) | (1 << 0) @ Enable SMP/nAMP mode and
mcreq p15, 0, r0, c1, c0, 1 @ TLB ops broadcasting
#endif
+__v7_setup:
adr r12, __v7_setup_stack @ the local stack
stmia r12, {r0-r5, r7, r9, r11, lr}
bl v7_flush_dcache_all
@@ -201,11 +202,16 @@
mrc p15, 0, r0, c0, c0, 0 @ read main ID register
and r10, r0, #0xff000000 @ ARM?
teq r10, #0x41000000
- bne 2f
+ bne 3f
and r5, r0, #0x00f00000 @ variant
and r6, r0, #0x0000000f @ revision
- orr r0, r6, r5, lsr #20-4 @ combine variant and revision
+ orr r6, r6, r5, lsr #20-4 @ combine variant and revision
+ ubfx r0, r0, #4, #12 @ primary part number
+ /* Cortex-A8 Errata */
+ ldr r10, =0x00000c08 @ Cortex-A8 primary part number
+ teq r0, r10
+ bne 2f
#ifdef CONFIG_ARM_ERRATA_430973
teq r5, #0x00100000 @ only present in r1p*
mrceq p15, 0, r10, c1, c0, 1 @ read aux control register
@@ -213,21 +219,50 @@
mcreq p15, 0, r10, c1, c0, 1 @ write aux control register
#endif
#ifdef CONFIG_ARM_ERRATA_458693
- teq r0, #0x20 @ only present in r2p0
+ teq r6, #0x20 @ only present in r2p0
mrceq p15, 0, r10, c1, c0, 1 @ read aux control register
orreq r10, r10, #(1 << 5) @ set L1NEON to 1
orreq r10, r10, #(1 << 9) @ set PLDNOP to 1
mcreq p15, 0, r10, c1, c0, 1 @ write aux control register
#endif
#ifdef CONFIG_ARM_ERRATA_460075
- teq r0, #0x20 @ only present in r2p0
+ teq r6, #0x20 @ only present in r2p0
mrceq p15, 1, r10, c9, c0, 2 @ read L2 cache aux ctrl register
tsteq r10, #1 << 22
orreq r10, r10, #(1 << 22) @ set the Write Allocate disable bit
mcreq p15, 1, r10, c9, c0, 2 @ write the L2 cache aux ctrl register
#endif
+ b 3f
-2: mov r10, #0
+ /* Cortex-A9 Errata */
+2: ldr r10, =0x00000c09 @ Cortex-A9 primary part number
+ teq r0, r10
+ bne 3f
+#ifdef CONFIG_ARM_ERRATA_742230
+ cmp r6, #0x22 @ only present up to r2p2
+ mrcle p15, 0, r10, c15, c0, 1 @ read diagnostic register
+ orrle r10, r10, #1 << 4 @ set bit #4
+ mcrle p15, 0, r10, c15, c0, 1 @ write diagnostic register
+#endif
+#ifdef CONFIG_ARM_ERRATA_742231
+ teq r6, #0x20 @ present in r2p0
+ teqne r6, #0x21 @ present in r2p1
+ teqne r6, #0x22 @ present in r2p2
+ mrceq p15, 0, r10, c15, c0, 1 @ read diagnostic register
+ orreq r10, r10, #1 << 12 @ set bit #12
+ orreq r10, r10, #1 << 22 @ set bit #22
+ mcreq p15, 0, r10, c15, c0, 1 @ write diagnostic register
+#endif
+#ifdef CONFIG_ARM_ERRATA_743622
+ teq r6, #0x20 @ present in r2p0
+ teqne r6, #0x21 @ present in r2p1
+ teqne r6, #0x22 @ present in r2p2
+ mrceq p15, 0, r10, c15, c0, 1 @ read diagnostic register
+ orreq r10, r10, #1 << 6 @ set bit #6
+ mcreq p15, 0, r10, c15, c0, 1 @ write diagnostic register
+#endif
+
+3: mov r10, #0
#ifdef HARVARD_CACHE
mcr p15, 0, r10, c7, c5, 0 @ I+BTB cache invalidate
#endif
@@ -323,6 +358,29 @@
.section ".proc.info.init", #alloc, #execinstr
+ .type __v7_ca9mp_proc_info, #object
+__v7_ca9mp_proc_info:
+ .long 0x410fc090 @ Required ID value
+ .long 0xff0ffff0 @ Mask for ID
+ .long PMD_TYPE_SECT | \
+ PMD_SECT_AP_WRITE | \
+ PMD_SECT_AP_READ | \
+ PMD_FLAGS
+ .long PMD_TYPE_SECT | \
+ PMD_SECT_XN | \
+ PMD_SECT_AP_WRITE | \
+ PMD_SECT_AP_READ
+ b __v7_ca9mp_setup
+ .long cpu_arch_name
+ .long cpu_elf_name
+ .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_TLS
+ .long cpu_v7_name
+ .long v7_processor_functions
+ .long v7wbi_tlb_fns
+ .long v6_user_fns
+ .long v7_cache_fns
+ .size __v7_ca9mp_proc_info, . - __v7_ca9mp_proc_info
+
/*
* Match any ARMv7 processor core.
*/
diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c
index 0691176..72e09eb 100644
--- a/arch/arm/oprofile/common.c
+++ b/arch/arm/oprofile/common.c
@@ -102,6 +102,7 @@
if (IS_ERR(pevent)) {
ret = PTR_ERR(pevent);
} else if (pevent->state != PERF_EVENT_STATE_ACTIVE) {
+ perf_event_release_kernel(pevent);
pr_warning("oprofile: failed to enable event %d "
"on CPU %d\n", event, cpu);
ret = -EBUSY;
@@ -365,6 +366,7 @@
ret = init_driverfs();
if (ret) {
kfree(counter_config);
+ counter_config = NULL;
return ret;
}
@@ -402,7 +404,6 @@
struct perf_event *event;
if (*perf_events) {
- exit_driverfs();
for_each_possible_cpu(cpu) {
for (id = 0; id < perf_num_counters; ++id) {
event = perf_events[cpu][id];
@@ -413,8 +414,10 @@
}
}
- if (counter_config)
+ if (counter_config) {
kfree(counter_config);
+ exit_driverfs();
+ }
}
#else
int __init oprofile_arch_init(struct oprofile_operations *ops)
diff --git a/arch/arm/plat-nomadik/timer.c b/arch/arm/plat-nomadik/timer.c
index ea3ca86..aedf9c1 100644
--- a/arch/arm/plat-nomadik/timer.c
+++ b/arch/arm/plat-nomadik/timer.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-nomadik/timer.c
+ * linux/arch/arm/plat-nomadik/timer.c
*
* Copyright (C) 2008 STMicroelectronics
* Copyright (C) 2010 Alessandro Rubini
@@ -75,7 +75,7 @@
cr = readl(mtu_base + MTU_CR(1));
writel(0, mtu_base + MTU_LR(1));
writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(1));
- writel(0x2, mtu_base + MTU_IMSC);
+ writel(1 << 1, mtu_base + MTU_IMSC);
break;
case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_UNUSED:
@@ -131,25 +131,23 @@
{
unsigned long rate;
struct clk *clk0;
- struct clk *clk1;
- u32 cr;
+ u32 cr = MTU_CRn_32BITS;
clk0 = clk_get_sys("mtu0", NULL);
BUG_ON(IS_ERR(clk0));
- clk1 = clk_get_sys("mtu1", NULL);
- BUG_ON(IS_ERR(clk1));
-
clk_enable(clk0);
- clk_enable(clk1);
/*
- * Tick rate is 2.4MHz for Nomadik and 110MHz for ux500:
- * use a divide-by-16 counter if it's more than 16MHz
+ * Tick rate is 2.4MHz for Nomadik and 2.4Mhz, 100MHz or 133 MHz
+ * for ux500.
+ * Use a divide-by-16 counter if the tick rate is more than 32MHz.
+ * At 32 MHz, the timer (with 32 bit counter) can be programmed
+ * to wake-up at a max 127s a head in time. Dividing a 2.4 MHz timer
+ * with 16 gives too low timer resolution.
*/
- cr = MTU_CRn_32BITS;;
rate = clk_get_rate(clk0);
- if (rate > 16 << 20) {
+ if (rate > 32000000) {
rate /= 16;
cr |= MTU_CRn_PRESCALE_16;
} else {
@@ -170,15 +168,8 @@
pr_err("timer: failed to initialize clock source %s\n",
nmdk_clksrc.name);
- /* Timer 1 is used for events, fix according to rate */
- cr = MTU_CRn_32BITS;
- rate = clk_get_rate(clk1);
- if (rate > 16 << 20) {
- rate /= 16;
- cr |= MTU_CRn_PRESCALE_16;
- } else {
- cr |= MTU_CRn_PRESCALE_1;
- }
+ /* Timer 1 is used for events */
+
clockevents_calc_mult_shift(&nmdk_clkevt, rate, MTU_MIN_RANGE);
writel(cr | MTU_CRn_ONESHOT, mtu_base + MTU_CR(1)); /* off, currently */
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index e39a417..a92cb49 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -33,7 +33,7 @@
config OMAP_DEBUG_LEDS
bool
depends on OMAP_DEBUG_DEVICES
- default y if LEDS
+ default y if LEDS_CLASS
config OMAP_RESET_CLOCKS
bool "Reset unused clocks during boot"
diff --git a/arch/arm/plat-omap/include/plat/mcbsp.h b/arch/arm/plat-omap/include/plat/mcbsp.h
index b4ff6a1..5b20103 100644
--- a/arch/arm/plat-omap/include/plat/mcbsp.h
+++ b/arch/arm/plat-omap/include/plat/mcbsp.h
@@ -30,6 +30,13 @@
#include <mach/hardware.h>
#include <plat/clock.h>
+/* macro for building platform_device for McBSP ports */
+#define OMAP_MCBSP_PLATFORM_DEVICE(port_nr) \
+static struct platform_device omap_mcbsp##port_nr = { \
+ .name = "omap-mcbsp-dai", \
+ .id = OMAP_MCBSP##port_nr, \
+}
+
#define OMAP7XX_MCBSP1_BASE 0xfffb1000
#define OMAP7XX_MCBSP2_BASE 0xfffb1800
diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c
index a202a2c..6cd151b 100644
--- a/arch/arm/plat-omap/iommu.c
+++ b/arch/arm/plat-omap/iommu.c
@@ -320,6 +320,7 @@
if ((start <= da) && (da < start + bytes)) {
dev_dbg(obj->dev, "%s: %08x<=%08x(%x)\n",
__func__, start, da, bytes);
+ iotlb_load_cr(obj, &cr);
iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY);
}
}
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index e31496e..0c8612f 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -156,7 +156,7 @@
/* Writing zero to RSYNC_ERR clears the IRQ */
MCBSP_WRITE(mcbsp_rx, SPCR1, MCBSP_READ_CACHE(mcbsp_rx, SPCR1));
} else {
- complete(&mcbsp_rx->tx_irq_completion);
+ complete(&mcbsp_rx->rx_irq_completion);
}
return IRQ_HANDLED;
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
index 226b2e8..10b3b4c 100644
--- a/arch/arm/plat-omap/sram.c
+++ b/arch/arm/plat-omap/sram.c
@@ -220,20 +220,7 @@
if (omap_sram_size == 0)
return;
- if (cpu_is_omap24xx()) {
- omap_sram_io_desc[0].virtual = OMAP2_SRAM_VA;
-
- base = OMAP2_SRAM_PA;
- base = ROUND_DOWN(base, PAGE_SIZE);
- omap_sram_io_desc[0].pfn = __phys_to_pfn(base);
- }
-
if (cpu_is_omap34xx()) {
- omap_sram_io_desc[0].virtual = OMAP3_SRAM_VA;
- base = OMAP3_SRAM_PA;
- base = ROUND_DOWN(base, PAGE_SIZE);
- omap_sram_io_desc[0].pfn = __phys_to_pfn(base);
-
/*
* SRAM must be marked as non-cached on OMAP3 since the
* CORE DPLL M2 divider change code (in SRAM) runs with the
@@ -244,13 +231,11 @@
omap_sram_io_desc[0].type = MT_MEMORY_NONCACHED;
}
- if (cpu_is_omap44xx()) {
- omap_sram_io_desc[0].virtual = OMAP4_SRAM_VA;
- base = OMAP4_SRAM_PA;
- base = ROUND_DOWN(base, PAGE_SIZE);
- omap_sram_io_desc[0].pfn = __phys_to_pfn(base);
- }
- omap_sram_io_desc[0].length = 1024 * 1024; /* Use section desc */
+ omap_sram_io_desc[0].virtual = omap_sram_base;
+ base = omap_sram_start;
+ base = ROUND_DOWN(base, PAGE_SIZE);
+ omap_sram_io_desc[0].pfn = __phys_to_pfn(base);
+ omap_sram_io_desc[0].length = ROUND_DOWN(omap_sram_size, PAGE_SIZE);
iotable_init(omap_sram_io_desc, ARRAY_SIZE(omap_sram_io_desc));
printk(KERN_INFO "SRAM: Mapped pa 0x%08lx to va 0x%08lx size: 0x%lx\n",
diff --git a/arch/arm/plat-s3c24xx/devs.c b/arch/arm/plat-s3c24xx/devs.c
index 452e184..2f91057 100644
--- a/arch/arm/plat-s3c24xx/devs.c
+++ b/arch/arm/plat-s3c24xx/devs.c
@@ -247,7 +247,7 @@
static u64 s3c_device_iis_dmamask = 0xffffffffUL;
struct platform_device s3c_device_iis = {
- .name = "s3c2410-iis",
+ .name = "s3c24xx-iis",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_iis_resource),
.resource = s3c_iis_resource,
@@ -259,6 +259,21 @@
EXPORT_SYMBOL(s3c_device_iis);
+/* ASoC PCM DMA */
+
+static u64 s3c_device_audio_dmamask = 0xffffffffUL;
+
+struct platform_device s3c_device_pcm = {
+ .name = "s3c24xx-pcm-audio",
+ .id = -1,
+ .dev = {
+ .dma_mask = &s3c_device_audio_dmamask,
+ .coherent_dma_mask = 0xffffffffUL
+ }
+};
+
+EXPORT_SYMBOL(s3c_device_pcm);
+
/* RTC */
static struct resource s3c_rtc_resource[] = {
@@ -481,19 +496,30 @@
},
};
-static u64 s3c_device_ac97_dmamask = 0xffffffffUL;
-
struct platform_device s3c_device_ac97 = {
.name = "s3c-ac97",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_ac97_resource),
.resource = s3c_ac97_resource,
.dev = {
- .dma_mask = &s3c_device_ac97_dmamask,
+ .dma_mask = &s3c_device_audio_dmamask,
.coherent_dma_mask = 0xffffffffUL
}
};
EXPORT_SYMBOL(s3c_device_ac97);
+/* ASoC I2S */
+
+struct platform_device s3c2412_device_iis = {
+ .name = "s3c2412-iis",
+ .id = -1,
+ .dev = {
+ .dma_mask = &s3c_device_audio_dmamask,
+ .coherent_dma_mask = 0xffffffffUL
+ }
+};
+
+EXPORT_SYMBOL(s3c2412_device_iis);
+
#endif // CONFIG_CPU_S32440
diff --git a/arch/arm/plat-s5p/dev-fimc0.c b/arch/arm/plat-s5p/dev-fimc0.c
index d3f1a9b..608770f 100644
--- a/arch/arm/plat-s5p/dev-fimc0.c
+++ b/arch/arm/plat-s5p/dev-fimc0.c
@@ -10,6 +10,7 @@
*/
#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
@@ -18,7 +19,7 @@
static struct resource s5p_fimc0_resource[] = {
[0] = {
.start = S5P_PA_FIMC0,
- .end = S5P_PA_FIMC0 + SZ_1M - 1,
+ .end = S5P_PA_FIMC0 + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -28,9 +29,15 @@
},
};
+static u64 s5p_fimc0_dma_mask = DMA_BIT_MASK(32);
+
struct platform_device s5p_device_fimc0 = {
.name = "s5p-fimc",
.id = 0,
.num_resources = ARRAY_SIZE(s5p_fimc0_resource),
.resource = s5p_fimc0_resource,
+ .dev = {
+ .dma_mask = &s5p_fimc0_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
};
diff --git a/arch/arm/plat-s5p/dev-fimc1.c b/arch/arm/plat-s5p/dev-fimc1.c
index 41bd698..76e3a97 100644
--- a/arch/arm/plat-s5p/dev-fimc1.c
+++ b/arch/arm/plat-s5p/dev-fimc1.c
@@ -10,6 +10,7 @@
*/
#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
@@ -18,7 +19,7 @@
static struct resource s5p_fimc1_resource[] = {
[0] = {
.start = S5P_PA_FIMC1,
- .end = S5P_PA_FIMC1 + SZ_1M - 1,
+ .end = S5P_PA_FIMC1 + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -28,9 +29,15 @@
},
};
+static u64 s5p_fimc1_dma_mask = DMA_BIT_MASK(32);
+
struct platform_device s5p_device_fimc1 = {
.name = "s5p-fimc",
.id = 1,
.num_resources = ARRAY_SIZE(s5p_fimc1_resource),
.resource = s5p_fimc1_resource,
+ .dev = {
+ .dma_mask = &s5p_fimc1_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
};
diff --git a/arch/arm/plat-s5p/dev-fimc2.c b/arch/arm/plat-s5p/dev-fimc2.c
index dfddeda..24d2981 100644
--- a/arch/arm/plat-s5p/dev-fimc2.c
+++ b/arch/arm/plat-s5p/dev-fimc2.c
@@ -10,6 +10,7 @@
*/
#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
@@ -18,7 +19,7 @@
static struct resource s5p_fimc2_resource[] = {
[0] = {
.start = S5P_PA_FIMC2,
- .end = S5P_PA_FIMC2 + SZ_1M - 1,
+ .end = S5P_PA_FIMC2 + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -28,9 +29,15 @@
},
};
+static u64 s5p_fimc2_dma_mask = DMA_BIT_MASK(32);
+
struct platform_device s5p_device_fimc2 = {
.name = "s5p-fimc",
.id = 2,
.num_resources = ARRAY_SIZE(s5p_fimc2_resource),
.resource = s5p_fimc2_resource,
+ .dev = {
+ .dma_mask = &s5p_fimc2_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
};
diff --git a/arch/arm/plat-samsung/adc.c b/arch/arm/plat-samsung/adc.c
index 04d9521..e8f2be2 100644
--- a/arch/arm/plat-samsung/adc.c
+++ b/arch/arm/plat-samsung/adc.c
@@ -435,7 +435,6 @@
static int s3c_adc_resume(struct platform_device *pdev)
{
struct adc_device *adc = platform_get_drvdata(pdev);
- unsigned long flags;
clk_enable(adc->clk);
enable_irq(adc->irq);
diff --git a/arch/arm/plat-samsung/clock.c b/arch/arm/plat-samsung/clock.c
index 90a2051..e8d20b0 100644
--- a/arch/arm/plat-samsung/clock.c
+++ b/arch/arm/plat-samsung/clock.c
@@ -48,6 +48,9 @@
#include <plat/clock.h>
#include <plat/cpu.h>
+#include <linux/serial_core.h>
+#include <plat/regs-serial.h> /* for s3c24xx_uart_devs */
+
/* clock information */
static LIST_HEAD(clocks);
@@ -65,6 +68,28 @@
return 0;
}
+static int dev_is_s3c_uart(struct device *dev)
+{
+ struct platform_device **pdev = s3c24xx_uart_devs;
+ int i;
+ for (i = 0; i < ARRAY_SIZE(s3c24xx_uart_devs); i++, pdev++)
+ if (*pdev && dev == &(*pdev)->dev)
+ return 1;
+ return 0;
+}
+
+/*
+ * Serial drivers call get_clock() very early, before platform bus
+ * has been set up, this requires a special check to let them get
+ * a proper clock
+ */
+
+static int dev_is_platform_device(struct device *dev)
+{
+ return dev->bus == &platform_bus_type ||
+ (dev->bus == NULL && dev_is_s3c_uart(dev));
+}
+
/* Clock API calls */
struct clk *clk_get(struct device *dev, const char *id)
@@ -73,7 +98,7 @@
struct clk *clk = ERR_PTR(-ENOENT);
int idno;
- if (dev == NULL || dev->bus != &platform_bus_type)
+ if (dev == NULL || !dev_is_platform_device(dev))
idno = -1;
else
idno = to_platform_device(dev)->id;
diff --git a/arch/arm/plat-samsung/gpio-config.c b/arch/arm/plat-samsung/gpio-config.c
index 57b68a5..e3d41ea 100644
--- a/arch/arm/plat-samsung/gpio-config.c
+++ b/arch/arm/plat-samsung/gpio-config.c
@@ -273,13 +273,13 @@
if (!chip)
return -EINVAL;
- off = chip->chip.base - pin;
+ off = pin - chip->chip.base;
shift = off * 2;
reg = chip->base + 0x0C;
drvstr = __raw_readl(reg);
- drvstr = 0xffff & (0x3 << shift);
drvstr = drvstr >> shift;
+ drvstr &= 0x3;
return (__force s5p_gpio_drvstr_t)drvstr;
}
@@ -296,11 +296,12 @@
if (!chip)
return -EINVAL;
- off = chip->chip.base - pin;
+ off = pin - chip->chip.base;
shift = off * 2;
reg = chip->base + 0x0C;
tmp = __raw_readl(reg);
+ tmp &= ~(0x3 << shift);
tmp |= drvstr << shift;
__raw_writel(tmp, reg);
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index 85f6f23..a9fecd6 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -32,6 +32,8 @@
extern struct platform_device s3c64xx_device_spi0;
extern struct platform_device s3c64xx_device_spi1;
+extern struct platform_device s3c_device_pcm;
+
extern struct platform_device s3c64xx_device_pcm0;
extern struct platform_device s3c64xx_device_pcm1;
diff --git a/arch/arm/plat-samsung/include/plat/gpio-cfg.h b/arch/arm/plat-samsung/include/plat/gpio-cfg.h
index db4112c..1c6b929 100644
--- a/arch/arm/plat-samsung/include/plat/gpio-cfg.h
+++ b/arch/arm/plat-samsung/include/plat/gpio-cfg.h
@@ -143,12 +143,12 @@
/* Define values for the drvstr available for each gpio pin.
*
* These values control the value of the output signal driver strength,
- * configurable on most pins on the S5C series.
+ * configurable on most pins on the S5P series.
*/
-#define S5P_GPIO_DRVSTR_LV1 ((__force s5p_gpio_drvstr_t)0x00)
-#define S5P_GPIO_DRVSTR_LV2 ((__force s5p_gpio_drvstr_t)0x01)
-#define S5P_GPIO_DRVSTR_LV3 ((__force s5p_gpio_drvstr_t)0x10)
-#define S5P_GPIO_DRVSTR_LV4 ((__force s5p_gpio_drvstr_t)0x11)
+#define S5P_GPIO_DRVSTR_LV1 ((__force s5p_gpio_drvstr_t)0x0)
+#define S5P_GPIO_DRVSTR_LV2 ((__force s5p_gpio_drvstr_t)0x2)
+#define S5P_GPIO_DRVSTR_LV3 ((__force s5p_gpio_drvstr_t)0x1)
+#define S5P_GPIO_DRVSTR_LV4 ((__force s5p_gpio_drvstr_t)0x3)
/**
* s5c_gpio_get_drvstr() - get the driver streght value of a gpio pin
diff --git a/arch/avr32/kernel/module.c b/arch/avr32/kernel/module.c
index 98f94d0..a727f54 100644
--- a/arch/avr32/kernel/module.c
+++ b/arch/avr32/kernel/module.c
@@ -314,10 +314,9 @@
vfree(module->arch.syminfo);
module->arch.syminfo = NULL;
- return module_bug_finalize(hdr, sechdrs, module);
+ return 0;
}
void module_arch_cleanup(struct module *module)
{
- module_bug_cleanup(module);
}
diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c
index 0974c0e..bab0129 100644
--- a/arch/frv/kernel/signal.c
+++ b/arch/frv/kernel/signal.c
@@ -121,6 +121,9 @@
struct user_context *user = current->thread.user;
unsigned long tbr, psr;
+ /* Always make any pending restarted system calls return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
tbr = user->i.tbr;
psr = user->i.psr;
if (copy_from_user(user, &sc->sc_context, sizeof(sc->sc_context)))
@@ -250,6 +253,8 @@
struct sigframe __user *frame;
int rsig;
+ set_fs(USER_DS);
+
frame = get_sigframe(ka, sizeof(*frame));
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
@@ -293,22 +298,23 @@
(unsigned long) (frame->retcode + 2));
}
- /* set up registers for signal handler */
- __frame->sp = (unsigned long) frame;
- __frame->lr = (unsigned long) &frame->retcode;
- __frame->gr8 = sig;
-
+ /* Set up registers for the signal handler */
if (current->personality & FDPIC_FUNCPTRS) {
struct fdpic_func_descriptor __user *funcptr =
(struct fdpic_func_descriptor __user *) ka->sa.sa_handler;
- __get_user(__frame->pc, &funcptr->text);
- __get_user(__frame->gr15, &funcptr->GOT);
+ struct fdpic_func_descriptor desc;
+ if (copy_from_user(&desc, funcptr, sizeof(desc)))
+ goto give_sigsegv;
+ __frame->pc = desc.text;
+ __frame->gr15 = desc.GOT;
} else {
__frame->pc = (unsigned long) ka->sa.sa_handler;
__frame->gr15 = 0;
}
- set_fs(USER_DS);
+ __frame->sp = (unsigned long) frame;
+ __frame->lr = (unsigned long) &frame->retcode;
+ __frame->gr8 = sig;
/* the tracer may want to single-step inside the handler */
if (test_thread_flag(TIF_SINGLESTEP))
@@ -323,7 +329,7 @@
return 0;
give_sigsegv:
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
return -EFAULT;
} /* end setup_frame() */
@@ -338,6 +344,8 @@
struct rt_sigframe __user *frame;
int rsig;
+ set_fs(USER_DS);
+
frame = get_sigframe(ka, sizeof(*frame));
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
@@ -392,22 +400,23 @@
}
/* Set up registers for signal handler */
- __frame->sp = (unsigned long) frame;
- __frame->lr = (unsigned long) &frame->retcode;
- __frame->gr8 = sig;
- __frame->gr9 = (unsigned long) &frame->info;
-
if (current->personality & FDPIC_FUNCPTRS) {
struct fdpic_func_descriptor __user *funcptr =
(struct fdpic_func_descriptor __user *) ka->sa.sa_handler;
- __get_user(__frame->pc, &funcptr->text);
- __get_user(__frame->gr15, &funcptr->GOT);
+ struct fdpic_func_descriptor desc;
+ if (copy_from_user(&desc, funcptr, sizeof(desc)))
+ goto give_sigsegv;
+ __frame->pc = desc.text;
+ __frame->gr15 = desc.GOT;
} else {
__frame->pc = (unsigned long) ka->sa.sa_handler;
__frame->gr15 = 0;
}
- set_fs(USER_DS);
+ __frame->sp = (unsigned long) frame;
+ __frame->lr = (unsigned long) &frame->retcode;
+ __frame->gr8 = sig;
+ __frame->gr9 = (unsigned long) &frame->info;
/* the tracer may want to single-step inside the handler */
if (test_thread_flag(TIF_SINGLESTEP))
@@ -422,7 +431,7 @@
return 0;
give_sigsegv:
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
return -EFAULT;
} /* end setup_rt_frame() */
@@ -437,7 +446,7 @@
int ret;
/* Are we from a system call? */
- if (in_syscall(__frame)) {
+ if (__frame->syscallno != -1) {
/* If so, check system call restarting.. */
switch (__frame->gr8) {
case -ERESTART_RESTARTBLOCK:
@@ -456,6 +465,7 @@
__frame->gr8 = __frame->orig_gr8;
__frame->pc -= 4;
}
+ __frame->syscallno = -1;
}
/* Set up the stack frame */
@@ -538,10 +548,11 @@
break;
case -ERESTART_RESTARTBLOCK:
- __frame->gr8 = __NR_restart_syscall;
+ __frame->gr7 = __NR_restart_syscall;
__frame->pc -= 4;
break;
}
+ __frame->syscallno = -1;
}
/* if there's no signal to deliver, we just put the saved sigmask
diff --git a/arch/h8300/kernel/module.c b/arch/h8300/kernel/module.c
index 0865e29..db4953d 100644
--- a/arch/h8300/kernel/module.c
+++ b/arch/h8300/kernel/module.c
@@ -112,10 +112,9 @@
const Elf_Shdr *sechdrs,
struct module *me)
{
- return module_bug_finalize(hdr, sechdrs, me);
+ return 0;
}
void module_arch_cleanup(struct module *mod)
{
- module_bug_cleanup(mod);
}
diff --git a/arch/ia64/include/asm/compat.h b/arch/ia64/include/asm/compat.h
index f90edc8..9301a28 100644
--- a/arch/ia64/include/asm/compat.h
+++ b/arch/ia64/include/asm/compat.h
@@ -199,7 +199,7 @@
}
static __inline__ void __user *
-compat_alloc_user_space (long len)
+arch_compat_alloc_user_space (long len)
{
struct pt_regs *regs = task_pt_regs(current);
return (void __user *) (((regs->r12 & 0xffffffff) & -16) - len);
diff --git a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S
index 3567d54..331d42b 100644
--- a/arch/ia64/kernel/fsys.S
+++ b/arch/ia64/kernel/fsys.S
@@ -420,22 +420,31 @@
;;
RSM_PSR_I(p0, r18, r19) // mask interrupt delivery
- mov ar.ccv=0
andcm r14=r14,r17 // filter out SIGKILL & SIGSTOP
+ mov r8=EINVAL // default to EINVAL
#ifdef CONFIG_SMP
- mov r17=1
+ // __ticket_spin_trylock(r31)
+ ld4 r17=[r31]
;;
- cmpxchg4.acq r18=[r31],r17,ar.ccv // try to acquire the lock
- mov r8=EINVAL // default to EINVAL
+ mov.m ar.ccv=r17
+ extr.u r9=r17,17,15
+ adds r19=1,r17
+ extr.u r18=r17,0,15
;;
+ cmp.eq p6,p7=r9,r18
+ ;;
+(p6) cmpxchg4.acq r9=[r31],r19,ar.ccv
+(p6) dep.z r20=r19,1,15 // next serving ticket for unlock
+(p7) br.cond.spnt.many .lock_contention
+ ;;
+ cmp4.eq p0,p7=r9,r17
+ adds r31=2,r31
+(p7) br.cond.spnt.many .lock_contention
ld8 r3=[r2] // re-read current->blocked now that we hold the lock
- cmp4.ne p6,p0=r18,r0
-(p6) br.cond.spnt.many .lock_contention
;;
#else
ld8 r3=[r2] // re-read current->blocked now that we hold the lock
- mov r8=EINVAL // default to EINVAL
#endif
add r18=IA64_TASK_PENDING_OFFSET+IA64_SIGPENDING_SIGNAL_OFFSET,r16
add r19=IA64_TASK_SIGNAL_OFFSET,r16
@@ -490,7 +499,9 @@
(p6) br.cond.spnt.few 1b // yes -> retry
#ifdef CONFIG_SMP
- st4.rel [r31]=r0 // release the lock
+ // __ticket_spin_unlock(r31)
+ st2.rel [r31]=r20
+ mov r20=0 // i must not leak kernel bits...
#endif
SSM_PSR_I(p0, p9, r31)
;;
@@ -512,7 +523,8 @@
.sig_pending:
#ifdef CONFIG_SMP
- st4.rel [r31]=r0 // release the lock
+ // __ticket_spin_unlock(r31)
+ st2.rel [r31]=r20 // release the lock
#endif
SSM_PSR_I(p0, p9, r17)
;;
diff --git a/arch/m32r/include/asm/elf.h b/arch/m32r/include/asm/elf.h
index 2f85412..b8da7d0 100644
--- a/arch/m32r/include/asm/elf.h
+++ b/arch/m32r/include/asm/elf.h
@@ -82,9 +82,9 @@
* These are used to set parameters in the core dumps.
*/
#define ELF_CLASS ELFCLASS32
-#if defined(__LITTLE_ENDIAN)
+#if defined(__LITTLE_ENDIAN__)
#define ELF_DATA ELFDATA2LSB
-#elif defined(__BIG_ENDIAN)
+#elif defined(__BIG_ENDIAN__)
#define ELF_DATA ELFDATA2MSB
#else
#error no endian defined
diff --git a/arch/m32r/include/asm/signal.h b/arch/m32r/include/asm/signal.h
index 9c1acb2..b2eeb0d 100644
--- a/arch/m32r/include/asm/signal.h
+++ b/arch/m32r/include/asm/signal.h
@@ -157,7 +157,6 @@
#undef __HAVE_ARCH_SIG_BITOPS
struct pt_regs;
-extern int do_signal(struct pt_regs *regs, sigset_t *oldset);
#define ptrace_signal_deliver(regs, cookie) do { } while (0)
diff --git a/arch/m32r/include/asm/unistd.h b/arch/m32r/include/asm/unistd.h
index 7612577..c705456 100644
--- a/arch/m32r/include/asm/unistd.h
+++ b/arch/m32r/include/asm/unistd.h
@@ -351,6 +351,7 @@
#define __ARCH_WANT_SYS_OLD_GETRLIMIT /*will be unused*/
#define __ARCH_WANT_SYS_OLDUMOUNT
#define __ARCH_WANT_SYS_RT_SIGACTION
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
#define __IGNORE_lchown
#define __IGNORE_setuid
diff --git a/arch/m32r/kernel/.gitignore b/arch/m32r/kernel/.gitignore
new file mode 100644
index 0000000..c5f676c
--- /dev/null
+++ b/arch/m32r/kernel/.gitignore
@@ -0,0 +1 @@
+vmlinux.lds
diff --git a/arch/m32r/kernel/entry.S b/arch/m32r/kernel/entry.S
index 4038698..225412b 100644
--- a/arch/m32r/kernel/entry.S
+++ b/arch/m32r/kernel/entry.S
@@ -235,10 +235,9 @@
work_notifysig: ; deal with pending signals and
; notify-resume requests
mv r0, sp ; arg1 : struct pt_regs *regs
- ldi r1, #0 ; arg2 : sigset_t *oldset
- mv r2, r9 ; arg3 : __u32 thread_info_flags
+ mv r1, r9 ; arg2 : __u32 thread_info_flags
bl do_notify_resume
- bra restore_all
+ bra resume_userspace
; perform syscall exit tracing
ALIGN
diff --git a/arch/m32r/kernel/ptrace.c b/arch/m32r/kernel/ptrace.c
index e555091..0021ade 100644
--- a/arch/m32r/kernel/ptrace.c
+++ b/arch/m32r/kernel/ptrace.c
@@ -592,16 +592,17 @@
if (access_process_vm(child, pc&~3, &insn, sizeof(insn), 0)
!= sizeof(insn))
- break;
+ return -EIO;
compute_next_pc(insn, pc, &next_pc, child);
if (next_pc & 0x80000000)
- break;
+ return -EIO;
if (embed_debug_trap(child, next_pc))
- break;
+ return -EIO;
invalidate_cache();
+ return 0;
}
void user_disable_single_step(struct task_struct *child)
diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c
index 144b0f1..a08697f 100644
--- a/arch/m32r/kernel/signal.c
+++ b/arch/m32r/kernel/signal.c
@@ -30,35 +30,6 @@
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-int do_signal(struct pt_regs *, sigset_t *);
-
-asmlinkage int
-sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize,
- unsigned long r2, unsigned long r3, unsigned long r4,
- unsigned long r5, unsigned long r6, struct pt_regs *regs)
-{
- sigset_t newset;
-
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(sigset_t))
- return -EINVAL;
-
- if (copy_from_user(&newset, unewset, sizeof(newset)))
- return -EFAULT;
- sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP));
-
- spin_lock_irq(¤t->sighand->siglock);
- current->saved_sigmask = current->blocked;
- current->blocked = newset;
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
- return -ERESTARTNOHAND;
-}
-
asmlinkage int
sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
unsigned long r2, unsigned long r3, unsigned long r4,
@@ -218,7 +189,7 @@
return (void __user *)((sp - frame_size) & -8ul);
}
-static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
@@ -275,22 +246,34 @@
current->comm, current->pid, frame, regs->pc);
#endif
- return;
+ return 0;
give_sigsegv:
force_sigsegv(sig, current);
+ return -EFAULT;
+}
+
+static int prev_insn(struct pt_regs *regs)
+{
+ u16 inst;
+ if (get_user(inst, (u16 __user *)(regs->bpc - 2)))
+ return -EFAULT;
+ if ((inst & 0xfff0) == 0x10f0) /* trap ? */
+ regs->bpc -= 2;
+ else
+ regs->bpc -= 4;
+ regs->syscall_nr = -1;
+ return 0;
}
/*
* OK, we're invoking a handler
*/
-static void
+static int
handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *oldset, struct pt_regs *regs)
{
- unsigned short inst;
-
/* Are we from a system call? */
if (regs->syscall_nr >= 0) {
/* If so, check system call restarting.. */
@@ -308,16 +291,14 @@
/* fallthrough */
case -ERESTARTNOINTR:
regs->r0 = regs->orig_r0;
- inst = *(unsigned short *)(regs->bpc - 2);
- if ((inst & 0xfff0) == 0x10f0) /* trap ? */
- regs->bpc -= 2;
- else
- regs->bpc -= 4;
+ if (prev_insn(regs) < 0)
+ return -EFAULT;
}
}
/* Set up the stack frame */
- setup_rt_frame(sig, ka, info, oldset, regs);
+ if (setup_rt_frame(sig, ka, info, oldset, regs))
+ return -EFAULT;
spin_lock_irq(¤t->sighand->siglock);
sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
@@ -325,6 +306,7 @@
sigaddset(¤t->blocked,sig);
recalc_sigpending();
spin_unlock_irq(¤t->sighand->siglock);
+ return 0;
}
/*
@@ -332,12 +314,12 @@
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake.
*/
-int do_signal(struct pt_regs *regs, sigset_t *oldset)
+static void do_signal(struct pt_regs *regs)
{
siginfo_t info;
int signr;
struct k_sigaction ka;
- unsigned short inst;
+ sigset_t *oldset;
/*
* We want the common case to go fast, which
@@ -346,12 +328,14 @@
* if so.
*/
if (!user_mode(regs))
- return 1;
+ return;
if (try_to_freeze())
goto no_signal;
- if (!oldset)
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = ¤t->saved_sigmask;
+ else
oldset = ¤t->blocked;
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
@@ -363,8 +347,10 @@
*/
/* Whee! Actually deliver the signal. */
- handle_signal(signr, &ka, &info, oldset, regs);
- return 1;
+ if (handle_signal(signr, &ka, &info, oldset, regs) == 0)
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+
+ return;
}
no_signal:
@@ -375,31 +361,24 @@
regs->r0 == -ERESTARTSYS ||
regs->r0 == -ERESTARTNOINTR) {
regs->r0 = regs->orig_r0;
- inst = *(unsigned short *)(regs->bpc - 2);
- if ((inst & 0xfff0) == 0x10f0) /* trap ? */
- regs->bpc -= 2;
- else
- regs->bpc -= 4;
- }
- if (regs->r0 == -ERESTART_RESTARTBLOCK){
+ prev_insn(regs);
+ } else if (regs->r0 == -ERESTART_RESTARTBLOCK){
regs->r0 = regs->orig_r0;
regs->r7 = __NR_restart_syscall;
- inst = *(unsigned short *)(regs->bpc - 2);
- if ((inst & 0xfff0) == 0x10f0) /* trap ? */
- regs->bpc -= 2;
- else
- regs->bpc -= 4;
+ prev_insn(regs);
}
}
- return 0;
+ if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
+ }
}
/*
* notification of userspace execution resumption
* - triggered by current->work.notify_resume
*/
-void do_notify_resume(struct pt_regs *regs, sigset_t *oldset,
- __u32 thread_info_flags)
+void do_notify_resume(struct pt_regs *regs, __u32 thread_info_flags)
{
/* Pending single-step? */
if (thread_info_flags & _TIF_SINGLESTEP)
@@ -407,7 +386,7 @@
/* deal with pending signal delivery */
if (thread_info_flags & _TIF_SIGPENDING)
- do_signal(regs,oldset);
+ do_signal(regs);
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
diff --git a/arch/m68k/include/asm/unistd.h b/arch/m68k/include/asm/unistd.h
index 60b15d0..b43b36b 100644
--- a/arch/m68k/include/asm/unistd.h
+++ b/arch/m68k/include/asm/unistd.h
@@ -340,10 +340,13 @@
#define __NR_set_thread_area 334
#define __NR_atomic_cmpxchg_32 335
#define __NR_atomic_barrier 336
+#define __NR_fanotify_init 337
+#define __NR_fanotify_mark 338
+#define __NR_prlimit64 339
#ifdef __KERNEL__
-#define NR_syscalls 337
+#define NR_syscalls 340
#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index 2391bdf..6360c43 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -765,4 +765,7 @@
.long sys_set_thread_area
.long sys_atomic_cmpxchg_32 /* 335 */
.long sys_atomic_barrier
+ .long sys_fanotify_init
+ .long sys_fanotify_mark
+ .long sys_prlimit64
diff --git a/arch/m68k/mac/macboing.c b/arch/m68k/mac/macboing.c
index 8f06408..05285d0 100644
--- a/arch/m68k/mac/macboing.c
+++ b/arch/m68k/mac/macboing.c
@@ -162,7 +162,7 @@
void mac_mksound( unsigned int freq, unsigned int length )
{
__u32 cfreq = ( freq << 5 ) / 468;
- __u32 flags;
+ unsigned long flags;
int i;
if ( mac_special_bell == NULL )
@@ -224,7 +224,7 @@
*/
static void mac_quadra_start_bell( unsigned int freq, unsigned int length, unsigned int volume )
{
- __u32 flags;
+ unsigned long flags;
/* if the bell is already ringing, ring longer */
if ( mac_bell_duration > 0 )
@@ -271,7 +271,7 @@
static void mac_quadra_ring_bell( unsigned long ignored )
{
int i, count = mac_asc_samplespersec / HZ;
- __u32 flags;
+ unsigned long flags;
/*
* we neither want a sound buffer overflow nor underflow, so we need to match
diff --git a/arch/m68knommu/kernel/syscalltable.S b/arch/m68knommu/kernel/syscalltable.S
index b30b3eb..79b1ed1 100644
--- a/arch/m68knommu/kernel/syscalltable.S
+++ b/arch/m68knommu/kernel/syscalltable.S
@@ -355,6 +355,9 @@
.long sys_set_thread_area
.long sys_atomic_cmpxchg_32 /* 335 */
.long sys_atomic_barrier
+ .long sys_fanotify_init
+ .long sys_fanotify_mark
+ .long sys_prlimit64
.rept NR_syscalls-(.-sys_call_table)/4
.long sys_ni_syscall
diff --git a/arch/mips/Kbuild b/arch/mips/Kbuild
index e322d65..7dd65cf 100644
--- a/arch/mips/Kbuild
+++ b/arch/mips/Kbuild
@@ -7,6 +7,10 @@
include arch/mips/Kbuild.platforms
obj-y := $(platform-y)
+# make clean traverses $(obj-) without having included .config, so
+# everything ends up here
+obj- := $(platform-)
+
# mips object files
# The object files are linked as core-y files would be linked
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 3ad59dd..4c9f402 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -13,6 +13,7 @@
select HAVE_KPROBES
select HAVE_KRETPROBES
select RTC_LIB if !MACH_LOONGSON
+ select GENERIC_ATOMIC64 if !64BIT
mainmenu "Linux/MIPS Kernel Configuration"
@@ -880,11 +881,15 @@
config GENERIC_ISA_DMA
bool
select ZONE_DMA if GENERIC_ISA_DMA_SUPPORT_BROKEN=n
+ select ISA_DMA_API
config GENERIC_ISA_DMA_SUPPORT_BROKEN
bool
select GENERIC_ISA_DMA
+config ISA_DMA_API
+ bool
+
config GENERIC_GPIO
bool
@@ -1646,8 +1651,16 @@
select SYS_SUPPORTS_SMP
select SMP_UP
help
- This is a kernel model which is also known a VSMP or lately
- has been marketesed into SMVP.
+ This is a kernel model which is known a VSMP but lately has been
+ marketesed into SMVP.
+ Virtual SMP uses the processor's VPEs to implement virtual
+ processors. In currently available configuration of the 34K processor
+ this allows for a dual processor. Both processors will share the same
+ primary caches; each will obtain the half of the TLB for it's own
+ exclusive use. For a layman this model can be described as similar to
+ what Intel calls Hyperthreading.
+
+ For further information see http://www.linux-mips.org/wiki/34K#VSMP
config MIPS_MT_SMTC
bool "SMTC: Use all TCs on all VPEs for SMP"
@@ -1664,6 +1677,14 @@
help
This is a kernel model which is known a SMTC or lately has been
marketesed into SMVP.
+ is presenting the available TC's of the core as processors to Linux.
+ On currently available 34K processors this means a Linux system will
+ see up to 5 processors. The implementation of the SMTC kernel differs
+ significantly from VSMP and cannot efficiently coexist in the same
+ kernel binary so the choice between VSMP and SMTC is a compile time
+ decision.
+
+ For further information see http://www.linux-mips.org/wiki/34K#SMTC
endchoice
diff --git a/arch/mips/alchemy/common/prom.c b/arch/mips/alchemy/common/prom.c
index c29511b..5340210 100644
--- a/arch/mips/alchemy/common/prom.c
+++ b/arch/mips/alchemy/common/prom.c
@@ -43,7 +43,7 @@
char **prom_argv;
char **prom_envp;
-void prom_init_cmdline(void)
+void __init prom_init_cmdline(void)
{
int i;
@@ -104,7 +104,7 @@
}
}
-int prom_get_ethernet_addr(char *ethernet_addr)
+int __init prom_get_ethernet_addr(char *ethernet_addr)
{
char *ethaddr_str;
@@ -123,7 +123,6 @@
return 0;
}
-EXPORT_SYMBOL(prom_get_ethernet_addr);
void __init prom_free_prom_memory(void)
{
diff --git a/arch/mips/alchemy/devboards/db1200/platform.c b/arch/mips/alchemy/devboards/db1200/platform.c
index 3fa34c3..fbb5593 100644
--- a/arch/mips/alchemy/devboards/db1200/platform.c
+++ b/arch/mips/alchemy/devboards/db1200/platform.c
@@ -429,6 +429,11 @@
.resource = au1200_psc1_res,
};
+static struct platform_device db1200_stac_dev = {
+ .name = "ac97-codec",
+ .id = 1, /* on PSC1 */
+};
+
static struct platform_device *db1200_devs[] __initdata = {
NULL, /* PSC0, selected by S6.8 */
&db1200_ide_dev,
@@ -436,6 +441,7 @@
&db1200_rtc_dev,
&db1200_nand_dev,
&db1200_audio_dev,
+ &db1200_stac_dev,
};
static int __init db1200_dev_init(void)
diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile
index ed9bb70..5042d51 100644
--- a/arch/mips/boot/compressed/Makefile
+++ b/arch/mips/boot/compressed/Makefile
@@ -59,7 +59,7 @@
hostprogs-y := calc_vmlinuz_load_addr
VMLINUZ_LOAD_ADDRESS = $(shell $(obj)/calc_vmlinuz_load_addr \
- $(objtree)/$(KBUILD_IMAGE) $(VMLINUX_LOAD_ADDRESS))
+ $(obj)/vmlinux.bin $(VMLINUX_LOAD_ADDRESS))
vmlinuzobjs-y += $(obj)/piggy.o
@@ -105,4 +105,4 @@
vmlinuz.srec: vmlinuz
$(call cmd,objcopy)
-clean-files := $(objtree)/vmlinuz.*
+clean-files := $(objtree)/vmlinuz $(objtree)/vmlinuz.{32,ecoff,bin,srec}
diff --git a/arch/mips/cavium-octeon/Kconfig b/arch/mips/cavium-octeon/Kconfig
index 094c17e..47323ca 100644
--- a/arch/mips/cavium-octeon/Kconfig
+++ b/arch/mips/cavium-octeon/Kconfig
@@ -83,3 +83,7 @@
def_bool y
select SPARSEMEM_STATIC
depends on CPU_CAVIUM_OCTEON
+
+config CAVIUM_OCTEON_HELPER
+ def_bool y
+ depends on OCTEON_ETHERNET || PCI
diff --git a/arch/mips/cavium-octeon/cpu.c b/arch/mips/cavium-octeon/cpu.c
index c664c8c..a5b4279 100644
--- a/arch/mips/cavium-octeon/cpu.c
+++ b/arch/mips/cavium-octeon/cpu.c
@@ -41,7 +41,7 @@
return NOTIFY_OK; /* Let default notifier send signals */
}
-static int cnmips_cu2_setup(void)
+static int __init cnmips_cu2_setup(void)
{
return cu2_notifier(cnmips_cu2_call, 0);
}
diff --git a/arch/mips/cavium-octeon/executive/Makefile b/arch/mips/cavium-octeon/executive/Makefile
index 2fd66db..7f41c5b 100644
--- a/arch/mips/cavium-octeon/executive/Makefile
+++ b/arch/mips/cavium-octeon/executive/Makefile
@@ -11,4 +11,4 @@
obj-y += cvmx-bootmem.o cvmx-l2c.o cvmx-sysinfo.o octeon-model.o
-obj-$(CONFIG_PCI) += cvmx-helper-errata.o cvmx-helper-jtag.o
+obj-$(CONFIG_CAVIUM_OCTEON_HELPER) += cvmx-helper-errata.o cvmx-helper-jtag.o
diff --git a/arch/mips/dec/Platform b/arch/mips/dec/Platform
index 3adbcbd..cf55a6f 100644
--- a/arch/mips/dec/Platform
+++ b/arch/mips/dec/Platform
@@ -1,7 +1,7 @@
#
# DECstation family
#
-platform-$(CONFIG_MACH_DECSTATION) = dec/
+platform-$(CONFIG_MACH_DECSTATION) += dec/
cflags-$(CONFIG_MACH_DECSTATION) += \
-I$(srctree)/arch/mips/include/asm/mach-dec
libs-$(CONFIG_MACH_DECSTATION) += arch/mips/dec/prom/
diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h
index c63c56b..47d87da 100644
--- a/arch/mips/include/asm/atomic.h
+++ b/arch/mips/include/asm/atomic.h
@@ -782,6 +782,10 @@
*/
#define atomic64_add_negative(i, v) (atomic64_add_return(i, (v)) < 0)
+#else /* !CONFIG_64BIT */
+
+#include <asm-generic/atomic64.h>
+
#endif /* CONFIG_64BIT */
/*
diff --git a/arch/mips/include/asm/compat.h b/arch/mips/include/asm/compat.h
index 613f691..dbc5106 100644
--- a/arch/mips/include/asm/compat.h
+++ b/arch/mips/include/asm/compat.h
@@ -145,7 +145,7 @@
return (u32)(unsigned long)uptr;
}
-static inline void __user *compat_alloc_user_space(long len)
+static inline void __user *arch_compat_alloc_user_space(long len)
{
struct pt_regs *regs = (struct pt_regs *)
((unsigned long) current_thread_info() + THREAD_SIZE - 32) - 1;
diff --git a/arch/mips/include/asm/cop2.h b/arch/mips/include/asm/cop2.h
index 2cb2f0c..3532e2c 100644
--- a/arch/mips/include/asm/cop2.h
+++ b/arch/mips/include/asm/cop2.h
@@ -24,7 +24,7 @@
#define cu2_notifier(fn, pri) \
({ \
- static struct notifier_block fn##_nb __cpuinitdata = { \
+ static struct notifier_block fn##_nb = { \
.notifier_call = fn, \
.priority = pri \
}; \
diff --git a/arch/mips/include/asm/fcntl.h b/arch/mips/include/asm/fcntl.h
index e482fe9..75edded 100644
--- a/arch/mips/include/asm/fcntl.h
+++ b/arch/mips/include/asm/fcntl.h
@@ -56,6 +56,7 @@
*/
#ifdef CONFIG_32BIT
+#include <linux/types.h>
struct flock {
short l_type;
diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h
index 9b9436a..86548da 100644
--- a/arch/mips/include/asm/gic.h
+++ b/arch/mips/include/asm/gic.h
@@ -321,6 +321,7 @@
*/
struct gic_intr_map {
unsigned int cpunum; /* Directed to this CPU */
+#define GIC_UNUSED 0xdead /* Dummy data */
unsigned int pin; /* Directed to this Pin */
unsigned int polarity; /* Polarity : +/- */
unsigned int trigtype; /* Trigger : Edge/Levl */
diff --git a/arch/mips/include/asm/mach-tx49xx/kmalloc.h b/arch/mips/include/asm/mach-tx49xx/kmalloc.h
index b74caf6..ff9a8b8 100644
--- a/arch/mips/include/asm/mach-tx49xx/kmalloc.h
+++ b/arch/mips/include/asm/mach-tx49xx/kmalloc.h
@@ -1,6 +1,6 @@
#ifndef __ASM_MACH_TX49XX_KMALLOC_H
#define __ASM_MACH_TX49XX_KMALLOC_H
-#define ARCH_KMALLOC_MINALIGN L1_CACHE_BYTES
+#define ARCH_DMA_MINALIGN L1_CACHE_BYTES
#endif /* __ASM_MACH_TX49XX_KMALLOC_H */
diff --git a/arch/mips/include/asm/mips-boards/maltaint.h b/arch/mips/include/asm/mips-boards/maltaint.h
index cea872f..d11aa02 100644
--- a/arch/mips/include/asm/mips-boards/maltaint.h
+++ b/arch/mips/include/asm/mips-boards/maltaint.h
@@ -88,9 +88,6 @@
#define GIC_EXT_INTR(x) x
-/* Dummy data */
-#define X 0xdead
-
/* External Interrupts used for IPI */
#define GIC_IPI_EXT_INTR_RESCHED_VPE0 16
#define GIC_IPI_EXT_INTR_CALLFNC_VPE0 17
diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
index a16beaf..e59cd1a 100644
--- a/arch/mips/include/asm/page.h
+++ b/arch/mips/include/asm/page.h
@@ -150,6 +150,20 @@
((unsigned long)(x) - PAGE_OFFSET + PHYS_OFFSET)
#endif
#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET - PHYS_OFFSET))
+
+/*
+ * RELOC_HIDE was originally added by 6007b903dfe5f1d13e0c711ac2894bdd4a61b1ad
+ * (lmo) rsp. 8431fd094d625b94d364fe393076ccef88e6ce18 (kernel.org). The
+ * discussion can be found in lkml posting
+ * <a2ebde260608230500o3407b108hc03debb9da6e62c@mail.gmail.com> which is
+ * archived at http://lists.linuxcoding.com/kernel/2006-q3/msg17360.html
+ *
+ * It is unclear if the misscompilations mentioned in
+ * http://lkml.org/lkml/2010/8/8/138 also affect MIPS so we keep this one
+ * until GCC 3.x has been retired before we can apply
+ * https://patchwork.linux-mips.org/patch/1541/
+ */
+
#define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x), 0))
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
diff --git a/arch/mips/include/asm/siginfo.h b/arch/mips/include/asm/siginfo.h
index 96e28f1..1ca64b4 100644
--- a/arch/mips/include/asm/siginfo.h
+++ b/arch/mips/include/asm/siginfo.h
@@ -88,6 +88,7 @@
#ifdef __ARCH_SI_TRAPNO
int _trapno; /* TRAP # which caused the signal */
#endif
+ short _addr_lsb;
} _sigfault;
/* SIGPOLL, SIGXFSZ (To do ...) */
diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h
index 2376f2e..70df9c0 100644
--- a/arch/mips/include/asm/thread_info.h
+++ b/arch/mips/include/asm/thread_info.h
@@ -146,7 +146,8 @@
#define _TIF_LOAD_WATCH (1<<TIF_LOAD_WATCH)
/* work to do on interrupt/exception return */
-#define _TIF_WORK_MASK (0x0000ffef & ~_TIF_SECCOMP)
+#define _TIF_WORK_MASK (0x0000ffef & \
+ ~(_TIF_SECCOMP | _TIF_SYSCALL_AUDIT))
/* work to do on any return to u-space */
#define _TIF_ALLWORK_MASK (0x8000ffff & ~_TIF_SECCOMP)
diff --git a/arch/mips/include/asm/unistd.h b/arch/mips/include/asm/unistd.h
index baa318a..550725b 100644
--- a/arch/mips/include/asm/unistd.h
+++ b/arch/mips/include/asm/unistd.h
@@ -356,16 +356,19 @@
#define __NR_perf_event_open (__NR_Linux + 333)
#define __NR_accept4 (__NR_Linux + 334)
#define __NR_recvmmsg (__NR_Linux + 335)
+#define __NR_fanotify_init (__NR_Linux + 336)
+#define __NR_fanotify_mark (__NR_Linux + 337)
+#define __NR_prlimit64 (__NR_Linux + 338)
/*
* Offset of the last Linux o32 flavoured syscall
*/
-#define __NR_Linux_syscalls 335
+#define __NR_Linux_syscalls 338
#endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
#define __NR_O32_Linux 4000
-#define __NR_O32_Linux_syscalls 335
+#define __NR_O32_Linux_syscalls 338
#if _MIPS_SIM == _MIPS_SIM_ABI64
@@ -668,16 +671,19 @@
#define __NR_perf_event_open (__NR_Linux + 292)
#define __NR_accept4 (__NR_Linux + 293)
#define __NR_recvmmsg (__NR_Linux + 294)
+#define __NR_fanotify_init (__NR_Linux + 295)
+#define __NR_fanotify_mark (__NR_Linux + 296)
+#define __NR_prlimit64 (__NR_Linux + 297)
/*
* Offset of the last Linux 64-bit flavoured syscall
*/
-#define __NR_Linux_syscalls 294
+#define __NR_Linux_syscalls 297
#endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */
#define __NR_64_Linux 5000
-#define __NR_64_Linux_syscalls 294
+#define __NR_64_Linux_syscalls 297
#if _MIPS_SIM == _MIPS_SIM_NABI32
@@ -985,16 +991,19 @@
#define __NR_accept4 (__NR_Linux + 297)
#define __NR_recvmmsg (__NR_Linux + 298)
#define __NR_getdents64 (__NR_Linux + 299)
+#define __NR_fanotify_init (__NR_Linux + 300)
+#define __NR_fanotify_mark (__NR_Linux + 301)
+#define __NR_prlimit64 (__NR_Linux + 302)
/*
* Offset of the last N32 flavoured syscall
*/
-#define __NR_Linux_syscalls 299
+#define __NR_Linux_syscalls 302
#endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */
#define __NR_N32_Linux 6000
-#define __NR_N32_Linux_syscalls 299
+#define __NR_N32_Linux_syscalls 302
#ifdef __KERNEL__
diff --git a/arch/mips/jz4740/Platform b/arch/mips/jz4740/Platform
index 6a97230..ba91be9 100644
--- a/arch/mips/jz4740/Platform
+++ b/arch/mips/jz4740/Platform
@@ -1,3 +1,3 @@
-core-$(CONFIG_MACH_JZ4740) += arch/mips/jz4740/
+platform-$(CONFIG_MACH_JZ4740) += jz4740/
cflags-$(CONFIG_MACH_JZ4740) += -I$(srctree)/arch/mips/include/asm/mach-jz4740
load-$(CONFIG_MACH_JZ4740) += 0xffffffff80010000
diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c
index 0176ed0..32103cc 100644
--- a/arch/mips/kernel/branch.c
+++ b/arch/mips/kernel/branch.c
@@ -40,7 +40,6 @@
return -EFAULT;
}
- regs->regs[0] = 0;
switch (insn.i_format.opcode) {
/*
* jr and jalr are in r_format format.
diff --git a/arch/mips/kernel/irq-gic.c b/arch/mips/kernel/irq-gic.c
index b181f2f..82ba9f6 100644
--- a/arch/mips/kernel/irq-gic.c
+++ b/arch/mips/kernel/irq-gic.c
@@ -7,7 +7,6 @@
#include <asm/io.h>
#include <asm/gic.h>
#include <asm/gcmpregs.h>
-#include <asm/mips-boards/maltaint.h>
#include <asm/irq.h>
#include <linux/hardirq.h>
#include <asm-generic/bitops/find.h>
@@ -131,7 +130,7 @@
int i;
irq -= _irqbase;
- pr_debug(KERN_DEBUG "%s(%d) called\n", __func__, irq);
+ pr_debug("%s(%d) called\n", __func__, irq);
cpumask_and(&tmp, cpumask, cpu_online_mask);
if (cpus_empty(tmp))
return -1;
@@ -222,7 +221,7 @@
/* Setup specifics */
for (i = 0; i < mapsize; i++) {
cpu = intrmap[i].cpunum;
- if (cpu == X)
+ if (cpu == GIC_UNUSED)
continue;
if (cpu == 0 && i != 0 && intrmap[i].flags == 0)
continue;
diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c
index 1f4e2fa..f4546e9 100644
--- a/arch/mips/kernel/kgdb.c
+++ b/arch/mips/kernel/kgdb.c
@@ -283,7 +283,7 @@
struct pt_regs *regs = args->regs;
int trap = (regs->cp0_cause & 0x7c) >> 2;
- /* Userpace events, ignore. */
+ /* Userspace events, ignore. */
if (user_mode(regs))
return NOTIFY_DONE;
diff --git a/arch/mips/kernel/kspd.c b/arch/mips/kernel/kspd.c
index 80e2ba6..29811f0 100644
--- a/arch/mips/kernel/kspd.c
+++ b/arch/mips/kernel/kspd.c
@@ -251,7 +251,7 @@
memset(&tz, 0, sizeof(tz));
if ((ret.retval = sp_syscall(__NR_gettimeofday, (int)&tv,
(int)&tz, 0, 0)) == 0)
- ret.retval = tv.tv_sec;
+ ret.retval = tv.tv_sec;
break;
case MTSP_SYSCALL_EXIT:
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index c2dab14..6343b4a 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -341,3 +341,10 @@
{
return sys_lookup_dcookie(merge_64(a0, a1), buf, len);
}
+
+SYSCALL_DEFINE6(32_fanotify_mark, int, fanotify_fd, unsigned int, flags,
+ u64, a3, u64, a4, int, dfd, const char __user *, pathname)
+{
+ return sys_fanotify_mark(fanotify_fd, flags, merge_64(a3, a4),
+ dfd, pathname);
+}
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index c51b95f..c877733 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -536,7 +536,7 @@
{
/* do the secure computing check first */
if (!entryexit)
- secure_computing(regs->regs[0]);
+ secure_computing(regs->regs[2]);
if (unlikely(current->audit_context) && entryexit)
audit_syscall_exit(AUDITSC_RESULT(regs->regs[2]),
@@ -565,7 +565,7 @@
out:
if (unlikely(current->audit_context) && !entryexit)
- audit_syscall_entry(audit_arch(), regs->regs[0],
+ audit_syscall_entry(audit_arch(), regs->regs[2],
regs->regs[4], regs->regs[5],
regs->regs[6], regs->regs[7]);
}
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index 17202bb..fbaabad 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -63,9 +63,9 @@
sw t0, PT_R7(sp) # set error flag
beqz t0, 1f
+ lw t1, PT_R2(sp) # syscall number
negu v0 # error
- sw v0, PT_R0(sp) # set flag for syscall
- # restarting
+ sw t1, PT_R0(sp) # save it for syscall restarting
1: sw v0, PT_R2(sp) # result
o32_syscall_exit:
@@ -104,9 +104,9 @@
sw t0, PT_R7(sp) # set error flag
beqz t0, 1f
+ lw t1, PT_R2(sp) # syscall number
negu v0 # error
- sw v0, PT_R0(sp) # set flag for syscall
- # restarting
+ sw t1, PT_R0(sp) # save it for syscall restarting
1: sw v0, PT_R2(sp) # result
j syscall_exit
@@ -169,8 +169,7 @@
* We probably should handle this case a bit more drastic.
*/
bad_stack:
- negu v0 # error
- sw v0, PT_R0(sp)
+ li v0, EFAULT
sw v0, PT_R2(sp)
li t0, 1 # set error flag
sw t0, PT_R7(sp)
@@ -583,7 +582,10 @@
sys sys_rt_tgsigqueueinfo 4
sys sys_perf_event_open 5
sys sys_accept4 4
- sys sys_recvmmsg 5
+ sys sys_recvmmsg 5 /* 4335 */
+ sys sys_fanotify_init 2
+ sys sys_fanotify_mark 6
+ sys sys_prlimit64 4
.endm
/* We pre-compute the number of _instruction_ bytes needed to
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index a8a6c59..3f41792 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -66,9 +66,9 @@
sd t0, PT_R7(sp) # set error flag
beqz t0, 1f
+ ld t1, PT_R2(sp) # syscall number
dnegu v0 # error
- sd v0, PT_R0(sp) # set flag for syscall
- # restarting
+ sd t1, PT_R0(sp) # save it for syscall restarting
1: sd v0, PT_R2(sp) # result
n64_syscall_exit:
@@ -109,8 +109,9 @@
sd t0, PT_R7(sp) # set error flag
beqz t0, 1f
+ ld t1, PT_R2(sp) # syscall number
dnegu v0 # error
- sd v0, PT_R0(sp) # set flag for syscall restarting
+ sd t1, PT_R0(sp) # save it for syscall restarting
1: sd v0, PT_R2(sp) # result
j syscall_exit
@@ -416,9 +417,12 @@
PTR sys_pipe2
PTR sys_inotify_init1
PTR sys_preadv
- PTR sys_pwritev /* 5390 */
+ PTR sys_pwritev /* 5290 */
PTR sys_rt_tgsigqueueinfo
PTR sys_perf_event_open
PTR sys_accept4
- PTR sys_recvmmsg
+ PTR sys_recvmmsg
+ PTR sys_fanotify_init /* 5295 */
+ PTR sys_fanotify_mark
+ PTR sys_prlimit64
.size sys_call_table,.-sys_call_table
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index a3d6613..f08ece6 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -65,8 +65,9 @@
sd t0, PT_R7(sp) # set error flag
beqz t0, 1f
+ ld t1, PT_R2(sp) # syscall number
dnegu v0 # error
- sd v0, PT_R0(sp) # set flag for syscall restarting
+ sd t1, PT_R0(sp) # save it for syscall restarting
1: sd v0, PT_R2(sp) # result
local_irq_disable # make sure need_resched and
@@ -106,8 +107,9 @@
sd t0, PT_R7(sp) # set error flag
beqz t0, 1f
+ ld t1, PT_R2(sp) # syscall number
dnegu v0 # error
- sd v0, PT_R0(sp) # set flag for syscall restarting
+ sd t1, PT_R0(sp) # save it for syscall restarting
1: sd v0, PT_R2(sp) # result
j syscall_exit
@@ -320,10 +322,10 @@
PTR sys_cacheflush
PTR sys_cachectl
PTR sys_sysmips
- PTR sys_io_setup /* 6200 */
+ PTR compat_sys_io_setup /* 6200 */
PTR sys_io_destroy
- PTR sys_io_getevents
- PTR sys_io_submit
+ PTR compat_sys_io_getevents
+ PTR compat_sys_io_submit
PTR sys_io_cancel
PTR sys_exit_group /* 6205 */
PTR sys_lookup_dcookie
@@ -419,5 +421,8 @@
PTR sys_perf_event_open
PTR sys_accept4
PTR compat_sys_recvmmsg
- PTR sys_getdents
+ PTR sys_getdents64
+ PTR sys_fanotify_init /* 6300 */
+ PTR sys_fanotify_mark
+ PTR sys_prlimit64
.size sysn32_call_table,.-sysn32_call_table
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 813689e..78d768a 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -93,8 +93,9 @@
sd t0, PT_R7(sp) # set error flag
beqz t0, 1f
+ ld t1, PT_R2(sp) # syscall number
dnegu v0 # error
- sd v0, PT_R0(sp) # flag for syscall restarting
+ sd t1, PT_R0(sp) # save it for syscall restarting
1: sd v0, PT_R2(sp) # result
o32_syscall_exit:
@@ -142,8 +143,9 @@
sd t0, PT_R7(sp) # set error flag
beqz t0, 1f
+ ld t1, PT_R2(sp) # syscall number
dnegu v0 # error
- sd v0, PT_R0(sp) # set flag for syscall restarting
+ sd t1, PT_R0(sp) # save it for syscall restarting
1: sd v0, PT_R2(sp) # result
j syscall_exit
@@ -154,8 +156,7 @@
* The stackpointer for a call with more than 4 arguments is bad.
*/
bad_stack:
- dnegu v0 # error
- sd v0, PT_R0(sp)
+ li v0, EFAULT
sd v0, PT_R2(sp)
li t0, 1 # set error flag
sd t0, PT_R7(sp)
@@ -444,10 +445,10 @@
PTR compat_sys_futex
PTR compat_sys_sched_setaffinity
PTR compat_sys_sched_getaffinity /* 4240 */
- PTR sys_io_setup
+ PTR compat_sys_io_setup
PTR sys_io_destroy
- PTR sys_io_getevents
- PTR sys_io_submit
+ PTR compat_sys_io_getevents
+ PTR compat_sys_io_submit
PTR sys_io_cancel /* 4245 */
PTR sys_exit_group
PTR sys32_lookup_dcookie
@@ -538,5 +539,8 @@
PTR compat_sys_rt_tgsigqueueinfo
PTR sys_perf_event_open
PTR sys_accept4
- PTR compat_sys_recvmmsg
+ PTR compat_sys_recvmmsg /* 4335 */
+ PTR sys_fanotify_init
+ PTR sys_32_fanotify_mark
+ PTR sys_prlimit64
.size sys_call_table,.-sys_call_table
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 2099d5a..5922342 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -390,7 +390,6 @@
{
struct rt_sigframe __user *frame;
sigset_t set;
- stack_t st;
int sig;
frame = (struct rt_sigframe __user *) regs.regs[29];
@@ -411,11 +410,9 @@
else if (sig)
force_sig(sig, current);
- if (__copy_from_user(&st, &frame->rs_uc.uc_stack, sizeof(st)))
- goto badframe;
/* It is more difficult to avoid calling this function than to
call it and ignore errors. */
- do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]);
+ do_sigaltstack(&frame->rs_uc.uc_stack, NULL, regs.regs[29]);
/*
* Don't let your children do this ...
@@ -550,23 +547,26 @@
struct mips_abi *abi = current->thread.abi;
void *vdso = current->mm->context.vdso;
- switch(regs->regs[0]) {
- case ERESTART_RESTARTBLOCK:
- case ERESTARTNOHAND:
- regs->regs[2] = EINTR;
- break;
- case ERESTARTSYS:
- if (!(ka->sa.sa_flags & SA_RESTART)) {
+ if (regs->regs[0]) {
+ switch(regs->regs[2]) {
+ case ERESTART_RESTARTBLOCK:
+ case ERESTARTNOHAND:
regs->regs[2] = EINTR;
break;
+ case ERESTARTSYS:
+ if (!(ka->sa.sa_flags & SA_RESTART)) {
+ regs->regs[2] = EINTR;
+ break;
+ }
+ /* fallthrough */
+ case ERESTARTNOINTR:
+ regs->regs[7] = regs->regs[26];
+ regs->regs[2] = regs->regs[0];
+ regs->cp0_epc -= 4;
}
- /* fallthrough */
- case ERESTARTNOINTR: /* Userland will reload $v0. */
- regs->regs[7] = regs->regs[26];
- regs->cp0_epc -= 8;
- }
- regs->regs[0] = 0; /* Don't deal with this again. */
+ regs->regs[0] = 0; /* Don't deal with this again. */
+ }
if (sig_uses_siginfo(ka))
ret = abi->setup_rt_frame(vdso + abi->rt_signal_return_offset,
@@ -575,6 +575,9 @@
ret = abi->setup_frame(vdso + abi->signal_return_offset,
ka, regs, sig, oldset);
+ if (ret)
+ return ret;
+
spin_lock_irq(¤t->sighand->siglock);
sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask);
if (!(ka->sa.sa_flags & SA_NODEFER))
@@ -622,17 +625,13 @@
return;
}
- /*
- * Who's code doesn't conform to the restartable syscall convention
- * dies here!!! The li instruction, a single machine instruction,
- * must directly be followed by the syscall instruction.
- */
if (regs->regs[0]) {
if (regs->regs[2] == ERESTARTNOHAND ||
regs->regs[2] == ERESTARTSYS ||
regs->regs[2] == ERESTARTNOINTR) {
+ regs->regs[2] = regs->regs[0];
regs->regs[7] = regs->regs[26];
- regs->cp0_epc -= 8;
+ regs->cp0_epc -= 4;
}
if (regs->regs[2] == ERESTART_RESTARTBLOCK) {
regs->regs[2] = current->thread.abi->restart;
diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c
index 2c5df81..ee24d81 100644
--- a/arch/mips/kernel/signal_n32.c
+++ b/arch/mips/kernel/signal_n32.c
@@ -109,6 +109,7 @@
asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
{
struct rt_sigframe_n32 __user *frame;
+ mm_segment_t old_fs;
sigset_t set;
stack_t st;
s32 sp;
@@ -143,7 +144,11 @@
/* It is more difficult to avoid calling this function than to
call it and ignore errors. */
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]);
+ set_fs(old_fs);
+
/*
* Don't let your children do this ...
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
index 69b039c..33d5a5c 100644
--- a/arch/mips/kernel/unaligned.c
+++ b/arch/mips/kernel/unaligned.c
@@ -109,8 +109,6 @@
unsigned long value;
unsigned int res;
- regs->regs[0] = 0;
-
/*
* This load never faults.
*/
diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c
index 7ba8908..469d401 100644
--- a/arch/mips/mm/dma-default.c
+++ b/arch/mips/mm/dma-default.c
@@ -44,27 +44,39 @@
static gfp_t massage_gfp_flags(const struct device *dev, gfp_t gfp)
{
+ gfp_t dma_flag;
+
/* ignore region specifiers */
gfp &= ~(__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM);
-#ifdef CONFIG_ZONE_DMA
+#ifdef CONFIG_ISA
if (dev == NULL)
- gfp |= __GFP_DMA;
- else if (dev->coherent_dma_mask < DMA_BIT_MASK(24))
- gfp |= __GFP_DMA;
+ dma_flag = __GFP_DMA;
else
#endif
-#ifdef CONFIG_ZONE_DMA32
+#if defined(CONFIG_ZONE_DMA32) && defined(CONFIG_ZONE_DMA)
if (dev->coherent_dma_mask < DMA_BIT_MASK(32))
- gfp |= __GFP_DMA32;
+ dma_flag = __GFP_DMA;
+ else if (dev->coherent_dma_mask < DMA_BIT_MASK(64))
+ dma_flag = __GFP_DMA32;
else
#endif
- ;
+#if defined(CONFIG_ZONE_DMA32) && !defined(CONFIG_ZONE_DMA)
+ if (dev->coherent_dma_mask < DMA_BIT_MASK(64))
+ dma_flag = __GFP_DMA32;
+ else
+#endif
+#if defined(CONFIG_ZONE_DMA) && !defined(CONFIG_ZONE_DMA32)
+ if (dev->coherent_dma_mask < DMA_BIT_MASK(64))
+ dma_flag = __GFP_DMA;
+ else
+#endif
+ dma_flag = 0;
/* Don't invoke OOM killer */
gfp |= __GFP_NORETRY;
- return gfp;
+ return gfp | dma_flag;
}
void *dma_alloc_noncoherent(struct device *dev, size_t size,
diff --git a/arch/mips/mm/sc-rm7k.c b/arch/mips/mm/sc-rm7k.c
index 1ef75cd..274af3b 100644
--- a/arch/mips/mm/sc-rm7k.c
+++ b/arch/mips/mm/sc-rm7k.c
@@ -30,7 +30,7 @@
#define tc_lsize 32
extern unsigned long icache_way_size, dcache_way_size;
-unsigned long tcache_size;
+static unsigned long tcache_size;
#include <asm/r4kcache.h>
diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c
index 15949b0..b79b24a 100644
--- a/arch/mips/mti-malta/malta-int.c
+++ b/arch/mips/mti-malta/malta-int.c
@@ -385,6 +385,8 @@
*/
#define GIC_CPU_NMI GIC_MAP_TO_NMI_MSK
+#define X GIC_UNUSED
+
static struct gic_intr_map gic_intr_map[GIC_NUM_INTRS] = {
{ X, X, X, X, 0 },
{ X, X, X, X, 0 },
@@ -404,6 +406,7 @@
{ X, X, X, X, 0 },
/* The remainder of this table is initialised by fill_ipi_map */
};
+#undef X
/*
* GCMP needs to be detected before any SMP initialisation
diff --git a/arch/mips/pci/pci-rc32434.c b/arch/mips/pci/pci-rc32434.c
index 71f7d27..f31218e 100644
--- a/arch/mips/pci/pci-rc32434.c
+++ b/arch/mips/pci/pci-rc32434.c
@@ -118,7 +118,7 @@
if (!((pcicvalue == PCIM_H_EA) ||
(pcicvalue == PCIM_H_IA_FIX) ||
(pcicvalue == PCIM_H_IA_RR))) {
- pr_err(KERN_ERR "PCI init error!!!\n");
+ pr_err("PCI init error!!!\n");
/* Not in Host Mode, return ERROR */
return -1;
}
diff --git a/arch/mips/pnx8550/common/reset.c b/arch/mips/pnx8550/common/reset.c
index fadd874..e7a12ff 100644
--- a/arch/mips/pnx8550/common/reset.c
+++ b/arch/mips/pnx8550/common/reset.c
@@ -22,29 +22,19 @@
*/
#include <linux/kernel.h>
+#include <asm/processor.h>
#include <asm/reboot.h>
#include <glb.h>
void pnx8550_machine_restart(char *command)
{
- char head[] = "************* Machine restart *************";
- char foot[] = "*******************************************";
-
- printk("\n\n");
- printk("%s\n", head);
- if (command != NULL)
- printk("* %s\n", command);
- printk("%s\n", foot);
-
PNX8550_RST_CTL = PNX8550_RST_DO_SW_RST;
}
void pnx8550_machine_halt(void)
{
- printk("*** Machine halt. (Not implemented) ***\n");
-}
-
-void pnx8550_machine_power_off(void)
-{
- printk("*** Machine power off. (Not implemented) ***\n");
+ while (1) {
+ if (cpu_wait)
+ cpu_wait();
+ }
}
diff --git a/arch/mips/pnx8550/common/setup.c b/arch/mips/pnx8550/common/setup.c
index 64246c9..43cb394 100644
--- a/arch/mips/pnx8550/common/setup.c
+++ b/arch/mips/pnx8550/common/setup.c
@@ -44,7 +44,6 @@
extern void __init board_setup(void);
extern void pnx8550_machine_restart(char *);
extern void pnx8550_machine_halt(void);
-extern void pnx8550_machine_power_off(void);
extern struct resource ioport_resource;
extern struct resource iomem_resource;
extern char *prom_getcmdline(void);
@@ -100,7 +99,7 @@
_machine_restart = pnx8550_machine_restart;
_machine_halt = pnx8550_machine_halt;
- pm_power_off = pnx8550_machine_power_off;
+ pm_power_off = pnx8550_machine_halt;
/* Clear the Global 2 Register, PCI Inta Output Enable Registers
Bit 1:Enable DAC Powerdown
diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig
index 444b9f9..7c2a2f7 100644
--- a/arch/mn10300/Kconfig
+++ b/arch/mn10300/Kconfig
@@ -8,7 +8,6 @@
config MN10300
def_bool y
select HAVE_OPROFILE
- select HAVE_ARCH_TRACEHOOK
config AM33
def_bool y
diff --git a/arch/mn10300/Kconfig.debug b/arch/mn10300/Kconfig.debug
index ff80e86..ce83c74 100644
--- a/arch/mn10300/Kconfig.debug
+++ b/arch/mn10300/Kconfig.debug
@@ -101,7 +101,7 @@
choice
prompt "GDB stub port"
- default GDBSTUB_TTYSM0
+ default GDBSTUB_ON_TTYSM0
depends on GDBSTUB
help
Select the serial port used for GDB-stub.
diff --git a/arch/mn10300/include/asm/bitops.h b/arch/mn10300/include/asm/bitops.h
index f49ac49..3f50e96 100644
--- a/arch/mn10300/include/asm/bitops.h
+++ b/arch/mn10300/include/asm/bitops.h
@@ -229,9 +229,9 @@
#include <asm-generic/bitops/hweight.h>
#define ext2_set_bit_atomic(lock, nr, addr) \
- test_and_set_bit((nr) ^ 0x18, (addr))
+ test_and_set_bit((nr), (addr))
#define ext2_clear_bit_atomic(lock, nr, addr) \
- test_and_clear_bit((nr) ^ 0x18, (addr))
+ test_and_clear_bit((nr), (addr))
#include <asm-generic/bitops/ext2-non-atomic.h>
#include <asm-generic/bitops/minix-le.h>
diff --git a/arch/mn10300/include/asm/signal.h b/arch/mn10300/include/asm/signal.h
index 7e891fc..1865d72 100644
--- a/arch/mn10300/include/asm/signal.h
+++ b/arch/mn10300/include/asm/signal.h
@@ -78,7 +78,7 @@
/* These should not be considered constants from userland. */
#define SIGRTMIN 32
-#define SIGRTMAX (_NSIG-1)
+#define SIGRTMAX _NSIG
/*
* SA_FLAGS values:
diff --git a/arch/mn10300/kernel/mn10300-serial.c b/arch/mn10300/kernel/mn10300-serial.c
index 9d49073..db509dd 100644
--- a/arch/mn10300/kernel/mn10300-serial.c
+++ b/arch/mn10300/kernel/mn10300-serial.c
@@ -156,17 +156,17 @@
._intr = &SC0ICR,
._rxb = &SC0RXB,
._txb = &SC0TXB,
- .rx_name = "ttySM0/Rx",
- .tx_name = "ttySM0/Tx",
+ .rx_name = "ttySM0:Rx",
+ .tx_name = "ttySM0:Tx",
#ifdef CONFIG_MN10300_TTYSM0_TIMER8
- .tm_name = "ttySM0/Timer8",
+ .tm_name = "ttySM0:Timer8",
._tmxmd = &TM8MD,
._tmxbr = &TM8BR,
._tmicr = &TM8ICR,
.tm_irq = TM8IRQ,
.div_timer = MNSCx_DIV_TIMER_16BIT,
#else /* CONFIG_MN10300_TTYSM0_TIMER2 */
- .tm_name = "ttySM0/Timer2",
+ .tm_name = "ttySM0:Timer2",
._tmxmd = &TM2MD,
._tmxbr = (volatile u16 *) &TM2BR,
._tmicr = &TM2ICR,
@@ -209,17 +209,17 @@
._intr = &SC1ICR,
._rxb = &SC1RXB,
._txb = &SC1TXB,
- .rx_name = "ttySM1/Rx",
- .tx_name = "ttySM1/Tx",
+ .rx_name = "ttySM1:Rx",
+ .tx_name = "ttySM1:Tx",
#ifdef CONFIG_MN10300_TTYSM1_TIMER9
- .tm_name = "ttySM1/Timer9",
+ .tm_name = "ttySM1:Timer9",
._tmxmd = &TM9MD,
._tmxbr = &TM9BR,
._tmicr = &TM9ICR,
.tm_irq = TM9IRQ,
.div_timer = MNSCx_DIV_TIMER_16BIT,
#else /* CONFIG_MN10300_TTYSM1_TIMER3 */
- .tm_name = "ttySM1/Timer3",
+ .tm_name = "ttySM1:Timer3",
._tmxmd = &TM3MD,
._tmxbr = (volatile u16 *) &TM3BR,
._tmicr = &TM3ICR,
@@ -260,9 +260,9 @@
.uart.lock =
__SPIN_LOCK_UNLOCKED(mn10300_serial_port_sif2.uart.lock),
.name = "ttySM2",
- .rx_name = "ttySM2/Rx",
- .tx_name = "ttySM2/Tx",
- .tm_name = "ttySM2/Timer10",
+ .rx_name = "ttySM2:Rx",
+ .tx_name = "ttySM2:Tx",
+ .tm_name = "ttySM2:Timer10",
._iobase = &SC2CTR,
._control = &SC2CTR,
._status = &SC2STR,
diff --git a/arch/mn10300/kernel/module.c b/arch/mn10300/kernel/module.c
index 6aea7fd..196a111 100644
--- a/arch/mn10300/kernel/module.c
+++ b/arch/mn10300/kernel/module.c
@@ -206,7 +206,7 @@
const Elf_Shdr *sechdrs,
struct module *me)
{
- return module_bug_finalize(hdr, sechdrs, me);
+ return 0;
}
/*
@@ -214,5 +214,4 @@
*/
void module_arch_cleanup(struct module *mod)
{
- module_bug_cleanup(mod);
}
diff --git a/arch/mn10300/kernel/signal.c b/arch/mn10300/kernel/signal.c
index 717db14..d4de05a 100644
--- a/arch/mn10300/kernel/signal.c
+++ b/arch/mn10300/kernel/signal.c
@@ -65,10 +65,10 @@
old_sigset_t mask;
if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
__get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
+ __get_user(mask, &act->sa_mask))
return -EFAULT;
- __get_user(new_ka.sa.sa_flags, &act->sa_flags);
- __get_user(mask, &act->sa_mask);
siginitset(&new_ka.sa.sa_mask, mask);
}
@@ -77,10 +77,10 @@
if (!ret && oact) {
if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
__put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
return -EFAULT;
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
}
return ret;
@@ -102,6 +102,9 @@
{
unsigned int err = 0;
+ /* Always make any pending restarted system calls return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
if (is_using_fpu(current))
fpu_kill_state(current);
@@ -330,8 +333,6 @@
regs->d0 = sig;
regs->d1 = (unsigned long) &frame->sc;
- set_fs(USER_DS);
-
/* the tracer may want to single-step inside the handler */
if (test_thread_flag(TIF_SINGLESTEP))
ptrace_notify(SIGTRAP);
@@ -345,7 +346,7 @@
return 0;
give_sigsegv:
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
return -EFAULT;
}
@@ -413,8 +414,6 @@
regs->d0 = sig;
regs->d1 = (long) &frame->info;
- set_fs(USER_DS);
-
/* the tracer may want to single-step inside the handler */
if (test_thread_flag(TIF_SINGLESTEP))
ptrace_notify(SIGTRAP);
@@ -428,10 +427,16 @@
return 0;
give_sigsegv:
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
return -EFAULT;
}
+static inline void stepback(struct pt_regs *regs)
+{
+ regs->pc -= 2;
+ regs->orig_d0 = -1;
+}
+
/*
* handle the actual delivery of a signal to userspace
*/
@@ -459,7 +464,7 @@
/* fallthrough */
case -ERESTARTNOINTR:
regs->d0 = regs->orig_d0;
- regs->pc -= 2;
+ stepback(regs);
}
}
@@ -527,12 +532,12 @@
case -ERESTARTSYS:
case -ERESTARTNOINTR:
regs->d0 = regs->orig_d0;
- regs->pc -= 2;
+ stepback(regs);
break;
case -ERESTART_RESTARTBLOCK:
regs->d0 = __NR_restart_syscall;
- regs->pc -= 2;
+ stepback(regs);
break;
}
}
diff --git a/arch/mn10300/mm/Makefile b/arch/mn10300/mm/Makefile
index 28b9d98..1557277 100644
--- a/arch/mn10300/mm/Makefile
+++ b/arch/mn10300/mm/Makefile
@@ -2,13 +2,11 @@
# Makefile for the MN10300-specific memory management code
#
+cacheflush-y := cache.o cache-mn10300.o
+cacheflush-$(CONFIG_MN10300_CACHE_WBACK) += cache-flush-mn10300.o
+
+cacheflush-$(CONFIG_MN10300_CACHE_DISABLED) := cache-disabled.o
+
obj-y := \
init.o fault.o pgtable.o extable.o tlb-mn10300.o mmu-context.o \
- misalignment.o dma-alloc.o
-
-ifneq ($(CONFIG_MN10300_CACHE_DISABLED),y)
-obj-y += cache.o cache-mn10300.o
-ifeq ($(CONFIG_MN10300_CACHE_WBACK),y)
-obj-y += cache-flush-mn10300.o
-endif
-endif
+ misalignment.o dma-alloc.o $(cacheflush-y)
diff --git a/arch/mn10300/mm/cache-disabled.c b/arch/mn10300/mm/cache-disabled.c
new file mode 100644
index 0000000..f669ea4
--- /dev/null
+++ b/arch/mn10300/mm/cache-disabled.c
@@ -0,0 +1,21 @@
+/* Handle the cache being disabled
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/mm.h>
+
+/*
+ * allow userspace to flush the instruction cache
+ */
+asmlinkage long sys_cacheflush(unsigned long start, unsigned long end)
+{
+ if (end < start)
+ return -EINVAL;
+ return 0;
+}
diff --git a/arch/mn10300/mm/cache.c b/arch/mn10300/mm/cache.c
index 1b76719..9261217 100644
--- a/arch/mn10300/mm/cache.c
+++ b/arch/mn10300/mm/cache.c
@@ -54,13 +54,30 @@
void flush_icache_range(unsigned long start, unsigned long end)
{
#ifdef CONFIG_MN10300_CACHE_WBACK
- unsigned long addr, size, off;
+ unsigned long addr, size, base, off;
struct page *page;
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
pte_t *ppte, pte;
+ if (end > 0x80000000UL) {
+ /* addresses above 0xa0000000 do not go through the cache */
+ if (end > 0xa0000000UL) {
+ end = 0xa0000000UL;
+ if (start >= end)
+ return;
+ }
+
+ /* kernel addresses between 0x80000000 and 0x9fffffff do not
+ * require page tables, so we just map such addresses directly */
+ base = (start >= 0x80000000UL) ? start : 0x80000000UL;
+ mn10300_dcache_flush_range(base, end);
+ if (base == start)
+ goto invalidate;
+ end = base;
+ }
+
for (; start < end; start += size) {
/* work out how much of the page to flush */
off = start & (PAGE_SIZE - 1);
@@ -104,6 +121,7 @@
}
#endif
+invalidate:
mn10300_icache_inv();
}
EXPORT_SYMBOL(flush_icache_range);
diff --git a/arch/parisc/include/asm/compat.h b/arch/parisc/include/asm/compat.h
index 02b77ba..efa0b60 100644
--- a/arch/parisc/include/asm/compat.h
+++ b/arch/parisc/include/asm/compat.h
@@ -147,7 +147,7 @@
return (u32)(unsigned long)uptr;
}
-static __inline__ void __user *compat_alloc_user_space(long len)
+static __inline__ void __user *arch_compat_alloc_user_space(long len)
{
struct pt_regs *regs = ¤t->thread.regs;
return (void __user *)regs->gr[30];
diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c
index 159a2b8..6e81bb5 100644
--- a/arch/parisc/kernel/module.c
+++ b/arch/parisc/kernel/module.c
@@ -941,11 +941,10 @@
nsyms = newptr - (Elf_Sym *)symhdr->sh_addr;
DEBUGP("NEW num_symtab %lu\n", nsyms);
symhdr->sh_size = nsyms * sizeof(Elf_Sym);
- return module_bug_finalize(hdr, sechdrs, me);
+ return 0;
}
void module_arch_cleanup(struct module *mod)
{
deregister_unwind_table(mod);
- module_bug_cleanup(mod);
}
diff --git a/arch/powerpc/boot/dts/mpc8610_hpcd.dts b/arch/powerpc/boot/dts/mpc8610_hpcd.dts
index 9535ce6..83c3218 100644
--- a/arch/powerpc/boot/dts/mpc8610_hpcd.dts
+++ b/arch/powerpc/boot/dts/mpc8610_hpcd.dts
@@ -286,6 +286,7 @@
ssi@16100 {
compatible = "fsl,mpc8610-ssi";
+ status = "disabled";
cell-index = <1>;
reg = <0x16100 0x100>;
interrupt-parent = <&mpic>;
diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig
index c3b113b..3aeb594 100644
--- a/arch/powerpc/configs/mpc85xx_defconfig
+++ b/arch/powerpc/configs/mpc85xx_defconfig
@@ -124,6 +124,9 @@
CONFIG_I2C_MPC=y
# CONFIG_HWMON is not set
CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FB_FSL_DIU=y
+# CONFIG_VGA_CONSOLE is not set
CONFIG_SOUND=y
CONFIG_SND=y
# CONFIG_SND_SUPPORT_OLD_API is not set
diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig
index a075da2..d62c801 100644
--- a/arch/powerpc/configs/mpc85xx_smp_defconfig
+++ b/arch/powerpc/configs/mpc85xx_smp_defconfig
@@ -126,6 +126,9 @@
CONFIG_I2C_MPC=y
# CONFIG_HWMON is not set
CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FB_FSL_DIU=y
+# CONFIG_VGA_CONSOLE is not set
CONFIG_SOUND=y
CONFIG_SND=y
# CONFIG_SND_SUPPORT_OLD_API is not set
diff --git a/arch/powerpc/include/asm/compat.h b/arch/powerpc/include/asm/compat.h
index 396d21a..a11d4ea 100644
--- a/arch/powerpc/include/asm/compat.h
+++ b/arch/powerpc/include/asm/compat.h
@@ -134,7 +134,7 @@
return (u32)(unsigned long)uptr;
}
-static inline void __user *compat_alloc_user_space(long len)
+static inline void __user *arch_compat_alloc_user_space(long len)
{
struct pt_regs *regs = current->thread.regs;
unsigned long usp = regs->gpr[1];
diff --git a/arch/powerpc/include/asm/immap_86xx.h b/arch/powerpc/include/asm/fsl_guts.h
similarity index 66%
rename from arch/powerpc/include/asm/immap_86xx.h
rename to arch/powerpc/include/asm/fsl_guts.h
index 0f165e5..bebd124 100644
--- a/arch/powerpc/include/asm/immap_86xx.h
+++ b/arch/powerpc/include/asm/fsl_guts.h
@@ -1,5 +1,5 @@
/**
- * MPC86xx Internal Memory Map
+ * Freecale 85xx and 86xx Global Utilties register set
*
* Authors: Jeff Brown
* Timur Tabi <timur@freescale.com>
@@ -10,73 +10,112 @@
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
- *
- * This header file defines structures for various 86xx SOC devices that are
- * used by multiple source files.
*/
-#ifndef __ASM_POWERPC_IMMAP_86XX_H__
-#define __ASM_POWERPC_IMMAP_86XX_H__
+#ifndef __ASM_POWERPC_FSL_GUTS_H__
+#define __ASM_POWERPC_FSL_GUTS_H__
#ifdef __KERNEL__
-/* Global Utility Registers */
-struct ccsr_guts {
+/*
+ * These #ifdefs are safe because it's not possible to build a kernel that
+ * runs on e500 and e600 cores.
+ */
+
+#if !defined(CONFIG_PPC_85xx) && !defined(CONFIG_PPC_86xx)
+#error Only 85xx and 86xx SOCs are supported
+#endif
+
+/**
+ * Global Utility Registers.
+ *
+ * Not all registers defined in this structure are available on all chips, so
+ * you are expected to know whether a given register actually exists on your
+ * chip before you access it.
+ *
+ * Also, some registers are similar on different chips but have slightly
+ * different names. In these cases, one name is chosen to avoid extraneous
+ * #ifdefs.
+ */
+#ifdef CONFIG_PPC_85xx
+struct ccsr_guts_85xx {
+#else
+struct ccsr_guts_86xx {
+#endif
__be32 porpllsr; /* 0x.0000 - POR PLL Ratio Status Register */
__be32 porbmsr; /* 0x.0004 - POR Boot Mode Status Register */
__be32 porimpscr; /* 0x.0008 - POR I/O Impedance Status and Control Register */
__be32 pordevsr; /* 0x.000c - POR I/O Device Status Register */
__be32 pordbgmsr; /* 0x.0010 - POR Debug Mode Status Register */
- u8 res1[0x20 - 0x14];
+ __be32 pordevsr2; /* 0x.0014 - POR device status register 2 */
+ u8 res018[0x20 - 0x18];
__be32 porcir; /* 0x.0020 - POR Configuration Information Register */
- u8 res2[0x30 - 0x24];
+ u8 res024[0x30 - 0x24];
__be32 gpiocr; /* 0x.0030 - GPIO Control Register */
- u8 res3[0x40 - 0x34];
+ u8 res034[0x40 - 0x34];
__be32 gpoutdr; /* 0x.0040 - General-Purpose Output Data Register */
- u8 res4[0x50 - 0x44];
+ u8 res044[0x50 - 0x44];
__be32 gpindr; /* 0x.0050 - General-Purpose Input Data Register */
- u8 res5[0x60 - 0x54];
+ u8 res054[0x60 - 0x54];
__be32 pmuxcr; /* 0x.0060 - Alternate Function Signal Multiplex Control */
- u8 res6[0x70 - 0x64];
+ __be32 pmuxcr2; /* 0x.0064 - Alternate function signal multiplex control 2 */
+ __be32 dmuxcr; /* 0x.0068 - DMA Mux Control Register */
+ u8 res06c[0x70 - 0x6c];
__be32 devdisr; /* 0x.0070 - Device Disable Control */
__be32 devdisr2; /* 0x.0074 - Device Disable Control 2 */
- u8 res7[0x80 - 0x78];
+ u8 res078[0x7c - 0x78];
+ __be32 pmjcr; /* 0x.007c - 4 Power Management Jog Control Register */
__be32 powmgtcsr; /* 0x.0080 - Power Management Status and Control Register */
- u8 res8[0x90 - 0x84];
+ __be32 pmrccr; /* 0x.0084 - Power Management Reset Counter Configuration Register */
+ __be32 pmpdccr; /* 0x.0088 - Power Management Power Down Counter Configuration Register */
+ __be32 pmcdr; /* 0x.008c - 4Power management clock disable register */
__be32 mcpsumr; /* 0x.0090 - Machine Check Summary Register */
__be32 rstrscr; /* 0x.0094 - Reset Request Status and Control Register */
- u8 res9[0xA0 - 0x98];
+ __be32 ectrstcr; /* 0x.0098 - Exception reset control register */
+ __be32 autorstsr; /* 0x.009c - Automatic reset status register */
__be32 pvr; /* 0x.00a0 - Processor Version Register */
__be32 svr; /* 0x.00a4 - System Version Register */
- u8 res10[0xB0 - 0xA8];
+ u8 res0a8[0xb0 - 0xa8];
__be32 rstcr; /* 0x.00b0 - Reset Control Register */
- u8 res11[0xC0 - 0xB4];
+ u8 res0b4[0xc0 - 0xb4];
+#ifdef CONFIG_PPC_85xx
+ __be32 iovselsr; /* 0x.00c0 - I/O voltage select status register */
+#else
__be32 elbcvselcr; /* 0x.00c0 - eLBC Voltage Select Ctrl Reg */
- u8 res12[0x800 - 0xC4];
+#endif
+ u8 res0c4[0x224 - 0xc4];
+ __be32 iodelay1; /* 0x.0224 - IO delay control register 1 */
+ __be32 iodelay2; /* 0x.0228 - IO delay control register 2 */
+ u8 res22c[0x800 - 0x22c];
__be32 clkdvdr; /* 0x.0800 - Clock Divide Register */
- u8 res13[0x900 - 0x804];
+ u8 res804[0x900 - 0x804];
__be32 ircr; /* 0x.0900 - Infrared Control Register */
- u8 res14[0x908 - 0x904];
+ u8 res904[0x908 - 0x904];
__be32 dmacr; /* 0x.0908 - DMA Control Register */
- u8 res15[0x914 - 0x90C];
+ u8 res90c[0x914 - 0x90c];
__be32 elbccr; /* 0x.0914 - eLBC Control Register */
- u8 res16[0xB20 - 0x918];
+ u8 res918[0xb20 - 0x918];
__be32 ddr1clkdr; /* 0x.0b20 - DDR1 Clock Disable Register */
__be32 ddr2clkdr; /* 0x.0b24 - DDR2 Clock Disable Register */
__be32 ddrclkdr; /* 0x.0b28 - DDR Clock Disable Register */
- u8 res17[0xE00 - 0xB2C];
+ u8 resb2c[0xe00 - 0xb2c];
__be32 clkocr; /* 0x.0e00 - Clock Out Select Register */
- u8 res18[0xE10 - 0xE04];
+ u8 rese04[0xe10 - 0xe04];
__be32 ddrdllcr; /* 0x.0e10 - DDR DLL Control Register */
- u8 res19[0xE20 - 0xE14];
+ u8 rese14[0xe20 - 0xe14];
__be32 lbcdllcr; /* 0x.0e20 - LBC DLL Control Register */
- u8 res20[0xF04 - 0xE24];
+ __be32 cpfor; /* 0x.0e24 - L2 charge pump fuse override register */
+ u8 rese28[0xf04 - 0xe28];
__be32 srds1cr0; /* 0x.0f04 - SerDes1 Control Register 0 */
__be32 srds1cr1; /* 0x.0f08 - SerDes1 Control Register 0 */
- u8 res21[0xF40 - 0xF0C];
- __be32 srds2cr0; /* 0x.0f40 - SerDes1 Control Register 0 */
- __be32 srds2cr1; /* 0x.0f44 - SerDes1 Control Register 0 */
+ u8 resf0c[0xf2c - 0xf0c];
+ __be32 itcr; /* 0x.0f2c - Internal transaction control register */
+ u8 resf30[0xf40 - 0xf30];
+ __be32 srds2cr0; /* 0x.0f40 - SerDes2 Control Register 0 */
+ __be32 srds2cr1; /* 0x.0f44 - SerDes2 Control Register 0 */
} __attribute__ ((packed));
+#ifdef CONFIG_PPC_86xx
+
#define CCSR_GUTS_DMACR_DEV_SSI 0 /* DMA controller/channel set to SSI */
#define CCSR_GUTS_DMACR_DEV_IR 1 /* DMA controller/channel set to IR */
@@ -93,7 +132,7 @@
* ch: The channel on the DMA controller (0, 1, 2, or 3)
* device: The device to set as the source (CCSR_GUTS_DMACR_DEV_xx)
*/
-static inline void guts_set_dmacr(struct ccsr_guts __iomem *guts,
+static inline void guts_set_dmacr(struct ccsr_guts_86xx __iomem *guts,
unsigned int co, unsigned int ch, unsigned int device)
{
unsigned int shift = 16 + (8 * (1 - co) + 2 * (3 - ch));
@@ -129,7 +168,7 @@
* ch: The channel on the DMA controller (0, 1, 2, or 3)
* value: the new value for the bit (0 or 1)
*/
-static inline void guts_set_pmuxcr_dma(struct ccsr_guts __iomem *guts,
+static inline void guts_set_pmuxcr_dma(struct ccsr_guts_86xx __iomem *guts,
unsigned int co, unsigned int ch, unsigned int value)
{
if ((ch == 0) || (ch == 3)) {
@@ -152,5 +191,7 @@
#define CCSR_GUTS_CLKDVDR_SSICLK_MASK 0x000000FF
#define CCSR_GUTS_CLKDVDR_SSICLK(x) ((x) & CCSR_GUTS_CLKDVDR_SSICLK_MASK)
-#endif /* __ASM_POWERPC_IMMAP_86XX_H__ */
-#endif /* __KERNEL__ */
+#endif
+
+#endif
+#endif
diff --git a/arch/powerpc/kernel/module.c b/arch/powerpc/kernel/module.c
index 477c663..49cee9d 100644
--- a/arch/powerpc/kernel/module.c
+++ b/arch/powerpc/kernel/module.c
@@ -63,11 +63,6 @@
const Elf_Shdr *sechdrs, struct module *me)
{
const Elf_Shdr *sect;
- int err;
-
- err = module_bug_finalize(hdr, sechdrs, me);
- if (err)
- return err;
/* Apply feature fixups */
sect = find_section(hdr, sechdrs, "__ftr_fixup");
@@ -101,5 +96,4 @@
void module_arch_cleanup(struct module *mod)
{
- module_bug_cleanup(mod);
}
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c
index 7109f5b..2300426 100644
--- a/arch/powerpc/kernel/signal.c
+++ b/arch/powerpc/kernel/signal.c
@@ -138,6 +138,7 @@
ti->local_flags &= ~_TLF_RESTORE_SIGMASK;
sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
}
+ regs->trap = 0;
return 0; /* no signals delivered */
}
@@ -164,6 +165,7 @@
ret = handle_rt_signal64(signr, &ka, &info, oldset, regs);
}
+ regs->trap = 0;
if (ret) {
spin_lock_irq(¤t->sighand->siglock);
sigorsets(¤t->blocked, ¤t->blocked,
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 2666101..b96a3a0 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -511,6 +511,7 @@
if (!sig)
save_r2 = (unsigned int)regs->gpr[2];
err = restore_general_regs(regs, sr);
+ regs->trap = 0;
err |= __get_user(msr, &sr->mc_gregs[PT_MSR]);
if (!sig)
regs->gpr[2] = (unsigned long) save_r2;
@@ -884,7 +885,6 @@
regs->nip = (unsigned long) ka->sa.sa_handler;
/* enter the signal handler in big-endian mode */
regs->msr &= ~MSR_LE;
- regs->trap = 0;
return 1;
badframe:
@@ -1228,7 +1228,6 @@
regs->nip = (unsigned long) ka->sa.sa_handler;
/* enter the signal handler in big-endian mode */
regs->msr &= ~MSR_LE;
- regs->trap = 0;
return 1;
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index 2fe6fc6..27c4a45 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -178,7 +178,7 @@
err |= __get_user(regs->xer, &sc->gp_regs[PT_XER]);
err |= __get_user(regs->ccr, &sc->gp_regs[PT_CCR]);
/* skip SOFTE */
- err |= __get_user(regs->trap, &sc->gp_regs[PT_TRAP]);
+ regs->trap = 0;
err |= __get_user(regs->dar, &sc->gp_regs[PT_DAR]);
err |= __get_user(regs->dsisr, &sc->gp_regs[PT_DSISR]);
err |= __get_user(regs->result, &sc->gp_regs[PT_RESULT]);
diff --git a/arch/powerpc/platforms/512x/clock.c b/arch/powerpc/platforms/512x/clock.c
index 5b243bd..3dc2a8d 100644
--- a/arch/powerpc/platforms/512x/clock.c
+++ b/arch/powerpc/platforms/512x/clock.c
@@ -57,7 +57,7 @@
int id_match = 0;
if (dev == NULL || id == NULL)
- return NULL;
+ return clk;
mutex_lock(&clocks_mutex);
list_for_each_entry(p, &clocks, node) {
diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c
index 45c0cb9..18c1048 100644
--- a/arch/powerpc/platforms/52xx/efika.c
+++ b/arch/powerpc/platforms/52xx/efika.c
@@ -99,7 +99,7 @@
if (bus_range == NULL || len < 2 * sizeof(int)) {
printk(KERN_WARNING EFIKA_PLATFORM_NAME
": Can't get bus-range for %s\n", pcictrl->full_name);
- return;
+ goto out_put;
}
if (bus_range[1] == bus_range[0])
@@ -111,12 +111,12 @@
printk(" controlled by %s\n", pcictrl->full_name);
printk("\n");
- hose = pcibios_alloc_controller(of_node_get(pcictrl));
+ hose = pcibios_alloc_controller(pcictrl);
if (!hose) {
printk(KERN_WARNING EFIKA_PLATFORM_NAME
": Can't allocate PCI controller structure for %s\n",
pcictrl->full_name);
- return;
+ goto out_put;
}
hose->first_busno = bus_range[0];
@@ -124,6 +124,9 @@
hose->ops = &rtas_pci_ops;
pci_process_bridge_OF_ranges(hose, pcictrl, 0);
+ return;
+out_put:
+ of_node_put(pcictrl);
}
#else
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c
index 6e90531..41f3a7e 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_common.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c
@@ -325,12 +325,16 @@
clrbits32(&simple_gpio->simple_dvo, sync | out);
clrbits8(&wkup_gpio->wkup_dvo, reset);
- /* wait at lease 1 us */
- udelay(2);
+ /* wait for 1 us */
+ udelay(1);
/* Deassert reset */
setbits8(&wkup_gpio->wkup_dvo, reset);
+ /* wait at least 200ns */
+ /* 7 ~= (200ns * timebase) / ns2sec */
+ __delay(7);
+
/* Restore pin-muxing */
out_be32(&simple_gpio->port_config, mux);
diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c
index 34e0090..e15afdf 100644
--- a/arch/powerpc/platforms/85xx/p1022_ds.c
+++ b/arch/powerpc/platforms/85xx/p1022_ds.c
@@ -8,7 +8,6 @@
* Copyright 2010 Freescale Semiconductor, Inc.
*
* This file is taken from the Freescale P1022DS BSP, with modifications:
- * 1) No DIU support (pending rewrite of DIU code)
* 2) No AMP support
* 3) No PCI endpoint support
*
@@ -20,12 +19,211 @@
#include <linux/pci.h>
#include <linux/of_platform.h>
#include <linux/memblock.h>
-
+#include <asm/div64.h>
#include <asm/mpic.h>
#include <asm/swiotlb.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
+#include <asm/fsl_guts.h>
+
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+
+/*
+ * Board-specific initialization of the DIU. This code should probably be
+ * executed when the DIU is opened, rather than in arch code, but the DIU
+ * driver does not have a mechanism for this (yet).
+ *
+ * This is especially problematic on the P1022DS because the local bus (eLBC)
+ * and the DIU video signals share the same pins, which means that enabling the
+ * DIU will disable access to NOR flash.
+ */
+
+/* DIU Pixel Clock bits of the CLKDVDR Global Utilities register */
+#define CLKDVDR_PXCKEN 0x80000000
+#define CLKDVDR_PXCKINV 0x10000000
+#define CLKDVDR_PXCKDLY 0x06000000
+#define CLKDVDR_PXCLK_MASK 0x00FF0000
+
+/* Some ngPIXIS register definitions */
+#define PX_BRDCFG1_DVIEN 0x80
+#define PX_BRDCFG1_DFPEN 0x40
+#define PX_BRDCFG1_BACKLIGHT 0x20
+#define PX_BRDCFG1_DDCEN 0x10
+
+/*
+ * DIU Area Descriptor
+ *
+ * Note that we need to byte-swap the value before it's written to the AD
+ * register. So even though the registers don't look like they're in the same
+ * bit positions as they are on the MPC8610, the same value is written to the
+ * AD register on the MPC8610 and on the P1022.
+ */
+#define AD_BYTE_F 0x10000000
+#define AD_ALPHA_C_MASK 0x0E000000
+#define AD_ALPHA_C_SHIFT 25
+#define AD_BLUE_C_MASK 0x01800000
+#define AD_BLUE_C_SHIFT 23
+#define AD_GREEN_C_MASK 0x00600000
+#define AD_GREEN_C_SHIFT 21
+#define AD_RED_C_MASK 0x00180000
+#define AD_RED_C_SHIFT 19
+#define AD_PALETTE 0x00040000
+#define AD_PIXEL_S_MASK 0x00030000
+#define AD_PIXEL_S_SHIFT 16
+#define AD_COMP_3_MASK 0x0000F000
+#define AD_COMP_3_SHIFT 12
+#define AD_COMP_2_MASK 0x00000F00
+#define AD_COMP_2_SHIFT 8
+#define AD_COMP_1_MASK 0x000000F0
+#define AD_COMP_1_SHIFT 4
+#define AD_COMP_0_MASK 0x0000000F
+#define AD_COMP_0_SHIFT 0
+
+#define MAKE_AD(alpha, red, blue, green, size, c0, c1, c2, c3) \
+ cpu_to_le32(AD_BYTE_F | (alpha << AD_ALPHA_C_SHIFT) | \
+ (blue << AD_BLUE_C_SHIFT) | (green << AD_GREEN_C_SHIFT) | \
+ (red << AD_RED_C_SHIFT) | (c3 << AD_COMP_3_SHIFT) | \
+ (c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \
+ (c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT))
+
+/**
+ * p1022ds_get_pixel_format: return the Area Descriptor for a given pixel depth
+ *
+ * The Area Descriptor is a 32-bit value that determine which bits in each
+ * pixel are to be used for each color.
+ */
+static unsigned int p1022ds_get_pixel_format(unsigned int bits_per_pixel,
+ int monitor_port)
+{
+ switch (bits_per_pixel) {
+ case 32:
+ /* 0x88883316 */
+ return MAKE_AD(3, 2, 0, 1, 3, 8, 8, 8, 8);
+ case 24:
+ /* 0x88082219 */
+ return MAKE_AD(4, 0, 1, 2, 2, 0, 8, 8, 8);
+ case 16:
+ /* 0x65053118 */
+ return MAKE_AD(4, 2, 1, 0, 1, 5, 6, 5, 0);
+ default:
+ pr_err("fsl-diu: unsupported pixel depth %u\n", bits_per_pixel);
+ return 0;
+ }
+}
+
+/**
+ * p1022ds_set_gamma_table: update the gamma table, if necessary
+ *
+ * On some boards, the gamma table for some ports may need to be modified.
+ * This is not the case on the P1022DS, so we do nothing.
+*/
+static void p1022ds_set_gamma_table(int monitor_port, char *gamma_table_base)
+{
+}
+
+/**
+ * p1022ds_set_monitor_port: switch the output to a different monitor port
+ *
+ */
+static void p1022ds_set_monitor_port(int monitor_port)
+{
+ struct device_node *pixis_node;
+ u8 __iomem *brdcfg1;
+
+ pixis_node = of_find_compatible_node(NULL, NULL, "fsl,p1022ds-pixis");
+ if (!pixis_node) {
+ pr_err("p1022ds: missing ngPIXIS node\n");
+ return;
+ }
+
+ brdcfg1 = of_iomap(pixis_node, 0);
+ if (!brdcfg1) {
+ pr_err("p1022ds: could not map ngPIXIS registers\n");
+ return;
+ }
+ brdcfg1 += 9; /* BRDCFG1 is at offset 9 in the ngPIXIS */
+
+ switch (monitor_port) {
+ case 0: /* DVI */
+ /* Enable the DVI port, disable the DFP and the backlight */
+ clrsetbits_8(brdcfg1, PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT,
+ PX_BRDCFG1_DVIEN);
+ break;
+ case 1: /* Single link LVDS */
+ /* Enable the DFP port, disable the DVI and the backlight */
+ clrsetbits_8(brdcfg1, PX_BRDCFG1_DVIEN | PX_BRDCFG1_BACKLIGHT,
+ PX_BRDCFG1_DFPEN);
+ break;
+ default:
+ pr_err("p1022ds: unsupported monitor port %i\n", monitor_port);
+ }
+}
+
+/**
+ * p1022ds_set_pixel_clock: program the DIU's clock
+ *
+ * @pixclock: the wavelength, in picoseconds, of the clock
+ */
+void p1022ds_set_pixel_clock(unsigned int pixclock)
+{
+ struct device_node *guts_np = NULL;
+ struct ccsr_guts_85xx __iomem *guts;
+ unsigned long freq;
+ u64 temp;
+ u32 pxclk;
+
+ /* Map the global utilities registers. */
+ guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");
+ if (!guts_np) {
+ pr_err("p1022ds: missing global utilties device node\n");
+ return;
+ }
+
+ guts = of_iomap(guts_np, 0);
+ of_node_put(guts_np);
+ if (!guts) {
+ pr_err("p1022ds: could not map global utilties device\n");
+ return;
+ }
+
+ /* Convert pixclock from a wavelength to a frequency */
+ temp = 1000000000000ULL;
+ do_div(temp, pixclock);
+ freq = temp;
+
+ /* pixclk is the ratio of the platform clock to the pixel clock */
+ pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq);
+
+ /* Disable the pixel clock, and set it to non-inverted and no delay */
+ clrbits32(&guts->clkdvdr,
+ CLKDVDR_PXCKEN | CLKDVDR_PXCKDLY | CLKDVDR_PXCLK_MASK);
+
+ /* Enable the clock and set the pxclk */
+ setbits32(&guts->clkdvdr, CLKDVDR_PXCKEN | (pxclk << 16));
+}
+
+/**
+ * p1022ds_show_monitor_port: show the current monitor
+ *
+ * This function returns a string indicating whether the current monitor is
+ * set to DVI or LVDS.
+ */
+ssize_t p1022ds_show_monitor_port(int monitor_port, char *buf)
+{
+ return sprintf(buf, "%c0 - DVI\n%c1 - Single link LVDS\n",
+ monitor_port == 0 ? '*' : ' ', monitor_port == 1 ? '*' : ' ');
+}
+
+/**
+ * p1022ds_set_sysfs_monitor_port: set the monitor port for sysfs
+ */
+int p1022ds_set_sysfs_monitor_port(int val)
+{
+ return val < 2 ? val : 0;
+}
+
+#endif
void __init p1022_ds_pic_init(void)
{
@@ -92,6 +290,15 @@
}
#endif
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+ diu_ops.get_pixel_format = p1022ds_get_pixel_format;
+ diu_ops.set_gamma_table = p1022ds_set_gamma_table;
+ diu_ops.set_monitor_port = p1022ds_set_monitor_port;
+ diu_ops.set_pixel_clock = p1022ds_set_pixel_clock;
+ diu_ops.show_monitor_port = p1022ds_show_monitor_port;
+ diu_ops.set_sysfs_monitor_port = p1022ds_set_sysfs_monitor_port;
+#endif
+
#ifdef CONFIG_SMP
mpc85xx_smp_init();
#endif
diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h
index 104f200..a875c2f 100644
--- a/arch/s390/include/asm/compat.h
+++ b/arch/s390/include/asm/compat.h
@@ -181,7 +181,7 @@
#endif
-static inline void __user *compat_alloc_user_space(long len)
+static inline void __user *arch_compat_alloc_user_space(long len)
{
unsigned long stack;
diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c
index 22cfd63..f7167ee 100644
--- a/arch/s390/kernel/module.c
+++ b/arch/s390/kernel/module.c
@@ -407,10 +407,9 @@
{
vfree(me->arch.syminfo);
me->arch.syminfo = NULL;
- return module_bug_finalize(hdr, sechdrs, me);
+ return 0;
}
void module_arch_cleanup(struct module *mod)
{
- module_bug_cleanup(mod);
}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
index 156ccc9..d551ed8 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
@@ -551,7 +551,7 @@
};
static struct platform_device siu_device = {
- .name = "sh_siu",
+ .name = "siu-pcm-audio",
.id = -1,
.dev = {
.platform_data = &siu_platform_data,
diff --git a/arch/sh/kernel/module.c b/arch/sh/kernel/module.c
index 43adddf..ae0be69 100644
--- a/arch/sh/kernel/module.c
+++ b/arch/sh/kernel/module.c
@@ -149,13 +149,11 @@
int ret = 0;
ret |= module_dwarf_finalize(hdr, sechdrs, me);
- ret |= module_bug_finalize(hdr, sechdrs, me);
return ret;
}
void module_arch_cleanup(struct module *mod)
{
- module_bug_cleanup(mod);
module_dwarf_cleanup(mod);
}
diff --git a/arch/sparc/include/asm/compat.h b/arch/sparc/include/asm/compat.h
index 5016f76..6f57325 100644
--- a/arch/sparc/include/asm/compat.h
+++ b/arch/sparc/include/asm/compat.h
@@ -167,7 +167,7 @@
return (u32)(unsigned long)uptr;
}
-static inline void __user *compat_alloc_user_space(long len)
+static inline void __user *arch_compat_alloc_user_space(long len)
{
struct pt_regs *regs = current_thread_info()->kregs;
unsigned long usp = regs->u_regs[UREG_I6];
diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c
index 357ced3..6318e62 100644
--- a/arch/sparc/kernel/perf_event.c
+++ b/arch/sparc/kernel/perf_event.c
@@ -1038,6 +1038,7 @@
if (atomic_read(&nmi_active) < 0)
return -ENODEV;
+ pmap = NULL;
if (attr->type == PERF_TYPE_HARDWARE) {
if (attr->config >= sparc_pmu->max_events)
return -EINVAL;
@@ -1046,9 +1047,18 @@
pmap = sparc_map_cache_event(attr->config);
if (IS_ERR(pmap))
return PTR_ERR(pmap);
- } else
+ } else if (attr->type != PERF_TYPE_RAW)
return -EOPNOTSUPP;
+ if (pmap) {
+ hwc->event_base = perf_event_encode(pmap);
+ } else {
+ /* User gives us "(encoding << 16) | pic_mask" for
+ * PERF_TYPE_RAW events.
+ */
+ hwc->event_base = attr->config;
+ }
+
/* We save the enable bits in the config_base. */
hwc->config_base = sparc_pmu->irq_bit;
if (!attr->exclude_user)
@@ -1058,8 +1068,6 @@
if (!attr->exclude_hv)
hwc->config_base |= sparc_pmu->hv_bit;
- hwc->event_base = perf_event_encode(pmap);
-
n = 0;
if (event->group_leader != event) {
n = collect_events(event->group_leader,
diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c
index ea22cd3..75fad42 100644
--- a/arch/sparc/kernel/signal32.c
+++ b/arch/sparc/kernel/signal32.c
@@ -453,8 +453,66 @@
return err;
}
-static void setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
- int signo, sigset_t *oldset)
+/* The I-cache flush instruction only works in the primary ASI, which
+ * right now is the nucleus, aka. kernel space.
+ *
+ * Therefore we have to kick the instructions out using the kernel
+ * side linear mapping of the physical address backing the user
+ * instructions.
+ */
+static void flush_signal_insns(unsigned long address)
+{
+ unsigned long pstate, paddr;
+ pte_t *ptep, pte;
+ pgd_t *pgdp;
+ pud_t *pudp;
+ pmd_t *pmdp;
+
+ /* Commit all stores of the instructions we are about to flush. */
+ wmb();
+
+ /* Disable cross-call reception. In this way even a very wide
+ * munmap() on another cpu can't tear down the page table
+ * hierarchy from underneath us, since that can't complete
+ * until the IPI tlb flush returns.
+ */
+
+ __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
+ __asm__ __volatile__("wrpr %0, %1, %%pstate"
+ : : "r" (pstate), "i" (PSTATE_IE));
+
+ pgdp = pgd_offset(current->mm, address);
+ if (pgd_none(*pgdp))
+ goto out_irqs_on;
+ pudp = pud_offset(pgdp, address);
+ if (pud_none(*pudp))
+ goto out_irqs_on;
+ pmdp = pmd_offset(pudp, address);
+ if (pmd_none(*pmdp))
+ goto out_irqs_on;
+
+ ptep = pte_offset_map(pmdp, address);
+ pte = *ptep;
+ if (!pte_present(pte))
+ goto out_unmap;
+
+ paddr = (unsigned long) page_address(pte_page(pte));
+
+ __asm__ __volatile__("flush %0 + %1"
+ : /* no outputs */
+ : "r" (paddr),
+ "r" (address & (PAGE_SIZE - 1))
+ : "memory");
+
+out_unmap:
+ pte_unmap(ptep);
+out_irqs_on:
+ __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate));
+
+}
+
+static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
+ int signo, sigset_t *oldset)
{
struct signal_frame32 __user *sf;
int sigframe_size;
@@ -547,13 +605,7 @@
if (ka->ka_restorer) {
regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
} else {
- /* Flush instruction space. */
unsigned long address = ((unsigned long)&(sf->insns[0]));
- pgd_t *pgdp = pgd_offset(current->mm, address);
- pud_t *pudp = pud_offset(pgdp, address);
- pmd_t *pmdp = pmd_offset(pudp, address);
- pte_t *ptep;
- pte_t pte;
regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
@@ -562,34 +614,22 @@
if (err)
goto sigsegv;
- preempt_disable();
- ptep = pte_offset_map(pmdp, address);
- pte = *ptep;
- if (pte_present(pte)) {
- unsigned long page = (unsigned long)
- page_address(pte_page(pte));
-
- wmb();
- __asm__ __volatile__("flush %0 + %1"
- : /* no outputs */
- : "r" (page),
- "r" (address & (PAGE_SIZE - 1))
- : "memory");
- }
- pte_unmap(ptep);
- preempt_enable();
+ flush_signal_insns(address);
}
- return;
+ return 0;
sigill:
do_exit(SIGILL);
+ return -EINVAL;
+
sigsegv:
force_sigsegv(signo, current);
+ return -EFAULT;
}
-static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
- unsigned long signr, sigset_t *oldset,
- siginfo_t *info)
+static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
+ unsigned long signr, sigset_t *oldset,
+ siginfo_t *info)
{
struct rt_signal_frame32 __user *sf;
int sigframe_size;
@@ -687,12 +727,7 @@
if (ka->ka_restorer)
regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
else {
- /* Flush instruction space. */
unsigned long address = ((unsigned long)&(sf->insns[0]));
- pgd_t *pgdp = pgd_offset(current->mm, address);
- pud_t *pudp = pud_offset(pgdp, address);
- pmd_t *pmdp = pmd_offset(pudp, address);
- pte_t *ptep;
regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
@@ -704,38 +739,32 @@
if (err)
goto sigsegv;
- preempt_disable();
- ptep = pte_offset_map(pmdp, address);
- if (pte_present(*ptep)) {
- unsigned long page = (unsigned long)
- page_address(pte_page(*ptep));
-
- wmb();
- __asm__ __volatile__("flush %0 + %1"
- : /* no outputs */
- : "r" (page),
- "r" (address & (PAGE_SIZE - 1))
- : "memory");
- }
- pte_unmap(ptep);
- preempt_enable();
+ flush_signal_insns(address);
}
- return;
+ return 0;
sigill:
do_exit(SIGILL);
+ return -EINVAL;
+
sigsegv:
force_sigsegv(signr, current);
+ return -EFAULT;
}
-static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka,
- siginfo_t *info,
- sigset_t *oldset, struct pt_regs *regs)
+static inline int handle_signal32(unsigned long signr, struct k_sigaction *ka,
+ siginfo_t *info,
+ sigset_t *oldset, struct pt_regs *regs)
{
+ int err;
+
if (ka->sa.sa_flags & SA_SIGINFO)
- setup_rt_frame32(ka, regs, signr, oldset, info);
+ err = setup_rt_frame32(ka, regs, signr, oldset, info);
else
- setup_frame32(ka, regs, signr, oldset);
+ err = setup_frame32(ka, regs, signr, oldset);
+
+ if (err)
+ return err;
spin_lock_irq(¤t->sighand->siglock);
sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
@@ -743,6 +772,10 @@
sigaddset(¤t->blocked,signr);
recalc_sigpending();
spin_unlock_irq(¤t->sighand->siglock);
+
+ tracehook_signal_handler(signr, info, ka, regs, 0);
+
+ return 0;
}
static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs,
@@ -789,16 +822,14 @@
if (signr > 0) {
if (restart_syscall)
syscall_restart32(orig_i0, regs, &ka.sa);
- handle_signal32(signr, &ka, &info, oldset, regs);
-
- /* A signal was successfully delivered; the saved
- * sigmask will have been stored in the signal frame,
- * and will be restored by sigreturn, so we can simply
- * clear the TS_RESTORE_SIGMASK flag.
- */
- current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
-
- tracehook_signal_handler(signr, &info, &ka, regs, 0);
+ if (handle_signal32(signr, &ka, &info, oldset, regs) == 0) {
+ /* A signal was successfully delivered; the saved
+ * sigmask will have been stored in the signal frame,
+ * and will be restored by sigreturn, so we can simply
+ * clear the TS_RESTORE_SIGMASK flag.
+ */
+ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
+ }
return;
}
if (restart_syscall &&
@@ -809,12 +840,14 @@
regs->u_regs[UREG_I0] = orig_i0;
regs->tpc -= 4;
regs->tnpc -= 4;
+ pt_regs_clear_syscall(regs);
}
if (restart_syscall &&
regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) {
regs->u_regs[UREG_G1] = __NR_restart_syscall;
regs->tpc -= 4;
regs->tnpc -= 4;
+ pt_regs_clear_syscall(regs);
}
/* If there's no signal to deliver, we just put the saved sigmask
diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c
index 9882df9..5e5c5fd 100644
--- a/arch/sparc/kernel/signal_32.c
+++ b/arch/sparc/kernel/signal_32.c
@@ -315,8 +315,8 @@
return err;
}
-static void setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
- int signo, sigset_t *oldset)
+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;
@@ -384,16 +384,19 @@
/* Flush instruction space. */
flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
}
- return;
+ return 0;
sigill_and_return:
do_exit(SIGILL);
+ return -EINVAL;
+
sigsegv:
force_sigsegv(signo, current);
+ return -EFAULT;
}
-static void setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
- int signo, sigset_t *oldset, siginfo_t *info)
+static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
+ int signo, sigset_t *oldset, siginfo_t *info)
{
struct rt_signal_frame __user *sf;
int sigframe_size;
@@ -466,22 +469,30 @@
/* Flush instruction space. */
flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
}
- return;
+ return 0;
sigill:
do_exit(SIGILL);
+ return -EINVAL;
+
sigsegv:
force_sigsegv(signo, current);
+ return -EFAULT;
}
-static inline void
+static inline int
handle_signal(unsigned long signr, struct k_sigaction *ka,
siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
{
+ int err;
+
if (ka->sa.sa_flags & SA_SIGINFO)
- setup_rt_frame(ka, regs, signr, oldset, info);
+ err = setup_rt_frame(ka, regs, signr, oldset, info);
else
- setup_frame(ka, regs, signr, oldset);
+ err = setup_frame(ka, regs, signr, oldset);
+
+ if (err)
+ return err;
spin_lock_irq(¤t->sighand->siglock);
sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
@@ -489,6 +500,10 @@
sigaddset(¤t->blocked, signr);
recalc_sigpending();
spin_unlock_irq(¤t->sighand->siglock);
+
+ tracehook_signal_handler(signr, info, ka, regs, 0);
+
+ return 0;
}
static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
@@ -546,17 +561,15 @@
if (signr > 0) {
if (restart_syscall)
syscall_restart(orig_i0, regs, &ka.sa);
- handle_signal(signr, &ka, &info, oldset, regs);
-
- /* a signal was successfully delivered; the saved
- * sigmask will have been stored in the signal frame,
- * and will be restored by sigreturn, so we can simply
- * clear the TIF_RESTORE_SIGMASK flag.
- */
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
- clear_thread_flag(TIF_RESTORE_SIGMASK);
-
- tracehook_signal_handler(signr, &info, &ka, regs, 0);
+ if (handle_signal(signr, &ka, &info, oldset, regs) == 0) {
+ /* a signal was successfully delivered; the saved
+ * sigmask will have been stored in the signal frame,
+ * and will be restored by sigreturn, so we can simply
+ * clear the TIF_RESTORE_SIGMASK flag.
+ */
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ }
return;
}
if (restart_syscall &&
@@ -567,12 +580,14 @@
regs->u_regs[UREG_I0] = orig_i0;
regs->pc -= 4;
regs->npc -= 4;
+ pt_regs_clear_syscall(regs);
}
if (restart_syscall &&
regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) {
regs->u_regs[UREG_G1] = __NR_restart_syscall;
regs->pc -= 4;
regs->npc -= 4;
+ pt_regs_clear_syscall(regs);
}
/* if there's no signal to deliver, we just put the saved sigmask
diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c
index 9fa48c3..006fe45 100644
--- a/arch/sparc/kernel/signal_64.c
+++ b/arch/sparc/kernel/signal_64.c
@@ -409,7 +409,7 @@
return (void __user *) sp;
}
-static inline void
+static inline int
setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
int signo, sigset_t *oldset, siginfo_t *info)
{
@@ -483,26 +483,37 @@
}
/* 4. return to kernel instructions */
regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
- return;
+ return 0;
sigill:
do_exit(SIGILL);
+ return -EINVAL;
+
sigsegv:
force_sigsegv(signo, current);
+ return -EFAULT;
}
-static inline void handle_signal(unsigned long signr, struct k_sigaction *ka,
- siginfo_t *info,
- sigset_t *oldset, struct pt_regs *regs)
+static inline int handle_signal(unsigned long signr, struct k_sigaction *ka,
+ siginfo_t *info,
+ sigset_t *oldset, struct pt_regs *regs)
{
- setup_rt_frame(ka, regs, signr, oldset,
- (ka->sa.sa_flags & SA_SIGINFO) ? info : NULL);
+ int err;
+
+ err = setup_rt_frame(ka, regs, signr, oldset,
+ (ka->sa.sa_flags & SA_SIGINFO) ? info : NULL);
+ if (err)
+ return err;
spin_lock_irq(¤t->sighand->siglock);
sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
if (!(ka->sa.sa_flags & SA_NOMASK))
sigaddset(¤t->blocked,signr);
recalc_sigpending();
spin_unlock_irq(¤t->sighand->siglock);
+
+ tracehook_signal_handler(signr, info, ka, regs, 0);
+
+ return 0;
}
static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
@@ -571,16 +582,14 @@
if (signr > 0) {
if (restart_syscall)
syscall_restart(orig_i0, regs, &ka.sa);
- handle_signal(signr, &ka, &info, oldset, regs);
-
- /* A signal was successfully delivered; the saved
- * sigmask will have been stored in the signal frame,
- * and will be restored by sigreturn, so we can simply
- * clear the TS_RESTORE_SIGMASK flag.
- */
- current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
-
- tracehook_signal_handler(signr, &info, &ka, regs, 0);
+ if (handle_signal(signr, &ka, &info, oldset, regs) == 0) {
+ /* A signal was successfully delivered; the saved
+ * sigmask will have been stored in the signal frame,
+ * and will be restored by sigreturn, so we can simply
+ * clear the TS_RESTORE_SIGMASK flag.
+ */
+ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
+ }
return;
}
if (restart_syscall &&
@@ -591,12 +600,14 @@
regs->u_regs[UREG_I0] = orig_i0;
regs->tpc -= 4;
regs->tnpc -= 4;
+ pt_regs_clear_syscall(regs);
}
if (restart_syscall &&
regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) {
regs->u_regs[UREG_G1] = __NR_restart_syscall;
regs->tpc -= 4;
regs->tnpc -= 4;
+ pt_regs_clear_syscall(regs);
}
/* If there's no signal to deliver, we just put the saved sigmask
diff --git a/arch/tile/include/arch/chip_tile64.h b/arch/tile/include/arch/chip_tile64.h
index 1246573..261aaba 100644
--- a/arch/tile/include/arch/chip_tile64.h
+++ b/arch/tile/include/arch/chip_tile64.h
@@ -150,6 +150,9 @@
/** Is the PROC_STATUS SPR supported? */
#define CHIP_HAS_PROC_STATUS_SPR() 0
+/** Is the DSTREAM_PF SPR supported? */
+#define CHIP_HAS_DSTREAM_PF() 0
+
/** Log of the number of mshims we have. */
#define CHIP_LOG_NUM_MSHIMS() 2
diff --git a/arch/tile/include/arch/chip_tilepro.h b/arch/tile/include/arch/chip_tilepro.h
index e864c47..7001769 100644
--- a/arch/tile/include/arch/chip_tilepro.h
+++ b/arch/tile/include/arch/chip_tilepro.h
@@ -150,6 +150,9 @@
/** Is the PROC_STATUS SPR supported? */
#define CHIP_HAS_PROC_STATUS_SPR() 1
+/** Is the DSTREAM_PF SPR supported? */
+#define CHIP_HAS_DSTREAM_PF() 0
+
/** Log of the number of mshims we have. */
#define CHIP_LOG_NUM_MSHIMS() 2
diff --git a/arch/tile/include/asm/compat.h b/arch/tile/include/asm/compat.h
index 5a34da6..8b60ec8 100644
--- a/arch/tile/include/asm/compat.h
+++ b/arch/tile/include/asm/compat.h
@@ -195,7 +195,7 @@
return (long)(int)(long __force)uptr;
}
-static inline void __user *compat_alloc_user_space(long len)
+static inline void __user *arch_compat_alloc_user_space(long len)
{
struct pt_regs *regs = task_pt_regs(current);
return (void __user *)regs->sp - len;
@@ -214,8 +214,9 @@
struct compat_sigaction;
struct compat_siginfo;
struct compat_sigaltstack;
-long compat_sys_execve(char __user *path, compat_uptr_t __user *argv,
- compat_uptr_t __user *envp);
+long compat_sys_execve(const char __user *path,
+ const compat_uptr_t __user *argv,
+ const compat_uptr_t __user *envp);
long compat_sys_rt_sigaction(int sig, struct compat_sigaction __user *act,
struct compat_sigaction __user *oact,
size_t sigsetsize);
diff --git a/arch/tile/include/asm/io.h b/arch/tile/include/asm/io.h
index 8c95bef..ee43328 100644
--- a/arch/tile/include/asm/io.h
+++ b/arch/tile/include/asm/io.h
@@ -164,22 +164,22 @@
#define iowrite32 writel
#define iowrite64 writeq
-static inline void *memcpy_fromio(void *dst, void *src, int len)
+static inline void memcpy_fromio(void *dst, const volatile void __iomem *src,
+ size_t len)
{
int x;
BUG_ON((unsigned long)src & 0x3);
for (x = 0; x < len; x += 4)
*(u32 *)(dst + x) = readl(src + x);
- return dst;
}
-static inline void *memcpy_toio(void *dst, void *src, int len)
+static inline void memcpy_toio(volatile void __iomem *dst, const void *src,
+ size_t len)
{
int x;
BUG_ON((unsigned long)dst & 0x3);
for (x = 0; x < len; x += 4)
writel(*(u32 *)(src + x), dst + x);
- return dst;
}
/*
diff --git a/arch/tile/include/asm/processor.h b/arch/tile/include/asm/processor.h
index d942d09..ccd5f84 100644
--- a/arch/tile/include/asm/processor.h
+++ b/arch/tile/include/asm/processor.h
@@ -103,6 +103,18 @@
/* Any other miscellaneous processor state bits */
unsigned long proc_status;
#endif
+#if !CHIP_HAS_FIXED_INTVEC_BASE()
+ /* Interrupt base for PL0 interrupts */
+ unsigned long interrupt_vector_base;
+#endif
+#if CHIP_HAS_TILE_RTF_HWM()
+ /* Tile cache retry fifo high-water mark */
+ unsigned long tile_rtf_hwm;
+#endif
+#if CHIP_HAS_DSTREAM_PF()
+ /* Data stream prefetch control */
+ unsigned long dstream_pf;
+#endif
#ifdef CONFIG_HARDWALL
/* Is this task tied to an activated hardwall? */
struct hardwall_info *hardwall;
diff --git a/arch/tile/include/asm/ptrace.h b/arch/tile/include/asm/ptrace.h
index acdae81..4a02bb0 100644
--- a/arch/tile/include/asm/ptrace.h
+++ b/arch/tile/include/asm/ptrace.h
@@ -51,10 +51,7 @@
/*
* This struct defines the way the registers are stored on the stack during a
- * system call/exception. It should be a multiple of 8 bytes to preserve
- * normal stack alignment rules.
- *
- * Must track <sys/ucontext.h> and <sys/procfs.h>
+ * system call or exception. "struct sigcontext" has the same shape.
*/
struct pt_regs {
/* Saved main processor registers; 56..63 are special. */
@@ -80,11 +77,6 @@
#endif /* __ASSEMBLY__ */
-/* Flag bits in pt_regs.flags */
-#define PT_FLAGS_DISABLE_IRQ 1 /* on return to kernel, disable irqs */
-#define PT_FLAGS_CALLER_SAVES 2 /* caller-save registers are valid */
-#define PT_FLAGS_RESTORE_REGS 4 /* restore callee-save regs on return */
-
#define PTRACE_GETREGS 12
#define PTRACE_SETREGS 13
#define PTRACE_GETFPREGS 14
@@ -101,6 +93,11 @@
#ifdef __KERNEL__
+/* Flag bits in pt_regs.flags */
+#define PT_FLAGS_DISABLE_IRQ 1 /* on return to kernel, disable irqs */
+#define PT_FLAGS_CALLER_SAVES 2 /* caller-save registers are valid */
+#define PT_FLAGS_RESTORE_REGS 4 /* restore callee-save regs on return */
+
#ifndef __ASSEMBLY__
#define instruction_pointer(regs) ((regs)->pc)
diff --git a/arch/tile/include/asm/sigcontext.h b/arch/tile/include/asm/sigcontext.h
index 7cd7672..5e2d033 100644
--- a/arch/tile/include/asm/sigcontext.h
+++ b/arch/tile/include/asm/sigcontext.h
@@ -15,13 +15,21 @@
#ifndef _ASM_TILE_SIGCONTEXT_H
#define _ASM_TILE_SIGCONTEXT_H
-/* NOTE: we can't include <linux/ptrace.h> due to #include dependencies. */
-#include <asm/ptrace.h>
+#include <arch/abi.h>
-/* Must track <sys/ucontext.h> */
-
+/*
+ * struct sigcontext has the same shape as struct pt_regs,
+ * but is simplified since we know the fault is from userspace.
+ */
struct sigcontext {
- struct pt_regs regs;
+ uint_reg_t gregs[53]; /* General-purpose registers. */
+ uint_reg_t tp; /* Aliases gregs[TREG_TP]. */
+ uint_reg_t sp; /* Aliases gregs[TREG_SP]. */
+ uint_reg_t lr; /* Aliases gregs[TREG_LR]. */
+ uint_reg_t pc; /* Program counter. */
+ uint_reg_t ics; /* In Interrupt Critical Section? */
+ uint_reg_t faultnum; /* Fault number. */
+ uint_reg_t pad[5];
};
#endif /* _ASM_TILE_SIGCONTEXT_H */
diff --git a/arch/tile/include/asm/signal.h b/arch/tile/include/asm/signal.h
index eb0253f..c1ee1d6 100644
--- a/arch/tile/include/asm/signal.h
+++ b/arch/tile/include/asm/signal.h
@@ -24,6 +24,7 @@
#include <asm-generic/signal.h>
#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
+struct pt_regs;
int restore_sigcontext(struct pt_regs *, struct sigcontext __user *, long *);
int setup_sigcontext(struct sigcontext __user *, struct pt_regs *);
void do_signal(struct pt_regs *regs);
diff --git a/arch/tile/include/asm/syscalls.h b/arch/tile/include/asm/syscalls.h
index af165a7..ce99ffe 100644
--- a/arch/tile/include/asm/syscalls.h
+++ b/arch/tile/include/asm/syscalls.h
@@ -62,10 +62,12 @@
long _sys_fork(struct pt_regs *regs);
long sys_vfork(void);
long _sys_vfork(struct pt_regs *regs);
-long sys_execve(char __user *filename, char __user * __user *argv,
- char __user * __user *envp);
-long _sys_execve(char __user *filename, char __user * __user *argv,
- char __user * __user *envp, struct pt_regs *regs);
+long sys_execve(const char __user *filename,
+ const char __user *const __user *argv,
+ const char __user *const __user *envp);
+long _sys_execve(const char __user *filename,
+ const char __user *const __user *argv,
+ const char __user *const __user *envp, struct pt_regs *regs);
/* kernel/signal.c */
long sys_sigaltstack(const stack_t __user *, stack_t __user *);
@@ -86,10 +88,13 @@
#endif
#ifdef CONFIG_COMPAT
-long compat_sys_execve(char __user *path, compat_uptr_t __user *argv,
- compat_uptr_t __user *envp);
-long _compat_sys_execve(char __user *path, compat_uptr_t __user *argv,
- compat_uptr_t __user *envp, struct pt_regs *regs);
+long compat_sys_execve(const char __user *path,
+ const compat_uptr_t __user *argv,
+ const compat_uptr_t __user *envp);
+long _compat_sys_execve(const char __user *path,
+ const compat_uptr_t __user *argv,
+ const compat_uptr_t __user *envp,
+ struct pt_regs *regs);
long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
struct compat_sigaltstack __user *uoss_ptr);
long _compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
diff --git a/arch/tile/kernel/intvec_32.S b/arch/tile/kernel/intvec_32.S
index 84f296c..8f58bdf 100644
--- a/arch/tile/kernel/intvec_32.S
+++ b/arch/tile/kernel/intvec_32.S
@@ -1506,13 +1506,6 @@
}
STD_ENDPROC(handle_ill)
- .pushsection .rodata, "a"
- .align 8
-bpt_code:
- bpt
- ENDPROC(bpt_code)
- .popsection
-
/* Various stub interrupt handlers and syscall handlers */
STD_ENTRY_LOCAL(_kernel_double_fault)
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c
index 985cc28..84c2911 100644
--- a/arch/tile/kernel/process.c
+++ b/arch/tile/kernel/process.c
@@ -408,6 +408,15 @@
#if CHIP_HAS_PROC_STATUS_SPR()
t->proc_status = __insn_mfspr(SPR_PROC_STATUS);
#endif
+#if !CHIP_HAS_FIXED_INTVEC_BASE()
+ t->interrupt_vector_base = __insn_mfspr(SPR_INTERRUPT_VECTOR_BASE_0);
+#endif
+#if CHIP_HAS_TILE_RTF_HWM()
+ t->tile_rtf_hwm = __insn_mfspr(SPR_TILE_RTF_HWM);
+#endif
+#if CHIP_HAS_DSTREAM_PF()
+ t->dstream_pf = __insn_mfspr(SPR_DSTREAM_PF);
+#endif
}
static void restore_arch_state(const struct thread_struct *t)
@@ -428,14 +437,14 @@
#if CHIP_HAS_PROC_STATUS_SPR()
__insn_mtspr(SPR_PROC_STATUS, t->proc_status);
#endif
+#if !CHIP_HAS_FIXED_INTVEC_BASE()
+ __insn_mtspr(SPR_INTERRUPT_VECTOR_BASE_0, t->interrupt_vector_base);
+#endif
#if CHIP_HAS_TILE_RTF_HWM()
- /*
- * Clear this whenever we switch back to a process in case
- * the previous process was monkeying with it. Even if enabled
- * in CBOX_MSR1 via TILE_RTF_HWM_MIN, it's still just a
- * performance hint, so isn't worth a full save/restore.
- */
- __insn_mtspr(SPR_TILE_RTF_HWM, 0);
+ __insn_mtspr(SPR_TILE_RTF_HWM, t->tile_rtf_hwm);
+#endif
+#if CHIP_HAS_DSTREAM_PF()
+ __insn_mtspr(SPR_DSTREAM_PF, t->dstream_pf);
#endif
}
@@ -561,8 +570,9 @@
}
#ifdef CONFIG_COMPAT
-long _compat_sys_execve(char __user *path, compat_uptr_t __user *argv,
- compat_uptr_t __user *envp, struct pt_regs *regs)
+long _compat_sys_execve(const char __user *path,
+ const compat_uptr_t __user *argv,
+ const compat_uptr_t __user *envp, struct pt_regs *regs)
{
long error;
char *filename;
@@ -657,7 +667,7 @@
regs->regs[51], regs->regs[52], regs->tp);
pr_err(" sp : "REGFMT" lr : "REGFMT"\n", regs->sp, regs->lr);
#else
- for (i = 0; i < 52; i += 3)
+ for (i = 0; i < 52; i += 4)
pr_err(" r%-2d: "REGFMT" r%-2d: "REGFMT
" r%-2d: "REGFMT" r%-2d: "REGFMT"\n",
i, regs->regs[i], i+1, regs->regs[i+1],
diff --git a/arch/tile/kernel/signal.c b/arch/tile/kernel/signal.c
index 45b66a3..ce183aa 100644
--- a/arch/tile/kernel/signal.c
+++ b/arch/tile/kernel/signal.c
@@ -61,13 +61,19 @@
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
+ /*
+ * Enforce that sigcontext is like pt_regs, and doesn't mess
+ * up our stack alignment rules.
+ */
+ BUILD_BUG_ON(sizeof(struct sigcontext) != sizeof(struct pt_regs));
+ BUILD_BUG_ON(sizeof(struct sigcontext) % 8 != 0);
+
for (i = 0; i < sizeof(struct pt_regs)/sizeof(long); ++i)
- err |= __get_user(((long *)regs)[i],
- &((long __user *)(&sc->regs))[i]);
+ err |= __get_user(regs->regs[i], &sc->gregs[i]);
regs->faultnum = INT_SWINT_1_SIGRETURN;
- err |= __get_user(*pr0, &sc->regs.regs[0]);
+ err |= __get_user(*pr0, &sc->gregs[0]);
return err;
}
@@ -112,8 +118,7 @@
int i, err = 0;
for (i = 0; i < sizeof(struct pt_regs)/sizeof(long); ++i)
- err |= __put_user(((long *)regs)[i],
- &((long __user *)(&sc->regs))[i]);
+ err |= __put_user(regs->regs[i], &sc->gregs[i]);
return err;
}
@@ -203,19 +208,17 @@
* Set up registers for signal handler.
* Registers that we don't modify keep the value they had from
* user-space at the time we took the signal.
+ * We always pass siginfo and mcontext, regardless of SA_SIGINFO,
+ * since some things rely on this (e.g. glibc's debug/segfault.c).
*/
regs->pc = (unsigned long) ka->sa.sa_handler;
regs->ex1 = PL_ICS_EX1(USER_PL, 1); /* set crit sec in handler */
regs->sp = (unsigned long) frame;
regs->lr = restorer;
regs->regs[0] = (unsigned long) usig;
-
- if (ka->sa.sa_flags & SA_SIGINFO) {
- /* Need extra arguments, so mark to restore caller-saves. */
- regs->regs[1] = (unsigned long) &frame->info;
- regs->regs[2] = (unsigned long) &frame->uc;
- regs->flags |= PT_FLAGS_CALLER_SAVES;
- }
+ regs->regs[1] = (unsigned long) &frame->info;
+ regs->regs[2] = (unsigned long) &frame->uc;
+ regs->flags |= PT_FLAGS_CALLER_SAVES;
/*
* Notify any tracer that was single-stepping it.
diff --git a/arch/tile/kernel/stack.c b/arch/tile/kernel/stack.c
index 38a68b0b4..ea2e0ce 100644
--- a/arch/tile/kernel/stack.c
+++ b/arch/tile/kernel/stack.c
@@ -175,7 +175,7 @@
pr_err(" <received signal %d>\n",
frame->info.si_signo);
}
- return &frame->uc.uc_mcontext.regs;
+ return (struct pt_regs *)&frame->uc.uc_mcontext;
}
return NULL;
}
diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c
index 0c46e39..63c740a 100644
--- a/arch/um/drivers/hostaudio_kern.c
+++ b/arch/um/drivers/hostaudio_kern.c
@@ -40,6 +40,11 @@
" This is used to specify the host mixer device to the hostaudio driver.\n"\
" The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n"
+module_param(dsp, charp, 0644);
+MODULE_PARM_DESC(dsp, DSP_HELP);
+module_param(mixer, charp, 0644);
+MODULE_PARM_DESC(mixer, MIXER_HELP);
+
#ifndef MODULE
static int set_dsp(char *name, int *add)
{
@@ -56,15 +61,6 @@
}
__uml_setup("mixer=", set_mixer, "mixer=<mixer device>\n" MIXER_HELP);
-
-#else /*MODULE*/
-
-module_param(dsp, charp, 0644);
-MODULE_PARM_DESC(dsp, DSP_HELP);
-
-module_param(mixer, charp, 0644);
-MODULE_PARM_DESC(mixer, MIXER_HELP);
-
#endif
/* /dev/dsp file operations */
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index 2ab233b..47d0c37 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -255,18 +255,6 @@
netif_wake_queue(dev);
}
-static int uml_net_set_mac(struct net_device *dev, void *addr)
-{
- struct uml_net_private *lp = netdev_priv(dev);
- struct sockaddr *hwaddr = addr;
-
- spin_lock_irq(&lp->lock);
- eth_mac_addr(dev, hwaddr->sa_data);
- spin_unlock_irq(&lp->lock);
-
- return 0;
-}
-
static int uml_net_change_mtu(struct net_device *dev, int new_mtu)
{
dev->mtu = new_mtu;
@@ -373,7 +361,7 @@
.ndo_start_xmit = uml_net_start_xmit,
.ndo_set_multicast_list = uml_net_set_multicast_list,
.ndo_tx_timeout = uml_net_tx_timeout,
- .ndo_set_mac_address = uml_net_set_mac,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = uml_net_change_mtu,
.ndo_validate_addr = eth_validate_addr,
};
@@ -472,7 +460,8 @@
((*transport->user->init)(&lp->user, dev) != 0))
goto out_unregister;
- eth_mac_addr(dev, device->mac);
+ /* don't use eth_mac_addr, it will not work here */
+ memcpy(dev->dev_addr, device->mac, ETH_ALEN);
dev->mtu = transport->user->mtu;
dev->netdev_ops = ¨_netdev_ops;
dev->ethtool_ops = ¨_net_ethtool_ops;
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index 1bcd208..9734994 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -163,6 +163,7 @@
struct scatterlist sg[MAX_SG];
struct request *request;
int start_sg, end_sg;
+ sector_t rq_pos;
};
#define DEFAULT_COW { \
@@ -187,6 +188,7 @@
.request = NULL, \
.start_sg = 0, \
.end_sg = 0, \
+ .rq_pos = 0, \
}
/* Protected by ubd_lock */
@@ -1228,7 +1230,6 @@
{
struct io_thread_req *io_req;
struct request *req;
- sector_t sector;
int n;
while(1){
@@ -1239,12 +1240,12 @@
return;
dev->request = req;
+ dev->rq_pos = blk_rq_pos(req);
dev->start_sg = 0;
dev->end_sg = blk_rq_map_sg(q, req, dev->sg);
}
req = dev->request;
- sector = blk_rq_pos(req);
while(dev->start_sg < dev->end_sg){
struct scatterlist *sg = &dev->sg[dev->start_sg];
@@ -1256,10 +1257,9 @@
return;
}
prepare_request(req, io_req,
- (unsigned long long)sector << 9,
+ (unsigned long long)dev->rq_pos << 9,
sg->offset, sg->length, sg_page(sg));
- sector += sg->length >> 9;
n = os_write_file(thread_fd, &io_req,
sizeof(struct io_thread_req *));
if(n != sizeof(struct io_thread_req *)){
@@ -1272,6 +1272,7 @@
return;
}
+ dev->rq_pos += sg->length >> 9;
dev->start_sg++;
}
dev->end_sg = 0;
diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c
index cd145ed..49b5e1e 100644
--- a/arch/um/kernel/exec.c
+++ b/arch/um/kernel/exec.c
@@ -62,7 +62,7 @@
return error;
}
-long um_execve(const char *file, char __user *__user *argv, char __user *__user *env)
+long um_execve(const char *file, const char __user *const __user *argv, const char __user *const __user *env)
{
long err;
@@ -72,8 +72,8 @@
return err;
}
-long sys_execve(const char __user *file, char __user *__user *argv,
- char __user *__user *env)
+long sys_execve(const char __user *file, const char __user *const __user *argv,
+ const char __user *const __user *env)
{
long error;
char *filename;
diff --git a/arch/um/kernel/internal.h b/arch/um/kernel/internal.h
index 1303a10..5bf97db 100644
--- a/arch/um/kernel/internal.h
+++ b/arch/um/kernel/internal.h
@@ -1 +1 @@
-extern long um_execve(const char *file, char __user *__user *argv, char __user *__user *env);
+extern long um_execve(const char *file, const char __user *const __user *argv, const char __user *const __user *env);
diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c
index 5ddb246..f958cb8 100644
--- a/arch/um/kernel/syscall.c
+++ b/arch/um/kernel/syscall.c
@@ -60,8 +60,8 @@
fs = get_fs();
set_fs(KERNEL_DS);
- ret = um_execve(filename, (char __user *__user *)argv,
- (char __user *__user *) envp);
+ ret = um_execve(filename, (const char __user *const __user *)argv,
+ (const char __user *const __user *) envp);
set_fs(fs);
return ret;
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index 8aa1b59..e8c8881 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -74,7 +74,7 @@
ifdef CONFIG_CC_STACKPROTECTOR
cc_has_sp := $(srctree)/scripts/gcc-x86_$(BITS)-has-stack-protector.sh
- ifeq ($(shell $(CONFIG_SHELL) $(cc_has_sp) $(CC) $(biarch)),y)
+ ifeq ($(shell $(CONFIG_SHELL) $(cc_has_sp) $(CC) $(KBUILD_CPPFLAGS) $(biarch)),y)
stackp-y := -fstack-protector
KBUILD_CFLAGS += $(stackp-y)
else
diff --git a/arch/x86/boot/early_serial_console.c b/arch/x86/boot/early_serial_console.c
index 030f4b9..5df2869 100644
--- a/arch/x86/boot/early_serial_console.c
+++ b/arch/x86/boot/early_serial_console.c
@@ -58,7 +58,19 @@
if (arg[pos] == ',')
pos++;
- if (!strncmp(arg, "ttyS", 4)) {
+ /*
+ * make sure we have
+ * "serial,0x3f8,115200"
+ * "serial,ttyS0,115200"
+ * "ttyS0,115200"
+ */
+ if (pos == 7 && !strncmp(arg + pos, "0x", 2)) {
+ port = simple_strtoull(arg + pos, &e, 16);
+ if (port == 0 || arg + pos == e)
+ port = DEFAULT_SERIAL_PORT;
+ else
+ pos = e - arg;
+ } else if (!strncmp(arg + pos, "ttyS", 4)) {
static const int bases[] = { 0x3f8, 0x2f8 };
int idx = 0;
diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c
index 0350311..2d93bdb 100644
--- a/arch/x86/ia32/ia32_aout.c
+++ b/arch/x86/ia32/ia32_aout.c
@@ -34,7 +34,7 @@
#include <asm/ia32.h>
#undef WARN_OLD
-#undef CORE_DUMP /* probably broken */
+#undef CORE_DUMP /* definitely broken */
static int load_aout_binary(struct linux_binprm *, struct pt_regs *regs);
static int load_aout_library(struct file *);
@@ -131,21 +131,15 @@
* macros to write out all the necessary info.
*/
-static int dump_write(struct file *file, const void *addr, int nr)
-{
- return file->f_op->write(file, addr, nr, &file->f_pos) == nr;
-}
+#include <linux/coredump.h>
#define DUMP_WRITE(addr, nr) \
if (!dump_write(file, (void *)(addr), (nr))) \
goto end_coredump;
-#define DUMP_SEEK(offset) \
- if (file->f_op->llseek) { \
- if (file->f_op->llseek(file, (offset), 0) != (offset)) \
- goto end_coredump; \
- } else \
- file->f_pos = (offset)
+#define DUMP_SEEK(offset) \
+ if (!dump_seek(file, offset)) \
+ goto end_coredump;
#define START_DATA() (u.u_tsize << PAGE_SHIFT)
#define START_STACK(u) (u.start_stack)
@@ -217,12 +211,6 @@
dump_size = dump.u_ssize << PAGE_SHIFT;
DUMP_WRITE(dump_start, dump_size);
}
- /*
- * Finally dump the task struct. Not be used by gdb, but
- * could be useful
- */
- set_fs(KERNEL_DS);
- DUMP_WRITE(current, sizeof(*current));
end_coredump:
set_fs(fs);
return has_dumped;
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index b86feab..518bb99 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -50,7 +50,12 @@
/*
* Reload arg registers from stack in case ptrace changed them.
* We don't reload %eax because syscall_trace_enter() returned
- * the value it wants us to use in the table lookup.
+ * the %rax value we should see. Instead, we just truncate that
+ * value to 32 bits again as we did on entry from user mode.
+ * If it's a new value set by user_regset during entry tracing,
+ * this matches the normal truncation of the user-mode value.
+ * If it's -1 to make us punt the syscall, then (u32)-1 is still
+ * an appropriately invalid value.
*/
.macro LOAD_ARGS32 offset, _r9=0
.if \_r9
@@ -60,6 +65,7 @@
movl \offset+48(%rsp),%edx
movl \offset+56(%rsp),%esi
movl \offset+64(%rsp),%edi
+ movl %eax,%eax /* zero extension */
.endm
.macro CFI_STARTPROC32 simple
@@ -153,7 +159,7 @@
testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10)
CFI_REMEMBER_STATE
jnz sysenter_tracesys
- cmpl $(IA32_NR_syscalls-1),%eax
+ cmpq $(IA32_NR_syscalls-1),%rax
ja ia32_badsys
sysenter_do_call:
IA32_ARG_FIXUP
@@ -195,7 +201,7 @@
movl $AUDIT_ARCH_I386,%edi /* 1st arg: audit arch */
call audit_syscall_entry
movl RAX-ARGOFFSET(%rsp),%eax /* reload syscall number */
- cmpl $(IA32_NR_syscalls-1),%eax
+ cmpq $(IA32_NR_syscalls-1),%rax
ja ia32_badsys
movl %ebx,%edi /* reload 1st syscall arg */
movl RCX-ARGOFFSET(%rsp),%esi /* reload 2nd syscall arg */
@@ -248,7 +254,7 @@
call syscall_trace_enter
LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */
RESTORE_REST
- cmpl $(IA32_NR_syscalls-1),%eax
+ cmpq $(IA32_NR_syscalls-1),%rax
ja int_ret_from_sys_call /* sysenter_tracesys has set RAX(%rsp) */
jmp sysenter_do_call
CFI_ENDPROC
@@ -314,7 +320,7 @@
testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10)
CFI_REMEMBER_STATE
jnz cstar_tracesys
- cmpl $IA32_NR_syscalls-1,%eax
+ cmpq $IA32_NR_syscalls-1,%rax
ja ia32_badsys
cstar_do_call:
IA32_ARG_FIXUP 1
@@ -367,7 +373,7 @@
LOAD_ARGS32 ARGOFFSET, 1 /* reload args from stack in case ptrace changed it */
RESTORE_REST
xchgl %ebp,%r9d
- cmpl $(IA32_NR_syscalls-1),%eax
+ cmpq $(IA32_NR_syscalls-1),%rax
ja int_ret_from_sys_call /* cstar_tracesys has set RAX(%rsp) */
jmp cstar_do_call
END(ia32_cstar_target)
@@ -425,7 +431,7 @@
orl $TS_COMPAT,TI_status(%r10)
testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10)
jnz ia32_tracesys
- cmpl $(IA32_NR_syscalls-1),%eax
+ cmpq $(IA32_NR_syscalls-1),%rax
ja ia32_badsys
ia32_do_call:
IA32_ARG_FIXUP
@@ -444,7 +450,7 @@
call syscall_trace_enter
LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */
RESTORE_REST
- cmpl $(IA32_NR_syscalls-1),%eax
+ cmpq $(IA32_NR_syscalls-1),%rax
ja int_ret_from_sys_call /* ia32_tracesys has set RAX(%rsp) */
jmp ia32_do_call
END(ia32_syscall)
diff --git a/arch/x86/include/asm/amd_iommu_proto.h b/arch/x86/include/asm/amd_iommu_proto.h
index d2544f1..cb03037 100644
--- a/arch/x86/include/asm/amd_iommu_proto.h
+++ b/arch/x86/include/asm/amd_iommu_proto.h
@@ -38,4 +38,10 @@
#endif /* !CONFIG_AMD_IOMMU_STATS */
+static inline bool is_rd890_iommu(struct pci_dev *pdev)
+{
+ return (pdev->vendor == PCI_VENDOR_ID_ATI) &&
+ (pdev->device == PCI_DEVICE_ID_RD890_IOMMU);
+}
+
#endif /* _ASM_X86_AMD_IOMMU_PROTO_H */
diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h
index 7014e88..0861618 100644
--- a/arch/x86/include/asm/amd_iommu_types.h
+++ b/arch/x86/include/asm/amd_iommu_types.h
@@ -368,6 +368,9 @@
/* capabilities of that IOMMU read from ACPI */
u32 cap;
+ /* flags read from acpi table */
+ u8 acpi_flags;
+
/*
* Capability pointer. There could be more than one IOMMU per PCI
* device function if there are more than one AMD IOMMU capability
@@ -411,6 +414,15 @@
/* default dma_ops domain for that IOMMU */
struct dma_ops_domain *default_dom;
+
+ /*
+ * This array is required to work around a potential BIOS bug.
+ * The BIOS may miss to restore parts of the PCI configuration
+ * space when the system resumes from S3. The result is that the
+ * IOMMU does not execute commands anymore which leads to system
+ * failure.
+ */
+ u32 cache_cfg[4];
};
/*
diff --git a/arch/x86/include/asm/bitops.h b/arch/x86/include/asm/bitops.h
index 545776e..bafd80d 100644
--- a/arch/x86/include/asm/bitops.h
+++ b/arch/x86/include/asm/bitops.h
@@ -309,7 +309,7 @@
static __always_inline int constant_test_bit(unsigned int nr, const volatile unsigned long *addr)
{
return ((1UL << (nr % BITS_PER_LONG)) &
- (((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0;
+ (addr[nr / BITS_PER_LONG])) != 0;
}
static inline int variable_test_bit(int nr, volatile const unsigned long *addr)
diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h
index 306160e..1d9cd27 100644
--- a/arch/x86/include/asm/compat.h
+++ b/arch/x86/include/asm/compat.h
@@ -205,7 +205,7 @@
return (u32)(unsigned long)uptr;
}
-static inline void __user *compat_alloc_user_space(long len)
+static inline void __user *arch_compat_alloc_user_space(long len)
{
struct pt_regs *regs = task_pt_regs(current);
return (void __user *)regs->sp - len;
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index 781a50b..3f76523 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -168,6 +168,7 @@
#define X86_FEATURE_XSAVEOPT (7*32+ 4) /* Optimized Xsave */
#define X86_FEATURE_PLN (7*32+ 5) /* Intel Power Limit Notification */
#define X86_FEATURE_PTS (7*32+ 6) /* Intel Package Thermal Status */
+#define X86_FEATURE_DTS (7*32+ 7) /* Digital Thermal Sensor */
/* Virtualization flags: Linux defined, word 8 */
#define X86_FEATURE_TPR_SHADOW (8*32+ 0) /* Intel TPR Shadow */
@@ -296,6 +297,7 @@
#endif /* CONFIG_X86_64 */
+#if __GNUC__ >= 4
/*
* Static testing of CPU features. Used the same as boot_cpu_has().
* These are only valid after alternatives have run, but will statically
@@ -304,7 +306,7 @@
*/
static __always_inline __pure bool __static_cpu_has(u16 bit)
{
-#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
+#if __GNUC__ > 4 || __GNUC_MINOR__ >= 5
asm goto("1: jmp %l[t_no]\n"
"2:\n"
".section .altinstructions,\"a\"\n"
@@ -345,7 +347,6 @@
#endif
}
-#if __GNUC__ >= 4
#define static_cpu_has(bit) \
( \
__builtin_constant_p(boot_cpu_has(bit)) ? \
diff --git a/arch/x86/include/asm/hpet.h b/arch/x86/include/asm/hpet.h
index 004e6e2..1d5c08a 100644
--- a/arch/x86/include/asm/hpet.h
+++ b/arch/x86/include/asm/hpet.h
@@ -68,7 +68,6 @@
extern u8 hpet_blockid;
extern int hpet_force_user;
extern u8 hpet_msi_disable;
-extern u8 hpet_readback_cmp;
extern int is_hpet_enabled(void);
extern int hpet_enable(void);
extern void hpet_disable(void);
diff --git a/arch/x86/include/asm/hw_breakpoint.h b/arch/x86/include/asm/hw_breakpoint.h
index 528a11e..824ca07 100644
--- a/arch/x86/include/asm/hw_breakpoint.h
+++ b/arch/x86/include/asm/hw_breakpoint.h
@@ -20,7 +20,7 @@
#include <linux/list.h>
/* Available HW breakpoint length encodings */
-#define X86_BREAKPOINT_LEN_X 0x00
+#define X86_BREAKPOINT_LEN_X 0x40
#define X86_BREAKPOINT_LEN_1 0x40
#define X86_BREAKPOINT_LEN_2 0x44
#define X86_BREAKPOINT_LEN_4 0x4c
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 502e53f..c52e2eb 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -652,20 +652,6 @@
return (struct kvm_mmu_page *)page_private(page);
}
-static inline u16 kvm_read_fs(void)
-{
- u16 seg;
- asm("mov %%fs, %0" : "=g"(seg));
- return seg;
-}
-
-static inline u16 kvm_read_gs(void)
-{
- u16 seg;
- asm("mov %%gs, %0" : "=g"(seg));
- return seg;
-}
-
static inline u16 kvm_read_ldt(void)
{
u16 ldt;
@@ -673,16 +659,6 @@
return ldt;
}
-static inline void kvm_load_fs(u16 sel)
-{
- asm("mov %0, %%fs" : : "rm"(sel));
-}
-
-static inline void kvm_load_gs(u16 sel)
-{
- asm("mov %0, %%gs" : : "rm"(sel));
-}
-
static inline void kvm_load_ldt(u16 sel)
{
asm("lldt %0" : : "rm"(sel));
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 0925676..fedf32a 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -11,6 +11,8 @@
CFLAGS_REMOVE_tsc.o = -pg
CFLAGS_REMOVE_rtc.o = -pg
CFLAGS_REMOVE_paravirt-spinlocks.o = -pg
+CFLAGS_REMOVE_pvclock.o = -pg
+CFLAGS_REMOVE_kvmclock.o = -pg
CFLAGS_REMOVE_ftrace.o = -pg
CFLAGS_REMOVE_early_printk.o = -pg
endif
diff --git a/arch/x86/kernel/acpi/cstate.c b/arch/x86/kernel/acpi/cstate.c
index fb7a5f0..fb16f17 100644
--- a/arch/x86/kernel/acpi/cstate.c
+++ b/arch/x86/kernel/acpi/cstate.c
@@ -61,7 +61,7 @@
unsigned int ecx;
} states[ACPI_PROCESSOR_MAX_POWER];
};
-static struct cstate_entry *cpu_cstate_entry; /* per CPU ptr */
+static struct cstate_entry __percpu *cpu_cstate_entry; /* per CPU ptr */
static short mwait_supported[ACPI_PROCESSOR_MAX_POWER];
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index fa044e1..679b645 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -1953,6 +1953,7 @@
size_t size,
int dir)
{
+ dma_addr_t flush_addr;
dma_addr_t i, start;
unsigned int pages;
@@ -1960,6 +1961,7 @@
(dma_addr + size > dma_dom->aperture_size))
return;
+ flush_addr = dma_addr;
pages = iommu_num_pages(dma_addr, size, PAGE_SIZE);
dma_addr &= PAGE_MASK;
start = dma_addr;
@@ -1974,7 +1976,7 @@
dma_ops_free_addresses(dma_dom, dma_addr, pages);
if (amd_iommu_unmap_flush || dma_dom->need_flush) {
- iommu_flush_pages(&dma_dom->domain, dma_addr, size);
+ iommu_flush_pages(&dma_dom->domain, flush_addr, size);
dma_dom->need_flush = false;
}
}
diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c
index 3cc63e2..5a170cb 100644
--- a/arch/x86/kernel/amd_iommu_init.c
+++ b/arch/x86/kernel/amd_iommu_init.c
@@ -632,6 +632,13 @@
iommu->last_device = calc_devid(MMIO_GET_BUS(range),
MMIO_GET_LD(range));
iommu->evt_msi_num = MMIO_MSI_NUM(misc);
+
+ if (is_rd890_iommu(iommu->dev)) {
+ pci_read_config_dword(iommu->dev, 0xf0, &iommu->cache_cfg[0]);
+ pci_read_config_dword(iommu->dev, 0xf4, &iommu->cache_cfg[1]);
+ pci_read_config_dword(iommu->dev, 0xf8, &iommu->cache_cfg[2]);
+ pci_read_config_dword(iommu->dev, 0xfc, &iommu->cache_cfg[3]);
+ }
}
/*
@@ -649,29 +656,9 @@
struct ivhd_entry *e;
/*
- * First set the recommended feature enable bits from ACPI
- * into the IOMMU control registers
+ * First save the recommended feature enable bits from ACPI
*/
- h->flags & IVHD_FLAG_HT_TUN_EN_MASK ?
- iommu_feature_enable(iommu, CONTROL_HT_TUN_EN) :
- iommu_feature_disable(iommu, CONTROL_HT_TUN_EN);
-
- h->flags & IVHD_FLAG_PASSPW_EN_MASK ?
- iommu_feature_enable(iommu, CONTROL_PASSPW_EN) :
- iommu_feature_disable(iommu, CONTROL_PASSPW_EN);
-
- h->flags & IVHD_FLAG_RESPASSPW_EN_MASK ?
- iommu_feature_enable(iommu, CONTROL_RESPASSPW_EN) :
- iommu_feature_disable(iommu, CONTROL_RESPASSPW_EN);
-
- h->flags & IVHD_FLAG_ISOC_EN_MASK ?
- iommu_feature_enable(iommu, CONTROL_ISOC_EN) :
- iommu_feature_disable(iommu, CONTROL_ISOC_EN);
-
- /*
- * make IOMMU memory accesses cache coherent
- */
- iommu_feature_enable(iommu, CONTROL_COHERENT_EN);
+ iommu->acpi_flags = h->flags;
/*
* Done. Now parse the device entries
@@ -1116,6 +1103,40 @@
}
}
+static void iommu_init_flags(struct amd_iommu *iommu)
+{
+ iommu->acpi_flags & IVHD_FLAG_HT_TUN_EN_MASK ?
+ iommu_feature_enable(iommu, CONTROL_HT_TUN_EN) :
+ iommu_feature_disable(iommu, CONTROL_HT_TUN_EN);
+
+ iommu->acpi_flags & IVHD_FLAG_PASSPW_EN_MASK ?
+ iommu_feature_enable(iommu, CONTROL_PASSPW_EN) :
+ iommu_feature_disable(iommu, CONTROL_PASSPW_EN);
+
+ iommu->acpi_flags & IVHD_FLAG_RESPASSPW_EN_MASK ?
+ iommu_feature_enable(iommu, CONTROL_RESPASSPW_EN) :
+ iommu_feature_disable(iommu, CONTROL_RESPASSPW_EN);
+
+ iommu->acpi_flags & IVHD_FLAG_ISOC_EN_MASK ?
+ iommu_feature_enable(iommu, CONTROL_ISOC_EN) :
+ iommu_feature_disable(iommu, CONTROL_ISOC_EN);
+
+ /*
+ * make IOMMU memory accesses cache coherent
+ */
+ iommu_feature_enable(iommu, CONTROL_COHERENT_EN);
+}
+
+static void iommu_apply_quirks(struct amd_iommu *iommu)
+{
+ if (is_rd890_iommu(iommu->dev)) {
+ pci_write_config_dword(iommu->dev, 0xf0, iommu->cache_cfg[0]);
+ pci_write_config_dword(iommu->dev, 0xf4, iommu->cache_cfg[1]);
+ pci_write_config_dword(iommu->dev, 0xf8, iommu->cache_cfg[2]);
+ pci_write_config_dword(iommu->dev, 0xfc, iommu->cache_cfg[3]);
+ }
+}
+
/*
* This function finally enables all IOMMUs found in the system after
* they have been initialized
@@ -1126,6 +1147,8 @@
for_each_iommu(iommu) {
iommu_disable(iommu);
+ iommu_apply_quirks(iommu);
+ iommu_init_flags(iommu);
iommu_set_device_table(iommu);
iommu_enable_command_buffer(iommu);
iommu_enable_event_buffer(iommu);
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index f1efeba..5c5b8f3 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -306,14 +306,19 @@
old_cfg = old_desc->chip_data;
- memcpy(cfg, old_cfg, sizeof(struct irq_cfg));
+ cfg->vector = old_cfg->vector;
+ cfg->move_in_progress = old_cfg->move_in_progress;
+ cpumask_copy(cfg->domain, old_cfg->domain);
+ cpumask_copy(cfg->old_domain, old_cfg->old_domain);
init_copy_irq_2_pin(old_cfg, cfg, node);
}
-static void free_irq_cfg(struct irq_cfg *old_cfg)
+static void free_irq_cfg(struct irq_cfg *cfg)
{
- kfree(old_cfg);
+ free_cpumask_var(cfg->domain);
+ free_cpumask_var(cfg->old_domain);
+ kfree(cfg);
}
void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc)
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c
index 7b598b8..f744f54 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -698,9 +698,11 @@
for (j = 0; j < 64; j++) {
if (!test_bit(j, &present))
continue;
- uv_blade_info[blade].pnode = (i * 64 + j);
+ pnode = (i * 64 + j);
+ uv_blade_info[blade].pnode = pnode;
uv_blade_info[blade].nr_possible_cpus = 0;
uv_blade_info[blade].nr_online_cpus = 0;
+ max_pnode = max(pnode, max_pnode);
blade++;
}
}
@@ -738,7 +740,6 @@
uv_cpu_hub_info(cpu)->scir.offset = uv_scir_offset(apicid);
uv_node_to_blade[nid] = blade;
uv_cpu_to_blade[cpu] = blade;
- max_pnode = max(pnode, max_pnode);
}
/* Add blade/pnode info for nodes without cpus */
@@ -750,7 +751,6 @@
pnode = (paddr >> m_val) & pnode_mask;
blade = boot_pnode_to_blade(pnode);
uv_node_to_blade[nid] = blade;
- max_pnode = max(pnode, max_pnode);
}
map_gru_high(max_pnode);
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 490dac6..f2f9ac7 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -545,7 +545,7 @@
}
}
-static void __cpuinit get_cpu_cap(struct cpuinfo_x86 *c)
+void __cpuinit get_cpu_cap(struct cpuinfo_x86 *c)
{
u32 tfms, xlvl;
u32 ebx;
diff --git a/arch/x86/kernel/cpu/cpu.h b/arch/x86/kernel/cpu/cpu.h
index 3624e8a..f668bb1 100644
--- a/arch/x86/kernel/cpu/cpu.h
+++ b/arch/x86/kernel/cpu/cpu.h
@@ -33,5 +33,6 @@
*const __x86_cpu_dev_end[];
extern void cpu_detect_cache_sizes(struct cpuinfo_x86 *c);
+extern void get_cpu_cap(struct cpuinfo_x86 *c);
#endif
diff --git a/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c
index 994230d..4f6f679 100644
--- a/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c
+++ b/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c
@@ -368,16 +368,22 @@
return -ENODEV;
out_obj = output.pointer;
- if (out_obj->type != ACPI_TYPE_BUFFER)
- return -ENODEV;
+ if (out_obj->type != ACPI_TYPE_BUFFER) {
+ ret = -ENODEV;
+ goto out_free;
+ }
errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0);
- if (errors)
- return -ENODEV;
+ if (errors) {
+ ret = -ENODEV;
+ goto out_free;
+ }
supported = *((u32 *)(out_obj->buffer.pointer + 4));
- if (!(supported & 0x1))
- return -ENODEV;
+ if (!(supported & 0x1)) {
+ ret = -ENODEV;
+ goto out_free;
+ }
out_free:
kfree(output.pointer);
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index 85f69cd..b438944 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -39,6 +39,7 @@
misc_enable &= ~MSR_IA32_MISC_ENABLE_LIMIT_CPUID;
wrmsrl(MSR_IA32_MISC_ENABLE, misc_enable);
c->cpuid_level = cpuid_eax(0);
+ get_cpu_cap(c);
}
}
diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c
index 5e97529..39aaee5 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_amd.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c
@@ -141,6 +141,7 @@
address = (low & MASK_BLKPTR_LO) >> 21;
if (!address)
break;
+
address += MCG_XBLK_ADDR;
} else
++address;
@@ -148,12 +149,8 @@
if (rdmsr_safe(address, &low, &high))
break;
- if (!(high & MASK_VALID_HI)) {
- if (block)
- continue;
- else
- break;
- }
+ if (!(high & MASK_VALID_HI))
+ continue;
if (!(high & MASK_CNTP_HI) ||
(high & MASK_LOCKED_HI))
diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c
index d9368ee..169d880 100644
--- a/arch/x86/kernel/cpu/mcheck/therm_throt.c
+++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c
@@ -216,7 +216,7 @@
err = sysfs_add_file_to_group(&sys_dev->kobj,
&attr_core_power_limit_count.attr,
thermal_attr_group.name);
- if (cpu_has(c, X86_FEATURE_PTS))
+ if (cpu_has(c, X86_FEATURE_PTS)) {
err = sysfs_add_file_to_group(&sys_dev->kobj,
&attr_package_throttle_count.attr,
thermal_attr_group.name);
@@ -224,6 +224,7 @@
err = sysfs_add_file_to_group(&sys_dev->kobj,
&attr_package_power_limit_count.attr,
thermal_attr_group.name);
+ }
return err;
}
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index 3efdf28..03a5b03 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -102,6 +102,7 @@
*/
struct perf_event *events[X86_PMC_IDX_MAX]; /* in counter order */
unsigned long active_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
+ unsigned long running[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
int enabled;
int n_events;
@@ -1010,6 +1011,7 @@
x86_perf_event_set_period(event);
cpuc->events[idx] = event;
__set_bit(idx, cpuc->active_mask);
+ __set_bit(idx, cpuc->running);
x86_pmu.enable(event);
perf_event_update_userpage(event);
@@ -1141,8 +1143,16 @@
cpuc = &__get_cpu_var(cpu_hw_events);
for (idx = 0; idx < x86_pmu.num_counters; idx++) {
- if (!test_bit(idx, cpuc->active_mask))
+ if (!test_bit(idx, cpuc->active_mask)) {
+ /*
+ * Though we deactivated the counter some cpus
+ * might still deliver spurious interrupts still
+ * in flight. Catch them:
+ */
+ if (__test_and_clear_bit(idx, cpuc->running))
+ handled++;
continue;
+ }
event = cpuc->events[idx];
hwc = &event->hw;
diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c
index b560db3..2490151 100644
--- a/arch/x86/kernel/cpu/perf_event_p4.c
+++ b/arch/x86/kernel/cpu/perf_event_p4.c
@@ -660,8 +660,12 @@
for (idx = 0; idx < x86_pmu.num_counters; idx++) {
int overflow;
- if (!test_bit(idx, cpuc->active_mask))
+ if (!test_bit(idx, cpuc->active_mask)) {
+ /* catch in-flight IRQs */
+ if (__test_and_clear_bit(idx, cpuc->running))
+ handled++;
continue;
+ }
event = cpuc->events[idx];
hwc = &event->hw;
diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c
index 34b4dad..d490795 100644
--- a/arch/x86/kernel/cpu/scattered.c
+++ b/arch/x86/kernel/cpu/scattered.c
@@ -31,6 +31,7 @@
const struct cpuid_bit *cb;
static const struct cpuid_bit __cpuinitconst cpuid_bits[] = {
+ { X86_FEATURE_DTS, CR_EAX, 0, 0x00000006, 0 },
{ X86_FEATURE_IDA, CR_EAX, 1, 0x00000006, 0 },
{ X86_FEATURE_ARAT, CR_EAX, 2, 0x00000006, 0 },
{ X86_FEATURE_PLN, CR_EAX, 4, 0x00000006, 0 },
diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c
index e5cc7e8..ebdb85c 100644
--- a/arch/x86/kernel/early-quirks.c
+++ b/arch/x86/kernel/early-quirks.c
@@ -18,7 +18,6 @@
#include <asm/apic.h>
#include <asm/iommu.h>
#include <asm/gart.h>
-#include <asm/hpet.h>
static void __init fix_hypertransport_config(int num, int slot, int func)
{
@@ -192,21 +191,6 @@
}
#endif
-/*
- * Force the read back of the CMP register in hpet_next_event()
- * to work around the problem that the CMP register write seems to be
- * delayed. See hpet_next_event() for details.
- *
- * We do this on all SMBUS incarnations for now until we have more
- * information about the affected chipsets.
- */
-static void __init ati_hpet_bugs(int num, int slot, int func)
-{
-#ifdef CONFIG_HPET_TIMER
- hpet_readback_cmp = 1;
-#endif
-}
-
#define QFLAG_APPLY_ONCE 0x1
#define QFLAG_APPLIED 0x2
#define QFLAG_DONE (QFLAG_APPLY_ONCE|QFLAG_APPLIED)
@@ -236,8 +220,6 @@
PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS,
PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs_contd },
- { PCI_VENDOR_ID_ATI, PCI_ANY_ID,
- PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_hpet_bugs },
{}
};
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index 351f9c0..7494999 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -35,7 +35,6 @@
unsigned long hpet_address;
u8 hpet_blockid; /* OS timer block num */
u8 hpet_msi_disable;
-u8 hpet_readback_cmp;
#ifdef CONFIG_PCI_MSI
static unsigned long hpet_num_timers;
@@ -395,23 +394,27 @@
* at that point and we would wait for the next hpet interrupt
* forever. We found out that reading the CMP register back
* forces the transfer so we can rely on the comparison with
- * the counter register below.
+ * the counter register below. If the read back from the
+ * compare register does not match the value we programmed
+ * then we might have a real hardware problem. We can not do
+ * much about it here, but at least alert the user/admin with
+ * a prominent warning.
*
- * That works fine on those ATI chipsets, but on newer Intel
- * chipsets (ICH9...) this triggers due to an erratum: Reading
- * the comparator immediately following a write is returning
- * the old value.
+ * An erratum on some chipsets (ICH9,..), results in
+ * comparator read immediately following a write returning old
+ * value. Workaround for this is to read this value second
+ * time, when first read returns old value.
*
- * We restrict the read back to the affected ATI chipsets (set
- * by quirks) and also run it with hpet=verbose for debugging
- * purposes.
+ * In fact the write to the comparator register is delayed up
+ * to two HPET cycles so the workaround we tried to restrict
+ * the readback to those known to be borked ATI chipsets
+ * failed miserably. So we give up on optimizations forever
+ * and penalize all HPET incarnations unconditionally.
*/
- if (hpet_readback_cmp || hpet_verbose) {
- u32 cmp = hpet_readl(HPET_Tn_CMP(timer));
-
- if (cmp != cnt)
+ if (unlikely((u32)hpet_readl(HPET_Tn_CMP(timer)) != cnt)) {
+ if (hpet_readl(HPET_Tn_CMP(timer)) != cnt)
printk_once(KERN_WARNING
- "hpet: compare register read back failed.\n");
+ "hpet: compare register read back failed.\n");
}
return (s32)(hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0;
@@ -503,7 +506,7 @@
{
unsigned int irq;
- irq = create_irq();
+ irq = create_irq_nr(0, -1);
if (!irq)
return -EINVAL;
diff --git a/arch/x86/kernel/hw_breakpoint.c b/arch/x86/kernel/hw_breakpoint.c
index a474ec3..ff15c9d 100644
--- a/arch/x86/kernel/hw_breakpoint.c
+++ b/arch/x86/kernel/hw_breakpoint.c
@@ -206,11 +206,27 @@
int arch_bp_generic_fields(int x86_len, int x86_type,
int *gen_len, int *gen_type)
{
+ /* Type */
+ switch (x86_type) {
+ case X86_BREAKPOINT_EXECUTE:
+ if (x86_len != X86_BREAKPOINT_LEN_X)
+ return -EINVAL;
+
+ *gen_type = HW_BREAKPOINT_X;
+ *gen_len = sizeof(long);
+ return 0;
+ case X86_BREAKPOINT_WRITE:
+ *gen_type = HW_BREAKPOINT_W;
+ break;
+ case X86_BREAKPOINT_RW:
+ *gen_type = HW_BREAKPOINT_W | HW_BREAKPOINT_R;
+ break;
+ default:
+ return -EINVAL;
+ }
+
/* Len */
switch (x86_len) {
- case X86_BREAKPOINT_LEN_X:
- *gen_len = sizeof(long);
- break;
case X86_BREAKPOINT_LEN_1:
*gen_len = HW_BREAKPOINT_LEN_1;
break;
@@ -229,21 +245,6 @@
return -EINVAL;
}
- /* Type */
- switch (x86_type) {
- case X86_BREAKPOINT_EXECUTE:
- *gen_type = HW_BREAKPOINT_X;
- break;
- case X86_BREAKPOINT_WRITE:
- *gen_type = HW_BREAKPOINT_W;
- break;
- case X86_BREAKPOINT_RW:
- *gen_type = HW_BREAKPOINT_W | HW_BREAKPOINT_R;
- break;
- default:
- return -EINVAL;
- }
-
return 0;
}
@@ -316,9 +317,6 @@
ret = -EINVAL;
switch (info->len) {
- case X86_BREAKPOINT_LEN_X:
- align = sizeof(long) -1;
- break;
case X86_BREAKPOINT_LEN_1:
align = 0;
break;
diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c
index e0bc186..1c355c5 100644
--- a/arch/x86/kernel/module.c
+++ b/arch/x86/kernel/module.c
@@ -239,11 +239,10 @@
apply_paravirt(pseg, pseg + para->sh_size);
}
- return module_bug_finalize(hdr, sechdrs, me);
+ return 0;
}
void module_arch_cleanup(struct module *mod)
{
alternatives_smp_module_del(mod);
- module_bug_cleanup(mod);
}
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index bc5b9b8..8a3f9f6 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -766,7 +766,6 @@
control->iopm_base_pa = iopm_base;
control->msrpm_base_pa = __pa(svm->msrpm);
- control->tsc_offset = 0;
control->int_ctl = V_INTR_MASKING_MASK;
init_seg(&save->es);
@@ -902,6 +901,7 @@
svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT;
svm->asid_generation = 0;
init_vmcb(svm);
+ svm->vmcb->control.tsc_offset = 0-native_read_tsc();
err = fx_init(&svm->vcpu);
if (err)
@@ -3163,8 +3163,8 @@
sync_lapic_to_cr8(vcpu);
save_host_msrs(vcpu);
- fs_selector = kvm_read_fs();
- gs_selector = kvm_read_gs();
+ savesegment(fs, fs_selector);
+ savesegment(gs, gs_selector);
ldt_selector = kvm_read_ldt();
svm->vmcb->save.cr2 = vcpu->arch.cr2;
/* required for live migration with NPT */
@@ -3251,10 +3251,15 @@
vcpu->arch.regs[VCPU_REGS_RSP] = svm->vmcb->save.rsp;
vcpu->arch.regs[VCPU_REGS_RIP] = svm->vmcb->save.rip;
- kvm_load_fs(fs_selector);
- kvm_load_gs(gs_selector);
- kvm_load_ldt(ldt_selector);
load_host_msrs(vcpu);
+ loadsegment(fs, fs_selector);
+#ifdef CONFIG_X86_64
+ load_gs_index(gs_selector);
+ wrmsrl(MSR_KERNEL_GS_BASE, current->thread.gs);
+#else
+ loadsegment(gs, gs_selector);
+#endif
+ kvm_load_ldt(ldt_selector);
reload_tss(vcpu);
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 49b25ee..7bddfab 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -803,7 +803,7 @@
*/
vmx->host_state.ldt_sel = kvm_read_ldt();
vmx->host_state.gs_ldt_reload_needed = vmx->host_state.ldt_sel;
- vmx->host_state.fs_sel = kvm_read_fs();
+ savesegment(fs, vmx->host_state.fs_sel);
if (!(vmx->host_state.fs_sel & 7)) {
vmcs_write16(HOST_FS_SELECTOR, vmx->host_state.fs_sel);
vmx->host_state.fs_reload_needed = 0;
@@ -811,7 +811,7 @@
vmcs_write16(HOST_FS_SELECTOR, 0);
vmx->host_state.fs_reload_needed = 1;
}
- vmx->host_state.gs_sel = kvm_read_gs();
+ savesegment(gs, vmx->host_state.gs_sel);
if (!(vmx->host_state.gs_sel & 7))
vmcs_write16(HOST_GS_SELECTOR, vmx->host_state.gs_sel);
else {
@@ -841,27 +841,21 @@
static void __vmx_load_host_state(struct vcpu_vmx *vmx)
{
- unsigned long flags;
-
if (!vmx->host_state.loaded)
return;
++vmx->vcpu.stat.host_state_reload;
vmx->host_state.loaded = 0;
if (vmx->host_state.fs_reload_needed)
- kvm_load_fs(vmx->host_state.fs_sel);
+ loadsegment(fs, vmx->host_state.fs_sel);
if (vmx->host_state.gs_ldt_reload_needed) {
kvm_load_ldt(vmx->host_state.ldt_sel);
- /*
- * If we have to reload gs, we must take care to
- * preserve our gs base.
- */
- local_irq_save(flags);
- kvm_load_gs(vmx->host_state.gs_sel);
#ifdef CONFIG_X86_64
- wrmsrl(MSR_GS_BASE, vmcs_readl(HOST_GS_BASE));
+ load_gs_index(vmx->host_state.gs_sel);
+ wrmsrl(MSR_KERNEL_GS_BASE, current->thread.gs);
+#else
+ loadsegment(gs, vmx->host_state.gs_sel);
#endif
- local_irq_restore(flags);
}
reload_tss();
#ifdef CONFIG_X86_64
@@ -2589,8 +2583,8 @@
vmcs_write16(HOST_CS_SELECTOR, __KERNEL_CS); /* 22.2.4 */
vmcs_write16(HOST_DS_SELECTOR, __KERNEL_DS); /* 22.2.4 */
vmcs_write16(HOST_ES_SELECTOR, __KERNEL_DS); /* 22.2.4 */
- vmcs_write16(HOST_FS_SELECTOR, kvm_read_fs()); /* 22.2.4 */
- vmcs_write16(HOST_GS_SELECTOR, kvm_read_gs()); /* 22.2.4 */
+ vmcs_write16(HOST_FS_SELECTOR, 0); /* 22.2.4 */
+ vmcs_write16(HOST_GS_SELECTOR, 0); /* 22.2.4 */
vmcs_write16(HOST_SS_SELECTOR, __KERNEL_DS); /* 22.2.4 */
#ifdef CONFIG_X86_64
rdmsrl(MSR_FS_BASE, a);
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c
index 9257510..9d5f558 100644
--- a/arch/x86/lguest/boot.c
+++ b/arch/x86/lguest/boot.c
@@ -324,9 +324,8 @@
}
/*
- * For a single GDT entry which changes, we do the lazy thing: alter our GDT,
- * then tell the Host to reload the entire thing. This operation is so rare
- * that this naive implementation is reasonable.
+ * For a single GDT entry which changes, we simply change our copy and
+ * then tell the host about it.
*/
static void lguest_write_gdt_entry(struct desc_struct *dt, int entrynum,
const void *desc, int type)
@@ -338,9 +337,13 @@
}
/*
- * OK, I lied. There are three "thread local storage" GDT entries which change
+ * There are three "thread local storage" GDT entries which change
* on every context switch (these three entries are how glibc implements
- * __thread variables). So we have a hypercall specifically for this case.
+ * __thread variables). As an optimization, we have a hypercall
+ * specifically for this case.
+ *
+ * Wouldn't it be nicer to have a general LOAD_GDT_ENTRIES hypercall
+ * which took a range of entries?
*/
static void lguest_load_tls(struct thread_struct *t, unsigned int cpu)
{
diff --git a/arch/x86/mm/srat_64.c b/arch/x86/mm/srat_64.c
index f9897f7..9c0d0d3 100644
--- a/arch/x86/mm/srat_64.c
+++ b/arch/x86/mm/srat_64.c
@@ -420,9 +420,11 @@
return -1;
}
- for_each_node_mask(i, nodes_parsed)
- e820_register_active_regions(i, nodes[i].start >> PAGE_SHIFT,
- nodes[i].end >> PAGE_SHIFT);
+ for (i = 0; i < num_node_memblks; i++)
+ e820_register_active_regions(memblk_nodeid[i],
+ node_memblk_range[i].start >> PAGE_SHIFT,
+ node_memblk_range[i].end >> PAGE_SHIFT);
+
/* for out of order entries in SRAT */
sort_node_map();
if (!nodes_cover_memory(nodes)) {
diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c
index cfe4faa..f1575c9 100644
--- a/arch/x86/oprofile/nmi_int.c
+++ b/arch/x86/oprofile/nmi_int.c
@@ -671,7 +671,10 @@
case 14:
*cpu_type = "i386/core";
break;
- case 15: case 23:
+ case 0x0f:
+ case 0x16:
+ case 0x17:
+ case 0x1d:
*cpu_type = "i386/core_2";
break;
case 0x1a:
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
index 1a5353a..b2bb5aa 100644
--- a/arch/x86/xen/time.c
+++ b/arch/x86/xen/time.c
@@ -489,8 +489,9 @@
__init void xen_hvm_init_time_ops(void)
{
/* vector callback is needed otherwise we cannot receive interrupts
- * on cpu > 0 */
- if (!xen_have_vector_callback && num_present_cpus() > 1)
+ * on cpu > 0 and at this point we don't know how many cpus are
+ * available */
+ if (!xen_have_vector_callback)
return;
if (!xen_feature(XENFEAT_hvm_safe_pvclock)) {
printk(KERN_INFO "Xen doesn't support pvclock on HVM,"
diff --git a/block/blk-map.c b/block/blk-map.c
index c65d759..ade0a08 100644
--- a/block/blk-map.c
+++ b/block/blk-map.c
@@ -307,7 +307,7 @@
return PTR_ERR(bio);
if (rq_data_dir(rq) == WRITE)
- bio->bi_rw |= (1 << REQ_WRITE);
+ bio->bi_rw |= REQ_WRITE;
if (do_copy)
rq->cmd_flags |= REQ_COPY_USER;
diff --git a/block/blk-merge.c b/block/blk-merge.c
index 3b0cd42..eafc94f 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -362,6 +362,18 @@
return 0;
/*
+ * Don't merge file system requests and discard requests
+ */
+ if ((req->cmd_flags & REQ_DISCARD) != (next->cmd_flags & REQ_DISCARD))
+ return 0;
+
+ /*
+ * Don't merge discard requests and secure discard requests
+ */
+ if ((req->cmd_flags & REQ_SECURE) != (next->cmd_flags & REQ_SECURE))
+ return 0;
+
+ /*
* not contiguous
*/
if (blk_rq_pos(req) + blk_rq_sectors(req) != blk_rq_pos(next))
diff --git a/block/bsg.c b/block/bsg.c
index 82d5882..0c00870 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -426,7 +426,7 @@
/*
* fill in all the output members
*/
- hdr->device_status = status_byte(rq->errors);
+ hdr->device_status = rq->errors & 0xff;
hdr->transport_status = host_byte(rq->errors);
hdr->driver_status = driver_byte(rq->errors);
hdr->info = 0;
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index f65c6f0..9eba291 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -1019,10 +1019,20 @@
*/
atomic_set(&cfqg->ref, 1);
- /* Add group onto cgroup list */
- sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
- cfq_blkiocg_add_blkio_group(blkcg, &cfqg->blkg, (void *)cfqd,
+ /*
+ * Add group onto cgroup list. It might happen that bdi->dev is
+ * not initiliazed yet. Initialize this new group without major
+ * and minor info and this info will be filled in once a new thread
+ * comes for IO. See code above.
+ */
+ if (bdi->dev) {
+ sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
+ cfq_blkiocg_add_blkio_group(blkcg, &cfqg->blkg, (void *)cfqd,
MKDEV(major, minor));
+ } else
+ cfq_blkiocg_add_blkio_group(blkcg, &cfqg->blkg, (void *)cfqd,
+ 0);
+
cfqg->weight = blkcg_get_weight(blkcg, cfqg->blkg.dev);
/* Add group on cfqd list */
diff --git a/block/elevator.c b/block/elevator.c
index 205b09a..4e11559 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -938,6 +938,7 @@
}
}
kobject_uevent(&e->kobj, KOBJ_ADD);
+ e->registered = 1;
}
return error;
}
@@ -947,6 +948,7 @@
{
kobject_uevent(&e->kobj, KOBJ_REMOVE);
kobject_del(&e->kobj);
+ e->registered = 0;
}
void elv_unregister_queue(struct request_queue *q)
@@ -1042,11 +1044,13 @@
spin_unlock_irq(q->queue_lock);
- __elv_unregister_queue(old_elevator);
+ if (old_elevator->registered) {
+ __elv_unregister_queue(old_elevator);
- err = elv_register_queue(q);
- if (err)
- goto fail_register;
+ err = elv_register_queue(q);
+ if (err)
+ goto fail_register;
+ }
/*
* finally exit old elevator and turn off BYPASS.
diff --git a/drivers/Makefile b/drivers/Makefile
index ae47344..a2aea53 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -50,7 +50,7 @@
obj-y += net/
obj-$(CONFIG_ATM) += atm/
obj-$(CONFIG_FUSION) += message/
-obj-$(CONFIG_FIREWIRE) += firewire/
+obj-y += firewire/
obj-y += ieee1394/
obj-$(CONFIG_UIO) += uio/
obj-y += cdrom/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index b811f21..88681ac 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -105,7 +105,7 @@
Be aware that using this interface can confuse your Embedded
Controller in a way that a normal reboot is not enough. You then
- have to power of your system, and remove the laptop battery for
+ have to power off your system, and remove the laptop battery for
some seconds.
An Embedded Controller typically is available on laptops and reads
sensor values like battery state and temperature.
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
index b76848c..6b115f6 100644
--- a/drivers/acpi/acpi_pad.c
+++ b/drivers/acpi/acpi_pad.c
@@ -382,31 +382,32 @@
device_remove_file(&device->dev, &dev_attr_rrtime);
}
-/* Query firmware how many CPUs should be idle */
-static int acpi_pad_pur(acpi_handle handle, int *num_cpus)
+/*
+ * Query firmware how many CPUs should be idle
+ * return -1 on failure
+ */
+static int acpi_pad_pur(acpi_handle handle)
{
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
union acpi_object *package;
- int rev, num, ret = -EINVAL;
+ int num = -1;
if (ACPI_FAILURE(acpi_evaluate_object(handle, "_PUR", NULL, &buffer)))
- return -EINVAL;
+ return num;
if (!buffer.length || !buffer.pointer)
- return -EINVAL;
+ return num;
package = buffer.pointer;
- if (package->type != ACPI_TYPE_PACKAGE || package->package.count != 2)
- goto out;
- rev = package->package.elements[0].integer.value;
- num = package->package.elements[1].integer.value;
- if (rev != 1 || num < 0)
- goto out;
- *num_cpus = num;
- ret = 0;
-out:
+
+ if (package->type == ACPI_TYPE_PACKAGE &&
+ package->package.count == 2 &&
+ package->package.elements[0].integer.value == 1) /* rev 1 */
+
+ num = package->package.elements[1].integer.value;
+
kfree(buffer.pointer);
- return ret;
+ return num;
}
/* Notify firmware how many CPUs are idle */
@@ -433,7 +434,8 @@
uint32_t idle_cpus;
mutex_lock(&isolated_cpus_lock);
- if (acpi_pad_pur(handle, &num_cpus)) {
+ num_cpus = acpi_pad_pur(handle);
+ if (num_cpus < 0) {
mutex_unlock(&isolated_cpus_lock);
return;
}
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index df85b53..7dad916 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -854,6 +854,7 @@
ACPI_BITMASK_POWER_BUTTON_STATUS | \
ACPI_BITMASK_SLEEP_BUTTON_STATUS | \
ACPI_BITMASK_RT_CLOCK_STATUS | \
+ ACPI_BITMASK_PCIEXP_WAKE_DISABLE | \
ACPI_BITMASK_WAKE_STATUS)
#define ACPI_BITMASK_TIMER_ENABLE 0x0001
diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c
index 74c24d5..4093522 100644
--- a/drivers/acpi/acpica/exutils.c
+++ b/drivers/acpi/acpica/exutils.c
@@ -109,7 +109,7 @@
*
* DESCRIPTION: Reacquire the interpreter execution region from within the
* interpreter code. Failure to enter the interpreter region is a
- * fatal system error. Used in conjuction with
+ * fatal system error. Used in conjunction with
* relinquish_interpreter
*
******************************************************************************/
diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c
index 22cfcfb..491191e 100644
--- a/drivers/acpi/acpica/rsutils.c
+++ b/drivers/acpi/acpica/rsutils.c
@@ -149,7 +149,7 @@
/*
* 16-, 32-, and 64-bit cases must use the move macros that perform
- * endian conversion and/or accomodate hardware that cannot perform
+ * endian conversion and/or accommodate hardware that cannot perform
* misaligned memory transfers
*/
case ACPI_RSC_MOVE16:
diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig
index 907e350..fca34cc 100644
--- a/drivers/acpi/apei/Kconfig
+++ b/drivers/acpi/apei/Kconfig
@@ -34,6 +34,6 @@
depends on ACPI_APEI
help
ERST is a way provided by APEI to save and retrieve hardware
- error infomation to and from a persistent store. Enable this
+ error information to and from a persistent store. Enable this
if you want to debugging and testing the ERST kernel support
and firmware implementation.
diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c
index 73fd0c7..4a904a4 100644
--- a/drivers/acpi/apei/apei-base.c
+++ b/drivers/acpi/apei/apei-base.c
@@ -445,11 +445,15 @@
int apei_resources_request(struct apei_resources *resources,
const char *desc)
{
- struct apei_res *res, *res_bak;
+ struct apei_res *res, *res_bak = NULL;
struct resource *r;
+ int rc;
- apei_resources_sub(resources, &apei_resources_all);
+ rc = apei_resources_sub(resources, &apei_resources_all);
+ if (rc)
+ return rc;
+ rc = -EINVAL;
list_for_each_entry(res, &resources->iomem, list) {
r = request_mem_region(res->start, res->end - res->start,
desc);
@@ -475,7 +479,11 @@
}
}
- apei_resources_merge(&apei_resources_all, resources);
+ rc = apei_resources_merge(&apei_resources_all, resources);
+ if (rc) {
+ pr_err(APEI_PFX "Fail to merge resources!\n");
+ goto err_unmap_ioport;
+ }
return 0;
err_unmap_ioport:
@@ -491,12 +499,13 @@
break;
release_mem_region(res->start, res->end - res->start);
}
- return -EINVAL;
+ return rc;
}
EXPORT_SYMBOL_GPL(apei_resources_request);
void apei_resources_release(struct apei_resources *resources)
{
+ int rc;
struct apei_res *res;
list_for_each_entry(res, &resources->iomem, list)
@@ -504,7 +513,9 @@
list_for_each_entry(res, &resources->ioport, list)
release_region(res->start, res->end - res->start);
- apei_resources_sub(&apei_resources_all, resources);
+ rc = apei_resources_sub(&apei_resources_all, resources);
+ if (rc)
+ pr_err(APEI_PFX "Fail to sub resources!\n");
}
EXPORT_SYMBOL_GPL(apei_resources_release);
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c
index 465c885..cf29df6 100644
--- a/drivers/acpi/apei/einj.c
+++ b/drivers/acpi/apei/einj.c
@@ -426,7 +426,9 @@
static int einj_check_table(struct acpi_table_einj *einj_tab)
{
- if (einj_tab->header_length != sizeof(struct acpi_table_einj))
+ if ((einj_tab->header_length !=
+ (sizeof(struct acpi_table_einj) - sizeof(einj_tab->header)))
+ && (einj_tab->header_length != sizeof(struct acpi_table_einj)))
return -EINVAL;
if (einj_tab->header.length < sizeof(struct acpi_table_einj))
return -EINVAL;
diff --git a/drivers/acpi/apei/erst-dbg.c b/drivers/acpi/apei/erst-dbg.c
index 5281ddd..da1228a 100644
--- a/drivers/acpi/apei/erst-dbg.c
+++ b/drivers/acpi/apei/erst-dbg.c
@@ -2,7 +2,7 @@
* APEI Error Record Serialization Table debug support
*
* ERST is a way provided by APEI to save and retrieve hardware error
- * infomation to and from a persistent store. This file provide the
+ * information to and from a persistent store. This file provide the
* debugging/testing support for ERST kernel support and firmware
* implementation.
*
@@ -111,11 +111,13 @@
goto out;
}
if (len > erst_dbg_buf_len) {
- kfree(erst_dbg_buf);
+ void *p;
rc = -ENOMEM;
- erst_dbg_buf = kmalloc(len, GFP_KERNEL);
- if (!erst_dbg_buf)
+ p = kmalloc(len, GFP_KERNEL);
+ if (!p)
goto out;
+ kfree(erst_dbg_buf);
+ erst_dbg_buf = p;
erst_dbg_buf_len = len;
goto retry;
}
@@ -150,11 +152,13 @@
if (mutex_lock_interruptible(&erst_dbg_mutex))
return -EINTR;
if (usize > erst_dbg_buf_len) {
- kfree(erst_dbg_buf);
+ void *p;
rc = -ENOMEM;
- erst_dbg_buf = kmalloc(usize, GFP_KERNEL);
- if (!erst_dbg_buf)
+ p = kmalloc(usize, GFP_KERNEL);
+ if (!p)
goto out;
+ kfree(erst_dbg_buf);
+ erst_dbg_buf = p;
erst_dbg_buf_len = usize;
}
rc = copy_from_user(erst_dbg_buf, ubuf, usize);
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c
index 18645f4..1211c03 100644
--- a/drivers/acpi/apei/erst.c
+++ b/drivers/acpi/apei/erst.c
@@ -2,7 +2,7 @@
* APEI Error Record Serialization Table support
*
* ERST is a way provided by APEI to save and retrieve hardware error
- * infomation to and from a persistent store.
+ * information to and from a persistent store.
*
* For more information about ERST, please refer to ACPI Specification
* version 4.0, section 17.4.
@@ -266,13 +266,30 @@
{
int rc;
u64 offset;
+ void *src, *dst;
+
+ /* ioremap does not work in interrupt context */
+ if (in_interrupt()) {
+ pr_warning(ERST_PFX
+ "MOVE_DATA can not be used in interrupt context");
+ return -EBUSY;
+ }
rc = __apei_exec_read_register(entry, &offset);
if (rc)
return rc;
- memmove((void *)ctx->dst_base + offset,
- (void *)ctx->src_base + offset,
- ctx->var2);
+
+ src = ioremap(ctx->src_base + offset, ctx->var2);
+ if (!src)
+ return -ENOMEM;
+ dst = ioremap(ctx->dst_base + offset, ctx->var2);
+ if (!dst)
+ return -ENOMEM;
+
+ memmove(dst, src, ctx->var2);
+
+ iounmap(src);
+ iounmap(dst);
return 0;
}
@@ -750,7 +767,9 @@
static int erst_check_table(struct acpi_table_erst *erst_tab)
{
- if (erst_tab->header_length != sizeof(struct acpi_table_erst))
+ if ((erst_tab->header_length !=
+ (sizeof(struct acpi_table_erst) - sizeof(erst_tab->header)))
+ && (erst_tab->header_length != sizeof(struct acpi_table_einj)))
return -EINVAL;
if (erst_tab->header.length < sizeof(struct acpi_table_erst))
return -EINVAL;
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 385a605..0d505e5 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -302,7 +302,7 @@
struct ghes *ghes = NULL;
int rc = -EINVAL;
- generic = ghes_dev->dev.platform_data;
+ generic = *(struct acpi_hest_generic **)ghes_dev->dev.platform_data;
if (!generic->enabled)
return -ENODEV;
diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c
index 343168d..1a3508a 100644
--- a/drivers/acpi/apei/hest.c
+++ b/drivers/acpi/apei/hest.c
@@ -137,20 +137,23 @@
static int hest_parse_ghes(struct acpi_hest_header *hest_hdr, void *data)
{
- struct acpi_hest_generic *generic;
struct platform_device *ghes_dev;
struct ghes_arr *ghes_arr = data;
int rc;
if (hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR)
return 0;
- generic = (struct acpi_hest_generic *)hest_hdr;
- if (!generic->enabled)
+
+ if (!((struct acpi_hest_generic *)hest_hdr)->enabled)
return 0;
ghes_dev = platform_device_alloc("GHES", hest_hdr->source_id);
if (!ghes_dev)
return -ENOMEM;
- ghes_dev->dev.platform_data = generic;
+
+ rc = platform_device_add_data(ghes_dev, &hest_hdr, sizeof(void *));
+ if (rc)
+ goto err;
+
rc = platform_device_add(ghes_dev);
if (rc)
goto err;
diff --git a/drivers/acpi/atomicio.c b/drivers/acpi/atomicio.c
index 8f8bd73..542e539 100644
--- a/drivers/acpi/atomicio.c
+++ b/drivers/acpi/atomicio.c
@@ -142,7 +142,7 @@
list_add_tail_rcu(&map->list, &acpi_iomaps);
spin_unlock_irqrestore(&acpi_iomaps_lock, flags);
- return vaddr + (paddr - pg_off);
+ return map->vaddr + (paddr - map->paddr);
err_unmap:
iounmap(vaddr);
return NULL;
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index dc58402..9841720 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -273,7 +273,6 @@
POWER_SUPPLY_PROP_CYCLE_COUNT,
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
- POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_POWER_NOW,
POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
POWER_SUPPLY_PROP_ENERGY_FULL,
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
index 2bb28b9..af308d0 100644
--- a/drivers/acpi/blacklist.c
+++ b/drivers/acpi/blacklist.c
@@ -183,6 +183,8 @@
{
printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident);
acpi_osi_setup("!Windows 2006");
+ acpi_osi_setup("!Windows 2006 SP1");
+ acpi_osi_setup("!Windows 2006 SP2");
return 0;
}
static int __init dmi_disable_osi_win7(const struct dmi_system_id *d)
@@ -202,6 +204,23 @@
},
},
{
+ /*
+ * There have a NVIF method in MSI GX723 DSDT need call by Nvidia
+ * driver (e.g. nouveau) when user press brightness hotkey.
+ * Currently, nouveau driver didn't do the job and it causes there
+ * have a infinite while loop in DSDT when user press hotkey.
+ * We add MSI GX723's dmi information to this table for workaround
+ * this issue.
+ * Will remove MSI GX723 from the table after nouveau grows support.
+ */
+ .callback = dmi_disable_osi_vista,
+ .ident = "MSI GX723",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "GX723"),
+ },
+ },
+ {
.callback = dmi_disable_osi_vista,
.ident = "Sony VGN-NS10J_S",
.matches = {
@@ -226,6 +245,14 @@
},
},
{
+ .callback = dmi_disable_osi_vista,
+ .ident = "Toshiba Satellite L355",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Satellite L355"),
+ },
+ },
+ {
.callback = dmi_disable_osi_win7,
.ident = "ASUS K50IJ",
.matches = {
@@ -233,6 +260,14 @@
DMI_MATCH(DMI_PRODUCT_NAME, "K50IJ"),
},
},
+ {
+ .callback = dmi_disable_osi_vista,
+ .ident = "Toshiba P305D",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P305D"),
+ },
+ },
/*
* BIOS invocation of _OSI(Linux) is almost always a BIOS bug.
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 5c221ab..310e3b9 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -55,7 +55,7 @@
static int set_power_nocheck(const struct dmi_system_id *id)
{
printk(KERN_NOTICE PREFIX "%s detected - "
- "disable power check in power transistion\n", id->ident);
+ "disable power check in power transition\n", id->ident);
acpi_power_nocheck = 1;
return 0;
}
@@ -80,23 +80,15 @@
static struct dmi_system_id dsdt_dmi_table[] __initdata = {
/*
- * Insyde BIOS on some TOSHIBA machines corrupt the DSDT.
+ * Invoke DSDT corruption work-around on all Toshiba Satellite.
* https://bugzilla.kernel.org/show_bug.cgi?id=14679
*/
{
.callback = set_copy_dsdt,
- .ident = "TOSHIBA Satellite A505",
+ .ident = "TOSHIBA Satellite",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
- DMI_MATCH(DMI_PRODUCT_NAME, "Satellite A505"),
- },
- },
- {
- .callback = set_copy_dsdt,
- .ident = "TOSHIBA Satellite L505D",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
- DMI_MATCH(DMI_PRODUCT_NAME, "Satellite L505D"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Satellite"),
},
},
{}
@@ -1027,7 +1019,7 @@
/*
* If the laptop falls into the DMI check table, the power state check
- * will be disabled in the course of device power transistion.
+ * will be disabled in the course of device power transition.
*/
dmi_check_system(power_nocheck_dmi_table);
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 8a3b840..d94d295 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -369,7 +369,9 @@
acpi_bus_unregister_driver(&acpi_fan_driver);
+#ifdef CONFIG_ACPI_PROCFS
remove_proc_entry(ACPI_FAN_CLASS, acpi_root_dir);
+#endif
return;
}
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index e9699aa..bec561c 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -29,12 +29,6 @@
static struct dmi_system_id __cpuinitdata processor_idle_dmi_table[] = {
{
- set_no_mwait, "IFL91 board", {
- DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
- DMI_MATCH(DMI_SYS_VENDOR, "ZEPTO"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "3215W"),
- DMI_MATCH(DMI_BOARD_NAME, "IFL91") }, NULL},
- {
set_no_mwait, "Extensa 5220", {
DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -352,4 +346,5 @@
acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX,
early_init_pdc, NULL, NULL, NULL);
+ acpi_get_devices("ACPI0007", early_init_pdc, NULL, NULL);
}
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index 1560218..347eb21 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -850,7 +850,7 @@
printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n",
acpi_idle_driver.name);
} else {
- printk(KERN_DEBUG "ACPI: acpi_idle yielding to %s",
+ printk(KERN_DEBUG "ACPI: acpi_idle yielding to %s\n",
cpuidle_get_driver()->name);
}
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index ba1bd26..3a73a93 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -447,8 +447,8 @@
if (!try_module_get(calling_module))
return -EINVAL;
- /* is_done is set to negative if an error occured,
- * and to postitive if _no_ error occured, but SMM
+ /* is_done is set to negative if an error occurred,
+ * and to postitive if _no_ error occurred, but SMM
* was already notified. This avoids double notification
* which might lead to unexpected results...
*/
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index cf82989..4754ff6 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -363,6 +363,12 @@
return 0;
}
+static int __init init_nvs_nosave(const struct dmi_system_id *d)
+{
+ acpi_nvs_nosave();
+ return 0;
+}
+
static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
{
.callback = init_old_suspend_ordering,
@@ -397,6 +403,22 @@
DMI_MATCH(DMI_BOARD_NAME, "CF51-2L"),
},
},
+ {
+ .callback = init_nvs_nosave,
+ .ident = "Sony Vaio VGN-SR11M",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR11M"),
+ },
+ },
+ {
+ .callback = init_nvs_nosave,
+ .ident = "Everex StepNote Series",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Everex Systems, Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Everex StepNote Series"),
+ },
+ },
{},
};
#endif /* CONFIG_SUSPEND */
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index 68e2e45..f8588f8 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -100,7 +100,7 @@
ACPI_DEBUG_INIT(ACPI_LV_EVENTS),
};
-static int param_get_debug_layer(char *buffer, struct kernel_param *kp)
+static int param_get_debug_layer(char *buffer, const struct kernel_param *kp)
{
int result = 0;
int i;
@@ -128,7 +128,7 @@
return result;
}
-static int param_get_debug_level(char *buffer, struct kernel_param *kp)
+static int param_get_debug_level(char *buffer, const struct kernel_param *kp)
{
int result = 0;
int i;
@@ -149,10 +149,18 @@
return result;
}
-module_param_call(debug_layer, param_set_uint, param_get_debug_layer,
- &acpi_dbg_layer, 0644);
-module_param_call(debug_level, param_set_uint, param_get_debug_level,
- &acpi_dbg_level, 0644);
+static struct kernel_param_ops param_ops_debug_layer = {
+ .set = param_set_uint,
+ .get = param_get_debug_layer,
+};
+
+static struct kernel_param_ops param_ops_debug_level = {
+ .set = param_set_uint,
+ .get = param_get_debug_level,
+};
+
+module_param_cb(debug_layer, ¶m_ops_debug_layer, &acpi_dbg_layer, 0644);
+module_param_cb(debug_level, ¶m_ops_debug_level, &acpi_dbg_level, 0644);
static char trace_method_name[6];
module_param_string(trace_method_name, trace_method_name, 6, 0644);
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index c5fef01..b836761 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -59,8 +59,8 @@
"support\n"));
*cap |= ACPI_VIDEO_BACKLIGHT;
if (ACPI_FAILURE(acpi_get_handle(handle, "_BQC", &h_dummy)))
- printk(KERN_WARNING FW_BUG PREFIX "ACPI brightness "
- "control misses _BQC function\n");
+ printk(KERN_WARNING FW_BUG PREFIX "No _BQC method, "
+ "cannot determine initial brightness\n");
/* We have backlight support, no need to scan further */
return AE_CTRL_TERMINATE;
}
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index ff1c945..99d0e5a 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -90,6 +90,10 @@
static int ahci_pci_device_resume(struct pci_dev *pdev);
#endif
+static struct scsi_host_template ahci_sht = {
+ AHCI_SHT("ahci"),
+};
+
static struct ata_port_operations ahci_vt8251_ops = {
.inherits = &ahci_ops,
.hardreset = ahci_vt8251_hardreset,
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 474427b..e5fdeeb 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -298,7 +298,17 @@
extern int ahci_ignore_sss;
-extern struct scsi_host_template ahci_sht;
+extern struct device_attribute *ahci_shost_attrs[];
+extern struct device_attribute *ahci_sdev_attrs[];
+
+#define AHCI_SHT(drv_name) \
+ ATA_NCQ_SHT(drv_name), \
+ .can_queue = AHCI_MAX_CMDS - 1, \
+ .sg_tablesize = AHCI_MAX_SG, \
+ .dma_boundary = AHCI_DMA_BOUNDARY, \
+ .shost_attrs = ahci_shost_attrs, \
+ .sdev_attrs = ahci_sdev_attrs
+
extern struct ata_port_operations ahci_ops;
void ahci_save_initial_config(struct device *dev,
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 4e97f33..84b6432 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -23,6 +23,10 @@
#include <linux/ahci_platform.h>
#include "ahci.h"
+static struct scsi_host_template ahci_platform_sht = {
+ AHCI_SHT("ahci_platform"),
+};
+
static int __init ahci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -145,7 +149,7 @@
ahci_print_info(host, "platform");
rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
- &ahci_sht);
+ &ahci_platform_sht);
if (rc)
goto err0;
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 68dc678..8eea309 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -121,7 +121,7 @@
static DEVICE_ATTR(em_buffer, S_IWUSR | S_IRUGO,
ahci_read_em_buffer, ahci_store_em_buffer);
-static struct device_attribute *ahci_shost_attrs[] = {
+struct device_attribute *ahci_shost_attrs[] = {
&dev_attr_link_power_management_policy,
&dev_attr_em_message_type,
&dev_attr_em_message,
@@ -132,22 +132,14 @@
&dev_attr_em_buffer,
NULL
};
+EXPORT_SYMBOL_GPL(ahci_shost_attrs);
-static struct device_attribute *ahci_sdev_attrs[] = {
+struct device_attribute *ahci_sdev_attrs[] = {
&dev_attr_sw_activity,
&dev_attr_unload_heads,
NULL
};
-
-struct scsi_host_template ahci_sht = {
- ATA_NCQ_SHT("ahci"),
- .can_queue = AHCI_MAX_CMDS - 1,
- .sg_tablesize = AHCI_MAX_SG,
- .dma_boundary = AHCI_DMA_BOUNDARY,
- .shost_attrs = ahci_shost_attrs,
- .sdev_attrs = ahci_sdev_attrs,
-};
-EXPORT_SYMBOL_GPL(ahci_sht);
+EXPORT_SYMBOL_GPL(ahci_sdev_attrs);
struct ata_port_operations ahci_ops = {
.inherits = &sata_pmp_port_ops,
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index ee9ddeb..8cb0347 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -3156,7 +3156,6 @@
{
struct atm_dev *dev;
IADEV *iadev;
- unsigned long flags;
int ret;
iadev = kzalloc(sizeof(*iadev), GFP_KERNEL);
@@ -3188,19 +3187,14 @@
ia_dev[iadev_count] = iadev;
_ia_dev[iadev_count] = dev;
iadev_count++;
- spin_lock_init(&iadev->misc_lock);
- /* First fixes first. I don't want to think about this now. */
- spin_lock_irqsave(&iadev->misc_lock, flags);
if (ia_init(dev) || ia_start(dev)) {
IF_INIT(printk("IA register failed!\n");)
iadev_count--;
ia_dev[iadev_count] = NULL;
_ia_dev[iadev_count] = NULL;
- spin_unlock_irqrestore(&iadev->misc_lock, flags);
ret = -EINVAL;
goto err_out_deregister_dev;
}
- spin_unlock_irqrestore(&iadev->misc_lock, flags);
IF_EVENT(printk("iadev_count = %d\n", iadev_count);)
iadev->next_board = ia_boards;
diff --git a/drivers/atm/iphase.h b/drivers/atm/iphase.h
index b2cd20f..077735e 100644
--- a/drivers/atm/iphase.h
+++ b/drivers/atm/iphase.h
@@ -1022,7 +1022,7 @@
struct dle_q rx_dle_q;
struct free_desc_q *rx_free_desc_qhead;
struct sk_buff_head rx_dma_q;
- spinlock_t rx_lock, misc_lock;
+ spinlock_t rx_lock;
struct atm_vcc **rx_open; /* list of all open VCs */
u16 num_rx_desc, rx_buf_sz, rxing;
u32 rx_pkt_ram, rx_tmp_cnt;
diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index f916ddf..f46138a 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -444,6 +444,7 @@
struct atm_dev *atmdev = container_of(dev, struct atm_dev, class_dev);
struct solos_card *card = atmdev->dev_data;
struct sk_buff *skb;
+ unsigned int len;
spin_lock(&card->cli_queue_lock);
skb = skb_dequeue(&card->cli_queue[SOLOS_CHAN(atmdev)]);
@@ -451,11 +452,12 @@
if(skb == NULL)
return sprintf(buf, "No data.\n");
- memcpy(buf, skb->data, skb->len);
- dev_dbg(&card->dev->dev, "len: %d\n", skb->len);
+ len = skb->len;
+ memcpy(buf, skb->data, len);
+ dev_dbg(&card->dev->dev, "len: %d\n", len);
kfree_skb(skb);
- return skb->len;
+ return len;
}
static int send_command(struct solos_card *card, int dev, const char *buf, size_t size)
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 6124c2f..5e4fadc 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -4792,7 +4792,7 @@
clean4:
kfree(h->cmd_pool_bits);
/* Free up sg elements */
- for (k = 0; k < h->nr_cmds; k++)
+ for (k-- ; k >= 0; k--)
kfree(h->scatter_list[k]);
kfree(h->scatter_list);
cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds);
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index b1cbeb5..37a2bb5 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -2369,7 +2369,7 @@
pkt_shrink_pktlist(pd);
}
-static struct pktcdvd_device *pkt_find_dev_from_minor(int dev_minor)
+static struct pktcdvd_device *pkt_find_dev_from_minor(unsigned int dev_minor)
{
if (dev_minor >= MAX_WRITERS)
return NULL;
diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c
index e9da874..03688c2 100644
--- a/drivers/block/ps3disk.c
+++ b/drivers/block/ps3disk.c
@@ -113,7 +113,7 @@
memcpy(buf, dev->bounce_buf+offset, size);
offset += size;
flush_kernel_dcache_page(bvec->bv_page);
- bvec_kunmap_irq(bvec, &flags);
+ bvec_kunmap_irq(buf, &flags);
i++;
}
}
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 2aafafc..1101e25 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -202,6 +202,7 @@
struct virtio_blk *vblk = disk->private_data;
struct request *req;
struct bio *bio;
+ int err;
bio = bio_map_kern(vblk->disk->queue, id_str, VIRTIO_BLK_ID_BYTES,
GFP_KERNEL);
@@ -215,7 +216,10 @@
}
req->cmd_type = REQ_TYPE_SPECIAL;
- return blk_execute_rq(vblk->disk->queue, vblk->disk, req, false);
+ err = blk_execute_rq(vblk->disk->queue, vblk->disk, req, false);
+ blk_put_request(req);
+
+ return err;
}
static int virtblk_locked_ioctl(struct block_device *bdev, fmode_t mode,
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index eab58db..cd18493 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -806,6 +806,8 @@
"G45/G43", NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_B43_HB, PCI_DEVICE_ID_INTEL_B43_IG,
"B43", NULL, &intel_i965_driver },
+ { PCI_DEVICE_ID_INTEL_B43_1_HB, PCI_DEVICE_ID_INTEL_B43_1_IG,
+ "B43", NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_G41_HB, PCI_DEVICE_ID_INTEL_G41_IG,
"G41", NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG,
diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h
index ee189c7..d09b1ab 100644
--- a/drivers/char/agp/intel-agp.h
+++ b/drivers/char/agp/intel-agp.h
@@ -186,6 +186,8 @@
#define PCI_DEVICE_ID_INTEL_Q33_IG 0x29D2
#define PCI_DEVICE_ID_INTEL_B43_HB 0x2E40
#define PCI_DEVICE_ID_INTEL_B43_IG 0x2E42
+#define PCI_DEVICE_ID_INTEL_B43_1_HB 0x2E90
+#define PCI_DEVICE_ID_INTEL_B43_1_IG 0x2E92
#define PCI_DEVICE_ID_INTEL_GM45_HB 0x2A40
#define PCI_DEVICE_ID_INTEL_GM45_IG 0x2A42
#define PCI_DEVICE_ID_INTEL_EAGLELAKE_HB 0x2E00
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 3822b4f..7bd7c45 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -305,6 +305,9 @@
#ifdef CONFIG_PCI
static int pci_registered;
#endif
+#ifdef CONFIG_ACPI
+static int pnp_registered;
+#endif
#ifdef CONFIG_PPC_OF
static int of_registered;
#endif
@@ -2126,7 +2129,7 @@
{
struct acpi_device *acpi_dev;
struct smi_info *info;
- struct resource *res;
+ struct resource *res, *res_second;
acpi_handle handle;
acpi_status status;
unsigned long long tmp;
@@ -2182,13 +2185,13 @@
info->io.addr_data = res->start;
info->io.regspacing = DEFAULT_REGSPACING;
- res = pnp_get_resource(dev,
+ res_second = pnp_get_resource(dev,
(info->io.addr_type == IPMI_IO_ADDR_SPACE) ?
IORESOURCE_IO : IORESOURCE_MEM,
1);
- if (res) {
- if (res->start > info->io.addr_data)
- info->io.regspacing = res->start - info->io.addr_data;
+ if (res_second) {
+ if (res_second->start > info->io.addr_data)
+ info->io.regspacing = res_second->start - info->io.addr_data;
}
info->io.regsize = DEFAULT_REGSPACING;
info->io.regshift = 0;
@@ -3359,6 +3362,7 @@
#ifdef CONFIG_ACPI
pnp_register_driver(&ipmi_pnp_driver);
+ pnp_registered = 1;
#endif
#ifdef CONFIG_DMI
@@ -3526,7 +3530,8 @@
pci_unregister_driver(&ipmi_pci_driver);
#endif
#ifdef CONFIG_ACPI
- pnp_unregister_driver(&ipmi_pnp_driver);
+ if (pnp_registered)
+ pnp_unregister_driver(&ipmi_pnp_driver);
#endif
#ifdef CONFIG_PPC_OF
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index a398ecd..1f528fa 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -788,10 +788,11 @@
/*
* capabilities for /dev/zero
* - permits private mappings, "copies" are taken of the source of zeros
+ * - no writeback happens
*/
static struct backing_dev_info zero_bdi = {
.name = "char/mem",
- .capabilities = BDI_CAP_MAP_COPY,
+ .capabilities = BDI_CAP_MAP_COPY | BDI_CAP_NO_ACCT_AND_WRITEBACK,
};
static const struct file_operations full_fops = {
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 942a982..0f69c5e 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -459,9 +459,12 @@
/*
* Wait till the host acknowledges it pushed out the data we
- * sent. This is done for ports in blocking mode or for data
- * from the hvc_console; the tty operations are performed with
- * spinlocks held so we can't sleep here.
+ * sent. This is done for data from the hvc_console; the tty
+ * operations are performed with spinlocks held so we can't
+ * sleep here. An alternative would be to copy the data to a
+ * buffer and relax the spinning requirement. The downside is
+ * we need to kmalloc a GFP_ATOMIC buffer each time the
+ * console driver writes something out.
*/
while (!virtqueue_get_buf(out_vq, &len))
cpu_relax();
@@ -596,6 +599,10 @@
ssize_t ret;
bool nonblock;
+ /* Userspace could be out to fool us */
+ if (!count)
+ return 0;
+
port = filp->private_data;
nonblock = filp->f_flags & O_NONBLOCK;
@@ -622,6 +629,14 @@
goto free_buf;
}
+ /*
+ * We now ask send_buf() to not spin for generic ports -- we
+ * can re-use the same code path that non-blocking file
+ * descriptors take for blocking file descriptors since the
+ * wait is already done and we're certain the write will go
+ * through to the host.
+ */
+ nonblock = true;
ret = send_buf(port, buf, count, nonblock);
if (nonblock && ret > 0)
@@ -642,7 +657,7 @@
poll_wait(filp, &port->waitqueue, wait);
ret = 0;
- if (port->inbuf)
+ if (!will_read_block(port))
ret |= POLLIN | POLLRDNORM;
if (!will_write_block(port))
ret |= POLLOUT;
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index c2408bb..f508690 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -80,7 +80,7 @@
* Limiting Performance Impact
* ---------------------------
* C states, especially those with large exit latencies, can have a real
- * noticable impact on workloads, which is not acceptable for most sysadmins,
+ * noticeable impact on workloads, which is not acceptable for most sysadmins,
* and in addition, less performance has a power price of its own.
*
* As a general rule of thumb, menu assumes that the following heuristic
diff --git a/drivers/dca/dca-core.c b/drivers/dca/dca-core.c
index 8661c84..b98c676 100644
--- a/drivers/dca/dca-core.c
+++ b/drivers/dca/dca-core.c
@@ -39,6 +39,10 @@
static LIST_HEAD(dca_domains);
+static BLOCKING_NOTIFIER_HEAD(dca_provider_chain);
+
+static int dca_providers_blocked;
+
static struct pci_bus *dca_pci_rc_from_dev(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
@@ -70,6 +74,60 @@
kfree(domain);
}
+static int dca_provider_ioat_ver_3_0(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+
+ return ((pdev->vendor == PCI_VENDOR_ID_INTEL) &&
+ ((pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG0) ||
+ (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG1) ||
+ (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG2) ||
+ (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG3) ||
+ (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG4) ||
+ (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG5) ||
+ (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG6) ||
+ (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG7)));
+}
+
+static void unregister_dca_providers(void)
+{
+ struct dca_provider *dca, *_dca;
+ struct list_head unregistered_providers;
+ struct dca_domain *domain;
+ unsigned long flags;
+
+ blocking_notifier_call_chain(&dca_provider_chain,
+ DCA_PROVIDER_REMOVE, NULL);
+
+ INIT_LIST_HEAD(&unregistered_providers);
+
+ spin_lock_irqsave(&dca_lock, flags);
+
+ if (list_empty(&dca_domains)) {
+ spin_unlock_irqrestore(&dca_lock, flags);
+ return;
+ }
+
+ /* at this point only one domain in the list is expected */
+ domain = list_first_entry(&dca_domains, struct dca_domain, node);
+ if (!domain)
+ return;
+
+ list_for_each_entry_safe(dca, _dca, &domain->dca_providers, node) {
+ list_del(&dca->node);
+ list_add(&dca->node, &unregistered_providers);
+ }
+
+ dca_free_domain(domain);
+
+ spin_unlock_irqrestore(&dca_lock, flags);
+
+ list_for_each_entry_safe(dca, _dca, &unregistered_providers, node) {
+ dca_sysfs_remove_provider(dca);
+ list_del(&dca->node);
+ }
+}
+
static struct dca_domain *dca_find_domain(struct pci_bus *rc)
{
struct dca_domain *domain;
@@ -90,9 +148,13 @@
domain = dca_find_domain(rc);
if (!domain) {
- domain = dca_allocate_domain(rc);
- if (domain)
- list_add(&domain->node, &dca_domains);
+ if (dca_provider_ioat_ver_3_0(dev) && !list_empty(&dca_domains)) {
+ dca_providers_blocked = 1;
+ } else {
+ domain = dca_allocate_domain(rc);
+ if (domain)
+ list_add(&domain->node, &dca_domains);
+ }
}
return domain;
@@ -293,8 +355,6 @@
}
EXPORT_SYMBOL_GPL(free_dca_provider);
-static BLOCKING_NOTIFIER_HEAD(dca_provider_chain);
-
/**
* register_dca_provider - register a dca provider
* @dca - struct created by alloc_dca_provider()
@@ -306,6 +366,13 @@
unsigned long flags;
struct dca_domain *domain;
+ spin_lock_irqsave(&dca_lock, flags);
+ if (dca_providers_blocked) {
+ spin_unlock_irqrestore(&dca_lock, flags);
+ return -ENODEV;
+ }
+ spin_unlock_irqrestore(&dca_lock, flags);
+
err = dca_sysfs_add_provider(dca, dev);
if (err)
return err;
@@ -313,7 +380,13 @@
spin_lock_irqsave(&dca_lock, flags);
domain = dca_get_domain(dev);
if (!domain) {
- spin_unlock_irqrestore(&dca_lock, flags);
+ if (dca_providers_blocked) {
+ spin_unlock_irqrestore(&dca_lock, flags);
+ dca_sysfs_remove_provider(dca);
+ unregister_dca_providers();
+ } else {
+ spin_unlock_irqrestore(&dca_lock, flags);
+ }
return -ENODEV;
}
list_add(&dca->node, &domain->dca_providers);
diff --git a/drivers/dma/ioat/dma_v2.c b/drivers/dma/ioat/dma_v2.c
index 216f9d3..effd140 100644
--- a/drivers/dma/ioat/dma_v2.c
+++ b/drivers/dma/ioat/dma_v2.c
@@ -879,7 +879,7 @@
dma->device_issue_pending = ioat2_issue_pending;
dma->device_alloc_chan_resources = ioat2_alloc_chan_resources;
dma->device_free_chan_resources = ioat2_free_chan_resources;
- dma->device_tx_status = ioat_tx_status;
+ dma->device_tx_status = ioat_dma_tx_status;
err = ioat_probe(device);
if (err)
diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
index 86c5ae9..411d5bf 100644
--- a/drivers/dma/mv_xor.c
+++ b/drivers/dma/mv_xor.c
@@ -162,7 +162,7 @@
static void mv_xor_device_clear_eoc_cause(struct mv_xor_chan *chan)
{
- u32 val = (1 << (1 + (chan->idx * 16)));
+ u32 val = ~(1 << (chan->idx * 16));
dev_dbg(chan->device->common.dev, "%s, val 0x%08x\n", __func__, val);
__raw_writel(val, XOR_INTR_CAUSE(chan));
}
diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c
index fb64cf3..eb6b54d 100644
--- a/drivers/dma/shdma.c
+++ b/drivers/dma/shdma.c
@@ -580,7 +580,6 @@
sh_chan = to_sh_chan(chan);
param = chan->private;
- slave_addr = param->config->addr;
/* Someone calling slave DMA on a public channel? */
if (!param || !sg_len) {
@@ -589,6 +588,8 @@
return NULL;
}
+ slave_addr = param->config->addr;
+
/*
* if (param != NULL), this is a successfully requested slave channel,
* therefore param->config != NULL too.
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 3630308..6b21e25 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -339,6 +339,9 @@
{
int status;
+ if (mci->op_state != OP_RUNNING_POLL)
+ return;
+
status = cancel_delayed_work(&mci->work);
if (status == 0) {
debugf0("%s() not canceled, flush the queue\n",
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
index e0187d1..0fd5b85 100644
--- a/drivers/edac/i7core_edac.c
+++ b/drivers/edac/i7core_edac.c
@@ -1140,6 +1140,7 @@
ATTR_COUNTER(0),
ATTR_COUNTER(1),
ATTR_COUNTER(2),
+ { .attr = { .name = NULL } }
};
static struct mcidev_sysfs_group i7core_udimm_counters = {
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index be29b0b..9dcb17d 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -263,6 +263,7 @@
{PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_FW, QUIRK_NO_MSI},
{PCI_VENDOR_ID_NEC, PCI_ANY_ID, QUIRK_CYCLE_TIMER},
{PCI_VENDOR_ID_VIA, PCI_ANY_ID, QUIRK_CYCLE_TIMER},
+ {PCI_VENDOR_ID_RICOH, PCI_ANY_ID, QUIRK_CYCLE_TIMER},
{PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_FW, QUIRK_BE_HEADERS},
};
@@ -2839,7 +2840,7 @@
const struct pci_device_id *ent)
{
struct fw_ohci *ohci;
- u32 bus_options, max_receive, link_speed, version, link_enh;
+ u32 bus_options, max_receive, link_speed, version;
u64 guid;
int i, err, n_ir, n_it;
size_t size;
@@ -2893,23 +2894,6 @@
if (param_quirks)
ohci->quirks = param_quirks;
- /* TI OHCI-Lynx and compatible: set recommended configuration bits. */
- if (dev->vendor == PCI_VENDOR_ID_TI) {
- pci_read_config_dword(dev, PCI_CFG_TI_LinkEnh, &link_enh);
-
- /* adjust latency of ATx FIFO: use 1.7 KB threshold */
- link_enh &= ~TI_LinkEnh_atx_thresh_mask;
- link_enh |= TI_LinkEnh_atx_thresh_1_7K;
-
- /* use priority arbitration for asynchronous responses */
- link_enh |= TI_LinkEnh_enab_unfair;
-
- /* required for aPhyEnhanceEnable to work */
- link_enh |= TI_LinkEnh_enab_accel;
-
- pci_write_config_dword(dev, PCI_CFG_TI_LinkEnh, link_enh);
- }
-
ar_context_init(&ohci->ar_request_ctx, ohci,
OHCI1394_AsReqRcvContextControlSet);
diff --git a/drivers/firewire/ohci.h b/drivers/firewire/ohci.h
index 0e6c5a4..ef5e733 100644
--- a/drivers/firewire/ohci.h
+++ b/drivers/firewire/ohci.h
@@ -155,12 +155,4 @@
#define OHCI1394_phy_tcode 0xe
-/* TI extensions */
-
-#define PCI_CFG_TI_LinkEnh 0xf4
-#define TI_LinkEnh_enab_accel 0x00000002
-#define TI_LinkEnh_enab_unfair 0x00000080
-#define TI_LinkEnh_atx_thresh_mask 0x00003000
-#define TI_LinkEnh_atx_thresh_1_7K 0x00001000
-
#endif /* _FIREWIRE_OHCI_H */
diff --git a/drivers/gpu/drm/drm_buffer.c b/drivers/gpu/drm/drm_buffer.c
index 55d03ed..529a0db 100644
--- a/drivers/gpu/drm/drm_buffer.c
+++ b/drivers/gpu/drm/drm_buffer.c
@@ -98,8 +98,8 @@
* user_data: A pointer the data that is copied to the buffer.
* size: The Number of bytes to copy.
*/
-extern int drm_buffer_copy_from_user(struct drm_buffer *buf,
- void __user *user_data, int size)
+int drm_buffer_copy_from_user(struct drm_buffer *buf,
+ void __user *user_data, int size)
{
int nr_pages = size / PAGE_SIZE + 1;
int idx;
@@ -163,7 +163,7 @@
{
int idx = drm_buffer_index(buf);
int page = drm_buffer_page(buf);
- void *obj = 0;
+ void *obj = NULL;
if (idx + objsize <= PAGE_SIZE) {
obj = &buf->data[page][idx];
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index d2ab01e..dcbeb98 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -103,8 +103,8 @@
if (connector->funcs->force)
connector->funcs->force(connector);
} else {
- connector->status = connector->funcs->detect(connector);
- drm_helper_hpd_irq_event(dev);
+ connector->status = connector->funcs->detect(connector, true);
+ drm_kms_helper_poll_enable(dev);
}
if (connector->status == connector_status_disconnected) {
@@ -637,13 +637,13 @@
mode_changed = true;
if (mode_changed) {
- old_fb = set->crtc->fb;
- set->crtc->fb = set->fb;
set->crtc->enabled = (set->mode != NULL);
if (set->mode != NULL) {
DRM_DEBUG_KMS("attempting to set mode from"
" userspace\n");
drm_mode_debug_printmodeline(set->mode);
+ old_fb = set->crtc->fb;
+ set->crtc->fb = set->fb;
if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
set->x, set->y,
old_fb)) {
@@ -866,7 +866,7 @@
!(connector->polled & DRM_CONNECTOR_POLL_HPD))
continue;
- status = connector->funcs->detect(connector);
+ status = connector->funcs->detect(connector, false);
if (old_status != status)
changed = true;
}
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index bf92d07..5663d27 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -148,7 +148,7 @@
return -ENOMEM;
kref_init(&obj->refcount);
- kref_init(&obj->handlecount);
+ atomic_set(&obj->handle_count, 0);
obj->size = size;
atomic_inc(&dev->object_count);
@@ -462,28 +462,6 @@
}
EXPORT_SYMBOL(drm_gem_object_free);
-/**
- * Called after the last reference to the object has been lost.
- * Must be called without holding struct_mutex
- *
- * Frees the object
- */
-void
-drm_gem_object_free_unlocked(struct kref *kref)
-{
- struct drm_gem_object *obj = (struct drm_gem_object *) kref;
- struct drm_device *dev = obj->dev;
-
- if (dev->driver->gem_free_object_unlocked != NULL)
- dev->driver->gem_free_object_unlocked(obj);
- else if (dev->driver->gem_free_object != NULL) {
- mutex_lock(&dev->struct_mutex);
- dev->driver->gem_free_object(obj);
- mutex_unlock(&dev->struct_mutex);
- }
-}
-EXPORT_SYMBOL(drm_gem_object_free_unlocked);
-
static void drm_gem_object_ref_bug(struct kref *list_kref)
{
BUG();
@@ -496,12 +474,8 @@
* called before drm_gem_object_free or we'll be touching
* freed memory
*/
-void
-drm_gem_object_handle_free(struct kref *kref)
+void drm_gem_object_handle_free(struct drm_gem_object *obj)
{
- struct drm_gem_object *obj = container_of(kref,
- struct drm_gem_object,
- handlecount);
struct drm_device *dev = obj->dev;
/* Remove any name for this object */
@@ -528,6 +502,10 @@
struct drm_gem_object *obj = vma->vm_private_data;
drm_gem_object_reference(obj);
+
+ mutex_lock(&obj->dev->struct_mutex);
+ drm_vm_open_locked(vma);
+ mutex_unlock(&obj->dev->struct_mutex);
}
EXPORT_SYMBOL(drm_gem_vm_open);
@@ -535,7 +513,10 @@
{
struct drm_gem_object *obj = vma->vm_private_data;
- drm_gem_object_unreference_unlocked(obj);
+ mutex_lock(&obj->dev->struct_mutex);
+ drm_vm_close_locked(vma);
+ drm_gem_object_unreference(obj);
+ mutex_unlock(&obj->dev->struct_mutex);
}
EXPORT_SYMBOL(drm_gem_vm_close);
diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c
index 2ef2c78..974e970 100644
--- a/drivers/gpu/drm/drm_info.c
+++ b/drivers/gpu/drm/drm_info.c
@@ -255,7 +255,7 @@
seq_printf(m, "%6d %8zd %7d %8d\n",
obj->name, obj->size,
- atomic_read(&obj->handlecount.refcount),
+ atomic_read(&obj->handle_count),
atomic_read(&obj->refcount.refcount));
return 0;
}
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c
index e20f78b..f5bd9e5 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -164,6 +164,8 @@
dev->hose = pdev->sysdata;
#endif
+ mutex_lock(&drm_global_mutex);
+
if ((ret = drm_fill_in_dev(dev, ent, driver))) {
printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
goto err_g2;
@@ -199,6 +201,7 @@
driver->name, driver->major, driver->minor, driver->patchlevel,
driver->date, pci_name(pdev), dev->primary->index);
+ mutex_unlock(&drm_global_mutex);
return 0;
err_g4:
@@ -210,6 +213,7 @@
pci_disable_device(pdev);
err_g1:
kfree(dev);
+ mutex_unlock(&drm_global_mutex);
return ret;
}
EXPORT_SYMBOL(drm_get_pci_dev);
diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c
index 460e9a3..92d1d0f 100644
--- a/drivers/gpu/drm/drm_platform.c
+++ b/drivers/gpu/drm/drm_platform.c
@@ -53,6 +53,8 @@
dev->platformdev = platdev;
dev->dev = &platdev->dev;
+ mutex_lock(&drm_global_mutex);
+
ret = drm_fill_in_dev(dev, NULL, driver);
if (ret) {
@@ -87,6 +89,8 @@
list_add_tail(&dev->driver_item, &driver->device_list);
+ mutex_unlock(&drm_global_mutex);
+
DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
driver->name, driver->major, driver->minor, driver->patchlevel,
driver->date, dev->primary->index);
@@ -100,6 +104,7 @@
drm_put_minor(&dev->control);
err_g1:
kfree(dev);
+ mutex_unlock(&drm_global_mutex);
return ret;
}
EXPORT_SYMBOL(drm_get_platform_dev);
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
index 86118a7..85da4c4 100644
--- a/drivers/gpu/drm/drm_sysfs.c
+++ b/drivers/gpu/drm/drm_sysfs.c
@@ -159,7 +159,7 @@
struct drm_connector *connector = to_drm_connector(device);
enum drm_connector_status status;
- status = connector->funcs->detect(connector);
+ status = connector->funcs->detect(connector, true);
return snprintf(buf, PAGE_SIZE, "%s\n",
drm_get_connector_status_name(status));
}
diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c
index fda6746..5df4506 100644
--- a/drivers/gpu/drm/drm_vm.c
+++ b/drivers/gpu/drm/drm_vm.c
@@ -433,6 +433,25 @@
mutex_unlock(&dev->struct_mutex);
}
+void drm_vm_close_locked(struct vm_area_struct *vma)
+{
+ struct drm_file *priv = vma->vm_file->private_data;
+ struct drm_device *dev = priv->minor->dev;
+ struct drm_vma_entry *pt, *temp;
+
+ DRM_DEBUG("0x%08lx,0x%08lx\n",
+ vma->vm_start, vma->vm_end - vma->vm_start);
+ atomic_dec(&dev->vma_count);
+
+ list_for_each_entry_safe(pt, temp, &dev->vmalist, head) {
+ if (pt->vma == vma) {
+ list_del(&pt->head);
+ kfree(pt);
+ break;
+ }
+ }
+}
+
/**
* \c close method for all virtual memory types.
*
@@ -445,20 +464,9 @@
{
struct drm_file *priv = vma->vm_file->private_data;
struct drm_device *dev = priv->minor->dev;
- struct drm_vma_entry *pt, *temp;
-
- DRM_DEBUG("0x%08lx,0x%08lx\n",
- vma->vm_start, vma->vm_end - vma->vm_start);
- atomic_dec(&dev->vma_count);
mutex_lock(&dev->struct_mutex);
- list_for_each_entry_safe(pt, temp, &dev->vmalist, head) {
- if (pt->vma == vma) {
- list_del(&pt->head);
- kfree(pt);
- break;
- }
- }
+ drm_vm_close_locked(vma);
mutex_unlock(&dev->struct_mutex);
}
diff --git a/drivers/gpu/drm/i810/i810_dma.c b/drivers/gpu/drm/i810/i810_dma.c
index 61b4caf..fb07e73 100644
--- a/drivers/gpu/drm/i810/i810_dma.c
+++ b/drivers/gpu/drm/i810/i810_dma.c
@@ -116,7 +116,7 @@
static const struct file_operations i810_buffer_fops = {
.open = drm_open,
.release = drm_release,
- .unlocked_ioctl = drm_ioctl,
+ .unlocked_ioctl = i810_ioctl,
.mmap = i810_mmap_buffers,
.fasync = drm_fasync,
};
diff --git a/drivers/gpu/drm/i830/i830_dma.c b/drivers/gpu/drm/i830/i830_dma.c
index 671aa18..cc92c7e 100644
--- a/drivers/gpu/drm/i830/i830_dma.c
+++ b/drivers/gpu/drm/i830/i830_dma.c
@@ -118,7 +118,7 @@
static const struct file_operations i830_buffer_fops = {
.open = drm_open,
.release = drm_release,
- .unlocked_ioctl = drm_ioctl,
+ .unlocked_ioctl = i830_ioctl,
.mmap = i830_mmap_buffers,
.fasync = drm_fasync,
};
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 9d67b48..2dd2c93 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1787,9 +1787,9 @@
}
}
- div_u64(diff, diff1);
+ diff = div_u64(diff, diff1);
ret = ((m * diff) + c);
- div_u64(ret, 10);
+ ret = div_u64(ret, 10);
dev_priv->last_count1 = total_count;
dev_priv->last_time1 = now;
@@ -1858,7 +1858,7 @@
/* More magic constants... */
diff = diff * 1181;
- div_u64(diff, diffms * 10);
+ diff = div_u64(diff, diffms * 10);
dev_priv->gfx_power = diff;
}
@@ -2231,6 +2231,9 @@
dev_priv->mchdev_lock = &mchdev_lock;
spin_unlock(&mchdev_lock);
+ /* XXX Prevent module unload due to memory corruption bugs. */
+ __module_get(THIS_MODULE);
+
return 0;
out_workqueue_free:
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 216deb5..6dbe14c 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -170,6 +170,7 @@
INTEL_VGA_DEVICE(0x2e22, &intel_g45_info), /* G45_G */
INTEL_VGA_DEVICE(0x2e32, &intel_g45_info), /* G41_G */
INTEL_VGA_DEVICE(0x2e42, &intel_g45_info), /* B43_G */
+ INTEL_VGA_DEVICE(0x2e92, &intel_g45_info), /* B43_G.1 */
INTEL_VGA_DEVICE(0xa001, &intel_pineview_info),
INTEL_VGA_DEVICE(0xa011, &intel_pineview_info),
INTEL_VGA_DEVICE(0x0042, &intel_ironlake_d_info),
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 16fca1d..90b1d67 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -136,14 +136,12 @@
return -ENOMEM;
ret = drm_gem_handle_create(file_priv, obj, &handle);
+ /* drop reference from allocate - handle holds it now */
+ drm_gem_object_unreference_unlocked(obj);
if (ret) {
- drm_gem_object_unreference_unlocked(obj);
return ret;
}
- /* Sink the floating reference from kref_init(handlecount) */
- drm_gem_object_handle_unreference_unlocked(obj);
-
args->handle = handle;
return 0;
}
@@ -471,14 +469,17 @@
return -ENOENT;
obj_priv = to_intel_bo(obj);
- /* Bounds check source.
- *
- * XXX: This could use review for overflow issues...
- */
- if (args->offset > obj->size || args->size > obj->size ||
- args->offset + args->size > obj->size) {
- drm_gem_object_unreference_unlocked(obj);
- return -EINVAL;
+ /* Bounds check source. */
+ if (args->offset > obj->size || args->size > obj->size - args->offset) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (!access_ok(VERIFY_WRITE,
+ (char __user *)(uintptr_t)args->data_ptr,
+ args->size)) {
+ ret = -EFAULT;
+ goto err;
}
if (i915_gem_object_needs_bit17_swizzle(obj)) {
@@ -490,8 +491,8 @@
file_priv);
}
+err:
drm_gem_object_unreference_unlocked(obj);
-
return ret;
}
@@ -580,8 +581,6 @@
user_data = (char __user *) (uintptr_t) args->data_ptr;
remain = args->size;
- if (!access_ok(VERIFY_READ, user_data, remain))
- return -EFAULT;
mutex_lock(&dev->struct_mutex);
@@ -934,14 +933,17 @@
return -ENOENT;
obj_priv = to_intel_bo(obj);
- /* Bounds check destination.
- *
- * XXX: This could use review for overflow issues...
- */
- if (args->offset > obj->size || args->size > obj->size ||
- args->offset + args->size > obj->size) {
- drm_gem_object_unreference_unlocked(obj);
- return -EINVAL;
+ /* Bounds check destination. */
+ if (args->offset > obj->size || args->size > obj->size - args->offset) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (!access_ok(VERIFY_READ,
+ (char __user *)(uintptr_t)args->data_ptr,
+ args->size)) {
+ ret = -EFAULT;
+ goto err;
}
/* We can only do the GTT pwrite on untiled buffers, as otherwise
@@ -975,8 +977,8 @@
DRM_INFO("pwrite failed %d\n", ret);
#endif
+err:
drm_gem_object_unreference_unlocked(obj);
-
return ret;
}
@@ -2351,14 +2353,21 @@
reg->obj = obj;
- if (IS_GEN6(dev))
+ switch (INTEL_INFO(dev)->gen) {
+ case 6:
sandybridge_write_fence_reg(reg);
- else if (IS_I965G(dev))
+ break;
+ case 5:
+ case 4:
i965_write_fence_reg(reg);
- else if (IS_I9XX(dev))
+ break;
+ case 3:
i915_write_fence_reg(reg);
- else
+ break;
+ case 2:
i830_write_fence_reg(reg);
+ break;
+ }
trace_i915_gem_object_get_fence(obj, obj_priv->fence_reg,
obj_priv->tiling_mode);
@@ -2381,22 +2390,26 @@
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
struct drm_i915_fence_reg *reg =
&dev_priv->fence_regs[obj_priv->fence_reg];
+ uint32_t fence_reg;
- if (IS_GEN6(dev)) {
+ switch (INTEL_INFO(dev)->gen) {
+ case 6:
I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 +
(obj_priv->fence_reg * 8), 0);
- } else if (IS_I965G(dev)) {
+ break;
+ case 5:
+ case 4:
I915_WRITE64(FENCE_REG_965_0 + (obj_priv->fence_reg * 8), 0);
- } else {
- uint32_t fence_reg;
-
- if (obj_priv->fence_reg < 8)
- fence_reg = FENCE_REG_830_0 + obj_priv->fence_reg * 4;
+ break;
+ case 3:
+ if (obj_priv->fence_reg >= 8)
+ fence_reg = FENCE_REG_945_8 + (obj_priv->fence_reg - 8) * 4;
else
- fence_reg = FENCE_REG_945_8 + (obj_priv->fence_reg -
- 8) * 4;
+ case 2:
+ fence_reg = FENCE_REG_830_0 + obj_priv->fence_reg * 4;
I915_WRITE(fence_reg, 0);
+ break;
}
reg->obj = NULL;
@@ -3247,6 +3260,8 @@
(int) reloc->offset,
reloc->read_domains,
reloc->write_domain);
+ drm_gem_object_unreference(target_obj);
+ i915_gem_object_unpin(obj);
return -EINVAL;
}
if (reloc->write_domain & I915_GEM_DOMAIN_CPU ||
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c
index 72cae3c..5c428fa 100644
--- a/drivers/gpu/drm/i915/i915_gem_evict.c
+++ b/drivers/gpu/drm/i915/i915_gem_evict.c
@@ -79,6 +79,7 @@
struct list_head *unwind)
{
list_add(&obj_priv->evict_list, unwind);
+ drm_gem_object_reference(&obj_priv->base);
return drm_mm_scan_add_block(obj_priv->gtt_space);
}
@@ -92,7 +93,7 @@
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct list_head eviction_list, unwind_list;
- struct drm_i915_gem_object *obj_priv, *tmp_obj_priv;
+ struct drm_i915_gem_object *obj_priv;
struct list_head *render_iter, *bsd_iter;
int ret = 0;
@@ -165,6 +166,7 @@
list_for_each_entry(obj_priv, &unwind_list, evict_list) {
ret = drm_mm_scan_remove_block(obj_priv->gtt_space);
BUG_ON(ret);
+ drm_gem_object_unreference(&obj_priv->base);
}
/* We expect the caller to unpin, evict all and try again, or give up.
@@ -173,36 +175,34 @@
return -ENOSPC;
found:
+ /* drm_mm doesn't allow any other other operations while
+ * scanning, therefore store to be evicted objects on a
+ * temporary list. */
INIT_LIST_HEAD(&eviction_list);
- list_for_each_entry_safe(obj_priv, tmp_obj_priv,
- &unwind_list, evict_list) {
+ while (!list_empty(&unwind_list)) {
+ obj_priv = list_first_entry(&unwind_list,
+ struct drm_i915_gem_object,
+ evict_list);
if (drm_mm_scan_remove_block(obj_priv->gtt_space)) {
- /* drm_mm doesn't allow any other other operations while
- * scanning, therefore store to be evicted objects on a
- * temporary list. */
list_move(&obj_priv->evict_list, &eviction_list);
+ continue;
}
+ list_del(&obj_priv->evict_list);
+ drm_gem_object_unreference(&obj_priv->base);
}
/* Unbinding will emit any required flushes */
- list_for_each_entry_safe(obj_priv, tmp_obj_priv,
- &eviction_list, evict_list) {
-#if WATCH_LRU
- DRM_INFO("%s: evicting %p\n", __func__, obj);
-#endif
- ret = i915_gem_object_unbind(&obj_priv->base);
- if (ret)
- return ret;
+ while (!list_empty(&eviction_list)) {
+ obj_priv = list_first_entry(&eviction_list,
+ struct drm_i915_gem_object,
+ evict_list);
+ if (ret == 0)
+ ret = i915_gem_object_unbind(&obj_priv->base);
+ list_del(&obj_priv->evict_list);
+ drm_gem_object_unreference(&obj_priv->base);
}
- /* The just created free hole should be on the top of the free stack
- * maintained by drm_mm, so this BUG_ON actually executes in O(1).
- * Furthermore all accessed data has just recently been used, so it
- * should be really fast, too. */
- BUG_ON(!drm_mm_search_free(&dev_priv->mm.gtt_space, min_size,
- alignment, 0));
-
- return 0;
+ return ret;
}
int
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index 2c6b98f..31f0858 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -789,16 +789,25 @@
dev_priv->saveSWF2[i] = I915_READ(SWF30 + (i << 2));
/* Fences */
- if (IS_I965G(dev)) {
+ switch (INTEL_INFO(dev)->gen) {
+ case 6:
+ for (i = 0; i < 16; i++)
+ dev_priv->saveFENCE[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8));
+ break;
+ case 5:
+ case 4:
for (i = 0; i < 16; i++)
dev_priv->saveFENCE[i] = I915_READ64(FENCE_REG_965_0 + (i * 8));
- } else {
- for (i = 0; i < 8; i++)
- dev_priv->saveFENCE[i] = I915_READ(FENCE_REG_830_0 + (i * 4));
-
+ break;
+ case 3:
if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
for (i = 0; i < 8; i++)
dev_priv->saveFENCE[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4));
+ case 2:
+ for (i = 0; i < 8; i++)
+ dev_priv->saveFENCE[i] = I915_READ(FENCE_REG_830_0 + (i * 4));
+ break;
+
}
return 0;
@@ -815,15 +824,24 @@
I915_WRITE(HWS_PGA, dev_priv->saveHWS);
/* Fences */
- if (IS_I965G(dev)) {
+ switch (INTEL_INFO(dev)->gen) {
+ case 6:
+ for (i = 0; i < 16; i++)
+ I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), dev_priv->saveFENCE[i]);
+ break;
+ case 5:
+ case 4:
for (i = 0; i < 16; i++)
I915_WRITE64(FENCE_REG_965_0 + (i * 8), dev_priv->saveFENCE[i]);
- } else {
- for (i = 0; i < 8; i++)
- I915_WRITE(FENCE_REG_830_0 + (i * 4), dev_priv->saveFENCE[i]);
+ break;
+ case 3:
+ case 2:
if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
for (i = 0; i < 8; i++)
I915_WRITE(FENCE_REG_945_8 + (i * 4), dev_priv->saveFENCE[i+8]);
+ for (i = 0; i < 8; i++)
+ I915_WRITE(FENCE_REG_830_0 + (i * 4), dev_priv->saveFENCE[i]);
+ break;
}
i915_restore_display(dev);
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 4b77351..197d4f3 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -188,7 +188,7 @@
if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
1000, 1))
- DRM_ERROR("timed out waiting for FORCE_TRIGGER");
+ DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");
if (turn_off_dac) {
I915_WRITE(PCH_ADPA, temp);
@@ -245,7 +245,7 @@
if (wait_for((I915_READ(PORT_HOTPLUG_EN) &
CRT_HOTPLUG_FORCE_DETECT) == 0,
1000, 1))
- DRM_ERROR("timed out waiting for FORCE_DETECT to go off");
+ DRM_DEBUG_KMS("timed out waiting for FORCE_DETECT to go off");
}
stat = I915_READ(PORT_HOTPLUG_STAT);
@@ -400,7 +400,8 @@
return status;
}
-static enum drm_connector_status intel_crt_detect(struct drm_connector *connector)
+static enum drm_connector_status
+intel_crt_detect(struct drm_connector *connector, bool force)
{
struct drm_device *dev = connector->dev;
struct drm_encoder *encoder = intel_attached_encoder(connector);
@@ -419,6 +420,9 @@
if (intel_crt_detect_ddc(encoder))
return connector_status_connected;
+ if (!force)
+ return connector->status;
+
/* for pre-945g platforms use load detect */
if (encoder->crtc && encoder->crtc->enabled) {
status = intel_crt_load_detect(encoder->crtc, intel_encoder);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 19daead..9792285 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1013,8 +1013,8 @@
DRM_DEBUG_KMS("vblank wait timed out\n");
}
-/**
- * intel_wait_for_vblank_off - wait for vblank after disabling a pipe
+/*
+ * intel_wait_for_pipe_off - wait for pipe to turn off
* @dev: drm device
* @pipe: pipe to wait for
*
@@ -1022,25 +1022,39 @@
* spinning on the vblank interrupt status bit, since we won't actually
* see an interrupt when the pipe is disabled.
*
- * So this function waits for the display line value to settle (it
- * usually ends up stopping at the start of the next frame).
+ * On Gen4 and above:
+ * wait for the pipe register state bit to turn off
+ *
+ * Otherwise:
+ * wait for the display line value to settle (it usually
+ * ends up stopping at the start of the next frame).
+ *
*/
-void intel_wait_for_vblank_off(struct drm_device *dev, int pipe)
+static void intel_wait_for_pipe_off(struct drm_device *dev, int pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- int pipedsl_reg = (pipe == 0 ? PIPEADSL : PIPEBDSL);
- unsigned long timeout = jiffies + msecs_to_jiffies(100);
- u32 last_line;
- /* Wait for the display line to settle */
- do {
- last_line = I915_READ(pipedsl_reg) & DSL_LINEMASK;
- mdelay(5);
- } while (((I915_READ(pipedsl_reg) & DSL_LINEMASK) != last_line) &&
- time_after(timeout, jiffies));
+ if (INTEL_INFO(dev)->gen >= 4) {
+ int pipeconf_reg = (pipe == 0 ? PIPEACONF : PIPEBCONF);
- if (time_after(jiffies, timeout))
- DRM_DEBUG_KMS("vblank wait timed out\n");
+ /* Wait for the Pipe State to go off */
+ if (wait_for((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) == 0,
+ 100, 0))
+ DRM_DEBUG_KMS("pipe_off wait timed out\n");
+ } else {
+ u32 last_line;
+ int pipedsl_reg = (pipe == 0 ? PIPEADSL : PIPEBDSL);
+ unsigned long timeout = jiffies + msecs_to_jiffies(100);
+
+ /* Wait for the display line to settle */
+ do {
+ last_line = I915_READ(pipedsl_reg) & DSL_LINEMASK;
+ mdelay(5);
+ } while (((I915_READ(pipedsl_reg) & DSL_LINEMASK) != last_line) &&
+ time_after(timeout, jiffies));
+ if (time_after(jiffies, timeout))
+ DRM_DEBUG_KMS("pipe_off wait timed out\n");
+ }
}
/* Parameters have changed, update FBC info */
@@ -2328,13 +2342,13 @@
I915_READ(dspbase_reg);
}
- /* Wait for vblank for the disable to take effect */
- intel_wait_for_vblank_off(dev, pipe);
-
/* Don't disable pipe A or pipe A PLLs if needed */
if (pipeconf_reg == PIPEACONF &&
- (dev_priv->quirks & QUIRK_PIPEA_FORCE))
+ (dev_priv->quirks & QUIRK_PIPEA_FORCE)) {
+ /* Wait for vblank for the disable to take effect */
+ intel_wait_for_vblank(dev, pipe);
goto skip_pipe_off;
+ }
/* Next, disable display pipes */
temp = I915_READ(pipeconf_reg);
@@ -2343,8 +2357,8 @@
I915_READ(pipeconf_reg);
}
- /* Wait for vblank for the disable to take effect. */
- intel_wait_for_vblank_off(dev, pipe);
+ /* Wait for the pipe to turn off */
+ intel_wait_for_pipe_off(dev, pipe);
temp = I915_READ(dpll_reg);
if ((temp & DPLL_VCO_ENABLE) != 0) {
@@ -2463,11 +2477,19 @@
struct drm_display_mode *adjusted_mode)
{
struct drm_device *dev = crtc->dev;
+
if (HAS_PCH_SPLIT(dev)) {
/* FDI link clock is fixed at 2.7G */
if (mode->clock * 3 > IRONLAKE_FDI_FREQ * 4)
return false;
}
+
+ /* XXX some encoders set the crtcinfo, others don't.
+ * Obviously we need some form of conflict resolution here...
+ */
+ if (adjusted_mode->crtc_htotal == 0)
+ drm_mode_set_crtcinfo(adjusted_mode, 0);
+
return true;
}
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 51d1429..9ab8708 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1138,18 +1138,14 @@
intel_dp_set_link_train(struct intel_dp *intel_dp,
uint32_t dp_reg_value,
uint8_t dp_train_pat,
- uint8_t train_set[4],
- bool first)
+ uint8_t train_set[4])
{
struct drm_device *dev = intel_dp->base.enc.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.enc.crtc);
int ret;
I915_WRITE(intel_dp->output_reg, dp_reg_value);
POSTING_READ(intel_dp->output_reg);
- if (first)
- intel_wait_for_vblank(dev, intel_crtc->pipe);
intel_dp_aux_native_write_1(intel_dp,
DP_TRAINING_PATTERN_SET,
@@ -1174,10 +1170,15 @@
uint8_t voltage;
bool clock_recovery = false;
bool channel_eq = false;
- bool first = true;
int tries;
u32 reg;
uint32_t DP = intel_dp->DP;
+ struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.enc.crtc);
+
+ /* Enable output, wait for it to become active */
+ I915_WRITE(intel_dp->output_reg, intel_dp->DP);
+ POSTING_READ(intel_dp->output_reg);
+ intel_wait_for_vblank(dev, intel_crtc->pipe);
/* Write the link configuration data */
intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET,
@@ -1210,9 +1211,8 @@
reg = DP | DP_LINK_TRAIN_PAT_1;
if (!intel_dp_set_link_train(intel_dp, reg,
- DP_TRAINING_PATTERN_1, train_set, first))
+ DP_TRAINING_PATTERN_1, train_set))
break;
- first = false;
/* Set training pattern 1 */
udelay(100);
@@ -1266,8 +1266,7 @@
/* channel eq pattern */
if (!intel_dp_set_link_train(intel_dp, reg,
- DP_TRAINING_PATTERN_2, train_set,
- false))
+ DP_TRAINING_PATTERN_2, train_set))
break;
udelay(400);
@@ -1386,7 +1385,7 @@
* \return false if DP port is disconnected.
*/
static enum drm_connector_status
-intel_dp_detect(struct drm_connector *connector)
+intel_dp_detect(struct drm_connector *connector, bool force)
{
struct drm_encoder *encoder = intel_attached_encoder(connector);
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index ad312ca..8828b3a 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -229,7 +229,6 @@
struct drm_crtc *crtc);
int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
struct drm_file *file_priv);
-extern void intel_wait_for_vblank_off(struct drm_device *dev, int pipe);
extern void intel_wait_for_vblank(struct drm_device *dev, int pipe);
extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe);
extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
index a399f4b..7c9ec14 100644
--- a/drivers/gpu/drm/i915/intel_dvo.c
+++ b/drivers/gpu/drm/i915/intel_dvo.c
@@ -221,7 +221,8 @@
*
* Unimplemented.
*/
-static enum drm_connector_status intel_dvo_detect(struct drm_connector *connector)
+static enum drm_connector_status
+intel_dvo_detect(struct drm_connector *connector, bool force)
{
struct drm_encoder *encoder = intel_attached_encoder(connector);
struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 7bdc962..b61966c 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -237,8 +237,10 @@
drm_fb_helper_fini(&ifbdev->helper);
drm_framebuffer_cleanup(&ifb->base);
- if (ifb->obj)
+ if (ifb->obj) {
drm_gem_object_unreference(ifb->obj);
+ ifb->obj = NULL;
+ }
return 0;
}
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index ccd4c97..926934a 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -139,7 +139,7 @@
}
static enum drm_connector_status
-intel_hdmi_detect(struct drm_connector *connector)
+intel_hdmi_detect(struct drm_connector *connector, bool force)
{
struct drm_encoder *encoder = intel_attached_encoder(connector);
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 4fbb016..6ec39a8 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -445,7 +445,8 @@
* connected and closed means disconnected. We also send hotplug events as
* needed, using lid status notification from the input layer.
*/
-static enum drm_connector_status intel_lvds_detect(struct drm_connector *connector)
+static enum drm_connector_status
+intel_lvds_detect(struct drm_connector *connector, bool force)
{
struct drm_device *dev = connector->dev;
enum drm_connector_status status = connector_status_connected;
@@ -540,7 +541,9 @@
* the LID nofication event.
*/
if (connector)
- connector->status = connector->funcs->detect(connector);
+ connector->status = connector->funcs->detect(connector,
+ false);
+
/* Don't force modeset on machines where it causes a GPU lockup */
if (dmi_check_system(intel_no_modeset_on_lid))
return NOTIFY_OK;
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index e3b7a7e..ee73e42 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -1417,7 +1417,7 @@
if (!analog_connector)
return false;
- if (analog_connector->funcs->detect(analog_connector) ==
+ if (analog_connector->funcs->detect(analog_connector, false) ==
connector_status_disconnected)
return false;
@@ -1486,7 +1486,8 @@
return status;
}
-static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector)
+static enum drm_connector_status
+intel_sdvo_detect(struct drm_connector *connector, bool force)
{
uint16_t response;
struct drm_encoder *encoder = intel_attached_encoder(connector);
@@ -2169,8 +2170,7 @@
return true;
err:
- intel_sdvo_destroy_enhance_property(connector);
- kfree(intel_sdvo_connector);
+ intel_sdvo_destroy(connector);
return false;
}
@@ -2242,8 +2242,7 @@
return true;
err:
- intel_sdvo_destroy_enhance_property(connector);
- kfree(intel_sdvo_connector);
+ intel_sdvo_destroy(connector);
return false;
}
@@ -2521,11 +2520,10 @@
uint16_t response;
} enhancements;
- if (!intel_sdvo_get_value(intel_sdvo,
- SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS,
- &enhancements, sizeof(enhancements)))
- return false;
-
+ enhancements.response = 0;
+ intel_sdvo_get_value(intel_sdvo,
+ SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS,
+ &enhancements, sizeof(enhancements));
if (enhancements.response == 0) {
DRM_DEBUG_KMS("No enhancement is supported\n");
return true;
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index c671f60..4a117e3 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1341,7 +1341,7 @@
* we have a pipe programmed in order to probe the TV.
*/
static enum drm_connector_status
-intel_tv_detect(struct drm_connector *connector)
+intel_tv_detect(struct drm_connector *connector, bool force)
{
struct drm_display_mode mode;
struct drm_encoder *encoder = intel_attached_encoder(connector);
@@ -1353,7 +1353,7 @@
if (encoder->crtc && encoder->crtc->enabled) {
type = intel_tv_detect_type(intel_tv);
- } else {
+ } else if (force) {
struct drm_crtc *crtc;
int dpms_mode;
@@ -1364,10 +1364,9 @@
intel_release_load_detect_pipe(&intel_tv->base, connector,
dpms_mode);
} else
- type = -1;
- }
-
- intel_tv->type = type;
+ return connector_status_unknown;
+ } else
+ return connector->status;
if (type < 0)
return connector_status_disconnected;
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index a1473ff..fc73703 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -168,7 +168,7 @@
}
static enum drm_connector_status
-nouveau_connector_detect(struct drm_connector *connector)
+nouveau_connector_detect(struct drm_connector *connector, bool force)
{
struct drm_device *dev = connector->dev;
struct nouveau_connector *nv_connector = nouveau_connector(connector);
@@ -246,7 +246,7 @@
}
static enum drm_connector_status
-nouveau_connector_detect_lvds(struct drm_connector *connector)
+nouveau_connector_detect_lvds(struct drm_connector *connector, bool force)
{
struct drm_device *dev = connector->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -267,7 +267,7 @@
/* Try retrieving EDID via DDC */
if (!dev_priv->vbios.fp_no_ddc) {
- status = nouveau_connector_detect(connector);
+ status = nouveau_connector_detect(connector, force);
if (status == connector_status_connected)
goto out;
}
@@ -558,8 +558,10 @@
if (nv_encoder->dcb->type == OUTPUT_LVDS &&
(nv_encoder->dcb->lvdsconf.use_straps_for_mode ||
dev_priv->vbios.fp_no_ddc) && nouveau_bios_fp_mode(dev, NULL)) {
- nv_connector->native_mode = drm_mode_create(dev);
- nouveau_bios_fp_mode(dev, nv_connector->native_mode);
+ struct drm_display_mode mode;
+
+ nouveau_bios_fp_mode(dev, &mode);
+ nv_connector->native_mode = drm_mode_duplicate(dev, &mode);
}
/* Find the native mode if this is a digital panel, if we didn't
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index ead7b8f..19620a6 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -167,11 +167,9 @@
goto out;
ret = drm_gem_handle_create(file_priv, nvbo->gem, &req->info.handle);
+ /* drop reference from allocate - handle holds it now */
+ drm_gem_object_unreference_unlocked(nvbo->gem);
out:
- drm_gem_object_handle_unreference_unlocked(nvbo->gem);
-
- if (ret)
- drm_gem_object_unreference_unlocked(nvbo->gem);
return ret;
}
diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h
index 1bc72c3..fe359a2 100644
--- a/drivers/gpu/drm/radeon/atombios.h
+++ b/drivers/gpu/drm/radeon/atombios.h
@@ -4999,7 +4999,7 @@
#define SW_I2C_CNTL_WRITE1BIT 6
//==============================VESA definition Portion===============================
-#define VESA_OEM_PRODUCT_REV '01.00'
+#define VESA_OEM_PRODUCT_REV "01.00"
#define VESA_MODE_ATTRIBUTE_MODE_SUPPORT 0xBB //refer to VBE spec p.32, no TTY support
#define VESA_MODE_WIN_ATTRIBUTE 7
#define VESA_WIN_SIZE 64
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 464a81a..cd0290f 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -539,14 +539,15 @@
pll->algo = PLL_ALGO_LEGACY;
pll->flags |= RADEON_PLL_PREFER_CLOSEST_LOWER;
}
- /* There is some evidence (often anecdotal) that RV515 LVDS
+ /* There is some evidence (often anecdotal) that RV515/RV620 LVDS
* (on some boards at least) prefers the legacy algo. I'm not
* sure whether this should handled generically or on a
* case-by-case quirk basis. Both algos should work fine in the
* majority of cases.
*/
if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) &&
- (rdev->family == CHIP_RV515)) {
+ ((rdev->family == CHIP_RV515) ||
+ (rdev->family == CHIP_RV620))) {
/* allow the user to overrride just in case */
if (radeon_new_pll == 1)
pll->algo = PLL_ALGO_NEW;
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index b8b7f01..2f93d46 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -1137,7 +1137,7 @@
WREG32(RCU_IND_INDEX, 0x203);
efuse_straps_3 = RREG32(RCU_IND_DATA);
- efuse_box_bit_127_124 = (u8)(efuse_straps_3 & 0xF0000000) >> 28;
+ efuse_box_bit_127_124 = (u8)((efuse_straps_3 & 0xF0000000) >> 28);
switch(efuse_box_bit_127_124) {
case 0x0:
@@ -1160,14 +1160,25 @@
EVERGREEN_MAX_BACKENDS_MASK));
break;
}
- } else
- gb_backend_map =
- evergreen_get_tile_pipe_to_backend_map(rdev,
- rdev->config.evergreen.max_tile_pipes,
- rdev->config.evergreen.max_backends,
- ((EVERGREEN_MAX_BACKENDS_MASK <<
- rdev->config.evergreen.max_backends) &
- EVERGREEN_MAX_BACKENDS_MASK));
+ } else {
+ switch (rdev->family) {
+ case CHIP_CYPRESS:
+ case CHIP_HEMLOCK:
+ gb_backend_map = 0x66442200;
+ break;
+ case CHIP_JUNIPER:
+ gb_backend_map = 0x00006420;
+ break;
+ default:
+ gb_backend_map =
+ evergreen_get_tile_pipe_to_backend_map(rdev,
+ rdev->config.evergreen.max_tile_pipes,
+ rdev->config.evergreen.max_backends,
+ ((EVERGREEN_MAX_BACKENDS_MASK <<
+ rdev->config.evergreen.max_backends) &
+ EVERGREEN_MAX_BACKENDS_MASK));
+ }
+ }
rdev->config.evergreen.tile_config = gb_addr_config;
WREG32(GB_BACKEND_MAP, gb_backend_map);
@@ -1396,6 +1407,7 @@
rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
rdev->mc.visible_vram_size = rdev->mc.aper_size;
+ rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
r600_vram_gtt_location(rdev, &rdev->mc);
radeon_update_bandwidth_info(rdev);
@@ -1509,7 +1521,7 @@
{
u32 tmp;
- WREG32(CP_INT_CNTL, 0);
+ WREG32(CP_INT_CNTL, CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
WREG32(GRBM_INT_CNTL, 0);
WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index e817a0b..e594223 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -1030,6 +1030,7 @@
return r;
}
rdev->cp.ready = true;
+ rdev->mc.active_vram_size = rdev->mc.real_vram_size;
return 0;
}
@@ -1047,6 +1048,7 @@
void r100_cp_disable(struct radeon_device *rdev)
{
/* Disable ring */
+ rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
rdev->cp.ready = false;
WREG32(RADEON_CP_CSQ_MODE, 0);
WREG32(RADEON_CP_CSQ_CNTL, 0);
@@ -2020,18 +2022,7 @@
return false;
}
elapsed = jiffies_to_msecs(cjiffies - lockup->last_jiffies);
- if (elapsed >= 3000) {
- /* very likely the improbable case where current
- * rptr is equal to last recorded, a while ago, rptr
- * this is more likely a false positive update tracking
- * information which should force us to be recall at
- * latter point
- */
- lockup->last_cp_rptr = cp->rptr;
- lockup->last_jiffies = jiffies;
- return false;
- }
- if (elapsed >= 1000) {
+ if (elapsed >= 10000) {
dev_err(rdev->dev, "GPU lockup CP stall for more than %lumsec\n", elapsed);
return true;
}
@@ -2306,6 +2297,7 @@
/* FIXME we don't use the second aperture yet when we could use it */
if (rdev->mc.visible_vram_size > rdev->mc.aper_size)
rdev->mc.visible_vram_size = rdev->mc.aper_size;
+ rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
config_aper_size = RREG32(RADEON_CONFIG_APER_SIZE);
if (rdev->flags & RADEON_IS_IGP) {
uint32_t tom;
@@ -3308,13 +3300,14 @@
unsigned long size;
unsigned prim_walk;
unsigned nverts;
+ unsigned num_cb = track->num_cb;
- for (i = 0; i < track->num_cb; i++) {
+ if (!track->zb_cb_clear && !track->color_channel_mask &&
+ !track->blend_read_enable)
+ num_cb = 0;
+
+ for (i = 0; i < num_cb; i++) {
if (track->cb[i].robj == NULL) {
- if (!(track->zb_cb_clear || track->color_channel_mask ||
- track->blend_read_enable)) {
- continue;
- }
DRM_ERROR("[drm] No buffer for color buffer %d !\n", i);
return -EINVAL;
}
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index afc18d8..7b65e4ef 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -1248,6 +1248,7 @@
rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE);
rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE);
rdev->mc.visible_vram_size = rdev->mc.aper_size;
+ rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
r600_vram_gtt_location(rdev, &rdev->mc);
if (rdev->flags & RADEON_IS_IGP) {
@@ -1917,6 +1918,7 @@
*/
void r600_cp_stop(struct radeon_device *rdev)
{
+ rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1));
}
@@ -2729,7 +2731,7 @@
if (i < rdev->usec_timeout) {
DRM_INFO("ib test succeeded in %u usecs\n", i);
} else {
- DRM_ERROR("radeon: ib test failed (sracth(0x%04X)=0x%08X)\n",
+ DRM_ERROR("radeon: ib test failed (scratch(0x%04X)=0x%08X)\n",
scratch, tmp);
r = -EINVAL;
}
@@ -2910,7 +2912,7 @@
{
u32 tmp;
- WREG32(CP_INT_CNTL, 0);
+ WREG32(CP_INT_CNTL, CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
WREG32(GRBM_INT_CNTL, 0);
WREG32(DxMODE_INT_MASK, 0);
if (ASIC_IS_DCE3(rdev)) {
@@ -3528,7 +3530,8 @@
/* r7xx hw bug. write to HDP_DEBUG1 followed by fb read
* rather than write to HDP_REG_COHERENCY_FLUSH_CNTL
*/
- if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740)) {
+ if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740) &&
+ rdev->vram_scratch.ptr) {
void __iomem *ptr = (void *)rdev->vram_scratch.ptr;
u32 tmp;
diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c
index d13622a..3473c00 100644
--- a/drivers/gpu/drm/radeon/r600_blit_kms.c
+++ b/drivers/gpu/drm/radeon/r600_blit_kms.c
@@ -1,3 +1,28 @@
+/*
+ * Copyright 2009 Advanced Micro Devices, Inc.
+ * Copyright 2009 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS 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 COPYRIGHT HOLDER(S) AND/OR ITS SUPPLIERS 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 SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
#include "drmP.h"
#include "drm.h"
#include "radeon_drm.h"
@@ -507,6 +532,7 @@
memcpy(ptr + rdev->r600_blit.ps_offset, r6xx_ps, r6xx_ps_size * 4);
radeon_bo_kunmap(rdev->r600_blit.shader_obj);
radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+ rdev->mc.active_vram_size = rdev->mc.real_vram_size;
return 0;
}
@@ -514,6 +540,7 @@
{
int r;
+ rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
if (rdev->r600_blit.shader_obj == NULL)
return;
/* If we can't reserve the bo, unref should be enough to destroy
diff --git a/drivers/gpu/drm/radeon/r600_blit_shaders.h b/drivers/gpu/drm/radeon/r600_blit_shaders.h
index fdc3b37..f437d36 100644
--- a/drivers/gpu/drm/radeon/r600_blit_shaders.h
+++ b/drivers/gpu/drm/radeon/r600_blit_shaders.h
@@ -1,3 +1,27 @@
+/*
+ * Copyright 2009 Advanced Micro Devices, Inc.
+ * Copyright 2009 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS 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 COPYRIGHT HOLDER(S) AND/OR ITS SUPPLIERS 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 SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
#ifndef R600_BLIT_SHADERS_H
#define R600_BLIT_SHADERS_H
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c
index d886494..250a3a9 100644
--- a/drivers/gpu/drm/radeon/r600_cs.c
+++ b/drivers/gpu/drm/radeon/r600_cs.c
@@ -1170,9 +1170,8 @@
/* using get ib will give us the offset into the mipmap bo */
word0 = radeon_get_ib_value(p, idx + 3) << 8;
if ((mipmap_size + word0) > radeon_bo_size(mipmap)) {
- dev_warn(p->dev, "mipmap bo too small (%d %d %d %d %d %d -> %d have %ld)\n",
- w0, h0, bpe, blevel, nlevels, word0, mipmap_size, radeon_bo_size(texture));
- return -EINVAL;
+ /*dev_warn(p->dev, "mipmap bo too small (%d %d %d %d %d %d -> %d have %ld)\n",
+ w0, h0, bpe, blevel, nlevels, word0, mipmap_size, radeon_bo_size(texture));*/
}
return 0;
}
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index a168d64..9ff38c9 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -344,6 +344,7 @@
* about vram size near mc fb location */
u64 mc_vram_size;
u64 visible_vram_size;
+ u64 active_vram_size;
u64 gtt_size;
u64 gtt_start;
u64 gtt_end;
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index ebae14c..8e43dda 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -317,6 +317,15 @@
*connector_type = DRM_MODE_CONNECTOR_DVID;
}
+ /* MSI K9A2GM V2/V3 board has no HDMI or DVI */
+ if ((dev->pdev->device == 0x796e) &&
+ (dev->pdev->subsystem_vendor == 0x1462) &&
+ (dev->pdev->subsystem_device == 0x7302)) {
+ if ((supported_device == ATOM_DEVICE_DFP2_SUPPORT) ||
+ (supported_device == ATOM_DEVICE_DFP3_SUPPORT))
+ return false;
+ }
+
/* a-bit f-i90hd - ciaranm on #radeonhd - this board has no DVI */
if ((dev->pdev->device == 0x7941) &&
(dev->pdev->subsystem_vendor == 0x147b) &&
@@ -1549,39 +1558,39 @@
switch (tv_info->ucTV_BootUpDefaultStandard) {
case ATOM_TV_NTSC:
tv_std = TV_STD_NTSC;
- DRM_INFO("Default TV standard: NTSC\n");
+ DRM_DEBUG_KMS("Default TV standard: NTSC\n");
break;
case ATOM_TV_NTSCJ:
tv_std = TV_STD_NTSC_J;
- DRM_INFO("Default TV standard: NTSC-J\n");
+ DRM_DEBUG_KMS("Default TV standard: NTSC-J\n");
break;
case ATOM_TV_PAL:
tv_std = TV_STD_PAL;
- DRM_INFO("Default TV standard: PAL\n");
+ DRM_DEBUG_KMS("Default TV standard: PAL\n");
break;
case ATOM_TV_PALM:
tv_std = TV_STD_PAL_M;
- DRM_INFO("Default TV standard: PAL-M\n");
+ DRM_DEBUG_KMS("Default TV standard: PAL-M\n");
break;
case ATOM_TV_PALN:
tv_std = TV_STD_PAL_N;
- DRM_INFO("Default TV standard: PAL-N\n");
+ DRM_DEBUG_KMS("Default TV standard: PAL-N\n");
break;
case ATOM_TV_PALCN:
tv_std = TV_STD_PAL_CN;
- DRM_INFO("Default TV standard: PAL-CN\n");
+ DRM_DEBUG_KMS("Default TV standard: PAL-CN\n");
break;
case ATOM_TV_PAL60:
tv_std = TV_STD_PAL_60;
- DRM_INFO("Default TV standard: PAL-60\n");
+ DRM_DEBUG_KMS("Default TV standard: PAL-60\n");
break;
case ATOM_TV_SECAM:
tv_std = TV_STD_SECAM;
- DRM_INFO("Default TV standard: SECAM\n");
+ DRM_DEBUG_KMS("Default TV standard: SECAM\n");
break;
default:
tv_std = TV_STD_NTSC;
- DRM_INFO("Unknown TV standard; defaulting to NTSC\n");
+ DRM_DEBUG_KMS("Unknown TV standard; defaulting to NTSC\n");
break;
}
}
diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c
index bd74e42..7b7ea26 100644
--- a/drivers/gpu/drm/radeon/radeon_combios.c
+++ b/drivers/gpu/drm/radeon/radeon_combios.c
@@ -913,47 +913,47 @@
switch (RBIOS8(tv_info + 7) & 0xf) {
case 1:
tv_std = TV_STD_NTSC;
- DRM_INFO("Default TV standard: NTSC\n");
+ DRM_DEBUG_KMS("Default TV standard: NTSC\n");
break;
case 2:
tv_std = TV_STD_PAL;
- DRM_INFO("Default TV standard: PAL\n");
+ DRM_DEBUG_KMS("Default TV standard: PAL\n");
break;
case 3:
tv_std = TV_STD_PAL_M;
- DRM_INFO("Default TV standard: PAL-M\n");
+ DRM_DEBUG_KMS("Default TV standard: PAL-M\n");
break;
case 4:
tv_std = TV_STD_PAL_60;
- DRM_INFO("Default TV standard: PAL-60\n");
+ DRM_DEBUG_KMS("Default TV standard: PAL-60\n");
break;
case 5:
tv_std = TV_STD_NTSC_J;
- DRM_INFO("Default TV standard: NTSC-J\n");
+ DRM_DEBUG_KMS("Default TV standard: NTSC-J\n");
break;
case 6:
tv_std = TV_STD_SCART_PAL;
- DRM_INFO("Default TV standard: SCART-PAL\n");
+ DRM_DEBUG_KMS("Default TV standard: SCART-PAL\n");
break;
default:
tv_std = TV_STD_NTSC;
- DRM_INFO
+ DRM_DEBUG_KMS
("Unknown TV standard; defaulting to NTSC\n");
break;
}
switch ((RBIOS8(tv_info + 9) >> 2) & 0x3) {
case 0:
- DRM_INFO("29.498928713 MHz TV ref clk\n");
+ DRM_DEBUG_KMS("29.498928713 MHz TV ref clk\n");
break;
case 1:
- DRM_INFO("28.636360000 MHz TV ref clk\n");
+ DRM_DEBUG_KMS("28.636360000 MHz TV ref clk\n");
break;
case 2:
- DRM_INFO("14.318180000 MHz TV ref clk\n");
+ DRM_DEBUG_KMS("14.318180000 MHz TV ref clk\n");
break;
case 3:
- DRM_INFO("27.000000000 MHz TV ref clk\n");
+ DRM_DEBUG_KMS("27.000000000 MHz TV ref clk\n");
break;
default:
break;
@@ -1324,7 +1324,7 @@
if (tmds_info) {
ver = RBIOS8(tmds_info);
- DRM_INFO("DFP table revision: %d\n", ver);
+ DRM_DEBUG_KMS("DFP table revision: %d\n", ver);
if (ver == 3) {
n = RBIOS8(tmds_info + 5) + 1;
if (n > 4)
@@ -1408,7 +1408,7 @@
offset = combios_get_table_offset(dev, COMBIOS_EXT_TMDS_INFO_TABLE);
if (offset) {
ver = RBIOS8(offset);
- DRM_INFO("External TMDS Table revision: %d\n", ver);
+ DRM_DEBUG_KMS("External TMDS Table revision: %d\n", ver);
tmds->slave_addr = RBIOS8(offset + 4 + 2);
tmds->slave_addr >>= 1; /* 7 bit addressing */
gpio = RBIOS8(offset + 4 + 3);
@@ -1485,6 +1485,11 @@
/* PowerMac8,1 ? */
/* imac g5 isight */
rdev->mode_info.connector_table = CT_IMAC_G5_ISIGHT;
+ } else if ((rdev->pdev->device == 0x4a48) &&
+ (rdev->pdev->subsystem_vendor == 0x1002) &&
+ (rdev->pdev->subsystem_device == 0x4a48)) {
+ /* Mac X800 */
+ rdev->mode_info.connector_table = CT_MAC_X800;
} else
#endif /* CONFIG_PPC_PMAC */
#ifdef CONFIG_PPC64
@@ -1961,6 +1966,48 @@
CONNECTOR_OBJECT_ID_VGA,
&hpd);
break;
+ case CT_MAC_X800:
+ DRM_INFO("Connector Table: %d (mac x800)\n",
+ rdev->mode_info.connector_table);
+ /* DVI - primary dac, internal tmds */
+ ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
+ hpd.hpd = RADEON_HPD_1; /* ??? */
+ radeon_add_legacy_encoder(dev,
+ radeon_get_encoder_enum(dev,
+ ATOM_DEVICE_DFP1_SUPPORT,
+ 0),
+ ATOM_DEVICE_DFP1_SUPPORT);
+ radeon_add_legacy_encoder(dev,
+ radeon_get_encoder_enum(dev,
+ ATOM_DEVICE_CRT1_SUPPORT,
+ 1),
+ ATOM_DEVICE_CRT1_SUPPORT);
+ radeon_add_legacy_connector(dev, 0,
+ ATOM_DEVICE_DFP1_SUPPORT |
+ ATOM_DEVICE_CRT1_SUPPORT,
+ DRM_MODE_CONNECTOR_DVII, &ddc_i2c,
+ CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I,
+ &hpd);
+ /* DVI - tv dac, dvo */
+ ddc_i2c = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0);
+ hpd.hpd = RADEON_HPD_2; /* ??? */
+ radeon_add_legacy_encoder(dev,
+ radeon_get_encoder_enum(dev,
+ ATOM_DEVICE_DFP2_SUPPORT,
+ 0),
+ ATOM_DEVICE_DFP2_SUPPORT);
+ radeon_add_legacy_encoder(dev,
+ radeon_get_encoder_enum(dev,
+ ATOM_DEVICE_CRT2_SUPPORT,
+ 2),
+ ATOM_DEVICE_CRT2_SUPPORT);
+ radeon_add_legacy_connector(dev, 1,
+ ATOM_DEVICE_DFP2_SUPPORT |
+ ATOM_DEVICE_CRT2_SUPPORT,
+ DRM_MODE_CONNECTOR_DVII, &ddc_i2c,
+ CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I,
+ &hpd);
+ break;
default:
DRM_INFO("Connector table: %d (invalid)\n",
rdev->mode_info.connector_table);
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index a9dd784..ecc1a8f 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -481,7 +481,8 @@
return MODE_OK;
}
-static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connector)
+static enum drm_connector_status
+radeon_lvds_detect(struct drm_connector *connector, bool force)
{
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
struct drm_encoder *encoder = radeon_best_single_encoder(connector);
@@ -594,7 +595,8 @@
return MODE_OK;
}
-static enum drm_connector_status radeon_vga_detect(struct drm_connector *connector)
+static enum drm_connector_status
+radeon_vga_detect(struct drm_connector *connector, bool force)
{
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
struct drm_encoder *encoder;
@@ -691,7 +693,8 @@
return MODE_OK;
}
-static enum drm_connector_status radeon_tv_detect(struct drm_connector *connector)
+static enum drm_connector_status
+radeon_tv_detect(struct drm_connector *connector, bool force)
{
struct drm_encoder *encoder;
struct drm_encoder_helper_funcs *encoder_funcs;
@@ -748,7 +751,8 @@
* we have to check if this analog encoder is shared with anyone else (TV)
* if its shared we have to set the other connector to disconnected.
*/
-static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connector)
+static enum drm_connector_status
+radeon_dvi_detect(struct drm_connector *connector, bool force)
{
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
struct drm_encoder *encoder = NULL;
@@ -972,7 +976,8 @@
return ret;
}
-static enum drm_connector_status radeon_dp_detect(struct drm_connector *connector)
+static enum drm_connector_status
+radeon_dp_detect(struct drm_connector *connector, bool force)
{
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
enum drm_connector_status ret = connector_status_disconnected;
diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c
index 5731fc9..3eef567 100644
--- a/drivers/gpu/drm/radeon/radeon_cursor.c
+++ b/drivers/gpu/drm/radeon/radeon_cursor.c
@@ -203,6 +203,7 @@
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct radeon_device *rdev = crtc->dev->dev_private;
int xorigin = 0, yorigin = 0;
+ int w = radeon_crtc->cursor_width;
if (x < 0)
xorigin = -x + 1;
@@ -213,22 +214,7 @@
if (yorigin >= CURSOR_HEIGHT)
yorigin = CURSOR_HEIGHT - 1;
- radeon_lock_cursor(crtc, true);
- if (ASIC_IS_DCE4(rdev)) {
- /* cursors 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);
-
- /* XXX: check if evergreen has the same issues as avivo chips */
- WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset,
- ((xorigin ? 0 : x) << 16) |
- (yorigin ? 0 : y));
- WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
- WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset,
- ((radeon_crtc->cursor_width - 1) << 16) | (radeon_crtc->cursor_height - 1));
- } else if (ASIC_IS_AVIVO(rdev)) {
- int w = radeon_crtc->cursor_width;
+ if (ASIC_IS_AVIVO(rdev)) {
int i = 0;
struct drm_crtc *crtc_p;
@@ -260,7 +246,17 @@
if (w <= 0)
w = 1;
}
+ }
+ radeon_lock_cursor(crtc, true);
+ if (ASIC_IS_DCE4(rdev)) {
+ WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset,
+ ((xorigin ? 0 : x) << 16) |
+ (yorigin ? 0 : y));
+ WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
+ WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset,
+ ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
+ } else if (ASIC_IS_AVIVO(rdev)) {
WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset,
((xorigin ? 0 : x) << 16) |
(yorigin ? 0 : y));
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 6dd434a..b92d2f2 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -349,6 +349,8 @@
DRM_INFO(" DFP4: %s\n", encoder_names[radeon_encoder->encoder_id]);
if (devices & ATOM_DEVICE_DFP5_SUPPORT)
DRM_INFO(" DFP5: %s\n", encoder_names[radeon_encoder->encoder_id]);
+ if (devices & ATOM_DEVICE_DFP6_SUPPORT)
+ DRM_INFO(" DFP6: %s\n", encoder_names[radeon_encoder->encoder_id]);
if (devices & ATOM_DEVICE_TV1_SUPPORT)
DRM_INFO(" TV1: %s\n", encoder_names[radeon_encoder->encoder_id]);
if (devices & ATOM_DEVICE_CV_SUPPORT)
@@ -841,8 +843,9 @@
{
struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb);
- if (radeon_fb->obj)
+ if (radeon_fb->obj) {
drm_gem_object_unreference_unlocked(radeon_fb->obj);
+ }
drm_framebuffer_cleanup(fb);
kfree(radeon_fb);
}
@@ -1140,17 +1143,18 @@
radeon_crtc->rmx_type = radeon_encoder->rmx_type;
else
radeon_crtc->rmx_type = RMX_OFF;
- src_v = crtc->mode.vdisplay;
- dst_v = radeon_crtc->native_mode.vdisplay;
- src_h = crtc->mode.hdisplay;
- dst_h = radeon_crtc->native_mode.vdisplay;
/* copy native mode */
memcpy(&radeon_crtc->native_mode,
&radeon_encoder->native_mode,
sizeof(struct drm_display_mode));
+ src_v = crtc->mode.vdisplay;
+ dst_v = radeon_crtc->native_mode.vdisplay;
+ src_h = crtc->mode.hdisplay;
+ dst_h = radeon_crtc->native_mode.hdisplay;
/* fix up for overscan on hdmi */
if (ASIC_IS_AVIVO(rdev) &&
+ (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) &&
((radeon_encoder->underscan_type == UNDERSCAN_ON) ||
((radeon_encoder->underscan_type == UNDERSCAN_AUTO) &&
drm_detect_hdmi_monitor(radeon_connector->edid) &&
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index c74a8b2..40b0c08 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -94,6 +94,7 @@
ret = radeon_bo_reserve(rbo, false);
if (likely(ret == 0)) {
radeon_bo_kunmap(rbo);
+ radeon_bo_unpin(rbo);
radeon_bo_unreserve(rbo);
}
drm_gem_object_unreference_unlocked(gobj);
@@ -325,8 +326,6 @@
{
struct fb_info *info;
struct radeon_framebuffer *rfb = &rfbdev->rfb;
- struct radeon_bo *rbo;
- int r;
if (rfbdev->helper.fbdev) {
info = rfbdev->helper.fbdev;
@@ -338,14 +337,8 @@
}
if (rfb->obj) {
- rbo = rfb->obj->driver_private;
- r = radeon_bo_reserve(rbo, false);
- if (likely(r == 0)) {
- radeon_bo_kunmap(rbo);
- radeon_bo_unpin(rbo);
- radeon_bo_unreserve(rbo);
- }
- drm_gem_object_unreference_unlocked(rfb->obj);
+ radeonfb_destroy_pinned_object(rfb->obj);
+ rfb->obj = NULL;
}
drm_fb_helper_fini(&rfbdev->helper);
drm_framebuffer_cleanup(&rfb->base);
diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c
index c578f26..d1e595d 100644
--- a/drivers/gpu/drm/radeon/radeon_gem.c
+++ b/drivers/gpu/drm/radeon/radeon_gem.c
@@ -201,11 +201,11 @@
return r;
}
r = drm_gem_handle_create(filp, gobj, &handle);
+ /* drop reference from allocate - handle holds it now */
+ drm_gem_object_unreference_unlocked(gobj);
if (r) {
- drm_gem_object_unreference_unlocked(gobj);
return r;
}
- drm_gem_object_handle_unreference_unlocked(gobj);
args->handle = handle;
return 0;
}
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index 5eee3c4..8fbbe1c 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -203,6 +203,10 @@
*/
int radeon_driver_firstopen_kms(struct drm_device *dev)
{
+ struct radeon_device *rdev = dev->dev_private;
+
+ if (rdev->powered_down)
+ return -EINVAL;
return 0;
}
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index efbe975..17a6602 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -204,7 +204,7 @@
/* mostly for macs, but really any system without connector tables */
enum radeon_connector_table {
- CT_NONE,
+ CT_NONE = 0,
CT_GENERIC,
CT_IBOOK,
CT_POWERBOOK_EXTERNAL,
@@ -215,6 +215,7 @@
CT_IMAC_G5_ISIGHT,
CT_EMAC,
CT_RN50_POWER,
+ CT_MAC_X800,
};
enum radeon_dvo_chip {
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index 0afd1e6..b3b5306 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -69,7 +69,7 @@
u32 c = 0;
rbo->placement.fpfn = 0;
- rbo->placement.lpfn = 0;
+ rbo->placement.lpfn = rbo->rdev->mc.active_vram_size >> PAGE_SHIFT;
rbo->placement.placement = rbo->placements;
rbo->placement.busy_placement = rbo->placements;
if (domain & RADEON_GEM_DOMAIN_VRAM)
diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h
index 353998d..3481bc7 100644
--- a/drivers/gpu/drm/radeon/radeon_object.h
+++ b/drivers/gpu/drm/radeon/radeon_object.h
@@ -124,11 +124,8 @@
int r;
r = ttm_bo_reserve(&bo->tbo, true, no_wait, false, 0);
- if (unlikely(r != 0)) {
- if (r != -ERESTARTSYS)
- dev_err(bo->rdev->dev, "%p reserve failed for wait\n", bo);
+ if (unlikely(r != 0))
return r;
- }
spin_lock(&bo->tbo.lock);
if (mem_type)
*mem_type = bo->tbo.mem.mem_type;
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index cc05b23..51d5f7b 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -693,6 +693,7 @@
rdev->mc.real_vram_size = RREG32(RADEON_CONFIG_MEMSIZE);
rdev->mc.mc_vram_size = rdev->mc.real_vram_size;
rdev->mc.visible_vram_size = rdev->mc.aper_size;
+ rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev);
base = RREG32_MC(R_000004_MC_FB_LOCATION);
base = G_000004_MC_FB_START(base) << 16;
diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c
index 3e3f757..4dc2a87 100644
--- a/drivers/gpu/drm/radeon/rs690.c
+++ b/drivers/gpu/drm/radeon/rs690.c
@@ -157,6 +157,7 @@
rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0);
rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0);
rdev->mc.visible_vram_size = rdev->mc.aper_size;
+ rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
base = RREG32_MC(R_000100_MCCFG_FB_LOCATION);
base = G_000100_MC_FB_START(base) << 16;
rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev);
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index bfa59db..9490da7 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -267,6 +267,7 @@
*/
void r700_cp_stop(struct radeon_device *rdev)
{
+ rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT));
}
@@ -992,6 +993,7 @@
rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE);
rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE);
rdev->mc.visible_vram_size = rdev->mc.aper_size;
+ rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
r600_vram_gtt_location(rdev, &rdev->mc);
radeon_update_bandwidth_info(rdev);
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index cb4cf7e..db809e0 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -442,6 +442,43 @@
}
/**
+ * Call bo::reserved and with the lru lock held.
+ * Will release GPU memory type usage on destruction.
+ * This is the place to put in driver specific hooks.
+ * Will release the bo::reserved lock and the
+ * lru lock on exit.
+ */
+
+static void ttm_bo_cleanup_memtype_use(struct ttm_buffer_object *bo)
+{
+ struct ttm_bo_global *glob = bo->glob;
+
+ if (bo->ttm) {
+
+ /**
+ * Release the lru_lock, since we don't want to have
+ * an atomic requirement on ttm_tt[unbind|destroy].
+ */
+
+ spin_unlock(&glob->lru_lock);
+ ttm_tt_unbind(bo->ttm);
+ ttm_tt_destroy(bo->ttm);
+ bo->ttm = NULL;
+ spin_lock(&glob->lru_lock);
+ }
+
+ if (bo->mem.mm_node) {
+ drm_mm_put_block(bo->mem.mm_node);
+ bo->mem.mm_node = NULL;
+ }
+
+ atomic_set(&bo->reserved, 0);
+ wake_up_all(&bo->event_queue);
+ spin_unlock(&glob->lru_lock);
+}
+
+
+/**
* If bo idle, remove from delayed- and lru lists, and unref.
* If not idle, and already on delayed list, do nothing.
* If not idle, and not on delayed list, put on delayed list,
@@ -456,6 +493,7 @@
int ret;
spin_lock(&bo->lock);
+retry:
(void) ttm_bo_wait(bo, false, false, !remove_all);
if (!bo->sync_obj) {
@@ -464,31 +502,52 @@
spin_unlock(&bo->lock);
spin_lock(&glob->lru_lock);
- put_count = ttm_bo_del_from_lru(bo);
+ ret = ttm_bo_reserve_locked(bo, false, !remove_all, false, 0);
- ret = ttm_bo_reserve_locked(bo, false, false, false, 0);
- BUG_ON(ret);
- if (bo->ttm)
- ttm_tt_unbind(bo->ttm);
+ /**
+ * Someone else has the object reserved. Bail and retry.
+ */
+
+ if (unlikely(ret == -EBUSY)) {
+ spin_unlock(&glob->lru_lock);
+ spin_lock(&bo->lock);
+ goto requeue;
+ }
+
+ /**
+ * We can re-check for sync object without taking
+ * the bo::lock since setting the sync object requires
+ * also bo::reserved. A busy object at this point may
+ * be caused by another thread starting an accelerated
+ * eviction.
+ */
+
+ if (unlikely(bo->sync_obj)) {
+ atomic_set(&bo->reserved, 0);
+ wake_up_all(&bo->event_queue);
+ spin_unlock(&glob->lru_lock);
+ spin_lock(&bo->lock);
+ if (remove_all)
+ goto retry;
+ else
+ goto requeue;
+ }
+
+ put_count = ttm_bo_del_from_lru(bo);
if (!list_empty(&bo->ddestroy)) {
list_del_init(&bo->ddestroy);
++put_count;
}
- if (bo->mem.mm_node) {
- drm_mm_put_block(bo->mem.mm_node);
- bo->mem.mm_node = NULL;
- }
- spin_unlock(&glob->lru_lock);
- atomic_set(&bo->reserved, 0);
+ ttm_bo_cleanup_memtype_use(bo);
while (put_count--)
kref_put(&bo->list_kref, ttm_bo_ref_bug);
return 0;
}
-
+requeue:
spin_lock(&glob->lru_lock);
if (list_empty(&bo->ddestroy)) {
void *sync_obj = bo->sync_obj;
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
index 7cffb3e..3451a82a 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -351,6 +351,7 @@
INIT_LIST_HEAD(&fbo->lru);
INIT_LIST_HEAD(&fbo->swap);
fbo->vm_node = NULL;
+ atomic_set(&fbo->cpu_writers, 0);
fbo->sync_obj = driver->sync_obj_ref(bo->sync_obj);
kref_init(&fbo->list_kref);
diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c
index ca90479..b1e02ff 100644
--- a/drivers/gpu/drm/ttm/ttm_page_alloc.c
+++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c
@@ -69,7 +69,7 @@
spinlock_t lock;
bool fill_lock;
struct list_head list;
- int gfp_flags;
+ gfp_t gfp_flags;
unsigned npages;
char *name;
unsigned long nfrees;
@@ -475,7 +475,7 @@
* This function is reentrant if caller updates count depending on number of
* pages returned in pages array.
*/
-static int ttm_alloc_new_pages(struct list_head *pages, int gfp_flags,
+static int ttm_alloc_new_pages(struct list_head *pages, gfp_t gfp_flags,
int ttm_flags, enum ttm_caching_state cstate, unsigned count)
{
struct page **caching_array;
@@ -666,7 +666,7 @@
{
struct ttm_page_pool *pool = ttm_get_pool(flags, cstate);
struct page *p = NULL;
- int gfp_flags = GFP_USER;
+ gfp_t gfp_flags = GFP_USER;
int r;
/* set zero flag for page allocation if required */
@@ -818,7 +818,7 @@
return 0;
}
-void ttm_page_alloc_fini()
+void ttm_page_alloc_fini(void)
{
int i;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 72ec2e2..a96ed6d 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -148,13 +148,16 @@
{0, 0, 0}
};
-static char *vmw_devname = "vmwgfx";
+static int enable_fbdev;
static int vmw_probe(struct pci_dev *, const struct pci_device_id *);
static void vmw_master_init(struct vmw_master *);
static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
void *ptr);
+MODULE_PARM_DESC(enable_fbdev, "Enable vmwgfx fbdev");
+module_param_named(enable_fbdev, enable_fbdev, int, 0600);
+
static void vmw_print_capabilities(uint32_t capabilities)
{
DRM_INFO("Capabilities:\n");
@@ -192,8 +195,6 @@
{
int ret;
- vmw_kms_save_vga(dev_priv);
-
ret = vmw_fifo_init(dev_priv, &dev_priv->fifo);
if (unlikely(ret != 0)) {
DRM_ERROR("Unable to initialize FIFO.\n");
@@ -206,9 +207,35 @@
static void vmw_release_device(struct vmw_private *dev_priv)
{
vmw_fifo_release(dev_priv, &dev_priv->fifo);
- vmw_kms_restore_vga(dev_priv);
}
+int vmw_3d_resource_inc(struct vmw_private *dev_priv)
+{
+ int ret = 0;
+
+ mutex_lock(&dev_priv->release_mutex);
+ if (unlikely(dev_priv->num_3d_resources++ == 0)) {
+ ret = vmw_request_device(dev_priv);
+ if (unlikely(ret != 0))
+ --dev_priv->num_3d_resources;
+ }
+ mutex_unlock(&dev_priv->release_mutex);
+ return ret;
+}
+
+
+void vmw_3d_resource_dec(struct vmw_private *dev_priv)
+{
+ int32_t n3d;
+
+ mutex_lock(&dev_priv->release_mutex);
+ if (unlikely(--dev_priv->num_3d_resources == 0))
+ vmw_release_device(dev_priv);
+ n3d = (int32_t) dev_priv->num_3d_resources;
+ mutex_unlock(&dev_priv->release_mutex);
+
+ BUG_ON(n3d < 0);
+}
static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
{
@@ -228,6 +255,7 @@
dev_priv->last_read_sequence = (uint32_t) -100;
mutex_init(&dev_priv->hw_mutex);
mutex_init(&dev_priv->cmdbuf_mutex);
+ mutex_init(&dev_priv->release_mutex);
rwlock_init(&dev_priv->resource_lock);
idr_init(&dev_priv->context_idr);
idr_init(&dev_priv->surface_idr);
@@ -244,6 +272,8 @@
dev_priv->vram_start = pci_resource_start(dev->pdev, 1);
dev_priv->mmio_start = pci_resource_start(dev->pdev, 2);
+ dev_priv->enable_fb = enable_fbdev;
+
mutex_lock(&dev_priv->hw_mutex);
vmw_write(dev_priv, SVGA_REG_ID, SVGA_ID_2);
@@ -343,17 +373,6 @@
dev->dev_private = dev_priv;
- if (!dev->devname)
- dev->devname = vmw_devname;
-
- if (dev_priv->capabilities & SVGA_CAP_IRQMASK) {
- ret = drm_irq_install(dev);
- if (unlikely(ret != 0)) {
- DRM_ERROR("Failed installing irq: %d\n", ret);
- goto out_no_irq;
- }
- }
-
ret = pci_request_regions(dev->pdev, "vmwgfx probe");
dev_priv->stealth = (ret != 0);
if (dev_priv->stealth) {
@@ -369,26 +388,52 @@
goto out_no_device;
}
}
- ret = vmw_request_device(dev_priv);
+ ret = vmw_kms_init(dev_priv);
if (unlikely(ret != 0))
- goto out_no_device;
- vmw_kms_init(dev_priv);
+ goto out_no_kms;
vmw_overlay_init(dev_priv);
- vmw_fb_init(dev_priv);
+ if (dev_priv->enable_fb) {
+ ret = vmw_3d_resource_inc(dev_priv);
+ if (unlikely(ret != 0))
+ goto out_no_fifo;
+ vmw_kms_save_vga(dev_priv);
+ vmw_fb_init(dev_priv);
+ DRM_INFO("%s", vmw_fifo_have_3d(dev_priv) ?
+ "Detected device 3D availability.\n" :
+ "Detected no device 3D availability.\n");
+ } else {
+ DRM_INFO("Delayed 3D detection since we're not "
+ "running the device in SVGA mode yet.\n");
+ }
+
+ if (dev_priv->capabilities & SVGA_CAP_IRQMASK) {
+ ret = drm_irq_install(dev);
+ if (unlikely(ret != 0)) {
+ DRM_ERROR("Failed installing irq: %d\n", ret);
+ goto out_no_irq;
+ }
+ }
dev_priv->pm_nb.notifier_call = vmwgfx_pm_notifier;
register_pm_notifier(&dev_priv->pm_nb);
- DRM_INFO("%s", vmw_fifo_have_3d(dev_priv) ? "Have 3D\n" : "No 3D\n");
-
return 0;
-out_no_device:
- if (dev_priv->capabilities & SVGA_CAP_IRQMASK)
- drm_irq_uninstall(dev_priv->dev);
- if (dev->devname == vmw_devname)
- dev->devname = NULL;
out_no_irq:
+ if (dev_priv->enable_fb) {
+ vmw_fb_close(dev_priv);
+ vmw_kms_restore_vga(dev_priv);
+ vmw_3d_resource_dec(dev_priv);
+ }
+out_no_fifo:
+ vmw_overlay_close(dev_priv);
+ vmw_kms_close(dev_priv);
+out_no_kms:
+ if (dev_priv->stealth)
+ pci_release_region(dev->pdev, 2);
+ else
+ pci_release_regions(dev->pdev);
+out_no_device:
ttm_object_device_release(&dev_priv->tdev);
out_err4:
iounmap(dev_priv->mmio_virt);
@@ -415,19 +460,20 @@
unregister_pm_notifier(&dev_priv->pm_nb);
- vmw_fb_close(dev_priv);
+ if (dev_priv->capabilities & SVGA_CAP_IRQMASK)
+ drm_irq_uninstall(dev_priv->dev);
+ if (dev_priv->enable_fb) {
+ vmw_fb_close(dev_priv);
+ vmw_kms_restore_vga(dev_priv);
+ vmw_3d_resource_dec(dev_priv);
+ }
vmw_kms_close(dev_priv);
vmw_overlay_close(dev_priv);
- vmw_release_device(dev_priv);
if (dev_priv->stealth)
pci_release_region(dev->pdev, 2);
else
pci_release_regions(dev->pdev);
- if (dev_priv->capabilities & SVGA_CAP_IRQMASK)
- drm_irq_uninstall(dev_priv->dev);
- if (dev->devname == vmw_devname)
- dev->devname = NULL;
ttm_object_device_release(&dev_priv->tdev);
iounmap(dev_priv->mmio_virt);
drm_mtrr_del(dev_priv->mmio_mtrr, dev_priv->mmio_start,
@@ -500,7 +546,7 @@
struct drm_ioctl_desc *ioctl =
&vmw_ioctls[nr - DRM_COMMAND_BASE];
- if (unlikely(ioctl->cmd != cmd)) {
+ if (unlikely(ioctl->cmd_drv != cmd)) {
DRM_ERROR("Invalid command format, ioctl %d\n",
nr - DRM_COMMAND_BASE);
return -EINVAL;
@@ -589,6 +635,16 @@
struct vmw_master *vmaster = vmw_master(file_priv->master);
int ret = 0;
+ if (!dev_priv->enable_fb) {
+ ret = vmw_3d_resource_inc(dev_priv);
+ if (unlikely(ret != 0))
+ return ret;
+ vmw_kms_save_vga(dev_priv);
+ mutex_lock(&dev_priv->hw_mutex);
+ vmw_write(dev_priv, SVGA_REG_TRACES, 0);
+ mutex_unlock(&dev_priv->hw_mutex);
+ }
+
if (active) {
BUG_ON(active != &dev_priv->fbdev_master);
ret = ttm_vt_lock(&active->lock, false, vmw_fp->tfile);
@@ -617,7 +673,13 @@
return 0;
out_no_active_lock:
- vmw_release_device(dev_priv);
+ if (!dev_priv->enable_fb) {
+ mutex_lock(&dev_priv->hw_mutex);
+ vmw_write(dev_priv, SVGA_REG_TRACES, 1);
+ mutex_unlock(&dev_priv->hw_mutex);
+ vmw_kms_restore_vga(dev_priv);
+ vmw_3d_resource_dec(dev_priv);
+ }
return ret;
}
@@ -645,11 +707,23 @@
ttm_lock_set_kill(&vmaster->lock, true, SIGTERM);
+ if (!dev_priv->enable_fb) {
+ ret = ttm_bo_evict_mm(&dev_priv->bdev, TTM_PL_VRAM);
+ if (unlikely(ret != 0))
+ DRM_ERROR("Unable to clean VRAM on master drop.\n");
+ mutex_lock(&dev_priv->hw_mutex);
+ vmw_write(dev_priv, SVGA_REG_TRACES, 1);
+ mutex_unlock(&dev_priv->hw_mutex);
+ vmw_kms_restore_vga(dev_priv);
+ vmw_3d_resource_dec(dev_priv);
+ }
+
dev_priv->active_master = &dev_priv->fbdev_master;
ttm_lock_set_kill(&dev_priv->fbdev_master.lock, false, SIGTERM);
ttm_vt_unlock(&dev_priv->fbdev_master.lock);
- vmw_fb_on(dev_priv);
+ if (dev_priv->enable_fb)
+ vmw_fb_on(dev_priv);
}
@@ -722,6 +796,7 @@
.irq_postinstall = vmw_irq_postinstall,
.irq_uninstall = vmw_irq_uninstall,
.irq_handler = vmw_irq_handler,
+ .get_vblank_counter = vmw_get_vblank_counter,
.reclaim_buffers_locked = NULL,
.get_map_ofs = drm_core_get_map_ofs,
.get_reg_ofs = drm_core_get_reg_ofs,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index 429f917..58de639 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -277,6 +277,7 @@
bool stealth;
bool is_opened;
+ bool enable_fb;
/**
* Master management.
@@ -285,6 +286,9 @@
struct vmw_master *active_master;
struct vmw_master fbdev_master;
struct notifier_block pm_nb;
+
+ struct mutex release_mutex;
+ uint32_t num_3d_resources;
};
static inline struct vmw_private *vmw_priv(struct drm_device *dev)
@@ -319,6 +323,9 @@
return val;
}
+int vmw_3d_resource_inc(struct vmw_private *dev_priv);
+void vmw_3d_resource_dec(struct vmw_private *dev_priv);
+
/**
* GMR utilities - vmwgfx_gmr.c
*/
@@ -511,6 +518,7 @@
unsigned bbp, unsigned depth);
int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
+u32 vmw_get_vblank_counter(struct drm_device *dev, int crtc);
/**
* Overlay control - vmwgfx_overlay.c
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
index 870967a..409e172 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
@@ -615,6 +615,11 @@
if (unlikely(ret != 0))
goto err_unlock;
+ if (bo->mem.mem_type == TTM_PL_VRAM &&
+ bo->mem.mm_node->start < bo->num_pages)
+ (void) ttm_bo_validate(bo, &vmw_sys_placement, false,
+ false, false);
+
ret = ttm_bo_validate(bo, &ne_placement, false, false, false);
/* Could probably bug on */
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
index e6a1eb7..0fe3176 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
@@ -106,6 +106,7 @@
mutex_lock(&dev_priv->hw_mutex);
dev_priv->enable_state = vmw_read(dev_priv, SVGA_REG_ENABLE);
dev_priv->config_done_state = vmw_read(dev_priv, SVGA_REG_CONFIG_DONE);
+ dev_priv->traces_state = vmw_read(dev_priv, SVGA_REG_TRACES);
vmw_write(dev_priv, SVGA_REG_ENABLE, 1);
min = 4;
@@ -175,6 +176,8 @@
dev_priv->config_done_state);
vmw_write(dev_priv, SVGA_REG_ENABLE,
dev_priv->enable_state);
+ vmw_write(dev_priv, SVGA_REG_TRACES,
+ dev_priv->traces_state);
mutex_unlock(&dev_priv->hw_mutex);
vmw_fence_queue_takedown(&fifo->fence_queue);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 64d7f47..e882ba0 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -898,7 +898,19 @@
save->width = vmw_read(vmw_priv, SVGA_REG_DISPLAY_WIDTH);
save->height = vmw_read(vmw_priv, SVGA_REG_DISPLAY_HEIGHT);
vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID);
+ if (i == 0 && vmw_priv->num_displays == 1 &&
+ save->width == 0 && save->height == 0) {
+
+ /*
+ * It should be fairly safe to assume that these
+ * values are uninitialized.
+ */
+
+ save->width = vmw_priv->vga_width - save->pos_x;
+ save->height = vmw_priv->vga_height - save->pos_y;
+ }
}
+
return 0;
}
@@ -984,3 +996,8 @@
ttm_read_unlock(&vmaster->lock);
return ret;
}
+
+u32 vmw_get_vblank_counter(struct drm_device *dev, int crtc)
+{
+ return 0;
+}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index 2ff5cf7..11cb39e 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -27,6 +27,8 @@
#include "vmwgfx_kms.h"
+#define VMWGFX_LDU_NUM_DU 8
+
#define vmw_crtc_to_ldu(x) \
container_of(x, struct vmw_legacy_display_unit, base.crtc)
#define vmw_encoder_to_ldu(x) \
@@ -335,7 +337,8 @@
}
static enum drm_connector_status
- vmw_ldu_connector_detect(struct drm_connector *connector)
+ vmw_ldu_connector_detect(struct drm_connector *connector,
+ bool force)
{
if (vmw_connector_to_ldu(connector)->pref_active)
return connector_status_connected;
@@ -516,7 +519,7 @@
drm_connector_init(dev, connector, &vmw_legacy_connector_funcs,
DRM_MODE_CONNECTOR_LVDS);
- connector->status = vmw_ldu_connector_detect(connector);
+ connector->status = vmw_ldu_connector_detect(connector, true);
drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs,
DRM_MODE_ENCODER_LVDS);
@@ -535,6 +538,10 @@
int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv)
{
+ struct drm_device *dev = dev_priv->dev;
+ int i;
+ int ret;
+
if (dev_priv->ldu_priv) {
DRM_INFO("ldu system already on\n");
return -EINVAL;
@@ -552,23 +559,24 @@
drm_mode_create_dirty_info_property(dev_priv->dev);
- vmw_ldu_init(dev_priv, 0);
- /* for old hardware without multimon only enable one display */
if (dev_priv->capabilities & SVGA_CAP_MULTIMON) {
- vmw_ldu_init(dev_priv, 1);
- vmw_ldu_init(dev_priv, 2);
- vmw_ldu_init(dev_priv, 3);
- vmw_ldu_init(dev_priv, 4);
- vmw_ldu_init(dev_priv, 5);
- vmw_ldu_init(dev_priv, 6);
- vmw_ldu_init(dev_priv, 7);
+ for (i = 0; i < VMWGFX_LDU_NUM_DU; ++i)
+ vmw_ldu_init(dev_priv, i);
+ ret = drm_vblank_init(dev, VMWGFX_LDU_NUM_DU);
+ } else {
+ /* for old hardware without multimon only enable one display */
+ vmw_ldu_init(dev_priv, 0);
+ ret = drm_vblank_init(dev, 1);
}
- return 0;
+ return ret;
}
int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv)
{
+ struct drm_device *dev = dev_priv->dev;
+
+ drm_vblank_cleanup(dev);
if (!dev_priv->ldu_priv)
return -ENOSYS;
@@ -610,7 +618,7 @@
ldu->pref_height = 600;
ldu->pref_active = false;
}
- con->status = vmw_ldu_connector_detect(con);
+ con->status = vmw_ldu_connector_detect(con, true);
}
mutex_unlock(&dev->mode_config.mutex);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index 5f2d5df..c8c40e9 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -211,6 +211,7 @@
cmd->body.cid = cpu_to_le32(res->id);
vmw_fifo_commit(dev_priv, sizeof(*cmd));
+ vmw_3d_resource_dec(dev_priv);
}
static int vmw_context_init(struct vmw_private *dev_priv,
@@ -247,6 +248,7 @@
cmd->body.cid = cpu_to_le32(res->id);
vmw_fifo_commit(dev_priv, sizeof(*cmd));
+ (void) vmw_3d_resource_inc(dev_priv);
vmw_resource_activate(res, vmw_hw_context_destroy);
return 0;
}
@@ -406,6 +408,7 @@
cmd->body.sid = cpu_to_le32(res->id);
vmw_fifo_commit(dev_priv, sizeof(*cmd));
+ vmw_3d_resource_dec(dev_priv);
}
void vmw_surface_res_free(struct vmw_resource *res)
@@ -473,6 +476,7 @@
}
vmw_fifo_commit(dev_priv, submit_size);
+ (void) vmw_3d_resource_inc(dev_priv);
vmw_resource_activate(res, vmw_hw_surface_destroy);
return 0;
}
diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c
index b87569e..f366f96 100644
--- a/drivers/gpu/vga/vgaarb.c
+++ b/drivers/gpu/vga/vgaarb.c
@@ -598,7 +598,7 @@
pr_debug("vgaarb: decoding count now is: %d\n", vga_decode_count);
}
-void __vga_set_legacy_decoding(struct pci_dev *pdev, unsigned int decodes, bool userspace)
+static void __vga_set_legacy_decoding(struct pci_dev *pdev, unsigned int decodes, bool userspace)
{
struct vga_device *vgadev;
unsigned long flags;
diff --git a/drivers/hid/hid-cando.c b/drivers/hid/hid-cando.c
index 4267a6f..5925bdc 100644
--- a/drivers/hid/hid-cando.c
+++ b/drivers/hid/hid-cando.c
@@ -237,6 +237,8 @@
USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+ USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
{ }
};
MODULE_DEVICE_TABLE(hid, cando_devices);
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 0c52899..a0dea3d 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1285,10 +1285,14 @@
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
@@ -1578,7 +1582,6 @@
{ HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) },
{ HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) },
- { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT)},
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)},
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)},
{ HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 85c6d13..c5ae5f1 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -105,6 +105,7 @@
#define USB_VENDOR_ID_ASUS 0x0486
#define USB_DEVICE_ID_ASUS_T91MT 0x0185
+#define USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO 0x0186
#define USB_VENDOR_ID_ASUSTEK 0x0b05
#define USB_DEVICE_ID_ASUSTEK_LCM 0x1726
@@ -128,10 +129,12 @@
#define USB_VENDOR_ID_BTC 0x046e
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578
+#define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577
#define USB_VENDOR_ID_CANDO 0x2087
#define USB_DEVICE_ID_CANDO_MULTI_TOUCH 0x0a01
#define USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6 0x0b03
+#define USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6 0x0f01
#define USB_VENDOR_ID_CH 0x068e
#define USB_DEVICE_ID_CH_PRO_PEDALS 0x00f2
@@ -149,6 +152,7 @@
#define USB_VENDOR_ID_CHICONY 0x04f2
#define USB_DEVICE_ID_CHICONY_TACTICAL_PAD 0x0418
+#define USB_DEVICE_ID_CHICONY_MULTI_TOUCH 0xb19d
#define USB_VENDOR_ID_CIDC 0x1677
@@ -500,6 +504,7 @@
#define USB_VENDOR_ID_TURBOX 0x062a
#define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201
+#define USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART 0x7100
#define USB_VENDOR_ID_TWINHAN 0x6253
#define USB_DEVICE_ID_TWINHAN_IR_REMOTE 0x0100
@@ -507,6 +512,7 @@
#define USB_VENDOR_ID_UCLOGIC 0x5543
#define USB_DEVICE_ID_UCLOGIC_TABLET_PF1209 0x0042
#define USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U 0x0003
+#define USB_DEVICE_ID_UCLOGIC_TABLET_KNA5 0x6001
#define USB_VENDOR_ID_VERNIER 0x08f7
#define USB_DEVICE_ID_VERNIER_LABPRO 0x0001
diff --git a/drivers/hid/hid-mosart.c b/drivers/hid/hid-mosart.c
index e91437c..ac5421d 100644
--- a/drivers/hid/hid-mosart.c
+++ b/drivers/hid/hid-mosart.c
@@ -239,6 +239,7 @@
static const struct hid_device_id mosart_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) },
{ }
};
MODULE_DEVICE_TABLE(hid, mosart_devices);
diff --git a/drivers/hid/hid-topseed.c b/drivers/hid/hid-topseed.c
index 5771f85..956ed9a 100644
--- a/drivers/hid/hid-topseed.c
+++ b/drivers/hid/hid-topseed.c
@@ -64,6 +64,7 @@
static const struct hid_device_id ts_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
{ }
};
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 47d70c5..a3866b5 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -109,6 +109,12 @@
int ret = 0;
mutex_lock(&minors_lock);
+
+ if (!hidraw_table[minor]) {
+ ret = -ENODEV;
+ goto out;
+ }
+
dev = hidraw_table[minor]->hid;
if (!dev->hid_output_raw_report) {
@@ -244,6 +250,10 @@
mutex_lock(&minors_lock);
dev = hidraw_table[minor];
+ if (!dev) {
+ ret = -ENODEV;
+ goto out;
+ }
switch (cmd) {
case HIDIOCGRDESCSIZE:
@@ -317,6 +327,7 @@
ret = -ENOTTY;
}
+out:
mutex_unlock(&minors_lock);
return ret;
}
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index b729c02..599041a 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -828,6 +828,7 @@
}
} else {
int skipped_report_id = 0;
+ int report_id = buf[0];
if (buf[0] == 0x0) {
/* Don't send the Report ID */
buf++;
@@ -837,7 +838,7 @@
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
HID_REQ_SET_REPORT,
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- ((report_type + 1) << 8) | *buf,
+ ((report_type + 1) << 8) | report_id,
interface->desc.bInterfaceNumber, buf, count,
USB_CTRL_SET_TIMEOUT);
/* count also the report id, if this was a numbered report. */
@@ -1445,6 +1446,11 @@
{ }
};
+struct usb_interface *usbhid_find_interface(int minor)
+{
+ return usb_find_interface(&hid_driver, minor);
+}
+
static struct hid_driver hid_usb_driver = {
.name = "generic-usb",
.id_table = hid_usb_table,
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 2643d31..f0260c6 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -33,8 +33,10 @@
{ USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD },
+ { USB_VENDOR_ID_DWAV, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER, HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET },
{ USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_MOJO, USB_DEVICE_ID_RETRO_ADAPTER, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
@@ -69,6 +71,7 @@
{ USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
@@ -77,6 +80,8 @@
{ USB_VENDOR_ID_PI_ENGINEERING, USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL, HID_QUIRK_HIDINPUT_FORCE },
+ { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH, HID_QUIRK_MULTI_INPUT },
+
{ 0, 0 }
};
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index 0a29c51..681e620 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -270,7 +270,7 @@
struct hiddev *hiddev;
int res;
- intf = usb_find_interface(&hiddev_driver, iminor(inode));
+ intf = usbhid_find_interface(iminor(inode));
if (!intf)
return -ENODEV;
hid = usb_get_intfdata(intf);
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
index 693fd3e..89d2e84 100644
--- a/drivers/hid/usbhid/usbhid.h
+++ b/drivers/hid/usbhid/usbhid.h
@@ -42,6 +42,7 @@
(struct hid_device *hid, struct hid_report *report, unsigned char dir);
int usbhid_get_power(struct hid_device *hid);
void usbhid_put_power(struct hid_device *hid);
+struct usb_interface *usbhid_find_interface(int minor);
/* iofl flags */
#define HID_CTRL_RUNNING 1
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 4d4d09b..97499d0 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -409,7 +409,7 @@
config SENSORS_PKGTEMP
tristate "Intel processor package temperature sensor"
- depends on X86 && PCI && EXPERIMENTAL
+ depends on X86 && EXPERIMENTAL
help
If you say yes here you get support for the package level temperature
sensor inside your CPU. Check documentation/driver for details.
diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c
index 15c1a96..0683e6b 100644
--- a/drivers/hwmon/adm1031.c
+++ b/drivers/hwmon/adm1031.c
@@ -79,7 +79,7 @@
int chip_type;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
- unsigned int update_rate; /* In milliseconds */
+ unsigned int update_interval; /* In milliseconds */
/* The chan_select_table contains the possible configurations for
* auto fan control.
*/
@@ -743,23 +743,23 @@
static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 13);
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 14);
-/* Update Rate */
-static const unsigned int update_rates[] = {
+/* Update Interval */
+static const unsigned int update_intervals[] = {
16000, 8000, 4000, 2000, 1000, 500, 250, 125,
};
-static ssize_t show_update_rate(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t show_update_interval(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct adm1031_data *data = i2c_get_clientdata(client);
- return sprintf(buf, "%u\n", data->update_rate);
+ return sprintf(buf, "%u\n", data->update_interval);
}
-static ssize_t set_update_rate(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t set_update_interval(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct adm1031_data *data = i2c_get_clientdata(client);
@@ -771,12 +771,15 @@
if (err)
return err;
- /* find the nearest update rate from the table */
- for (i = 0; i < ARRAY_SIZE(update_rates) - 1; i++) {
- if (val >= update_rates[i])
+ /*
+ * Find the nearest update interval from the table.
+ * Use it to determine the matching update rate.
+ */
+ for (i = 0; i < ARRAY_SIZE(update_intervals) - 1; i++) {
+ if (val >= update_intervals[i])
break;
}
- /* if not found, we point to the last entry (lowest update rate) */
+ /* if not found, we point to the last entry (lowest update interval) */
/* set the new update rate while preserving other settings */
reg = adm1031_read_value(client, ADM1031_REG_FAN_FILTER);
@@ -785,14 +788,14 @@
adm1031_write_value(client, ADM1031_REG_FAN_FILTER, reg);
mutex_lock(&data->update_lock);
- data->update_rate = update_rates[i];
+ data->update_interval = update_intervals[i];
mutex_unlock(&data->update_lock);
return count;
}
-static DEVICE_ATTR(update_rate, S_IRUGO | S_IWUSR, show_update_rate,
- set_update_rate);
+static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval,
+ set_update_interval);
static struct attribute *adm1031_attributes[] = {
&sensor_dev_attr_fan1_input.dev_attr.attr,
@@ -830,7 +833,7 @@
&sensor_dev_attr_auto_fan1_min_pwm.dev_attr.attr,
- &dev_attr_update_rate.attr,
+ &dev_attr_update_interval.attr,
&dev_attr_alarms.attr,
NULL
@@ -981,7 +984,8 @@
mask = ADM1031_UPDATE_RATE_MASK;
read_val = adm1031_read_value(client, ADM1031_REG_FAN_FILTER);
i = (read_val & mask) >> ADM1031_UPDATE_RATE_SHIFT;
- data->update_rate = update_rates[i];
+ /* Save it as update interval */
+ data->update_interval = update_intervals[i];
}
static struct adm1031_data *adm1031_update_device(struct device *dev)
@@ -993,7 +997,8 @@
mutex_lock(&data->update_lock);
- next_update = data->last_updated + msecs_to_jiffies(data->update_rate);
+ next_update = data->last_updated
+ + msecs_to_jiffies(data->update_interval);
if (time_after(jiffies, next_update) || !data->valid) {
dev_dbg(&client->dev, "Starting adm1031 update\n");
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index de81111..a23b17a 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -36,6 +36,7 @@
#include <linux/pci.h>
#include <asm/msr.h>
#include <asm/processor.h>
+#include <asm/smp.h>
#define DRVNAME "coretemp"
@@ -423,9 +424,18 @@
int err;
struct platform_device *pdev;
struct pdev_entry *pdev_entry;
-#ifdef CONFIG_SMP
struct cpuinfo_x86 *c = &cpu_data(cpu);
-#endif
+
+ /*
+ * CPUID.06H.EAX[0] indicates whether the CPU has thermal
+ * sensors. We check this bit only, all the early CPUs
+ * without thermal sensors will be filtered out.
+ */
+ if (!cpu_has(c, X86_FEATURE_DTS)) {
+ printk(KERN_INFO DRVNAME ": CPU (model=0x%x)"
+ " has no thermal sensor.\n", c->x86_model);
+ return 0;
+ }
mutex_lock(&pdev_list_mutex);
@@ -482,14 +492,22 @@
static void coretemp_device_remove(unsigned int cpu)
{
- struct pdev_entry *p, *n;
+ struct pdev_entry *p;
+ unsigned int i;
+
mutex_lock(&pdev_list_mutex);
- list_for_each_entry_safe(p, n, &pdev_list, list) {
- if (p->cpu == cpu) {
- platform_device_unregister(p->pdev);
- list_del(&p->list);
- kfree(p);
- }
+ list_for_each_entry(p, &pdev_list, list) {
+ if (p->cpu != cpu)
+ continue;
+
+ platform_device_unregister(p->pdev);
+ list_del(&p->list);
+ mutex_unlock(&pdev_list_mutex);
+ kfree(p);
+ for_each_cpu(i, cpu_sibling_mask(cpu))
+ if (i != cpu && !coretemp_device_add(i))
+ break;
+ return;
}
mutex_unlock(&pdev_list_mutex);
}
@@ -527,30 +545,21 @@
if (err)
goto exit;
- for_each_online_cpu(i) {
- struct cpuinfo_x86 *c = &cpu_data(i);
- /*
- * CPUID.06H.EAX[0] indicates whether the CPU has thermal
- * sensors. We check this bit only, all the early CPUs
- * without thermal sensors will be filtered out.
- */
- if (c->cpuid_level >= 6 && (cpuid_eax(0x06) & 0x01))
- coretemp_device_add(i);
- else {
- printk(KERN_INFO DRVNAME ": CPU (model=0x%x)"
- " has no thermal sensor.\n", c->x86_model);
- }
- }
+ for_each_online_cpu(i)
+ coretemp_device_add(i);
+
+#ifndef CONFIG_HOTPLUG_CPU
if (list_empty(&pdev_list)) {
err = -ENODEV;
goto exit_driver_unreg;
}
+#endif
register_hotcpu_notifier(&coretemp_cpu_notifier);
return 0;
-exit_driver_unreg:
#ifndef CONFIG_HOTPLUG_CPU
+exit_driver_unreg:
platform_driver_unregister(&coretemp_driver);
#endif
exit:
diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c
index 5b58b20..8dee3f3 100644
--- a/drivers/hwmon/emc1403.c
+++ b/drivers/hwmon/emc1403.c
@@ -308,7 +308,6 @@
res = sysfs_create_group(&client->dev.kobj, &m_thermal_gr);
if (res) {
dev_warn(&client->dev, "create group failed\n");
- hwmon_device_unregister(data->hwmon_dev);
goto thermal_error1;
}
data->hwmon_dev = hwmon_device_register(&client->dev);
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c
index 537841e..75afb3b 100644
--- a/drivers/hwmon/f71882fg.c
+++ b/drivers/hwmon/f71882fg.c
@@ -111,7 +111,7 @@
/* Super-I/O Function prototypes */
static inline int superio_inb(int base, int reg);
static inline int superio_inw(int base, int reg);
-static inline void superio_enter(int base);
+static inline int superio_enter(int base);
static inline void superio_select(int base, int ld);
static inline void superio_exit(int base);
@@ -861,11 +861,20 @@
return val;
}
-static inline void superio_enter(int base)
+static inline int superio_enter(int base)
{
+ /* Don't step on other drivers' I/O space by accident */
+ if (!request_muxed_region(base, 2, DRVNAME)) {
+ printk(KERN_ERR DRVNAME ": I/O address 0x%04x already in use\n",
+ base);
+ return -EBUSY;
+ }
+
/* according to the datasheet the key must be send twice! */
outb(SIO_UNLOCK_KEY, base);
outb(SIO_UNLOCK_KEY, base);
+
+ return 0;
}
static inline void superio_select(int base, int ld)
@@ -877,6 +886,7 @@
static inline void superio_exit(int base)
{
outb(SIO_LOCK_KEY, base);
+ release_region(base, 2);
}
static inline int fan_from_reg(u16 reg)
@@ -2175,21 +2185,15 @@
static int __init f71882fg_find(int sioaddr, unsigned short *address,
struct f71882fg_sio_data *sio_data)
{
- int err = -ENODEV;
u16 devid;
-
- /* Don't step on other drivers' I/O space by accident */
- if (!request_region(sioaddr, 2, DRVNAME)) {
- printk(KERN_ERR DRVNAME ": I/O address 0x%04x already in use\n",
- (int)sioaddr);
- return -EBUSY;
- }
-
- superio_enter(sioaddr);
+ int err = superio_enter(sioaddr);
+ if (err)
+ return err;
devid = superio_inw(sioaddr, SIO_REG_MANID);
if (devid != SIO_FINTEK_ID) {
pr_debug(DRVNAME ": Not a Fintek device\n");
+ err = -ENODEV;
goto exit;
}
@@ -2213,6 +2217,7 @@
default:
printk(KERN_INFO DRVNAME ": Unsupported Fintek device: %04x\n",
(unsigned int)devid);
+ err = -ENODEV;
goto exit;
}
@@ -2223,12 +2228,14 @@
if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
printk(KERN_WARNING DRVNAME ": Device not activated\n");
+ err = -ENODEV;
goto exit;
}
*address = superio_inw(sioaddr, SIO_REG_ADDR);
if (*address == 0) {
printk(KERN_WARNING DRVNAME ": Base address not set\n");
+ err = -ENODEV;
goto exit;
}
*address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
@@ -2239,7 +2246,6 @@
(int)superio_inb(sioaddr, SIO_REG_DEVREV));
exit:
superio_exit(sioaddr);
- release_region(sioaddr, 2);
return err;
}
diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c
index 0f58ecc..9638d58 100644
--- a/drivers/hwmon/f75375s.c
+++ b/drivers/hwmon/f75375s.c
@@ -79,7 +79,7 @@
#define F75375_REG_PWM2_DROP_DUTY 0x6C
#define FAN_CTRL_LINEAR(nr) (4 + nr)
-#define FAN_CTRL_MODE(nr) (5 + ((nr) * 2))
+#define FAN_CTRL_MODE(nr) (4 + ((nr) * 2))
/*
* Data structures and manipulation thereof
@@ -298,7 +298,7 @@
return -EINVAL;
fanmode = f75375_read8(client, F75375_REG_FAN_TIMER);
- fanmode = ~(3 << FAN_CTRL_MODE(nr));
+ fanmode &= ~(3 << FAN_CTRL_MODE(nr));
switch (val) {
case 0: /* Full speed */
@@ -350,7 +350,7 @@
mutex_lock(&data->update_lock);
conf = f75375_read8(client, F75375_REG_CONFIG1);
- conf = ~(1 << FAN_CTRL_LINEAR(nr));
+ conf &= ~(1 << FAN_CTRL_LINEAR(nr));
if (val == 0)
conf |= (1 << FAN_CTRL_LINEAR(nr)) ;
diff --git a/drivers/hwmon/lis3lv02d.c b/drivers/hwmon/lis3lv02d.c
index 6138f03..fc591ae 100644
--- a/drivers/hwmon/lis3lv02d.c
+++ b/drivers/hwmon/lis3lv02d.c
@@ -277,7 +277,7 @@
wake_up_interruptible(&lis3_dev.misc_wait);
kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN);
out:
- if (lis3_dev.whoami == WAI_8B && lis3_dev.idev &&
+ if (lis3_dev.pdata && lis3_dev.whoami == WAI_8B && lis3_dev.idev &&
lis3_dev.idev->input->users)
return IRQ_WAKE_THREAD;
return IRQ_HANDLED;
@@ -718,7 +718,7 @@
* io-apic is not configurable (and generates a warning) but I keep it
* in case of support for other hardware.
*/
- if (dev->whoami == WAI_8B)
+ if (dev->pdata && dev->whoami == WAI_8B)
thread_fn = lis302dl_interrupt_thread1_8b;
else
thread_fn = NULL;
diff --git a/drivers/hwmon/lis3lv02d_i2c.c b/drivers/hwmon/lis3lv02d_i2c.c
index dc1f540..8e5933b 100644
--- a/drivers/hwmon/lis3lv02d_i2c.c
+++ b/drivers/hwmon/lis3lv02d_i2c.c
@@ -121,7 +121,7 @@
{
struct lis3lv02d *lis3 = i2c_get_clientdata(client);
- if (!lis3->pdata->wakeup_flags)
+ if (!lis3->pdata || !lis3->pdata->wakeup_flags)
lis3lv02d_poweroff(lis3);
return 0;
}
@@ -130,7 +130,7 @@
{
struct lis3lv02d *lis3 = i2c_get_clientdata(client);
- if (!lis3->pdata->wakeup_flags)
+ if (!lis3->pdata || !lis3->pdata->wakeup_flags)
lis3lv02d_poweron(lis3);
return 0;
}
diff --git a/drivers/hwmon/lis3lv02d_spi.c b/drivers/hwmon/lis3lv02d_spi.c
index 82b1680..b9be5e3 100644
--- a/drivers/hwmon/lis3lv02d_spi.c
+++ b/drivers/hwmon/lis3lv02d_spi.c
@@ -92,7 +92,7 @@
{
struct lis3lv02d *lis3 = spi_get_drvdata(spi);
- if (!lis3->pdata->wakeup_flags)
+ if (!lis3->pdata || !lis3->pdata->wakeup_flags)
lis3lv02d_poweroff(&lis3_dev);
return 0;
@@ -102,7 +102,7 @@
{
struct lis3lv02d *lis3 = spi_get_drvdata(spi);
- if (!lis3->pdata->wakeup_flags)
+ if (!lis3->pdata || !lis3->pdata->wakeup_flags)
lis3lv02d_poweron(lis3);
return 0;
diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c
index 94741d4..464340f 100644
--- a/drivers/hwmon/lm95241.c
+++ b/drivers/hwmon/lm95241.c
@@ -91,7 +91,7 @@
struct lm95241_data {
struct device *hwmon_dev;
struct mutex update_lock;
- unsigned long last_updated, rate; /* in jiffies */
+ unsigned long last_updated, interval; /* in jiffies */
char valid; /* zero until following fields are valid */
/* registers values */
u8 local_h, local_l; /* local */
@@ -114,23 +114,23 @@
show_temp(remote1);
show_temp(remote2);
-static ssize_t show_rate(struct device *dev, struct device_attribute *attr,
+static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct lm95241_data *data = lm95241_update_device(dev);
- snprintf(buf, PAGE_SIZE - 1, "%lu\n", 1000 * data->rate / HZ);
+ snprintf(buf, PAGE_SIZE - 1, "%lu\n", 1000 * data->interval / HZ);
return strlen(buf);
}
-static ssize_t set_rate(struct device *dev, struct device_attribute *attr,
+static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm95241_data *data = i2c_get_clientdata(client);
- strict_strtol(buf, 10, &data->rate);
- data->rate = data->rate * HZ / 1000;
+ strict_strtol(buf, 10, &data->interval);
+ data->interval = data->interval * HZ / 1000;
return count;
}
@@ -286,7 +286,8 @@
static DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_min2, set_min2);
static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_max1, set_max1);
static DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_max2, set_max2);
-static DEVICE_ATTR(rate, S_IWUSR | S_IRUGO, show_rate, set_rate);
+static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval,
+ set_interval);
static struct attribute *lm95241_attributes[] = {
&dev_attr_temp1_input.attr,
@@ -298,7 +299,7 @@
&dev_attr_temp3_min.attr,
&dev_attr_temp2_max.attr,
&dev_attr_temp3_max.attr,
- &dev_attr_rate.attr,
+ &dev_attr_update_interval.attr,
NULL
};
@@ -376,7 +377,7 @@
{
struct lm95241_data *data = i2c_get_clientdata(client);
- data->rate = HZ; /* 1 sec default */
+ data->interval = HZ; /* 1 sec default */
data->valid = 0;
data->config = CFG_CR0076;
data->model = 0;
@@ -410,7 +411,7 @@
mutex_lock(&data->update_lock);
- if (time_after(jiffies, data->last_updated + data->rate) ||
+ if (time_after(jiffies, data->last_updated + data->interval) ||
!data->valid) {
dev_dbg(&client->dev, "Updating lm95241 data.\n");
data->local_h =
diff --git a/drivers/hwmon/pkgtemp.c b/drivers/hwmon/pkgtemp.c
index 74157fc..f119039 100644
--- a/drivers/hwmon/pkgtemp.c
+++ b/drivers/hwmon/pkgtemp.c
@@ -33,7 +33,6 @@
#include <linux/list.h>
#include <linux/platform_device.h>
#include <linux/cpu.h>
-#include <linux/pci.h>
#include <asm/msr.h>
#include <asm/processor.h>
@@ -224,7 +223,7 @@
err = sysfs_create_group(&pdev->dev.kobj, &pkgtemp_group);
if (err)
- goto exit_free;
+ goto exit_dev;
data->hwmon_dev = hwmon_device_register(&pdev->dev);
if (IS_ERR(data->hwmon_dev)) {
@@ -238,6 +237,8 @@
exit_class:
sysfs_remove_group(&pdev->dev.kobj, &pkgtemp_group);
+exit_dev:
+ device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
exit_free:
kfree(data);
exit:
@@ -250,6 +251,7 @@
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &pkgtemp_group);
+ device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
platform_set_drvdata(pdev, NULL);
kfree(data);
return 0;
@@ -281,9 +283,10 @@
int err;
struct platform_device *pdev;
struct pdev_entry *pdev_entry;
-#ifdef CONFIG_SMP
struct cpuinfo_x86 *c = &cpu_data(cpu);
-#endif
+
+ if (!cpu_has(c, X86_FEATURE_PTS))
+ return 0;
mutex_lock(&pdev_list_mutex);
@@ -339,17 +342,18 @@
#ifdef CONFIG_HOTPLUG_CPU
static void pkgtemp_device_remove(unsigned int cpu)
{
- struct pdev_entry *p, *n;
+ struct pdev_entry *p;
unsigned int i;
int err;
mutex_lock(&pdev_list_mutex);
- list_for_each_entry_safe(p, n, &pdev_list, list) {
+ list_for_each_entry(p, &pdev_list, list) {
if (p->cpu != cpu)
continue;
platform_device_unregister(p->pdev);
list_del(&p->list);
+ mutex_unlock(&pdev_list_mutex);
kfree(p);
for_each_cpu(i, cpu_core_mask(cpu)) {
if (i != cpu) {
@@ -358,7 +362,7 @@
break;
}
}
- break;
+ return;
}
mutex_unlock(&pdev_list_mutex);
}
@@ -399,11 +403,6 @@
goto exit;
for_each_online_cpu(i) {
- struct cpuinfo_x86 *c = &cpu_data(i);
-
- if (!cpu_has(c, X86_FEATURE_PTS))
- continue;
-
err = pkgtemp_device_add(i);
if (err)
goto exit_devices_unreg;
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index e96e69d..072c580 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -127,6 +127,7 @@
static inline void
superio_exit(int ioreg)
{
+ outb(0xaa, ioreg);
outb(0x02, ioreg);
outb(0x02, ioreg + 1);
}
diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c
index f7bd261..f2de3be 100644
--- a/drivers/i2c/busses/i2c-cpm.c
+++ b/drivers/i2c/busses/i2c-cpm.c
@@ -677,6 +677,11 @@
dev_dbg(&ofdev->dev, "hw routines for %s registered.\n",
cpm->adap.name);
+ /*
+ * register OF I2C devices
+ */
+ of_i2c_register_devices(&cpm->adap);
+
return 0;
out_shut:
cpm_i2c_shutdown(cpm);
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index 2222c87..5795c83 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -331,21 +331,16 @@
INIT_COMPLETION(dev->cmd_complete);
dev->cmd_err = 0;
- /* Take I2C out of reset, configure it as master and set the
- * start bit */
- flag = DAVINCI_I2C_MDR_IRS | DAVINCI_I2C_MDR_MST | DAVINCI_I2C_MDR_STT;
+ /* Take I2C out of reset and configure it as master */
+ flag = DAVINCI_I2C_MDR_IRS | DAVINCI_I2C_MDR_MST;
/* if the slave address is ten bit address, enable XA bit */
if (msg->flags & I2C_M_TEN)
flag |= DAVINCI_I2C_MDR_XA;
if (!(msg->flags & I2C_M_RD))
flag |= DAVINCI_I2C_MDR_TRX;
- if (stop)
- flag |= DAVINCI_I2C_MDR_STP;
- if (msg->len == 0) {
+ if (msg->len == 0)
flag |= DAVINCI_I2C_MDR_RM;
- flag &= ~DAVINCI_I2C_MDR_STP;
- }
/* Enable receive or transmit interrupts */
w = davinci_i2c_read_reg(dev, DAVINCI_I2C_IMR_REG);
@@ -357,7 +352,11 @@
dev->terminate = 0;
- /* write the data into mode register */
+ /*
+ * Write mode register first as needed for correct behaviour
+ * on OMAP-L138, but don't set STT yet to avoid a race with XRDY
+ * occuring before we have loaded DXR
+ */
davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
/*
@@ -365,12 +364,19 @@
* because transmit-data-ready interrupt can come before
* NACK-interrupt during sending of previous message and
* ICDXR may have wrong data
+ * It also saves us one interrupt, slightly faster
*/
if ((!(msg->flags & I2C_M_RD)) && dev->buf_len) {
davinci_i2c_write_reg(dev, DAVINCI_I2C_DXR_REG, *dev->buf++);
dev->buf_len--;
}
+ /* Set STT to begin transmit now DXR is loaded */
+ flag |= DAVINCI_I2C_MDR_STT;
+ if (stop && msg->len != 0)
+ flag |= DAVINCI_I2C_MDR_STP;
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
+
r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
dev->adapter.timeout);
if (r == 0) {
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
index 43ca32f..89eedf4 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.c
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -761,6 +761,9 @@
dev_info(&ofdev->dev, "using %s mode\n",
dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)");
+ /* Now register all the child nodes */
+ of_i2c_register_devices(adap);
+
return 0;
error_cleanup:
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index d1ff940..4c2a62b 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -159,15 +159,9 @@
static int i2c_imx_trx_complete(struct imx_i2c_struct *i2c_imx)
{
- int result;
+ wait_event_timeout(i2c_imx->queue, i2c_imx->i2csr & I2SR_IIF, HZ / 10);
- result = wait_event_interruptible_timeout(i2c_imx->queue,
- i2c_imx->i2csr & I2SR_IIF, HZ / 10);
-
- if (unlikely(result < 0)) {
- dev_dbg(&i2c_imx->adapter.dev, "<%s> result < 0\n", __func__);
- return result;
- } else if (unlikely(!(i2c_imx->i2csr & I2SR_IIF))) {
+ if (unlikely(!(i2c_imx->i2csr & I2SR_IIF))) {
dev_dbg(&i2c_imx->adapter.dev, "<%s> Timeout\n", __func__);
return -ETIMEDOUT;
}
@@ -295,7 +289,7 @@
i2c_imx->i2csr = temp;
temp &= ~I2SR_IIF;
writeb(temp, i2c_imx->base + IMX_I2C_I2SR);
- wake_up_interruptible(&i2c_imx->queue);
+ wake_up(&i2c_imx->queue);
return IRQ_HANDLED;
}
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index a1c419a..b74e6dc 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -632,6 +632,7 @@
dev_err(i2c->dev, "failed to add adapter\n");
goto fail_add;
}
+ of_i2c_register_devices(&i2c->adap);
return result;
diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index 0e9f85d..56dbe54 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -218,7 +218,7 @@
return result;
} else if (result == 0) {
dev_dbg(i2c->dev, "%s: timeout\n", __func__);
- result = -ETIMEDOUT;
+ return -ETIMEDOUT;
}
return 0;
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 7674efb..b33c785 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -680,6 +680,8 @@
if (r == 0)
r = num;
+
+ omap_i2c_wait_for_bb(dev);
out:
omap_i2c_idle(dev);
return r;
diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c
index bbd7760..29933f8 100644
--- a/drivers/i2c/busses/i2c-pca-isa.c
+++ b/drivers/i2c/busses/i2c-pca-isa.c
@@ -71,8 +71,8 @@
static int pca_isa_waitforcompletion(void *pd)
{
- long ret = ~0;
unsigned long timeout;
+ long ret;
if (irq > -1) {
ret = wait_event_timeout(pca_wait,
@@ -81,11 +81,15 @@
} else {
/* Do polling */
timeout = jiffies + pca_isa_ops.timeout;
- while (((pca_isa_readbyte(pd, I2C_PCA_CON)
- & I2C_PCA_CON_SI) == 0)
- && (ret = time_before(jiffies, timeout)))
+ do {
+ ret = time_before(jiffies, timeout);
+ if (pca_isa_readbyte(pd, I2C_PCA_CON)
+ & I2C_PCA_CON_SI)
+ break;
udelay(100);
+ } while (ret);
}
+
return ret > 0;
}
diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c
index ef5c784..5f6d7f8 100644
--- a/drivers/i2c/busses/i2c-pca-platform.c
+++ b/drivers/i2c/busses/i2c-pca-platform.c
@@ -80,8 +80,8 @@
static int i2c_pca_pf_waitforcompletion(void *pd)
{
struct i2c_pca_pf_data *i2c = pd;
- long ret = ~0;
unsigned long timeout;
+ long ret;
if (i2c->irq) {
ret = wait_event_timeout(i2c->wait,
@@ -90,10 +90,13 @@
} else {
/* Do polling */
timeout = jiffies + i2c->adap.timeout;
- while (((i2c->algo_data.read_byte(i2c, I2C_PCA_CON)
- & I2C_PCA_CON_SI) == 0)
- && (ret = time_before(jiffies, timeout)))
+ do {
+ ret = time_before(jiffies, timeout);
+ if (i2c->algo_data.read_byte(i2c, I2C_PCA_CON)
+ & I2C_PCA_CON_SI)
+ break;
udelay(100);
+ } while (ret);
}
return ret > 0;
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 72902e0..bf831bf 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -662,8 +662,8 @@
unsigned long sda_delay;
if (pdata->sda_delay) {
- sda_delay = (freq / 1000) * pdata->sda_delay;
- sda_delay /= 1000000;
+ sda_delay = clkin * pdata->sda_delay;
+ sda_delay = DIV_ROUND_UP(sda_delay, 1000000);
sda_delay = DIV_ROUND_UP(sda_delay, 5);
if (sda_delay > 3)
sda_delay = 3;
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 6649176..bea4c50 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -32,7 +32,6 @@
#include <linux/init.h>
#include <linux/idr.h>
#include <linux/mutex.h>
-#include <linux/of_i2c.h>
#include <linux/of_device.h>
#include <linux/completion.h>
#include <linux/hardirq.h>
@@ -197,11 +196,12 @@
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
- if (pm_runtime_suspended(dev))
- return 0;
-
- if (pm)
- return pm->suspend ? pm->suspend(dev) : 0;
+ if (pm) {
+ if (pm_runtime_suspended(dev))
+ return 0;
+ else
+ return pm->suspend ? pm->suspend(dev) : 0;
+ }
return i2c_legacy_suspend(dev, PMSG_SUSPEND);
}
@@ -216,12 +216,6 @@
else
ret = i2c_legacy_resume(dev);
- if (!ret) {
- pm_runtime_disable(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
- }
-
return ret;
}
@@ -229,11 +223,12 @@
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
- if (pm_runtime_suspended(dev))
- return 0;
-
- if (pm)
- return pm->freeze ? pm->freeze(dev) : 0;
+ if (pm) {
+ if (pm_runtime_suspended(dev))
+ return 0;
+ else
+ return pm->freeze ? pm->freeze(dev) : 0;
+ }
return i2c_legacy_suspend(dev, PMSG_FREEZE);
}
@@ -242,11 +237,12 @@
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
- if (pm_runtime_suspended(dev))
- return 0;
-
- if (pm)
- return pm->thaw ? pm->thaw(dev) : 0;
+ if (pm) {
+ if (pm_runtime_suspended(dev))
+ return 0;
+ else
+ return pm->thaw ? pm->thaw(dev) : 0;
+ }
return i2c_legacy_resume(dev);
}
@@ -255,11 +251,12 @@
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
- if (pm_runtime_suspended(dev))
- return 0;
-
- if (pm)
- return pm->poweroff ? pm->poweroff(dev) : 0;
+ if (pm) {
+ if (pm_runtime_suspended(dev))
+ return 0;
+ else
+ return pm->poweroff ? pm->poweroff(dev) : 0;
+ }
return i2c_legacy_suspend(dev, PMSG_HIBERNATE);
}
@@ -876,9 +873,6 @@
if (adap->nr < __i2c_first_dynamic_bus_num)
i2c_scan_static_board_info(adap);
- /* Register devices from the device tree */
- of_i2c_register_devices(adap);
-
/* Notify drivers */
mutex_lock(&core_lock);
bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 4c3d1bf..068cef0 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -1448,19 +1448,13 @@
if (hwif == NULL)
continue;
- if (hwif->present)
- hwif_register_devices(hwif);
- }
-
- ide_host_for_each_port(i, hwif, host) {
- if (hwif == NULL)
- continue;
-
ide_sysfs_register_port(hwif);
ide_proc_register_port(hwif);
- if (hwif->present)
+ if (hwif->present) {
ide_proc_port_register_devices(hwif);
+ hwif_register_devices(hwif);
+ }
}
return j ? 0 : -1;
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
old mode 100755
new mode 100644
index a10152b..c37ef64
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -83,7 +83,7 @@
/* Reliable LAPIC Timer States, bit 1 for C1 etc. */
static unsigned int lapic_timer_reliable_states;
-static struct cpuidle_device *intel_idle_cpuidle_devices;
+static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state);
static struct cpuidle_state *cpuidle_state_table;
@@ -108,7 +108,7 @@
.name = "NHM-C3",
.desc = "MWAIT 0x10",
.driver_data = (void *) 0x10,
- .flags = CPUIDLE_FLAG_TIME_VALID,
+ .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 20,
.power_usage = 500,
.target_residency = 80,
@@ -117,7 +117,7 @@
.name = "NHM-C6",
.desc = "MWAIT 0x20",
.driver_data = (void *) 0x20,
- .flags = CPUIDLE_FLAG_TIME_VALID,
+ .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 200,
.power_usage = 350,
.target_residency = 800,
@@ -149,7 +149,7 @@
.name = "ATM-C4",
.desc = "MWAIT 0x30",
.driver_data = (void *) 0x30,
- .flags = CPUIDLE_FLAG_TIME_VALID,
+ .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 100,
.power_usage = 250,
.target_residency = 400,
@@ -157,13 +157,13 @@
{ /* MWAIT C5 */ },
{ /* MWAIT C6 */
.name = "ATM-C6",
- .desc = "MWAIT 0x40",
- .driver_data = (void *) 0x40,
- .flags = CPUIDLE_FLAG_TIME_VALID,
- .exit_latency = 200,
+ .desc = "MWAIT 0x52",
+ .driver_data = (void *) 0x52,
+ .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .exit_latency = 140,
.power_usage = 150,
- .target_residency = 800,
- .enter = NULL }, /* disabled */
+ .target_residency = 560,
+ .enter = &intel_idle },
};
/**
@@ -185,6 +185,16 @@
local_irq_disable();
+ /*
+ * If the state flag indicates that the TLB will be flushed or if this
+ * is the deepest c-state supported, do a voluntary leave mm to avoid
+ * costly and mostly unnecessary wakeups for flushing the user TLB's
+ * associated with the active mm.
+ */
+ if (state->flags & CPUIDLE_FLAG_TLB_FLUSHED ||
+ (&dev->states[dev->state_count - 1] == state))
+ leave_mm(cpu);
+
if (!(lapic_timer_reliable_states & (1 << (cstate))))
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index d88077a..13c8887 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -463,7 +463,8 @@
V_MSS_IDX(mtu_idx) |
V_L2T_IDX(ep->l2t->idx) | V_TX_CHANNEL(ep->l2t->smt_idx);
opt0l = V_TOS((ep->tos >> 2) & M_TOS) | V_RCV_BUFSIZ(rcv_win>>10);
- opt2 = V_FLAVORS_VALID(1) | V_CONG_CONTROL_FLAVOR(cong_flavor);
+ opt2 = F_RX_COALESCE_VALID | V_RX_COALESCE(0) | V_FLAVORS_VALID(1) |
+ V_CONG_CONTROL_FLAVOR(cong_flavor);
skb->priority = CPL_PRIORITY_SETUP;
set_arp_failure_handler(skb, act_open_req_arp_failure);
@@ -1280,7 +1281,8 @@
V_MSS_IDX(mtu_idx) |
V_L2T_IDX(ep->l2t->idx) | V_TX_CHANNEL(ep->l2t->smt_idx);
opt0l = V_TOS((ep->tos >> 2) & M_TOS) | V_RCV_BUFSIZ(rcv_win>>10);
- opt2 = V_FLAVORS_VALID(1) | V_CONG_CONTROL_FLAVOR(cong_flavor);
+ opt2 = F_RX_COALESCE_VALID | V_RX_COALESCE(0) | V_FLAVORS_VALID(1) |
+ V_CONG_CONTROL_FLAVOR(cong_flavor);
rpl = cplhdr(skb);
rpl->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index c908c5f..9ddafc3 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -669,6 +669,9 @@
if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
+ if (!dev->absinfo)
+ return -EINVAL;
+
t = _IOC_NR(cmd) & ABS_MAX;
abs = dev->absinfo[t];
@@ -680,10 +683,13 @@
}
}
- if (_IOC_DIR(cmd) == _IOC_READ) {
+ if (_IOC_DIR(cmd) == _IOC_WRITE) {
if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
+ if (!dev->absinfo)
+ return -EINVAL;
+
t = _IOC_NR(cmd) & ABS_MAX;
if (copy_from_user(&abs, p, min_t(size_t,
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index d85bd8a..22239e9 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -483,6 +483,9 @@
memcpy(joydev->abspam, abspam, len);
+ for (i = 0; i < joydev->nabs; i++)
+ joydev->absmap[joydev->abspam[i]] = i;
+
out:
kfree(abspam);
return retval;
diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c
index 4f9b2af..014dd4a 100644
--- a/drivers/input/misc/twl4030-vibra.c
+++ b/drivers/input/misc/twl4030-vibra.c
@@ -271,7 +271,7 @@
.probe = twl4030_vibra_probe,
.remove = __devexit_p(twl4030_vibra_remove),
.driver = {
- .name = "twl4030_codec_vibra",
+ .name = "twl4030-vibra",
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &twl4030_vibra_pm_ops,
@@ -291,7 +291,7 @@
}
module_exit(twl4030_vibra_exit);
-MODULE_ALIAS("platform:twl4030_codec_vibra");
+MODULE_ALIAS("platform:twl4030-vibra");
MODULE_DESCRIPTION("TWL4030 Vibra driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 0d4266a..3606985 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -404,6 +404,13 @@
retval = uinput_validate_absbits(dev);
if (retval < 0)
goto exit;
+ if (test_bit(ABS_MT_SLOT, dev->absbit)) {
+ int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
+ input_mt_create_slots(dev, nslot);
+ input_set_events_per_packet(dev, 6 * nslot);
+ } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
+ input_set_events_per_packet(dev, 60);
+ }
}
udev->state = UIST_SETUP_COMPLETE;
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index 42ba369..b35876e 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -103,27 +103,26 @@
static int wacom_open(struct input_dev *dev)
{
struct wacom *wacom = input_get_drvdata(dev);
+ int retval = 0;
+
+ if (usb_autopm_get_interface(wacom->intf) < 0)
+ return -EIO;
mutex_lock(&wacom->lock);
- wacom->irq->dev = wacom->usbdev;
-
- if (usb_autopm_get_interface(wacom->intf) < 0) {
- mutex_unlock(&wacom->lock);
- return -EIO;
- }
-
if (usb_submit_urb(wacom->irq, GFP_KERNEL)) {
- usb_autopm_put_interface(wacom->intf);
- mutex_unlock(&wacom->lock);
- return -EIO;
+ retval = -EIO;
+ goto out;
}
wacom->open = true;
wacom->intf->needs_remote_wakeup = 1;
+out:
mutex_unlock(&wacom->lock);
- return 0;
+ if (retval)
+ usb_autopm_put_interface(wacom->intf);
+ return retval;
}
static void wacom_close(struct input_dev *dev)
@@ -135,6 +134,8 @@
wacom->open = false;
wacom->intf->needs_remote_wakeup = 0;
mutex_unlock(&wacom->lock);
+
+ usb_autopm_put_interface(wacom->intf);
}
static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hid_desc,
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 6e29bad..47fd7a0 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -442,8 +442,10 @@
/* general pen packet */
if ((data[1] & 0xb8) == 0xa0) {
t = (data[6] << 2) | ((data[7] >> 6) & 3);
- if (features->type >= INTUOS4S && features->type <= INTUOS4L)
+ if ((features->type >= INTUOS4S && features->type <= INTUOS4L) ||
+ features->type == WACOM_21UX2) {
t = (t << 1) | (data[1] & 1);
+ }
input_report_abs(input, ABS_PRESSURE, t);
input_report_abs(input, ABS_TILT_X,
((data[7] << 1) & 0x7e) | (data[8] >> 7));
diff --git a/drivers/isdn/sc/interrupt.c b/drivers/isdn/sc/interrupt.c
index 485be8b..f0225bc 100644
--- a/drivers/isdn/sc/interrupt.c
+++ b/drivers/isdn/sc/interrupt.c
@@ -112,11 +112,19 @@
}
else if(callid>=0x0000 && callid<=0x7FFF)
{
+ int len;
+
pr_debug("%s: Got Incoming Call\n",
sc_adapter[card]->devicename);
- strcpy(setup.phone,&(rcvmsg.msg_data.byte_array[4]));
- strcpy(setup.eazmsn,
- sc_adapter[card]->channel[rcvmsg.phy_link_no-1].dn);
+ len = strlcpy(setup.phone, &(rcvmsg.msg_data.byte_array[4]),
+ sizeof(setup.phone));
+ if (len >= sizeof(setup.phone))
+ continue;
+ len = strlcpy(setup.eazmsn,
+ sc_adapter[card]->channel[rcvmsg.phy_link_no - 1].dn,
+ sizeof(setup.eazmsn));
+ if (len >= sizeof(setup.eazmsn))
+ continue;
setup.si1 = 7;
setup.si2 = 0;
setup.plan = 0;
@@ -176,7 +184,9 @@
* Handle a GetMyNumber Rsp
*/
if (IS_CE_MESSAGE(rcvmsg,Call,0,GetMyNumber)){
- strcpy(sc_adapter[card]->channel[rcvmsg.phy_link_no-1].dn,rcvmsg.msg_data.byte_array);
+ strlcpy(sc_adapter[card]->channel[rcvmsg.phy_link_no - 1].dn,
+ rcvmsg.msg_data.byte_array,
+ sizeof(rcvmsg.msg_data.byte_array));
continue;
}
diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c
index 74dce4b..350eb34 100644
--- a/drivers/leds/leds-ns2.c
+++ b/drivers/leds/leds-ns2.c
@@ -81,7 +81,7 @@
int cmd_level;
int slow_level;
- read_lock(&led_dat->rw_lock);
+ read_lock_irq(&led_dat->rw_lock);
cmd_level = gpio_get_value(led_dat->cmd);
slow_level = gpio_get_value(led_dat->slow);
@@ -95,7 +95,7 @@
}
}
- read_unlock(&led_dat->rw_lock);
+ read_unlock_irq(&led_dat->rw_lock);
return ret;
}
@@ -104,8 +104,9 @@
enum ns2_led_modes mode)
{
int i;
+ unsigned long flags;
- write_lock(&led_dat->rw_lock);
+ write_lock_irqsave(&led_dat->rw_lock, flags);
for (i = 0; i < ARRAY_SIZE(ns2_led_modval); i++) {
if (mode == ns2_led_modval[i].mode) {
@@ -116,7 +117,7 @@
}
}
- write_unlock(&led_dat->rw_lock);
+ write_unlock_irqrestore(&led_dat->rw_lock, flags);
}
static void ns2_led_set(struct led_classdev *led_cdev,
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index ed4900a..e4fb58d 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -1000,10 +1000,11 @@
page = bitmap->sb_page;
offset = sizeof(bitmap_super_t);
if (!file)
- read_sb_page(bitmap->mddev,
- bitmap->mddev->bitmap_info.offset,
- page,
- index, count);
+ page = read_sb_page(
+ bitmap->mddev,
+ bitmap->mddev->bitmap_info.offset,
+ page,
+ index, count);
} else if (file) {
page = read_page(file, index, bitmap, count);
offset = 0;
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 43cf9cc..f20d13e 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1643,7 +1643,9 @@
bmask = queue_logical_block_size(rdev->bdev->bd_disk->queue)-1;
if (rdev->sb_size & bmask)
rdev->sb_size = (rdev->sb_size | bmask) + 1;
- }
+ } else
+ max_dev = le32_to_cpu(sb->max_dev);
+
for (i=0; i<max_dev;i++)
sb->dev_roles[i] = cpu_to_le16(0xfffe);
@@ -7069,7 +7071,7 @@
if (mddev->ro && !test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))
return;
if ( ! (
- (mddev->flags && !mddev->external) ||
+ (mddev->flags & ~ (1<<MD_CHANGE_PENDING)) ||
test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) ||
test_bit(MD_RECOVERY_DONE, &mddev->recovery) ||
(mddev->external == 0 && mddev->safemode == 1) ||
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index ad83a4d..0b830bb 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1839,7 +1839,9 @@
/* take from bio_init */
bio->bi_next = NULL;
+ bio->bi_flags &= ~(BIO_POOL_MASK-1);
bio->bi_flags |= 1 << BIO_UPTODATE;
+ bio->bi_comp_cpu = -1;
bio->bi_rw = READ;
bio->bi_vcnt = 0;
bio->bi_idx = 0;
@@ -1912,7 +1914,7 @@
!test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
break;
BUG_ON(sync_blocks < (PAGE_SIZE>>9));
- if (len > (sync_blocks<<9))
+ if ((len >> 9) > sync_blocks)
len = sync_blocks<<9;
}
diff --git a/drivers/media/IR/ir-keytable.c b/drivers/media/IR/ir-keytable.c
index 7e82a9d..7961d59 100644
--- a/drivers/media/IR/ir-keytable.c
+++ b/drivers/media/IR/ir-keytable.c
@@ -319,7 +319,7 @@
* a keyup event might follow immediately after the keydown.
*/
spin_lock_irqsave(&ir->keylock, flags);
- if (time_is_after_eq_jiffies(ir->keyup_jiffies))
+ if (time_is_before_eq_jiffies(ir->keyup_jiffies))
ir_keyup(ir);
spin_unlock_irqrestore(&ir->keylock, flags);
}
@@ -510,6 +510,13 @@
(ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_IR_RAW) ?
" in raw mode" : "");
+ /*
+ * Default delay of 250ms is too short for some protocols, expecially
+ * since the timeout is currently set to 250ms. Increase it to 500ms,
+ * to avoid wrong repetition of the keycodes.
+ */
+ input_dev->rep[REP_DELAY] = 500;
+
return 0;
out_event:
diff --git a/drivers/media/IR/ir-lirc-codec.c b/drivers/media/IR/ir-lirc-codec.c
index 77b5946..e63f757 100644
--- a/drivers/media/IR/ir-lirc-codec.c
+++ b/drivers/media/IR/ir-lirc-codec.c
@@ -267,7 +267,7 @@
features |= LIRC_CAN_SET_SEND_CARRIER;
if (ir_dev->props->s_tx_duty_cycle)
- features |= LIRC_CAN_SET_REC_DUTY_CYCLE;
+ features |= LIRC_CAN_SET_SEND_DUTY_CYCLE;
}
if (ir_dev->props->s_rx_carrier_range)
diff --git a/drivers/media/IR/ir-raw-event.c b/drivers/media/IR/ir-raw-event.c
index 43094e7..8e0e1b1 100644
--- a/drivers/media/IR/ir-raw-event.c
+++ b/drivers/media/IR/ir-raw-event.c
@@ -279,9 +279,11 @@
"rc%u", (unsigned int)ir->devno);
if (IS_ERR(ir->raw->thread)) {
+ int ret = PTR_ERR(ir->raw->thread);
+
kfree(ir->raw);
ir->raw = NULL;
- return PTR_ERR(ir->raw->thread);
+ return ret;
}
mutex_lock(&ir_raw_handler_lock);
diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c
index 96dafc4..46d4246 100644
--- a/drivers/media/IR/ir-sysfs.c
+++ b/drivers/media/IR/ir-sysfs.c
@@ -67,13 +67,14 @@
char *tmp = buf;
int i;
- if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) {
+ if (ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_SCANCODE) {
enabled = ir_dev->rc_tab.ir_type;
allowed = ir_dev->props->allowed_protos;
- } else {
+ } else if (ir_dev->raw) {
enabled = ir_dev->raw->enabled_protocols;
allowed = ir_raw_get_allowed_protocols();
- }
+ } else
+ return sprintf(tmp, "[builtin]\n");
IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n",
(long long)allowed,
@@ -121,10 +122,14 @@
int rc, i, count = 0;
unsigned long flags;
- if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE)
+ if (ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_SCANCODE)
type = ir_dev->rc_tab.ir_type;
- else
+ else if (ir_dev->raw)
type = ir_dev->raw->enabled_protocols;
+ else {
+ IR_dprintk(1, "Protocol switching not supported\n");
+ return -EINVAL;
+ }
while ((tmp = strsep((char **) &data, " \n")) != NULL) {
if (!*tmp)
@@ -185,7 +190,7 @@
}
}
- if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) {
+ if (ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_SCANCODE) {
spin_lock_irqsave(&ir_dev->rc_tab.lock, flags);
ir_dev->rc_tab.ir_type = type;
spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags);
diff --git a/drivers/media/IR/keymaps/rc-rc6-mce.c b/drivers/media/IR/keymaps/rc-rc6-mce.c
index 64264f7..39557ad 100644
--- a/drivers/media/IR/keymaps/rc-rc6-mce.c
+++ b/drivers/media/IR/keymaps/rc-rc6-mce.c
@@ -19,6 +19,7 @@
{ 0x800f0416, KEY_PLAY },
{ 0x800f0418, KEY_PAUSE },
+ { 0x800f046e, KEY_PLAYPAUSE },
{ 0x800f0419, KEY_STOP },
{ 0x800f0417, KEY_RECORD },
@@ -37,6 +38,8 @@
{ 0x800f0411, KEY_VOLUMEDOWN },
{ 0x800f0412, KEY_CHANNELUP },
{ 0x800f0413, KEY_CHANNELDOWN },
+ { 0x800f043a, KEY_BRIGHTNESSUP },
+ { 0x800f0480, KEY_BRIGHTNESSDOWN },
{ 0x800f0401, KEY_NUMERIC_1 },
{ 0x800f0402, KEY_NUMERIC_2 },
diff --git a/drivers/media/IR/mceusb.c b/drivers/media/IR/mceusb.c
index ac6bb2c..bc620e1 100644
--- a/drivers/media/IR/mceusb.c
+++ b/drivers/media/IR/mceusb.c
@@ -120,6 +120,10 @@
{ USB_DEVICE(VENDOR_PHILIPS, 0x0613) },
/* Philips eHome Infrared Transceiver */
{ USB_DEVICE(VENDOR_PHILIPS, 0x0815) },
+ /* Philips/Spinel plus IR transceiver for ASUS */
+ { USB_DEVICE(VENDOR_PHILIPS, 0x206c) },
+ /* Philips/Spinel plus IR transceiver for ASUS */
+ { USB_DEVICE(VENDOR_PHILIPS, 0x2088) },
/* Realtek MCE IR Receiver */
{ USB_DEVICE(VENDOR_REALTEK, 0x0161) },
/* SMK/Toshiba G83C0004D410 */
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index fe81834..48397f1 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -673,9 +673,6 @@
else
dev->props.rc.core.bulk_mode = false;
- /* Need a higher delay, to avoid wrong repeat */
- dev->rc_input_dev->rep[REP_DELAY] = 500;
-
dib0700_rc_setup(dev);
return 0;
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index f634d2e..e06acd1 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -940,6 +940,58 @@
return adap->fe == NULL ? -ENODEV : 0;
}
+/* STK7770P */
+static struct dib7000p_config dib7770p_dib7000p_config = {
+ .output_mpeg2_in_188_bytes = 1,
+
+ .agc_config_count = 1,
+ .agc = &dib7070_agc_config,
+ .bw = &dib7070_bw_config_12_mhz,
+ .tuner_is_baseband = 1,
+ .spur_protect = 1,
+
+ .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+ .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+ .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+ .hostbus_diversity = 1,
+ .enable_current_mirror = 1,
+ .disable_sample_and_hold = 0,
+};
+
+static int stk7770p_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ struct usb_device_descriptor *p = &adap->dev->udev->descriptor;
+ if (p->idVendor == cpu_to_le16(USB_VID_PINNACLE) &&
+ p->idProduct == cpu_to_le16(USB_PID_PINNACLE_PCTV72E))
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
+ else
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+ dib0700_ctrl_clock(adap->dev, 72, 1);
+
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+ if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+ &dib7770p_dib7000p_config) != 0) {
+ err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
+ &dib7770p_dib7000p_config);
+ return adap->fe == NULL ? -ENODEV : 0;
+}
+
/* DIB807x generic */
static struct dibx000_agc_config dib807x_agc_config[2] = {
{
@@ -1781,7 +1833,7 @@
/* 60 */{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS_2) },
{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XPVR) },
{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XP) },
- { USB_DEVICE(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD) },
+ { USB_DEVICE_VER(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD, 0x000, 0x3f00) },
{ USB_DEVICE(USB_VID_EVOLUTEPC, USB_PID_TVWAY_PLUS) },
/* 65 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73ESE) },
{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV282E) },
@@ -2406,7 +2458,7 @@
.pid_filter_count = 32,
.pid_filter = stk70x0p_pid_filter,
.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
- .frontend_attach = stk7070p_frontend_attach,
+ .frontend_attach = stk7770p_frontend_attach,
.tuner_attach = dib7770p_tuner_attach,
DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c
index 6b22ec6..f896337 100644
--- a/drivers/media/dvb/dvb-usb/opera1.c
+++ b/drivers/media/dvb/dvb-usb/opera1.c
@@ -483,9 +483,7 @@
}
}
kfree(p);
- if (fw) {
- release_firmware(fw);
- }
+ release_firmware(fw);
return ret;
}
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
index 2e28b97..3aed0d4 100644
--- a/drivers/media/dvb/frontends/dib7000p.c
+++ b/drivers/media/dvb/frontends/dib7000p.c
@@ -260,6 +260,9 @@
// dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
+ reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4;
+ reg_908 |= (state->cfg.enable_current_mirror & 1) << 7;
+
dib7000p_write_word(state, 908, reg_908);
dib7000p_write_word(state, 909, reg_909);
}
@@ -778,7 +781,10 @@
default:
case GUARD_INTERVAL_1_32: value *= 1; break;
}
- state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO
+ if (state->cfg.diversity_delay == 0)
+ state->div_sync_wait = (value * 3) / 2 + 48; // add 50% SFN margin + compensate for one DVSY-fifo
+ else
+ state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay; // add 50% SFN margin + compensate for one DVSY-fifo
/* deactive the possibility of diversity reception if extended interleaver */
state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K;
diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h
index 805dd13..da17345 100644
--- a/drivers/media/dvb/frontends/dib7000p.h
+++ b/drivers/media/dvb/frontends/dib7000p.h
@@ -33,6 +33,11 @@
int (*agc_control) (struct dvb_frontend *, u8 before);
u8 output_mode;
+ u8 disable_sample_and_hold : 1;
+
+ u8 enable_current_mirror : 1;
+ u8 diversity_delay;
+
};
#define DEFAULT_DIB7000P_I2C_ADDRESS 18
diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c
index d93468c..ff3b0fa 100644
--- a/drivers/media/dvb/siano/smscoreapi.c
+++ b/drivers/media/dvb/siano/smscoreapi.c
@@ -1098,33 +1098,26 @@
*
* @return pointer to descriptor on success, NULL on error.
*/
-struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
+
+struct smscore_buffer_t *get_entry(struct smscore_device_t *coredev)
{
struct smscore_buffer_t *cb = NULL;
unsigned long flags;
- DEFINE_WAIT(wait);
-
spin_lock_irqsave(&coredev->bufferslock, flags);
-
- /* This function must return a valid buffer, since the buffer list is
- * finite, we check that there is an available buffer, if not, we wait
- * until such buffer become available.
- */
-
- prepare_to_wait(&coredev->buffer_mng_waitq, &wait, TASK_INTERRUPTIBLE);
- if (list_empty(&coredev->buffers)) {
- spin_unlock_irqrestore(&coredev->bufferslock, flags);
- schedule();
- spin_lock_irqsave(&coredev->bufferslock, flags);
+ if (!list_empty(&coredev->buffers)) {
+ cb = (struct smscore_buffer_t *) coredev->buffers.next;
+ list_del(&cb->entry);
}
-
- finish_wait(&coredev->buffer_mng_waitq, &wait);
-
- cb = (struct smscore_buffer_t *) coredev->buffers.next;
- list_del(&cb->entry);
-
spin_unlock_irqrestore(&coredev->bufferslock, flags);
+ return cb;
+}
+
+struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
+{
+ struct smscore_buffer_t *cb = NULL;
+
+ wait_event(coredev->buffer_mng_waitq, (cb = get_entry(coredev)));
return cb;
}
diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c
index 67a4ec8..4ce541a 100644
--- a/drivers/media/radio/si470x/radio-si470x-i2c.c
+++ b/drivers/media/radio/si470x/radio-si470x-i2c.c
@@ -395,7 +395,7 @@
radio->registers[POWERCFG] = POWERCFG_ENABLE;
if (si470x_set_register(radio, POWERCFG) < 0) {
retval = -EIO;
- goto err_all;
+ goto err_video;
}
msleep(110);
diff --git a/drivers/media/video/cx231xx/Makefile b/drivers/media/video/cx231xx/Makefile
index 755dd0c..6f2b573 100644
--- a/drivers/media/video/cx231xx/Makefile
+++ b/drivers/media/video/cx231xx/Makefile
@@ -11,4 +11,5 @@
EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-usb
diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c
index 6bdc0ef..f2a4900 100644
--- a/drivers/media/video/cx231xx/cx231xx-cards.c
+++ b/drivers/media/video/cx231xx/cx231xx-cards.c
@@ -32,6 +32,7 @@
#include <media/v4l2-chip-ident.h>
#include <media/cx25840.h>
+#include "dvb-usb-ids.h"
#include "xc5000.h"
#include "cx231xx.h"
@@ -175,6 +176,8 @@
.driver_info = CX231XX_BOARD_CNXT_RDE_250},
{USB_DEVICE(0x0572, 0x58A1),
.driver_info = CX231XX_BOARD_CNXT_RDU_250},
+ {USB_DEVICE_VER(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD, 0x4000,0x4fff),
+ .driver_info = CX231XX_BOARD_UNKNOWN},
{},
};
@@ -226,14 +229,16 @@
dev->board.name, dev->model);
/* set the direction for GPIO pins */
- cx231xx_set_gpio_direction(dev, dev->board.tuner_gpio->bit, 1);
- cx231xx_set_gpio_value(dev, dev->board.tuner_gpio->bit, 1);
- cx231xx_set_gpio_direction(dev, dev->board.tuner_sif_gpio, 1);
+ if (dev->board.tuner_gpio) {
+ cx231xx_set_gpio_direction(dev, dev->board.tuner_gpio->bit, 1);
+ cx231xx_set_gpio_value(dev, dev->board.tuner_gpio->bit, 1);
+ cx231xx_set_gpio_direction(dev, dev->board.tuner_sif_gpio, 1);
- /* request some modules if any required */
+ /* request some modules if any required */
- /* reset the Tuner */
- cx231xx_gpio_set(dev, dev->board.tuner_gpio);
+ /* reset the Tuner */
+ cx231xx_gpio_set(dev, dev->board.tuner_gpio);
+ }
/* set the mode to Analog mode initially */
cx231xx_set_mode(dev, CX231XX_ANALOG_MODE);
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 86ca8c2..f5a3e74 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -1996,7 +1996,7 @@
state->volume = v4l2_ctrl_new_std(&state->hdl,
&cx25840_audio_ctrl_ops, V4L2_CID_AUDIO_VOLUME,
- 0, 65335, 65535 / 100, default_volume);
+ 0, 65535, 65535 / 100, default_volume);
state->mute = v4l2_ctrl_new_std(&state->hdl,
&cx25840_audio_ctrl_ops, V4L2_CID_AUDIO_MUTE,
0, 1, 1, 0);
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 99dbae1..0fa85cb 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -17,7 +17,7 @@
config VIDEO_CX88_ALSA
tristate "Conexant 2388x DMA audio support"
- depends on VIDEO_CX88 && SND && EXPERIMENTAL
+ depends on VIDEO_CX88 && SND
select SND_PCM
---help---
This is a video4linux driver for direct (DMA) audio on
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index b984610..78abc1c 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -223,6 +223,7 @@
usb_rcvintpipe(dev, ep->bEndpointAddress),
buffer, buffer_len,
int_irq, (void *)gspca_dev, interval);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
gspca_dev->int_urb = urb;
ret = usb_submit_urb(urb, GFP_KERNEL);
if (ret < 0) {
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c
index 83a718f..9052d57 100644
--- a/drivers/media/video/gspca/sn9c20x.c
+++ b/drivers/media/video/gspca/sn9c20x.c
@@ -2357,8 +2357,7 @@
(data[33] << 10);
avg_lum >>= 9;
atomic_set(&sd->avg_lum, avg_lum);
- gspca_frame_add(gspca_dev, LAST_PACKET,
- data, len);
+ gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
return;
}
if (gspca_dev->last_packet_type == LAST_PACKET) {
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
index be03a71..f0316d0 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -466,6 +466,8 @@
struct fb_vblank vblank;
u32 trace;
+ memset(&vblank, 0, sizeof(struct fb_vblank));
+
vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
FB_VBLANK_HAVE_VSYNC;
trace = read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16;
diff --git a/drivers/media/video/mem2mem_testdev.c b/drivers/media/video/mem2mem_testdev.c
index 4525335..a7210d9 100644
--- a/drivers/media/video/mem2mem_testdev.c
+++ b/drivers/media/video/mem2mem_testdev.c
@@ -239,7 +239,7 @@
return -EFAULT;
}
- if (in_buf->vb.size < out_buf->vb.size) {
+ if (in_buf->vb.size > out_buf->vb.size) {
v4l2_err(&dev->v4l2_dev, "Output buffer is too small\n");
return -EINVAL;
}
@@ -1014,6 +1014,7 @@
v4l2_m2m_release(dev->m2m_dev);
del_timer_sync(&dev->timer);
video_unregister_device(dev->vfd);
+ video_device_release(dev->vfd);
v4l2_device_unregister(&dev->v4l2_dev);
kfree(dev);
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
index 758a4db..c71af4e 100644
--- a/drivers/media/video/mt9m111.c
+++ b/drivers/media/video/mt9m111.c
@@ -447,6 +447,9 @@
dev_dbg(&client->dev, "%s left=%d, top=%d, width=%d, height=%d\n",
__func__, rect.left, rect.top, rect.width, rect.height);
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
ret = mt9m111_make_rect(client, &rect);
if (!ret)
mt9m111->rect = rect;
@@ -466,12 +469,14 @@
static int mt9m111_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
{
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
a->bounds.left = MT9M111_MIN_DARK_COLS;
a->bounds.top = MT9M111_MIN_DARK_ROWS;
a->bounds.width = MT9M111_MAX_WIDTH;
a->bounds.height = MT9M111_MAX_HEIGHT;
a->defrect = a->bounds;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
a->pixelaspect.numerator = 1;
a->pixelaspect.denominator = 1;
@@ -487,6 +492,7 @@
mf->width = mt9m111->rect.width;
mf->height = mt9m111->rect.height;
mf->code = mt9m111->fmt->code;
+ mf->colorspace = mt9m111->fmt->colorspace;
mf->field = V4L2_FIELD_NONE;
return 0;
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index e7cd23c..b48473c 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -402,9 +402,6 @@
if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC)
return -EINVAL;
break;
- case 0:
- /* No format change, only geometry */
- break;
default:
return -EINVAL;
}
diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c
index 66ff174..b6ea672 100644
--- a/drivers/media/video/mx2_camera.c
+++ b/drivers/media/video/mx2_camera.c
@@ -378,6 +378,9 @@
spin_lock_irqsave(&pcdev->lock, flags);
+ if (*fb_active == NULL)
+ goto out;
+
vb = &(*fb_active)->vb;
dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
@@ -402,6 +405,7 @@
*fb_active = buf;
+out:
spin_unlock_irqrestore(&pcdev->lock, flags);
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
index 1b992b8..55ea914 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
@@ -513,7 +513,7 @@
if (ret >= 0) {
ret = pvr2_ctrl_range_check(cptr,*valptr);
}
- if (maskptr) *maskptr = ~0;
+ *maskptr = ~0;
} else if (cptr->info->type == pvr2_ctl_bool) {
ret = parse_token(ptr,len,valptr,boolNames,
ARRAY_SIZE(boolNames));
@@ -522,7 +522,7 @@
} else if (ret == 0) {
*valptr = (*valptr & 1) ? !0 : 0;
}
- if (maskptr) *maskptr = 1;
+ *maskptr = 1;
} else if (cptr->info->type == pvr2_ctl_enum) {
ret = parse_token(
ptr,len,valptr,
@@ -531,7 +531,7 @@
if (ret >= 0) {
ret = pvr2_ctrl_range_check(cptr,*valptr);
}
- if (maskptr) *maskptr = ~0;
+ *maskptr = ~0;
} else if (cptr->info->type == pvr2_ctl_bitmask) {
ret = parse_tlist(
ptr,len,maskptr,valptr,
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c
index b151c7b..6961c55 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.c
+++ b/drivers/media/video/s5p-fimc/fimc-core.c
@@ -393,6 +393,37 @@
dbg("ctx->out_order_1p= %d", ctx->out_order_1p);
}
+static void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
+{
+ struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
+
+ f->dma_offset.y_h = f->offs_h;
+ if (!variant->pix_hoff)
+ f->dma_offset.y_h *= (f->fmt->depth >> 3);
+
+ f->dma_offset.y_v = f->offs_v;
+
+ f->dma_offset.cb_h = f->offs_h;
+ f->dma_offset.cb_v = f->offs_v;
+
+ f->dma_offset.cr_h = f->offs_h;
+ f->dma_offset.cr_v = f->offs_v;
+
+ if (!variant->pix_hoff) {
+ if (f->fmt->planes_cnt == 3) {
+ f->dma_offset.cb_h >>= 1;
+ f->dma_offset.cr_h >>= 1;
+ }
+ if (f->fmt->color == S5P_FIMC_YCBCR420) {
+ f->dma_offset.cb_v >>= 1;
+ f->dma_offset.cr_v >>= 1;
+ }
+ }
+
+ dbg("in_offset: color= %d, y_h= %d, y_v= %d",
+ f->fmt->color, f->dma_offset.y_h, f->dma_offset.y_v);
+}
+
/**
* fimc_prepare_config - check dimensions, operation and color mode
* and pre-calculate offset and the scaling coefficients.
@@ -406,7 +437,6 @@
{
struct fimc_frame *s_frame, *d_frame;
struct fimc_vid_buffer *buf = NULL;
- struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
int ret = 0;
s_frame = &ctx->s_frame;
@@ -419,61 +449,16 @@
swap(d_frame->width, d_frame->height);
}
- /* Prepare the output offset ratios for scaler. */
- d_frame->dma_offset.y_h = d_frame->offs_h;
- if (!variant->pix_hoff)
- d_frame->dma_offset.y_h *= (d_frame->fmt->depth >> 3);
+ /* Prepare the DMA offset ratios for scaler. */
+ fimc_prepare_dma_offset(ctx, &ctx->s_frame);
+ fimc_prepare_dma_offset(ctx, &ctx->d_frame);
- d_frame->dma_offset.y_v = d_frame->offs_v;
-
- d_frame->dma_offset.cb_h = d_frame->offs_h;
- d_frame->dma_offset.cb_v = d_frame->offs_v;
-
- d_frame->dma_offset.cr_h = d_frame->offs_h;
- d_frame->dma_offset.cr_v = d_frame->offs_v;
-
- if (!variant->pix_hoff && d_frame->fmt->planes_cnt == 3) {
- d_frame->dma_offset.cb_h >>= 1;
- d_frame->dma_offset.cb_v >>= 1;
- d_frame->dma_offset.cr_h >>= 1;
- d_frame->dma_offset.cr_v >>= 1;
- }
-
- dbg("out offset: color= %d, y_h= %d, y_v= %d",
- d_frame->fmt->color,
- d_frame->dma_offset.y_h, d_frame->dma_offset.y_v);
-
- /* Prepare the input offset ratios for scaler. */
- s_frame->dma_offset.y_h = s_frame->offs_h;
- if (!variant->pix_hoff)
- s_frame->dma_offset.y_h *= (s_frame->fmt->depth >> 3);
- s_frame->dma_offset.y_v = s_frame->offs_v;
-
- s_frame->dma_offset.cb_h = s_frame->offs_h;
- s_frame->dma_offset.cb_v = s_frame->offs_v;
-
- s_frame->dma_offset.cr_h = s_frame->offs_h;
- s_frame->dma_offset.cr_v = s_frame->offs_v;
-
- if (!variant->pix_hoff && s_frame->fmt->planes_cnt == 3) {
- s_frame->dma_offset.cb_h >>= 1;
- s_frame->dma_offset.cb_v >>= 1;
- s_frame->dma_offset.cr_h >>= 1;
- s_frame->dma_offset.cr_v >>= 1;
- }
-
- dbg("in offset: color= %d, y_h= %d, y_v= %d",
- s_frame->fmt->color, s_frame->dma_offset.y_h,
- s_frame->dma_offset.y_v);
-
- fimc_set_yuv_order(ctx);
-
- /* Check against the scaler ratio. */
if (s_frame->height > (SCALER_MAX_VRATIO * d_frame->height) ||
s_frame->width > (SCALER_MAX_HRATIO * d_frame->width)) {
err("out of scaler range");
return -EINVAL;
}
+ fimc_set_yuv_order(ctx);
}
/* Input DMA mode is not allowed when the scaler is disabled. */
@@ -822,7 +807,8 @@
} else {
v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev,
"Wrong buffer/video queue type (%d)\n", f->type);
- return -EINVAL;
+ ret = -EINVAL;
+ goto s_fmt_out;
}
pix = &f->fmt.pix;
@@ -1414,8 +1400,10 @@
}
fimc->work_queue = create_workqueue(dev_name(&fimc->pdev->dev));
- if (!fimc->work_queue)
+ if (!fimc->work_queue) {
+ ret = -ENOMEM;
goto err_irq;
+ }
ret = fimc_register_m2m_device(fimc);
if (ret)
@@ -1492,6 +1480,7 @@
};
static struct samsung_fimc_variant fimc01_variant_s5pv210 = {
+ .pix_hoff = 1,
.has_inp_rot = 1,
.has_out_rot = 1,
.min_inp_pixsize = 16,
@@ -1506,6 +1495,7 @@
};
static struct samsung_fimc_variant fimc2_variant_s5pv210 = {
+ .pix_hoff = 1,
.min_inp_pixsize = 16,
.min_out_pixsize = 32,
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index ec697fc..bb8d83d 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -4323,13 +4323,13 @@
},
[SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM] = {
/* Beholder Intl. Ltd. 2008 */
- /*Dmitry Belimov <d.belimov@gmail.com> */
- .name = "Beholder BeholdTV Columbus TVFM",
+ /* Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV Columbus TV/FM",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_ALPS_TSBE5_PAL,
- .radio_type = UNSET,
- .tuner_addr = ADDR_UNSET,
- .radio_addr = ADDR_UNSET,
+ .radio_type = TUNER_TEA5767,
+ .tuner_addr = 0xc2 >> 1,
+ .radio_addr = 0xc0 >> 1,
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x000A8004,
.inputs = {{
diff --git a/drivers/media/video/saa7164/saa7164-buffer.c b/drivers/media/video/saa7164/saa7164-buffer.c
index 5713f3a..ddd25d3 100644
--- a/drivers/media/video/saa7164/saa7164-buffer.c
+++ b/drivers/media/video/saa7164/saa7164-buffer.c
@@ -136,10 +136,11 @@
int saa7164_buffer_dealloc(struct saa7164_tsport *port,
struct saa7164_buffer *buf)
{
- struct saa7164_dev *dev = port->dev;
+ struct saa7164_dev *dev;
- if ((buf == 0) || (port == 0))
+ if (!buf || !port)
return SAA_ERR_BAD_PARAMETER;
+ dev = port->dev;
dprintk(DBGLVL_BUF, "%s() deallocating buffer @ 0x%p\n", __func__, buf);
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index 8bdd940..2ac85d8 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -486,6 +486,12 @@
max(frame->dwFrameInterval[0],
frame->dwDefaultFrameInterval));
+ if (dev->quirks & UVC_QUIRK_RESTRICT_FRAME_RATE) {
+ frame->bFrameIntervalType = 1;
+ frame->dwFrameInterval[0] =
+ frame->dwDefaultFrameInterval;
+ }
+
uvc_trace(UVC_TRACE_DESCR, "- %ux%u (%u.%u fps)\n",
frame->wWidth, frame->wHeight,
10000000/frame->dwDefaultFrameInterval,
@@ -2026,6 +2032,15 @@
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0 },
+ /* Chicony CNF7129 (Asus EEE 100HE) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x04f2,
+ .idProduct = 0xb071,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_RESTRICT_FRAME_RATE },
/* Alcor Micro AU3820 (Future Boy PC USB Webcam) */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2091,6 +2106,15 @@
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_PROBE_MINMAX
| UVC_QUIRK_PROBE_DEF },
+ /* IMC Networks (Medion Akoya) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x13d3,
+ .idProduct = 0x5103,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
/* Syntek (HP Spartan) */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index bdacf3b..892e0e5 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -182,6 +182,7 @@
#define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020
#define UVC_QUIRK_FIX_BANDWIDTH 0x00000080
#define UVC_QUIRK_PROBE_DEF 0x00000100
+#define UVC_QUIRK_RESTRICT_FRAME_RATE 0x00000200
/* Format flags */
#define UVC_FMT_FLAG_COMPRESSED 0x00000001
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
index 073f013..86294ed3 100644
--- a/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/drivers/media/video/v4l2-compat-ioctl32.c
@@ -193,17 +193,24 @@
struct video_code32 {
char loadwhat[16]; /* name or tag of file being passed */
compat_int_t datasize;
- unsigned char *data;
+ compat_uptr_t data;
};
-static int get_microcode32(struct video_code *kp, struct video_code32 __user *up)
+static struct video_code __user *get_microcode32(struct video_code32 *kp)
{
- if (!access_ok(VERIFY_READ, up, sizeof(struct video_code32)) ||
- copy_from_user(kp->loadwhat, up->loadwhat, sizeof(up->loadwhat)) ||
- get_user(kp->datasize, &up->datasize) ||
- copy_from_user(kp->data, up->data, up->datasize))
- return -EFAULT;
- return 0;
+ struct video_code __user *up;
+
+ up = compat_alloc_user_space(sizeof(*up));
+
+ /*
+ * NOTE! We don't actually care if these fail. If the
+ * user address is invalid, the native ioctl will do
+ * the error handling for us
+ */
+ (void) copy_to_user(up->loadwhat, kp->loadwhat, sizeof(up->loadwhat));
+ (void) put_user(kp->datasize, &up->datasize);
+ (void) put_user(compat_ptr(kp->data), &up->data);
+ return up;
}
#define VIDIOCGTUNER32 _IOWR('v', 4, struct video_tuner32)
@@ -739,7 +746,7 @@
struct video_tuner vt;
struct video_buffer vb;
struct video_window vw;
- struct video_code vc;
+ struct video_code32 vc;
struct video_audio va;
#endif
struct v4l2_format v2f;
@@ -818,8 +825,11 @@
break;
case VIDIOCSMICROCODE:
- err = get_microcode32(&karg.vc, up);
- compatible_arg = 0;
+ /* Copy the 32-bit "video_code32" to kernel space */
+ if (copy_from_user(&karg.vc, up, sizeof(karg.vc)))
+ return -EFAULT;
+ /* Convert the 32-bit version to a 64-bit version in user space */
+ up = get_microcode32(&karg.vc);
break;
case VIDIOCSFREQ:
diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c
index 372b87e..6ff9e4b 100644
--- a/drivers/media/video/videobuf-dma-contig.c
+++ b/drivers/media/video/videobuf-dma-contig.c
@@ -393,8 +393,10 @@
}
/* read() method */
- dma_free_coherent(q->dev, mem->size, mem->vaddr, mem->dma_handle);
- mem->vaddr = NULL;
+ if (mem->vaddr) {
+ dma_free_coherent(q->dev, mem->size, mem->vaddr, mem->dma_handle);
+ mem->vaddr = NULL;
+ }
}
EXPORT_SYMBOL_GPL(videobuf_dma_contig_free);
diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c
index 06f9a9c..2ad0bc2 100644
--- a/drivers/media/video/videobuf-dma-sg.c
+++ b/drivers/media/video/videobuf-dma-sg.c
@@ -94,7 +94,7 @@
* must free the memory.
*/
static struct scatterlist *videobuf_pages_to_sg(struct page **pages,
- int nr_pages, int offset)
+ int nr_pages, int offset, size_t size)
{
struct scatterlist *sglist;
int i;
@@ -110,12 +110,14 @@
/* DMA to highmem pages might not work */
goto highmem;
sg_set_page(&sglist[0], pages[0], PAGE_SIZE - offset, offset);
+ size -= PAGE_SIZE - offset;
for (i = 1; i < nr_pages; i++) {
if (NULL == pages[i])
goto nopage;
if (PageHighMem(pages[i]))
goto highmem;
- sg_set_page(&sglist[i], pages[i], PAGE_SIZE, 0);
+ sg_set_page(&sglist[i], pages[i], min(PAGE_SIZE, size), 0);
+ size -= min(PAGE_SIZE, size);
}
return sglist;
@@ -170,7 +172,8 @@
first = (data & PAGE_MASK) >> PAGE_SHIFT;
last = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT;
- dma->offset = data & ~PAGE_MASK;
+ dma->offset = data & ~PAGE_MASK;
+ dma->size = size;
dma->nr_pages = last-first+1;
dma->pages = kmalloc(dma->nr_pages * sizeof(struct page *), GFP_KERNEL);
if (NULL == dma->pages)
@@ -252,7 +255,7 @@
if (dma->pages) {
dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages,
- dma->offset);
+ dma->offset, dma->size);
}
if (dma->vaddr) {
dma->sglist = videobuf_vmalloc_to_sg(dma->vaddr,
diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c
index 04028a9..428377a 100644
--- a/drivers/mfd/max8925-core.c
+++ b/drivers/mfd/max8925-core.c
@@ -429,24 +429,25 @@
irq_tsc = cache_tsc;
for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) {
irq_data = &max8925_irqs[i];
+ /* 1 -- disable, 0 -- enable */
switch (irq_data->mask_reg) {
case MAX8925_CHG_IRQ1_MASK:
- irq_chg[0] &= irq_data->enable;
+ irq_chg[0] &= ~irq_data->enable;
break;
case MAX8925_CHG_IRQ2_MASK:
- irq_chg[1] &= irq_data->enable;
+ irq_chg[1] &= ~irq_data->enable;
break;
case MAX8925_ON_OFF_IRQ1_MASK:
- irq_on[0] &= irq_data->enable;
+ irq_on[0] &= ~irq_data->enable;
break;
case MAX8925_ON_OFF_IRQ2_MASK:
- irq_on[1] &= irq_data->enable;
+ irq_on[1] &= ~irq_data->enable;
break;
case MAX8925_RTC_IRQ_MASK:
- irq_rtc &= irq_data->enable;
+ irq_rtc &= ~irq_data->enable;
break;
case MAX8925_TSC_IRQ_MASK:
- irq_tsc &= irq_data->enable;
+ irq_tsc &= ~irq_data->enable;
break;
default:
dev_err(chip->dev, "wrong IRQ\n");
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 720e099..5d0fb60 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -698,17 +698,17 @@
if (twl_has_codec() && pdata->codec && twl_class_is_4030()) {
sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
- child = add_child(sub_chip_id, "twl4030_codec",
+ child = add_child(sub_chip_id, "twl4030-audio",
pdata->codec, sizeof(*pdata->codec),
false, 0, 0);
if (IS_ERR(child))
return PTR_ERR(child);
}
- /* Phoenix*/
+ /* Phoenix codec driver is probed directly atm */
if (twl_has_codec() && pdata->codec && twl_class_is_6030()) {
sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
- child = add_child(sub_chip_id, "twl6040_codec",
+ child = add_child(sub_chip_id, "twl6040-codec",
pdata->codec, sizeof(*pdata->codec),
false, 0, 0);
if (IS_ERR(child))
diff --git a/drivers/mfd/twl4030-codec.c b/drivers/mfd/twl4030-codec.c
index add6f67..9a4b196 100644
--- a/drivers/mfd/twl4030-codec.c
+++ b/drivers/mfd/twl4030-codec.c
@@ -207,14 +207,14 @@
if (pdata->audio) {
cell = &codec->cells[childs];
- cell->name = "twl4030_codec_audio";
+ cell->name = "twl4030-codec";
cell->platform_data = pdata->audio;
cell->data_size = sizeof(*pdata->audio);
childs++;
}
if (pdata->vibra) {
cell = &codec->cells[childs];
- cell->name = "twl4030_codec_vibra";
+ cell->name = "twl4030-vibra";
cell->platform_data = pdata->vibra;
cell->data_size = sizeof(*pdata->vibra);
childs++;
@@ -249,14 +249,14 @@
return 0;
}
-MODULE_ALIAS("platform:twl4030_codec");
+MODULE_ALIAS("platform:twl4030-audio");
static struct platform_driver twl4030_codec_driver = {
.probe = twl4030_codec_probe,
.remove = __devexit_p(twl4030_codec_remove),
.driver = {
.owner = THIS_MODULE,
- .name = "twl4030_codec",
+ .name = "twl4030-audio",
},
};
diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c
index 7dabe4d..294183b 100644
--- a/drivers/mfd/wm831x-irq.c
+++ b/drivers/mfd/wm831x-irq.c
@@ -394,8 +394,13 @@
irq = irq - wm831x->irq_base;
- if (irq < WM831X_IRQ_GPIO_1 || irq > WM831X_IRQ_GPIO_11)
- return -EINVAL;
+ if (irq < WM831X_IRQ_GPIO_1 || irq > WM831X_IRQ_GPIO_11) {
+ /* Ignore internal-only IRQs */
+ if (irq >= 0 && irq < WM831X_NUM_IRQS)
+ return 0;
+ else
+ return -EINVAL;
+ }
switch (type) {
case IRQ_TYPE_EDGE_BOTH:
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 0b591b6..b743312 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -368,7 +368,7 @@
If unsure, say N.
To compile this driver as a module, choose M here: the
- module will be called vmware_balloon.
+ module will be called vmw_balloon.
config ARM_CHARLCD
bool "ARM Ltd. Character LCD Driver"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 255a80d..42eab95 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -33,5 +33,5 @@
obj-$(CONFIG_HMC6352) += hmc6352.o
obj-y += eeprom/
obj-y += cb710/
-obj-$(CONFIG_VMWARE_BALLOON) += vmware_balloon.o
+obj-$(CONFIG_VMWARE_BALLOON) += vmw_balloon.o
obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o
diff --git a/drivers/misc/bh1780gli.c b/drivers/misc/bh1780gli.c
index 714c6b4..d5f3a3f 100644
--- a/drivers/misc/bh1780gli.c
+++ b/drivers/misc/bh1780gli.c
@@ -190,7 +190,6 @@
ddata = i2c_get_clientdata(client);
sysfs_remove_group(&client->dev.kobj, &bh1780_attr_group);
- i2c_set_clientdata(client, NULL);
kfree(ddata);
return 0;
diff --git a/drivers/misc/vmware_balloon.c b/drivers/misc/vmw_balloon.c
similarity index 100%
rename from drivers/misc/vmware_balloon.c
rename to drivers/misc/vmw_balloon.c
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 5db49b1..09eee6d 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1631,6 +1631,19 @@
if (host->bus_ops && !host->bus_dead) {
if (host->bus_ops->suspend)
err = host->bus_ops->suspend(host);
+ if (err == -ENOSYS || !host->bus_ops->resume) {
+ /*
+ * We simply "remove" the card in this case.
+ * It will be redetected on resume.
+ */
+ if (host->bus_ops->remove)
+ host->bus_ops->remove(host);
+ mmc_claim_host(host);
+ mmc_detach_bus(host);
+ mmc_release_host(host);
+ host->pm_flags = 0;
+ err = 0;
+ }
}
mmc_bus_put(host);
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index 71ad416..aacb862 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -241,8 +241,10 @@
static void sdhci_s3c_notify_change(struct platform_device *dev, int state)
{
struct sdhci_host *host = platform_get_drvdata(dev);
+ unsigned long flags;
+
if (host) {
- spin_lock(&host->lock);
+ spin_lock_irqsave(&host->lock, flags);
if (state) {
dev_dbg(&dev->dev, "card inserted.\n");
host->flags &= ~SDHCI_DEVICE_DEAD;
@@ -253,7 +255,7 @@
host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
}
tasklet_schedule(&host->card_tasklet);
- spin_unlock(&host->lock);
+ spin_unlock_irqrestore(&host->lock, flags);
}
}
@@ -481,8 +483,10 @@
sdhci_remove_host(host, 1);
for (ptr = 0; ptr < 3; ptr++) {
- clk_disable(sc->clk_bus[ptr]);
- clk_put(sc->clk_bus[ptr]);
+ if (sc->clk_bus[ptr]) {
+ clk_disable(sc->clk_bus[ptr]);
+ clk_put(sc->clk_bus[ptr]);
+ }
}
clk_disable(sc->clk_io);
clk_put(sc->clk_io);
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c
index a382e3d..6fbeefa 100644
--- a/drivers/mtd/nand/bf5xx_nand.c
+++ b/drivers/mtd/nand/bf5xx_nand.c
@@ -682,7 +682,6 @@
static int __devexit bf5xx_nand_remove(struct platform_device *pdev)
{
struct bf5xx_nand_info *info = to_nand_info(pdev);
- struct mtd_info *mtd = NULL;
platform_set_drvdata(pdev, NULL);
@@ -690,11 +689,7 @@
* and their partitions, then go through freeing the
* resources used
*/
- mtd = &info->mtd;
- if (mtd) {
- nand_release(mtd);
- kfree(mtd);
- }
+ nand_release(&info->mtd);
peripheral_free_list(bfin_nfc_pin_req);
bf5xx_nand_dma_remove(info);
@@ -710,7 +705,7 @@
struct nand_chip *chip = mtd->priv;
int ret;
- ret = nand_scan_ident(mtd, 1);
+ ret = nand_scan_ident(mtd, 1, NULL);
if (ret)
return ret;
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index fcf8ceb..214b03a 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -30,6 +30,8 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/completion.h>
#include <asm/mach/flash.h>
#include <mach/mxc_nand.h>
@@ -67,7 +69,9 @@
#define NFC_V1_V2_CONFIG1_BIG (1 << 5)
#define NFC_V1_V2_CONFIG1_RST (1 << 6)
#define NFC_V1_V2_CONFIG1_CE (1 << 7)
-#define NFC_V1_V2_CONFIG1_ONE_CYCLE (1 << 8)
+#define NFC_V2_CONFIG1_ONE_CYCLE (1 << 8)
+#define NFC_V2_CONFIG1_PPB(x) (((x) & 0x3) << 9)
+#define NFC_V2_CONFIG1_FP_INT (1 << 11)
#define NFC_V1_V2_CONFIG2_INT (1 << 15)
@@ -149,7 +153,7 @@
int irq;
int eccsize;
- wait_queue_head_t irq_waitq;
+ struct completion op_completion;
uint8_t *data_buf;
unsigned int buf_start;
@@ -162,6 +166,7 @@
void (*send_read_id)(struct mxc_nand_host *);
uint16_t (*get_dev_status)(struct mxc_nand_host *);
int (*check_int)(struct mxc_nand_host *);
+ void (*irq_control)(struct mxc_nand_host *, int);
};
/* OOB placement block for use with hardware ecc generation */
@@ -214,9 +219,12 @@
{
struct mxc_nand_host *host = dev_id;
- disable_irq_nosync(irq);
+ if (!host->check_int(host))
+ return IRQ_NONE;
- wake_up(&host->irq_waitq);
+ host->irq_control(host, 0);
+
+ complete(&host->op_completion);
return IRQ_HANDLED;
}
@@ -243,11 +251,54 @@
if (!(tmp & NFC_V1_V2_CONFIG2_INT))
return 0;
- writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2);
+ if (!cpu_is_mx21())
+ writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2);
return 1;
}
+/*
+ * It has been observed that the i.MX21 cannot read the CONFIG2:INT bit
+ * if interrupts are masked (CONFIG1:INT_MSK is set). To handle this, the
+ * driver can enable/disable the irq line rather than simply masking the
+ * interrupts.
+ */
+static void irq_control_mx21(struct mxc_nand_host *host, int activate)
+{
+ if (activate)
+ enable_irq(host->irq);
+ else
+ disable_irq_nosync(host->irq);
+}
+
+static void irq_control_v1_v2(struct mxc_nand_host *host, int activate)
+{
+ uint16_t tmp;
+
+ tmp = readw(NFC_V1_V2_CONFIG1);
+
+ if (activate)
+ tmp &= ~NFC_V1_V2_CONFIG1_INT_MSK;
+ else
+ tmp |= NFC_V1_V2_CONFIG1_INT_MSK;
+
+ writew(tmp, NFC_V1_V2_CONFIG1);
+}
+
+static void irq_control_v3(struct mxc_nand_host *host, int activate)
+{
+ uint32_t tmp;
+
+ tmp = readl(NFC_V3_CONFIG2);
+
+ if (activate)
+ tmp &= ~NFC_V3_CONFIG2_INT_MSK;
+ else
+ tmp |= NFC_V3_CONFIG2_INT_MSK;
+
+ writel(tmp, NFC_V3_CONFIG2);
+}
+
/* This function polls the NANDFC to wait for the basic operation to
* complete by checking the INT bit of config2 register.
*/
@@ -257,10 +308,9 @@
if (useirq) {
if (!host->check_int(host)) {
-
- enable_irq(host->irq);
-
- wait_event(host->irq_waitq, host->check_int(host));
+ INIT_COMPLETION(host->op_completion);
+ host->irq_control(host, 1);
+ wait_for_completion(&host->op_completion);
}
} else {
while (max_retries-- > 0) {
@@ -402,16 +452,16 @@
/* Wait for operation to complete */
wait_op_done(host, true);
- if (this->options & NAND_BUSWIDTH_16) {
- void __iomem *main_buf = host->main_area0;
- /* compress the ID info */
- writeb(readb(main_buf + 2), main_buf + 1);
- writeb(readb(main_buf + 4), main_buf + 2);
- writeb(readb(main_buf + 6), main_buf + 3);
- writeb(readb(main_buf + 8), main_buf + 4);
- writeb(readb(main_buf + 10), main_buf + 5);
- }
memcpy(host->data_buf, host->main_area0, 16);
+
+ if (this->options & NAND_BUSWIDTH_16) {
+ /* compress the ID info */
+ host->data_buf[1] = host->data_buf[2];
+ host->data_buf[2] = host->data_buf[4];
+ host->data_buf[3] = host->data_buf[6];
+ host->data_buf[4] = host->data_buf[8];
+ host->data_buf[5] = host->data_buf[10];
+ }
}
static uint16_t get_dev_status_v3(struct mxc_nand_host *host)
@@ -729,27 +779,30 @@
{
struct nand_chip *nand_chip = mtd->priv;
struct mxc_nand_host *host = nand_chip->priv;
- uint16_t tmp;
+ uint16_t config1 = 0;
- /* enable interrupt, disable spare enable */
- tmp = readw(NFC_V1_V2_CONFIG1);
- tmp &= ~NFC_V1_V2_CONFIG1_INT_MSK;
- tmp &= ~NFC_V1_V2_CONFIG1_SP_EN;
- if (nand_chip->ecc.mode == NAND_ECC_HW) {
- tmp |= NFC_V1_V2_CONFIG1_ECC_EN;
- } else {
- tmp &= ~NFC_V1_V2_CONFIG1_ECC_EN;
- }
+ if (nand_chip->ecc.mode == NAND_ECC_HW)
+ config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
+
+ if (nfc_is_v21())
+ config1 |= NFC_V2_CONFIG1_FP_INT;
+
+ if (!cpu_is_mx21())
+ config1 |= NFC_V1_V2_CONFIG1_INT_MSK;
if (nfc_is_v21() && mtd->writesize) {
+ uint16_t pages_per_block = mtd->erasesize / mtd->writesize;
+
host->eccsize = get_eccsize(mtd);
if (host->eccsize == 4)
- tmp |= NFC_V2_CONFIG1_ECC_MODE_4;
+ config1 |= NFC_V2_CONFIG1_ECC_MODE_4;
+
+ config1 |= NFC_V2_CONFIG1_PPB(ffs(pages_per_block) - 6);
} else {
host->eccsize = 1;
}
- writew(tmp, NFC_V1_V2_CONFIG1);
+ writew(config1, NFC_V1_V2_CONFIG1);
/* preset operation */
/* Unlock the internal RAM Buffer */
@@ -794,6 +847,7 @@
NFC_V3_CONFIG2_2CMD_PHASES |
NFC_V3_CONFIG2_SPAS(mtd->oobsize >> 1) |
NFC_V3_CONFIG2_ST_CMD(0x70) |
+ NFC_V3_CONFIG2_INT_MSK |
NFC_V3_CONFIG2_NUM_ADDR_PHASE0;
if (chip->ecc.mode == NAND_ECC_HW)
@@ -1019,6 +1073,10 @@
host->send_read_id = send_read_id_v1_v2;
host->get_dev_status = get_dev_status_v1_v2;
host->check_int = check_int_v1_v2;
+ if (cpu_is_mx21())
+ host->irq_control = irq_control_mx21;
+ else
+ host->irq_control = irq_control_v1_v2;
}
if (nfc_is_v21()) {
@@ -1057,6 +1115,7 @@
host->send_read_id = send_read_id_v3;
host->check_int = check_int_v3;
host->get_dev_status = get_dev_status_v3;
+ host->irq_control = irq_control_v3;
oob_smallpage = &nandv2_hw_eccoob_smallpage;
oob_largepage = &nandv2_hw_eccoob_largepage;
} else
@@ -1088,14 +1147,34 @@
this->options |= NAND_USE_FLASH_BBT;
}
- init_waitqueue_head(&host->irq_waitq);
+ init_completion(&host->op_completion);
host->irq = platform_get_irq(pdev, 0);
+ /*
+ * mask the interrupt. For i.MX21 explicitely call
+ * irq_control_v1_v2 to use the mask bit. We can't call
+ * disable_irq_nosync() for an interrupt we do not own yet.
+ */
+ if (cpu_is_mx21())
+ irq_control_v1_v2(host, 0);
+ else
+ host->irq_control(host, 0);
+
err = request_irq(host->irq, mxc_nfc_irq, IRQF_DISABLED, DRIVER_NAME, host);
if (err)
goto eirq;
+ host->irq_control(host, 0);
+
+ /*
+ * Now that the interrupt is disabled make sure the interrupt
+ * mask bit is cleared on i.MX21. Otherwise we can't read
+ * the interrupt status bit on this machine.
+ */
+ if (cpu_is_mx21())
+ irq_control_v1_v2(host, 1);
+
/* first scan to find the device and get the page size */
if (nand_scan_ident(mtd, 1, NULL)) {
err = -ENXIO;
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 133d515..513e0a7 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -413,7 +413,7 @@
prefetch_status = gpmc_read_status(GPMC_PREFETCH_COUNT);
} while (prefetch_status);
/* disable and stop the PFPW engine */
- gpmc_prefetch_reset();
+ gpmc_prefetch_reset(info->gpmc_cs);
dma_unmap_single(&info->pdev->dev, dma_addr, len, dir);
return 0;
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index 4d89f37..4d01cda6 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -1320,6 +1320,7 @@
goto fail_free_irq;
}
+#ifdef CONFIG_MTD_PARTITIONS
if (mtd_has_cmdlinepart()) {
static const char *probes[] = { "cmdlinepart", NULL };
struct mtd_partition *parts;
@@ -1332,6 +1333,9 @@
}
return add_mtd_partitions(mtd, pdata->parts, pdata->nr_parts);
+#else
+ return 0;
+#endif
fail_free_irq:
free_irq(irq, info);
@@ -1364,7 +1368,9 @@
platform_set_drvdata(pdev, NULL);
del_mtd_device(mtd);
+#ifdef CONFIG_MTD_PARTITIONS
del_mtd_partitions(mtd);
+#endif
irq = platform_get_irq(pdev, 0);
if (irq >= 0)
free_irq(irq, info);
diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c
index cb443af..a460f1b 100644
--- a/drivers/mtd/onenand/samsung.c
+++ b/drivers/mtd/onenand/samsung.c
@@ -554,14 +554,13 @@
do {
status = readl(base + S5PC110_DMA_TRANS_STATUS);
+ if (status & S5PC110_DMA_TRANS_STATUS_TE) {
+ writel(S5PC110_DMA_TRANS_CMD_TEC,
+ base + S5PC110_DMA_TRANS_CMD);
+ return -EIO;
+ }
} while (!(status & S5PC110_DMA_TRANS_STATUS_TD));
- if (status & S5PC110_DMA_TRANS_STATUS_TE) {
- writel(S5PC110_DMA_TRANS_CMD_TEC, base + S5PC110_DMA_TRANS_CMD);
- writel(S5PC110_DMA_TRANS_CMD_TDC, base + S5PC110_DMA_TRANS_CMD);
- return -EIO;
- }
-
writel(S5PC110_DMA_TRANS_CMD_TDC, base + S5PC110_DMA_TRANS_CMD);
return 0;
@@ -571,13 +570,12 @@
unsigned char *buffer, int offset, size_t count)
{
struct onenand_chip *this = mtd->priv;
- void __iomem *bufferram;
void __iomem *p;
void *buf = (void *) buffer;
dma_addr_t dma_src, dma_dst;
int err;
- p = bufferram = this->base + area;
+ p = this->base + area;
if (ONENAND_CURRENT_BUFFERRAM(this)) {
if (area == ONENAND_DATARAM)
p += this->writesize;
@@ -621,7 +619,7 @@
normal:
if (count != mtd->writesize) {
/* Copy the bufferram to memory to prevent unaligned access */
- memcpy(this->page_buf, bufferram, mtd->writesize);
+ memcpy(this->page_buf, p, mtd->writesize);
p = this->page_buf + offset;
}
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 85671ad..179871d 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -635,6 +635,9 @@
must_free_region:1, /* Flag: if zero, Cardbus owns the I/O region */
large_frames:1, /* accept large frames */
handling_irq:1; /* private in_irq indicator */
+ /* {get|set}_wol operations are already serialized by rtnl.
+ * no additional locking is required for the enable_wol and acpi_set_WOL()
+ */
int drv_flags;
u16 status_enable;
u16 intr_enable;
@@ -2939,28 +2942,31 @@
{
struct vortex_private *vp = netdev_priv(dev);
- spin_lock_irq(&vp->lock);
+ if (!VORTEX_PCI(vp))
+ return;
+
wol->supported = WAKE_MAGIC;
wol->wolopts = 0;
if (vp->enable_wol)
wol->wolopts |= WAKE_MAGIC;
- spin_unlock_irq(&vp->lock);
}
static int vortex_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct vortex_private *vp = netdev_priv(dev);
+
+ if (!VORTEX_PCI(vp))
+ return -EOPNOTSUPP;
+
if (wol->wolopts & ~WAKE_MAGIC)
return -EINVAL;
- spin_lock_irq(&vp->lock);
if (wol->wolopts & WAKE_MAGIC)
vp->enable_wol = 1;
else
vp->enable_wol = 0;
acpi_set_WOL(dev);
- spin_unlock_irq(&vp->lock);
return 0;
}
@@ -3202,6 +3208,9 @@
return;
}
+ if (VORTEX_PCI(vp)->current_state < PCI_D3hot)
+ return;
+
/* Change the power state to D3; RxEnable doesn't take effect. */
pci_set_power_state(VORTEX_PCI(vp), PCI_D3hot);
}
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 2cc81a5..5db667c 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2428,7 +2428,7 @@
config MV643XX_ETH
tristate "Marvell Discovery (643XX) and Orion ethernet support"
- depends on MV64X60 || PPC32 || PLAT_ORION
+ depends on (MV64X60 || PPC32 || PLAT_ORION) && INET
select INET_LRO
select PHYLIB
help
@@ -2803,7 +2803,7 @@
config PASEMI_MAC
tristate "PA Semi 1/10Gbit MAC"
- depends on PPC_PASEMI && PCI
+ depends on PPC_PASEMI && PCI && INET
select PHYLIB
select INET_LRO
help
diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c
index 63b9ba0..c73be28 100644
--- a/drivers/net/atlx/atl1.c
+++ b/drivers/net/atlx/atl1.c
@@ -1251,6 +1251,12 @@
rrd_ring->desc = NULL;
rrd_ring->dma = 0;
+
+ adapter->cmb.dma = 0;
+ adapter->cmb.cmb = NULL;
+
+ adapter->smb.dma = 0;
+ adapter->smb.smb = NULL;
}
static void atl1_setup_mac_ctrl(struct atl1_adapter *adapter)
@@ -2847,10 +2853,11 @@
pci_enable_wake(pdev, PCI_D3cold, 0);
atl1_reset_hw(&adapter->hw);
- adapter->cmb.cmb->int_stats = 0;
- if (netif_running(netdev))
+ if (netif_running(netdev)) {
+ adapter->cmb.cmb->int_stats = 0;
atl1_up(adapter);
+ }
netif_device_attach(netdev);
return 0;
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 1e620e2..efeffdf 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -2170,8 +2170,6 @@
dev->irq = sdev->irq;
SET_ETHTOOL_OPS(dev, &b44_ethtool_ops);
- netif_carrier_off(dev);
-
err = ssb_bus_powerup(sdev->bus, 0);
if (err) {
dev_err(sdev->dev,
@@ -2213,6 +2211,8 @@
goto err_out_powerdown;
}
+ netif_carrier_off(dev);
+
ssb_set_drvdata(sdev, dev);
/* Chip reset provides power to the b44 MAC & PCI cores, which
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 822f586..0ddf4c6 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -2466,6 +2466,9 @@
if (!(dev->flags & IFF_MASTER))
goto out;
+ if (!pskb_may_pull(skb, sizeof(struct lacpdu)))
+ goto out;
+
read_lock(&bond->lock);
slave = bond_get_slave_by_dev((struct bonding *)netdev_priv(dev),
orig_dev);
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index c746b33..26bb118 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -362,6 +362,9 @@
goto out;
}
+ if (!pskb_may_pull(skb, arp_hdr_len(bond_dev)))
+ goto out;
+
if (skb->len < sizeof(struct arp_pkt)) {
pr_debug("Packet is too small to be an ARP\n");
goto out;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 3b16f62..e953c6a 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -5164,6 +5164,15 @@
res = dev_alloc_name(bond_dev, "bond%d");
if (res < 0)
goto out;
+ } else {
+ /*
+ * If we're given a name to register
+ * we need to ensure that its not already
+ * registered
+ */
+ res = -EEXIST;
+ if (__dev_get_by_name(net, name) != NULL)
+ goto out;
}
res = register_netdevice(bond_dev);
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index ad19585..f208712 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -2296,6 +2296,8 @@
case CHELSIO_GET_QSET_NUM:{
struct ch_reg edata;
+ memset(&edata, 0, sizeof(struct ch_reg));
+
edata.cmd = CHELSIO_GET_QSET_NUM;
edata.val = pi->nqsets;
if (copy_to_user(useraddr, &edata, sizeof(edata)))
diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h
index 66ed08f..ba302a5 100644
--- a/drivers/net/e1000e/hw.h
+++ b/drivers/net/e1000e/hw.h
@@ -57,6 +57,7 @@
E1000_SCTL = 0x00024, /* SerDes Control - RW */
E1000_FCAL = 0x00028, /* Flow Control Address Low - RW */
E1000_FCAH = 0x0002C, /* Flow Control Address High -RW */
+ E1000_FEXTNVM4 = 0x00024, /* Future Extended NVM 4 - RW */
E1000_FEXTNVM = 0x00028, /* Future Extended NVM - RW */
E1000_FCT = 0x00030, /* Flow Control Type - RW */
E1000_VET = 0x00038, /* VLAN Ether Type - RW */
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
index 63930d1..57b5435 100644
--- a/drivers/net/e1000e/ich8lan.c
+++ b/drivers/net/e1000e/ich8lan.c
@@ -105,6 +105,10 @@
#define E1000_FEXTNVM_SW_CONFIG 1
#define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* Bit redefined for ICH8M :/ */
+#define E1000_FEXTNVM4_BEACON_DURATION_MASK 0x7
+#define E1000_FEXTNVM4_BEACON_DURATION_8USEC 0x7
+#define E1000_FEXTNVM4_BEACON_DURATION_16USEC 0x3
+
#define PCIE_ICH8_SNOOP_ALL PCIE_NO_SNOOP_ALL
#define E1000_ICH_RAR_ENTRIES 7
@@ -125,6 +129,7 @@
/* SMBus Address Phy Register */
#define HV_SMB_ADDR PHY_REG(768, 26)
+#define HV_SMB_ADDR_MASK 0x007F
#define HV_SMB_ADDR_PEC_EN 0x0200
#define HV_SMB_ADDR_VALID 0x0080
@@ -237,6 +242,8 @@
static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw);
static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw);
static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw);
+static s32 e1000_k1_workaround_lv(struct e1000_hw *hw);
+static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate);
static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg)
{
@@ -272,7 +279,7 @@
static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
{
struct e1000_phy_info *phy = &hw->phy;
- u32 ctrl;
+ u32 ctrl, fwsm;
s32 ret_val = 0;
phy->addr = 1;
@@ -294,7 +301,8 @@
* disabled, then toggle the LANPHYPC Value bit to force
* the interconnect to PCIe mode.
*/
- if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) {
+ fwsm = er32(FWSM);
+ if (!(fwsm & E1000_ICH_FWSM_FW_VALID)) {
ctrl = er32(CTRL);
ctrl |= E1000_CTRL_LANPHYPC_OVERRIDE;
ctrl &= ~E1000_CTRL_LANPHYPC_VALUE;
@@ -303,6 +311,13 @@
ctrl &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
ew32(CTRL, ctrl);
msleep(50);
+
+ /*
+ * Gate automatic PHY configuration by hardware on
+ * non-managed 82579
+ */
+ if (hw->mac.type == e1000_pch2lan)
+ e1000_gate_hw_phy_config_ich8lan(hw, true);
}
/*
@@ -315,6 +330,13 @@
if (ret_val)
goto out;
+ /* Ungate automatic PHY configuration on non-managed 82579 */
+ if ((hw->mac.type == e1000_pch2lan) &&
+ !(fwsm & E1000_ICH_FWSM_FW_VALID)) {
+ msleep(10);
+ e1000_gate_hw_phy_config_ich8lan(hw, false);
+ }
+
phy->id = e1000_phy_unknown;
ret_val = e1000e_get_phy_id(hw);
if (ret_val)
@@ -561,13 +583,10 @@
if (mac->type == e1000_ich8lan)
e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, true);
- /* Disable PHY configuration by hardware, config by software */
- if (mac->type == e1000_pch2lan) {
- u32 extcnf_ctrl = er32(EXTCNF_CTRL);
-
- extcnf_ctrl |= E1000_EXTCNF_CTRL_GATE_PHY_CFG;
- ew32(EXTCNF_CTRL, extcnf_ctrl);
- }
+ /* Gate automatic PHY configuration by hardware on managed 82579 */
+ if ((mac->type == e1000_pch2lan) &&
+ (er32(FWSM) & E1000_ICH_FWSM_FW_VALID))
+ e1000_gate_hw_phy_config_ich8lan(hw, true);
return 0;
}
@@ -652,6 +671,12 @@
goto out;
}
+ if (hw->mac.type == e1000_pch2lan) {
+ ret_val = e1000_k1_workaround_lv(hw);
+ if (ret_val)
+ goto out;
+ }
+
/*
* Check if there was DownShift, must be checked
* immediately after link-up
@@ -895,6 +920,34 @@
}
/**
+ * e1000_write_smbus_addr - Write SMBus address to PHY needed during Sx states
+ * @hw: pointer to the HW structure
+ *
+ * Assumes semaphore already acquired.
+ *
+ **/
+static s32 e1000_write_smbus_addr(struct e1000_hw *hw)
+{
+ u16 phy_data;
+ u32 strap = er32(STRAP);
+ s32 ret_val = 0;
+
+ strap &= E1000_STRAP_SMBUS_ADDRESS_MASK;
+
+ ret_val = e1000_read_phy_reg_hv_locked(hw, HV_SMB_ADDR, &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data &= ~HV_SMB_ADDR_MASK;
+ phy_data |= (strap >> E1000_STRAP_SMBUS_ADDRESS_SHIFT);
+ phy_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID;
+ ret_val = e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR, phy_data);
+
+out:
+ return ret_val;
+}
+
+/**
* e1000_sw_lcd_config_ich8lan - SW-based LCD Configuration
* @hw: pointer to the HW structure
*
@@ -903,7 +956,6 @@
**/
static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
{
- struct e1000_adapter *adapter = hw->adapter;
struct e1000_phy_info *phy = &hw->phy;
u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask;
s32 ret_val = 0;
@@ -921,7 +973,8 @@
if (phy->type != e1000_phy_igp_3)
return ret_val;
- if (adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_AMT) {
+ if ((hw->adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_AMT) ||
+ (hw->adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_C)) {
sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
break;
}
@@ -961,21 +1014,16 @@
cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
- if (!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) &&
- ((hw->mac.type == e1000_pchlan) ||
- (hw->mac.type == e1000_pch2lan))) {
+ if ((!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) &&
+ (hw->mac.type == e1000_pchlan)) ||
+ (hw->mac.type == e1000_pch2lan)) {
/*
* HW configures the SMBus address and LEDs when the
* OEM and LCD Write Enable bits are set in the NVM.
* When both NVM bits are cleared, SW will configure
* them instead.
*/
- data = er32(STRAP);
- data &= E1000_STRAP_SMBUS_ADDRESS_MASK;
- reg_data = data >> E1000_STRAP_SMBUS_ADDRESS_SHIFT;
- reg_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID;
- ret_val = e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR,
- reg_data);
+ ret_val = e1000_write_smbus_addr(hw);
if (ret_val)
goto out;
@@ -1440,10 +1488,6 @@
goto out;
/* Enable jumbo frame workaround in the PHY */
- e1e_rphy(hw, PHY_REG(769, 20), &data);
- ret_val = e1e_wphy(hw, PHY_REG(769, 20), data & ~(1 << 14));
- if (ret_val)
- goto out;
e1e_rphy(hw, PHY_REG(769, 23), &data);
data &= ~(0x7F << 5);
data |= (0x37 << 5);
@@ -1452,7 +1496,6 @@
goto out;
e1e_rphy(hw, PHY_REG(769, 16), &data);
data &= ~(1 << 13);
- data |= (1 << 12);
ret_val = e1e_wphy(hw, PHY_REG(769, 16), data);
if (ret_val)
goto out;
@@ -1477,7 +1520,7 @@
mac_reg = er32(RCTL);
mac_reg &= ~E1000_RCTL_SECRC;
- ew32(FFLT_DBG, mac_reg);
+ ew32(RCTL, mac_reg);
ret_val = e1000e_read_kmrn_reg(hw,
E1000_KMRNCTRLSTA_CTRL_OFFSET,
@@ -1503,17 +1546,12 @@
goto out;
/* Write PHY register values back to h/w defaults */
- e1e_rphy(hw, PHY_REG(769, 20), &data);
- ret_val = e1e_wphy(hw, PHY_REG(769, 20), data & ~(1 << 14));
- if (ret_val)
- goto out;
e1e_rphy(hw, PHY_REG(769, 23), &data);
data &= ~(0x7F << 5);
ret_val = e1e_wphy(hw, PHY_REG(769, 23), data);
if (ret_val)
goto out;
e1e_rphy(hw, PHY_REG(769, 16), &data);
- data &= ~(1 << 12);
data |= (1 << 13);
ret_val = e1e_wphy(hw, PHY_REG(769, 16), data);
if (ret_val)
@@ -1559,6 +1597,69 @@
}
/**
+ * e1000_k1_gig_workaround_lv - K1 Si workaround
+ * @hw: pointer to the HW structure
+ *
+ * Workaround to set the K1 beacon duration for 82579 parts
+ **/
+static s32 e1000_k1_workaround_lv(struct e1000_hw *hw)
+{
+ s32 ret_val = 0;
+ u16 status_reg = 0;
+ u32 mac_reg;
+
+ if (hw->mac.type != e1000_pch2lan)
+ goto out;
+
+ /* Set K1 beacon duration based on 1Gbps speed or otherwise */
+ ret_val = e1e_rphy(hw, HV_M_STATUS, &status_reg);
+ if (ret_val)
+ goto out;
+
+ if ((status_reg & (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE))
+ == (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE)) {
+ 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;
+
+ ew32(FEXTNVM4, mac_reg);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_gate_hw_phy_config_ich8lan - disable PHY config via hardware
+ * @hw: pointer to the HW structure
+ * @gate: boolean set to true to gate, false to ungate
+ *
+ * Gate/ungate the automatic PHY configuration via hardware; perform
+ * the configuration via software instead.
+ **/
+static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate)
+{
+ u32 extcnf_ctrl;
+
+ if (hw->mac.type != e1000_pch2lan)
+ return;
+
+ extcnf_ctrl = er32(EXTCNF_CTRL);
+
+ if (gate)
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_GATE_PHY_CFG;
+ else
+ extcnf_ctrl &= ~E1000_EXTCNF_CTRL_GATE_PHY_CFG;
+
+ ew32(EXTCNF_CTRL, extcnf_ctrl);
+ return;
+}
+
+/**
* e1000_lan_init_done_ich8lan - Check for PHY config completion
* @hw: pointer to the HW structure
*
@@ -1602,6 +1703,9 @@
if (e1000_check_reset_block(hw))
goto out;
+ /* Allow time for h/w to get to quiescent state after reset */
+ msleep(10);
+
/* Perform any necessary post-reset workarounds */
switch (hw->mac.type) {
case e1000_pchlan:
@@ -1630,6 +1734,13 @@
/* Configure the LCD with the OEM bits in NVM */
ret_val = e1000_oem_bits_config_ich8lan(hw, true);
+ /* Ungate automatic PHY configuration on non-managed 82579 */
+ if ((hw->mac.type == e1000_pch2lan) &&
+ !(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) {
+ msleep(10);
+ e1000_gate_hw_phy_config_ich8lan(hw, false);
+ }
+
out:
return ret_val;
}
@@ -1646,6 +1757,11 @@
{
s32 ret_val = 0;
+ /* Gate automatic PHY configuration by hardware on non-managed 82579 */
+ if ((hw->mac.type == e1000_pch2lan) &&
+ !(er32(FWSM) & E1000_ICH_FWSM_FW_VALID))
+ e1000_gate_hw_phy_config_ich8lan(hw, true);
+
ret_val = e1000e_phy_hw_reset_generic(hw);
if (ret_val)
goto out;
@@ -2910,6 +3026,14 @@
* external PHY is reset.
*/
ctrl |= E1000_CTRL_PHY_RST;
+
+ /*
+ * Gate automatic PHY configuration by hardware on
+ * non-managed 82579
+ */
+ if ((hw->mac.type == e1000_pch2lan) &&
+ !(er32(FWSM) & E1000_ICH_FWSM_FW_VALID))
+ e1000_gate_hw_phy_config_ich8lan(hw, true);
}
ret_val = e1000_acquire_swflag_ich8lan(hw);
e_dbg("Issuing a global reset to ich8lan\n");
@@ -3460,13 +3584,20 @@
void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw)
{
u32 phy_ctrl;
+ s32 ret_val;
phy_ctrl = er32(PHY_CTRL);
phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU | E1000_PHY_CTRL_GBE_DISABLE;
ew32(PHY_CTRL, phy_ctrl);
- if (hw->mac.type >= e1000_pchlan)
- e1000_phy_hw_reset_ich8lan(hw);
+ if (hw->mac.type >= e1000_pchlan) {
+ e1000_oem_bits_config_ich8lan(hw, true);
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return;
+ e1000_write_smbus_addr(hw);
+ hw->phy.ops.release(hw);
+ }
}
/**
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 2b8ef44..e561d15 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -2704,6 +2704,16 @@
u32 psrctl = 0;
u32 pages = 0;
+ /* Workaround Si errata on 82579 - configure jumbo frame flow */
+ if (hw->mac.type == e1000_pch2lan) {
+ s32 ret_val;
+
+ if (adapter->netdev->mtu > ETH_DATA_LEN)
+ ret_val = e1000_lv_jumbo_workaround_ich8lan(hw, true);
+ else
+ ret_val = e1000_lv_jumbo_workaround_ich8lan(hw, false);
+ }
+
/* Program MC offset vector base */
rctl = er32(RCTL);
rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
@@ -2744,16 +2754,6 @@
e1e_wphy(hw, 22, phy_data);
}
- /* Workaround Si errata on 82579 - configure jumbo frame flow */
- if (hw->mac.type == e1000_pch2lan) {
- s32 ret_val;
-
- if (rctl & E1000_RCTL_LPE)
- ret_val = e1000_lv_jumbo_workaround_ich8lan(hw, true);
- else
- ret_val = e1000_lv_jumbo_workaround_ich8lan(hw, false);
- }
-
/* Setup buffer sizes */
rctl &= ~E1000_RCTL_SZ_4096;
rctl |= E1000_RCTL_BSEX;
@@ -4833,6 +4833,15 @@
return -EINVAL;
}
+ /* Jumbo frame workaround on 82579 requires CRC be stripped */
+ if ((adapter->hw.mac.type == e1000_pch2lan) &&
+ !(adapter->flags2 & FLAG2_CRC_STRIPPING) &&
+ (new_mtu > ETH_DATA_LEN)) {
+ e_err("Jumbo Frames not supported on 82579 when CRC "
+ "stripping is disabled.\n");
+ return -EINVAL;
+ }
+
/* 82573 Errata 17 */
if (((adapter->hw.mac.type == e1000_82573) ||
(adapter->hw.mac.type == e1000_82574)) &&
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index a333b42..6372610 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -533,8 +533,15 @@
int length = cqe->num_bytes_transfered - 4; /*remove CRC */
skb_put(skb, length);
- skb->ip_summed = CHECKSUM_UNNECESSARY;
skb->protocol = eth_type_trans(skb, dev);
+
+ /* The packet was not an IPV4 packet so a complemented checksum was
+ calculated. The value is found in the Internet Checksum field. */
+ if (cqe->status & EHEA_CQE_BLIND_CKSUM) {
+ skb->ip_summed = CHECKSUM_COMPLETE;
+ skb->csum = csum_unfold(~cqe->inet_checksum_value);
+ } else
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
}
static inline struct sk_buff *get_skb_by_index(struct sk_buff **skb_array,
diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h
index f608a6c..3810473 100644
--- a/drivers/net/ehea/ehea_qmr.h
+++ b/drivers/net/ehea/ehea_qmr.h
@@ -150,6 +150,7 @@
#define EHEA_CQE_TYPE_RQ 0x60
#define EHEA_CQE_STAT_ERR_MASK 0x700F
#define EHEA_CQE_STAT_FAT_ERR_MASK 0xF
+#define EHEA_CQE_BLIND_CKSUM 0x8000
#define EHEA_CQE_STAT_ERR_TCP 0x4000
#define EHEA_CQE_STAT_ERR_IP 0x2000
#define EHEA_CQE_STAT_ERR_CRC 0x1000
diff --git a/drivers/net/eql.c b/drivers/net/eql.c
index dda2c79..0cb1cf9 100644
--- a/drivers/net/eql.c
+++ b/drivers/net/eql.c
@@ -555,6 +555,8 @@
equalizer_t *eql;
master_config_t mc;
+ memset(&mc, 0, sizeof(master_config_t));
+
if (eql_is_master(dev)) {
eql = netdev_priv(dev);
mc.max_slaves = eql->max_slaves;
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index 768b840..cce32d4 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -678,24 +678,37 @@
{
struct fec_enet_private *fep = netdev_priv(dev);
struct phy_device *phy_dev = NULL;
- int ret;
+ char mdio_bus_id[MII_BUS_ID_SIZE];
+ char phy_name[MII_BUS_ID_SIZE + 3];
+ int phy_id;
fep->phy_dev = NULL;
- /* find the first phy */
- phy_dev = phy_find_first(fep->mii_bus);
- if (!phy_dev) {
- printk(KERN_ERR "%s: no PHY found\n", dev->name);
- return -ENODEV;
+ /* check for attached phy */
+ for (phy_id = 0; (phy_id < PHY_MAX_ADDR); phy_id++) {
+ if ((fep->mii_bus->phy_mask & (1 << phy_id)))
+ continue;
+ if (fep->mii_bus->phy_map[phy_id] == NULL)
+ continue;
+ if (fep->mii_bus->phy_map[phy_id]->phy_id == 0)
+ continue;
+ strncpy(mdio_bus_id, fep->mii_bus->id, MII_BUS_ID_SIZE);
+ break;
}
- /* attach the mac to the phy */
- ret = phy_connect_direct(dev, phy_dev,
- &fec_enet_adjust_link, 0,
- PHY_INTERFACE_MODE_MII);
- if (ret) {
- printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
- return ret;
+ if (phy_id >= PHY_MAX_ADDR) {
+ printk(KERN_INFO "%s: no PHY, assuming direct connection "
+ "to switch\n", dev->name);
+ strncpy(mdio_bus_id, "0", MII_BUS_ID_SIZE);
+ phy_id = 0;
+ }
+
+ snprintf(phy_name, MII_BUS_ID_SIZE, PHY_ID_FMT, mdio_bus_id, phy_id);
+ phy_dev = phy_connect(dev, phy_name, &fec_enet_adjust_link, 0,
+ PHY_INTERFACE_MODE_MII);
+ if (IS_ERR(phy_dev)) {
+ printk(KERN_ERR "%s: could not attach to PHY\n", dev->name);
+ return PTR_ERR(phy_dev);
}
/* mask with MAC supported features */
@@ -738,7 +751,7 @@
fep->mii_bus->read = fec_enet_mdio_read;
fep->mii_bus->write = fec_enet_mdio_write;
fep->mii_bus->reset = fec_enet_mdio_reset;
- snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id);
+ snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id + 1);
fep->mii_bus->priv = fep;
fep->mii_bus->parent = &pdev->dev;
@@ -1311,6 +1324,9 @@
if (ret)
goto failed_mii_init;
+ /* Carrier starts down, phylib will bring it up */
+ netif_carrier_off(ndev);
+
ret = register_netdev(ndev);
if (ret)
goto failed_register;
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index 3506fd6..519e19e 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -2928,7 +2928,7 @@
if (dev->emac_irq != NO_IRQ)
irq_dispose_mapping(dev->emac_irq);
err_free:
- kfree(ndev);
+ free_netdev(ndev);
err_gone:
/* if we were on the bootlist, remove us as we won't show up and
* wake up all waiters to notify them in case they were waiting
@@ -2971,7 +2971,7 @@
if (dev->emac_irq != NO_IRQ)
irq_dispose_mapping(dev->emac_irq);
- kfree(dev->ndev);
+ free_netdev(dev->ndev);
return 0;
}
diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c
index bdf2149..87f0a93 100644
--- a/drivers/net/ll_temac_main.c
+++ b/drivers/net/ll_temac_main.c
@@ -38,6 +38,7 @@
#include <linux/of_device.h>
#include <linux/of_mdio.h>
#include <linux/of_platform.h>
+#include <linux/of_address.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/tcp.h> /* needed for sizeof(tcphdr) */
diff --git a/drivers/net/ll_temac_mdio.c b/drivers/net/ll_temac_mdio.c
index 5ae28c9..8cf9d4f 100644
--- a/drivers/net/ll_temac_mdio.c
+++ b/drivers/net/ll_temac_mdio.c
@@ -10,6 +10,7 @@
#include <linux/phy.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/of_address.h>
#include <linux/slab.h>
#include <linux/of_mdio.h>
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index cabae7b..b075a35 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -1540,7 +1540,6 @@
if (pkt_offset)
skb_pull(skb, pkt_offset);
- skb->truesize = skb->len + sizeof(struct sk_buff);
skb->protocol = eth_type_trans(skb, netdev);
napi_gro_receive(&sds_ring->napi, skb);
@@ -1602,8 +1601,6 @@
skb_put(skb, lro_length + data_offset);
- skb->truesize = skb->len + sizeof(struct sk_buff) + skb_headroom(skb);
-
skb_pull(skb, l2_hdr_offset);
skb->protocol = eth_type_trans(skb, netdev);
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index 49279b0..f9b509a 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -508,7 +508,8 @@
unsigned int vcc,
void *priv_data)
{
- int *has_shmem = priv_data;
+ int *priv = priv_data;
+ int try = (*priv & 0x1);
int i;
cistpl_io_t *io = &cfg->io;
@@ -525,77 +526,103 @@
i = p_dev->resource[1]->end = 0;
}
- *has_shmem = ((cfg->mem.nwin == 1) &&
- (cfg->mem.win[0].len >= 0x4000));
+ *priv &= ((cfg->mem.nwin == 1) &&
+ (cfg->mem.win[0].len >= 0x4000)) ? 0x10 : ~0x10;
+
p_dev->resource[0]->start = io->win[i].base;
p_dev->resource[0]->end = io->win[i].len;
- p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
+ if (!try)
+ p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
+ else
+ p_dev->io_lines = 16;
if (p_dev->resource[0]->end + p_dev->resource[1]->end >= 32)
return try_io_port(p_dev);
- return 0;
+ return -EINVAL;
+}
+
+static hw_info_t *pcnet_try_config(struct pcmcia_device *link,
+ int *has_shmem, int try)
+{
+ struct net_device *dev = link->priv;
+ hw_info_t *local_hw_info;
+ pcnet_dev_t *info = PRIV(dev);
+ int priv = try;
+ int ret;
+
+ ret = pcmcia_loop_config(link, pcnet_confcheck, &priv);
+ if (ret) {
+ dev_warn(&link->dev, "no useable port range found\n");
+ return NULL;
+ }
+ *has_shmem = (priv & 0x10);
+
+ if (!link->irq)
+ return NULL;
+
+ if (resource_size(link->resource[1]) == 8) {
+ link->conf.Attributes |= CONF_ENABLE_SPKR;
+ link->conf.Status = CCSR_AUDIO_ENA;
+ }
+ if ((link->manf_id == MANFID_IBM) &&
+ (link->card_id == PRODID_IBM_HOME_AND_AWAY))
+ link->conf.ConfigIndex |= 0x10;
+
+ ret = pcmcia_request_configuration(link, &link->conf);
+ if (ret)
+ return NULL;
+
+ dev->irq = link->irq;
+ dev->base_addr = link->resource[0]->start;
+
+ if (info->flags & HAS_MISC_REG) {
+ if ((if_port == 1) || (if_port == 2))
+ dev->if_port = if_port;
+ else
+ dev_notice(&link->dev, "invalid if_port requested\n");
+ } else
+ dev->if_port = 0;
+
+ if ((link->conf.ConfigBase == 0x03c0) &&
+ (link->manf_id == 0x149) && (link->card_id == 0xc1ab)) {
+ dev_info(&link->dev,
+ "this is an AX88190 card - use axnet_cs instead.\n");
+ return NULL;
+ }
+
+ local_hw_info = get_hwinfo(link);
+ if (!local_hw_info)
+ local_hw_info = get_prom(link);
+ if (!local_hw_info)
+ local_hw_info = get_dl10019(link);
+ if (!local_hw_info)
+ local_hw_info = get_ax88190(link);
+ if (!local_hw_info)
+ local_hw_info = get_hwired(link);
+
+ return local_hw_info;
}
static int pcnet_config(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
pcnet_dev_t *info = PRIV(dev);
- int ret, start_pg, stop_pg, cm_offset;
+ int start_pg, stop_pg, cm_offset;
int has_shmem = 0;
hw_info_t *local_hw_info;
dev_dbg(&link->dev, "pcnet_config\n");
- ret = pcmcia_loop_config(link, pcnet_confcheck, &has_shmem);
- if (ret)
- goto failed;
-
- if (!link->irq)
- goto failed;
-
- if (resource_size(link->resource[1]) == 8) {
- link->conf.Attributes |= CONF_ENABLE_SPKR;
- link->conf.Status = CCSR_AUDIO_ENA;
- }
- if ((link->manf_id == MANFID_IBM) &&
- (link->card_id == PRODID_IBM_HOME_AND_AWAY))
- link->conf.ConfigIndex |= 0x10;
-
- ret = pcmcia_request_configuration(link, &link->conf);
- if (ret)
- goto failed;
- dev->irq = link->irq;
- dev->base_addr = link->resource[0]->start;
- if (info->flags & HAS_MISC_REG) {
- if ((if_port == 1) || (if_port == 2))
- dev->if_port = if_port;
- else
- printk(KERN_NOTICE "pcnet_cs: invalid if_port requested\n");
- } else {
- dev->if_port = 0;
- }
-
- if ((link->conf.ConfigBase == 0x03c0) &&
- (link->manf_id == 0x149) && (link->card_id == 0xc1ab)) {
- printk(KERN_INFO "pcnet_cs: this is an AX88190 card!\n");
- printk(KERN_INFO "pcnet_cs: use axnet_cs instead.\n");
- goto failed;
- }
-
- local_hw_info = get_hwinfo(link);
- if (local_hw_info == NULL)
- local_hw_info = get_prom(link);
- if (local_hw_info == NULL)
- local_hw_info = get_dl10019(link);
- if (local_hw_info == NULL)
- local_hw_info = get_ax88190(link);
- if (local_hw_info == NULL)
- local_hw_info = get_hwired(link);
-
- if (local_hw_info == NULL) {
- printk(KERN_NOTICE "pcnet_cs: unable to read hardware net"
- " address for io base %#3lx\n", dev->base_addr);
- goto failed;
+ local_hw_info = pcnet_try_config(link, &has_shmem, 0);
+ if (!local_hw_info) {
+ /* check whether forcing io_lines to 16 helps... */
+ pcmcia_disable_device(link);
+ local_hw_info = pcnet_try_config(link, &has_shmem, 1);
+ if (local_hw_info == NULL) {
+ dev_notice(&link->dev, "unable to read hardware net"
+ " address for io base %#3lx\n", dev->base_addr);
+ goto failed;
+ }
}
info->flags = local_hw_info->flags;
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 6a6b819..6c58da2 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -308,7 +308,7 @@
* may call phy routines that try to grab the same lock, and that may
* lead to a deadlock.
*/
- if (phydev->attached_dev)
+ if (phydev->attached_dev && phydev->adjust_link)
phy_stop_machine(phydev);
if (!mdio_bus_phy_may_suspend(phydev))
@@ -331,7 +331,7 @@
return ret;
no_resume:
- if (phydev->attached_dev)
+ if (phydev->attached_dev && phydev->adjust_link)
phy_start_machine(phydev, NULL);
return 0;
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 6695a51..736b917 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -1314,8 +1314,13 @@
hdrlen = (ppp->flags & SC_MP_XSHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN;
i = 0;
list_for_each_entry(pch, &ppp->channels, clist) {
- navail += pch->avail = (pch->chan != NULL);
- pch->speed = pch->chan->speed;
+ if (pch->chan) {
+ pch->avail = 1;
+ navail++;
+ pch->speed = pch->chan->speed;
+ } else {
+ pch->avail = 0;
+ }
if (pch->avail) {
if (skb_queue_empty(&pch->file.xq) ||
!pch->had_frag) {
diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c
index 75ba744..2c7cf0b 100644
--- a/drivers/net/qlcnic/qlcnic_init.c
+++ b/drivers/net/qlcnic/qlcnic_init.c
@@ -1316,7 +1316,7 @@
return -ENOMEM;
}
- skb_reserve(skb, 2);
+ skb_reserve(skb, NET_IP_ALIGN);
dma = pci_map_single(pdev, skb->data,
rds_ring->dma_size, PCI_DMA_FROMDEVICE);
@@ -1404,7 +1404,6 @@
if (pkt_offset)
skb_pull(skb, pkt_offset);
- skb->truesize = skb->len + sizeof(struct sk_buff);
skb->protocol = eth_type_trans(skb, netdev);
napi_gro_receive(&sds_ring->napi, skb);
@@ -1466,8 +1465,6 @@
skb_put(skb, lro_length + data_offset);
- skb->truesize = skb->len + sizeof(struct sk_buff) + skb_headroom(skb);
-
skb_pull(skb, l2_hdr_offset);
skb->protocol = eth_type_trans(skb, netdev);
@@ -1700,8 +1697,6 @@
if (pkt_offset)
skb_pull(skb, pkt_offset);
- skb->truesize = skb->len + sizeof(struct sk_buff);
-
if (!qlcnic_check_loopback_buff(skb->data))
adapter->diag_cnt++;
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 078bbf4..992db2f 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -1212,7 +1212,8 @@
if ((RTL_R8(ChipCmd) & CmdRxEnb) == 0)
return;
- counters = pci_alloc_consistent(tp->pci_dev, sizeof(*counters), &paddr);
+ counters = dma_alloc_coherent(&tp->pci_dev->dev, sizeof(*counters),
+ &paddr, GFP_KERNEL);
if (!counters)
return;
@@ -1233,7 +1234,8 @@
RTL_W32(CounterAddrLow, 0);
RTL_W32(CounterAddrHigh, 0);
- pci_free_consistent(tp->pci_dev, sizeof(*counters), counters, paddr);
+ dma_free_coherent(&tp->pci_dev->dev, sizeof(*counters), counters,
+ paddr);
}
static void rtl8169_get_ethtool_stats(struct net_device *dev,
@@ -2934,7 +2936,7 @@
.hw_start = rtl_hw_start_8168,
.region = 2,
.align = 8,
- .intr_event = SYSErr | LinkChg | RxOverflow |
+ .intr_event = SYSErr | RxFIFOOver | LinkChg | RxOverflow |
TxErr | TxOK | RxOK | RxErr,
.napi_event = TxErr | TxOK | RxOK | RxOverflow,
.features = RTL_FEATURE_GMII | RTL_FEATURE_MSI,
@@ -3292,15 +3294,15 @@
/*
* Rx and Tx desscriptors needs 256 bytes alignment.
- * pci_alloc_consistent provides more.
+ * dma_alloc_coherent provides more.
*/
- tp->TxDescArray = pci_alloc_consistent(pdev, R8169_TX_RING_BYTES,
- &tp->TxPhyAddr);
+ tp->TxDescArray = dma_alloc_coherent(&pdev->dev, R8169_TX_RING_BYTES,
+ &tp->TxPhyAddr, GFP_KERNEL);
if (!tp->TxDescArray)
goto err_pm_runtime_put;
- tp->RxDescArray = pci_alloc_consistent(pdev, R8169_RX_RING_BYTES,
- &tp->RxPhyAddr);
+ tp->RxDescArray = dma_alloc_coherent(&pdev->dev, R8169_RX_RING_BYTES,
+ &tp->RxPhyAddr, GFP_KERNEL);
if (!tp->RxDescArray)
goto err_free_tx_0;
@@ -3334,12 +3336,12 @@
err_release_ring_2:
rtl8169_rx_clear(tp);
err_free_rx_1:
- pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray,
- tp->RxPhyAddr);
+ dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
+ tp->RxPhyAddr);
tp->RxDescArray = NULL;
err_free_tx_0:
- pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray,
- tp->TxPhyAddr);
+ dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
+ tp->TxPhyAddr);
tp->TxDescArray = NULL;
err_pm_runtime_put:
pm_runtime_put_noidle(&pdev->dev);
@@ -3975,7 +3977,7 @@
{
struct pci_dev *pdev = tp->pci_dev;
- pci_unmap_single(pdev, le64_to_cpu(desc->addr), tp->rx_buf_sz,
+ dma_unmap_single(&pdev->dev, le64_to_cpu(desc->addr), tp->rx_buf_sz,
PCI_DMA_FROMDEVICE);
dev_kfree_skb(*sk_buff);
*sk_buff = NULL;
@@ -4000,7 +4002,7 @@
static struct sk_buff *rtl8169_alloc_rx_skb(struct pci_dev *pdev,
struct net_device *dev,
struct RxDesc *desc, int rx_buf_sz,
- unsigned int align)
+ unsigned int align, gfp_t gfp)
{
struct sk_buff *skb;
dma_addr_t mapping;
@@ -4008,13 +4010,13 @@
pad = align ? align : NET_IP_ALIGN;
- skb = netdev_alloc_skb(dev, rx_buf_sz + pad);
+ skb = __netdev_alloc_skb(dev, rx_buf_sz + pad, gfp);
if (!skb)
goto err_out;
skb_reserve(skb, align ? ((pad - 1) & (unsigned long)skb->data) : pad);
- mapping = pci_map_single(pdev, skb->data, rx_buf_sz,
+ mapping = dma_map_single(&pdev->dev, skb->data, rx_buf_sz,
PCI_DMA_FROMDEVICE);
rtl8169_map_to_asic(desc, mapping, rx_buf_sz);
@@ -4039,7 +4041,7 @@
}
static u32 rtl8169_rx_fill(struct rtl8169_private *tp, struct net_device *dev,
- u32 start, u32 end)
+ u32 start, u32 end, gfp_t gfp)
{
u32 cur;
@@ -4054,7 +4056,7 @@
skb = rtl8169_alloc_rx_skb(tp->pci_dev, dev,
tp->RxDescArray + i,
- tp->rx_buf_sz, tp->align);
+ tp->rx_buf_sz, tp->align, gfp);
if (!skb)
break;
@@ -4082,7 +4084,7 @@
memset(tp->tx_skb, 0x0, NUM_TX_DESC * sizeof(struct ring_info));
memset(tp->Rx_skbuff, 0x0, NUM_RX_DESC * sizeof(struct sk_buff *));
- if (rtl8169_rx_fill(tp, dev, 0, NUM_RX_DESC) != NUM_RX_DESC)
+ if (rtl8169_rx_fill(tp, dev, 0, NUM_RX_DESC, GFP_KERNEL) != NUM_RX_DESC)
goto err_out;
rtl8169_mark_as_last_descriptor(tp->RxDescArray + NUM_RX_DESC - 1);
@@ -4099,7 +4101,8 @@
{
unsigned int len = tx_skb->len;
- pci_unmap_single(pdev, le64_to_cpu(desc->addr), len, PCI_DMA_TODEVICE);
+ dma_unmap_single(&pdev->dev, le64_to_cpu(desc->addr), len,
+ PCI_DMA_TODEVICE);
desc->opts1 = 0x00;
desc->opts2 = 0x00;
desc->addr = 0x00;
@@ -4243,7 +4246,8 @@
txd = tp->TxDescArray + entry;
len = frag->size;
addr = ((void *) page_address(frag->page)) + frag->page_offset;
- mapping = pci_map_single(tp->pci_dev, addr, len, PCI_DMA_TODEVICE);
+ mapping = dma_map_single(&tp->pci_dev->dev, addr, len,
+ PCI_DMA_TODEVICE);
/* anti gcc 2.95.3 bugware (sic) */
status = opts1 | len | (RingEnd * !((entry + 1) % NUM_TX_DESC));
@@ -4313,7 +4317,8 @@
tp->tx_skb[entry].skb = skb;
}
- mapping = pci_map_single(tp->pci_dev, skb->data, len, PCI_DMA_TODEVICE);
+ mapping = dma_map_single(&tp->pci_dev->dev, skb->data, len,
+ PCI_DMA_TODEVICE);
tp->tx_skb[entry].len = len;
txd->addr = cpu_to_le64(mapping);
@@ -4477,8 +4482,8 @@
if (!skb)
goto out;
- pci_dma_sync_single_for_cpu(tp->pci_dev, addr, pkt_size,
- PCI_DMA_FROMDEVICE);
+ dma_sync_single_for_cpu(&tp->pci_dev->dev, addr, pkt_size,
+ PCI_DMA_FROMDEVICE);
skb_copy_from_linear_data(*sk_buff, skb->data, pkt_size);
*sk_buff = skb;
done = true;
@@ -4549,11 +4554,11 @@
rtl8169_rx_csum(skb, desc);
if (rtl8169_try_rx_copy(&skb, tp, pkt_size, addr)) {
- pci_dma_sync_single_for_device(pdev, addr,
+ dma_sync_single_for_device(&pdev->dev, addr,
pkt_size, PCI_DMA_FROMDEVICE);
rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
} else {
- pci_unmap_single(pdev, addr, tp->rx_buf_sz,
+ dma_unmap_single(&pdev->dev, addr, tp->rx_buf_sz,
PCI_DMA_FROMDEVICE);
tp->Rx_skbuff[entry] = NULL;
}
@@ -4583,7 +4588,7 @@
count = cur_rx - tp->cur_rx;
tp->cur_rx = cur_rx;
- delta = rtl8169_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx);
+ delta = rtl8169_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx, GFP_ATOMIC);
if (!delta && count)
netif_info(tp, intr, dev, "no Rx buffer allocated\n");
tp->dirty_rx += delta;
@@ -4625,8 +4630,7 @@
}
/* Work around for rx fifo overflow */
- if (unlikely(status & RxFIFOOver) &&
- (tp->mac_version == RTL_GIGA_MAC_VER_11)) {
+ if (unlikely(status & RxFIFOOver)) {
netif_stop_queue(dev);
rtl8169_tx_timeout(dev);
break;
@@ -4770,10 +4774,10 @@
free_irq(dev->irq, dev);
- pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray,
- tp->RxPhyAddr);
- pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray,
- tp->TxPhyAddr);
+ dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
+ tp->RxPhyAddr);
+ dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
+ tp->TxPhyAddr);
tp->TxDescArray = NULL;
tp->RxDescArray = NULL;
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
index 07eb884..44150f2 100644
--- a/drivers/net/rionet.c
+++ b/drivers/net/rionet.c
@@ -384,7 +384,7 @@
free_pages((unsigned long)rionet_active, rdev->net->hport->sys_size ?
__ilog2(sizeof(void *)) + 4 : 0);
unregister_netdev(ndev);
- kfree(ndev);
+ free_netdev(ndev);
list_for_each_entry_safe(peer, tmp, &rionet_peers, node) {
list_del(&peer->node);
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index cc4bd8c..9265315 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -804,7 +804,7 @@
err_out_free_page:
free_page((unsigned long) sp->srings);
err_out_free_dev:
- kfree(dev);
+ free_netdev(dev);
err_out:
return err;
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 40e5c46..465ae7e 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -43,6 +43,7 @@
#include <linux/seq_file.h>
#include <linux/mii.h>
#include <linux/slab.h>
+#include <linux/dmi.h>
#include <asm/irq.h>
#include "skge.h"
@@ -3868,6 +3869,8 @@
netif_info(skge, probe, skge->netdev, "addr %pM\n", dev->dev_addr);
}
+static int only_32bit_dma;
+
static int __devinit skge_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -3889,7 +3892,7 @@
pci_set_master(pdev);
- if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
+ if (!only_32bit_dma && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
using_dac = 1;
err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
} else if (!(err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))) {
@@ -4147,8 +4150,21 @@
.shutdown = skge_shutdown,
};
+static struct dmi_system_id skge_32bit_dma_boards[] = {
+ {
+ .ident = "Gigabyte nForce boards",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co"),
+ DMI_MATCH(DMI_BOARD_NAME, "nForce"),
+ },
+ },
+ {}
+};
+
static int __init skge_init_module(void)
{
+ if (dmi_check_system(skge_32bit_dma_boards))
+ only_32bit_dma = 1;
skge_debug_init();
return pci_register_driver(&skge_driver);
}
diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c
index 0909ae9..8150ba1 100644
--- a/drivers/net/smsc911x.c
+++ b/drivers/net/smsc911x.c
@@ -58,6 +58,7 @@
MODULE_LICENSE("GPL");
MODULE_VERSION(SMSC_DRV_VERSION);
+MODULE_ALIAS("platform:smsc911x");
#if USE_DEBUG > 0
static int debug = 16;
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index bc3af78..1ec4b9e 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -4666,7 +4666,7 @@
desc_idx, *post_ptr);
drop_it_no_recycle:
/* Other statistics kept track of by card. */
- tp->net_stats.rx_dropped++;
+ tp->rx_dropped++;
goto next_pkt;
}
@@ -4726,7 +4726,7 @@
if (len > (tp->dev->mtu + ETH_HLEN) &&
skb->protocol != htons(ETH_P_8021Q)) {
dev_kfree_skb(skb);
- goto next_pkt;
+ goto drop_it_no_recycle;
}
if (desc->type_flags & RXD_FLAG_VLAN &&
@@ -9240,6 +9240,8 @@
stats->rx_missed_errors = old_stats->rx_missed_errors +
get_stat64(&hw_stats->rx_discards);
+ stats->rx_dropped = tp->rx_dropped;
+
return stats;
}
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 4937bd1..be7ff13 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -2759,7 +2759,7 @@
/* begin "everything else" cacheline(s) section */
- struct rtnl_link_stats64 net_stats;
+ unsigned long rx_dropped;
struct rtnl_link_stats64 net_stats_prev;
struct tg3_ethtool_stats estats;
struct tg3_ethtool_stats estats_prev;
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index 5efa577..6888e3d 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -243,6 +243,7 @@
NWayState = (1 << 14) | (1 << 13) | (1 << 12),
NWayRestart = (1 << 12),
NonselPortActive = (1 << 9),
+ SelPortActive = (1 << 8),
LinkFailStatus = (1 << 2),
NetCxnErr = (1 << 1),
};
@@ -363,7 +364,9 @@
/* 21041 transceiver register settings: TP AUTO, BNC, AUI, TP, TP FD*/
static u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };
-static u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x6F3F, 0x6F3D, };
+static u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
+/* If on-chip autonegotiation is broken, use half-duplex (FF3F) instead */
+static u16 t21041_csr14_brk[] = { 0xFF3F, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
@@ -1064,6 +1067,9 @@
unsigned int carrier;
unsigned long flags;
+ /* clear port active bits */
+ dw32(SIAStatus, NonselPortActive | SelPortActive);
+
carrier = (status & NetCxnErr) ? 0 : 1;
if (carrier) {
@@ -1158,14 +1164,29 @@
static void de_media_interrupt (struct de_private *de, u32 status)
{
if (status & LinkPass) {
+ /* Ignore if current media is AUI or BNC and we can't use TP */
+ if ((de->media_type == DE_MEDIA_AUI ||
+ de->media_type == DE_MEDIA_BNC) &&
+ (de->media_lock ||
+ !de_ok_to_advertise(de, DE_MEDIA_TP_AUTO)))
+ return;
+ /* If current media is not TP, change it to TP */
+ if ((de->media_type == DE_MEDIA_AUI ||
+ de->media_type == DE_MEDIA_BNC)) {
+ de->media_type = DE_MEDIA_TP_AUTO;
+ de_stop_rxtx(de);
+ de_set_media(de);
+ de_start_rxtx(de);
+ }
de_link_up(de);
mod_timer(&de->media_timer, jiffies + DE_TIMER_LINK);
return;
}
BUG_ON(!(status & LinkFail));
-
- if (netif_carrier_ok(de->dev)) {
+ /* Mark the link as down only if current media is TP */
+ if (netif_carrier_ok(de->dev) && de->media_type != DE_MEDIA_AUI &&
+ de->media_type != DE_MEDIA_BNC) {
de_link_down(de);
mod_timer(&de->media_timer, jiffies + DE_TIMER_NO_LINK);
}
@@ -1229,6 +1250,7 @@
if (de->de21040)
return;
+ dw32(CSR13, 0); /* Reset phy */
pci_read_config_dword(de->pdev, PCIPM, &pmctl);
pmctl |= PM_Sleep;
pci_write_config_dword(de->pdev, PCIPM, pmctl);
@@ -1574,12 +1596,15 @@
return 0; /* nothing to change */
de_link_down(de);
+ mod_timer(&de->media_timer, jiffies + DE_TIMER_NO_LINK);
de_stop_rxtx(de);
de->media_type = new_media;
de->media_lock = media_lock;
de->media_advertise = ecmd->advertising;
de_set_media(de);
+ if (netif_running(de->dev))
+ de_start_rxtx(de);
return 0;
}
@@ -1911,8 +1936,14 @@
for (i = 0; i < DE_MAX_MEDIA; i++) {
if (de->media[i].csr13 == 0xffff)
de->media[i].csr13 = t21041_csr13[i];
- if (de->media[i].csr14 == 0xffff)
- de->media[i].csr14 = t21041_csr14[i];
+ if (de->media[i].csr14 == 0xffff) {
+ /* autonegotiation is broken at least on some chip
+ revisions - rev. 0x21 works, 0x11 does not */
+ if (de->pdev->revision < 0x20)
+ de->media[i].csr14 = t21041_csr14_brk[i];
+ else
+ de->media[i].csr14 = t21041_csr14[i];
+ }
if (de->media[i].csr15 == 0xffff)
de->media[i].csr15 = t21041_csr15[i];
}
@@ -2158,6 +2189,8 @@
dev_err(&dev->dev, "pci_enable_device failed in resume\n");
goto out;
}
+ pci_set_master(pdev);
+ de_init_rings(de);
de_init_hw(de);
out_attach:
netif_device_attach(dev);
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 6efca66..1cd752f 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -1652,6 +1652,8 @@
struct uart_icount cnow;
struct hso_tiocmget *tiocmget = serial->tiocmget;
+ memset(&icount, 0, sizeof(struct serial_icounter_struct));
+
if (!tiocmget)
return -ENOENT;
spin_lock_irq(&serial->serial_lock);
diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c
index 8cc9e31..1737d14 100644
--- a/drivers/net/wimax/i2400m/rx.c
+++ b/drivers/net/wimax/i2400m/rx.c
@@ -1244,16 +1244,16 @@
int i, result;
struct device *dev = i2400m_dev(i2400m);
const struct i2400m_msg_hdr *msg_hdr;
- size_t pl_itr, pl_size, skb_len;
+ size_t pl_itr, pl_size;
unsigned long flags;
- unsigned num_pls, single_last;
+ unsigned num_pls, single_last, skb_len;
skb_len = skb->len;
- d_fnstart(4, dev, "(i2400m %p skb %p [size %zu])\n",
+ d_fnstart(4, dev, "(i2400m %p skb %p [size %u])\n",
i2400m, skb, skb_len);
result = -EIO;
msg_hdr = (void *) skb->data;
- result = i2400m_rx_msg_hdr_check(i2400m, msg_hdr, skb->len);
+ result = i2400m_rx_msg_hdr_check(i2400m, msg_hdr, skb_len);
if (result < 0)
goto error_msg_hdr_check;
result = -EIO;
@@ -1261,10 +1261,10 @@
pl_itr = sizeof(*msg_hdr) + /* Check payload descriptor(s) */
num_pls * sizeof(msg_hdr->pld[0]);
pl_itr = ALIGN(pl_itr, I2400M_PL_ALIGN);
- if (pl_itr > skb->len) { /* got all the payload descriptors? */
+ if (pl_itr > skb_len) { /* got all the payload descriptors? */
dev_err(dev, "RX: HW BUG? message too short (%u bytes) for "
"%u payload descriptors (%zu each, total %zu)\n",
- skb->len, num_pls, sizeof(msg_hdr->pld[0]), pl_itr);
+ skb_len, num_pls, sizeof(msg_hdr->pld[0]), pl_itr);
goto error_pl_descr_short;
}
/* Walk each payload payload--check we really got it */
@@ -1272,7 +1272,7 @@
/* work around old gcc warnings */
pl_size = i2400m_pld_size(&msg_hdr->pld[i]);
result = i2400m_rx_pl_descr_check(i2400m, &msg_hdr->pld[i],
- pl_itr, skb->len);
+ pl_itr, skb_len);
if (result < 0)
goto error_pl_descr_check;
single_last = num_pls == 1 || i == num_pls - 1;
@@ -1290,16 +1290,16 @@
if (i < i2400m->rx_pl_min)
i2400m->rx_pl_min = i;
i2400m->rx_num++;
- i2400m->rx_size_acc += skb->len;
- if (skb->len < i2400m->rx_size_min)
- i2400m->rx_size_min = skb->len;
- if (skb->len > i2400m->rx_size_max)
- i2400m->rx_size_max = skb->len;
+ i2400m->rx_size_acc += skb_len;
+ if (skb_len < i2400m->rx_size_min)
+ i2400m->rx_size_min = skb_len;
+ if (skb_len > i2400m->rx_size_max)
+ i2400m->rx_size_max = skb_len;
spin_unlock_irqrestore(&i2400m->rx_lock, flags);
error_pl_descr_check:
error_pl_descr_short:
error_msg_hdr_check:
- d_fnend(4, dev, "(i2400m %p skb %p [size %zu]) = %d\n",
+ d_fnend(4, dev, "(i2400m %p skb %p [size %u]) = %d\n",
i2400m, skb, skb_len, result);
return result;
}
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index cc648b6..a3d95cc 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -543,7 +543,7 @@
if (conf_is_ht40(conf))
return clockrate * 2;
- return clockrate * 2;
+ return clockrate;
}
static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index 9dd9e64..8fd00a6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -1411,7 +1411,7 @@
clear_bit(STATUS_SCAN_HW, &priv->status);
clear_bit(STATUS_SCANNING, &priv->status);
/* inform mac80211 scan aborted */
- queue_work(priv->workqueue, &priv->scan_completed);
+ queue_work(priv->workqueue, &priv->abort_scan);
}
int iwlagn_manage_ibss_station(struct iwl_priv *priv,
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 07dbc27..e23c406 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -2613,6 +2613,11 @@
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return -EINVAL;
+ if (test_bit(STATUS_SCANNING, &priv->status)) {
+ IWL_DEBUG_INFO(priv, "scan in progress.\n");
+ return -EINVAL;
+ }
+
if (mode >= IWL_MAX_FORCE_RESET) {
IWL_DEBUG_INFO(priv, "invalid reset request.\n");
return -EINVAL;
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 59a308b..d31661c 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -3018,7 +3018,7 @@
clear_bit(STATUS_SCANNING, &priv->status);
/* inform mac80211 scan aborted */
- queue_work(priv->workqueue, &priv->scan_completed);
+ queue_work(priv->workqueue, &priv->abort_scan);
}
static void iwl3945_bg_restart(struct work_struct *data)
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index c3ceebb..4789f8e 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -71,6 +71,49 @@
#define DMA_32BIT_PFN IOVA_PFN(DMA_BIT_MASK(32))
#define DMA_64BIT_PFN IOVA_PFN(DMA_BIT_MASK(64))
+/* page table handling */
+#define LEVEL_STRIDE (9)
+#define LEVEL_MASK (((u64)1 << LEVEL_STRIDE) - 1)
+
+static inline int agaw_to_level(int agaw)
+{
+ return agaw + 2;
+}
+
+static inline int agaw_to_width(int agaw)
+{
+ return 30 + agaw * LEVEL_STRIDE;
+}
+
+static inline int width_to_agaw(int width)
+{
+ return (width - 30) / LEVEL_STRIDE;
+}
+
+static inline unsigned int level_to_offset_bits(int level)
+{
+ return (level - 1) * LEVEL_STRIDE;
+}
+
+static inline int pfn_level_offset(unsigned long pfn, int level)
+{
+ return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
+}
+
+static inline unsigned long level_mask(int level)
+{
+ return -1UL << level_to_offset_bits(level);
+}
+
+static inline unsigned long level_size(int level)
+{
+ return 1UL << level_to_offset_bits(level);
+}
+
+static inline unsigned long align_to_level(unsigned long pfn, int level)
+{
+ return (pfn + level_size(level) - 1) & level_mask(level);
+}
/* VT-d pages must always be _smaller_ than MM pages. Otherwise things
are never going to work. */
@@ -434,8 +477,6 @@
}
-static inline int width_to_agaw(int width);
-
static int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw)
{
unsigned long sagaw;
@@ -646,51 +687,6 @@
spin_unlock_irqrestore(&iommu->lock, flags);
}
-/* page table handling */
-#define LEVEL_STRIDE (9)
-#define LEVEL_MASK (((u64)1 << LEVEL_STRIDE) - 1)
-
-static inline int agaw_to_level(int agaw)
-{
- return agaw + 2;
-}
-
-static inline int agaw_to_width(int agaw)
-{
- return 30 + agaw * LEVEL_STRIDE;
-
-}
-
-static inline int width_to_agaw(int width)
-{
- return (width - 30) / LEVEL_STRIDE;
-}
-
-static inline unsigned int level_to_offset_bits(int level)
-{
- return (level - 1) * LEVEL_STRIDE;
-}
-
-static inline int pfn_level_offset(unsigned long pfn, int level)
-{
- return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
-}
-
-static inline unsigned long level_mask(int level)
-{
- return -1UL << level_to_offset_bits(level);
-}
-
-static inline unsigned long level_size(int level)
-{
- return 1UL << level_to_offset_bits(level);
-}
-
-static inline unsigned long align_to_level(unsigned long pfn, int level)
-{
- return (pfn + level_size(level) - 1) & level_mask(level);
-}
-
static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
unsigned long pfn)
{
@@ -3761,6 +3757,33 @@
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);
+#define GGC 0x52
+#define GGC_MEMORY_SIZE_MASK (0xf << 8)
+#define GGC_MEMORY_SIZE_NONE (0x0 << 8)
+#define GGC_MEMORY_SIZE_1M (0x1 << 8)
+#define GGC_MEMORY_SIZE_2M (0x3 << 8)
+#define GGC_MEMORY_VT_ENABLED (0x8 << 8)
+#define GGC_MEMORY_SIZE_2M_VT (0x9 << 8)
+#define GGC_MEMORY_SIZE_3M_VT (0xa << 8)
+#define GGC_MEMORY_SIZE_4M_VT (0xb << 8)
+
+static void __devinit quirk_calpella_no_shadow_gtt(struct pci_dev *dev)
+{
+ unsigned short ggc;
+
+ if (pci_read_config_word(dev, GGC, &ggc))
+ return;
+
+ if (!(ggc & GGC_MEMORY_VT_ENABLED)) {
+ printk(KERN_INFO "DMAR: BIOS has allocated no shadow GTT; disabling IOMMU for graphics\n");
+ dmar_map_gfx = 0;
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0040, quirk_calpella_no_shadow_gtt);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_calpella_no_shadow_gtt);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0062, quirk_calpella_no_shadow_gtt);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x006a, quirk_calpella_no_shadow_gtt);
+
/* On Tylersburg chipsets, some BIOSes have been known to enable the
ISOCH DMAR unit for the Azalia sound device, but not give it any
TLB entries, which causes it to deadlock. Check for that. We do
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index ce6a366..553d8ee 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -608,7 +608,7 @@
* the VF BAR size multiplied by the number of VFs. The alignment
* is just the VF BAR size.
*/
-int pci_sriov_resource_alignment(struct pci_dev *dev, int resno)
+resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno)
{
struct resource tmp;
enum pci_bar_type type;
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 7754a67..6beb11b 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -264,7 +264,8 @@
extern void pci_iov_release(struct pci_dev *dev);
extern int pci_iov_resource_bar(struct pci_dev *dev, int resno,
enum pci_bar_type *type);
-extern int pci_sriov_resource_alignment(struct pci_dev *dev, int resno);
+extern resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev,
+ int resno);
extern void pci_restore_iov_state(struct pci_dev *dev);
extern int pci_iov_bus_range(struct pci_bus *bus);
@@ -320,7 +321,7 @@
}
#endif /* CONFIG_PCI_IOV */
-static inline int pci_resource_alignment(struct pci_dev *dev,
+static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
struct resource *res)
{
#ifdef CONFIG_PCI_IOV
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 89ed181..857ae01 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -163,6 +163,26 @@
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_3, quirk_isa_dma_hangs);
/*
+ * Intel NM10 "TigerPoint" LPC PM1a_STS.BM_STS must be clear
+ * for some HT machines to use C4 w/o hanging.
+ */
+static void __devinit quirk_tigerpoint_bm_sts(struct pci_dev *dev)
+{
+ u32 pmbase;
+ u16 pm1a;
+
+ pci_read_config_dword(dev, 0x40, &pmbase);
+ pmbase = pmbase & 0xff80;
+ pm1a = inw(pmbase);
+
+ if (pm1a & 0x10) {
+ dev_info(&dev->dev, FW_BUG "TigerPoint LPC.BM_STS cleared\n");
+ outw(0x10, pmbase);
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TGP_LPC, quirk_tigerpoint_bm_sts);
+
+/*
* Chipsets where PCI->PCI transfers vanish or hang
*/
static void __devinit quirk_nopcipci(struct pci_dev *dev)
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index 54aa1c2..9ba4dad 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -163,7 +163,7 @@
c = p_dev->function_config;
if (!(c->state & CONFIG_LOCKED)) {
- dev_dbg(&s->dev, "Configuration isnt't locked\n");
+ dev_dbg(&p_dev->dev, "Configuration isnt't locked\n");
mutex_unlock(&s->ops_mutex);
return -EACCES;
}
@@ -220,7 +220,7 @@
s->win[w].card_start = offset;
ret = s->ops->set_mem_map(s, &s->win[w]);
if (ret)
- dev_warn(&s->dev, "failed to set_mem_map\n");
+ dev_warn(&p_dev->dev, "failed to set_mem_map\n");
mutex_unlock(&s->ops_mutex);
return ret;
} /* pcmcia_map_mem_page */
@@ -244,18 +244,18 @@
c = p_dev->function_config;
if (!(s->state & SOCKET_PRESENT)) {
- dev_dbg(&s->dev, "No card present\n");
+ dev_dbg(&p_dev->dev, "No card present\n");
ret = -ENODEV;
goto unlock;
}
if (!(c->state & CONFIG_LOCKED)) {
- dev_dbg(&s->dev, "Configuration isnt't locked\n");
+ dev_dbg(&p_dev->dev, "Configuration isnt't locked\n");
ret = -EACCES;
goto unlock;
}
if (mod->Attributes & (CONF_IRQ_CHANGE_VALID | CONF_VCC_CHANGE_VALID)) {
- dev_dbg(&s->dev,
+ dev_dbg(&p_dev->dev,
"changing Vcc or IRQ is not allowed at this time\n");
ret = -EINVAL;
goto unlock;
@@ -265,20 +265,22 @@
if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) &&
(mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
if (mod->Vpp1 != mod->Vpp2) {
- dev_dbg(&s->dev, "Vpp1 and Vpp2 must be the same\n");
+ dev_dbg(&p_dev->dev,
+ "Vpp1 and Vpp2 must be the same\n");
ret = -EINVAL;
goto unlock;
}
s->socket.Vpp = mod->Vpp1;
if (s->ops->set_socket(s, &s->socket)) {
- dev_printk(KERN_WARNING, &s->dev,
+ dev_printk(KERN_WARNING, &p_dev->dev,
"Unable to set VPP\n");
ret = -EIO;
goto unlock;
}
} else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) ||
(mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
- dev_dbg(&s->dev, "changing Vcc is not allowed at this time\n");
+ dev_dbg(&p_dev->dev,
+ "changing Vcc is not allowed at this time\n");
ret = -EINVAL;
goto unlock;
}
@@ -401,7 +403,7 @@
win = &s->win[w];
if (!(p_dev->_win & CLIENT_WIN_REQ(w))) {
- dev_dbg(&s->dev, "not releasing unknown window\n");
+ dev_dbg(&p_dev->dev, "not releasing unknown window\n");
mutex_unlock(&s->ops_mutex);
return -EINVAL;
}
@@ -439,7 +441,7 @@
return -ENODEV;
if (req->IntType & INT_CARDBUS) {
- dev_dbg(&s->dev, "IntType may not be INT_CARDBUS\n");
+ dev_dbg(&p_dev->dev, "IntType may not be INT_CARDBUS\n");
return -EINVAL;
}
@@ -447,7 +449,7 @@
c = p_dev->function_config;
if (c->state & CONFIG_LOCKED) {
mutex_unlock(&s->ops_mutex);
- dev_dbg(&s->dev, "Configuration is locked\n");
+ dev_dbg(&p_dev->dev, "Configuration is locked\n");
return -EACCES;
}
@@ -455,7 +457,7 @@
s->socket.Vpp = req->Vpp;
if (s->ops->set_socket(s, &s->socket)) {
mutex_unlock(&s->ops_mutex);
- dev_printk(KERN_WARNING, &s->dev,
+ dev_printk(KERN_WARNING, &p_dev->dev,
"Unable to set socket state\n");
return -EINVAL;
}
@@ -569,19 +571,20 @@
int ret = -EINVAL;
mutex_lock(&s->ops_mutex);
- dev_dbg(&s->dev, "pcmcia_request_io: %pR , %pR", &c->io[0], &c->io[1]);
+ dev_dbg(&p_dev->dev, "pcmcia_request_io: %pR , %pR",
+ &c->io[0], &c->io[1]);
if (!(s->state & SOCKET_PRESENT)) {
- dev_dbg(&s->dev, "pcmcia_request_io: No card present\n");
+ dev_dbg(&p_dev->dev, "pcmcia_request_io: No card present\n");
goto out;
}
if (c->state & CONFIG_LOCKED) {
- dev_dbg(&s->dev, "Configuration is locked\n");
+ dev_dbg(&p_dev->dev, "Configuration is locked\n");
goto out;
}
if (c->state & CONFIG_IO_REQ) {
- dev_dbg(&s->dev, "IO already configured\n");
+ dev_dbg(&p_dev->dev, "IO already configured\n");
goto out;
}
@@ -592,7 +595,13 @@
if (c->io[1].end) {
ret = alloc_io_space(s, &c->io[1], p_dev->io_lines);
if (ret) {
+ struct resource tmp = c->io[0];
+ /* release the previously allocated resource */
release_io_space(s, &c->io[0]);
+ /* but preserve the settings, for they worked... */
+ c->io[0].end = resource_size(&tmp);
+ c->io[0].start = tmp.start;
+ c->io[0].flags = tmp.flags;
goto out;
}
} else
@@ -601,7 +610,7 @@
c->state |= CONFIG_IO_REQ;
p_dev->_io = 1;
- dev_dbg(&s->dev, "pcmcia_request_io succeeded: %pR , %pR",
+ dev_dbg(&p_dev->dev, "pcmcia_request_io succeeded: %pR , %pR",
&c->io[0], &c->io[1]);
out:
mutex_unlock(&s->ops_mutex);
@@ -800,7 +809,7 @@
int w;
if (!(s->state & SOCKET_PRESENT)) {
- dev_dbg(&s->dev, "No card present\n");
+ dev_dbg(&p_dev->dev, "No card present\n");
return -ENODEV;
}
@@ -809,12 +818,12 @@
req->Size = s->map_size;
align = (s->features & SS_CAP_MEM_ALIGN) ? req->Size : s->map_size;
if (req->Size & (s->map_size-1)) {
- dev_dbg(&s->dev, "invalid map size\n");
+ dev_dbg(&p_dev->dev, "invalid map size\n");
return -EINVAL;
}
if ((req->Base && (s->features & SS_CAP_STATIC_MAP)) ||
(req->Base & (align-1))) {
- dev_dbg(&s->dev, "invalid base address\n");
+ dev_dbg(&p_dev->dev, "invalid base address\n");
return -EINVAL;
}
if (req->Base)
@@ -826,7 +835,7 @@
if (!(s->state & SOCKET_WIN_REQ(w)))
break;
if (w == MAX_WIN) {
- dev_dbg(&s->dev, "all windows are used already\n");
+ dev_dbg(&p_dev->dev, "all windows are used already\n");
mutex_unlock(&s->ops_mutex);
return -EINVAL;
}
@@ -837,7 +846,7 @@
win->res = pcmcia_find_mem_region(req->Base, req->Size, align,
0, s);
if (!win->res) {
- dev_dbg(&s->dev, "allocating mem region failed\n");
+ dev_dbg(&p_dev->dev, "allocating mem region failed\n");
mutex_unlock(&s->ops_mutex);
return -EINVAL;
}
@@ -851,7 +860,7 @@
win->card_start = 0;
if (s->ops->set_mem_map(s, win) != 0) {
- dev_dbg(&s->dev, "failed to set memory mapping\n");
+ dev_dbg(&p_dev->dev, "failed to set memory mapping\n");
mutex_unlock(&s->ops_mutex);
return -EIO;
}
@@ -874,7 +883,7 @@
if (win->res)
request_resource(&iomem_resource, res);
- dev_dbg(&s->dev, "request_window results in %pR\n", res);
+ dev_dbg(&p_dev->dev, "request_window results in %pR\n", res);
mutex_unlock(&s->ops_mutex);
*wh = res;
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
index b8a869a..deef665 100644
--- a/drivers/pcmcia/pd6729.c
+++ b/drivers/pcmcia/pd6729.c
@@ -646,7 +646,7 @@
if (!pci_resource_start(dev, 0)) {
dev_warn(&dev->dev, "refusing to load the driver as the "
"io_base is NULL.\n");
- goto err_out_free_mem;
+ goto err_out_disable;
}
dev_info(&dev->dev, "Cirrus PD6729 PCI to PCMCIA Bridge at 0x%llx "
diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c
index 9024480..c44a5e8 100644
--- a/drivers/platform/x86/intel_ips.c
+++ b/drivers/platform/x86/intel_ips.c
@@ -51,7 +51,6 @@
* TODO:
* - handle CPU hotplug
* - provide turbo enable/disable api
- * - make sure we can write turbo enable/disable reg based on MISC_EN
*
* Related documents:
* - CDI 403777, 403778 - Auburndale EDS vol 1 & 2
@@ -230,7 +229,7 @@
#define THM_TC2 0xac
#define THM_DTV 0xb0
#define THM_ITV 0xd8
-#define ITV_ME_SEQNO_MASK 0x000f0000 /* ME should update every ~200ms */
+#define ITV_ME_SEQNO_MASK 0x00ff0000 /* ME should update every ~200ms */
#define ITV_ME_SEQNO_SHIFT (16)
#define ITV_MCH_TEMP_MASK 0x0000ff00
#define ITV_MCH_TEMP_SHIFT (8)
@@ -325,6 +324,7 @@
bool gpu_preferred;
bool poll_turbo_status;
bool second_cpu;
+ bool turbo_toggle_allowed;
struct ips_mcp_limits *limits;
/* Optional MCH interfaces for if i915 is in use */
@@ -415,7 +415,7 @@
new_limit = cur_limit - 8; /* 1W decrease */
/* Clamp to SKU TDP limit */
- if (((new_limit * 10) / 8) < (ips->orig_turbo_limit & TURBO_TDP_MASK))
+ if (new_limit < (ips->orig_turbo_limit & TURBO_TDP_MASK))
new_limit = ips->orig_turbo_limit & TURBO_TDP_MASK;
thm_writew(THM_MPCPC, (new_limit * 10) / 8);
@@ -461,7 +461,8 @@
if (ips->__cpu_turbo_on)
return;
- on_each_cpu(do_enable_cpu_turbo, ips, 1);
+ if (ips->turbo_toggle_allowed)
+ on_each_cpu(do_enable_cpu_turbo, ips, 1);
ips->__cpu_turbo_on = true;
}
@@ -498,7 +499,8 @@
if (!ips->__cpu_turbo_on)
return;
- on_each_cpu(do_disable_cpu_turbo, ips, 1);
+ if (ips->turbo_toggle_allowed)
+ on_each_cpu(do_disable_cpu_turbo, ips, 1);
ips->__cpu_turbo_on = false;
}
@@ -598,17 +600,29 @@
{
unsigned long flags;
bool ret = false;
+ u32 temp_limit;
+ u32 avg_power;
+ const char *msg = "MCP limit exceeded: ";
spin_lock_irqsave(&ips->turbo_status_lock, flags);
- if (ips->mcp_avg_temp > (ips->mcp_temp_limit * 100))
- ret = true;
- if (ips->cpu_avg_power + ips->mch_avg_power > ips->mcp_power_limit)
- ret = true;
- spin_unlock_irqrestore(&ips->turbo_status_lock, flags);
- if (ret)
+ temp_limit = ips->mcp_temp_limit * 100;
+ if (ips->mcp_avg_temp > temp_limit) {
dev_info(&ips->dev->dev,
- "MCP power or thermal limit exceeded\n");
+ "%sAvg temp %u, limit %u\n", msg, ips->mcp_avg_temp,
+ temp_limit);
+ ret = true;
+ }
+
+ avg_power = ips->cpu_avg_power + ips->mch_avg_power;
+ if (avg_power > ips->mcp_power_limit) {
+ dev_info(&ips->dev->dev,
+ "%sAvg power %u, limit %u\n", msg, avg_power,
+ ips->mcp_power_limit);
+ ret = true;
+ }
+
+ spin_unlock_irqrestore(&ips->turbo_status_lock, flags);
return ret;
}
@@ -663,6 +677,27 @@
}
/**
+ * verify_limits - verify BIOS provided limits
+ * @ips: IPS structure
+ *
+ * BIOS can optionally provide non-default limits for power and temp. Check
+ * them here and use the defaults if the BIOS values are not provided or
+ * are otherwise unusable.
+ */
+static void verify_limits(struct ips_driver *ips)
+{
+ if (ips->mcp_power_limit < ips->limits->mcp_power_limit ||
+ ips->mcp_power_limit > 35000)
+ ips->mcp_power_limit = ips->limits->mcp_power_limit;
+
+ if (ips->mcp_temp_limit < ips->limits->core_temp_limit ||
+ ips->mcp_temp_limit < ips->limits->mch_temp_limit ||
+ ips->mcp_temp_limit > 150)
+ ips->mcp_temp_limit = min(ips->limits->core_temp_limit,
+ ips->limits->mch_temp_limit);
+}
+
+/**
* update_turbo_limits - get various limits & settings from regs
* @ips: IPS driver struct
*
@@ -680,12 +715,21 @@
u32 hts = thm_readl(THM_HTS);
ips->cpu_turbo_enabled = !(hts & HTS_PCTD_DIS);
- ips->gpu_turbo_enabled = !(hts & HTS_GTD_DIS);
+ /*
+ * Disable turbo for now, until we can figure out why the power figures
+ * are wrong
+ */
+ ips->cpu_turbo_enabled = false;
+
+ if (ips->gpu_busy)
+ ips->gpu_turbo_enabled = !(hts & HTS_GTD_DIS);
+
ips->core_power_limit = thm_readw(THM_MPCPC);
ips->mch_power_limit = thm_readw(THM_MMGPC);
ips->mcp_temp_limit = thm_readw(THM_PTL);
ips->mcp_power_limit = thm_readw(THM_MPPC);
+ verify_limits(ips);
/* Ignore BIOS CPU vs GPU pref */
}
@@ -858,7 +902,7 @@
ret = (ret * 1000) / 65535;
*last = val;
- return ret;
+ return 0;
}
static const u16 temp_decay_factor = 2;
@@ -940,7 +984,6 @@
kfree(mch_samples);
kfree(cpu_samples);
kfree(mchp_samples);
- kthread_stop(ips->adjust);
return -ENOMEM;
}
@@ -948,7 +991,7 @@
ITV_ME_SEQNO_SHIFT;
seqno_timestamp = get_jiffies_64();
- old_cpu_power = thm_readl(THM_CEC) / 65535;
+ old_cpu_power = thm_readl(THM_CEC);
schedule_timeout_interruptible(msecs_to_jiffies(IPS_SAMPLE_PERIOD));
/* Collect an initial average */
@@ -1150,11 +1193,18 @@
STS_GPL_SHIFT;
/* ignore EC CPU vs GPU pref */
ips->cpu_turbo_enabled = !(sts & STS_PCTD_DIS);
- ips->gpu_turbo_enabled = !(sts & STS_GTD_DIS);
+ /*
+ * Disable turbo for now, until we can figure
+ * out why the power figures are wrong
+ */
+ ips->cpu_turbo_enabled = false;
+ if (ips->gpu_busy)
+ ips->gpu_turbo_enabled = !(sts & STS_GTD_DIS);
ips->mcp_temp_limit = (sts & STS_PTL_MASK) >>
STS_PTL_SHIFT;
ips->mcp_power_limit = (tc1 & STS_PPL_MASK) >>
STS_PPL_SHIFT;
+ verify_limits(ips);
spin_unlock(&ips->turbo_status_lock);
thm_writeb(THM_SEC, SEC_ACK);
@@ -1333,8 +1383,10 @@
* turbo manually or we'll get an illegal MSR access, even though
* turbo will still be available.
*/
- if (!(misc_en & IA32_MISC_TURBO_EN))
- ; /* add turbo MSR write allowed flag if necessary */
+ if (misc_en & IA32_MISC_TURBO_EN)
+ ips->turbo_toggle_allowed = true;
+ else
+ ips->turbo_toggle_allowed = false;
if (strstr(boot_cpu_data.x86_model_id, "CPU M"))
limits = &ips_sv_limits;
@@ -1351,9 +1403,10 @@
tdp = turbo_power & TURBO_TDP_MASK;
/* Sanity check TDP against CPU */
- if (limits->mcp_power_limit != (tdp / 8) * 1000) {
- dev_warn(&ips->dev->dev, "Warning: CPU TDP doesn't match expected value (found %d, expected %d)\n",
- tdp / 8, limits->mcp_power_limit / 1000);
+ if (limits->core_power_limit != (tdp / 8) * 1000) {
+ dev_info(&ips->dev->dev, "CPU TDP doesn't match expected value (found %d, expected %d)\n",
+ tdp / 8, limits->core_power_limit / 1000);
+ limits->core_power_limit = (tdp / 8) * 1000;
}
out:
@@ -1390,7 +1443,7 @@
return true;
out_put_busy:
- symbol_put(i915_gpu_turbo_disable);
+ symbol_put(i915_gpu_busy);
out_put_lower:
symbol_put(i915_gpu_lower);
out_put_raise:
@@ -1532,23 +1585,28 @@
/* Save turbo limits & ratios */
rdmsrl(TURBO_POWER_CURRENT_LIMIT, ips->orig_turbo_limit);
- ips_enable_cpu_turbo(ips);
- ips->cpu_turbo_enabled = true;
+ ips_disable_cpu_turbo(ips);
+ ips->cpu_turbo_enabled = false;
- /* Set up the work queue and monitor/adjust threads */
- ips->monitor = kthread_run(ips_monitor, ips, "ips-monitor");
- if (IS_ERR(ips->monitor)) {
- dev_err(&dev->dev,
- "failed to create thermal monitor thread, aborting\n");
- ret = -ENOMEM;
- goto error_free_irq;
- }
-
+ /* Create thermal adjust thread */
ips->adjust = kthread_create(ips_adjust, ips, "ips-adjust");
if (IS_ERR(ips->adjust)) {
dev_err(&dev->dev,
"failed to create thermal adjust thread, aborting\n");
ret = -ENOMEM;
+ goto error_free_irq;
+
+ }
+
+ /*
+ * Set up the work queue and monitor thread. The monitor thread
+ * will wake up ips_adjust thread.
+ */
+ ips->monitor = kthread_run(ips_monitor, ips, "ips-monitor");
+ if (IS_ERR(ips->monitor)) {
+ dev_err(&dev->dev,
+ "failed to create thermal monitor thread, aborting\n");
+ ret = -ENOMEM;
goto error_thread_cleanup;
}
@@ -1566,7 +1624,7 @@
return ret;
error_thread_cleanup:
- kthread_stop(ips->monitor);
+ kthread_stop(ips->adjust);
error_free_irq:
free_irq(ips->dev->irq, ips);
error_unmap:
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index e35ed12..2d61186 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -3093,7 +3093,8 @@
TPACPI_Q_IBM('1', 'D', TPACPI_HK_Q_INIMASK), /* X22, X23, X24 */
};
-typedef u16 tpacpi_keymap_t[TPACPI_HOTKEY_MAP_LEN];
+typedef u16 tpacpi_keymap_entry_t;
+typedef tpacpi_keymap_entry_t tpacpi_keymap_t[TPACPI_HOTKEY_MAP_LEN];
static int __init hotkey_init(struct ibm_init_struct *iibm)
{
@@ -3230,7 +3231,7 @@
};
#define TPACPI_HOTKEY_MAP_SIZE sizeof(tpacpi_keymap_t)
-#define TPACPI_HOTKEY_MAP_TYPESIZE sizeof(tpacpi_keymap_t[0])
+#define TPACPI_HOTKEY_MAP_TYPESIZE sizeof(tpacpi_keymap_entry_t)
int res, i;
int status;
diff --git a/drivers/power/apm_power.c b/drivers/power/apm_power.c
index 936bae5..dc628cb 100644
--- a/drivers/power/apm_power.c
+++ b/drivers/power/apm_power.c
@@ -233,6 +233,7 @@
empty_design_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN;
now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
+ break;
case SOURCE_VOLTAGE:
full_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX;
empty_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN;
diff --git a/drivers/power/intel_mid_battery.c b/drivers/power/intel_mid_battery.c
index c61ffec..2a10cd3 100644
--- a/drivers/power/intel_mid_battery.c
+++ b/drivers/power/intel_mid_battery.c
@@ -185,8 +185,8 @@
{
u32 data[3];
u8 *p = (u8 *)&data[1];
- int err = intel_scu_ipc_command(IPC_CMD_BATTERY_PROPERTY,
- IPCMSG_BATTERY, NULL, 0, data, 3);
+ int err = intel_scu_ipc_command(IPCMSG_BATTERY,
+ IPC_CMD_BATTERY_PROPERTY, NULL, 0, data, 3);
prop->capacity = data[0];
prop->crnt = *p++;
@@ -207,7 +207,7 @@
static int pmic_scu_ipc_set_charger(int charger)
{
- return intel_scu_ipc_simple_command(charger, IPCMSG_BATTERY);
+ return intel_scu_ipc_simple_command(IPCMSG_BATTERY, charger);
}
/**
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c
index 7d149a8..2ce2eb7 100644
--- a/drivers/regulator/88pm8607.c
+++ b/drivers/regulator/88pm8607.c
@@ -215,7 +215,7 @@
struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
int ret = -EINVAL;
- if (info->vol_table && (index < (2 << info->vol_nbits))) {
+ if (info->vol_table && (index < (1 << info->vol_nbits))) {
ret = info->vol_table[index];
if (info->slope_double)
ret <<= 1;
@@ -233,7 +233,7 @@
max_uV = max_uV >> 1;
}
if (info->vol_table) {
- for (i = 0; i < (2 << info->vol_nbits); i++) {
+ for (i = 0; i < (1 << info->vol_nbits); i++) {
if (!info->vol_table[i])
break;
if ((min_uV <= info->vol_table[i])
diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c
index 1179099..b349266 100644
--- a/drivers/regulator/ab3100.c
+++ b/drivers/regulator/ab3100.c
@@ -634,12 +634,9 @@
"%s: failed to register regulator %s err %d\n",
__func__, ab3100_regulator_desc[i].name,
err);
- i--;
/* remove the already registered regulators */
- while (i > 0) {
+ while (--i >= 0)
regulator_unregister(ab3100_regulators[i].rdev);
- i--;
- }
return err;
}
diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c
index dc3f1a4..28c7ae6 100644
--- a/drivers/regulator/ab8500.c
+++ b/drivers/regulator/ab8500.c
@@ -157,7 +157,7 @@
if (info->fixed_uV)
return info->fixed_uV;
- if (selector > info->voltages_len)
+ if (selector >= info->voltages_len)
return -EINVAL;
return info->supported_voltages[selector];
@@ -344,13 +344,14 @@
static __devinit int ab8500_regulator_probe(struct platform_device *pdev)
{
struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
- struct ab8500_platform_data *pdata = dev_get_platdata(ab8500->dev);
+ struct ab8500_platform_data *pdata;
int i, err;
if (!ab8500) {
dev_err(&pdev->dev, "null mfd parent\n");
return -EINVAL;
}
+ pdata = dev_get_platdata(ab8500->dev);
/* register all regulators */
for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
@@ -368,11 +369,9 @@
dev_err(&pdev->dev, "failed to register regulator %s\n",
info->desc.name);
/* when we fail, un-register all earlier regulators */
- i--;
- while (i > 0) {
+ while (--i >= 0) {
info = &ab8500_regulator_info[i];
regulator_unregister(info->regulator);
- i--;
}
return err;
}
diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c
index d59d2f2..a4be416 100644
--- a/drivers/regulator/ad5398.c
+++ b/drivers/regulator/ad5398.c
@@ -25,7 +25,7 @@
unsigned int current_level;
unsigned int current_mask;
unsigned int current_offset;
- struct regulator_dev rdev;
+ struct regulator_dev *rdev;
};
static int ad5398_calc_current(struct ad5398_chip_info *chip,
@@ -211,7 +211,6 @@
static int __devinit ad5398_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct regulator_dev *rdev;
struct regulator_init_data *init_data = client->dev.platform_data;
struct ad5398_chip_info *chip;
const struct ad5398_current_data_format *df =
@@ -233,9 +232,10 @@
chip->current_offset = df->current_offset;
chip->current_mask = (chip->current_level - 1) << chip->current_offset;
- rdev = regulator_register(&ad5398_reg, &client->dev, init_data, chip);
- if (IS_ERR(rdev)) {
- ret = PTR_ERR(rdev);
+ chip->rdev = regulator_register(&ad5398_reg, &client->dev,
+ init_data, chip);
+ if (IS_ERR(chip->rdev)) {
+ ret = PTR_ERR(chip->rdev);
dev_err(&client->dev, "failed to register %s %s\n",
id->name, ad5398_reg.name);
goto err;
@@ -254,9 +254,8 @@
{
struct ad5398_chip_info *chip = i2c_get_clientdata(client);
- regulator_unregister(&chip->rdev);
+ regulator_unregister(chip->rdev);
kfree(chip);
- i2c_set_clientdata(client, NULL);
return 0;
}
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 422a709..cc8b337 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -700,7 +700,7 @@
constraints->min_uA != constraints->max_uA) {
ret = _regulator_get_current_limit(rdev);
if (ret > 0)
- count += sprintf(buf + count, "at %d uA ", ret / 1000);
+ count += sprintf(buf + count, "at %d mA ", ret / 1000);
}
if (constraints->valid_modes_mask & REGULATOR_MODE_FAST)
@@ -2302,8 +2302,10 @@
dev_set_name(&rdev->dev, "regulator.%d",
atomic_inc_return(®ulator_no) - 1);
ret = device_register(&rdev->dev);
- if (ret != 0)
+ if (ret != 0) {
+ put_device(&rdev->dev);
goto clean;
+ }
dev_set_drvdata(&rdev->dev, rdev);
diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c
index e49d2bd..b8cc638 100644
--- a/drivers/regulator/isl6271a-regulator.c
+++ b/drivers/regulator/isl6271a-regulator.c
@@ -165,7 +165,7 @@
mutex_init(&pmic->mtx);
for (i = 0; i < 3; i++) {
- pmic->rdev[i] = regulator_register(&isl_rd[0], &i2c->dev,
+ pmic->rdev[i] = regulator_register(&isl_rd[i], &i2c->dev,
init_data, pmic);
if (IS_ERR(pmic->rdev[i])) {
dev_err(&i2c->dev, "failed to register %s\n", id->name);
@@ -191,8 +191,6 @@
struct isl_pmic *pmic = i2c_get_clientdata(i2c);
int i;
- i2c_set_clientdata(i2c, NULL);
-
for (i = 0; i < 3; i++)
regulator_unregister(pmic->rdev[i]);
diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c
index 8867c27..559cfa2 100644
--- a/drivers/regulator/max1586.c
+++ b/drivers/regulator/max1586.c
@@ -121,14 +121,14 @@
if (max_uV < MAX1586_V6_MIN_UV || max_uV > MAX1586_V6_MAX_UV)
return -EINVAL;
- if (min_uV >= 3000000)
- selector = 3;
- if (min_uV < 3000000)
- selector = 2;
- if (min_uV < 2500000)
- selector = 1;
if (min_uV < 1800000)
selector = 0;
+ else if (min_uV < 2500000)
+ selector = 1;
+ else if (min_uV < 3000000)
+ selector = 2;
+ else if (min_uV >= 3000000)
+ selector = 3;
if (max1586_v6_calc_voltage(selector) > max_uV)
return -EINVAL;
diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c
index 4520ace..6b60a9c 100644
--- a/drivers/regulator/max8649.c
+++ b/drivers/regulator/max8649.c
@@ -330,7 +330,7 @@
/* set external clock frequency */
info->extclk_freq = pdata->extclk_freq;
max8649_set_bits(info->i2c, MAX8649_SYNC, MAX8649_EXT_MASK,
- info->extclk_freq);
+ info->extclk_freq << 6);
}
if (pdata->ramp_timing) {
diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c
index ab67298..a1baf1f 100644
--- a/drivers/regulator/max8998.c
+++ b/drivers/regulator/max8998.c
@@ -549,7 +549,7 @@
if (!max8998)
return -ENOMEM;
- size = sizeof(struct regulator_dev *) * (pdata->num_regulators + 1);
+ size = sizeof(struct regulator_dev *) * pdata->num_regulators;
max8998->rdev = kzalloc(size, GFP_KERNEL);
if (!max8998->rdev) {
kfree(max8998);
@@ -557,7 +557,9 @@
}
rdev = max8998->rdev;
+ max8998->dev = &pdev->dev;
max8998->iodev = iodev;
+ max8998->num_regulators = pdata->num_regulators;
platform_set_drvdata(pdev, max8998);
for (i = 0; i < pdata->num_regulators; i++) {
@@ -583,7 +585,7 @@
return 0;
err:
- for (i = 0; i <= max8998->num_regulators; i++)
+ for (i = 0; i < max8998->num_regulators; i++)
if (rdev[i])
regulator_unregister(rdev[i]);
@@ -599,7 +601,7 @@
struct regulator_dev **rdev = max8998->rdev;
int i;
- for (i = 0; i <= max8998->num_regulators; i++)
+ for (i = 0; i < max8998->num_regulators; i++)
if (rdev[i])
regulator_unregister(rdev[i]);
diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c
index c239f42..020f587 100644
--- a/drivers/regulator/tps6507x-regulator.c
+++ b/drivers/regulator/tps6507x-regulator.c
@@ -626,12 +626,6 @@
return error;
}
-/**
- * tps6507x_remove - TPS6507x driver i2c remove handler
- * @client: i2c driver client device structure
- *
- * Unregister TPS driver as an i2c client device driver
- */
static int __devexit tps6507x_pmic_remove(struct platform_device *pdev)
{
struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev);
diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c
index 8cff141..51237fb 100644
--- a/drivers/regulator/tps6586x-regulator.c
+++ b/drivers/regulator/tps6586x-regulator.c
@@ -133,7 +133,7 @@
mask = ((1 << ri->volt_nbits) - 1) << ri->volt_shift;
val = (val & mask) >> ri->volt_shift;
- if (val > ri->desc.n_voltages)
+ if (val >= ri->desc.n_voltages)
BUG();
return ri->voltages[val] * 1000;
@@ -150,7 +150,7 @@
if (ret)
return ret;
- return tps6586x_set_bits(parent, ri->go_reg, ri->go_bit);
+ return tps6586x_set_bits(parent, ri->go_reg, 1 << ri->go_bit);
}
static int tps6586x_regulator_enable(struct regulator_dev *rdev)
diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c
index e686cdb..9edf8f6 100644
--- a/drivers/regulator/wm831x-ldo.c
+++ b/drivers/regulator/wm831x-ldo.c
@@ -215,8 +215,7 @@
case REGULATOR_MODE_IDLE:
ret = wm831x_set_bits(wm831x, ctrl_reg,
- WM831X_LDO1_LP_MODE,
- WM831X_LDO1_LP_MODE);
+ WM831X_LDO1_LP_MODE, 0);
if (ret < 0)
return ret;
@@ -225,10 +224,12 @@
WM831X_LDO1_ON_MODE);
if (ret < 0)
return ret;
+ break;
case REGULATOR_MODE_STANDBY:
ret = wm831x_set_bits(wm831x, ctrl_reg,
- WM831X_LDO1_LP_MODE, 0);
+ WM831X_LDO1_LP_MODE,
+ WM831X_LDO1_LP_MODE);
if (ret < 0)
return ret;
diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c
index 0e6ed7d..fe4b8a8 100644
--- a/drivers/regulator/wm8350-regulator.c
+++ b/drivers/regulator/wm8350-regulator.c
@@ -1129,7 +1129,7 @@
mode = REGULATOR_MODE_NORMAL;
} else if (!active && !sleep)
mode = REGULATOR_MODE_IDLE;
- else if (!sleep)
+ else if (sleep)
mode = REGULATOR_MODE_STANDBY;
return mode;
diff --git a/drivers/rtc/rtc-ab3100.c b/drivers/rtc/rtc-ab3100.c
index d26780e..261a07e 100644
--- a/drivers/rtc/rtc-ab3100.c
+++ b/drivers/rtc/rtc-ab3100.c
@@ -235,6 +235,7 @@
err = PTR_ERR(rtc);
return err;
}
+ platform_set_drvdata(pdev, rtc);
return 0;
}
@@ -244,6 +245,7 @@
struct rtc_device *rtc = platform_get_drvdata(pdev);
rtc_device_unregister(rtc);
+ platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c
index 9daed8d..9de8516 100644
--- a/drivers/rtc/rtc-ds3232.c
+++ b/drivers/rtc/rtc-ds3232.c
@@ -268,7 +268,6 @@
free_irq(client->irq, client);
out_free:
- i2c_set_clientdata(client, NULL);
kfree(ds3232);
return ret;
}
@@ -287,7 +286,6 @@
}
rtc_device_unregister(ds3232->rtc);
- i2c_set_clientdata(client, NULL);
kfree(ds3232);
return 0;
}
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index a0d3ec8..f57a87f 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -310,11 +310,6 @@
s3c_rtc_setaie(alrm->enabled);
- if (alrm->enabled)
- enable_irq_wake(s3c_rtc_alarmno);
- else
- disable_irq_wake(s3c_rtc_alarmno);
-
return 0;
}
@@ -587,6 +582,10 @@
ticnt_en_save &= S3C64XX_RTCCON_TICEN;
}
s3c_rtc_enable(pdev, 0);
+
+ if (device_may_wakeup(&pdev->dev))
+ enable_irq_wake(s3c_rtc_alarmno);
+
return 0;
}
@@ -600,6 +599,10 @@
tmp = readb(s3c_rtc_base + S3C2410_RTCCON);
writeb(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON);
}
+
+ if (device_may_wakeup(&pdev->dev))
+ disable_irq_wake(s3c_rtc_alarmno);
+
return 0;
}
#else
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c
index 6edf20b..2c7d2d9 100644
--- a/drivers/s390/net/ctcm_main.c
+++ b/drivers/s390/net/ctcm_main.c
@@ -1154,7 +1154,7 @@
dev_fsm, dev_fsm_len, GFP_KERNEL);
if (priv->fsm == NULL) {
CTCMY_DBF_DEV(SETUP, dev, "init_fsm error");
- kfree(dev);
+ free_netdev(dev);
return NULL;
}
fsm_newstate(priv->fsm, DEV_STATE_STOPPED);
@@ -1165,7 +1165,7 @@
grp = ctcmpc_init_mpc_group(priv);
if (grp == NULL) {
MPC_DBF_DEV(SETUP, dev, "init_mpc_group error");
- kfree(dev);
+ free_netdev(dev);
return NULL;
}
tasklet_init(&grp->mpc_tasklet2,
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index ad0ed21..348fba0 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -1046,13 +1046,13 @@
/* If the user actually wanted this page, we can skip the rest */
if (page == 0)
- return -EINVAL;
+ return 0;
for (i = 0; i < min((int)buf[3], buf_len - 4); i++)
if (buf[i + 4] == page)
goto found;
- if (i < buf[3] && i > buf_len)
+ if (i < buf[3] && i >= buf_len - 4)
/* ran off the end of the buffer, give us benefit of doubt */
goto found;
/* The device claims it doesn't support the requested page */
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c
index 50441ff..2904aa0 100644
--- a/drivers/serial/amba-pl010.c
+++ b/drivers/serial/amba-pl010.c
@@ -472,14 +472,9 @@
spin_unlock_irqrestore(&uap->port.lock, flags);
}
-static void pl010_set_ldisc(struct uart_port *port)
+static void pl010_set_ldisc(struct uart_port *port, int new)
{
- int line = port->line;
-
- if (line >= port->state->port.tty->driver->num)
- return;
-
- if (port->state->port.tty->ldisc->ops->num == N_PPS) {
+ if (new == N_PPS) {
port->flags |= UPF_HARDPPS_CD;
pl010_enable_ms(port);
} else
diff --git a/drivers/serial/ioc3_serial.c b/drivers/serial/ioc3_serial.c
index 93de907..800c546 100644
--- a/drivers/serial/ioc3_serial.c
+++ b/drivers/serial/ioc3_serial.c
@@ -2044,6 +2044,7 @@
if (!port) {
printk(KERN_WARNING
"IOC3 serial memory not available for port\n");
+ ret = -ENOMEM;
goto out4;
}
spin_lock_init(&port->ip_lock);
diff --git a/drivers/serial/mfd.c b/drivers/serial/mfd.c
index bc9af50..5dff45c 100644
--- a/drivers/serial/mfd.c
+++ b/drivers/serial/mfd.c
@@ -27,6 +27,7 @@
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
+#include <linux/slab.h>
#include <linux/serial_reg.h>
#include <linux/circ_buf.h>
#include <linux/delay.h>
@@ -1423,7 +1424,6 @@
}
phsu = hsu;
-
hsu_debugfs_init(hsu);
return;
@@ -1435,18 +1435,20 @@
static void serial_hsu_remove(struct pci_dev *pdev)
{
- struct hsu_port *hsu;
- int i;
+ void *priv = pci_get_drvdata(pdev);
+ struct uart_hsu_port *up;
- hsu = pci_get_drvdata(pdev);
- if (!hsu)
+ if (!priv)
return;
- for (i = 0; i < 3; i++)
- uart_remove_one_port(&serial_hsu_reg, &hsu->port[i].port);
+ /* For port 0/1/2, priv is the address of uart_hsu_port */
+ if (pdev->device != 0x081E) {
+ up = priv;
+ uart_remove_one_port(&serial_hsu_reg, &up->port);
+ }
pci_set_drvdata(pdev, NULL);
- free_irq(hsu->irq, hsu);
+ free_irq(pdev->irq, priv);
pci_disable_device(pdev);
}
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 8dedb26..c4399e2 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -500,6 +500,7 @@
psc_fifoc = of_iomap(np, 0);
if (!psc_fifoc) {
pr_err("%s: Can't map FIFOC\n", __func__);
+ of_node_put(np);
return -ENODEV;
}
diff --git a/drivers/serial/mrst_max3110.c b/drivers/serial/mrst_max3110.c
index f6ad1ec..51c15f5 100644
--- a/drivers/serial/mrst_max3110.c
+++ b/drivers/serial/mrst_max3110.c
@@ -29,6 +29,7 @@
#include <linux/module.h>
#include <linux/ioport.h>
+#include <linux/irq.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index 141c695..7d475b2 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -335,8 +335,6 @@
info->p_dev = link;
link->priv = info;
- link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
- link->resource[0]->end = 8;
link->conf.Attributes = CONF_ENABLE_IRQ;
if (do_sound) {
link->conf.Attributes |= CONF_ENABLE_SPKR;
@@ -411,6 +409,27 @@
/*====================================================================*/
+static int pfc_config(struct pcmcia_device *p_dev)
+{
+ unsigned int port = 0;
+ struct serial_info *info = p_dev->priv;
+
+ if ((p_dev->resource[1]->end != 0) &&
+ (resource_size(p_dev->resource[1]) == 8)) {
+ port = p_dev->resource[1]->start;
+ info->slave = 1;
+ } else if ((info->manfid == MANFID_OSITECH) &&
+ (resource_size(p_dev->resource[0]) == 0x40)) {
+ port = p_dev->resource[0]->start + 0x28;
+ info->slave = 1;
+ }
+ if (info->slave)
+ return setup_serial(p_dev, info, port, p_dev->irq);
+
+ dev_warn(&p_dev->dev, "no usable port range found, giving up\n");
+ return -ENODEV;
+}
+
static int simple_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cf,
cistpl_cftable_entry_t *dflt,
@@ -461,23 +480,8 @@
struct serial_info *info = link->priv;
int i = -ENODEV, try;
- /* If the card is already configured, look up the port and irq */
- if (link->function_config) {
- unsigned int port = 0;
- if ((link->resource[1]->end != 0) &&
- (resource_size(link->resource[1]) == 8)) {
- port = link->resource[1]->end;
- info->slave = 1;
- } else if ((info->manfid == MANFID_OSITECH) &&
- (resource_size(link->resource[0]) == 0x40)) {
- port = link->resource[0]->start + 0x28;
- info->slave = 1;
- }
- if (info->slave) {
- return setup_serial(link, info, port,
- link->irq);
- }
- }
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+ link->resource[0]->end = 8;
/* First pass: look for a config entry that looks normal.
* Two tries: without IO aliases, then with aliases */
@@ -491,8 +495,7 @@
if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL))
goto found_port;
- printk(KERN_NOTICE
- "serial_cs: no usable port range found, giving up\n");
+ dev_warn(&link->dev, "no usable port range found, giving up\n");
return -1;
found_port:
@@ -558,6 +561,7 @@
int i, base2 = 0;
/* First, look for a generic full-sized window */
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
link->resource[0]->end = info->multi * 8;
if (pcmcia_loop_config(link, multi_config_check, &base2)) {
/* If that didn't work, look for two windows */
@@ -565,15 +569,14 @@
info->multi = 2;
if (pcmcia_loop_config(link, multi_config_check_notpicky,
&base2)) {
- printk(KERN_NOTICE "serial_cs: no usable port range"
+ dev_warn(&link->dev, "no usable port range "
"found, giving up\n");
return -ENODEV;
}
}
if (!link->irq)
- dev_warn(&link->dev,
- "serial_cs: no usable IRQ found, continuing...\n");
+ dev_warn(&link->dev, "no usable IRQ found, continuing...\n");
/*
* Apply any configuration quirks.
@@ -675,6 +678,7 @@
multifunction cards that ask for appropriate IO port ranges */
if ((info->multi == 0) &&
(link->has_func_id) &&
+ (link->socket->pcmcia_pfc == 0) &&
((link->func_id == CISTPL_FUNCID_MULTI) ||
(link->func_id == CISTPL_FUNCID_SERIAL)))
pcmcia_loop_config(link, serial_check_for_multi, info);
@@ -685,7 +689,13 @@
if (info->quirk && info->quirk->multi != -1)
info->multi = info->quirk->multi;
- if (info->multi > 1)
+ dev_info(&link->dev,
+ "trying to set up [0x%04x:0x%04x] (pfc: %d, multi: %d, quirk: %p)\n",
+ link->manf_id, link->card_id,
+ link->socket->pcmcia_pfc, info->multi, info->quirk);
+ if (link->socket->pcmcia_pfc)
+ i = pfc_config(link);
+ else if (info->multi > 1)
i = multi_config(link);
else
i = simple_config(link);
@@ -704,7 +714,7 @@
return 0;
failed:
- dev_warn(&link->dev, "serial_cs: failed to initialize\n");
+ dev_warn(&link->dev, "failed to initialize\n");
serial_remove(link);
return -ENODEV;
}
diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c
index acd35d1..4c37c4e2 100644
--- a/drivers/spi/amba-pl022.c
+++ b/drivers/spi/amba-pl022.c
@@ -503,8 +503,9 @@
msg->state = NULL;
if (msg->complete)
msg->complete(msg->context);
- /* This message is completed, so let's turn off the clock! */
+ /* This message is completed, so let's turn off the clocks! */
clk_disable(pl022->clk);
+ amba_pclk_disable(pl022->adev);
}
/**
@@ -1139,9 +1140,10 @@
/* Setup the SPI using the per chip configuration */
pl022->cur_chip = spi_get_ctldata(pl022->cur_msg->spi);
/*
- * We enable the clock here, then the clock will be disabled when
+ * We enable the clocks here, then the clocks will be disabled when
* giveback() is called in each method (poll/interrupt/DMA)
*/
+ amba_pclk_enable(pl022->adev);
clk_enable(pl022->clk);
restore_state(pl022);
flush(pl022);
@@ -1786,11 +1788,9 @@
}
/* Disable SSP */
- clk_enable(pl022->clk);
writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)),
SSP_CR1(pl022->virtbase));
load_ssp_default_config(pl022);
- clk_disable(pl022->clk);
status = request_irq(adev->irq[0], pl022_interrupt_handler, 0, "pl022",
pl022);
@@ -1818,6 +1818,8 @@
goto err_spi_register;
}
dev_dbg(dev, "probe succeded\n");
+ /* Disable the silicon block pclk and clock it when needed */
+ amba_pclk_disable(adev);
return 0;
err_spi_register:
@@ -1879,9 +1881,9 @@
return status;
}
- clk_enable(pl022->clk);
+ amba_pclk_enable(adev);
load_ssp_default_config(pl022);
- clk_disable(pl022->clk);
+ amba_pclk_disable(adev);
dev_dbg(&adev->dev, "suspended\n");
return 0;
}
@@ -1981,7 +1983,7 @@
return amba_driver_register(&pl022_driver);
}
-module_init(pl022_init);
+subsys_initcall(pl022_init);
static void __exit pl022_exit(void)
{
diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c
index d256cb0..5624785 100644
--- a/drivers/spi/dw_spi.c
+++ b/drivers/spi/dw_spi.c
@@ -181,10 +181,6 @@
wait_till_not_busy(dws);
}
-static void null_cs_control(u32 command)
-{
-}
-
static int null_writer(struct dw_spi *dws)
{
u8 n_bytes = dws->n_bytes;
@@ -322,7 +318,7 @@
struct spi_transfer,
transfer_list);
- if (!last_transfer->cs_change)
+ if (!last_transfer->cs_change && dws->cs_control)
dws->cs_control(MRST_SPI_DEASSERT);
msg->state = NULL;
@@ -396,6 +392,11 @@
static irqreturn_t dw_spi_irq(int irq, void *dev_id)
{
struct dw_spi *dws = dev_id;
+ u16 irq_status, irq_mask = 0x3f;
+
+ irq_status = dw_readw(dws, isr) & irq_mask;
+ if (!irq_status)
+ return IRQ_NONE;
if (!dws->cur_msg) {
spi_mask_intr(dws, SPI_INT_TXEI);
@@ -544,13 +545,13 @@
*/
if (dws->cs_control) {
if (dws->rx && dws->tx)
- chip->tmode = 0x00;
+ chip->tmode = SPI_TMOD_TR;
else if (dws->rx)
- chip->tmode = 0x02;
+ chip->tmode = SPI_TMOD_RO;
else
- chip->tmode = 0x01;
+ chip->tmode = SPI_TMOD_TO;
- cr0 &= ~(0x3 << SPI_MODE_OFFSET);
+ cr0 &= ~SPI_TMOD_MASK;
cr0 |= (chip->tmode << SPI_TMOD_OFFSET);
}
@@ -699,9 +700,6 @@
chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
if (!chip)
return -ENOMEM;
-
- chip->cs_control = null_cs_control;
- chip->enable_dma = 0;
}
/*
@@ -883,7 +881,7 @@
dws->dma_inited = 0;
dws->dma_addr = (dma_addr_t)(dws->paddr + 0x60);
- ret = request_irq(dws->irq, dw_spi_irq, 0,
+ ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED,
"dw_spi", dws);
if (ret < 0) {
dev_err(&master->dev, "can not get IRQ\n");
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index a9e5c79..b5a78a1 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -23,6 +23,7 @@
#include <linux/init.h>
#include <linux/cache.h>
#include <linux/mutex.h>
+#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
@@ -86,6 +87,10 @@
const struct spi_device *spi = to_spi_device(dev);
const struct spi_driver *sdrv = to_spi_driver(drv);
+ /* Attempt an OF style match */
+ if (of_driver_match_device(dev, drv))
+ return 1;
+
if (sdrv->id_table)
return !!spi_match_id(sdrv->id_table, spi);
@@ -554,11 +559,9 @@
EXPORT_SYMBOL_GPL(spi_register_master);
-static int __unregister(struct device *dev, void *master_dev)
+static int __unregister(struct device *dev, void *null)
{
- /* note: before about 2.6.14-rc1 this would corrupt memory: */
- if (dev != master_dev)
- spi_unregister_device(to_spi_device(dev));
+ spi_unregister_device(to_spi_device(dev));
return 0;
}
@@ -576,8 +579,7 @@
{
int dummy;
- dummy = device_for_each_child(master->dev.parent, &master->dev,
- __unregister);
+ dummy = device_for_each_child(&master->dev, NULL, __unregister);
device_unregister(&master->dev);
}
EXPORT_SYMBOL_GPL(spi_unregister_master);
diff --git a/drivers/spi/spi_gpio.c b/drivers/spi/spi_gpio.c
index e24a634..63e51b0 100644
--- a/drivers/spi/spi_gpio.c
+++ b/drivers/spi/spi_gpio.c
@@ -350,7 +350,7 @@
spi_gpio->bitbang.master = spi_master_get(master);
spi_gpio->bitbang.chipselect = spi_gpio_chipselect;
- if ((master_flags & (SPI_MASTER_NO_RX | SPI_MASTER_NO_RX)) == 0) {
+ if ((master_flags & (SPI_MASTER_NO_TX | SPI_MASTER_NO_RX)) == 0) {
spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0;
spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_word_mode1;
spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_word_mode2;
diff --git a/drivers/spi/spi_mpc8xxx.c b/drivers/spi/spi_mpc8xxx.c
index d31b57f..1dd86b8 100644
--- a/drivers/spi/spi_mpc8xxx.c
+++ b/drivers/spi/spi_mpc8xxx.c
@@ -408,11 +408,17 @@
xfer_ofs = mspi->xfer_in_progress->len - mspi->count;
- out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma + xfer_ofs);
+ if (mspi->rx_dma == mspi->dma_dummy_rx)
+ out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma);
+ else
+ out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma + xfer_ofs);
out_be16(&rx_bd->cbd_datlen, 0);
out_be16(&rx_bd->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT | BD_SC_WRAP);
- out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma + xfer_ofs);
+ if (mspi->tx_dma == mspi->dma_dummy_tx)
+ out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma);
+ else
+ out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma + xfer_ofs);
out_be16(&tx_bd->cbd_datlen, xfer_len);
out_be16(&tx_bd->cbd_sc, BD_SC_READY | BD_SC_INTRPT | BD_SC_WRAP |
BD_SC_LAST);
diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c
index 9736581..c3038da 100644
--- a/drivers/spi/spi_s3c64xx.c
+++ b/drivers/spi/spi_s3c64xx.c
@@ -200,6 +200,9 @@
val = readl(regs + S3C64XX_SPI_STATUS);
} while (TX_FIFO_LVL(val, sci) && loops--);
+ if (loops == 0)
+ dev_warn(&sdd->pdev->dev, "Timed out flushing TX FIFO\n");
+
/* Flush RxFIFO*/
loops = msecs_to_loops(1);
do {
@@ -210,6 +213,9 @@
break;
} while (loops--);
+ if (loops == 0)
+ dev_warn(&sdd->pdev->dev, "Timed out flushing RX FIFO\n");
+
val = readl(regs + S3C64XX_SPI_CH_CFG);
val &= ~S3C64XX_SPI_CH_SW_RST;
writel(val, regs + S3C64XX_SPI_CH_CFG);
@@ -320,16 +326,17 @@
/* millisecs to xfer 'len' bytes @ 'cur_speed' */
ms = xfer->len * 8 * 1000 / sdd->cur_speed;
- ms += 5; /* some tolerance */
+ ms += 10; /* some tolerance */
if (dma_mode) {
val = msecs_to_jiffies(ms) + 10;
val = wait_for_completion_timeout(&sdd->xfer_completion, val);
} else {
+ u32 status;
val = msecs_to_loops(ms);
do {
- val = readl(regs + S3C64XX_SPI_STATUS);
- } while (RX_FIFO_LVL(val, sci) < xfer->len && --val);
+ status = readl(regs + S3C64XX_SPI_STATUS);
+ } while (RX_FIFO_LVL(status, sci) < xfer->len && --val);
}
if (!val)
@@ -447,8 +454,8 @@
writel(val, regs + S3C64XX_SPI_CLK_CFG);
}
-void s3c64xx_spi_dma_rxcb(struct s3c2410_dma_chan *chan, void *buf_id,
- int size, enum s3c2410_dma_buffresult res)
+static void s3c64xx_spi_dma_rxcb(struct s3c2410_dma_chan *chan, void *buf_id,
+ int size, enum s3c2410_dma_buffresult res)
{
struct s3c64xx_spi_driver_data *sdd = buf_id;
unsigned long flags;
@@ -467,8 +474,8 @@
spin_unlock_irqrestore(&sdd->lock, flags);
}
-void s3c64xx_spi_dma_txcb(struct s3c2410_dma_chan *chan, void *buf_id,
- int size, enum s3c2410_dma_buffresult res)
+static void s3c64xx_spi_dma_txcb(struct s3c2410_dma_chan *chan, void *buf_id,
+ int size, enum s3c2410_dma_buffresult res)
{
struct s3c64xx_spi_driver_data *sdd = buf_id;
unsigned long flags;
@@ -508,8 +515,9 @@
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
if (xfer->tx_buf != NULL) {
- xfer->tx_dma = dma_map_single(dev, xfer->tx_buf,
- xfer->len, DMA_TO_DEVICE);
+ xfer->tx_dma = dma_map_single(dev,
+ (void *)xfer->tx_buf, xfer->len,
+ DMA_TO_DEVICE);
if (dma_mapping_error(dev, xfer->tx_dma)) {
dev_err(dev, "dma_map_single Tx failed\n");
xfer->tx_dma = XFER_DMAADDR_INVALID;
@@ -919,6 +927,13 @@
return -ENODEV;
}
+ sci = pdev->dev.platform_data;
+ if (!sci->src_clk_name) {
+ dev_err(&pdev->dev,
+ "Board init must call s3c64xx_spi_set_info()\n");
+ return -EINVAL;
+ }
+
/* Check for availability of necessary resource */
dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
@@ -946,8 +961,6 @@
return -ENOMEM;
}
- sci = pdev->dev.platform_data;
-
platform_set_drvdata(pdev, master);
sdd = spi_master_get_devdata(master);
@@ -1170,7 +1183,7 @@
{
return platform_driver_probe(&s3c64xx_spi_driver, s3c64xx_spi_probe);
}
-module_init(s3c64xx_spi_init);
+subsys_initcall(s3c64xx_spi_init);
static void __exit s3c64xx_spi_exit(void)
{
diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c
index baa8b05..6e973a7 100644
--- a/drivers/staging/batman-adv/hard-interface.c
+++ b/drivers/staging/batman-adv/hard-interface.c
@@ -30,7 +30,6 @@
#include "hash.h"
#include <linux/if_arp.h>
-#include <linux/netfilter_bridge.h>
#define MIN(x, y) ((x) < (y) ? (x) : (y))
@@ -431,11 +430,6 @@
return NOTIFY_DONE;
}
-static int batman_skb_recv_finish(struct sk_buff *skb)
-{
- return NF_ACCEPT;
-}
-
/* receive a packet with the batman ethertype coming on a hard
* interface */
int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
@@ -456,13 +450,6 @@
if (atomic_read(&module_state) != MODULE_ACTIVE)
goto err_free;
- /* if netfilter/ebtables wants to block incoming batman
- * packets then give them a chance to do so here */
- ret = NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, dev, NULL,
- batman_skb_recv_finish);
- if (ret != 1)
- goto err_out;
-
/* packet should hold at least type and version */
if (unlikely(skb_headlen(skb) < 2))
goto err_free;
diff --git a/drivers/staging/batman-adv/send.c b/drivers/staging/batman-adv/send.c
index 055edee..da3c82e 100644
--- a/drivers/staging/batman-adv/send.c
+++ b/drivers/staging/batman-adv/send.c
@@ -29,7 +29,6 @@
#include "vis.h"
#include "aggregation.h"
-#include <linux/netfilter_bridge.h>
static void send_outstanding_bcast_packet(struct work_struct *work);
@@ -92,12 +91,9 @@
/* dev_queue_xmit() returns a negative result on error. However on
* congestion and traffic shaping, it drops and returns NET_XMIT_DROP
- * (which is > 0). This will not be treated as an error.
- * Also, if netfilter/ebtables wants to block outgoing batman
- * packets then giving them a chance to do so here */
+ * (which is > 0). This will not be treated as an error. */
- return NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
- dev_queue_xmit);
+ return dev_queue_xmit(skb);
send_skb_err:
kfree_skb(skb);
return NET_XMIT_DROP;
diff --git a/drivers/staging/ti-st/st.h b/drivers/staging/ti-st/st.h
index 9952579..1b3060e 100644
--- a/drivers/staging/ti-st/st.h
+++ b/drivers/staging/ti-st/st.h
@@ -80,5 +80,4 @@
extern long st_register(struct st_proto_s *);
extern long st_unregister(enum proto_type);
-extern struct platform_device *st_get_plat_device(void);
#endif /* ST_H */
diff --git a/drivers/staging/ti-st/st_core.c b/drivers/staging/ti-st/st_core.c
index 063c9b1..b85d8bf 100644
--- a/drivers/staging/ti-st/st_core.c
+++ b/drivers/staging/ti-st/st_core.c
@@ -38,7 +38,6 @@
#include "st_ll.h"
#include "st.h"
-#define VERBOSE
/* strings to be used for rfkill entries and by
* ST Core to be used for sysfs debug entry
*/
@@ -581,7 +580,7 @@
long err = 0;
unsigned long flags = 0;
- st_kim_ref(&st_gdata);
+ st_kim_ref(&st_gdata, 0);
pr_info("%s(%d) ", __func__, new_proto->type);
if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL
|| new_proto->reg_complete_cb == NULL) {
@@ -713,7 +712,7 @@
pr_debug("%s: %d ", __func__, type);
- st_kim_ref(&st_gdata);
+ st_kim_ref(&st_gdata, 0);
if (type < ST_BT || type >= ST_MAX) {
pr_err(" protocol %d not supported", type);
return -EPROTONOSUPPORT;
@@ -767,7 +766,7 @@
#endif
long len;
- st_kim_ref(&st_gdata);
+ st_kim_ref(&st_gdata, 0);
if (unlikely(skb == NULL || st_gdata == NULL
|| st_gdata->tty == NULL)) {
pr_err("data/tty unavailable to perform write");
@@ -818,7 +817,7 @@
struct st_data_s *st_gdata;
pr_info("%s ", __func__);
- st_kim_ref(&st_gdata);
+ st_kim_ref(&st_gdata, 0);
st_gdata->tty = tty;
tty->disc_data = st_gdata;
diff --git a/drivers/staging/ti-st/st_core.h b/drivers/staging/ti-st/st_core.h
index e0c32d1..8601320 100644
--- a/drivers/staging/ti-st/st_core.h
+++ b/drivers/staging/ti-st/st_core.h
@@ -117,7 +117,7 @@
void st_core_exit(struct st_data_s *);
/* ask for reference from KIM */
-void st_kim_ref(struct st_data_s **);
+void st_kim_ref(struct st_data_s **, int);
#define GPS_STUB_TEST
#ifdef GPS_STUB_TEST
diff --git a/drivers/staging/ti-st/st_kim.c b/drivers/staging/ti-st/st_kim.c
index b4a6c7f..9e99463 100644
--- a/drivers/staging/ti-st/st_kim.c
+++ b/drivers/staging/ti-st/st_kim.c
@@ -72,11 +72,26 @@
PROTO_ENTRY(ST_GPS, "GPS"),
};
+#define MAX_ST_DEVICES 3 /* Imagine 1 on each UART for now */
+struct platform_device *st_kim_devices[MAX_ST_DEVICES];
/**********************************************************************/
/* internal functions */
/**
+ * st_get_plat_device -
+ * function which returns the reference to the platform device
+ * requested by id. As of now only 1 such device exists (id=0)
+ * the context requesting for reference can get the id to be
+ * requested by a. The protocol driver which is registering or
+ * b. the tty device which is opened.
+ */
+static struct platform_device *st_get_plat_device(int id)
+{
+ return st_kim_devices[id];
+}
+
+/**
* validate_firmware_response -
* function to return whether the firmware response was proper
* in case of error don't complete so that waiting for proper
@@ -353,7 +368,7 @@
struct kim_data_s *kim_gdata;
pr_info(" %s ", __func__);
- kim_pdev = st_get_plat_device();
+ kim_pdev = st_get_plat_device(0);
kim_gdata = dev_get_drvdata(&kim_pdev->dev);
if (kim_gdata->gpios[type] == -1) {
@@ -574,12 +589,12 @@
* This would enable multiple such platform devices to exist
* on a given platform
*/
-void st_kim_ref(struct st_data_s **core_data)
+void st_kim_ref(struct st_data_s **core_data, int id)
{
struct platform_device *pdev;
struct kim_data_s *kim_gdata;
/* get kim_gdata reference from platform device */
- pdev = st_get_plat_device();
+ pdev = st_get_plat_device(id);
kim_gdata = dev_get_drvdata(&pdev->dev);
*core_data = kim_gdata->core_data;
}
@@ -623,6 +638,7 @@
long *gpios = pdev->dev.platform_data;
struct kim_data_s *kim_gdata;
+ st_kim_devices[pdev->id] = pdev;
kim_gdata = kzalloc(sizeof(struct kim_data_s), GFP_ATOMIC);
if (!kim_gdata) {
pr_err("no mem to allocate");
diff --git a/drivers/staging/tm6000/Kconfig b/drivers/staging/tm6000/Kconfig
index c725356..de7ebb9 100644
--- a/drivers/staging/tm6000/Kconfig
+++ b/drivers/staging/tm6000/Kconfig
@@ -1,6 +1,6 @@
config VIDEO_TM6000
tristate "TV Master TM5600/6000/6010 driver"
- depends on VIDEO_DEV && I2C && INPUT && USB && EXPERIMENTAL
+ depends on VIDEO_DEV && I2C && INPUT && IR_CORE && USB && EXPERIMENTAL
select VIDEO_TUNER
select MEDIA_TUNER_XC2028
select MEDIA_TUNER_XC5000
diff --git a/drivers/staging/tm6000/tm6000-input.c b/drivers/staging/tm6000/tm6000-input.c
index 32f7a0a..54f7667 100644
--- a/drivers/staging/tm6000/tm6000-input.c
+++ b/drivers/staging/tm6000/tm6000-input.c
@@ -46,7 +46,7 @@
}
struct tm6000_ir_poll_result {
- u8 rc_data[4];
+ u16 rc_data;
};
struct tm6000_IR {
@@ -60,9 +60,9 @@
int polling;
struct delayed_work work;
u8 wait:1;
+ u8 key:1;
struct urb *int_urb;
u8 *urb_data;
- u8 key:1;
int (*get_key) (struct tm6000_IR *, struct tm6000_ir_poll_result *);
@@ -122,13 +122,14 @@
if (urb->status != 0)
printk(KERN_INFO "not ready\n");
- else if (urb->actual_length > 0)
+ else if (urb->actual_length > 0) {
memcpy(ir->urb_data, urb->transfer_buffer, urb->actual_length);
- dprintk("data %02x %02x %02x %02x\n", ir->urb_data[0],
- ir->urb_data[1], ir->urb_data[2], ir->urb_data[3]);
+ dprintk("data %02x %02x %02x %02x\n", ir->urb_data[0],
+ ir->urb_data[1], ir->urb_data[2], ir->urb_data[3]);
- ir->key = 1;
+ ir->key = 1;
+ }
rc = usb_submit_urb(urb, GFP_ATOMIC);
}
@@ -140,30 +141,47 @@
int rc;
u8 buf[2];
- if (ir->wait && !&dev->int_in) {
- poll_result->rc_data[0] = 0xff;
+ if (ir->wait && !&dev->int_in)
return 0;
- }
if (&dev->int_in) {
- poll_result->rc_data[0] = ir->urb_data[0];
- poll_result->rc_data[1] = ir->urb_data[1];
+ if (ir->ir.ir_type == IR_TYPE_RC5)
+ poll_result->rc_data = ir->urb_data[0];
+ else
+ poll_result->rc_data = ir->urb_data[0] | ir->urb_data[1] << 8;
} else {
tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0);
msleep(10);
tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 1);
msleep(10);
- rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR |
- USB_RECIP_DEVICE, REQ_02_GET_IR_CODE, 0, 0, buf, 1);
+ if (ir->ir.ir_type == IR_TYPE_RC5) {
+ rc = tm6000_read_write_usb(dev, USB_DIR_IN |
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ REQ_02_GET_IR_CODE, 0, 0, buf, 1);
- msleep(10);
+ msleep(10);
- dprintk("read data=%02x\n", buf[0]);
- if (rc < 0)
- return rc;
+ dprintk("read data=%02x\n", buf[0]);
+ if (rc < 0)
+ return rc;
- poll_result->rc_data[0] = buf[0];
+ poll_result->rc_data = buf[0];
+ } else {
+ rc = tm6000_read_write_usb(dev, USB_DIR_IN |
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ REQ_02_GET_IR_CODE, 0, 0, buf, 2);
+
+ msleep(10);
+
+ dprintk("read data=%04x\n", buf[0] | buf[1] << 8);
+ if (rc < 0)
+ return rc;
+
+ poll_result->rc_data = buf[0] | buf[1] << 8;
+ }
+ if ((poll_result->rc_data & 0x00ff) != 0xff)
+ ir->key = 1;
}
return 0;
}
@@ -180,12 +198,11 @@
return;
}
- dprintk("ir->get_key result data=%02x %02x\n",
- poll_result.rc_data[0], poll_result.rc_data[1]);
+ dprintk("ir->get_key result data=%04x\n", poll_result.rc_data);
- if (poll_result.rc_data[0] != 0xff && ir->key == 1) {
+ if (ir->key) {
ir_input_keydown(ir->input->input_dev, &ir->ir,
- poll_result.rc_data[0] | poll_result.rc_data[1] << 8);
+ (u32)poll_result.rc_data);
ir_input_nokey(ir->input->input_dev, &ir->ir);
ir->key = 0;
diff --git a/drivers/staging/vt6655/wpactl.c b/drivers/staging/vt6655/wpactl.c
index 0142338b..4bdb836 100644
--- a/drivers/staging/vt6655/wpactl.c
+++ b/drivers/staging/vt6655/wpactl.c
@@ -766,9 +766,14 @@
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wpa_ie_len = %d\n", param->u.wpa_associate.wpa_ie_len);
- if (param->u.wpa_associate.wpa_ie &&
- copy_from_user(&abyWPAIE[0], param->u.wpa_associate.wpa_ie, param->u.wpa_associate.wpa_ie_len))
- return -EINVAL;
+ if (param->u.wpa_associate.wpa_ie_len) {
+ if (!param->u.wpa_associate.wpa_ie)
+ return -EINVAL;
+ if (param->u.wpa_associate.wpa_ie_len > sizeof(abyWPAIE))
+ return -EINVAL;
+ if (copy_from_user(&abyWPAIE[0], param->u.wpa_associate.wpa_ie, param->u.wpa_associate.wpa_ie_len))
+ return -EFAULT;
+ }
if (param->u.wpa_associate.mode == 1)
pMgmt->eConfigMode = WMAC_CONFIG_IBSS_STA;
diff --git a/drivers/staging/xgifb/TODO b/drivers/staging/xgifb/TODO
index 7d71019..c85ff5e 100644
--- a/drivers/staging/xgifb/TODO
+++ b/drivers/staging/xgifb/TODO
@@ -12,4 +12,4 @@
- get rid of non-linux related stuff
Please send patches to:
-Arnaud Patard <apatard@mandriva.com>
+Arnaud Patard <arnaud.patard@rtp-net.org>
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index 7e59444..9eed5b5 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -91,12 +91,12 @@
If you are unsure about this, say N here.
config USB_SUSPEND
- bool "USB runtime power management (suspend/resume and wakeup)"
+ bool "USB runtime power management (autosuspend) and wakeup"
depends on USB && PM_RUNTIME
help
If you say Y here, you can use driver calls or the sysfs
- "power/level" file to suspend or resume individual USB
- peripherals and to enable or disable autosuspend (see
+ "power/control" file to enable or disable autosuspend for
+ individual USB peripherals (see
Documentation/usb/power-management.txt for more details).
Also, USB "remote wakeup" signaling is supported, whereby some
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index f06f5db..1e6ccef 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -159,9 +159,9 @@
int usb_register_dev(struct usb_interface *intf,
struct usb_class_driver *class_driver)
{
- int retval = -EINVAL;
+ int retval;
int minor_base = class_driver->minor_base;
- int minor = 0;
+ int minor;
char name[20];
char *temp;
@@ -173,12 +173,17 @@
*/
minor_base = 0;
#endif
- intf->minor = -1;
-
- dbg ("looking for a minor, starting at %d", minor_base);
if (class_driver->fops == NULL)
- goto exit;
+ return -EINVAL;
+ if (intf->minor >= 0)
+ return -EADDRINUSE;
+
+ retval = init_usb_class();
+ if (retval)
+ return retval;
+
+ dev_dbg(&intf->dev, "looking for a minor, starting at %d", minor_base);
down_write(&minor_rwsem);
for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {
@@ -186,20 +191,12 @@
continue;
usb_minors[minor] = class_driver->fops;
-
- retval = 0;
+ intf->minor = minor;
break;
}
up_write(&minor_rwsem);
-
- if (retval)
- goto exit;
-
- retval = init_usb_class();
- if (retval)
- goto exit;
-
- intf->minor = minor;
+ if (intf->minor < 0)
+ return -EXFULL;
/* create a usb class device for this usb interface */
snprintf(name, sizeof(name), class_driver->name, minor - minor_base);
@@ -213,11 +210,11 @@
"%s", temp);
if (IS_ERR(intf->usb_dev)) {
down_write(&minor_rwsem);
- usb_minors[intf->minor] = NULL;
+ usb_minors[minor] = NULL;
+ intf->minor = -1;
up_write(&minor_rwsem);
retval = PTR_ERR(intf->usb_dev);
}
-exit:
return retval;
}
EXPORT_SYMBOL_GPL(usb_register_dev);
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 844683e..9f0ce7d 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1802,6 +1802,7 @@
intf->dev.groups = usb_interface_groups;
intf->dev.dma_mask = dev->dev.dma_mask;
INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
+ intf->minor = -1;
device_initialize(&intf->dev);
dev_set_name(&intf->dev, "%d-%s:%d.%d",
dev->bus->busnum, dev->devpath,
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 58b72d7..a1e8d27 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -119,6 +119,11 @@
ehci->broken_periodic = 1;
ehci_info(ehci, "using broken periodic workaround\n");
}
+ if (pdev->device == 0x0806 || pdev->device == 0x0811
+ || pdev->device == 0x0829) {
+ ehci_info(ehci, "disable lpm for langwell/penwell\n");
+ ehci->has_lpm = 0;
+ }
break;
case PCI_VENDOR_ID_TDI:
if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) {
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
index 59dc3d3..5ab5bb8 100644
--- a/drivers/usb/musb/cppi_dma.c
+++ b/drivers/usb/musb/cppi_dma.c
@@ -322,6 +322,7 @@
index, transmit ? 'T' : 'R', cppi_ch);
cppi_ch->hw_ep = ep;
cppi_ch->channel.status = MUSB_DMA_STATUS_FREE;
+ cppi_ch->channel.max_len = 0x7fffffff;
DBG(4, "Allocate CPPI%d %cX\n", index, transmit ? 'T' : 'R');
return &cppi_ch->channel;
diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c
index c79a5e3..9e8639d 100644
--- a/drivers/usb/musb/musb_debugfs.c
+++ b/drivers/usb/musb/musb_debugfs.c
@@ -195,15 +195,14 @@
static int musb_test_mode_open(struct inode *inode, struct file *file)
{
- file->private_data = inode->i_private;
-
return single_open(file, musb_test_mode_show, inode->i_private);
}
static ssize_t musb_test_mode_write(struct file *file,
const char __user *ubuf, size_t count, loff_t *ppos)
{
- struct musb *musb = file->private_data;
+ struct seq_file *s = file->private_data;
+ struct musb *musb = s->private;
u8 test = 0;
char buf[18];
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 6fca870..d065e23 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -300,6 +300,11 @@
#ifndef CONFIG_MUSB_PIO_ONLY
if (is_dma_capable() && musb_ep->dma) {
struct dma_controller *c = musb->dma_controller;
+ size_t request_size;
+
+ /* setup DMA, then program endpoint CSR */
+ request_size = min_t(size_t, request->length - request->actual,
+ musb_ep->dma->max_len);
use_dma = (request->dma != DMA_ADDR_INVALID);
@@ -307,11 +312,6 @@
#ifdef CONFIG_USB_INVENTRA_DMA
{
- size_t request_size;
-
- /* setup DMA, then program endpoint CSR */
- request_size = min_t(size_t, request->length,
- musb_ep->dma->max_len);
if (request_size < musb_ep->packet_sz)
musb_ep->dma->desired_mode = 0;
else
@@ -373,8 +373,8 @@
use_dma = use_dma && c->channel_program(
musb_ep->dma, musb_ep->packet_sz,
0,
- request->dma,
- request->length);
+ request->dma + request->actual,
+ request_size);
if (!use_dma) {
c->channel_release(musb_ep->dma);
musb_ep->dma = NULL;
@@ -386,8 +386,8 @@
use_dma = use_dma && c->channel_program(
musb_ep->dma, musb_ep->packet_sz,
request->zero,
- request->dma,
- request->length);
+ request->dma + request->actual,
+ request_size);
#endif
}
#endif
@@ -501,26 +501,14 @@
request->zero = 0;
}
- /* ... or if not, then complete it. */
- musb_g_giveback(musb_ep, request, 0);
-
- /*
- * Kickstart next transfer if appropriate;
- * the packet that just completed might not
- * be transmitted for hours or days.
- * REVISIT for double buffering...
- * FIXME revisit for stalls too...
- */
- musb_ep_select(mbase, epnum);
- csr = musb_readw(epio, MUSB_TXCSR);
- if (csr & MUSB_TXCSR_FIFONOTEMPTY)
- return;
-
- request = musb_ep->desc ? next_request(musb_ep) : NULL;
- if (!request) {
- DBG(4, "%s idle now\n",
- musb_ep->end_point.name);
- return;
+ if (request->actual == request->length) {
+ musb_g_giveback(musb_ep, request, 0);
+ request = musb_ep->desc ? next_request(musb_ep) : NULL;
+ if (!request) {
+ DBG(4, "%s idle now\n",
+ musb_ep->end_point.name);
+ return;
+ }
}
}
@@ -568,11 +556,19 @@
{
const u8 epnum = req->epnum;
struct usb_request *request = &req->request;
- struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_out;
+ struct musb_ep *musb_ep;
void __iomem *epio = musb->endpoints[epnum].regs;
unsigned fifo_count = 0;
- u16 len = musb_ep->packet_sz;
+ u16 len;
u16 csr = musb_readw(epio, MUSB_RXCSR);
+ struct musb_hw_ep *hw_ep = &musb->endpoints[epnum];
+
+ if (hw_ep->is_shared_fifo)
+ musb_ep = &hw_ep->ep_in;
+ else
+ musb_ep = &hw_ep->ep_out;
+
+ len = musb_ep->packet_sz;
/* We shouldn't get here while DMA is active, but we do... */
if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) {
@@ -647,8 +643,8 @@
*/
csr |= MUSB_RXCSR_DMAENAB;
-#ifdef USE_MODE1
csr |= MUSB_RXCSR_AUTOCLEAR;
+#ifdef USE_MODE1
/* csr |= MUSB_RXCSR_DMAMODE; */
/* this special sequence (enabling and then
@@ -663,10 +659,11 @@
if (request->actual < request->length) {
int transfer_size = 0;
#ifdef USE_MODE1
- transfer_size = min(request->length,
+ transfer_size = min(request->length - request->actual,
channel->max_len);
#else
- transfer_size = len;
+ transfer_size = min(request->length - request->actual,
+ (unsigned)len);
#endif
if (transfer_size <= musb_ep->packet_sz)
musb_ep->dma->desired_mode = 0;
@@ -740,9 +737,15 @@
u16 csr;
struct usb_request *request;
void __iomem *mbase = musb->mregs;
- struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_out;
+ struct musb_ep *musb_ep;
void __iomem *epio = musb->endpoints[epnum].regs;
struct dma_channel *dma;
+ struct musb_hw_ep *hw_ep = &musb->endpoints[epnum];
+
+ if (hw_ep->is_shared_fifo)
+ musb_ep = &hw_ep->ep_in;
+ else
+ musb_ep = &hw_ep->ep_out;
musb_ep_select(mbase, epnum);
@@ -1081,7 +1084,7 @@
/*
* Context: controller locked, IRQs blocked.
*/
-static void musb_ep_restart(struct musb *musb, struct musb_request *req)
+void musb_ep_restart(struct musb *musb, struct musb_request *req)
{
DBG(3, "<== %s request %p len %u on hw_ep%d\n",
req->tx ? "TX/IN" : "RX/OUT",
diff --git a/drivers/usb/musb/musb_gadget.h b/drivers/usb/musb/musb_gadget.h
index c8b1403..572b1da 100644
--- a/drivers/usb/musb/musb_gadget.h
+++ b/drivers/usb/musb/musb_gadget.h
@@ -105,4 +105,6 @@
extern void musb_g_giveback(struct musb_ep *, struct usb_request *, int);
+extern void musb_ep_restart(struct musb *, struct musb_request *);
+
#endif /* __MUSB_GADGET_H */
diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c
index 59bef8f..6dd03f4 100644
--- a/drivers/usb/musb/musb_gadget_ep0.c
+++ b/drivers/usb/musb/musb_gadget_ep0.c
@@ -261,6 +261,7 @@
ctrlrequest->wIndex & 0x0f;
struct musb_ep *musb_ep;
struct musb_hw_ep *ep;
+ struct musb_request *request;
void __iomem *regs;
int is_in;
u16 csr;
@@ -302,6 +303,14 @@
musb_writew(regs, MUSB_RXCSR, csr);
}
+ /* Maybe start the first request in the queue */
+ request = to_musb_request(
+ next_request(musb_ep));
+ if (!musb_ep->busy && request) {
+ DBG(3, "restarting the request\n");
+ musb_ep_restart(musb, request);
+ }
+
/* select ep0 again */
musb_ep_select(mbase, 0);
} break;
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 877d20b..9e65c47 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -660,6 +660,12 @@
qh->segsize = length;
+ /*
+ * Ensure the data reaches to main memory before starting
+ * DMA transfer
+ */
+ wmb();
+
if (!dma->channel_program(channel, pkt_size, mode,
urb->transfer_dma + offset, length)) {
dma->channel_release(channel);
diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c
index 05aaac1..0bc9769 100644
--- a/drivers/usb/otg/twl4030-usb.c
+++ b/drivers/usb/otg/twl4030-usb.c
@@ -347,11 +347,20 @@
}
}
+static void __twl4030_phy_power(struct twl4030_usb *twl, int on)
+{
+ u8 pwr = twl4030_usb_read(twl, PHY_PWR_CTRL);
+
+ if (on)
+ pwr &= ~PHY_PWR_PHYPWD;
+ else
+ pwr |= PHY_PWR_PHYPWD;
+
+ WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
+}
+
static void twl4030_phy_power(struct twl4030_usb *twl, int on)
{
- u8 pwr;
-
- pwr = twl4030_usb_read(twl, PHY_PWR_CTRL);
if (on) {
regulator_enable(twl->usb3v1);
regulator_enable(twl->usb1v8);
@@ -365,15 +374,13 @@
twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0,
VUSB_DEDICATED2);
regulator_enable(twl->usb1v5);
- pwr &= ~PHY_PWR_PHYPWD;
- WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
+ __twl4030_phy_power(twl, 1);
twl4030_usb_write(twl, PHY_CLK_CTRL,
twl4030_usb_read(twl, PHY_CLK_CTRL) |
(PHY_CLK_CTRL_CLOCKGATING_EN |
PHY_CLK_CTRL_CLK32K_EN));
- } else {
- pwr |= PHY_PWR_PHYPWD;
- WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
+ } else {
+ __twl4030_phy_power(twl, 0);
regulator_disable(twl->usb1v5);
regulator_disable(twl->usb1v8);
regulator_disable(twl->usb3v1);
@@ -387,19 +394,25 @@
twl4030_phy_power(twl, 0);
twl->asleep = 1;
+ dev_dbg(twl->dev, "%s\n", __func__);
+}
+
+static void __twl4030_phy_resume(struct twl4030_usb *twl)
+{
+ twl4030_phy_power(twl, 1);
+ twl4030_i2c_access(twl, 1);
+ twl4030_usb_set_mode(twl, twl->usb_mode);
+ if (twl->usb_mode == T2_USB_MODE_ULPI)
+ twl4030_i2c_access(twl, 0);
}
static void twl4030_phy_resume(struct twl4030_usb *twl)
{
if (!twl->asleep)
return;
-
- twl4030_phy_power(twl, 1);
- twl4030_i2c_access(twl, 1);
- twl4030_usb_set_mode(twl, twl->usb_mode);
- if (twl->usb_mode == T2_USB_MODE_ULPI)
- twl4030_i2c_access(twl, 0);
+ __twl4030_phy_resume(twl);
twl->asleep = 0;
+ dev_dbg(twl->dev, "%s\n", __func__);
}
static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
@@ -408,8 +421,8 @@
twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0xC0, PROTECT_KEY);
twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0x0C, PROTECT_KEY);
- /* put VUSB3V1 LDO in active state */
- twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2);
+ /* Keep VUSB3V1 LDO in sleep state until VBUS/ID change detected*/
+ /*twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2);*/
/* input to VUSB3V1 LDO is from VBAT, not VBUS */
twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x14, VUSB_DEDICATED1);
@@ -502,6 +515,26 @@
return IRQ_HANDLED;
}
+static void twl4030_usb_phy_init(struct twl4030_usb *twl)
+{
+ int status;
+
+ status = twl4030_usb_linkstat(twl);
+ if (status >= 0) {
+ if (status == USB_EVENT_NONE) {
+ __twl4030_phy_power(twl, 0);
+ twl->asleep = 1;
+ } else {
+ __twl4030_phy_resume(twl);
+ twl->asleep = 0;
+ }
+
+ blocking_notifier_call_chain(&twl->otg.notifier, status,
+ twl->otg.gadget);
+ }
+ sysfs_notify(&twl->dev->kobj, NULL, "vbus");
+}
+
static int twl4030_set_suspend(struct otg_transceiver *x, int suspend)
{
struct twl4030_usb *twl = xceiv_to_twl(x);
@@ -550,7 +583,6 @@
struct twl4030_usb_data *pdata = pdev->dev.platform_data;
struct twl4030_usb *twl;
int status, err;
- u8 pwr;
if (!pdata) {
dev_dbg(&pdev->dev, "platform_data not available\n");
@@ -569,10 +601,7 @@
twl->otg.set_peripheral = twl4030_set_peripheral;
twl->otg.set_suspend = twl4030_set_suspend;
twl->usb_mode = pdata->usb_mode;
-
- pwr = twl4030_usb_read(twl, PHY_PWR_CTRL);
-
- twl->asleep = (pwr & PHY_PWR_PHYPWD);
+ twl->asleep = 1;
/* init spinlock for workqueue */
spin_lock_init(&twl->lock);
@@ -610,15 +639,10 @@
return status;
}
- /* The IRQ handler just handles changes from the previous states
- * of the ID and VBUS pins ... in probe() we must initialize that
- * previous state. The easy way: fake an IRQ.
- *
- * REVISIT: a real IRQ might have happened already, if PREEMPT is
- * enabled. Else the IRQ may not yet be configured or enabled,
- * because of scheduling delays.
+ /* Power down phy or make it work according to
+ * current link state.
*/
- twl4030_usb_irq(twl->irq, twl);
+ twl4030_usb_phy_init(twl);
dev_info(&pdev->dev, "Initialized TWL4030 USB module\n");
return 0;
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 30922a7..aa66581 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -2024,6 +2024,9 @@
case TIOCGICOUNT:
cnow = mos7720_port->icount;
+
+ memset(&icount, 0, sizeof(struct serial_icounter_struct));
+
icount.cts = cnow.cts;
icount.dsr = cnow.dsr;
icount.rng = cnow.rng;
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 1c9b6e9..1a42bc2 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -2285,6 +2285,9 @@
case TIOCGICOUNT:
cnow = mos7840_port->icount;
smp_rmb();
+
+ memset(&icount, 0, sizeof(struct serial_icounter_struct));
+
icount.cts = cnow.cts;
icount.dsr = cnow.dsr;
icount.rng = cnow.rng;
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 29e850a..7c80082 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -243,7 +243,7 @@
int r, nlogs = 0;
while (datalen > 0) {
- if (unlikely(headcount >= VHOST_NET_MAX_SG)) {
+ if (unlikely(seg >= VHOST_NET_MAX_SG)) {
r = -ENOBUFS;
goto err;
}
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index c579dcc..dd3d6f7 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -858,11 +858,12 @@
if (r < 0)
return r;
len -= l;
- if (!len)
+ if (!len) {
+ if (vq->log_ctx)
+ eventfd_signal(vq->log_ctx, 1);
return 0;
+ }
}
- if (vq->log_ctx)
- eventfd_signal(vq->log_ctx, 1);
/* Length written exceeds what we have stored. This is a bug. */
BUG();
return 0;
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 8b31fdf..935cdc2 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1919,6 +1919,9 @@
tristate "SuperH Mobile HDMI controller support"
depends on FB_SH_MOBILE_LCDC
select FB_MODE_HELPERS
+ select SOUND
+ select SND
+ select SND_SOC
---help---
Driver for the on-chip SH-Mobile HDMI controller.
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 84f8423..7ccc967 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -3508,7 +3508,7 @@
softback_buf = 0UL;
for (i = 0; i < FB_MAX; i++) {
- int pending;
+ int pending = 0;
mapped = 0;
info = registered_fb[i];
@@ -3516,7 +3516,8 @@
if (info == NULL)
continue;
- pending = cancel_work_sync(&info->queue);
+ if (info->queue.func)
+ pending = cancel_work_sync(&info->queue);
DPRINTK("fbcon: %s pending work\n", (pending ? "canceled" :
"no"));
diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c
index 815f84b..70477c2 100644
--- a/drivers/video/efifb.c
+++ b/drivers/video/efifb.c
@@ -13,7 +13,7 @@
#include <linux/platform_device.h>
#include <linux/screen_info.h>
#include <linux/dmi.h>
-
+#include <linux/pci.h>
#include <video/vga.h>
static struct fb_var_screeninfo efifb_defined __devinitdata = {
@@ -39,17 +39,31 @@
M_I20, /* 20-Inch iMac */
M_I20_SR, /* 20-Inch iMac (Santa Rosa) */
M_I24, /* 24-Inch iMac */
+ M_I24_8_1, /* 24-Inch iMac, 8,1th gen */
+ M_I24_10_1, /* 24-Inch iMac, 10,1th gen */
+ M_I27_11_1, /* 27-Inch iMac, 11,1th gen */
M_MINI, /* Mac Mini */
+ M_MINI_3_1, /* Mac Mini, 3,1th gen */
+ M_MINI_4_1, /* Mac Mini, 4,1th gen */
M_MB, /* MacBook */
M_MB_2, /* MacBook, 2nd rev. */
M_MB_3, /* MacBook, 3rd rev. */
+ M_MB_5_1, /* MacBook, 5th rev. */
+ M_MB_6_1, /* MacBook, 6th rev. */
+ M_MB_7_1, /* MacBook, 7th rev. */
M_MB_SR, /* MacBook, 2nd gen, (Santa Rosa) */
M_MBA, /* MacBook Air */
M_MBP, /* MacBook Pro */
M_MBP_2, /* MacBook Pro 2nd gen */
+ M_MBP_2_2, /* MacBook Pro 2,2nd gen */
M_MBP_SR, /* MacBook Pro (Santa Rosa) */
M_MBP_4, /* MacBook Pro, 4th gen */
M_MBP_5_1, /* MacBook Pro, 5,1th gen */
+ M_MBP_5_2, /* MacBook Pro, 5,2th gen */
+ M_MBP_5_3, /* MacBook Pro, 5,3rd gen */
+ M_MBP_6_1, /* MacBook Pro, 6,1th gen */
+ M_MBP_6_2, /* MacBook Pro, 6,2th gen */
+ M_MBP_7_1, /* MacBook Pro, 7,1th gen */
M_UNKNOWN /* placeholder */
};
@@ -64,14 +78,28 @@
[M_I20] = { "i20", 0x80010000, 1728 * 4, 1680, 1050 }, /* guess */
[M_I20_SR] = { "imac7", 0x40010000, 1728 * 4, 1680, 1050 },
[M_I24] = { "i24", 0x80010000, 2048 * 4, 1920, 1200 }, /* guess */
+ [M_I24_8_1] = { "imac8", 0xc0060000, 2048 * 4, 1920, 1200 },
+ [M_I24_10_1] = { "imac10", 0xc0010000, 2048 * 4, 1920, 1080 },
+ [M_I27_11_1] = { "imac11", 0xc0010000, 2560 * 4, 2560, 1440 },
[M_MINI]= { "mini", 0x80000000, 2048 * 4, 1024, 768 },
+ [M_MINI_3_1] = { "mini31", 0x40010000, 1024 * 4, 1024, 768 },
+ [M_MINI_4_1] = { "mini41", 0xc0010000, 2048 * 4, 1920, 1200 },
[M_MB] = { "macbook", 0x80000000, 2048 * 4, 1280, 800 },
+ [M_MB_5_1] = { "macbook51", 0x80010000, 2048 * 4, 1280, 800 },
+ [M_MB_6_1] = { "macbook61", 0x80010000, 2048 * 4, 1280, 800 },
+ [M_MB_7_1] = { "macbook71", 0x80010000, 2048 * 4, 1280, 800 },
[M_MBA] = { "mba", 0x80000000, 2048 * 4, 1280, 800 },
[M_MBP] = { "mbp", 0x80010000, 1472 * 4, 1440, 900 },
[M_MBP_2] = { "mbp2", 0, 0, 0, 0 }, /* placeholder */
+ [M_MBP_2_2] = { "mbp22", 0x80010000, 1472 * 4, 1440, 900 },
[M_MBP_SR] = { "mbp3", 0x80030000, 2048 * 4, 1440, 900 },
[M_MBP_4] = { "mbp4", 0xc0060000, 2048 * 4, 1920, 1200 },
[M_MBP_5_1] = { "mbp51", 0xc0010000, 2048 * 4, 1440, 900 },
+ [M_MBP_5_2] = { "mbp52", 0xc0010000, 2048 * 4, 1920, 1200 },
+ [M_MBP_5_3] = { "mbp53", 0xd0010000, 2048 * 4, 1440, 900 },
+ [M_MBP_6_1] = { "mbp61", 0x90030000, 2048 * 4, 1920, 1200 },
+ [M_MBP_6_2] = { "mbp62", 0x90030000, 2048 * 4, 1680, 1050 },
+ [M_MBP_7_1] = { "mbp71", 0xc0010000, 2048 * 4, 1280, 800 },
[M_UNKNOWN] = { NULL, 0, 0, 0, 0 }
};
@@ -92,7 +120,12 @@
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac6,1", M_I24),
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac6,1", M_I24),
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac7,1", M_I20_SR),
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac8,1", M_I24_8_1),
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac10,1", M_I24_10_1),
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac11,1", M_I27_11_1),
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "Macmini1,1", M_MINI),
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "Macmini3,1", M_MINI_3_1),
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "Macmini4,1", M_MINI_4_1),
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook1,1", M_MB),
/* At least one of these two will be right; maybe both? */
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook2,1", M_MB),
@@ -101,14 +134,23 @@
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook3,1", M_MB),
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook3,1", M_MB),
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook4,1", M_MB),
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook5,1", M_MB_5_1),
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook6,1", M_MB_6_1),
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook7,1", M_MB_7_1),
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir1,1", M_MBA),
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro1,1", M_MBP),
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,1", M_MBP_2),
+ EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,2", M_MBP_2_2),
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro2,1", M_MBP_2),
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro3,1", M_MBP_SR),
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro3,1", M_MBP_SR),
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro4,1", M_MBP_4),
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,1", M_MBP_5_1),
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,2", M_MBP_5_2),
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,3", M_MBP_5_3),
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro6,1", M_MBP_6_1),
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro6,2", M_MBP_6_2),
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro7,1", M_MBP_7_1),
{},
};
@@ -116,7 +158,7 @@
{
struct efifb_dmi_info *info = id->driver_data;
if (info->base == 0)
- return -ENODEV;
+ return 0;
printk(KERN_INFO "efifb: dmi detected %s - framebuffer at %p "
"(%dx%d, stride %d)\n", id->ident,
@@ -124,18 +166,55 @@
info->stride);
/* Trust the bootloader over the DMI tables */
- if (screen_info.lfb_base == 0)
+ if (screen_info.lfb_base == 0) {
+#if defined(CONFIG_PCI)
+ struct pci_dev *dev = NULL;
+ int found_bar = 0;
+#endif
screen_info.lfb_base = info->base;
- if (screen_info.lfb_linelength == 0)
- screen_info.lfb_linelength = info->stride;
- if (screen_info.lfb_width == 0)
- screen_info.lfb_width = info->width;
- if (screen_info.lfb_height == 0)
- screen_info.lfb_height = info->height;
- if (screen_info.orig_video_isVGA == 0)
- screen_info.orig_video_isVGA = VIDEO_TYPE_EFI;
- return 0;
+#if defined(CONFIG_PCI)
+ /* make sure that the address in the table is actually on a
+ * VGA device's PCI BAR */
+
+ for_each_pci_dev(dev) {
+ int i;
+ if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
+ continue;
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ resource_size_t start, end;
+
+ start = pci_resource_start(dev, i);
+ if (start == 0)
+ break;
+ end = pci_resource_end(dev, i);
+ if (screen_info.lfb_base >= start &&
+ screen_info.lfb_base < end) {
+ found_bar = 1;
+ }
+ }
+ }
+ if (!found_bar)
+ screen_info.lfb_base = 0;
+#endif
+ }
+ if (screen_info.lfb_base) {
+ if (screen_info.lfb_linelength == 0)
+ screen_info.lfb_linelength = info->stride;
+ if (screen_info.lfb_width == 0)
+ screen_info.lfb_width = info->width;
+ if (screen_info.lfb_height == 0)
+ screen_info.lfb_height = info->height;
+ if (screen_info.orig_video_isVGA == 0)
+ screen_info.orig_video_isVGA = VIDEO_TYPE_EFI;
+ } else {
+ screen_info.lfb_linelength = 0;
+ screen_info.lfb_width = 0;
+ screen_info.lfb_height = 0;
+ screen_info.orig_video_isVGA = 0;
+ return 0;
+ }
+ return 1;
}
static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
diff --git a/drivers/video/pxa168fb.c b/drivers/video/pxa168fb.c
index 5d786bd..a31a77f 100644
--- a/drivers/video/pxa168fb.c
+++ b/drivers/video/pxa168fb.c
@@ -298,8 +298,8 @@
* Set bit to enable graphics DMA.
*/
x = readl(fbi->reg_base + LCD_SPU_DMA_CTRL0);
- x |= fbi->active ? 0x00000100 : 0;
- fbi->active = 0;
+ x &= ~CFG_GRA_ENA_MASK;
+ x |= fbi->active ? CFG_GRA_ENA(1) : CFG_GRA_ENA(0);
/*
* If we are in a pseudo-color mode, we need to enable
diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c
index 2fde08c..ef989d9 100644
--- a/drivers/video/sh_mobile_hdmi.c
+++ b/drivers/video/sh_mobile_hdmi.c
@@ -22,6 +22,8 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/workqueue.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
#include <video/sh_mobile_hdmi.h>
#include <video/sh_mobile_lcdc.h>
@@ -222,6 +224,58 @@
return ioread8(hdmi->base + reg);
}
+/*
+ * HDMI sound
+ */
+static unsigned int sh_hdmi_snd_read(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ struct sh_hdmi *hdmi = snd_soc_codec_get_drvdata(codec);
+
+ return hdmi_read(hdmi, reg);
+}
+
+static int sh_hdmi_snd_write(struct snd_soc_codec *codec,
+ unsigned int reg,
+ unsigned int value)
+{
+ struct sh_hdmi *hdmi = snd_soc_codec_get_drvdata(codec);
+
+ hdmi_write(hdmi, value, reg);
+ return 0;
+}
+
+static struct snd_soc_dai_driver sh_hdmi_dai = {
+ .name = "sh_mobile_hdmi-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ },
+};
+
+static int sh_hdmi_snd_probe(struct snd_soc_codec *codec)
+{
+ dev_info(codec->dev, "SH Mobile HDMI Audio Codec");
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_sh_hdmi = {
+ .probe = sh_hdmi_snd_probe,
+ .read = sh_hdmi_snd_read,
+ .write = sh_hdmi_snd_write,
+};
+
+/*
+ * HDMI video
+ */
+
/* External video parameter settings */
static void hdmi_external_video_param(struct sh_hdmi *hdmi)
{
@@ -318,6 +372,9 @@
*/
static void sh_hdmi_audio_config(struct sh_hdmi *hdmi)
{
+ u8 data;
+ struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data;
+
/*
* [7:4] L/R data swap control
* [3:0] appropriate N[19:16]
@@ -335,7 +392,23 @@
* [6:5] set required down sampling rate if required
* [4:3] set required audio source
*/
- hdmi_write(hdmi, 0x00, HDMI_AUDIO_SETTING_1);
+ switch (pdata->flags & HDMI_SND_SRC_MASK) {
+ default:
+ /* fall through */
+ case HDMI_SND_SRC_I2S:
+ data = 0x0 << 3;
+ break;
+ case HDMI_SND_SRC_SPDIF:
+ data = 0x1 << 3;
+ break;
+ case HDMI_SND_SRC_DSD:
+ data = 0x2 << 3;
+ break;
+ case HDMI_SND_SRC_HBR:
+ data = 0x3 << 3;
+ break;
+ }
+ hdmi_write(hdmi, data, HDMI_AUDIO_SETTING_1);
/* [3:0] set sending channel number for channel status */
hdmi_write(hdmi, 0x40, HDMI_AUDIO_SETTING_2);
@@ -891,6 +964,11 @@
return -ENOMEM;
}
+ ret = snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_sh_hdmi, &sh_hdmi_dai, 1);
+ if (ret < 0)
+ goto esndreg;
+
hdmi->dev = &pdev->dev;
hdmi->hdmi_clk = clk_get(&pdev->dev, "ick");
@@ -976,6 +1054,8 @@
erate:
clk_put(hdmi->hdmi_clk);
egetclk:
+ snd_soc_unregister_codec(&pdev->dev);
+esndreg:
kfree(hdmi);
return ret;
@@ -988,6 +1068,8 @@
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
int irq = platform_get_irq(pdev, 0);
+ snd_soc_unregister_codec(&pdev->dev);
+
pdata->lcd_chan->board_cfg.display_on = NULL;
pdata->lcd_chan->board_cfg.display_off = NULL;
pdata->lcd_chan->board_cfg.board_data = NULL;
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
index 559bf17..b52f8e4 100644
--- a/drivers/video/sis/sis_main.c
+++ b/drivers/video/sis/sis_main.c
@@ -1701,6 +1701,9 @@
break;
case FBIOGET_VBLANK:
+
+ memset(&sisvbblank, 0, sizeof(struct fb_vblank));
+
sisvbblank.count = 0;
sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
diff --git a/drivers/video/via/ioctl.c b/drivers/video/via/ioctl.c
index da03c07..4d553d0 100644
--- a/drivers/video/via/ioctl.c
+++ b/drivers/video/via/ioctl.c
@@ -25,6 +25,8 @@
{
struct viafb_ioctl_info viainfo;
+ memset(&viainfo, 0, sizeof(struct viafb_ioctl_info));
+
viainfo.viafb_id = VIAID;
viainfo.vendor_id = PCI_VIA_VENDOR_ID;
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index b036677..24efd8e 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -213,11 +213,11 @@
here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog timer.
config PNX4008_WATCHDOG
- tristate "PNX4008 Watchdog"
- depends on ARCH_PNX4008
+ tristate "PNX4008 and LPC32XX Watchdog"
+ depends on ARCH_PNX4008 || ARCH_LPC32XX
help
Say Y here if to include support for the watchdog timer
- in the PNX4008 processor.
+ in the PNX4008 or LPC32XX processor.
This driver can be built as a module by choosing M. The module
will be called pnx4008_wdt.
diff --git a/drivers/watchdog/sb_wdog.c b/drivers/watchdog/sb_wdog.c
index 88c83aa..f31493e 100644
--- a/drivers/watchdog/sb_wdog.c
+++ b/drivers/watchdog/sb_wdog.c
@@ -305,7 +305,7 @@
if (ret) {
printk(KERN_ERR "%s: failed to request irq 1 - %d\n",
ident.identity, ret);
- return ret;
+ goto out;
}
ret = misc_register(&sbwdog_miscdev);
@@ -313,14 +313,20 @@
printk(KERN_INFO "%s: timeout is %ld.%ld secs\n",
ident.identity,
timeout / 1000000, (timeout / 100000) % 10);
- } else
- free_irq(1, (void *)user_dog);
+ return 0;
+ }
+ free_irq(1, (void *)user_dog);
+out:
+ unregister_reboot_notifier(&sbwdog_notifier);
+
return ret;
}
static void __exit sbwdog_exit(void)
{
misc_deregister(&sbwdog_miscdev);
+ free_irq(1, (void *)user_dog);
+ unregister_reboot_notifier(&sbwdog_notifier);
}
module_init(sbwdog_init);
diff --git a/drivers/watchdog/ts72xx_wdt.c b/drivers/watchdog/ts72xx_wdt.c
index 458c499..18cdeb4 100644
--- a/drivers/watchdog/ts72xx_wdt.c
+++ b/drivers/watchdog/ts72xx_wdt.c
@@ -449,6 +449,9 @@
wdt->pdev = pdev;
mutex_init(&wdt->lock);
+ /* make sure that the watchdog is disabled */
+ ts72xx_wdt_stop(wdt);
+
error = misc_register(&ts72xx_wdt_miscdev);
if (error) {
dev_err(&pdev->dev, "failed to register miscdev\n");
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index 29bac51..d409495 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -755,7 +755,10 @@
{
int ret = 0;
- blocking_notifier_chain_register(&xenstore_chain, nb);
+ if (xenstored_ready > 0)
+ ret = nb->notifier_call(nb, 0, NULL);
+ else
+ blocking_notifier_chain_register(&xenstore_chain, nb);
return ret;
}
@@ -769,7 +772,7 @@
void xenbus_probe(struct work_struct *unused)
{
- BUG_ON((xenstored_ready <= 0));
+ xenstored_ready = 1;
/* Enumerate devices in xenstore and watch for changes. */
xenbus_probe_devices(&xenbus_frontend);
@@ -835,8 +838,8 @@
xen_store_evtchn = xen_start_info->store_evtchn;
xen_store_mfn = xen_start_info->store_mfn;
xen_store_interface = mfn_to_virt(xen_store_mfn);
+ xenstored_ready = 1;
}
- xenstored_ready = 1;
}
/* Initialize the interface to xenstore. */
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index 16c8a2a..899f168 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -292,9 +292,11 @@
fid = filp->private_data;
P9_DPRINTK(P9_DEBUG_VFS,
- "inode: %p filp: %p fid: %d\n", inode, filp, fid->fid);
+ "v9fs_dir_release: inode: %p filp: %p fid: %d\n",
+ inode, filp, fid ? fid->fid : -1);
filemap_write_and_wait(inode->i_mapping);
- p9_client_clunk(fid);
+ if (fid)
+ p9_client_clunk(fid);
return 0;
}
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index c7c23ea..9e670d5 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -730,7 +730,10 @@
P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err);
goto error;
}
- dentry->d_op = &v9fs_cached_dentry_operations;
+ if (v9ses->cache)
+ dentry->d_op = &v9fs_cached_dentry_operations;
+ else
+ dentry->d_op = &v9fs_dentry_operations;
d_instantiate(dentry, inode);
err = v9fs_fid_add(dentry, fid);
if (err < 0)
@@ -1128,6 +1131,7 @@
v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb);
generic_fillattr(dentry->d_inode, stat);
+ p9stat_free(st);
kfree(st);
return 0;
}
@@ -1489,6 +1493,7 @@
retval = strnlen(buffer, buflen);
done:
+ p9stat_free(st);
kfree(st);
return retval;
}
@@ -1942,7 +1947,7 @@
.unlink = v9fs_vfs_unlink,
.mkdir = v9fs_vfs_mkdir,
.rmdir = v9fs_vfs_rmdir,
- .mknod = v9fs_vfs_mknod_dotl,
+ .mknod = v9fs_vfs_mknod,
.rename = v9fs_vfs_rename,
.getattr = v9fs_vfs_getattr,
.setattr = v9fs_vfs_setattr,
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index f931107..1d12ba0 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -122,6 +122,10 @@
fid = v9fs_session_init(v9ses, dev_name, data);
if (IS_ERR(fid)) {
retval = PTR_ERR(fid);
+ /*
+ * we need to call session_close to tear down some
+ * of the data structure setup by session_init
+ */
goto close_session;
}
@@ -144,7 +148,6 @@
retval = -ENOMEM;
goto release_sb;
}
-
sb->s_root = root;
if (v9fs_proto_dotl(v9ses)) {
@@ -152,7 +155,7 @@
st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
if (IS_ERR(st)) {
retval = PTR_ERR(st);
- goto clunk_fid;
+ goto release_sb;
}
v9fs_stat2inode_dotl(st, root->d_inode);
@@ -162,7 +165,7 @@
st = p9_client_stat(fid);
if (IS_ERR(st)) {
retval = PTR_ERR(st);
- goto clunk_fid;
+ goto release_sb;
}
root->d_inode->i_ino = v9fs_qid2ino(&st->qid);
@@ -174,19 +177,24 @@
v9fs_fid_add(root, fid);
-P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n");
+ P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n");
simple_set_mnt(mnt, sb);
return 0;
clunk_fid:
p9_client_clunk(fid);
-
close_session:
v9fs_session_close(v9ses);
kfree(v9ses);
return retval;
-
release_sb:
+ /*
+ * we will do the session_close and root dentry release
+ * in the below call. But we need to clunk fid, because we haven't
+ * attached the fid to dentry so it won't get clunked
+ * automatically.
+ */
+ p9_client_clunk(fid);
deactivate_locked_super(sb);
return retval;
}
diff --git a/fs/aio.c b/fs/aio.c
index 3006b5b..250b0a7 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -712,8 +712,16 @@
*/
ret = retry(iocb);
- if (ret != -EIOCBRETRY && ret != -EIOCBQUEUED)
+ if (ret != -EIOCBRETRY && ret != -EIOCBQUEUED) {
+ /*
+ * There's no easy way to restart the syscall since other AIO's
+ * may be already running. Just fail this IO with EINTR.
+ */
+ if (unlikely(ret == -ERESTARTSYS || ret == -ERESTARTNOINTR ||
+ ret == -ERESTARTNOHAND || ret == -ERESTART_RESTARTBLOCK))
+ ret = -EINTR;
aio_complete(iocb, ret, 0);
+ }
out:
spin_lock_irq(&ctx->ctx_lock);
@@ -1659,6 +1667,9 @@
if (unlikely(nr < 0))
return -EINVAL;
+ if (unlikely(nr > LONG_MAX/sizeof(*iocbpp)))
+ nr = LONG_MAX/sizeof(*iocbpp);
+
if (unlikely(!access_ok(VERIFY_READ, iocbpp, (nr*sizeof(*iocbpp)))))
return -EFAULT;
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index f96eff0..a6395bd 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -134,10 +134,6 @@
if (!dump_write(file, dump_start, dump_size))
goto end_coredump;
}
-/* Finally dump the task struct. Not be used by gdb, but could be useful */
- set_fs(KERNEL_DS);
- if (!dump_write(file, current, sizeof(*current)))
- goto end_coredump;
end_coredump:
set_fs(fs);
return has_dumped;
diff --git a/fs/ceph/Kconfig b/fs/ceph/Kconfig
index bc87b9c..0fcd264 100644
--- a/fs/ceph/Kconfig
+++ b/fs/ceph/Kconfig
@@ -3,6 +3,7 @@
depends on INET && EXPERIMENTAL
select LIBCRC32C
select CRYPTO_AES
+ select CRYPTO
help
Choose Y or M here to include support for mounting the
experimental Ceph distributed file system. Ceph is an extremely
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index 4cfce1e..efbc604 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -411,8 +411,8 @@
if (i_size < page_off + len)
len = i_size - page_off;
- dout("writepage %p page %p index %lu on %llu~%u\n",
- inode, page, page->index, page_off, len);
+ dout("writepage %p page %p index %lu on %llu~%u snapc %p\n",
+ inode, page, page->index, page_off, len, snapc);
writeback_stat = atomic_long_inc_return(&client->writeback_count);
if (writeback_stat >
@@ -766,7 +766,8 @@
/* ok */
if (locked_pages == 0) {
/* prepare async write request */
- offset = page->index << PAGE_CACHE_SHIFT;
+ offset = (unsigned long long)page->index
+ << PAGE_CACHE_SHIFT;
len = wsize;
req = ceph_osdc_new_request(&client->osdc,
&ci->i_layout,
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
index a2069b6..5e9da99 100644
--- a/fs/ceph/caps.c
+++ b/fs/ceph/caps.c
@@ -814,7 +814,7 @@
used |= CEPH_CAP_PIN;
if (ci->i_rd_ref)
used |= CEPH_CAP_FILE_RD;
- if (ci->i_rdcache_ref || ci->i_rdcache_gen)
+ if (ci->i_rdcache_ref || ci->vfs_inode.i_data.nrpages)
used |= CEPH_CAP_FILE_CACHE;
if (ci->i_wr_ref)
used |= CEPH_CAP_FILE_WR;
@@ -1195,10 +1195,14 @@
* asynchronously back to the MDS once sync writes complete and dirty
* data is written out.
*
+ * Unless @again is true, skip cap_snaps that were already sent to
+ * the MDS (i.e., during this session).
+ *
* Called under i_lock. Takes s_mutex as needed.
*/
void __ceph_flush_snaps(struct ceph_inode_info *ci,
- struct ceph_mds_session **psession)
+ struct ceph_mds_session **psession,
+ int again)
__releases(ci->vfs_inode->i_lock)
__acquires(ci->vfs_inode->i_lock)
{
@@ -1227,7 +1231,7 @@
* pages to be written out.
*/
if (capsnap->dirty_pages || capsnap->writing)
- continue;
+ break;
/*
* if cap writeback already occurred, we should have dropped
@@ -1240,6 +1244,13 @@
dout("no auth cap (migrating?), doing nothing\n");
goto out;
}
+
+ /* only flush each capsnap once */
+ if (!again && !list_empty(&capsnap->flushing_item)) {
+ dout("already flushed %p, skipping\n", capsnap);
+ continue;
+ }
+
mds = ci->i_auth_cap->session->s_mds;
mseq = ci->i_auth_cap->mseq;
@@ -1276,8 +1287,8 @@
&session->s_cap_snaps_flushing);
spin_unlock(&inode->i_lock);
- dout("flush_snaps %p cap_snap %p follows %lld size %llu\n",
- inode, capsnap, next_follows, capsnap->size);
+ dout("flush_snaps %p cap_snap %p follows %lld tid %llu\n",
+ inode, capsnap, capsnap->follows, capsnap->flush_tid);
send_cap_msg(session, ceph_vino(inode).ino, 0,
CEPH_CAP_OP_FLUSHSNAP, capsnap->issued, 0,
capsnap->dirty, 0, capsnap->flush_tid, 0, mseq,
@@ -1314,7 +1325,7 @@
struct inode *inode = &ci->vfs_inode;
spin_lock(&inode->i_lock);
- __ceph_flush_snaps(ci, NULL);
+ __ceph_flush_snaps(ci, NULL, 0);
spin_unlock(&inode->i_lock);
}
@@ -1477,7 +1488,7 @@
/* flush snaps first time around only */
if (!list_empty(&ci->i_cap_snaps))
- __ceph_flush_snaps(ci, &session);
+ __ceph_flush_snaps(ci, &session, 0);
goto retry_locked;
retry:
spin_lock(&inode->i_lock);
@@ -1894,7 +1905,7 @@
if (cap && cap->session == session) {
dout("kick_flushing_caps %p cap %p capsnap %p\n", inode,
cap, capsnap);
- __ceph_flush_snaps(ci, &session);
+ __ceph_flush_snaps(ci, &session, 1);
} else {
pr_err("%p auth cap %p not mds%d ???\n", inode,
cap, session->s_mds);
@@ -2272,7 +2283,8 @@
{
struct ceph_inode_info *ci = ceph_inode(inode);
int mds = session->s_mds;
- int seq = le32_to_cpu(grant->seq);
+ unsigned seq = le32_to_cpu(grant->seq);
+ unsigned issue_seq = le32_to_cpu(grant->issue_seq);
int newcaps = le32_to_cpu(grant->caps);
int issued, implemented, used, wanted, dirty;
u64 size = le64_to_cpu(grant->size);
@@ -2284,8 +2296,8 @@
int revoked_rdcache = 0;
int queue_invalidate = 0;
- dout("handle_cap_grant inode %p cap %p mds%d seq %d %s\n",
- inode, cap, mds, seq, ceph_cap_string(newcaps));
+ dout("handle_cap_grant inode %p cap %p mds%d seq %u/%u %s\n",
+ inode, cap, mds, seq, issue_seq, ceph_cap_string(newcaps));
dout(" size %llu max_size %llu, i_size %llu\n", size, max_size,
inode->i_size);
@@ -2381,6 +2393,7 @@
}
cap->seq = seq;
+ cap->issue_seq = issue_seq;
/* file layout may have changed */
ci->i_layout = grant->layout;
@@ -2763,15 +2776,7 @@
if (op == CEPH_CAP_OP_IMPORT)
__queue_cap_release(session, vino.ino, cap_id,
mseq, seq);
-
- /*
- * send any full release message to try to move things
- * along for the mds (who clearly thinks we still have this
- * cap).
- */
- ceph_add_cap_releases(mdsc, session);
- ceph_send_cap_releases(mdsc, session);
- goto done;
+ goto flush_cap_releases;
}
/* these will work even if we don't have a cap yet */
@@ -2799,7 +2804,7 @@
dout(" no cap on %p ino %llx.%llx from mds%d\n",
inode, ceph_ino(inode), ceph_snap(inode), mds);
spin_unlock(&inode->i_lock);
- goto done;
+ goto flush_cap_releases;
}
/* note that each of these drops i_lock for us */
@@ -2823,6 +2828,17 @@
ceph_cap_op_name(op));
}
+ goto done;
+
+flush_cap_releases:
+ /*
+ * send any full release message to try to move things
+ * along for the mds (who clearly thinks we still have this
+ * cap).
+ */
+ ceph_add_cap_releases(mdsc, session);
+ ceph_send_cap_releases(mdsc, session);
+
done:
mutex_unlock(&session->s_mutex);
done_unlocked:
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index 6e4f43f..a1986eb 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -1021,11 +1021,15 @@
static void ceph_dentry_release(struct dentry *dentry)
{
struct ceph_dentry_info *di = ceph_dentry(dentry);
- struct inode *parent_inode = dentry->d_parent->d_inode;
- u64 snapid = ceph_snap(parent_inode);
+ struct inode *parent_inode = NULL;
+ u64 snapid = CEPH_NOSNAP;
+ if (!IS_ROOT(dentry)) {
+ parent_inode = dentry->d_parent->d_inode;
+ if (parent_inode)
+ snapid = ceph_snap(parent_inode);
+ }
dout("dentry_release %p parent %p\n", dentry, parent_inode);
-
if (parent_inode && snapid != CEPH_SNAPDIR) {
struct ceph_inode_info *ci = ceph_inode(parent_inode);
diff --git a/fs/ceph/export.c b/fs/ceph/export.c
index 4480cb1..e38423e 100644
--- a/fs/ceph/export.c
+++ b/fs/ceph/export.c
@@ -42,32 +42,37 @@
static int ceph_encode_fh(struct dentry *dentry, u32 *rawfh, int *max_len,
int connectable)
{
+ int type;
struct ceph_nfs_fh *fh = (void *)rawfh;
struct ceph_nfs_confh *cfh = (void *)rawfh;
struct dentry *parent = dentry->d_parent;
struct inode *inode = dentry->d_inode;
- int type;
+ int connected_handle_length = sizeof(*cfh)/4;
+ int handle_length = sizeof(*fh)/4;
/* don't re-export snaps */
if (ceph_snap(inode) != CEPH_NOSNAP)
return -EINVAL;
- if (*max_len >= sizeof(*cfh)) {
+ if (*max_len >= connected_handle_length) {
dout("encode_fh %p connectable\n", dentry);
cfh->ino = ceph_ino(dentry->d_inode);
cfh->parent_ino = ceph_ino(parent->d_inode);
cfh->parent_name_hash = parent->d_name.hash;
- *max_len = sizeof(*cfh);
+ *max_len = connected_handle_length;
type = 2;
- } else if (*max_len > sizeof(*fh)) {
- if (connectable)
- return -ENOSPC;
+ } else if (*max_len >= handle_length) {
+ if (connectable) {
+ *max_len = connected_handle_length;
+ return 255;
+ }
dout("encode_fh %p\n", dentry);
fh->ino = ceph_ino(dentry->d_inode);
- *max_len = sizeof(*fh);
+ *max_len = handle_length;
type = 1;
} else {
- return -ENOSPC;
+ *max_len = handle_length;
+ return 255;
}
return type;
}
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index 8c044a4..66e4da6 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -697,7 +697,7 @@
* start_request so that a tid has been assigned.
*/
spin_lock(&ci->i_unsafe_lock);
- list_add(&ci->i_unsafe_writes, &req->r_unsafe_item);
+ list_add(&req->r_unsafe_item, &ci->i_unsafe_writes);
spin_unlock(&ci->i_unsafe_lock);
ceph_get_cap_refs(ci, CEPH_CAP_FILE_WR);
}
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index e7cca41..62377ec 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -845,7 +845,7 @@
* the caller) if we fail.
*/
static struct dentry *splice_dentry(struct dentry *dn, struct inode *in,
- bool *prehash)
+ bool *prehash, bool set_offset)
{
struct dentry *realdn;
@@ -877,7 +877,8 @@
}
if ((!prehash || *prehash) && d_unhashed(dn))
d_rehash(dn);
- ceph_set_dentry_offset(dn);
+ if (set_offset)
+ ceph_set_dentry_offset(dn);
out:
return dn;
}
@@ -1062,7 +1063,7 @@
d_delete(dn);
goto done;
}
- dn = splice_dentry(dn, in, &have_lease);
+ dn = splice_dentry(dn, in, &have_lease, true);
if (IS_ERR(dn)) {
err = PTR_ERR(dn);
goto done;
@@ -1105,7 +1106,7 @@
goto done;
}
dout(" linking snapped dir %p to dn %p\n", in, dn);
- dn = splice_dentry(dn, in, NULL);
+ dn = splice_dentry(dn, in, NULL, true);
if (IS_ERR(dn)) {
err = PTR_ERR(dn);
goto done;
@@ -1237,7 +1238,7 @@
err = PTR_ERR(in);
goto out;
}
- dn = splice_dentry(dn, in, NULL);
+ dn = splice_dentry(dn, in, NULL, false);
if (IS_ERR(dn))
dn = NULL;
}
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index f091b13..fad95f8 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -2374,6 +2374,8 @@
num_fcntl_locks,
num_flock_locks);
unlock_kernel();
+ } else {
+ err = ceph_pagelist_append(pagelist, &rec, reclen);
}
out_free:
diff --git a/fs/ceph/osd_client.c b/fs/ceph/osd_client.c
index dfced1d..3b5571b 100644
--- a/fs/ceph/osd_client.c
+++ b/fs/ceph/osd_client.c
@@ -549,7 +549,7 @@
*/
static void __cancel_request(struct ceph_osd_request *req)
{
- if (req->r_sent) {
+ if (req->r_sent && req->r_osd) {
ceph_con_revoke(&req->r_osd->o_con, req->r_request);
req->r_sent = 0;
}
diff --git a/fs/ceph/pagelist.c b/fs/ceph/pagelist.c
index b6859f4..46a368b 100644
--- a/fs/ceph/pagelist.c
+++ b/fs/ceph/pagelist.c
@@ -5,10 +5,18 @@
#include "pagelist.h"
+static void ceph_pagelist_unmap_tail(struct ceph_pagelist *pl)
+{
+ struct page *page = list_entry(pl->head.prev, struct page,
+ lru);
+ kunmap(page);
+}
+
int ceph_pagelist_release(struct ceph_pagelist *pl)
{
if (pl->mapped_tail)
- kunmap(pl->mapped_tail);
+ ceph_pagelist_unmap_tail(pl);
+
while (!list_empty(&pl->head)) {
struct page *page = list_first_entry(&pl->head, struct page,
lru);
@@ -26,7 +34,7 @@
pl->room += PAGE_SIZE;
list_add_tail(&page->lru, &pl->head);
if (pl->mapped_tail)
- kunmap(pl->mapped_tail);
+ ceph_pagelist_unmap_tail(pl);
pl->mapped_tail = kmap(page);
return 0;
}
diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c
index 4868b9d..190b6c4 100644
--- a/fs/ceph/snap.c
+++ b/fs/ceph/snap.c
@@ -119,6 +119,7 @@
INIT_LIST_HEAD(&realm->children);
INIT_LIST_HEAD(&realm->child_item);
INIT_LIST_HEAD(&realm->empty_item);
+ INIT_LIST_HEAD(&realm->dirty_item);
INIT_LIST_HEAD(&realm->inodes_with_caps);
spin_lock_init(&realm->inodes_with_caps_lock);
__insert_snap_realm(&mdsc->snap_realms, realm);
@@ -467,7 +468,7 @@
INIT_LIST_HEAD(&capsnap->ci_item);
INIT_LIST_HEAD(&capsnap->flushing_item);
- capsnap->follows = snapc->seq - 1;
+ capsnap->follows = snapc->seq;
capsnap->issued = __ceph_caps_issued(ci, NULL);
capsnap->dirty = dirty;
@@ -604,6 +605,7 @@
struct ceph_snap_realm *realm;
int invalidate = 0;
int err = -ENOMEM;
+ LIST_HEAD(dirty_realms);
dout("update_snap_trace deletion=%d\n", deletion);
more:
@@ -626,24 +628,6 @@
}
}
- if (le64_to_cpu(ri->seq) > realm->seq) {
- dout("update_snap_trace updating %llx %p %lld -> %lld\n",
- realm->ino, realm, realm->seq, le64_to_cpu(ri->seq));
- /*
- * if the realm seq has changed, queue a cap_snap for every
- * inode with open caps. we do this _before_ we update
- * the realm info so that we prepare for writeback under the
- * _previous_ snap context.
- *
- * ...unless it's a snap deletion!
- */
- if (!deletion)
- queue_realm_cap_snaps(realm);
- } else {
- dout("update_snap_trace %llx %p seq %lld unchanged\n",
- realm->ino, realm, realm->seq);
- }
-
/* ensure the parent is correct */
err = adjust_snap_realm_parent(mdsc, realm, le64_to_cpu(ri->parent));
if (err < 0)
@@ -651,6 +635,8 @@
invalidate += err;
if (le64_to_cpu(ri->seq) > realm->seq) {
+ dout("update_snap_trace updating %llx %p %lld -> %lld\n",
+ realm->ino, realm, realm->seq, le64_to_cpu(ri->seq));
/* update realm parameters, snap lists */
realm->seq = le64_to_cpu(ri->seq);
realm->created = le64_to_cpu(ri->created);
@@ -668,9 +654,17 @@
if (err < 0)
goto fail;
+ /* queue realm for cap_snap creation */
+ list_add(&realm->dirty_item, &dirty_realms);
+
invalidate = 1;
} else if (!realm->cached_context) {
+ dout("update_snap_trace %llx %p seq %lld new\n",
+ realm->ino, realm, realm->seq);
invalidate = 1;
+ } else {
+ dout("update_snap_trace %llx %p seq %lld unchanged\n",
+ realm->ino, realm, realm->seq);
}
dout("done with %llx %p, invalidated=%d, %p %p\n", realm->ino,
@@ -683,6 +677,14 @@
if (invalidate)
rebuild_snap_realms(realm);
+ /*
+ * queue cap snaps _after_ we've built the new snap contexts,
+ * so that i_head_snapc can be set appropriately.
+ */
+ list_for_each_entry(realm, &dirty_realms, dirty_item) {
+ queue_realm_cap_snaps(realm);
+ }
+
__cleanup_empty_realms(mdsc);
return 0;
@@ -715,7 +717,7 @@
igrab(inode);
spin_unlock(&mdsc->snap_flush_lock);
spin_lock(&inode->i_lock);
- __ceph_flush_snaps(ci, &session);
+ __ceph_flush_snaps(ci, &session, 0);
spin_unlock(&inode->i_lock);
iput(inode);
spin_lock(&mdsc->snap_flush_lock);
@@ -816,6 +818,7 @@
};
struct inode *inode = ceph_find_inode(sb, vino);
struct ceph_inode_info *ci;
+ struct ceph_snap_realm *oldrealm;
if (!inode)
continue;
@@ -841,18 +844,19 @@
dout(" will move %p to split realm %llx %p\n",
inode, realm->ino, realm);
/*
- * Remove the inode from the realm's inode
- * list, but don't add it to the new realm
- * yet. We don't want the cap_snap to be
- * queued (again) by ceph_update_snap_trace()
- * below. Queue it _now_, under the old context.
+ * Move the inode to the new realm
*/
spin_lock(&realm->inodes_with_caps_lock);
list_del_init(&ci->i_snap_realm_item);
+ list_add(&ci->i_snap_realm_item,
+ &realm->inodes_with_caps);
+ oldrealm = ci->i_snap_realm;
+ ci->i_snap_realm = realm;
spin_unlock(&realm->inodes_with_caps_lock);
spin_unlock(&inode->i_lock);
- ceph_queue_cap_snap(ci);
+ ceph_get_snap_realm(mdsc, realm);
+ ceph_put_snap_realm(mdsc, oldrealm);
iput(inode);
continue;
@@ -880,43 +884,9 @@
ceph_update_snap_trace(mdsc, p, e,
op == CEPH_SNAP_OP_DESTROY);
- if (op == CEPH_SNAP_OP_SPLIT) {
- /*
- * ok, _now_ add the inodes into the new realm.
- */
- for (i = 0; i < num_split_inos; i++) {
- struct ceph_vino vino = {
- .ino = le64_to_cpu(split_inos[i]),
- .snap = CEPH_NOSNAP,
- };
- struct inode *inode = ceph_find_inode(sb, vino);
- struct ceph_inode_info *ci;
-
- if (!inode)
- continue;
- ci = ceph_inode(inode);
- spin_lock(&inode->i_lock);
- if (list_empty(&ci->i_snap_realm_item)) {
- struct ceph_snap_realm *oldrealm =
- ci->i_snap_realm;
-
- dout(" moving %p to split realm %llx %p\n",
- inode, realm->ino, realm);
- spin_lock(&realm->inodes_with_caps_lock);
- list_add(&ci->i_snap_realm_item,
- &realm->inodes_with_caps);
- ci->i_snap_realm = realm;
- spin_unlock(&realm->inodes_with_caps_lock);
- ceph_get_snap_realm(mdsc, realm);
- ceph_put_snap_realm(mdsc, oldrealm);
- }
- spin_unlock(&inode->i_lock);
- iput(inode);
- }
-
+ if (op == CEPH_SNAP_OP_SPLIT)
/* we took a reference when we created the realm, above */
ceph_put_snap_realm(mdsc, realm);
- }
__cleanup_empty_realms(mdsc);
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index c33897a..b87638e 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -690,6 +690,8 @@
struct list_head empty_item; /* if i have ref==0 */
+ struct list_head dirty_item; /* if realm needs new context */
+
/* the current set of snaps for this realm */
struct ceph_snap_context *cached_context;
@@ -826,7 +828,8 @@
extern void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr,
struct ceph_snap_context *snapc);
extern void __ceph_flush_snaps(struct ceph_inode_info *ci,
- struct ceph_mds_session **psession);
+ struct ceph_mds_session **psession,
+ int again);
extern void ceph_check_caps(struct ceph_inode_info *ci, int flags,
struct ceph_mds_session *session);
extern void ceph_check_delayed_caps(struct ceph_mds_client *mdsc);
diff --git a/fs/char_dev.c b/fs/char_dev.c
index f80a4f2..143d393 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -40,7 +40,9 @@
#endif
/* permit direct mmap, for read, write or exec */
BDI_CAP_MAP_DIRECT |
- BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP),
+ BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP |
+ /* no writeback happens */
+ BDI_CAP_NO_ACCT_AND_WRITEBACK),
};
static struct kobj_map *cdev_map;
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig
index 0da1deb..917b7d4 100644
--- a/fs/cifs/Kconfig
+++ b/fs/cifs/Kconfig
@@ -2,8 +2,6 @@
tristate "CIFS support (advanced network filesystem, SMBFS successor)"
depends on INET
select NLS
- select CRYPTO_MD5
- select CRYPTO_ARC4
help
This is the client VFS module for the Common Internet File System
(CIFS) protocol which is the successor to the Server Message Block
diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c
index 21f0fbd..cfd1ce3 100644
--- a/fs/cifs/asn1.c
+++ b/fs/cifs/asn1.c
@@ -597,13 +597,13 @@
if (compare_oid(oid, oidlen, MSKRB5_OID,
MSKRB5_OID_LEN))
server->sec_mskerberos = true;
- if (compare_oid(oid, oidlen, KRB5U2U_OID,
+ else if (compare_oid(oid, oidlen, KRB5U2U_OID,
KRB5U2U_OID_LEN))
server->sec_kerberosu2u = true;
- if (compare_oid(oid, oidlen, KRB5_OID,
+ else if (compare_oid(oid, oidlen, KRB5_OID,
KRB5_OID_LEN))
server->sec_kerberos = true;
- if (compare_oid(oid, oidlen, NTLMSSP_OID,
+ else if (compare_oid(oid, oidlen, NTLMSSP_OID,
NTLMSSP_OID_LEN))
server->sec_ntlmssp = true;
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 709f229..35042d8 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -27,7 +27,6 @@
#include "md5.h"
#include "cifs_unicode.h"
#include "cifsproto.h"
-#include "ntlmssp.h"
#include <linux/ctype.h>
#include <linux/random.h>
@@ -43,43 +42,21 @@
unsigned char *p24);
static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu,
- struct TCP_Server_Info *server, char *signature)
+ const struct mac_key *key, char *signature)
{
- int rc;
+ struct MD5Context context;
- if (cifs_pdu == NULL || server == NULL || signature == NULL)
+ if ((cifs_pdu == NULL) || (signature == NULL) || (key == NULL))
return -EINVAL;
- if (!server->ntlmssp.sdescmd5) {
- cERROR(1,
- "cifs_calculate_signature: can't generate signature\n");
- return -1;
- }
+ cifs_MD5_init(&context);
+ cifs_MD5_update(&context, (char *)&key->data, key->len);
+ cifs_MD5_update(&context, cifs_pdu->Protocol, cifs_pdu->smb_buf_length);
- rc = crypto_shash_init(&server->ntlmssp.sdescmd5->shash);
- if (rc) {
- cERROR(1, "cifs_calculate_signature: oould not init md5\n");
- return rc;
- }
-
- if (server->secType == RawNTLMSSP)
- crypto_shash_update(&server->ntlmssp.sdescmd5->shash,
- server->session_key.data.ntlmv2.key,
- CIFS_NTLMV2_SESSKEY_SIZE);
- else
- crypto_shash_update(&server->ntlmssp.sdescmd5->shash,
- (char *)&server->session_key.data,
- server->session_key.len);
-
- crypto_shash_update(&server->ntlmssp.sdescmd5->shash,
- cifs_pdu->Protocol, cifs_pdu->smb_buf_length);
-
- rc = crypto_shash_final(&server->ntlmssp.sdescmd5->shash, signature);
-
- return rc;
+ cifs_MD5_final(signature, &context);
+ return 0;
}
-
int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
__u32 *pexpected_response_sequence_number)
{
@@ -101,7 +78,8 @@
server->sequence_number++;
spin_unlock(&GlobalMid_Lock);
- rc = cifs_calculate_signature(cifs_pdu, server, smb_signature);
+ rc = cifs_calculate_signature(cifs_pdu, &server->mac_signing_key,
+ smb_signature);
if (rc)
memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
else
@@ -111,39 +89,21 @@
}
static int cifs_calc_signature2(const struct kvec *iov, int n_vec,
- struct TCP_Server_Info *server, char *signature)
+ const struct mac_key *key, char *signature)
{
+ struct MD5Context context;
int i;
- int rc;
- if (iov == NULL || server == NULL || signature == NULL)
+ if ((iov == NULL) || (signature == NULL) || (key == NULL))
return -EINVAL;
- if (!server->ntlmssp.sdescmd5) {
- cERROR(1, "cifs_calc_signature2: can't generate signature\n");
- return -1;
- }
-
- rc = crypto_shash_init(&server->ntlmssp.sdescmd5->shash);
- if (rc) {
- cERROR(1, "cifs_calc_signature2: oould not init md5\n");
- return rc;
- }
-
- if (server->secType == RawNTLMSSP)
- crypto_shash_update(&server->ntlmssp.sdescmd5->shash,
- server->session_key.data.ntlmv2.key,
- CIFS_NTLMV2_SESSKEY_SIZE);
- else
- crypto_shash_update(&server->ntlmssp.sdescmd5->shash,
- (char *)&server->session_key.data,
- server->session_key.len);
-
+ cifs_MD5_init(&context);
+ cifs_MD5_update(&context, (char *)&key->data, key->len);
for (i = 0; i < n_vec; i++) {
if (iov[i].iov_len == 0)
continue;
if (iov[i].iov_base == NULL) {
- cERROR(1, "cifs_calc_signature2: null iovec entry");
+ cERROR(1, "null iovec entry");
return -EIO;
}
/* The first entry includes a length field (which does not get
@@ -151,18 +111,18 @@
if (i == 0) {
if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
break; /* nothing to sign or corrupt header */
- crypto_shash_update(&server->ntlmssp.sdescmd5->shash,
- iov[i].iov_base + 4, iov[i].iov_len - 4);
+ cifs_MD5_update(&context, iov[0].iov_base+4,
+ iov[0].iov_len-4);
} else
- crypto_shash_update(&server->ntlmssp.sdescmd5->shash,
- iov[i].iov_base, iov[i].iov_len);
+ cifs_MD5_update(&context, iov[i].iov_base, iov[i].iov_len);
}
- rc = crypto_shash_final(&server->ntlmssp.sdescmd5->shash, signature);
+ cifs_MD5_final(signature, &context);
- return rc;
+ return 0;
}
+
int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
__u32 *pexpected_response_sequence_number)
{
@@ -185,7 +145,8 @@
server->sequence_number++;
spin_unlock(&GlobalMid_Lock);
- rc = cifs_calc_signature2(iov, n_vec, server, smb_signature);
+ rc = cifs_calc_signature2(iov, n_vec, &server->mac_signing_key,
+ smb_signature);
if (rc)
memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
else
@@ -195,14 +156,14 @@
}
int cifs_verify_signature(struct smb_hdr *cifs_pdu,
- struct TCP_Server_Info *server,
+ const struct mac_key *mac_key,
__u32 expected_sequence_number)
{
- int rc;
+ unsigned int rc;
char server_response_sig[8];
char what_we_think_sig_should_be[20];
- if (cifs_pdu == NULL || server == NULL)
+ if ((cifs_pdu == NULL) || (mac_key == NULL))
return -EINVAL;
if (cifs_pdu->Command == SMB_COM_NEGOTIATE)
@@ -231,7 +192,7 @@
cpu_to_le32(expected_sequence_number);
cifs_pdu->Signature.Sequence.Reserved = 0;
- rc = cifs_calculate_signature(cifs_pdu, server,
+ rc = cifs_calculate_signature(cifs_pdu, mac_key,
what_we_think_sig_should_be);
if (rc)
@@ -248,7 +209,7 @@
}
/* We fill in key by putting in 40 byte array which was allocated by caller */
-int cifs_calculate_session_key(struct session_key *key, const char *rn,
+int cifs_calculate_mac_key(struct mac_key *key, const char *rn,
const char *password)
{
char temp_key[16];
@@ -306,52 +267,38 @@
{
int rc = 0;
int len;
- char nt_hash[CIFS_NTHASH_SIZE];
+ char nt_hash[16];
+ struct HMACMD5Context *pctxt;
wchar_t *user;
wchar_t *domain;
- wchar_t *server;
- if (!ses->server->ntlmssp.sdeschmacmd5) {
- cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n");
- return -1;
- }
+ pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL);
+
+ if (pctxt == NULL)
+ return -ENOMEM;
/* calculate md4 hash of password */
E_md4hash(ses->password, nt_hash);
- crypto_shash_setkey(ses->server->ntlmssp.hmacmd5, nt_hash,
- CIFS_NTHASH_SIZE);
-
- rc = crypto_shash_init(&ses->server->ntlmssp.sdeschmacmd5->shash);
- if (rc) {
- cERROR(1, "calc_ntlmv2_hash: could not init hmacmd5\n");
- return rc;
- }
+ /* convert Domainname to unicode and uppercase */
+ hmac_md5_init_limK_to_64(nt_hash, 16, pctxt);
/* convert ses->userName to unicode and uppercase */
len = strlen(ses->userName);
user = kmalloc(2 + (len * 2), GFP_KERNEL);
- if (user == NULL) {
- cERROR(1, "calc_ntlmv2_hash: user mem alloc failure\n");
- rc = -ENOMEM;
+ if (user == NULL)
goto calc_exit_2;
- }
len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp);
UniStrupr(user);
-
- crypto_shash_update(&ses->server->ntlmssp.sdeschmacmd5->shash,
- (char *)user, 2 * len);
+ hmac_md5_update((char *)user, 2*len, pctxt);
/* convert ses->domainName to unicode and uppercase */
if (ses->domainName) {
len = strlen(ses->domainName);
domain = kmalloc(2 + (len * 2), GFP_KERNEL);
- if (domain == NULL) {
- cERROR(1, "calc_ntlmv2_hash: domain mem alloc failure");
- rc = -ENOMEM;
+ if (domain == NULL)
goto calc_exit_1;
- }
len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len,
nls_cp);
/* the following line was removed since it didn't work well
@@ -359,292 +306,65 @@
Maybe converting the domain name earlier makes sense */
/* UniStrupr(domain); */
- crypto_shash_update(&ses->server->ntlmssp.sdeschmacmd5->shash,
- (char *)domain, 2 * len);
+ hmac_md5_update((char *)domain, 2*len, pctxt);
kfree(domain);
- } else if (ses->serverName) {
- len = strlen(ses->serverName);
-
- server = kmalloc(2 + (len * 2), GFP_KERNEL);
- if (server == NULL) {
- cERROR(1, "calc_ntlmv2_hash: server mem alloc failure");
- rc = -ENOMEM;
- goto calc_exit_1;
- }
- len = cifs_strtoUCS((__le16 *)server, ses->serverName, len,
- nls_cp);
- /* the following line was removed since it didn't work well
- with lower cased domain name that passed as an option.
- Maybe converting the domain name earlier makes sense */
- /* UniStrupr(domain); */
-
- crypto_shash_update(&ses->server->ntlmssp.sdeschmacmd5->shash,
- (char *)server, 2 * len);
-
- kfree(server);
}
-
- rc = crypto_shash_final(&ses->server->ntlmssp.sdeschmacmd5->shash,
- ses->server->ntlmv2_hash);
-
calc_exit_1:
kfree(user);
calc_exit_2:
/* BB FIXME what about bytes 24 through 40 of the signing key?
compare with the NTLM example */
+ hmac_md5_final(ses->server->ntlmv2_hash, pctxt);
+ kfree(pctxt);
return rc;
}
-static int
-find_domain_name(struct cifsSesInfo *ses)
-{
- int rc = 0;
- unsigned int attrsize;
- unsigned int type;
- unsigned char *blobptr;
- struct ntlmssp2_name *attrptr;
-
- if (ses->server->tiblob) {
- blobptr = ses->server->tiblob;
- attrptr = (struct ntlmssp2_name *) blobptr;
-
- while ((type = attrptr->type) != 0) {
- blobptr += 2; /* advance attr type */
- attrsize = attrptr->length;
- blobptr += 2; /* advance attr size */
- if (type == NTLMSSP_AV_NB_DOMAIN_NAME) {
- if (!ses->domainName) {
- ses->domainName =
- kmalloc(attrptr->length + 1,
- GFP_KERNEL);
- if (!ses->domainName)
- return -ENOMEM;
- cifs_from_ucs2(ses->domainName,
- (__le16 *)blobptr,
- attrptr->length,
- attrptr->length,
- load_nls_default(), false);
- }
- }
- blobptr += attrsize; /* advance attr value */
- attrptr = (struct ntlmssp2_name *) blobptr;
- }
- } else {
- ses->server->tilen = 2 * sizeof(struct ntlmssp2_name);
- ses->server->tiblob = kmalloc(ses->server->tilen, GFP_KERNEL);
- if (!ses->server->tiblob) {
- ses->server->tilen = 0;
- cERROR(1, "Challenge target info allocation failure");
- return -ENOMEM;
- }
- memset(ses->server->tiblob, 0x0, ses->server->tilen);
- attrptr = (struct ntlmssp2_name *) ses->server->tiblob;
- attrptr->type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE);
- }
-
- return rc;
-}
-
-static int
-CalcNTLMv2_response(const struct TCP_Server_Info *server,
- char *v2_session_response)
-{
- int rc;
-
- if (!server->ntlmssp.sdeschmacmd5) {
- cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n");
- return -1;
- }
-
- crypto_shash_setkey(server->ntlmssp.hmacmd5, server->ntlmv2_hash,
- CIFS_HMAC_MD5_HASH_SIZE);
-
- rc = crypto_shash_init(&server->ntlmssp.sdeschmacmd5->shash);
- if (rc) {
- cERROR(1, "CalcNTLMv2_response: could not init hmacmd5");
- return rc;
- }
-
- memcpy(v2_session_response + CIFS_SERVER_CHALLENGE_SIZE,
- server->cryptKey, CIFS_SERVER_CHALLENGE_SIZE);
- crypto_shash_update(&server->ntlmssp.sdeschmacmd5->shash,
- v2_session_response + CIFS_SERVER_CHALLENGE_SIZE,
- sizeof(struct ntlmv2_resp) - CIFS_SERVER_CHALLENGE_SIZE);
-
- if (server->tilen)
- crypto_shash_update(&server->ntlmssp.sdeschmacmd5->shash,
- server->tiblob, server->tilen);
-
- rc = crypto_shash_final(&server->ntlmssp.sdeschmacmd5->shash,
- v2_session_response);
-
- return rc;
-}
-
-int
-setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
+void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
const struct nls_table *nls_cp)
{
- int rc = 0;
+ int rc;
struct ntlmv2_resp *buf = (struct ntlmv2_resp *)resp_buf;
+ struct HMACMD5Context context;
buf->blob_signature = cpu_to_le32(0x00000101);
buf->reserved = 0;
buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
get_random_bytes(&buf->client_chal, sizeof(buf->client_chal));
buf->reserved2 = 0;
-
- if (!ses->domainName) {
- rc = find_domain_name(ses);
- if (rc) {
- cERROR(1, "could not get domain/server name rc %d", rc);
- return rc;
- }
- }
+ buf->names[0].type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE);
+ buf->names[0].length = 0;
+ buf->names[1].type = 0;
+ buf->names[1].length = 0;
/* calculate buf->ntlmv2_hash */
rc = calc_ntlmv2_hash(ses, nls_cp);
- if (rc) {
+ if (rc)
cERROR(1, "could not get v2 hash rc %d", rc);
- return rc;
- }
- rc = CalcNTLMv2_response(ses->server, resp_buf);
- if (rc) {
- cERROR(1, "could not get v2 hash rc %d", rc);
- return rc;
- }
+ CalcNTLMv2_response(ses, resp_buf);
- if (!ses->server->ntlmssp.sdeschmacmd5) {
- cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n");
- return -1;
- }
+ /* now calculate the MAC key for NTLMv2 */
+ hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context);
+ hmac_md5_update(resp_buf, 16, &context);
+ hmac_md5_final(ses->server->mac_signing_key.data.ntlmv2.key, &context);
- crypto_shash_setkey(ses->server->ntlmssp.hmacmd5,
- ses->server->ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
-
- rc = crypto_shash_init(&ses->server->ntlmssp.sdeschmacmd5->shash);
- if (rc) {
- cERROR(1, "setup_ntlmv2_rsp: could not init hmacmd5\n");
- return rc;
- }
-
- crypto_shash_update(&ses->server->ntlmssp.sdeschmacmd5->shash,
- resp_buf, CIFS_HMAC_MD5_HASH_SIZE);
-
- rc = crypto_shash_final(&ses->server->ntlmssp.sdeschmacmd5->shash,
- ses->server->session_key.data.ntlmv2.key);
-
- memcpy(&ses->server->session_key.data.ntlmv2.resp, resp_buf,
- sizeof(struct ntlmv2_resp));
- ses->server->session_key.len = 16 + sizeof(struct ntlmv2_resp);
-
- return rc;
+ memcpy(&ses->server->mac_signing_key.data.ntlmv2.resp, resp_buf,
+ sizeof(struct ntlmv2_resp));
+ ses->server->mac_signing_key.len = 16 + sizeof(struct ntlmv2_resp);
}
-int
-calc_seckey(struct TCP_Server_Info *server)
+void CalcNTLMv2_response(const struct cifsSesInfo *ses,
+ char *v2_session_response)
{
- int rc;
- unsigned char sec_key[CIFS_NTLMV2_SESSKEY_SIZE];
- struct crypto_blkcipher *tfm_arc4;
- struct scatterlist sgin, sgout;
- struct blkcipher_desc desc;
+ struct HMACMD5Context context;
+ /* rest of v2 struct already generated */
+ memcpy(v2_session_response + 8, ses->server->cryptKey, 8);
+ hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context);
- get_random_bytes(sec_key, CIFS_NTLMV2_SESSKEY_SIZE);
+ hmac_md5_update(v2_session_response+8,
+ sizeof(struct ntlmv2_resp) - 8, &context);
- tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)",
- 0, CRYPTO_ALG_ASYNC);
- if (!tfm_arc4 || IS_ERR(tfm_arc4)) {
- cERROR(1, "could not allocate " "master crypto API arc4\n");
- return 1;
- }
-
- desc.tfm = tfm_arc4;
-
- crypto_blkcipher_setkey(tfm_arc4,
- server->session_key.data.ntlmv2.key, CIFS_CPHTXT_SIZE);
- sg_init_one(&sgin, sec_key, CIFS_CPHTXT_SIZE);
- sg_init_one(&sgout, server->ntlmssp.ciphertext, CIFS_CPHTXT_SIZE);
- rc = crypto_blkcipher_encrypt(&desc, &sgout, &sgin, CIFS_CPHTXT_SIZE);
-
- if (!rc)
- memcpy(server->session_key.data.ntlmv2.key,
- sec_key, CIFS_NTLMV2_SESSKEY_SIZE);
-
- crypto_free_blkcipher(tfm_arc4);
-
- return 0;
-}
-
-void
-cifs_crypto_shash_release(struct TCP_Server_Info *server)
-{
- if (server->ntlmssp.md5)
- crypto_free_shash(server->ntlmssp.md5);
-
- if (server->ntlmssp.hmacmd5)
- crypto_free_shash(server->ntlmssp.hmacmd5);
-
- kfree(server->ntlmssp.sdeschmacmd5);
-
- kfree(server->ntlmssp.sdescmd5);
-}
-
-int
-cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
-{
- int rc;
- unsigned int size;
-
- server->ntlmssp.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
- if (!server->ntlmssp.hmacmd5 ||
- IS_ERR(server->ntlmssp.hmacmd5)) {
- cERROR(1, "could not allocate crypto hmacmd5\n");
- return 1;
- }
-
- server->ntlmssp.md5 = crypto_alloc_shash("md5", 0, 0);
- if (!server->ntlmssp.md5 || IS_ERR(server->ntlmssp.md5)) {
- cERROR(1, "could not allocate crypto md5\n");
- rc = 1;
- goto cifs_crypto_shash_allocate_ret1;
- }
-
- size = sizeof(struct shash_desc) +
- crypto_shash_descsize(server->ntlmssp.hmacmd5);
- server->ntlmssp.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
- if (!server->ntlmssp.sdeschmacmd5) {
- cERROR(1, "cifs_crypto_shash_allocate: can't alloc hmacmd5\n");
- rc = -ENOMEM;
- goto cifs_crypto_shash_allocate_ret2;
- }
- server->ntlmssp.sdeschmacmd5->shash.tfm = server->ntlmssp.hmacmd5;
- server->ntlmssp.sdeschmacmd5->shash.flags = 0x0;
-
-
- size = sizeof(struct shash_desc) +
- crypto_shash_descsize(server->ntlmssp.md5);
- server->ntlmssp.sdescmd5 = kmalloc(size, GFP_KERNEL);
- if (!server->ntlmssp.sdescmd5) {
- cERROR(1, "cifs_crypto_shash_allocate: can't alloc md5\n");
- rc = -ENOMEM;
- goto cifs_crypto_shash_allocate_ret3;
- }
- server->ntlmssp.sdescmd5->shash.tfm = server->ntlmssp.md5;
- server->ntlmssp.sdescmd5->shash.flags = 0x0;
-
- return 0;
-
-cifs_crypto_shash_allocate_ret3:
- kfree(server->ntlmssp.sdeschmacmd5);
-
-cifs_crypto_shash_allocate_ret2:
- crypto_free_shash(server->ntlmssp.md5);
-
-cifs_crypto_shash_allocate_ret1:
- crypto_free_shash(server->ntlmssp.hmacmd5);
-
- return rc;
+ hmac_md5_final(v2_session_response, &context);
+/* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */
}
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index c9d0cfc..0cdfb8c 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -25,9 +25,6 @@
#include <linux/workqueue.h>
#include "cifs_fs_sb.h"
#include "cifsacl.h"
-#include <crypto/internal/hash.h>
-#include <linux/scatterlist.h>
-
/*
* The sizes of various internal tables and strings
*/
@@ -100,7 +97,7 @@
/* Netbios frames protocol not supported at this time */
};
-struct session_key {
+struct mac_key {
unsigned int len;
union {
char ntlm[CIFS_SESS_KEY_SIZE + 16];
@@ -123,21 +120,6 @@
struct cifs_ace *aces;
};
-struct sdesc {
- struct shash_desc shash;
- char ctx[];
-};
-
-struct ntlmssp_auth {
- __u32 client_flags;
- __u32 server_flags;
- unsigned char ciphertext[CIFS_CPHTXT_SIZE];
- struct crypto_shash *hmacmd5;
- struct crypto_shash *md5;
- struct sdesc *sdeschmacmd5;
- struct sdesc *sdescmd5;
-};
-
/*
*****************************************************************
* Except the CIFS PDUs themselves all the
@@ -200,14 +182,11 @@
/* 16th byte of RFC1001 workstation name is always null */
char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
__u32 sequence_number; /* needed for CIFS PDU signature */
- struct session_key session_key;
+ struct mac_key mac_signing_key;
char ntlmv2_hash[16];
unsigned long lstrp; /* when we got last response from this server */
u16 dialect; /* dialect index that server chose */
/* extended security flavors that server supports */
- unsigned int tilen; /* length of the target info blob */
- unsigned char *tiblob; /* target info blob in challenge response */
- struct ntlmssp_auth ntlmssp; /* various keys, ciphers, flags */
bool sec_kerberos; /* supports plain Kerberos */
bool sec_mskerberos; /* supports legacy MS Kerberos */
bool sec_kerberosu2u; /* supports U2U Kerberos */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 320e0fd..14d036d 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -134,12 +134,6 @@
* Size of the session key (crypto key encrypted with the password
*/
#define CIFS_SESS_KEY_SIZE (24)
-#define CIFS_CLIENT_CHALLENGE_SIZE (8)
-#define CIFS_SERVER_CHALLENGE_SIZE (8)
-#define CIFS_HMAC_MD5_HASH_SIZE (16)
-#define CIFS_CPHTXT_SIZE (16)
-#define CIFS_NTLMV2_SESSKEY_SIZE (16)
-#define CIFS_NTHASH_SIZE (16)
/*
* Maximum user name length
@@ -669,6 +663,7 @@
__le64 time;
__u64 client_chal; /* random */
__u32 reserved2;
+ struct ntlmssp2_name names[2];
/* array of name entries could follow ending in minimum 4 byte struct */
} __attribute__((packed));
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 1378d91..1d60c65 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -87,8 +87,9 @@
extern int decode_negTokenInit(unsigned char *security_blob, int length,
struct TCP_Server_Info *server);
extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len);
+extern int cifs_set_port(struct sockaddr *addr, const unsigned short int port);
extern int cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len,
- unsigned short int port);
+ const unsigned short int port);
extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr);
extern void header_assemble(struct smb_hdr *, char /* command */ ,
const struct cifsTconInfo *, int /* length of
@@ -361,15 +362,13 @@
extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *,
__u32 *);
extern int cifs_verify_signature(struct smb_hdr *,
- struct TCP_Server_Info *server,
+ const struct mac_key *mac_key,
__u32 expected_sequence_number);
-extern int cifs_calculate_session_key(struct session_key *key, const char *rn,
+extern int cifs_calculate_mac_key(struct mac_key *key, const char *rn,
const char *pass);
-extern int setup_ntlmv2_rsp(struct cifsSesInfo *, char *,
+extern void CalcNTLMv2_response(const struct cifsSesInfo *, char *);
+extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *,
const struct nls_table *);
-extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *);
-extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
-extern int calc_seckey(struct TCP_Server_Info *);
#ifdef CONFIG_CIFS_WEAK_PW_HASH
extern void calc_lanman_hash(const char *password, const char *cryptkey,
bool encrypt, char *lnm_session_key);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 4bda920..7e83b35 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -232,7 +232,7 @@
small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
void **request_buf)
{
- int rc = 0;
+ int rc;
rc = cifs_reconnect_tcon(tcon, smb_command);
if (rc)
@@ -250,7 +250,7 @@
if (tcon != NULL)
cifs_stats_inc(&tcon->num_smbs_sent);
- return rc;
+ return 0;
}
int
@@ -281,16 +281,9 @@
/* If the return code is zero, this function must fill in request_buf pointer */
static int
-smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
- void **request_buf /* returned */ ,
- void **response_buf /* returned */ )
+__smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
+ void **request_buf, void **response_buf)
{
- int rc = 0;
-
- rc = cifs_reconnect_tcon(tcon, smb_command);
- if (rc)
- return rc;
-
*request_buf = cifs_buf_get();
if (*request_buf == NULL) {
/* BB should we add a retry in here if not a writepage? */
@@ -309,7 +302,31 @@
if (tcon != NULL)
cifs_stats_inc(&tcon->num_smbs_sent);
- return rc;
+ return 0;
+}
+
+/* If the return code is zero, this function must fill in request_buf pointer */
+static int
+smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
+ void **request_buf, void **response_buf)
+{
+ int rc;
+
+ rc = cifs_reconnect_tcon(tcon, smb_command);
+ if (rc)
+ return rc;
+
+ return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
+}
+
+static int
+smb_init_no_reconnect(int smb_command, int wct, struct cifsTconInfo *tcon,
+ void **request_buf, void **response_buf)
+{
+ if (tcon->ses->need_reconnect || tcon->need_reconnect)
+ return -EHOSTDOWN;
+
+ return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
}
static int validate_t2(struct smb_t2_rsp *pSMB)
@@ -604,14 +621,11 @@
else
rc = -EINVAL;
- if (server->secType == Kerberos) {
- if (!server->sec_kerberos &&
- !server->sec_mskerberos)
- rc = -EOPNOTSUPP;
- } else if (server->secType == RawNTLMSSP) {
- if (!server->sec_ntlmssp)
- rc = -EOPNOTSUPP;
- } else
+ if (server->sec_kerberos || server->sec_mskerberos)
+ server->secType = Kerberos;
+ else if (server->sec_ntlmssp)
+ server->secType = RawNTLMSSP;
+ else
rc = -EOPNOTSUPP;
}
} else
@@ -4537,8 +4551,8 @@
cFYI(1, "In QFSUnixInfo");
QFSUnixRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
+ rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
+ (void **) &pSMB, (void **) &pSMBr);
if (rc)
return rc;
@@ -4607,8 +4621,8 @@
cFYI(1, "In SETFSUnixInfo");
SETFSUnixRetry:
/* BB switch to small buf init to save memory */
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
+ rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
+ (void **) &pSMB, (void **) &pSMBr);
if (rc)
return rc;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index ec0ea4a..88c84a3 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -400,7 +400,9 @@
cFYI(1, "call to reconnect done");
csocket = server->ssocket;
continue;
- } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
+ } else if (length == -ERESTARTSYS ||
+ length == -EAGAIN ||
+ length == -EINTR) {
msleep(1); /* minimum sleep to prevent looping
allowing socket to clear and app threads to set
tcpStatus CifsNeedReconnect if server hung */
@@ -414,18 +416,6 @@
} else
continue;
} else if (length <= 0) {
- if (server->tcpStatus == CifsNew) {
- cFYI(1, "tcp session abend after SMBnegprot");
- /* some servers kill the TCP session rather than
- returning an SMB negprot error, in which
- case reconnecting here is not going to help,
- and so simply return error to mount */
- break;
- }
- if (!try_to_freeze() && (length == -EINTR)) {
- cFYI(1, "cifsd thread killed");
- break;
- }
cFYI(1, "Reconnect after unexpected peek error %d",
length);
cifs_reconnect(server);
@@ -466,27 +456,19 @@
an error on SMB negprot response */
cFYI(1, "Negative RFC1002 Session Response Error 0x%x)",
pdu_length);
- if (server->tcpStatus == CifsNew) {
- /* if nack on negprot (rather than
- ret of smb negprot error) reconnecting
- not going to help, ret error to mount */
- break;
- } else {
- /* give server a second to
- clean up before reconnect attempt */
- msleep(1000);
- /* always try 445 first on reconnect
- since we get NACK on some if we ever
- connected to port 139 (the NACK is
- since we do not begin with RFC1001
- session initialize frame) */
- server->addr.sockAddr.sin_port =
- htons(CIFS_PORT);
- cifs_reconnect(server);
- csocket = server->ssocket;
- wake_up(&server->response_q);
- continue;
- }
+ /* give server a second to clean up */
+ msleep(1000);
+ /* always try 445 first on reconnect since we get NACK
+ * on some if we ever connected to port 139 (the NACK
+ * is since we do not begin with RFC1001 session
+ * initialize frame)
+ */
+ cifs_set_port((struct sockaddr *)
+ &server->addr.sockAddr, CIFS_PORT);
+ cifs_reconnect(server);
+ csocket = server->ssocket;
+ wake_up(&server->response_q);
+ continue;
} else if (temp != (char) 0) {
cERROR(1, "Unknown RFC 1002 frame");
cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
@@ -522,8 +504,7 @@
total_read += length) {
length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
pdu_length - total_read, 0);
- if ((server->tcpStatus == CifsExiting) ||
- (length == -EINTR)) {
+ if (server->tcpStatus == CifsExiting) {
/* then will exit */
reconnect = 2;
break;
@@ -534,8 +515,9 @@
/* Now we will reread sock */
reconnect = 1;
break;
- } else if ((length == -ERESTARTSYS) ||
- (length == -EAGAIN)) {
+ } else if (length == -ERESTARTSYS ||
+ length == -EAGAIN ||
+ length == -EINTR) {
msleep(1); /* minimum sleep to prevent looping,
allowing socket to clear and app
threads to set tcpStatus
@@ -1708,7 +1690,6 @@
CIFSSMBLogoff(xid, ses);
_FreeXid(xid);
}
- cifs_crypto_shash_release(server);
sesInfoFree(ses);
cifs_put_tcp_session(server);
}
@@ -1725,9 +1706,6 @@
if (ses) {
cFYI(1, "Existing smb sess found (status=%d)", ses->status);
- /* existing SMB ses has a server reference already */
- cifs_put_tcp_session(server);
-
mutex_lock(&ses->session_mutex);
rc = cifs_negotiate_protocol(xid, ses);
if (rc) {
@@ -1750,6 +1728,9 @@
}
}
mutex_unlock(&ses->session_mutex);
+
+ /* existing SMB ses has a server reference already */
+ cifs_put_tcp_session(server);
FreeXid(xid);
return ses;
}
@@ -1788,23 +1769,13 @@
ses->linux_uid = volume_info->linux_uid;
ses->overrideSecFlg = volume_info->secFlg;
- rc = cifs_crypto_shash_allocate(server);
- if (rc) {
- cERROR(1, "could not setup hash structures rc %d", rc);
- goto get_ses_fail;
- }
- server->tilen = 0;
- server->tiblob = NULL;
-
mutex_lock(&ses->session_mutex);
rc = cifs_negotiate_protocol(xid, ses);
if (!rc)
rc = cifs_setup_session(xid, ses, volume_info->local_nls);
mutex_unlock(&ses->session_mutex);
- if (rc) {
- cifs_crypto_shash_release(ses->server);
+ if (rc)
goto get_ses_fail;
- }
/* success, put it on the list */
write_lock(&cifs_tcp_ses_lock);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 86a164f..53cce8c 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -801,6 +801,8 @@
inode->i_flags |= S_NOATIME | S_NOCMTIME;
if (inode->i_state & I_NEW) {
inode->i_ino = hash;
+ if (S_ISREG(inode->i_mode))
+ inode->i_data.backing_dev_info = sb->s_bdi;
#ifdef CONFIG_CIFS_FSCACHE
/* initialize per-inode cache cookie pointer */
CIFS_I(inode)->fscache = NULL;
@@ -1462,29 +1464,18 @@
{
char *fromName = NULL;
char *toName = NULL;
- struct cifs_sb_info *cifs_sb_source;
- struct cifs_sb_info *cifs_sb_target;
+ struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *tcon;
FILE_UNIX_BASIC_INFO *info_buf_source = NULL;
FILE_UNIX_BASIC_INFO *info_buf_target;
int xid, rc, tmprc;
- cifs_sb_target = CIFS_SB(target_dir->i_sb);
- cifs_sb_source = CIFS_SB(source_dir->i_sb);
- tcon = cifs_sb_source->tcon;
+ cifs_sb = CIFS_SB(source_dir->i_sb);
+ tcon = cifs_sb->tcon;
xid = GetXid();
/*
- * BB: this might be allowed if same server, but different share.
- * Consider adding support for this
- */
- if (tcon != cifs_sb_target->tcon) {
- rc = -EXDEV;
- goto cifs_rename_exit;
- }
-
- /*
* we already have the rename sem so we do not need to
* grab it again here to protect the path integrity
*/
@@ -1519,17 +1510,16 @@
info_buf_target = info_buf_source + 1;
tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName,
info_buf_source,
- cifs_sb_source->local_nls,
- cifs_sb_source->mnt_cifs_flags &
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (tmprc != 0)
goto unlink_target;
- tmprc = CIFSSMBUnixQPathInfo(xid, tcon,
- toName, info_buf_target,
- cifs_sb_target->local_nls,
- /* remap based on source sb */
- cifs_sb_source->mnt_cifs_flags &
+ tmprc = CIFSSMBUnixQPathInfo(xid, tcon, toName,
+ info_buf_target,
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (tmprc == 0 && (info_buf_source->UniqueId ==
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index f978511..9aad47a 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -206,24 +206,28 @@
}
int
+cifs_set_port(struct sockaddr *addr, const unsigned short int port)
+{
+ switch (addr->sa_family) {
+ case AF_INET:
+ ((struct sockaddr_in *)addr)->sin_port = htons(port);
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *)addr)->sin6_port = htons(port);
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+int
cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len,
const unsigned short int port)
{
if (!cifs_convert_address(dst, src, len))
return 0;
-
- switch (dst->sa_family) {
- case AF_INET:
- ((struct sockaddr_in *)dst)->sin_port = htons(port);
- break;
- case AF_INET6:
- ((struct sockaddr_in6 *)dst)->sin6_port = htons(port);
- break;
- default:
- return 0;
- }
-
- return 1;
+ return cifs_set_port(dst, port);
}
/*****************************************************************************
diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h
index 1db0f07..49c9a4e 100644
--- a/fs/cifs/ntlmssp.h
+++ b/fs/cifs/ntlmssp.h
@@ -61,19 +61,6 @@
#define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000
#define NTLMSSP_NEGOTIATE_56 0x80000000
-/* Define AV Pair Field IDs */
-#define NTLMSSP_AV_EOL 0
-#define NTLMSSP_AV_NB_COMPUTER_NAME 1
-#define NTLMSSP_AV_NB_DOMAIN_NAME 2
-#define NTLMSSP_AV_DNS_COMPUTER_NAME 3
-#define NTLMSSP_AV_DNS_DOMAIN_NAME 4
-#define NTLMSSP_AV_DNS_TREE_NAME 5
-#define NTLMSSP_AV_FLAGS 6
-#define NTLMSSP_AV_TIMESTAMP 7
-#define NTLMSSP_AV_RESTRICTION 8
-#define NTLMSSP_AV_TARGET_NAME 9
-#define NTLMSSP_AV_CHANNEL_BINDINGS 10
-
/* Although typedefs are not commonly used for structure definitions */
/* in the Linux kernel, in this particular case they are useful */
/* to more closely match the standards document for NTLMSSP from */
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 795095f..0a57cb7 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -383,9 +383,6 @@
static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
struct cifsSesInfo *ses)
{
- unsigned int tioffset; /* challeng message target info area */
- unsigned int tilen; /* challeng message target info area length */
-
CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr;
if (blob_len < sizeof(CHALLENGE_MESSAGE)) {
@@ -408,20 +405,6 @@
/* BB spec says that if AvId field of MsvAvTimestamp is populated then
we must set the MIC field of the AUTHENTICATE_MESSAGE */
- ses->server->ntlmssp.server_flags = le32_to_cpu(pblob->NegotiateFlags);
-
- tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset);
- tilen = cpu_to_le16(pblob->TargetInfoArray.Length);
- ses->server->tilen = tilen;
- if (tilen) {
- ses->server->tiblob = kmalloc(tilen, GFP_KERNEL);
- if (!ses->server->tiblob) {
- cERROR(1, "Challenge target info allocation failure");
- return -ENOMEM;
- }
- memcpy(ses->server->tiblob, bcc_ptr + tioffset, tilen);
- }
-
return 0;
}
@@ -442,13 +425,12 @@
/* BB is NTLMV2 session security format easier to use here? */
flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET |
NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
- NTLMSSP_NEGOTIATE_NTLM;
+ NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM;
if (ses->server->secMode &
- (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
- flags |= NTLMSSP_NEGOTIATE_SIGN |
- NTLMSSP_NEGOTIATE_KEY_XCH |
- NTLMSSP_NEGOTIATE_EXTENDED_SEC;
- }
+ (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+ flags |= NTLMSSP_NEGOTIATE_SIGN;
+ if (ses->server->secMode & SECMODE_SIGN_REQUIRED)
+ flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
sec_blob->NegotiateFlags |= cpu_to_le32(flags);
@@ -469,12 +451,10 @@
struct cifsSesInfo *ses,
const struct nls_table *nls_cp, bool first)
{
- int rc;
- unsigned int size;
AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer;
__u32 flags;
unsigned char *tmp;
- struct ntlmv2_resp ntlmv2_response = {};
+ char ntlm_session_key[CIFS_SESS_KEY_SIZE];
memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8);
sec_blob->MessageType = NtLmAuthenticate;
@@ -497,25 +477,19 @@
sec_blob->LmChallengeResponse.Length = 0;
sec_blob->LmChallengeResponse.MaximumLength = 0;
- sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer);
- rc = setup_ntlmv2_rsp(ses, (char *)&ntlmv2_response, nls_cp);
- if (rc) {
- cERROR(1, "error rc: %d during ntlmssp ntlmv2 setup", rc);
- goto setup_ntlmv2_ret;
- }
- size = sizeof(struct ntlmv2_resp);
- memcpy(tmp, (char *)&ntlmv2_response, size);
- tmp += size;
- if (ses->server->tilen > 0) {
- memcpy(tmp, ses->server->tiblob, ses->server->tilen);
- tmp += ses->server->tilen;
- } else
- ses->server->tilen = 0;
+ /* calculate session key, BB what about adding similar ntlmv2 path? */
+ SMBNTencrypt(ses->password, ses->server->cryptKey, ntlm_session_key);
+ if (first)
+ cifs_calculate_mac_key(&ses->server->mac_signing_key,
+ ntlm_session_key, ses->password);
- sec_blob->NtChallengeResponse.Length = cpu_to_le16(size +
- ses->server->tilen);
+ memcpy(tmp, ntlm_session_key, CIFS_SESS_KEY_SIZE);
+ sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer);
+ sec_blob->NtChallengeResponse.Length = cpu_to_le16(CIFS_SESS_KEY_SIZE);
sec_blob->NtChallengeResponse.MaximumLength =
- cpu_to_le16(size + ses->server->tilen);
+ cpu_to_le16(CIFS_SESS_KEY_SIZE);
+
+ tmp += CIFS_SESS_KEY_SIZE;
if (ses->domainName == NULL) {
sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer);
@@ -527,6 +501,7 @@
len = cifs_strtoUCS((__le16 *)tmp, ses->domainName,
MAX_USERNAME_SIZE, nls_cp);
len *= 2; /* unicode is 2 bytes each */
+ len += 2; /* trailing null */
sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer);
sec_blob->DomainName.Length = cpu_to_le16(len);
sec_blob->DomainName.MaximumLength = cpu_to_le16(len);
@@ -543,6 +518,7 @@
len = cifs_strtoUCS((__le16 *)tmp, ses->userName,
MAX_USERNAME_SIZE, nls_cp);
len *= 2; /* unicode is 2 bytes each */
+ len += 2; /* trailing null */
sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer);
sec_blob->UserName.Length = cpu_to_le16(len);
sec_blob->UserName.MaximumLength = cpu_to_le16(len);
@@ -554,26 +530,9 @@
sec_blob->WorkstationName.MaximumLength = 0;
tmp += 2;
- if ((ses->server->ntlmssp.server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) &&
- !calc_seckey(ses->server)) {
- memcpy(tmp, ses->server->ntlmssp.ciphertext, CIFS_CPHTXT_SIZE);
- sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer);
- sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE);
- sec_blob->SessionKey.MaximumLength =
- cpu_to_le16(CIFS_CPHTXT_SIZE);
- tmp += CIFS_CPHTXT_SIZE;
- } else {
- sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer);
- sec_blob->SessionKey.Length = 0;
- sec_blob->SessionKey.MaximumLength = 0;
- }
-
- ses->server->sequence_number = 0;
-
-setup_ntlmv2_ret:
- if (ses->server->tilen > 0)
- kfree(ses->server->tiblob);
-
+ sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer);
+ sec_blob->SessionKey.Length = 0;
+ sec_blob->SessionKey.MaximumLength = 0;
return tmp - pbuffer;
}
@@ -587,14 +546,15 @@
return;
}
-static int setup_ntlmssp_auth_req(char *ntlmsspblob,
+static int setup_ntlmssp_auth_req(SESSION_SETUP_ANDX *pSMB,
struct cifsSesInfo *ses,
const struct nls_table *nls, bool first_time)
{
int bloblen;
- bloblen = build_ntlmssp_auth_blob(ntlmsspblob, ses, nls,
+ bloblen = build_ntlmssp_auth_blob(&pSMB->req.SecurityBlob[0], ses, nls,
first_time);
+ pSMB->req.SecurityBlobLength = cpu_to_le16(bloblen);
return bloblen;
}
@@ -730,7 +690,7 @@
if (first_time) /* should this be moved into common code
with similar ntlmv2 path? */
- cifs_calculate_session_key(&ses->server->session_key,
+ cifs_calculate_mac_key(&ses->server->mac_signing_key,
ntlm_session_key, ses->password);
/* copy session key */
@@ -769,21 +729,12 @@
cpu_to_le16(sizeof(struct ntlmv2_resp));
/* calculate session key */
- rc = setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp);
- if (rc) {
- kfree(v2_sess_key);
- goto ssetup_exit;
- }
+ setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp);
/* FIXME: calculate MAC key */
memcpy(bcc_ptr, (char *)v2_sess_key,
sizeof(struct ntlmv2_resp));
bcc_ptr += sizeof(struct ntlmv2_resp);
kfree(v2_sess_key);
- if (ses->server->tilen > 0) {
- memcpy(bcc_ptr, ses->server->tiblob,
- ses->server->tilen);
- bcc_ptr += ses->server->tilen;
- }
if (ses->capabilities & CAP_UNICODE) {
if (iov[0].iov_len % 2) {
*bcc_ptr = 0;
@@ -814,15 +765,15 @@
}
/* bail out if key is too long */
if (msg->sesskey_len >
- sizeof(ses->server->session_key.data.krb5)) {
+ sizeof(ses->server->mac_signing_key.data.krb5)) {
cERROR(1, "Kerberos signing key too long (%u bytes)",
msg->sesskey_len);
rc = -EOVERFLOW;
goto ssetup_exit;
}
if (first_time) {
- ses->server->session_key.len = msg->sesskey_len;
- memcpy(ses->server->session_key.data.krb5,
+ ses->server->mac_signing_key.len = msg->sesskey_len;
+ memcpy(ses->server->mac_signing_key.data.krb5,
msg->data, msg->sesskey_len);
}
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
@@ -864,28 +815,12 @@
if (phase == NtLmNegotiate) {
setup_ntlmssp_neg_req(pSMB, ses);
iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE);
- iov[1].iov_base = &pSMB->req.SecurityBlob[0];
} else if (phase == NtLmAuthenticate) {
int blob_len;
- char *ntlmsspblob;
-
- ntlmsspblob = kmalloc(5 *
- sizeof(struct _AUTHENTICATE_MESSAGE),
- GFP_KERNEL);
- if (!ntlmsspblob) {
- cERROR(1, "Can't allocate NTLMSSP");
- rc = -ENOMEM;
- goto ssetup_exit;
- }
-
- blob_len = setup_ntlmssp_auth_req(ntlmsspblob,
- ses,
- nls_cp,
- first_time);
+ blob_len = setup_ntlmssp_auth_req(pSMB, ses,
+ nls_cp,
+ first_time);
iov[1].iov_len = blob_len;
- iov[1].iov_base = ntlmsspblob;
- pSMB->req.SecurityBlobLength =
- cpu_to_le16(blob_len);
/* Make sure that we tell the server that we
are using the uid that it just gave us back
on the response (challenge) */
@@ -895,6 +830,7 @@
rc = -ENOSYS;
goto ssetup_exit;
}
+ iov[1].iov_base = &pSMB->req.SecurityBlob[0];
/* unicode strings must be word aligned */
if ((iov[0].iov_len + iov[1].iov_len) % 2) {
*bcc_ptr = 0;
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index e0588cd..82f78c4 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -543,7 +543,7 @@
(ses->server->secMode & (SECMODE_SIGN_REQUIRED |
SECMODE_SIGN_ENABLED))) {
rc = cifs_verify_signature(midQ->resp_buf,
- ses->server,
+ &ses->server->mac_signing_key,
midQ->sequence_number+1);
if (rc) {
cERROR(1, "Unexpected SMB signature");
@@ -731,7 +731,7 @@
(ses->server->secMode & (SECMODE_SIGN_REQUIRED |
SECMODE_SIGN_ENABLED))) {
rc = cifs_verify_signature(out_buf,
- ses->server,
+ &ses->server->mac_signing_key,
midQ->sequence_number+1);
if (rc) {
cERROR(1, "Unexpected SMB signature");
@@ -981,7 +981,7 @@
(ses->server->secMode & (SECMODE_SIGN_REQUIRED |
SECMODE_SIGN_ENABLED))) {
rc = cifs_verify_signature(out_buf,
- ses->server,
+ &ses->server->mac_signing_key,
midQ->sequence_number+1);
if (rc) {
cERROR(1, "Unexpected SMB signature");
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index de89645..116af75 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -184,8 +184,8 @@
}
/* adjust outsize. is this useful ?? */
- req->uc_outSize = nbytes;
- req->uc_flags |= REQ_WRITE;
+ req->uc_outSize = nbytes;
+ req->uc_flags |= CODA_REQ_WRITE;
count = nbytes;
/* Convert filedescriptor into a file handle */
diff --git a/fs/compat.c b/fs/compat.c
index 718c706..0644a15 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1153,7 +1153,7 @@
{
compat_ssize_t tot_len;
struct iovec iovstack[UIO_FASTIOV];
- struct iovec *iov;
+ struct iovec *iov = iovstack;
ssize_t ret;
io_fn_t fn;
iov_fn_t fnv;
diff --git a/fs/exec.c b/fs/exec.c
index 828dd24..6d2b6f9 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -2014,3 +2014,43 @@
fail:
return;
}
+
+/*
+ * Core dumping helper functions. These are the only things you should
+ * do on a core-file: use only these functions to write out all the
+ * necessary info.
+ */
+int dump_write(struct file *file, const void *addr, int nr)
+{
+ return access_ok(VERIFY_READ, addr, nr) && file->f_op->write(file, addr, nr, &file->f_pos) == nr;
+}
+EXPORT_SYMBOL(dump_write);
+
+int dump_seek(struct file *file, loff_t off)
+{
+ int ret = 1;
+
+ if (file->f_op->llseek && file->f_op->llseek != no_llseek) {
+ if (file->f_op->llseek(file, off, SEEK_CUR) < 0)
+ return 0;
+ } else {
+ char *buf = (char *)get_zeroed_page(GFP_KERNEL);
+
+ if (!buf)
+ return 0;
+ while (off > 0) {
+ unsigned long n = off;
+
+ if (n > PAGE_SIZE)
+ n = PAGE_SIZE;
+ if (!dump_write(file, buf, n)) {
+ ret = 0;
+ break;
+ }
+ off -= n;
+ }
+ free_page((unsigned long)buf);
+ }
+ return ret;
+}
+EXPORT_SYMBOL(dump_seek);
diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c
index eb7368e..3eadd97 100644
--- a/fs/exofs/inode.c
+++ b/fs/exofs/inode.c
@@ -54,6 +54,9 @@
unsigned nr_pages;
unsigned long length;
loff_t pg_first; /* keep 64bit also in 32-arches */
+ bool read_4_write; /* This means two things: that the read is sync
+ * And the pages should not be unlocked.
+ */
};
static void _pcol_init(struct page_collect *pcol, unsigned expected_pages,
@@ -71,6 +74,7 @@
pcol->nr_pages = 0;
pcol->length = 0;
pcol->pg_first = -1;
+ pcol->read_4_write = false;
}
static void _pcol_reset(struct page_collect *pcol)
@@ -347,7 +351,8 @@
if (PageError(page))
ClearPageError(page);
- unlock_page(page);
+ if (!pcol->read_4_write)
+ unlock_page(page);
EXOFS_DBGMSG("readpage_strip(0x%lx, 0x%lx) empty page,"
" splitting\n", inode->i_ino, page->index);
@@ -428,6 +433,7 @@
/* readpage_strip might call read_exec(,is_sync==false) at several
* places but not if we have a single page.
*/
+ pcol.read_4_write = is_sync;
ret = readpage_strip(&pcol, page);
if (ret) {
EXOFS_ERR("_readpage => %d\n", ret);
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 81e086d..ab38fef 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -52,8 +52,6 @@
#define CREATE_TRACE_POINTS
#include <trace/events/writeback.h>
-#define inode_to_bdi(inode) ((inode)->i_mapping->backing_dev_info)
-
/*
* We don't actually have pdflush, but this one is exported though /proc...
*/
@@ -71,6 +69,16 @@
return test_bit(BDI_writeback_running, &bdi->state);
}
+static inline struct backing_dev_info *inode_to_bdi(struct inode *inode)
+{
+ struct super_block *sb = inode->i_sb;
+
+ if (strcmp(sb->s_type->name, "bdev") == 0)
+ return inode->i_mapping->backing_dev_info;
+
+ return sb->s_bdi;
+}
+
static void bdi_queue_work(struct backing_dev_info *bdi,
struct wb_writeback_work *work)
{
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index d367af1..cde755c 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1354,7 +1354,7 @@
loff_t file_size;
unsigned int num;
unsigned int offset;
- size_t total_len;
+ size_t total_len = 0;
req = fuse_get_req(fc);
if (IS_ERR(req))
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index cde1248..ac750bd 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -932,7 +932,7 @@
do {
prepare_to_wait(&sdp->sd_logd_waitq, &wait,
- TASK_UNINTERRUPTIBLE);
+ TASK_INTERRUPTIBLE);
if (!gfs2_ail_flush_reqd(sdp) &&
!gfs2_jrnl_flush_reqd(sdp) &&
!kthread_should_stop())
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index 6c2aad4..f7e13db 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -63,6 +63,7 @@
config NFS_V4
bool "NFS client support for NFS version 4"
depends on NFS_FS
+ select SUNRPC_GSS
help
This option enables support for version 4 of the NFS protocol
(RFC 3530) in the kernel's NFS client.
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 4e7df2a..e734072 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -275,7 +275,7 @@
sin1->sin6_scope_id != sin2->sin6_scope_id)
return 0;
- return ipv6_addr_equal(&sin1->sin6_addr, &sin1->sin6_addr);
+ return ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr);
}
#else /* !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE) */
static int nfs_sockaddr_match_ipaddr6(const struct sockaddr *sa1,
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index eb51bd6..05bf3c0 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -723,10 +723,6 @@
default:
BUG();
}
- if (res < 0)
- dprintk(KERN_WARNING "%s: VFS is out of sync with lock manager"
- " - error %d!\n",
- __func__, res);
return res;
}
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index ec3966e..f4cbf0c 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -431,7 +431,15 @@
goto out_err;
error = server->nfs_client->rpc_ops->statfs(server, fh, &res);
+ if (unlikely(error == -ESTALE)) {
+ struct dentry *pd_dentry;
+ pd_dentry = dget_parent(dentry);
+ if (pd_dentry != NULL) {
+ nfs_zap_caches(pd_dentry->d_inode);
+ dput(pd_dentry);
+ }
+ }
nfs_free_fattr(res.fattr);
if (error < 0)
goto out_err;
diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig
index 95932f5..4264377 100644
--- a/fs/nfsd/Kconfig
+++ b/fs/nfsd/Kconfig
@@ -69,6 +69,7 @@
depends on NFSD && PROC_FS && EXPERIMENTAL
select NFSD_V3
select FS_POSIX_ACL
+ select SUNRPC_GSS
help
This option enables support in your system's NFS server for
version 4 of the NFS protocol (RFC 3530).
diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h
index cdfb8c6..c16f8d8 100644
--- a/fs/nfsd/nfsfh.h
+++ b/fs/nfsd/nfsfh.h
@@ -196,8 +196,6 @@
static inline void
fh_unlock(struct svc_fh *fhp)
{
- BUG_ON(!fhp->fh_dentry);
-
if (fhp->fh_locked) {
fill_post_wcc(fhp);
mutex_unlock(&fhp->fh_dentry->d_inode->i_mutex);
diff --git a/fs/notify/Kconfig b/fs/notify/Kconfig
index 22c629e..b388443 100644
--- a/fs/notify/Kconfig
+++ b/fs/notify/Kconfig
@@ -3,4 +3,4 @@
source "fs/notify/dnotify/Kconfig"
source "fs/notify/inotify/Kconfig"
-source "fs/notify/fanotify/Kconfig"
+#source "fs/notify/fanotify/Kconfig"
diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c
index a76e0aa..3919150 100644
--- a/fs/ocfs2/acl.c
+++ b/fs/ocfs2/acl.c
@@ -209,7 +209,10 @@
}
inode->i_mode = new_mode;
+ inode->i_ctime = CURRENT_TIME;
di->i_mode = cpu_to_le16(inode->i_mode);
+ di->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
+ di->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
ocfs2_journal_dirty(handle, di_bh);
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c
index 1361997..cbe2f05 100644
--- a/fs/ocfs2/cluster/tcp.c
+++ b/fs/ocfs2/cluster/tcp.c
@@ -977,7 +977,7 @@
int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec,
size_t caller_veclen, u8 target_node, int *status)
{
- int ret;
+ int ret = 0;
struct o2net_msg *msg = NULL;
size_t veclen, caller_bytes = 0;
struct kvec *vec = NULL;
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index f04ebcf..c49f6de 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -3931,6 +3931,15 @@
goto out_commit;
}
+ cpos = split_hash;
+ ret = ocfs2_dx_dir_new_cluster(dir, &et, cpos, handle,
+ data_ac, meta_ac, new_dx_leaves,
+ num_dx_leaves);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
for (i = 0; i < num_dx_leaves; i++) {
ret = ocfs2_journal_access_dl(handle, INODE_CACHE(dir),
orig_dx_leaves[i],
@@ -3939,15 +3948,14 @@
mlog_errno(ret);
goto out_commit;
}
- }
- cpos = split_hash;
- ret = ocfs2_dx_dir_new_cluster(dir, &et, cpos, handle,
- data_ac, meta_ac, new_dx_leaves,
- num_dx_leaves);
- if (ret) {
- mlog_errno(ret);
- goto out_commit;
+ ret = ocfs2_journal_access_dl(handle, INODE_CACHE(dir),
+ new_dx_leaves[i],
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
}
ocfs2_dx_dir_transfer_leaf(dir, split_hash, handle, tmp_dx_leaf,
diff --git a/fs/ocfs2/dlm/dlmcommon.h b/fs/ocfs2/dlm/dlmcommon.h
index 4b6ae2c..7652989 100644
--- a/fs/ocfs2/dlm/dlmcommon.h
+++ b/fs/ocfs2/dlm/dlmcommon.h
@@ -1030,6 +1030,7 @@
struct dlm_lock_resource *res);
void dlm_clean_master_list(struct dlm_ctxt *dlm,
u8 dead_node);
+void dlm_force_free_mles(struct dlm_ctxt *dlm);
int dlm_lock_basts_flushed(struct dlm_ctxt *dlm, struct dlm_lock *lock);
int __dlm_lockres_has_locks(struct dlm_lock_resource *res);
int __dlm_lockres_unused(struct dlm_lock_resource *res);
diff --git a/fs/ocfs2/dlm/dlmdebug.c b/fs/ocfs2/dlm/dlmdebug.c
index 5efdd37..901ca52 100644
--- a/fs/ocfs2/dlm/dlmdebug.c
+++ b/fs/ocfs2/dlm/dlmdebug.c
@@ -636,8 +636,14 @@
spin_lock(&dlm->track_lock);
if (oldres)
track_list = &oldres->tracking;
- else
+ else {
track_list = &dlm->tracking_list;
+ if (list_empty(track_list)) {
+ dl = NULL;
+ spin_unlock(&dlm->track_lock);
+ goto bail;
+ }
+ }
list_for_each_entry(res, track_list, tracking) {
if (&res->tracking == &dlm->tracking_list)
@@ -660,6 +666,7 @@
} else
dl = NULL;
+bail:
/* passed to seq_show */
return dl;
}
diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c
index 153abb5..11a5c87 100644
--- a/fs/ocfs2/dlm/dlmdomain.c
+++ b/fs/ocfs2/dlm/dlmdomain.c
@@ -693,6 +693,7 @@
dlm_mark_domain_leaving(dlm);
dlm_leave_domain(dlm);
+ dlm_force_free_mles(dlm);
dlm_complete_dlm_shutdown(dlm);
}
dlm_put(dlm);
diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c
index ffb4c68..f564b0e 100644
--- a/fs/ocfs2/dlm/dlmmaster.c
+++ b/fs/ocfs2/dlm/dlmmaster.c
@@ -3433,3 +3433,43 @@
wake_up(&res->wq);
wake_up(&dlm->migration_wq);
}
+
+void dlm_force_free_mles(struct dlm_ctxt *dlm)
+{
+ int i;
+ struct hlist_head *bucket;
+ struct dlm_master_list_entry *mle;
+ struct hlist_node *tmp, *list;
+
+ /*
+ * We notified all other nodes that we are exiting the domain and
+ * marked the dlm state to DLM_CTXT_LEAVING. If any mles are still
+ * around we force free them and wake any processes that are waiting
+ * on the mles
+ */
+ spin_lock(&dlm->spinlock);
+ spin_lock(&dlm->master_lock);
+
+ BUG_ON(dlm->dlm_state != DLM_CTXT_LEAVING);
+ BUG_ON((find_next_bit(dlm->domain_map, O2NM_MAX_NODES, 0) < O2NM_MAX_NODES));
+
+ for (i = 0; i < DLM_HASH_BUCKETS; i++) {
+ bucket = dlm_master_hash(dlm, i);
+ hlist_for_each_safe(list, tmp, bucket) {
+ mle = hlist_entry(list, struct dlm_master_list_entry,
+ master_hash_node);
+ if (mle->type != DLM_MLE_BLOCK) {
+ mlog(ML_ERROR, "bad mle: %p\n", mle);
+ dlm_print_one_mle(mle);
+ }
+ atomic_set(&mle->woken, 1);
+ wake_up(&mle->wq);
+
+ __dlm_unlink_mle(dlm, mle);
+ __dlm_mle_detach_hb_events(dlm, mle);
+ __dlm_put_mle(mle);
+ }
+ }
+ spin_unlock(&dlm->master_lock);
+ spin_unlock(&dlm->spinlock);
+}
diff --git a/fs/ocfs2/dlmglue.h b/fs/ocfs2/dlmglue.h
index d1ce48e..1d596d8 100644
--- a/fs/ocfs2/dlmglue.h
+++ b/fs/ocfs2/dlmglue.h
@@ -84,6 +84,7 @@
OI_LS_PARENT,
OI_LS_RENAME1,
OI_LS_RENAME2,
+ OI_LS_REFLINK_TARGET,
};
int ocfs2_dlm_init(struct ocfs2_super *osb);
diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h
index 33f1c9a..fa31d05 100644
--- a/fs/ocfs2/ocfs2_fs.h
+++ b/fs/ocfs2/ocfs2_fs.h
@@ -235,18 +235,31 @@
#define OCFS2_HAS_REFCOUNT_FL (0x0010)
/* Inode attributes, keep in sync with EXT2 */
-#define OCFS2_SECRM_FL (0x00000001) /* Secure deletion */
-#define OCFS2_UNRM_FL (0x00000002) /* Undelete */
-#define OCFS2_COMPR_FL (0x00000004) /* Compress file */
-#define OCFS2_SYNC_FL (0x00000008) /* Synchronous updates */
-#define OCFS2_IMMUTABLE_FL (0x00000010) /* Immutable file */
-#define OCFS2_APPEND_FL (0x00000020) /* writes to file may only append */
-#define OCFS2_NODUMP_FL (0x00000040) /* do not dump file */
-#define OCFS2_NOATIME_FL (0x00000080) /* do not update atime */
-#define OCFS2_DIRSYNC_FL (0x00010000) /* dirsync behaviour (directories only) */
+#define OCFS2_SECRM_FL FS_SECRM_FL /* Secure deletion */
+#define OCFS2_UNRM_FL FS_UNRM_FL /* Undelete */
+#define OCFS2_COMPR_FL FS_COMPR_FL /* Compress file */
+#define OCFS2_SYNC_FL FS_SYNC_FL /* Synchronous updates */
+#define OCFS2_IMMUTABLE_FL FS_IMMUTABLE_FL /* Immutable file */
+#define OCFS2_APPEND_FL FS_APPEND_FL /* writes to file may only append */
+#define OCFS2_NODUMP_FL FS_NODUMP_FL /* do not dump file */
+#define OCFS2_NOATIME_FL FS_NOATIME_FL /* do not update atime */
+/* Reserved for compression usage... */
+#define OCFS2_DIRTY_FL FS_DIRTY_FL
+#define OCFS2_COMPRBLK_FL FS_COMPRBLK_FL /* One or more compressed clusters */
+#define OCFS2_NOCOMP_FL FS_NOCOMP_FL /* Don't compress */
+#define OCFS2_ECOMPR_FL FS_ECOMPR_FL /* Compression error */
+/* End compression flags --- maybe not all used */
+#define OCFS2_BTREE_FL FS_BTREE_FL /* btree format dir */
+#define OCFS2_INDEX_FL FS_INDEX_FL /* hash-indexed directory */
+#define OCFS2_IMAGIC_FL FS_IMAGIC_FL /* AFS directory */
+#define OCFS2_JOURNAL_DATA_FL FS_JOURNAL_DATA_FL /* Reserved for ext3 */
+#define OCFS2_NOTAIL_FL FS_NOTAIL_FL /* file tail should not be merged */
+#define OCFS2_DIRSYNC_FL FS_DIRSYNC_FL /* dirsync behaviour (directories only) */
+#define OCFS2_TOPDIR_FL FS_TOPDIR_FL /* Top of directory hierarchies*/
+#define OCFS2_RESERVED_FL FS_RESERVED_FL /* reserved for ext2 lib */
-#define OCFS2_FL_VISIBLE (0x000100FF) /* User visible flags */
-#define OCFS2_FL_MODIFIABLE (0x000100FF) /* User modifiable flags */
+#define OCFS2_FL_VISIBLE FS_FL_USER_VISIBLE /* User visible flags */
+#define OCFS2_FL_MODIFIABLE FS_FL_USER_MODIFIABLE /* User modifiable flags */
/*
* Extent record flags (e_node.leaf.flags)
diff --git a/fs/ocfs2/ocfs2_ioctl.h b/fs/ocfs2/ocfs2_ioctl.h
index 2d3420a..5d24150 100644
--- a/fs/ocfs2/ocfs2_ioctl.h
+++ b/fs/ocfs2/ocfs2_ioctl.h
@@ -23,10 +23,10 @@
/*
* ioctl commands
*/
-#define OCFS2_IOC_GETFLAGS _IOR('f', 1, long)
-#define OCFS2_IOC_SETFLAGS _IOW('f', 2, long)
-#define OCFS2_IOC32_GETFLAGS _IOR('f', 1, int)
-#define OCFS2_IOC32_SETFLAGS _IOW('f', 2, int)
+#define OCFS2_IOC_GETFLAGS FS_IOC_GETFLAGS
+#define OCFS2_IOC_SETFLAGS FS_IOC_SETFLAGS
+#define OCFS2_IOC32_GETFLAGS FS_IOC32_GETFLAGS
+#define OCFS2_IOC32_SETFLAGS FS_IOC32_SETFLAGS
/*
* Space reservation / allocation / free ioctls and argument structure
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c
index 0afeda831..efdd756 100644
--- a/fs/ocfs2/refcounttree.c
+++ b/fs/ocfs2/refcounttree.c
@@ -4201,8 +4201,9 @@
goto out;
}
- mutex_lock(&new_inode->i_mutex);
- ret = ocfs2_inode_lock(new_inode, &new_bh, 1);
+ mutex_lock_nested(&new_inode->i_mutex, I_MUTEX_CHILD);
+ ret = ocfs2_inode_lock_nested(new_inode, &new_bh, 1,
+ OI_LS_REFLINK_TARGET);
if (ret) {
mlog_errno(ret);
goto out_unlock;
diff --git a/fs/ocfs2/reservations.c b/fs/ocfs2/reservations.c
index d8b6e42..3e78db3 100644
--- a/fs/ocfs2/reservations.c
+++ b/fs/ocfs2/reservations.c
@@ -732,25 +732,23 @@
struct ocfs2_alloc_reservation *resv,
int *cstart, int *clen)
{
- unsigned int wanted = *clen;
-
if (resv == NULL || ocfs2_resmap_disabled(resmap))
return -ENOSPC;
spin_lock(&resv_lock);
- /*
- * We don't want to over-allocate for temporary
- * windows. Otherwise, we run the risk of fragmenting the
- * allocation space.
- */
- wanted = ocfs2_resv_window_bits(resmap, resv);
- if ((resv->r_flags & OCFS2_RESV_FLAG_TMP) || wanted < *clen)
- wanted = *clen;
-
if (ocfs2_resv_empty(resv)) {
- mlog(0, "empty reservation, find new window\n");
+ /*
+ * We don't want to over-allocate for temporary
+ * windows. Otherwise, we run the risk of fragmenting the
+ * allocation space.
+ */
+ unsigned int wanted = ocfs2_resv_window_bits(resmap, resv);
+ if ((resv->r_flags & OCFS2_RESV_FLAG_TMP) || wanted < *clen)
+ wanted = *clen;
+
+ mlog(0, "empty reservation, find new window\n");
/*
* Try to get a window here. If it works, we must fall
* through and test the bitmap . This avoids some
diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c
index 8a286f5..849c2f0 100644
--- a/fs/ocfs2/suballoc.c
+++ b/fs/ocfs2/suballoc.c
@@ -357,7 +357,7 @@
static void ocfs2_bg_discontig_add_extent(struct ocfs2_super *osb,
struct ocfs2_group_desc *bg,
struct ocfs2_chain_list *cl,
- u64 p_blkno, u32 clusters)
+ u64 p_blkno, unsigned int clusters)
{
struct ocfs2_extent_list *el = &bg->bg_list;
struct ocfs2_extent_rec *rec;
@@ -369,7 +369,7 @@
rec->e_blkno = cpu_to_le64(p_blkno);
rec->e_cpos = cpu_to_le32(le16_to_cpu(bg->bg_bits) /
le16_to_cpu(cl->cl_bpc));
- rec->e_leaf_clusters = cpu_to_le32(clusters);
+ rec->e_leaf_clusters = cpu_to_le16(clusters);
le16_add_cpu(&bg->bg_bits, clusters * le16_to_cpu(cl->cl_bpc));
le16_add_cpu(&bg->bg_free_bits_count,
clusters * le16_to_cpu(cl->cl_bpc));
diff --git a/fs/ocfs2/symlink.c b/fs/ocfs2/symlink.c
index 32499d21..9975457 100644
--- a/fs/ocfs2/symlink.c
+++ b/fs/ocfs2/symlink.c
@@ -128,7 +128,7 @@
}
/* Fast symlinks can't be large */
- len = strlen(target);
+ len = strnlen(target, ocfs2_fast_symlink_chars(inode->i_sb));
link = kzalloc(len + 1, GFP_NOFS);
if (!link) {
status = -ENOMEM;
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
index d03469f..06fa5e7 100644
--- a/fs/ocfs2/xattr.c
+++ b/fs/ocfs2/xattr.c
@@ -1286,13 +1286,11 @@
xis.inode_bh = xbs.inode_bh = di_bh;
di = (struct ocfs2_dinode *)di_bh->b_data;
- down_read(&oi->ip_xattr_sem);
ret = ocfs2_xattr_ibody_get(inode, name_index, name, buffer,
buffer_size, &xis);
if (ret == -ENODATA && di->i_xattr_loc)
ret = ocfs2_xattr_block_get(inode, name_index, name, buffer,
buffer_size, &xbs);
- up_read(&oi->ip_xattr_sem);
return ret;
}
@@ -1316,8 +1314,10 @@
mlog_errno(ret);
return ret;
}
+ down_read(&OCFS2_I(inode)->ip_xattr_sem);
ret = ocfs2_xattr_get_nolock(inode, di_bh, name_index,
name, buffer, buffer_size);
+ up_read(&OCFS2_I(inode)->ip_xattr_sem);
ocfs2_inode_unlock(inode, 0);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index a1c43e7..8e4adda 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2675,7 +2675,7 @@
INF("auxv", S_IRUSR, proc_pid_auxv),
ONE("status", S_IRUGO, proc_pid_status),
ONE("personality", S_IRUSR, proc_pid_personality),
- INF("limits", S_IRUSR, proc_pid_limits),
+ INF("limits", S_IRUGO, proc_pid_limits),
#ifdef CONFIG_SCHED_DEBUG
REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations),
#endif
@@ -3011,7 +3011,7 @@
INF("auxv", S_IRUSR, proc_pid_auxv),
ONE("status", S_IRUGO, proc_pid_status),
ONE("personality", S_IRUSR, proc_pid_personality),
- INF("limits", S_IRUSR, proc_pid_limits),
+ INF("limits", S_IRUGO, proc_pid_limits),
#ifdef CONFIG_SCHED_DEBUG
REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations),
#endif
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 271afc4..1dbca4e8 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -363,13 +363,13 @@
mss->referenced += PAGE_SIZE;
mapcount = page_mapcount(page);
if (mapcount >= 2) {
- if (pte_dirty(ptent))
+ if (pte_dirty(ptent) || PageDirty(page))
mss->shared_dirty += PAGE_SIZE;
else
mss->shared_clean += PAGE_SIZE;
mss->pss += (PAGE_SIZE << PSS_SHIFT) / mapcount;
} else {
- if (pte_dirty(ptent))
+ if (pte_dirty(ptent) || PageDirty(page))
mss->private_dirty += PAGE_SIZE;
else
mss->private_clean += PAGE_SIZE;
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index 91c817f..2367fb3 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -163,7 +163,7 @@
static const struct file_operations proc_vmcore_operations = {
.read = read_vmcore,
- .llseek = generic_file_llseek,
+ .llseek = default_llseek,
};
static struct vmcore* __init get_new_element(void)
diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c
index f53505d..5cbb81e 100644
--- a/fs/reiserfs/ioctl.c
+++ b/fs/reiserfs/ioctl.c
@@ -170,6 +170,7 @@
int reiserfs_unpack(struct inode *inode, struct file *filp)
{
int retval = 0;
+ int depth;
int index;
struct page *page;
struct address_space *mapping;
@@ -188,8 +189,8 @@
/* we need to make sure nobody is changing the file size beneath
** us
*/
- mutex_lock(&inode->i_mutex);
- reiserfs_write_lock(inode->i_sb);
+ reiserfs_mutex_lock_safe(&inode->i_mutex, inode->i_sb);
+ depth = reiserfs_write_lock_once(inode->i_sb);
write_from = inode->i_size & (blocksize - 1);
/* if we are on a block boundary, we are already unpacked. */
@@ -224,6 +225,6 @@
out:
mutex_unlock(&inode->i_mutex);
- reiserfs_write_unlock(inode->i_sb);
+ reiserfs_write_unlock_once(inode->i_sb, depth);
return retval;
}
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c
index d59c4a6..81976ff 100644
--- a/fs/xfs/linux-2.6/xfs_sync.c
+++ b/fs/xfs/linux-2.6/xfs_sync.c
@@ -668,14 +668,11 @@
xfs_perag_put(pag);
}
-void
-__xfs_inode_clear_reclaim_tag(
- xfs_mount_t *mp,
+STATIC void
+__xfs_inode_clear_reclaim(
xfs_perag_t *pag,
xfs_inode_t *ip)
{
- radix_tree_tag_clear(&pag->pag_ici_root,
- XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG);
pag->pag_ici_reclaimable--;
if (!pag->pag_ici_reclaimable) {
/* clear the reclaim tag from the perag radix tree */
@@ -689,6 +686,17 @@
}
}
+void
+__xfs_inode_clear_reclaim_tag(
+ xfs_mount_t *mp,
+ xfs_perag_t *pag,
+ xfs_inode_t *ip)
+{
+ radix_tree_tag_clear(&pag->pag_ici_root,
+ XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG);
+ __xfs_inode_clear_reclaim(pag, ip);
+}
+
/*
* Inodes in different states need to be treated differently, and the return
* value of xfs_iflush is not sufficient to get this right. The following table
@@ -838,6 +846,7 @@
if (!radix_tree_delete(&pag->pag_ici_root,
XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino)))
ASSERT(0);
+ __xfs_inode_clear_reclaim(pag, ip);
write_unlock(&pag->pag_ici_lock);
/*
diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c
index ed575fb..7e206fc 100644
--- a/fs/xfs/xfs_log_cil.c
+++ b/fs/xfs/xfs_log_cil.c
@@ -405,9 +405,15 @@
new_ctx = kmem_zalloc(sizeof(*new_ctx), KM_SLEEP|KM_NOFS);
new_ctx->ticket = xlog_cil_ticket_alloc(log);
- /* lock out transaction commit, but don't block on background push */
+ /*
+ * Lock out transaction commit, but don't block for background pushes
+ * unless we are well over the CIL space limit. See the definition of
+ * XLOG_CIL_HARD_SPACE_LIMIT() for the full explanation of the logic
+ * used here.
+ */
if (!down_write_trylock(&cil->xc_ctx_lock)) {
- if (!push_seq)
+ if (!push_seq &&
+ cil->xc_ctx->space_used < XLOG_CIL_HARD_SPACE_LIMIT(log))
goto out_free_ticket;
down_write(&cil->xc_ctx_lock);
}
@@ -422,7 +428,7 @@
goto out_skip;
/* check for a previously pushed seqeunce */
- if (push_seq < cil->xc_ctx->sequence)
+ if (push_seq && push_seq < cil->xc_ctx->sequence)
goto out_skip;
/*
diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h
index ced52b9..edcdfe0 100644
--- a/fs/xfs/xfs_log_priv.h
+++ b/fs/xfs/xfs_log_priv.h
@@ -426,13 +426,13 @@
};
/*
- * The amount of log space we should the CIL to aggregate is difficult to size.
- * Whatever we chose we have to make we can get a reservation for the log space
- * effectively, that it is large enough to capture sufficient relogging to
- * reduce log buffer IO significantly, but it is not too large for the log or
- * induces too much latency when writing out through the iclogs. We track both
- * space consumed and the number of vectors in the checkpoint context, so we
- * need to decide which to use for limiting.
+ * The amount of log space we allow the CIL to aggregate is difficult to size.
+ * Whatever we choose, we have to make sure we can get a reservation for the
+ * log space effectively, that it is large enough to capture sufficient
+ * relogging to reduce log buffer IO significantly, but it is not too large for
+ * the log or induces too much latency when writing out through the iclogs. We
+ * track both space consumed and the number of vectors in the checkpoint
+ * context, so we need to decide which to use for limiting.
*
* Every log buffer we write out during a push needs a header reserved, which
* is at least one sector and more for v2 logs. Hence we need a reservation of
@@ -459,16 +459,21 @@
* checkpoint transaction ticket is specific to the checkpoint context, rather
* than the CIL itself.
*
- * With dynamic reservations, we can basically make up arbitrary limits for the
- * checkpoint size so long as they don't violate any other size rules. Hence
- * the initial maximum size for the checkpoint transaction will be set to a
- * quarter of the log or 8MB, which ever is smaller. 8MB is an arbitrary limit
- * right now based on the latency of writing out a large amount of data through
- * the circular iclog buffers.
+ * With dynamic reservations, we can effectively make up arbitrary limits for
+ * the checkpoint size so long as they don't violate any other size rules.
+ * Recovery imposes a rule that no transaction exceed half the log, so we are
+ * limited by that. Furthermore, the log transaction reservation subsystem
+ * tries to keep 25% of the log free, so we need to keep below that limit or we
+ * risk running out of free log space to start any new transactions.
+ *
+ * In order to keep background CIL push efficient, we will set a lower
+ * threshold at which background pushing is attempted without blocking current
+ * transaction commits. A separate, higher bound defines when CIL pushes are
+ * enforced to ensure we stay within our maximum checkpoint size bounds.
+ * threshold, yet give us plenty of space for aggregation on large logs.
*/
-
-#define XLOG_CIL_SPACE_LIMIT(log) \
- (min((log->l_logsize >> 2), (8 * 1024 * 1024)))
+#define XLOG_CIL_SPACE_LIMIT(log) (log->l_logsize >> 3)
+#define XLOG_CIL_HARD_SPACE_LIMIT(log) (3 * (log->l_logsize >> 4))
/*
* The reservation head lsn is not made up of a cycle number and block number.
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index c0786d4..984cdc6 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -55,7 +55,7 @@
extern u8 acpi_gbl_permanent_mmap;
/*
- * Globals that are publically available, allowing for
+ * Globals that are publicly available, allowing for
* run time configuration
*/
extern u32 acpi_dbg_level;
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 7809d23..4c9461a 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -612,7 +612,7 @@
struct kref refcount;
/** Handle count of this object. Each handle also holds a reference */
- struct kref handlecount;
+ atomic_t handle_count; /* number of handles on this object */
/** Related drm device */
struct drm_device *dev;
@@ -808,7 +808,6 @@
*/
int (*gem_init_object) (struct drm_gem_object *obj);
void (*gem_free_object) (struct drm_gem_object *obj);
- void (*gem_free_object_unlocked) (struct drm_gem_object *obj);
/* vga arb irq handler */
void (*vgaarb_irq)(struct drm_device *dev, bool state);
@@ -1175,6 +1174,7 @@
extern int drm_mmap(struct file *filp, struct vm_area_struct *vma);
extern int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma);
extern void drm_vm_open_locked(struct vm_area_struct *vma);
+extern void drm_vm_close_locked(struct vm_area_struct *vma);
extern resource_size_t drm_core_get_map_ofs(struct drm_local_map * map);
extern resource_size_t drm_core_get_reg_ofs(struct drm_device *dev);
extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait);
@@ -1455,12 +1455,11 @@
void drm_gem_destroy(struct drm_device *dev);
void drm_gem_object_release(struct drm_gem_object *obj);
void drm_gem_object_free(struct kref *kref);
-void drm_gem_object_free_unlocked(struct kref *kref);
struct drm_gem_object *drm_gem_object_alloc(struct drm_device *dev,
size_t size);
int drm_gem_object_init(struct drm_device *dev,
struct drm_gem_object *obj, size_t size);
-void drm_gem_object_handle_free(struct kref *kref);
+void drm_gem_object_handle_free(struct drm_gem_object *obj);
void drm_gem_vm_open(struct vm_area_struct *vma);
void drm_gem_vm_close(struct vm_area_struct *vma);
int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
@@ -1483,8 +1482,12 @@
static inline void
drm_gem_object_unreference_unlocked(struct drm_gem_object *obj)
{
- if (obj != NULL)
- kref_put(&obj->refcount, drm_gem_object_free_unlocked);
+ if (obj != NULL) {
+ struct drm_device *dev = obj->dev;
+ mutex_lock(&dev->struct_mutex);
+ kref_put(&obj->refcount, drm_gem_object_free);
+ mutex_unlock(&dev->struct_mutex);
+ }
}
int drm_gem_handle_create(struct drm_file *file_priv,
@@ -1495,7 +1498,7 @@
drm_gem_object_handle_reference(struct drm_gem_object *obj)
{
drm_gem_object_reference(obj);
- kref_get(&obj->handlecount);
+ atomic_inc(&obj->handle_count);
}
static inline void
@@ -1504,12 +1507,15 @@
if (obj == NULL)
return;
+ if (atomic_read(&obj->handle_count) == 0)
+ return;
/*
* Must bump handle count first as this may be the last
* ref, in which case the object would disappear before we
* checked for a name
*/
- kref_put(&obj->handlecount, drm_gem_object_handle_free);
+ if (atomic_dec_and_test(&obj->handle_count))
+ drm_gem_object_handle_free(obj);
drm_gem_object_unreference(obj);
}
@@ -1519,12 +1525,17 @@
if (obj == NULL)
return;
+ if (atomic_read(&obj->handle_count) == 0)
+ return;
+
/*
* Must bump handle count first as this may be the last
* ref, in which case the object would disappear before we
* checked for a name
*/
- kref_put(&obj->handlecount, drm_gem_object_handle_free);
+
+ if (atomic_dec_and_test(&obj->handle_count))
+ drm_gem_object_handle_free(obj);
drm_gem_object_unreference_unlocked(obj);
}
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index c9f3cc5..3e5a51a 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -386,7 +386,15 @@
void (*dpms)(struct drm_connector *connector, int mode);
void (*save)(struct drm_connector *connector);
void (*restore)(struct drm_connector *connector);
- enum drm_connector_status (*detect)(struct drm_connector *connector);
+
+ /* Check to see if anything is attached to the connector.
+ * @force is set to false whilst polling, true when checking the
+ * connector due to user request. @force can be used by the driver
+ * to avoid expensive, destructive operations during automated
+ * probing.
+ */
+ enum drm_connector_status (*detect)(struct drm_connector *connector,
+ bool force);
int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height);
int (*set_property)(struct drm_connector *connector, struct drm_property *property,
uint64_t val);
diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h
index 3a9940e..883c1d4 100644
--- a/include/drm/drm_pciids.h
+++ b/include/drm/drm_pciids.h
@@ -85,7 +85,6 @@
{0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
{0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
{0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
- {0x1002, 0x5657, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
{0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
{0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
{0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
@@ -103,6 +102,7 @@
{0x1002, 0x564F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x5652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5657, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
{0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP}, \
{0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
{0x1002, 0x5954, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h
index 267a86c..2040e6c 100644
--- a/include/drm/ttm/ttm_bo_api.h
+++ b/include/drm/ttm/ttm_bo_api.h
@@ -246,9 +246,11 @@
atomic_t reserved;
-
/**
* Members protected by the bo::lock
+ * In addition, setting sync_obj to anything else
+ * than NULL requires bo::reserved to be held. This allows for
+ * checking NULL while reserved but not holding bo::lock.
*/
void *sync_obj_arg;
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 626b629..4e8ea8c 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -118,7 +118,6 @@
header-y += ext2_fs.h
header-y += fadvise.h
header-y += falloc.h
-header-y += fanotify.h
header-y += fb.h
header-y += fcntl.h
header-y += fd.h
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 9ddc878..5778b55 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -360,5 +360,8 @@
const struct compat_iovec __user *uvector, unsigned long nr_segs,
unsigned long fast_segs, struct iovec *fast_pointer,
struct iovec **ret_pointer);
+
+extern void __user *compat_alloc_user_space(unsigned long len);
+
#endif /* CONFIG_COMPAT */
#endif /* _LINUX_COMPAT_H */
diff --git a/include/linux/coredump.h b/include/linux/coredump.h
index 8ba66a9..ba4b85a 100644
--- a/include/linux/coredump.h
+++ b/include/linux/coredump.h
@@ -9,37 +9,7 @@
* These are the only things you should do on a core-file: use only these
* functions to write out all the necessary info.
*/
-static inline int dump_write(struct file *file, const void *addr, int nr)
-{
- return file->f_op->write(file, addr, nr, &file->f_pos) == nr;
-}
-
-static inline int dump_seek(struct file *file, loff_t off)
-{
- int ret = 1;
-
- if (file->f_op->llseek && file->f_op->llseek != no_llseek) {
- if (file->f_op->llseek(file, off, SEEK_CUR) < 0)
- return 0;
- } else {
- char *buf = (char *)get_zeroed_page(GFP_KERNEL);
-
- if (!buf)
- return 0;
- while (off > 0) {
- unsigned long n = off;
-
- if (n > PAGE_SIZE)
- n = PAGE_SIZE;
- if (!dump_write(file, buf, n)) {
- ret = 0;
- break;
- }
- off -= n;
- }
- free_page((unsigned long)buf);
- }
- return ret;
-}
+extern int dump_write(struct file *file, const void *addr, int nr);
+extern int dump_seek(struct file *file, loff_t off);
#endif /* _LINUX_COREDUMP_H */
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 36ca972..1be416b 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -53,6 +53,7 @@
#define CPUIDLE_FLAG_BALANCED (0x40) /* medium latency, moderate savings */
#define CPUIDLE_FLAG_DEEP (0x80) /* high latency, large savings */
#define CPUIDLE_FLAG_IGNORE (0x100) /* ignore during this idle period */
+#define CPUIDLE_FLAG_TLB_FLUSHED (0x200) /* tlb will be flushed */
#define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000)
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index ce29b81..ba8319a 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -102,6 +102,9 @@
return DMA_BIT_MASK(32);
}
+#ifdef ARCH_HAS_DMA_SET_COHERENT_MASK
+int dma_set_coherent_mask(struct device *dev, u64 mask);
+#else
static inline int dma_set_coherent_mask(struct device *dev, u64 mask)
{
if (!dma_supported(dev, mask))
@@ -109,6 +112,7 @@
dev->coherent_dma_mask = mask;
return 0;
}
+#endif
extern u64 dma_get_required_mask(struct device *dev);
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index c61d4ca..e210649 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -548,7 +548,7 @@
return (dma->max_pq & DMA_HAS_PQ_CONTINUE) == DMA_HAS_PQ_CONTINUE;
}
-static unsigned short dma_dev_to_maxpq(struct dma_device *dma)
+static inline unsigned short dma_dev_to_maxpq(struct dma_device *dma)
{
return dma->max_pq & ~DMA_HAS_PQ_CONTINUE;
}
diff --git a/include/linux/elevator.h b/include/linux/elevator.h
index 926b503..4fd978e 100644
--- a/include/linux/elevator.h
+++ b/include/linux/elevator.h
@@ -93,6 +93,7 @@
struct elevator_type *elevator_type;
struct mutex sysfs_lock;
struct hlist_head *hash;
+ unsigned int registered:1;
};
/*
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 76041b6..63d069b 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1093,6 +1093,10 @@
#include <linux/fcntl.h>
+/* temporary stubs for BKL removal */
+#define lock_flocks() lock_kernel()
+#define unlock_flocks() unlock_kernel()
+
extern void send_sigio(struct fown_struct *fown, int fd, int band);
#ifdef CONFIG_FILE_LOCKING
diff --git a/include/linux/gpio.h b/include/linux/gpio.h
index 03f616b..e41f7dd 100644
--- a/include/linux/gpio.h
+++ b/include/linux/gpio.h
@@ -13,6 +13,7 @@
#include <linux/errno.h>
struct device;
+struct gpio_chip;
/*
* Some platforms don't support the GPIO programming interface.
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
index 6de90bf..4793d8a 100644
--- a/include/linux/i2c/twl.h
+++ b/include/linux/i2c/twl.h
@@ -553,8 +553,12 @@
extern int twl4030_remove_script(u8 flags);
struct twl4030_codec_audio_data {
- unsigned int audio_mclk;
+ unsigned int audio_mclk; /* not used, will be removed */
+ unsigned int digimic_delay; /* in ms */
unsigned int ramp_delay_value;
+ unsigned int offset_cncl_path;
+ unsigned int check_defaults:1;
+ unsigned int reset_registers:1;
unsigned int hs_extmute:1;
void (*set_hs_extmute)(int mute);
};
diff --git a/include/linux/module.h b/include/linux/module.h
index 8a6b9fd..aace066 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -686,17 +686,16 @@
#ifdef CONFIG_GENERIC_BUG
-int module_bug_finalize(const Elf_Ehdr *, const Elf_Shdr *,
+void module_bug_finalize(const Elf_Ehdr *, const Elf_Shdr *,
struct module *);
void module_bug_cleanup(struct module *);
#else /* !CONFIG_GENERIC_BUG */
-static inline int module_bug_finalize(const Elf_Ehdr *hdr,
+static inline void module_bug_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs,
struct module *mod)
{
- return 0;
}
static inline void module_bug_cleanup(struct module *mod) {}
#endif /* CONFIG_GENERIC_BUG */
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 59d0669..1235669 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -27,8 +27,6 @@
#define MAX_LINKS 32
-struct net;
-
struct sockaddr_nl {
sa_family_t nl_family; /* AF_NETLINK */
unsigned short nl_pad; /* zero */
@@ -151,6 +149,8 @@
#include <linux/capability.h>
#include <linux/skbuff.h>
+struct net;
+
static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb)
{
return (struct nlmsghdr *)skb->data;
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index 791d510..50d8009 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -63,20 +63,20 @@
unsigned long flags;
bool ret = false;
- rcu_read_lock_bh();
+ local_irq_save(flags);
npinfo = rcu_dereference_bh(skb->dev->npinfo);
if (!npinfo || (list_empty(&npinfo->rx_np) && !npinfo->rx_flags))
goto out;
- spin_lock_irqsave(&npinfo->rx_lock, flags);
+ spin_lock(&npinfo->rx_lock);
/* check rx_flags again with the lock held */
if (npinfo->rx_flags && __netpoll_rx(skb))
ret = true;
- spin_unlock_irqrestore(&npinfo->rx_lock, flags);
+ spin_unlock(&npinfo->rx_lock);
out:
- rcu_read_unlock_bh();
+ local_irq_restore(flags);
return ret;
}
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 10d3330..570fdde 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -393,6 +393,9 @@
#define PCI_DEVICE_ID_VLSI_82C147 0x0105
#define PCI_DEVICE_ID_VLSI_VAS96011 0x0702
+/* AMD RD890 Chipset */
+#define PCI_DEVICE_ID_RD890_IOMMU 0x5a23
+
#define PCI_VENDOR_ID_ADL 0x1005
#define PCI_DEVICE_ID_ADL_2301 0x2301
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index d50ba85..d1a9193 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -274,8 +274,14 @@
int ret;
ret = dquot_alloc_space_nodirty(inode, nr);
- if (!ret)
- mark_inode_dirty_sync(inode);
+ if (!ret) {
+ /*
+ * Mark inode fully dirty. Since we are allocating blocks, inode
+ * would become fully dirty soon anyway and it reportedly
+ * reduces inode_lock contention.
+ */
+ mark_inode_dirty(inode);
+ }
return ret;
}
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 9fbc54a..83af1f8 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -454,7 +454,7 @@
* Makes rcu_dereference_check() do the dirty work.
*/
#define rcu_dereference_bh(p) \
- rcu_dereference_check(p, rcu_read_lock_bh_held())
+ rcu_dereference_check(p, rcu_read_lock_bh_held() || irqs_disabled())
/**
* rcu_dereference_sched - fetch RCU-protected pointer, checking for RCU-sched
diff --git a/include/linux/socket.h b/include/linux/socket.h
index a2fada9..a8f56e1 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -322,7 +322,7 @@
int offset,
unsigned int len, __wsum *csump);
-extern int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address, int mode);
+extern long verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address, int mode);
extern int memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len);
extern int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata,
int offset, int len);
diff --git a/include/linux/spi/dw_spi.h b/include/linux/spi/dw_spi.h
index cc813f9..c91302f 100644
--- a/include/linux/spi/dw_spi.h
+++ b/include/linux/spi/dw_spi.h
@@ -14,7 +14,9 @@
#define SPI_MODE_OFFSET 6
#define SPI_SCPH_OFFSET 6
#define SPI_SCOL_OFFSET 7
+
#define SPI_TMOD_OFFSET 8
+#define SPI_TMOD_MASK (0x3 << SPI_TMOD_OFFSET)
#define SPI_TMOD_TR 0x0 /* xmit & recv */
#define SPI_TMOD_TO 0x1 /* xmit only */
#define SPI_TMOD_RO 0x2 /* recv only */
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 569dc72..85f38a63 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -30,7 +30,7 @@
* The high-level client handle
*/
struct rpc_clnt {
- struct kref cl_kref; /* Number of references */
+ atomic_t cl_count; /* Number of references */
struct list_head cl_clients; /* Global list of clients */
struct list_head cl_tasks; /* List of tasks */
spinlock_t cl_lock; /* spinlock */
diff --git a/include/linux/types.h b/include/linux/types.h
index 01a082f..357dbc1 100644
--- a/include/linux/types.h
+++ b/include/linux/types.h
@@ -121,7 +121,15 @@
typedef __s64 int64_t;
#endif
-/* this is a special 64bit data type that is 8-byte aligned */
+/*
+ * aligned_u64 should be used in defining kernel<->userspace ABIs to avoid
+ * common 32/64-bit compat problems.
+ * 64-bit values align to 4-byte boundaries on x86_32 (and possibly other
+ * architectures) and to 8-byte boundaries on 64-bit architetures. The new
+ * aligned_64 type enforces 8-byte alignment so that structs containing
+ * aligned_64 values have the same alignment on 32-bit and 64-bit architectures.
+ * No conversions are necessary between 32-bit user-space and a 64-bit kernel.
+ */
#define aligned_u64 __u64 __attribute__((aligned(8)))
#define aligned_be64 __be64 __attribute__((aligned(8)))
#define aligned_le64 __le64 __attribute__((aligned(8)))
@@ -178,6 +186,11 @@
typedef __u16 __bitwise __sum16;
typedef __u32 __bitwise __wsum;
+/* this is a special 64bit data type that is 8-byte aligned */
+#define __aligned_u64 __u64 __attribute__((aligned(8)))
+#define __aligned_be64 __be64 __attribute__((aligned(8)))
+#define __aligned_le64 __le64 __attribute__((aligned(8)))
+
#ifdef __KERNEL__
typedef unsigned __bitwise__ gfp_t;
typedef unsigned __bitwise__ fmode_t;
diff --git a/include/linux/wait.h b/include/linux/wait.h
index 0836ccc..3efc9f3 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -614,6 +614,7 @@
(wait)->private = current; \
(wait)->func = autoremove_wake_function; \
INIT_LIST_HEAD(&(wait)->task_list); \
+ (wait)->flags = 0; \
} while (0)
/**
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index f11100f..25e02c9 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -235,6 +235,10 @@
#define work_clear_pending(work) \
clear_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))
+/*
+ * Workqueue flags and constants. For details, please refer to
+ * Documentation/workqueue.txt.
+ */
enum {
WQ_NON_REENTRANT = 1 << 0, /* guarantee non-reentrance */
WQ_UNBOUND = 1 << 1, /* not bound to any cpu */
diff --git a/include/media/videobuf-dma-sg.h b/include/media/videobuf-dma-sg.h
index 97e07f4..aa4ebb4 100644
--- a/include/media/videobuf-dma-sg.h
+++ b/include/media/videobuf-dma-sg.h
@@ -48,6 +48,7 @@
/* for userland buffer */
int offset;
+ size_t size;
struct page **pages;
/* for kernel buffers */
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index 45375b4..4d40c4d 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -121,6 +121,7 @@
* IPv6 Address Label subsystem (addrlabel.c)
*/
extern int ipv6_addr_label_init(void);
+extern void ipv6_addr_label_cleanup(void);
extern void ipv6_addr_label_rtnl_register(void);
extern u32 ipv6_addr_label(struct net *net,
const struct in6_addr *addr,
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 27a902d..30fce01 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -161,12 +161,30 @@
{
struct sk_buff *skb;
+ release_sock(sk);
if ((skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err))) {
skb_reserve(skb, BT_SKB_RESERVE);
bt_cb(skb)->incoming = 0;
}
+ lock_sock(sk);
+
+ if (!skb && *err)
+ return NULL;
+
+ *err = sock_error(sk);
+ if (*err)
+ goto out;
+
+ if (sk->sk_shutdown) {
+ *err = -ECONNRESET;
+ goto out;
+ }
return skb;
+
+out:
+ kfree_skb(skb);
+ return NULL;
}
int bt_err(__u16 code);
diff --git a/include/net/dst.h b/include/net/dst.h
index 81d1413..0238650 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -242,6 +242,7 @@
dev->stats.rx_packets++;
dev->stats.rx_bytes += skb->len;
skb->rxhash = 0;
+ skb_set_queue_mapping(skb, 0);
skb_dst_drop(skb);
nf_reset(skb);
}
diff --git a/include/net/route.h b/include/net/route.h
index bd732d6..7e5e73b 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -199,6 +199,8 @@
fl.fl_ip_sport = sport;
fl.fl_ip_dport = dport;
fl.proto = protocol;
+ if (inet_sk(sk)->transparent)
+ fl.flags |= FLOWI_FLAG_ANYSRC;
ip_rt_put(*rp);
*rp = NULL;
security_sk_classify_flow(sk, &fl);
diff --git a/include/net/tcp.h b/include/net/tcp.h
index eaa9582..3e4b33e 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -475,8 +475,22 @@
/* Bound MSS / TSO packet size with the half of the window */
static inline int tcp_bound_to_half_wnd(struct tcp_sock *tp, int pktsize)
{
- if (tp->max_window && pktsize > (tp->max_window >> 1))
- return max(tp->max_window >> 1, 68U - tp->tcp_header_len);
+ int cutoff;
+
+ /* When peer uses tiny windows, there is no use in packetizing
+ * to sub-MSS pieces for the sake of SWS or making sure there
+ * are enough packets in the pipe for fast recovery.
+ *
+ * On the other hand, for extremely large MSS devices, handling
+ * smaller than MSS windows in this way does make sense.
+ */
+ if (tp->max_window >= 512)
+ cutoff = (tp->max_window >> 1);
+ else
+ cutoff = tp->max_window;
+
+ if (cutoff && pktsize > cutoff)
+ return max_t(int, cutoff, 68U - tp->tcp_header_len);
else
return pktsize;
}
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index fc8f36d..4f53532 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -298,8 +298,8 @@
const struct xfrm_type *type_map[IPPROTO_MAX];
struct xfrm_mode *mode_map[XFRM_MODE_MAX];
int (*init_flags)(struct xfrm_state *x);
- void (*init_tempsel)(struct xfrm_state *x, struct flowi *fl,
- struct xfrm_tmpl *tmpl,
+ void (*init_tempsel)(struct xfrm_selector *sel, struct flowi *fl);
+ void (*init_temprop)(struct xfrm_state *x, struct xfrm_tmpl *tmpl,
xfrm_address_t *daddr, xfrm_address_t *saddr);
int (*tmpl_sort)(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n);
int (*state_sort)(struct xfrm_state **dst, struct xfrm_state **src, int n);
diff --git a/include/sound/core.h b/include/sound/core.h
index 89e0ac1..c129f08 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -179,7 +179,7 @@
#define snd_power_lock(card) do { (void)(card); } while (0)
#define snd_power_unlock(card) do { (void)(card); } while (0)
static inline int snd_power_wait(struct snd_card *card, unsigned int state) { return 0; }
-#define snd_power_get_state(card) SNDRV_CTL_POWER_D0
+#define snd_power_get_state(card) ({ (void)(card); SNDRV_CTL_POWER_D0; })
#define snd_power_change_state(card, state) do { (void)(card); } while (0)
#endif /* CONFIG_PM */
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 7dc97d1..4f865df 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -438,6 +438,8 @@
#define CCCA_CURRADDR_MASK 0x00ffffff /* Current address of the selected channel */
#define CCCA_CURRADDR 0x18000008
+/* undefine CCR to avoid conflict with the definition for SH */
+#undef CCR
#define CCR 0x09 /* Cache control register */
#define CCR_CACHEINVALIDSIZE 0x07190009
#define CCR_CACHEINVALIDSIZE_MASK 0xfe000000 /* Number of invalid samples cache for this channel */
diff --git a/include/sound/jack.h b/include/sound/jack.h
index d90b9fa..c140fc7 100644
--- a/include/sound/jack.h
+++ b/include/sound/jack.h
@@ -47,6 +47,9 @@
SND_JACK_BTN_0 = 0x4000,
SND_JACK_BTN_1 = 0x2000,
SND_JACK_BTN_2 = 0x1000,
+ SND_JACK_BTN_3 = 0x0800,
+ SND_JACK_BTN_4 = 0x0400,
+ SND_JACK_BTN_5 = 0x0200,
};
struct snd_jack {
@@ -55,7 +58,7 @@
int type;
const char *id;
char name[100];
- unsigned int key[3]; /* Keep in sync with definitions above */
+ unsigned int key[6]; /* Keep in sync with definitions above */
void *private_data;
void (*private_free)(struct snd_jack *);
};
diff --git a/include/sound/max98088.h b/include/sound/max98088.h
new file mode 100644
index 0000000..c3ba823
--- /dev/null
+++ b/include/sound/max98088.h
@@ -0,0 +1,50 @@
+/*
+ * Platform data for MAX98088
+ *
+ * Copyright 2010 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef __SOUND_MAX98088_PDATA_H__
+#define __SOUND_MAX98088_PDATA_H__
+
+/* Equalizer filter response configuration */
+struct max98088_eq_cfg {
+ const char *name;
+ unsigned int rate;
+ u16 band1[5];
+ u16 band2[5];
+ u16 band3[5];
+ u16 band4[5];
+ u16 band5[5];
+};
+
+/* codec platform data */
+struct max98088_pdata {
+
+ /* Equalizers for DAI1 and DAI2 */
+ struct max98088_eq_cfg *eq_cfg;
+ unsigned int eq_cfgcnt;
+
+ /* Receiver output can be configured as power amplifier or LINE out */
+ /* Set receiver_mode to:
+ * 0 = amplifier output, or
+ * 1 = LINE level output
+ */
+ unsigned int receiver_mode:1;
+
+ /* Analog/digital microphone configuration:
+ * 0 = analog microphone input (normal setting)
+ * 1 = digital microphone input
+ */
+ unsigned int digmic_left_mode:1;
+ unsigned int digmic_right_mode:1;
+
+};
+
+#endif
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 85f1c6b..dfd9b76 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -278,6 +278,7 @@
snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */
snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */
unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */
+ unsigned long hw_ptr_buffer_jiffies; /* buffer time in jiffies */
snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */
/* -- HW params -- */
diff --git a/include/sound/sh_fsi.h b/include/sound/sh_fsi.h
index 9d51d6f..fa60cbd 100644
--- a/include/sound/sh_fsi.h
+++ b/include/sound/sh_fsi.h
@@ -114,7 +114,4 @@
int (*set_rate)(int is_porta, int rate); /* for master mode */
};
-extern struct snd_soc_dai fsi_soc_dai[2];
-extern struct snd_soc_platform fsi_soc_platform;
-
#endif /* __SOUND_FSI_H */
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 377693a..e7b6802 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -91,15 +91,17 @@
SNDRV_PCM_FMTBIT_S32_LE |\
SNDRV_PCM_FMTBIT_S32_BE)
-struct snd_soc_dai_ops;
+struct snd_soc_dai_driver;
struct snd_soc_dai;
struct snd_ac97_bus_ops;
/* Digital Audio Interface registration */
-int snd_soc_register_dai(struct snd_soc_dai *dai);
-void snd_soc_unregister_dai(struct snd_soc_dai *dai);
-int snd_soc_register_dais(struct snd_soc_dai *dai, size_t count);
-void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count);
+int snd_soc_register_dai(struct device *dev,
+ struct snd_soc_dai_driver *dai_drv);
+void snd_soc_unregister_dai(struct device *dev);
+int snd_soc_register_dais(struct device *dev,
+ struct snd_soc_dai_driver *dai_drv, size_t count);
+void snd_soc_unregister_dais(struct device *dev, size_t count);
/* Digital Audio Interface clocking API.*/
int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
@@ -126,16 +128,6 @@
/* Digital Audio Interface mute */
int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute);
-/*
- * Digital Audio Interface.
- *
- * Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97
- * operations and capabilities. Codec and platform drivers will register this
- * structure for every DAI they have.
- *
- * This structure covers the clocking, formating and ALSA operations for each
- * interface.
- */
struct snd_soc_dai_ops {
/*
* DAI clocking configuration, all optional.
@@ -191,24 +183,24 @@
};
/*
- * Digital Audio Interface runtime data.
+ * Digital Audio Interface Driver.
*
- * Holds runtime data for a DAI.
+ * Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97
+ * operations and capabilities. Codec and platform drivers will register this
+ * structure for every DAI they have.
+ *
+ * This structure covers the clocking, formating and ALSA operations for each
+ * interface.
*/
-struct snd_soc_dai {
+struct snd_soc_dai_driver {
/* DAI description */
- char *name;
+ const char *name;
unsigned int id;
int ac97_control;
- struct device *dev;
- void *ac97_pdata; /* platform_data for the ac97 codec */
-
- /* DAI callbacks */
- int (*probe)(struct platform_device *pdev,
- struct snd_soc_dai *dai);
- void (*remove)(struct platform_device *pdev,
- struct snd_soc_dai *dai);
+ /* DAI driver callbacks */
+ int (*probe)(struct snd_soc_dai *dai);
+ int (*remove)(struct snd_soc_dai *dai);
int (*suspend)(struct snd_soc_dai *dai);
int (*resume)(struct snd_soc_dai *dai);
@@ -219,26 +211,51 @@
struct snd_soc_pcm_stream capture;
struct snd_soc_pcm_stream playback;
unsigned int symmetric_rates:1;
+};
+
+/*
+ * Digital Audio Interface runtime data.
+ *
+ * Holds runtime data for a DAI.
+ */
+struct snd_soc_dai {
+ const char *name;
+ int id;
+ struct device *dev;
+ void *ac97_pdata; /* platform_data for the ac97 codec */
+
+ /* driver ops */
+ struct snd_soc_dai_driver *driver;
/* DAI runtime info */
- struct snd_soc_codec *codec;
+ unsigned int capture_active:1; /* stream is in use */
+ unsigned int playback_active:1; /* stream is in use */
+ unsigned int symmetric_rates:1;
+ struct snd_pcm_runtime *runtime;
unsigned int active;
unsigned char pop_wait:1;
+ unsigned char probed:1;
- /* DAI private data */
- void *private_data;
+ /* DAI DMA data */
+ void *playback_dma_data;
+ void *capture_dma_data;
- /* parent platform */
- struct snd_soc_platform *platform;
+ /* parent platform/codec */
+ union {
+ struct snd_soc_platform *platform;
+ struct snd_soc_codec *codec;
+ };
+ struct snd_soc_card *card;
struct list_head list;
+ struct list_head card_list;
};
static inline void *snd_soc_dai_get_dma_data(const struct snd_soc_dai *dai,
const struct snd_pcm_substream *ss)
{
return (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
- dai->playback.dma_data : dai->capture.dma_data;
+ dai->playback_dma_data : dai->capture_dma_data;
}
static inline void snd_soc_dai_set_dma_data(struct snd_soc_dai *dai,
@@ -246,9 +263,20 @@
void *data)
{
if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
- dai->playback.dma_data = data;
+ dai->playback_dma_data = data;
else
- dai->capture.dma_data = data;
+ dai->capture_dma_data = data;
+}
+
+static inline void snd_soc_dai_set_drvdata(struct snd_soc_dai *dai,
+ void *data)
+{
+ dev_set_drvdata(dai->dev, data);
+}
+
+static inline void *snd_soc_dai_get_drvdata(struct snd_soc_dai *dai)
+{
+ return dev_get_drvdata(dai->dev);
}
#endif
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index c5d9987..8fd3b41 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -172,9 +172,19 @@
#define SND_SOC_DAPM_AIF_IN(wname, stname, wslot, wreg, wshift, winvert) \
{ .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
.reg = wreg, .shift = wshift, .invert = winvert }
+#define SND_SOC_DAPM_AIF_IN_E(wname, stname, wslot, wreg, wshift, winvert, \
+ wevent, wflags) \
+{ .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
+ .reg = wreg, .shift = wshift, .invert = winvert, \
+ .event = wevent, .event_flags = wflags }
#define SND_SOC_DAPM_AIF_OUT(wname, stname, wslot, wreg, wshift, winvert) \
{ .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
.reg = wreg, .shift = wshift, .invert = winvert }
+#define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wslot, wreg, wshift, winvert, \
+ wevent, wflags) \
+{ .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
+ .reg = wreg, .shift = wshift, .invert = winvert, \
+ .event = wevent, .event_flags = wflags }
#define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
{ .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
.shift = wshift, .invert = winvert}
@@ -322,14 +332,14 @@
/* dapm path setup */
int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec);
-void snd_soc_dapm_free(struct snd_soc_device *socdev);
+void snd_soc_dapm_free(struct snd_soc_codec *codec);
int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
const struct snd_soc_dapm_route *route, int num);
/* dapm events */
-int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream,
- int event);
-void snd_soc_dapm_shutdown(struct snd_soc_device *socdev);
+int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
+ const char *stream, int event);
+void snd_soc_dapm_shutdown(struct snd_soc_card *card);
/* dapm sys fs - used by the core */
int snd_soc_dapm_sys_add(struct device *dev);
diff --git a/include/sound/soc-of-simple.h b/include/sound/soc-of-simple.h
deleted file mode 100644
index a064e19..0000000
--- a/include/sound/soc-of-simple.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * OF helpers for ALSA SoC
- *
- * Copyright (C) 2008, Secret Lab Technologies Ltd.
- */
-
-#ifndef _INCLUDE_SOC_OF_H_
-#define _INCLUDE_SOC_OF_H_
-
-#if defined(CONFIG_SND_SOC_OF_SIMPLE) || defined(CONFIG_SND_SOC_OF_SIMPLE_MODULE)
-
-#include <linux/of.h>
-#include <sound/soc.h>
-
-int of_snd_soc_register_codec(struct snd_soc_codec_device *codec_dev,
- void *codec_data, struct snd_soc_dai *dai,
- struct device_node *node);
-
-int of_snd_soc_register_platform(struct snd_soc_platform *platform,
- struct device_node *node,
- struct snd_soc_dai *cpu_dai);
-
-#endif
-
-#endif /* _INCLUDE_SOC_OF_H_ */
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 65e9d03..5c3bce8 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -214,10 +214,10 @@
* @OFF: Power Off. No restrictions on transition times.
*/
enum snd_soc_bias_level {
- SND_SOC_BIAS_ON,
- SND_SOC_BIAS_PREPARE,
- SND_SOC_BIAS_STANDBY,
SND_SOC_BIAS_OFF,
+ SND_SOC_BIAS_STANDBY,
+ SND_SOC_BIAS_PREPARE,
+ SND_SOC_BIAS_ON,
};
struct snd_jack;
@@ -228,13 +228,17 @@
struct snd_soc_dai_mode;
struct snd_soc_pcm_runtime;
struct snd_soc_dai;
+struct snd_soc_dai_driver;
struct snd_soc_platform;
struct snd_soc_dai_link;
+struct snd_soc_platform_driver;
struct snd_soc_codec;
+struct snd_soc_codec_driver;
struct soc_enum;
struct snd_soc_ac97_ops;
struct snd_soc_jack;
struct snd_soc_jack_pin;
+
#ifdef CONFIG_GPIOLIB
struct snd_soc_jack_gpio;
#endif
@@ -249,19 +253,18 @@
SND_SOC_SPI,
};
-int snd_soc_register_platform(struct snd_soc_platform *platform);
-void snd_soc_unregister_platform(struct snd_soc_platform *platform);
-int snd_soc_register_codec(struct snd_soc_codec *codec);
-void snd_soc_unregister_codec(struct snd_soc_codec *codec);
+int snd_soc_register_platform(struct device *dev,
+ struct snd_soc_platform_driver *platform_drv);
+void snd_soc_unregister_platform(struct device *dev);
+int snd_soc_register_codec(struct device *dev,
+ struct snd_soc_codec_driver *codec_drv,
+ struct snd_soc_dai_driver *dai_drv, int num_dai);
+void snd_soc_unregister_codec(struct device *dev);
int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg);
int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
int addr_bits, int data_bits,
enum snd_soc_control_type control);
-/* pcm <-> DAI connect */
-void snd_soc_free_pcms(struct snd_soc_device *socdev);
-int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid);
-
/* Utility functions to get clock rates from various things */
int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
@@ -273,7 +276,7 @@
const struct snd_pcm_hardware *hw);
/* Jack reporting */
-int snd_soc_jack_new(struct snd_soc_card *card, const char *id, int type,
+int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
struct snd_soc_jack *jack);
void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask);
int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
@@ -382,7 +385,7 @@
int invert;
int debounce_time;
struct snd_soc_jack *jack;
- struct work_struct work;
+ struct delayed_work work;
int (*jack_status_check)(void);
};
@@ -390,7 +393,7 @@
struct snd_soc_jack {
struct snd_jack *jack;
- struct snd_soc_card *card;
+ struct snd_soc_codec *codec;
struct list_head pins;
int status;
struct blocking_notifier_head notifier;
@@ -398,15 +401,13 @@
/* SoC PCM stream information */
struct snd_soc_pcm_stream {
- char *stream_name;
+ const char *stream_name;
u64 formats; /* SNDRV_PCM_FMTBIT_* */
unsigned int rates; /* SNDRV_PCM_RATE_* */
unsigned int rate_min; /* min rate */
unsigned int rate_max; /* max rate */
unsigned int channels_min; /* min channels */
unsigned int channels_max; /* max channels */
- unsigned int active; /* stream is in use */
- void *dma_data; /* used by platform code */
};
/* SoC audio ops */
@@ -419,44 +420,36 @@
int (*trigger)(struct snd_pcm_substream *, int);
};
-/* SoC Audio Codec */
+/* SoC Audio Codec device */
struct snd_soc_codec {
- char *name;
- struct module *owner;
- struct mutex mutex;
+ const char *name;
+ int id;
struct device *dev;
- struct snd_soc_device *socdev;
+ struct snd_soc_codec_driver *driver;
+ struct mutex mutex;
+ struct snd_soc_card *card;
struct list_head list;
-
- /* callbacks */
- int (*set_bias_level)(struct snd_soc_codec *,
- enum snd_soc_bias_level level);
+ struct list_head card_list;
+ int num_dai;
/* runtime */
- struct snd_card *card;
struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */
unsigned int active;
- unsigned int pcm_devs;
- void *drvdata;
-
- /* codec IO */
- void *control_data; /* codec control (i2c/3wire) data */
- unsigned int (*read)(struct snd_soc_codec *, unsigned int);
- int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
- int (*display_register)(struct snd_soc_codec *, char *,
- size_t, unsigned int);
- int (*volatile_register)(unsigned int);
- int (*readable_register)(unsigned int);
- hw_write_t hw_write;
- unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
- void *reg_cache;
- short reg_cache_size;
- short reg_cache_step;
-
unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
unsigned int cache_only:1; /* Suppress writes to hardware */
unsigned int cache_sync:1; /* Cache needs to be synced to hardware */
+ unsigned int suspended:1; /* Codec is in suspend PM state */
+ unsigned int probed:1; /* Codec has been probed */
+ unsigned int ac97_registered:1; /* Codec has been AC97 registered */
+ unsigned int ac97_created:1; /* Codec has been created by SoC */
+ unsigned int sysfs_registered:1; /* codec has been sysfs registered */
+
+ /* codec IO */
+ void *control_data; /* codec control (i2c/3wire) data */
+ hw_write_t hw_write;
+ unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
+ void *reg_cache;
/* dapm */
u32 pop_time;
@@ -466,10 +459,6 @@
enum snd_soc_bias_level suspend_bias_level;
struct delayed_work delayed_work;
- /* codec DAI's */
- struct snd_soc_dai *dai;
- unsigned int num_dai;
-
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_codec_root;
struct dentry *debugfs_reg;
@@ -478,23 +467,40 @@
#endif
};
-/* codec device */
-struct snd_soc_codec_device {
- int (*probe)(struct platform_device *pdev);
- int (*remove)(struct platform_device *pdev);
- int (*suspend)(struct platform_device *pdev, pm_message_t state);
- int (*resume)(struct platform_device *pdev);
+/* codec driver */
+struct snd_soc_codec_driver {
+
+ /* driver ops */
+ int (*probe)(struct snd_soc_codec *);
+ int (*remove)(struct snd_soc_codec *);
+ int (*suspend)(struct snd_soc_codec *,
+ pm_message_t state);
+ int (*resume)(struct snd_soc_codec *);
+
+ /* codec IO */
+ unsigned int (*read)(struct snd_soc_codec *, unsigned int);
+ int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
+ int (*display_register)(struct snd_soc_codec *, char *,
+ size_t, unsigned int);
+ int (*volatile_register)(unsigned int);
+ int (*readable_register)(unsigned int);
+ short reg_cache_size;
+ short reg_cache_step;
+ short reg_word_size;
+ const void *reg_cache_default;
+
+ /* codec bias level */
+ int (*set_bias_level)(struct snd_soc_codec *,
+ enum snd_soc_bias_level level);
};
/* SoC platform interface */
-struct snd_soc_platform {
- char *name;
- struct list_head list;
+struct snd_soc_platform_driver {
- int (*probe)(struct platform_device *pdev);
- int (*remove)(struct platform_device *pdev);
- int (*suspend)(struct snd_soc_dai_link *dai_link);
- int (*resume)(struct snd_soc_dai_link *dai_link);
+ int (*probe)(struct snd_soc_platform *);
+ int (*remove)(struct snd_soc_platform *);
+ int (*suspend)(struct snd_soc_dai *dai);
+ int (*resume)(struct snd_soc_dai *dai);
/* pcm creation and destruction */
int (*pcm_new)(struct snd_card *, struct snd_soc_dai *,
@@ -509,23 +515,31 @@
struct snd_soc_dai *);
/* platform stream ops */
- struct snd_pcm_ops *pcm_ops;
+ struct snd_pcm_ops *ops;
};
-/* SoC machine DAI configuration, glues a codec and cpu DAI together */
-struct snd_soc_dai_link {
- char *name; /* Codec name */
- char *stream_name; /* Stream name */
+struct snd_soc_platform {
+ const char *name;
+ int id;
+ struct device *dev;
+ struct snd_soc_platform_driver *driver;
- /* DAI */
- struct snd_soc_dai *codec_dai;
- struct snd_soc_dai *cpu_dai;
+ unsigned int suspended:1; /* platform is suspended */
+ unsigned int probed:1;
- /* machine stream operations */
- struct snd_soc_ops *ops;
+ struct snd_soc_card *card;
+ struct list_head list;
+ struct list_head card_list;
+};
- /* codec/machine specific init - e.g. add machine controls */
- int (*init)(struct snd_soc_codec *codec);
+struct snd_soc_dai_link {
+ /* config - must be set by machine driver */
+ const char *name; /* Codec name */
+ const char *stream_name; /* Stream name */
+ const char *codec_name; /* for multi-codec */
+ const char *platform_name; /* for multi-platform */
+ const char *cpu_dai_name;
+ const char *codec_dai_name;
/* Keep DAI active over suspend */
unsigned int ignore_suspend:1;
@@ -533,21 +547,24 @@
/* Symmetry requirements */
unsigned int symmetric_rates:1;
- /* Symmetry data - only valid if symmetry is being enforced */
- unsigned int rate;
+ /* codec/machine specific init - e.g. add machine controls */
+ int (*init)(struct snd_soc_pcm_runtime *rtd);
- /* DAI pcm */
- struct snd_pcm *pcm;
+ /* machine stream operations */
+ struct snd_soc_ops *ops;
};
/* SoC card */
struct snd_soc_card {
- char *name;
+ const char *name;
struct device *dev;
+ struct snd_card *snd_card;
+ struct module *owner;
struct list_head list;
+ struct mutex mutex;
- int instantiated;
+ bool instantiated;
int (*probe)(struct platform_device *pdev);
int (*remove)(struct platform_device *pdev);
@@ -568,28 +585,38 @@
/* CPU <--> Codec DAI links */
struct snd_soc_dai_link *dai_link;
int num_links;
+ struct snd_soc_pcm_runtime *rtd;
+ int num_rtd;
- struct snd_soc_device *socdev;
-
- struct snd_soc_codec *codec;
-
- struct snd_soc_platform *platform;
- struct delayed_work delayed_work;
struct work_struct deferred_resume_work;
+
+ /* lists of probed devices belonging to this card */
+ struct list_head codec_dev_list;
+ struct list_head platform_dev_list;
+ struct list_head dai_dev_list;
};
-/* SoC Device - the audio subsystem */
-struct snd_soc_device {
- struct device *dev;
+/* SoC machine DAI configuration, glues a codec and cpu DAI together */
+struct snd_soc_pcm_runtime {
+ struct device dev;
struct snd_soc_card *card;
- struct snd_soc_codec_device *codec_dev;
- void *codec_data;
-};
+ struct snd_soc_dai_link *dai_link;
-/* runtime channel data */
-struct snd_soc_pcm_runtime {
- struct snd_soc_dai_link *dai;
- struct snd_soc_device *socdev;
+ unsigned int complete:1;
+ unsigned int dev_registered:1;
+
+ /* Symmetry data - only valid if symmetry is being enforced */
+ unsigned int rate;
+ long pmdown_time;
+
+ /* runtime devices */
+ struct snd_pcm *pcm;
+ struct snd_soc_codec *codec;
+ struct snd_soc_platform *platform;
+ struct snd_soc_dai *codec_dai;
+ struct snd_soc_dai *cpu_dai;
+
+ struct delayed_work delayed_work;
};
/* mixer control */
@@ -615,24 +642,48 @@
static inline unsigned int snd_soc_read(struct snd_soc_codec *codec,
unsigned int reg)
{
- return codec->read(codec, reg);
+ return codec->driver->read(codec, reg);
}
static inline unsigned int snd_soc_write(struct snd_soc_codec *codec,
unsigned int reg, unsigned int val)
{
- return codec->write(codec, reg, val);
+ return codec->driver->write(codec, reg, val);
}
+/* device driver data */
+
static inline void snd_soc_codec_set_drvdata(struct snd_soc_codec *codec,
- void *data)
+ void *data)
{
- codec->drvdata = data;
+ dev_set_drvdata(codec->dev, data);
}
static inline void *snd_soc_codec_get_drvdata(struct snd_soc_codec *codec)
{
- return codec->drvdata;
+ return dev_get_drvdata(codec->dev);
+}
+
+static inline void snd_soc_platform_set_drvdata(struct snd_soc_platform *platform,
+ void *data)
+{
+ dev_set_drvdata(platform->dev, data);
+}
+
+static inline void *snd_soc_platform_get_drvdata(struct snd_soc_platform *platform)
+{
+ return dev_get_drvdata(platform->dev);
+}
+
+static inline void snd_soc_pcm_set_drvdata(struct snd_soc_pcm_runtime *rtd,
+ void *data)
+{
+ dev_set_drvdata(&rtd->dev, data);
+}
+
+static inline void *snd_soc_pcm_get_drvdata(struct snd_soc_pcm_runtime *rtd)
+{
+ return dev_get_drvdata(&rtd->dev);
}
#include <sound/soc-dai.h>
diff --git a/include/sound/tlv320aic3x.h b/include/sound/tlv320aic3x.h
index b1a5f34..99e0308 100644
--- a/include/sound/tlv320aic3x.h
+++ b/include/sound/tlv320aic3x.h
@@ -10,8 +10,49 @@
#ifndef __TLV320AIC3x_H__
#define __TLV320AIC3x_H__
-struct aic3x_pdata {
- int gpio_reset; /* < 0 if not used */
+/* GPIO API */
+enum {
+ AIC3X_GPIO1_FUNC_DISABLED = 0,
+ AIC3X_GPIO1_FUNC_AUDIO_WORDCLK_ADC = 1,
+ AIC3X_GPIO1_FUNC_CLOCK_MUX = 2,
+ AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV2 = 3,
+ AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV4 = 4,
+ AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV8 = 5,
+ AIC3X_GPIO1_FUNC_SHORT_CIRCUIT_IRQ = 6,
+ AIC3X_GPIO1_FUNC_AGC_NOISE_IRQ = 7,
+ AIC3X_GPIO1_FUNC_INPUT = 8,
+ AIC3X_GPIO1_FUNC_OUTPUT = 9,
+ AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK = 10,
+ AIC3X_GPIO1_FUNC_AUDIO_WORDCLK = 11,
+ AIC3X_GPIO1_FUNC_BUTTON_IRQ = 12,
+ AIC3X_GPIO1_FUNC_HEADSET_DETECT_IRQ = 13,
+ AIC3X_GPIO1_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 14,
+ AIC3X_GPIO1_FUNC_ALL_IRQ = 16
};
-#endif
\ No newline at end of file
+enum {
+ AIC3X_GPIO2_FUNC_DISABLED = 0,
+ AIC3X_GPIO2_FUNC_HEADSET_DETECT_IRQ = 2,
+ AIC3X_GPIO2_FUNC_INPUT = 3,
+ AIC3X_GPIO2_FUNC_OUTPUT = 4,
+ AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT = 5,
+ AIC3X_GPIO2_FUNC_AUDIO_BITCLK = 8,
+ AIC3X_GPIO2_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 9,
+ AIC3X_GPIO2_FUNC_ALL_IRQ = 10,
+ AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_OR_AGC_IRQ = 11,
+ AIC3X_GPIO2_FUNC_HEADSET_OR_BUTTON_PRESS_OR_SHORT_CIRCUIT_IRQ = 12,
+ AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_IRQ = 13,
+ AIC3X_GPIO2_FUNC_AGC_NOISE_IRQ = 14,
+ AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ = 15
+};
+
+struct aic3x_setup_data {
+ unsigned int gpio_func[2];
+};
+
+struct aic3x_pdata {
+ int gpio_reset; /* < 0 if not used */
+ struct aic3x_setup_data *setup;
+};
+
+#endif
diff --git a/include/sound/wm8962.h b/include/sound/wm8962.h
new file mode 100644
index 0000000..2b5306c
--- /dev/null
+++ b/include/sound/wm8962.h
@@ -0,0 +1,32 @@
+/*
+ * wm8962.h -- WM8962 Soc Audio driver platform data
+ *
+ * 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 _WM8962_PDATA_H
+#define _WM8962_PDATA_H
+
+#define WM8962_MAX_GPIO 6
+
+/* Use to set GPIO default values to zero */
+#define WM8962_GPIO_SET 0x10000
+
+struct wm8962_pdata {
+ int gpio_base;
+ u32 gpio_init[WM8962_MAX_GPIO];
+
+ /* Setup for microphone detection, raw value to be written to
+ * R48(0x30) - only microphone related bits will be updated.
+ * Detection may be enabled here for use with signals brought
+ * out on the GPIOs. */
+ u32 mic_cfg;
+
+ bool irq_active_low;
+
+ bool spk_mono; /* Speaker outputs tied together as mono */
+};
+
+#endif
diff --git a/include/video/sh_mobile_hdmi.h b/include/video/sh_mobile_hdmi.h
index 577cf18..1e1aa54 100644
--- a/include/video/sh_mobile_hdmi.h
+++ b/include/video/sh_mobile_hdmi.h
@@ -14,9 +14,25 @@
struct sh_mobile_lcdc_chan_cfg;
struct device;
+/*
+ * flags format
+ *
+ * 0x0000000A
+ *
+ * A: Audio source select
+ */
+
+/* Audio source select */
+#define HDMI_SND_SRC_MASK (0xF << 0)
+#define HDMI_SND_SRC_I2S (0 << 0) /* default */
+#define HDMI_SND_SRC_SPDIF (1 << 0)
+#define HDMI_SND_SRC_DSD (2 << 0)
+#define HDMI_SND_SRC_HBR (3 << 0)
+
struct sh_mobile_hdmi_info {
struct sh_mobile_lcdc_chan_cfg *lcd_chan;
struct device *lcd_dev;
+ unsigned int flags;
};
#endif
diff --git a/ipc/sem.c b/ipc/sem.c
index 40a8f46..0e0d49b 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -743,6 +743,8 @@
{
struct semid_ds out;
+ memset(&out, 0, sizeof(out));
+
ipc64_perm_to_ipc_perm(&in->sem_perm, &out.sem_perm);
out.sem_otime = in->sem_otime;
diff --git a/kernel/compat.c b/kernel/compat.c
index e167efc..c9e2ec0 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -1126,3 +1126,24 @@
return 0;
}
+
+/*
+ * Allocate user-space memory for the duration of a single system call,
+ * in order to marshall parameters inside a compat thunk.
+ */
+void __user *compat_alloc_user_space(unsigned long len)
+{
+ void __user *ptr;
+
+ /* If len would occupy more than half of the entire compat space... */
+ if (unlikely(len > (((compat_uptr_t)~0) >> 1)))
+ return NULL;
+
+ ptr = arch_compat_alloc_user_space(len);
+
+ if (unlikely(!access_ok(VERIFY_WRITE, ptr, len)))
+ return NULL;
+
+ return ptr;
+}
+EXPORT_SYMBOL_GPL(compat_alloc_user_space);
diff --git a/kernel/fork.c b/kernel/fork.c
index b7e9d60..c445f8c 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -356,10 +356,10 @@
if (IS_ERR(pol))
goto fail_nomem_policy;
vma_set_policy(tmp, pol);
+ tmp->vm_mm = mm;
if (anon_vma_fork(tmp, mpnt))
goto fail_nomem_anon_vma_fork;
tmp->vm_flags &= ~VM_LOCKED;
- tmp->vm_mm = mm;
tmp->vm_next = tmp->vm_prev = NULL;
file = tmp->vm_file;
if (file) {
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 1decafb..72206cf 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -931,6 +931,7 @@
remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base)
{
if (hrtimer_is_queued(timer)) {
+ unsigned long state;
int reprogram;
/*
@@ -944,8 +945,13 @@
debug_deactivate(timer);
timer_stats_hrtimer_clear_start_info(timer);
reprogram = base->cpu_base == &__get_cpu_var(hrtimer_bases);
- __remove_hrtimer(timer, base, HRTIMER_STATE_INACTIVE,
- reprogram);
+ /*
+ * We must preserve the CALLBACK state flag here,
+ * otherwise we could move the timer base in
+ * switch_hrtimer_base.
+ */
+ state = timer->state & HRTIMER_STATE_CALLBACK;
+ __remove_hrtimer(timer, base, state, reprogram);
return 1;
}
return 0;
@@ -1231,6 +1237,9 @@
BUG_ON(timer->state != HRTIMER_STATE_CALLBACK);
enqueue_hrtimer(timer, base);
}
+
+ WARN_ON_ONCE(!(timer->state & HRTIMER_STATE_CALLBACK));
+
timer->state &= ~HRTIMER_STATE_CALLBACK;
}
diff --git a/kernel/hw_breakpoint.c b/kernel/hw_breakpoint.c
index d71a987..c7c2aed 100644
--- a/kernel/hw_breakpoint.c
+++ b/kernel/hw_breakpoint.c
@@ -433,7 +433,8 @@
perf_overflow_handler_t triggered,
struct task_struct *tsk)
{
- return perf_event_create_kernel_counter(attr, -1, tsk->pid, triggered);
+ return perf_event_create_kernel_counter(attr, -1, task_pid_vnr(tsk),
+ triggered);
}
EXPORT_SYMBOL_GPL(register_user_hw_breakpoint);
diff --git a/kernel/kfifo.c b/kernel/kfifo.c
index 6b5580c..01a0700 100644
--- a/kernel/kfifo.c
+++ b/kernel/kfifo.c
@@ -365,8 +365,6 @@
n = setup_sgl_buf(sgl, fifo->data + off, nents, l);
n += setup_sgl_buf(sgl + n, fifo->data, nents - n, len - l);
- if (n)
- sg_mark_end(sgl + n - 1);
return n;
}
diff --git a/kernel/module.c b/kernel/module.c
index d0b5f8d..ccd6419 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1537,6 +1537,7 @@
{
struct module *mod = _mod;
list_del(&mod->list);
+ module_bug_cleanup(mod);
return 0;
}
@@ -2625,6 +2626,7 @@
if (err < 0)
goto ddebug;
+ module_bug_finalize(info.hdr, info.sechdrs, mod);
list_add_rcu(&mod->list, &modules);
mutex_unlock(&module_mutex);
@@ -2650,6 +2652,8 @@
mutex_lock(&module_mutex);
/* Unlink carefully: kallsyms could be walking list. */
list_del_rcu(&mod->list);
+ module_bug_cleanup(mod);
+
ddebug:
if (!mod->taints)
dynamic_debug_remove(info.debug);
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index db5b560..b98bed3 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -2202,15 +2202,13 @@
static int perf_event_period(struct perf_event *event, u64 __user *arg)
{
struct perf_event_context *ctx = event->ctx;
- unsigned long size;
int ret = 0;
u64 value;
if (!event->attr.sample_period)
return -EINVAL;
- size = copy_from_user(&value, arg, sizeof(value));
- if (size != sizeof(value))
+ if (copy_from_user(&value, arg, sizeof(value)))
return -EFAULT;
if (!value)
diff --git a/kernel/sched.c b/kernel/sched.c
index ed09d4f..dc85ceb 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -3513,9 +3513,9 @@
rtime = nsecs_to_cputime(p->se.sum_exec_runtime);
if (total) {
- u64 temp;
+ u64 temp = rtime;
- temp = (u64)(rtime * utime);
+ temp *= utime;
do_div(temp, total);
utime = (cputime_t)temp;
} else
@@ -3546,9 +3546,9 @@
rtime = nsecs_to_cputime(cputime.sum_exec_runtime);
if (total) {
- u64 temp;
+ u64 temp = rtime;
- temp = (u64)(rtime * cputime.utime);
+ temp *= cputime.utime;
do_div(temp, total);
utime = (cputime_t)temp;
} else
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c
index 9b5b4f8..db3f674 100644
--- a/kernel/sched_fair.c
+++ b/kernel/sched_fair.c
@@ -54,13 +54,13 @@
* Minimal preemption granularity for CPU-bound tasks:
* (default: 2 msec * (1 + ilog(ncpus)), units: nanoseconds)
*/
-unsigned int sysctl_sched_min_granularity = 2000000ULL;
-unsigned int normalized_sysctl_sched_min_granularity = 2000000ULL;
+unsigned int sysctl_sched_min_granularity = 750000ULL;
+unsigned int normalized_sysctl_sched_min_granularity = 750000ULL;
/*
* is kept at sysctl_sched_latency / sysctl_sched_min_granularity
*/
-static unsigned int sched_nr_latency = 3;
+static unsigned int sched_nr_latency = 8;
/*
* After fork, child runs first. If set to 0 (default) then
@@ -3630,7 +3630,7 @@
if (time_before(now, nohz.next_balance))
return 0;
- if (!rq->nr_running)
+ if (rq->idle_at_tick)
return 0;
first_pick_cpu = atomic_read(&nohz.first_pick_cpu);
diff --git a/kernel/signal.c b/kernel/signal.c
index bded651..919562c 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2215,6 +2215,14 @@
#ifdef __ARCH_SI_TRAPNO
err |= __put_user(from->si_trapno, &to->si_trapno);
#endif
+#ifdef BUS_MCEERR_AO
+ /*
+ * Other callers might not initialize the si_lsb field,
+ * so check explicitely for the right codes here.
+ */
+ if (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO)
+ err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb);
+#endif
break;
case __SI_CHLD:
err |= __put_user(from->si_pid, &to->si_pid);
diff --git a/kernel/smp.c b/kernel/smp.c
index 75c970c..ed6aacf 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -365,9 +365,10 @@
EXPORT_SYMBOL_GPL(smp_call_function_any);
/**
- * __smp_call_function_single(): Run a function on another CPU
+ * __smp_call_function_single(): Run a function on a specific CPU
* @cpu: The CPU to run on.
* @data: Pre-allocated and setup data structure
+ * @wait: If true, wait until function has completed on specified CPU.
*
* Like smp_call_function_single(), but allow caller to pass in a
* pre-allocated data structure. Useful for embedding @data inside
@@ -376,8 +377,10 @@
void __smp_call_function_single(int cpu, struct call_single_data *data,
int wait)
{
- csd_lock(data);
+ unsigned int this_cpu;
+ unsigned long flags;
+ this_cpu = get_cpu();
/*
* Can deadlock when called with interrupts disabled.
* We allow cpu's that are not yet online though, as no one else can
@@ -387,7 +390,15 @@
WARN_ON_ONCE(cpu_online(smp_processor_id()) && wait && irqs_disabled()
&& !oops_in_progress);
- generic_exec_single(cpu, data, wait);
+ if (cpu == this_cpu) {
+ local_irq_save(flags);
+ data->func(data->info);
+ local_irq_restore(flags);
+ } else {
+ csd_lock(data);
+ generic_exec_single(cpu, data, wait);
+ }
+ put_cpu();
}
/**
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index f88552c..3a45c22 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -2485,7 +2485,7 @@
kbuf[left] = 0;
}
- for (; left && vleft--; i++, min++, max++, first=0) {
+ for (; left && vleft--; i++, first = 0) {
unsigned long val;
if (write) {
diff --git a/kernel/sysctl_check.c b/kernel/sysctl_check.c
index 04cdcf7..10b90d8 100644
--- a/kernel/sysctl_check.c
+++ b/kernel/sysctl_check.c
@@ -143,15 +143,6 @@
if (!table->maxlen)
set_fail(&fail, table, "No maxlen");
}
- if ((table->proc_handler == proc_doulongvec_minmax) ||
- (table->proc_handler == proc_doulongvec_ms_jiffies_minmax)) {
- if (table->maxlen > sizeof (unsigned long)) {
- if (!table->extra1)
- set_fail(&fail, table, "No min");
- if (!table->extra2)
- set_fail(&fail, table, "No max");
- }
- }
#ifdef CONFIG_PROC_SYSCTL
if (table->procname && !table->proc_handler)
set_fail(&fail, table, "No proc_handler");
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 492197e..bca9637 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -405,7 +405,7 @@
#define BUF_MAX_DATA_SIZE (BUF_PAGE_SIZE - (sizeof(u32) * 2))
/* Max number of timestamps that can fit on a page */
-#define RB_TIMESTAMPS_PER_PAGE (BUF_PAGE_SIZE / RB_LEN_TIME_STAMP)
+#define RB_TIMESTAMPS_PER_PAGE (BUF_PAGE_SIZE / RB_LEN_TIME_EXTEND)
int ring_buffer_print_page_header(struct trace_seq *s)
{
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 727f24e..f77afd9 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -1,19 +1,26 @@
/*
- * linux/kernel/workqueue.c
+ * kernel/workqueue.c - generic async execution with shared worker pool
*
- * Generic mechanism for defining kernel helper threads for running
- * arbitrary tasks in process context.
+ * Copyright (C) 2002 Ingo Molnar
*
- * Started by Ingo Molnar, Copyright (C) 2002
- *
- * Derived from the taskqueue/keventd code by:
- *
- * David Woodhouse <dwmw2@infradead.org>
- * Andrew Morton
- * Kai Petzke <wpp@marie.physik.tu-berlin.de>
- * Theodore Ts'o <tytso@mit.edu>
+ * Derived from the taskqueue/keventd code by:
+ * David Woodhouse <dwmw2@infradead.org>
+ * Andrew Morton
+ * Kai Petzke <wpp@marie.physik.tu-berlin.de>
+ * Theodore Ts'o <tytso@mit.edu>
*
* Made to use alloc_percpu by Christoph Lameter.
+ *
+ * Copyright (C) 2010 SUSE Linux Products GmbH
+ * Copyright (C) 2010 Tejun Heo <tj@kernel.org>
+ *
+ * This is the generic async execution mechanism. Work items as are
+ * executed in process context. The worker pool is shared and
+ * automatically managed. There is one worker pool for each CPU and
+ * one extra for works which are better served by workers which are
+ * not bound to any specific CPU.
+ *
+ * Please read Documentation/workqueue.txt for details.
*/
#include <linux/module.h>
diff --git a/lib/bug.c b/lib/bug.c
index 7cdfad8..1955209 100644
--- a/lib/bug.c
+++ b/lib/bug.c
@@ -72,8 +72,8 @@
return NULL;
}
-int module_bug_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
- struct module *mod)
+void module_bug_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
+ struct module *mod)
{
char *secstrings;
unsigned int i;
@@ -97,8 +97,6 @@
* could potentially lead to deadlock and thus be counter-productive.
*/
list_add(&mod->bug_list, &module_bug_list);
-
- return 0;
}
void module_bug_cleanup(struct module *mod)
diff --git a/lib/list_sort.c b/lib/list_sort.c
index 4b5cb79..a7616fa 100644
--- a/lib/list_sort.c
+++ b/lib/list_sort.c
@@ -70,7 +70,7 @@
* element comparison is needed, so the client's cmp()
* routine can invoke cond_resched() periodically.
*/
- (*cmp)(priv, tail, tail);
+ (*cmp)(priv, tail->next, tail->next);
tail->next->prev = tail;
tail = tail->next;
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index c2bf86f..65d4204 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -30,6 +30,7 @@
struct backing_dev_info noop_backing_dev_info = {
.name = "noop",
+ .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK,
};
EXPORT_SYMBOL_GPL(noop_backing_dev_info);
@@ -243,6 +244,7 @@
err = bdi_init(&default_backing_dev_info);
if (!err)
bdi_register(&default_backing_dev_info, NULL, "default");
+ err = bdi_init(&noop_backing_dev_info);
return err;
}
diff --git a/mm/fremap.c b/mm/fremap.c
index 46f5dac..ec520c7 100644
--- a/mm/fremap.c
+++ b/mm/fremap.c
@@ -125,7 +125,6 @@
{
struct mm_struct *mm = current->mm;
struct address_space *mapping;
- unsigned long end = start + size;
struct vm_area_struct *vma;
int err = -EINVAL;
int has_write_lock = 0;
@@ -142,6 +141,10 @@
if (start + size <= start)
return err;
+ /* Does pgoff wrap? */
+ if (pgoff + (size >> PAGE_SHIFT) < pgoff)
+ return err;
+
/* Can we represent this offset inside this architecture's pte's? */
#if PTE_FILE_MAX_BITS < BITS_PER_LONG
if (pgoff + (size >> PAGE_SHIFT) >= (1UL << PTE_FILE_MAX_BITS))
@@ -168,7 +171,7 @@
if (!(vma->vm_flags & VM_CAN_NONLINEAR))
goto out;
- if (end <= start || start < vma->vm_start || end > vma->vm_end)
+ if (start < vma->vm_start || start + size > vma->vm_end)
goto out;
/* Must set VM_NONLINEAR before any pages are populated. */
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index cc5be78..c032738 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -2324,11 +2324,8 @@
* and just make the page writable */
avoidcopy = (page_mapcount(old_page) == 1);
if (avoidcopy) {
- if (!trylock_page(old_page)) {
- if (PageAnon(old_page))
- page_move_anon_rmap(old_page, vma, address);
- } else
- unlock_page(old_page);
+ if (PageAnon(old_page))
+ page_move_anon_rmap(old_page, vma, address);
set_huge_ptep_writable(vma, address, ptep);
return 0;
}
@@ -2404,7 +2401,7 @@
set_huge_pte_at(mm, address, ptep,
make_huge_pte(vma, new_page, 1));
page_remove_rmap(old_page);
- hugepage_add_anon_rmap(new_page, vma, address);
+ hugepage_add_new_anon_rmap(new_page, vma, address);
/* Make the old page be freed below */
new_page = old_page;
mmu_notifier_invalidate_range_end(mm,
@@ -2631,10 +2628,16 @@
vma, address);
}
- if (!pagecache_page) {
- page = pte_page(entry);
+ /*
+ * hugetlb_cow() requires page locks of pte_page(entry) and
+ * pagecache_page, so here we need take the former one
+ * when page != pagecache_page or !pagecache_page.
+ * Note that locking order is always pagecache_page -> page,
+ * so no worry about deadlock.
+ */
+ page = pte_page(entry);
+ if (page != pagecache_page)
lock_page(page);
- }
spin_lock(&mm->page_table_lock);
/* Check for a racing update before calling hugetlb_cow */
@@ -2661,9 +2664,8 @@
if (pagecache_page) {
unlock_page(pagecache_page);
put_page(pagecache_page);
- } else {
- unlock_page(page);
}
+ unlock_page(page);
out_mutex:
mutex_unlock(&hugetlb_instantiation_mutex);
diff --git a/mm/ksm.c b/mm/ksm.c
index b1873cf..65ab5c7 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -712,7 +712,7 @@
if (!ptep)
goto out;
- if (pte_write(*ptep)) {
+ if (pte_write(*ptep) || pte_dirty(*ptep)) {
pte_t entry;
swapped = PageSwapCache(page);
@@ -735,7 +735,9 @@
set_pte_at(mm, addr, ptep, entry);
goto out_unlock;
}
- entry = pte_wrprotect(entry);
+ if (pte_dirty(entry))
+ set_page_dirty(page);
+ entry = pte_mkclean(pte_wrprotect(entry));
set_pte_at_notify(mm, addr, ptep, entry);
}
*orig_pte = *ptep;
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 3eed583..9be3cf8 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -3587,9 +3587,13 @@
static void mem_cgroup_threshold(struct mem_cgroup *memcg)
{
- __mem_cgroup_threshold(memcg, false);
- if (do_swap_account)
- __mem_cgroup_threshold(memcg, true);
+ while (memcg) {
+ __mem_cgroup_threshold(memcg, false);
+ if (do_swap_account)
+ __mem_cgroup_threshold(memcg, true);
+
+ memcg = parent_mem_cgroup(memcg);
+ }
}
static int compare_thresholds(const void *a, const void *b)
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 9c26eec..757f6b0 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -183,7 +183,7 @@
* signal.
*/
static int kill_proc_ao(struct task_struct *t, unsigned long addr, int trapno,
- unsigned long pfn)
+ unsigned long pfn, struct page *page)
{
struct siginfo si;
int ret;
@@ -198,7 +198,7 @@
#ifdef __ARCH_SI_TRAPNO
si.si_trapno = trapno;
#endif
- si.si_addr_lsb = PAGE_SHIFT;
+ si.si_addr_lsb = compound_order(compound_head(page)) + PAGE_SHIFT;
/*
* Don't use force here, it's convenient if the signal
* can be temporarily blocked.
@@ -235,7 +235,7 @@
int nr;
do {
nr = shrink_slab(1000, GFP_KERNEL, 1000);
- if (page_count(p) == 0)
+ if (page_count(p) == 1)
break;
} while (nr > 10);
}
@@ -327,7 +327,7 @@
* wrong earlier.
*/
static void kill_procs_ao(struct list_head *to_kill, int doit, int trapno,
- int fail, unsigned long pfn)
+ int fail, struct page *page, unsigned long pfn)
{
struct to_kill *tk, *next;
@@ -352,7 +352,7 @@
* process anyways.
*/
else if (kill_proc_ao(tk->tsk, tk->addr, trapno,
- pfn) < 0)
+ pfn, page) < 0)
printk(KERN_ERR
"MCE %#lx: Cannot send advisory machine check signal to %s:%d\n",
pfn, tk->tsk->comm, tk->tsk->pid);
@@ -928,7 +928,7 @@
* any accesses to the poisoned memory.
*/
kill_procs_ao(&tokill, !!PageDirty(hpage), trapno,
- ret != SWAP_SUCCESS, pfn);
+ ret != SWAP_SUCCESS, p, pfn);
return ret;
}
diff --git a/mm/memory.c b/mm/memory.c
index 71b161b..0e18b4d 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -2680,10 +2680,12 @@
delayacct_clear_flag(DELAYACCT_PF_SWAPIN);
/*
- * Make sure try_to_free_swap didn't release the swapcache
- * from under us. The page pin isn't enough to prevent that.
+ * Make sure try_to_free_swap or reuse_swap_page or swapoff did not
+ * release the swapcache from under us. The page pin, and pte_same
+ * test below, are not enough to exclude that. Even if it is still
+ * swapcache, we need to check that the page's swap has not changed.
*/
- if (unlikely(!PageSwapCache(page)))
+ if (unlikely(!PageSwapCache(page) || page_private(page) != entry.val))
goto out_page;
if (ksm_might_need_to_copy(page, vma, address)) {
diff --git a/mm/mmap.c b/mm/mmap.c
index 6128dc8..00161a4 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2009,6 +2009,7 @@
removed_exe_file_vma(mm);
fput(new->vm_file);
}
+ unlink_anon_vmas(new);
out_free_mpol:
mpol_put(pol);
out_free_vma:
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index fc81cb2..4029583 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -121,8 +121,8 @@
}
/* return true if the task is not adequate as candidate victim task. */
-static bool oom_unkillable_task(struct task_struct *p, struct mem_cgroup *mem,
- const nodemask_t *nodemask)
+static bool oom_unkillable_task(struct task_struct *p,
+ const struct mem_cgroup *mem, const nodemask_t *nodemask)
{
if (is_global_init(p))
return true;
@@ -208,8 +208,13 @@
*/
points += p->signal->oom_score_adj;
- if (points < 0)
- return 0;
+ /*
+ * Never return 0 for an eligible task that may be killed since it's
+ * possible that no single user task uses more than 0.1% of memory and
+ * no single admin tasks uses more than 3.0%.
+ */
+ if (points <= 0)
+ return 1;
return (points < 1000) ? points : 1000;
}
@@ -339,26 +344,24 @@
/**
* dump_tasks - dump current memory state of all system tasks
* @mem: current's memory controller, if constrained
+ * @nodemask: nodemask passed to page allocator for mempolicy ooms
*
- * Dumps the current memory state of all system tasks, excluding kernel threads.
+ * Dumps the current memory state of all eligible tasks. Tasks not in the same
+ * memcg, not in the same cpuset, or bound to a disjoint set of mempolicy nodes
+ * are not shown.
* State information includes task's pid, uid, tgid, vm size, rss, cpu, oom_adj
* value, oom_score_adj value, and name.
*
- * If the actual is non-NULL, only tasks that are a member of the mem_cgroup are
- * shown.
- *
* Call with tasklist_lock read-locked.
*/
-static void dump_tasks(const struct mem_cgroup *mem)
+static void dump_tasks(const struct mem_cgroup *mem, const nodemask_t *nodemask)
{
struct task_struct *p;
struct task_struct *task;
pr_info("[ pid ] uid tgid total_vm rss cpu oom_adj oom_score_adj name\n");
for_each_process(p) {
- if (p->flags & PF_KTHREAD)
- continue;
- if (mem && !task_in_mem_cgroup(p, mem))
+ if (oom_unkillable_task(p, mem, nodemask))
continue;
task = find_lock_task_mm(p);
@@ -381,7 +384,7 @@
}
static void dump_header(struct task_struct *p, gfp_t gfp_mask, int order,
- struct mem_cgroup *mem)
+ struct mem_cgroup *mem, const nodemask_t *nodemask)
{
task_lock(current);
pr_warning("%s invoked oom-killer: gfp_mask=0x%x, order=%d, "
@@ -394,7 +397,7 @@
mem_cgroup_print_oom_info(mem, p);
show_mem();
if (sysctl_oom_dump_tasks)
- dump_tasks(mem);
+ dump_tasks(mem, nodemask);
}
#define K(x) ((x) << (PAGE_SHIFT-10))
@@ -436,7 +439,7 @@
unsigned int victim_points = 0;
if (printk_ratelimit())
- dump_header(p, gfp_mask, order, mem);
+ dump_header(p, gfp_mask, order, mem, nodemask);
/*
* If the task is already exiting, don't alarm the sysadmin or kill
@@ -482,7 +485,7 @@
* Determines whether the kernel must panic because of the panic_on_oom sysctl.
*/
static void check_panic_on_oom(enum oom_constraint constraint, gfp_t gfp_mask,
- int order)
+ int order, const nodemask_t *nodemask)
{
if (likely(!sysctl_panic_on_oom))
return;
@@ -496,7 +499,7 @@
return;
}
read_lock(&tasklist_lock);
- dump_header(NULL, gfp_mask, order, NULL);
+ dump_header(NULL, gfp_mask, order, NULL, nodemask);
read_unlock(&tasklist_lock);
panic("Out of memory: %s panic_on_oom is enabled\n",
sysctl_panic_on_oom == 2 ? "compulsory" : "system-wide");
@@ -509,7 +512,7 @@
unsigned int points = 0;
struct task_struct *p;
- check_panic_on_oom(CONSTRAINT_MEMCG, gfp_mask, 0);
+ check_panic_on_oom(CONSTRAINT_MEMCG, gfp_mask, 0, NULL);
limit = mem_cgroup_get_limit(mem) >> PAGE_SHIFT;
read_lock(&tasklist_lock);
retry:
@@ -641,6 +644,7 @@
void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask,
int order, nodemask_t *nodemask)
{
+ const nodemask_t *mpol_mask;
struct task_struct *p;
unsigned long totalpages;
unsigned long freed = 0;
@@ -670,7 +674,8 @@
*/
constraint = constrained_alloc(zonelist, gfp_mask, nodemask,
&totalpages);
- check_panic_on_oom(constraint, gfp_mask, order);
+ mpol_mask = (constraint == CONSTRAINT_MEMORY_POLICY) ? nodemask : NULL;
+ check_panic_on_oom(constraint, gfp_mask, order, mpol_mask);
read_lock(&tasklist_lock);
if (sysctl_oom_kill_allocating_task &&
@@ -688,15 +693,13 @@
}
retry:
- p = select_bad_process(&points, totalpages, NULL,
- constraint == CONSTRAINT_MEMORY_POLICY ? nodemask :
- NULL);
+ p = select_bad_process(&points, totalpages, NULL, mpol_mask);
if (PTR_ERR(p) == -1UL)
goto out;
/* Found nothing?!?! Either we hang forever, or we panic. */
if (!p) {
- dump_header(NULL, gfp_mask, order, NULL);
+ dump_header(NULL, gfp_mask, order, NULL, mpol_mask);
read_unlock(&tasklist_lock);
panic("Out of memory and no killable processes...\n");
}
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index a8cfa9c..f12ad18 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -5182,9 +5182,9 @@
if (!table)
panic("Failed to allocate %s hash table\n", tablename);
- printk(KERN_INFO "%s hash table entries: %d (order: %d, %lu bytes)\n",
+ printk(KERN_INFO "%s hash table entries: %ld (order: %d, %lu bytes)\n",
tablename,
- (1U << log2qty),
+ (1UL << log2qty),
ilog2(size) - PAGE_SHIFT,
size);
diff --git a/mm/percpu.c b/mm/percpu.c
index 58c572b..c76ef38 100644
--- a/mm/percpu.c
+++ b/mm/percpu.c
@@ -1401,9 +1401,9 @@
if (pcpu_first_unit_cpu == NR_CPUS)
pcpu_first_unit_cpu = cpu;
+ pcpu_last_unit_cpu = cpu;
}
}
- pcpu_last_unit_cpu = cpu;
pcpu_nr_units = unit;
for_each_possible_cpu(cpu)
diff --git a/mm/rmap.c b/mm/rmap.c
index f6f0d2d..92e6757 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -381,7 +381,13 @@
unsigned long page_address_in_vma(struct page *page, struct vm_area_struct *vma)
{
if (PageAnon(page)) {
- if (vma->anon_vma->root != page_anon_vma(page)->root)
+ struct anon_vma *page__anon_vma = page_anon_vma(page);
+ /*
+ * Note: swapoff's unuse_vma() is more efficient with this
+ * check, and needs it to match anon_vma when KSM is active.
+ */
+ if (!vma->anon_vma || !page__anon_vma ||
+ vma->anon_vma->root != page__anon_vma->root)
return -EFAULT;
} else if (page->mapping && !(vma->vm_flags & VM_NONLINEAR)) {
if (!vma->vm_file ||
@@ -1564,13 +1570,14 @@
struct vm_area_struct *vma, unsigned long address, int exclusive)
{
struct anon_vma *anon_vma = vma->anon_vma;
+
BUG_ON(!anon_vma);
- if (!exclusive) {
- struct anon_vma_chain *avc;
- avc = list_entry(vma->anon_vma_chain.prev,
- struct anon_vma_chain, same_vma);
- anon_vma = avc->anon_vma;
- }
+
+ if (PageAnon(page))
+ return;
+ if (!exclusive)
+ anon_vma = anon_vma->root;
+
anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON;
page->mapping = (struct address_space *) anon_vma;
page->index = linear_page_index(vma, address);
@@ -1581,6 +1588,8 @@
{
struct anon_vma *anon_vma = vma->anon_vma;
int first;
+
+ BUG_ON(!PageLocked(page));
BUG_ON(!anon_vma);
BUG_ON(address < vma->vm_start || address >= vma->vm_end);
first = atomic_inc_and_test(&page->_mapcount);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index c391c32..c5dfabf 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1804,12 +1804,11 @@
* If a zone is deemed to be full of pinned pages then just give it a light
* scan then give up on it.
*/
-static bool shrink_zones(int priority, struct zonelist *zonelist,
+static void shrink_zones(int priority, struct zonelist *zonelist,
struct scan_control *sc)
{
struct zoneref *z;
struct zone *zone;
- bool all_unreclaimable = true;
for_each_zone_zonelist_nodemask(zone, z, zonelist,
gfp_zone(sc->gfp_mask), sc->nodemask) {
@@ -1827,8 +1826,38 @@
}
shrink_zone(priority, zone, sc);
- all_unreclaimable = false;
}
+}
+
+static bool zone_reclaimable(struct zone *zone)
+{
+ return zone->pages_scanned < zone_reclaimable_pages(zone) * 6;
+}
+
+/*
+ * As hibernation is going on, kswapd is freezed so that it can't mark
+ * the zone into all_unreclaimable. It can't handle OOM during hibernation.
+ * So let's check zone's unreclaimable in direct reclaim as well as kswapd.
+ */
+static bool all_unreclaimable(struct zonelist *zonelist,
+ struct scan_control *sc)
+{
+ struct zoneref *z;
+ struct zone *zone;
+ bool all_unreclaimable = true;
+
+ for_each_zone_zonelist_nodemask(zone, z, zonelist,
+ gfp_zone(sc->gfp_mask), sc->nodemask) {
+ if (!populated_zone(zone))
+ continue;
+ if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
+ continue;
+ if (zone_reclaimable(zone)) {
+ all_unreclaimable = false;
+ break;
+ }
+ }
+
return all_unreclaimable;
}
@@ -1852,7 +1881,6 @@
struct scan_control *sc)
{
int priority;
- bool all_unreclaimable;
unsigned long total_scanned = 0;
struct reclaim_state *reclaim_state = current->reclaim_state;
struct zoneref *z;
@@ -1869,7 +1897,7 @@
sc->nr_scanned = 0;
if (!priority)
disable_swap_token();
- all_unreclaimable = shrink_zones(priority, zonelist, sc);
+ shrink_zones(priority, zonelist, sc);
/*
* Don't shrink slabs when reclaiming memory from
* over limit cgroups
@@ -1931,7 +1959,7 @@
return sc->nr_reclaimed;
/* top priority shrink_zones still had more to do? don't OOM, then */
- if (scanning_global_lru(sc) && !all_unreclaimable)
+ if (scanning_global_lru(sc) && !all_unreclaimable(zonelist, sc))
return 1;
return 0;
@@ -2197,8 +2225,7 @@
total_scanned += sc.nr_scanned;
if (zone->all_unreclaimable)
continue;
- if (nr_slab == 0 &&
- zone->pages_scanned >= (zone_reclaimable_pages(zone) * 6))
+ if (nr_slab == 0 && !zone_reclaimable(zone))
zone->all_unreclaimable = 1;
/*
* If we've done a decent amount of scanning and
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index 01ddb04..0eb96f7 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -24,8 +24,11 @@
if (vlan_dev)
skb->dev = vlan_dev;
- else if (vlan_id)
- goto drop;
+ else if (vlan_id) {
+ if (!(skb->dev->flags & IFF_PROMISC))
+ goto drop;
+ skb->pkt_type = PACKET_OTHERHOST;
+ }
return (polling ? netif_receive_skb(skb) : netif_rx(skb));
@@ -102,8 +105,11 @@
if (vlan_dev)
skb->dev = vlan_dev;
- else if (vlan_id)
- goto drop;
+ else if (vlan_id) {
+ if (!(skb->dev->flags & IFF_PROMISC))
+ goto drop;
+ skb->pkt_type = PACKET_OTHERHOST;
+ }
for (p = napi->gro_list; p; p = p->next) {
NAPI_GRO_CB(p)->same_flow =
diff --git a/net/9p/client.c b/net/9p/client.c
index dc6f2f2..9eb7250 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -331,8 +331,10 @@
}
}
- if (c->tagpool)
+ if (c->tagpool) {
+ p9_idpool_put(0, c->tagpool); /* free reserved tag 0 */
p9_idpool_destroy(c->tagpool);
+ }
/* free requests associated with tags */
for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) {
@@ -944,6 +946,7 @@
int16_t nwqids, count;
err = 0;
+ wqids = NULL;
clnt = oldfid->clnt;
if (clone) {
fid = p9_fid_create(clnt);
@@ -994,9 +997,11 @@
else
fid->qid = oldfid->qid;
+ kfree(wqids);
return fid;
clunk_fid:
+ kfree(wqids);
p9_client_clunk(fid);
fid = NULL;
diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c
index 0ea20c3..17c5ba7 100644
--- a/net/9p/trans_rdma.c
+++ b/net/9p/trans_rdma.c
@@ -426,8 +426,10 @@
/* Allocate an fcall for the reply */
rpl_context = kmalloc(sizeof *rpl_context, GFP_KERNEL);
- if (!rpl_context)
+ if (!rpl_context) {
+ err = -ENOMEM;
goto err_close;
+ }
/*
* If the request has a buffer, steal it, otherwise
@@ -445,8 +447,8 @@
}
rpl_context->rc = req->rc;
if (!rpl_context->rc) {
- kfree(rpl_context);
- goto err_close;
+ err = -ENOMEM;
+ goto err_free2;
}
/*
@@ -458,11 +460,8 @@
*/
if (atomic_inc_return(&rdma->rq_count) <= rdma->rq_depth) {
err = post_recv(client, rpl_context);
- if (err) {
- kfree(rpl_context->rc);
- kfree(rpl_context);
- goto err_close;
- }
+ if (err)
+ goto err_free1;
} else
atomic_dec(&rdma->rq_count);
@@ -471,8 +470,10 @@
/* Post the request */
c = kmalloc(sizeof *c, GFP_KERNEL);
- if (!c)
- goto err_close;
+ if (!c) {
+ err = -ENOMEM;
+ goto err_free1;
+ }
c->req = req;
c->busa = ib_dma_map_single(rdma->cm_id->device,
@@ -499,9 +500,15 @@
return ib_post_send(rdma->qp, &wr, &bad_wr);
error:
+ kfree(c);
+ kfree(rpl_context->rc);
+ kfree(rpl_context);
P9_DPRINTK(P9_DEBUG_ERROR, "EIO\n");
return -EIO;
-
+ err_free1:
+ kfree(rpl_context->rc);
+ err_free2:
+ kfree(rpl_context);
err_close:
spin_lock_irqsave(&rdma->req_lock, flags);
if (rdma->state < P9_RDMA_CLOSING) {
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index dcfbe99..b885159 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -329,7 +329,8 @@
mutex_lock(&virtio_9p_lock);
list_for_each_entry(chan, &virtio_chan_list, chan_list) {
- if (!strncmp(devname, chan->tag, chan->tag_len)) {
+ if (!strncmp(devname, chan->tag, chan->tag_len) &&
+ strlen(devname) == chan->tag_len) {
if (!chan->inuse) {
chan->inuse = true;
found = 1;
diff --git a/net/Kconfig b/net/Kconfig
index e330594..e926884 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -217,7 +217,7 @@
config RPS
boolean
- depends on SMP && SYSFS
+ depends on SMP && SYSFS && USE_GENERIC_SMP_HELPERS
default y
menu "Network testing"
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
index 651babd..ad2b232 100644
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -399,12 +399,6 @@
unregister_netdev(net_dev);
free_netdev(net_dev);
}
- read_lock_irq(&devs_lock);
- if (list_empty(&br2684_devs)) {
- /* last br2684 device */
- unregister_atmdevice_notifier(&atm_dev_notifier);
- }
- read_unlock_irq(&devs_lock);
return;
}
@@ -675,7 +669,6 @@
if (list_empty(&br2684_devs)) {
/* 1st br2684 device */
- register_atmdevice_notifier(&atm_dev_notifier);
brdev->number = 1;
} else
brdev->number = BRPRIV(list_entry_brdev(br2684_devs.prev))->number + 1;
@@ -815,6 +808,7 @@
return -ENOMEM;
#endif
register_atm_ioctl(&br2684_ioctl_ops);
+ register_atmdevice_notifier(&atm_dev_notifier);
return 0;
}
@@ -830,9 +824,7 @@
#endif
- /* if not already empty */
- if (!list_empty(&br2684_devs))
- unregister_atmdevice_notifier(&atm_dev_notifier);
+ unregister_atmdevice_notifier(&atm_dev_notifier);
while (!list_empty(&br2684_devs)) {
net_dev = list_entry_brdev(br2684_devs.next);
diff --git a/net/atm/mpc.c b/net/atm/mpc.c
index 622b471..74bcc66 100644
--- a/net/atm/mpc.c
+++ b/net/atm/mpc.c
@@ -778,7 +778,7 @@
eg->packets_rcvd++;
mpc->eg_ops->put(eg);
- memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
+ memset(ATM_SKB(new_skb), 0, sizeof(struct atm_skb_data));
netif_rx(new_skb);
}
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index fadf26b..0b54b7d 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -1441,33 +1441,23 @@
static void l2cap_streaming_send(struct sock *sk)
{
- struct sk_buff *skb, *tx_skb;
+ struct sk_buff *skb;
struct l2cap_pinfo *pi = l2cap_pi(sk);
u16 control, fcs;
- while ((skb = sk->sk_send_head)) {
- tx_skb = skb_clone(skb, GFP_ATOMIC);
-
- control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
+ while ((skb = skb_dequeue(TX_QUEUE(sk)))) {
+ control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE);
control |= pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
- put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
+ put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE);
if (pi->fcs == L2CAP_FCS_CRC16) {
- fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2);
- put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2);
+ fcs = crc16(0, (u8 *)skb->data, skb->len - 2);
+ put_unaligned_le16(fcs, skb->data + skb->len - 2);
}
- l2cap_do_send(sk, tx_skb);
+ l2cap_do_send(sk, skb);
pi->next_tx_seq = (pi->next_tx_seq + 1) % 64;
-
- if (skb_queue_is_last(TX_QUEUE(sk), skb))
- sk->sk_send_head = NULL;
- else
- sk->sk_send_head = skb_queue_next(TX_QUEUE(sk), skb);
-
- skb = skb_dequeue(TX_QUEUE(sk));
- kfree_skb(skb);
}
}
@@ -1960,6 +1950,11 @@
switch (optname) {
case L2CAP_OPTIONS:
+ if (sk->sk_state == BT_CONNECTED) {
+ err = -EINVAL;
+ break;
+ }
+
opts.imtu = l2cap_pi(sk)->imtu;
opts.omtu = l2cap_pi(sk)->omtu;
opts.flush_to = l2cap_pi(sk)->flush_to;
@@ -2771,10 +2766,10 @@
case L2CAP_CONF_MTU:
if (val < L2CAP_DEFAULT_MIN_MTU) {
*result = L2CAP_CONF_UNACCEPT;
- pi->omtu = L2CAP_DEFAULT_MIN_MTU;
+ pi->imtu = L2CAP_DEFAULT_MIN_MTU;
} else
- pi->omtu = val;
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu);
+ pi->imtu = val;
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
break;
case L2CAP_CONF_FLUSH_TO:
@@ -3071,6 +3066,17 @@
return 0;
}
+static inline void set_default_fcs(struct l2cap_pinfo *pi)
+{
+ /* FCS is enabled only in ERTM or streaming mode, if one or both
+ * sides request it.
+ */
+ if (pi->mode != L2CAP_MODE_ERTM && pi->mode != L2CAP_MODE_STREAMING)
+ pi->fcs = L2CAP_FCS_NONE;
+ else if (!(pi->conf_state & L2CAP_CONF_NO_FCS_RECV))
+ pi->fcs = L2CAP_FCS_CRC16;
+}
+
static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
{
struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
@@ -3088,14 +3094,8 @@
if (!sk)
return -ENOENT;
- if (sk->sk_state != BT_CONFIG) {
- struct l2cap_cmd_rej rej;
-
- rej.reason = cpu_to_le16(0x0002);
- l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
- sizeof(rej), &rej);
+ if (sk->sk_state == BT_DISCONN)
goto unlock;
- }
/* Reject if config buffer is too small. */
len = cmd_len - sizeof(*req);
@@ -3135,9 +3135,7 @@
goto unlock;
if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) {
- if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_NO_FCS_RECV) ||
- l2cap_pi(sk)->fcs != L2CAP_FCS_NONE)
- l2cap_pi(sk)->fcs = L2CAP_FCS_CRC16;
+ set_default_fcs(l2cap_pi(sk));
sk->sk_state = BT_CONNECTED;
@@ -3225,9 +3223,7 @@
l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE;
if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) {
- if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_NO_FCS_RECV) ||
- l2cap_pi(sk)->fcs != L2CAP_FCS_NONE)
- l2cap_pi(sk)->fcs = L2CAP_FCS_CRC16;
+ set_default_fcs(l2cap_pi(sk));
sk->sk_state = BT_CONNECTED;
l2cap_pi(sk)->next_tx_seq = 0;
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 44a6232..194b3a0 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -82,11 +82,14 @@
static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
{
struct sock *sk = d->owner, *parent;
+ unsigned long flags;
+
if (!sk)
return;
BT_DBG("dlc %p state %ld err %d", d, d->state, err);
+ local_irq_save(flags);
bh_lock_sock(sk);
if (err)
@@ -108,6 +111,7 @@
}
bh_unlock_sock(sk);
+ local_irq_restore(flags);
if (parent && sock_flag(sk, SOCK_ZAPPED)) {
/* We have to drop DLC lock here, otherwise
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
index 8ce9047..4bf28f2 100644
--- a/net/caif/caif_socket.c
+++ b/net/caif/caif_socket.c
@@ -827,6 +827,7 @@
long timeo;
int err;
int ifindex, headroom, tailroom;
+ unsigned int mtu;
struct net_device *dev;
lock_sock(sk);
@@ -896,15 +897,23 @@
cf_sk->sk.sk_state = CAIF_DISCONNECTED;
goto out;
}
- dev = dev_get_by_index(sock_net(sk), ifindex);
+
+ err = -ENODEV;
+ rcu_read_lock();
+ dev = dev_get_by_index_rcu(sock_net(sk), ifindex);
+ if (!dev) {
+ rcu_read_unlock();
+ goto out;
+ }
cf_sk->headroom = LL_RESERVED_SPACE_EXTRA(dev, headroom);
+ mtu = dev->mtu;
+ rcu_read_unlock();
+
cf_sk->tailroom = tailroom;
- cf_sk->maxframe = dev->mtu - (headroom + tailroom);
- dev_put(dev);
+ cf_sk->maxframe = mtu - (headroom + tailroom);
if (cf_sk->maxframe < 1) {
- pr_warning("CAIF: %s(): CAIF Interface MTU too small (%d)\n",
- __func__, dev->mtu);
- err = -ENODEV;
+ pr_warning("CAIF: %s(): CAIF Interface MTU too small (%u)\n",
+ __func__, mtu);
goto out;
}
diff --git a/net/core/dev.c b/net/core/dev.c
index b9b22a3..660dd41 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4845,7 +4845,7 @@
dev = list_first_entry(head, struct net_device, unreg_list);
call_netdevice_notifiers(NETDEV_UNREGISTER_BATCH, dev);
- synchronize_net();
+ rcu_barrier();
list_for_each_entry(dev, head, unreg_list)
dev_put(dev);
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 7a85367..8451ab4 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -348,7 +348,7 @@
if (info.cmd == ETHTOOL_GRXCLSRLALL) {
if (info.rule_cnt > 0) {
if (info.rule_cnt <= KMALLOC_MAX_SIZE / sizeof(u32))
- rule_buf = kmalloc(info.rule_cnt * sizeof(u32),
+ rule_buf = kzalloc(info.rule_cnt * sizeof(u32),
GFP_USER);
if (!rule_buf)
return -ENOMEM;
@@ -397,7 +397,7 @@
(KMALLOC_MAX_SIZE - sizeof(*indir)) / sizeof(*indir->ring_index))
return -ENOMEM;
full_size = sizeof(*indir) + sizeof(*indir->ring_index) * table_size;
- indir = kmalloc(full_size, GFP_USER);
+ indir = kzalloc(full_size, GFP_USER);
if (!indir)
return -ENOMEM;
@@ -538,7 +538,7 @@
gstrings.len = ret;
- data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER);
+ data = kzalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER);
if (!data)
return -ENOMEM;
@@ -775,7 +775,7 @@
if (regs.len > reglen)
regs.len = reglen;
- regbuf = kmalloc(reglen, GFP_USER);
+ regbuf = kzalloc(reglen, GFP_USER);
if (!regbuf)
return -ENOMEM;
diff --git a/net/core/iovec.c b/net/core/iovec.c
index 1cd98df..e6b133b 100644
--- a/net/core/iovec.c
+++ b/net/core/iovec.c
@@ -35,9 +35,10 @@
* in any case.
*/
-int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address, int mode)
+long verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address, int mode)
{
- int size, err, ct;
+ int size, ct;
+ long err;
if (m->msg_namelen) {
if (mode == VERIFY_READ) {
diff --git a/net/core/sock.c b/net/core/sock.c
index b05b9b6..ef30e9d 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1351,9 +1351,9 @@
{
int uid;
- read_lock(&sk->sk_callback_lock);
+ read_lock_bh(&sk->sk_callback_lock);
uid = sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_uid : 0;
- read_unlock(&sk->sk_callback_lock);
+ read_unlock_bh(&sk->sk_callback_lock);
return uid;
}
EXPORT_SYMBOL(sock_i_uid);
@@ -1362,9 +1362,9 @@
{
unsigned long ino;
- read_lock(&sk->sk_callback_lock);
+ read_lock_bh(&sk->sk_callback_lock);
ino = sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_ino : 0;
- read_unlock(&sk->sk_callback_lock);
+ read_unlock_bh(&sk->sk_callback_lock);
return ino;
}
EXPORT_SYMBOL(sock_i_ino);
diff --git a/net/core/stream.c b/net/core/stream.c
index d959e0f..f5df85d 100644
--- a/net/core/stream.c
+++ b/net/core/stream.c
@@ -141,10 +141,10 @@
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
sk->sk_write_pending++;
- sk_wait_event(sk, ¤t_timeo, !sk->sk_err &&
- !(sk->sk_shutdown & SEND_SHUTDOWN) &&
- sk_stream_memory_free(sk) &&
- vm_wait);
+ sk_wait_event(sk, ¤t_timeo, sk->sk_err ||
+ (sk->sk_shutdown & SEND_SHUTDOWN) ||
+ (sk_stream_memory_free(sk) &&
+ !vm_wait));
sk->sk_write_pending--;
if (vm_wait) {
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index 571f895..7cd7760 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -217,6 +217,7 @@
config NET_IPGRE
tristate "IP: GRE tunnels over IP"
+ depends on IPV6 || IPV6=n
help
Tunneling means encapsulating data of one protocol type within
another protocol and sending it over a channel that understands the
@@ -412,7 +413,7 @@
If unsure, say Y.
config INET_LRO
- bool "Large Receive Offload (ipv4/tcp)"
+ tristate "Large Receive Offload (ipv4/tcp)"
default y
---help---
Support for Large Receive Offload (ipv4/tcp).
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index a1ad0e7..2a4bb76 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -856,6 +856,18 @@
igmpv3_clear_delrec(in_dev);
} else if (len < 12) {
return; /* ignore bogus packet; freed by caller */
+ } else if (IGMP_V1_SEEN(in_dev)) {
+ /* This is a v3 query with v1 queriers present */
+ max_delay = IGMP_Query_Response_Interval;
+ group = 0;
+ } else if (IGMP_V2_SEEN(in_dev)) {
+ /* this is a v3 query with v2 queriers present;
+ * Interpretation of the max_delay code is problematic here.
+ * A real v2 host would use ih_code directly, while v3 has a
+ * different encoding. We use the v3 encoding as more likely
+ * to be intended in a v3 query.
+ */
+ max_delay = IGMPV3_MRC(ih3->code)*(HZ/IGMP_TIMER_SCALE);
} else { /* v3 */
if (!pskb_may_pull(skb, sizeof(struct igmpv3_query)))
return;
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 945b20a..35c93e8 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -45,7 +45,7 @@
#include <net/netns/generic.h>
#include <net/rtnetlink.h>
-#ifdef CONFIG_IPV6
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
#include <net/ipv6.h>
#include <net/ip6_fib.h>
#include <net/ip6_route.h>
@@ -699,7 +699,7 @@
if ((dst = rt->rt_gateway) == 0)
goto tx_error_icmp;
}
-#ifdef CONFIG_IPV6
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
else if (skb->protocol == htons(ETH_P_IPV6)) {
struct in6_addr *addr6;
int addr_type;
@@ -774,7 +774,7 @@
goto tx_error;
}
}
-#ifdef CONFIG_IPV6
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
else if (skb->protocol == htons(ETH_P_IPV6)) {
struct rt6_info *rt6 = (struct rt6_info *)skb_dst(skb);
@@ -850,7 +850,7 @@
if ((iph->ttl = tiph->ttl) == 0) {
if (skb->protocol == htons(ETH_P_IP))
iph->ttl = old_iph->ttl;
-#ifdef CONFIG_IPV6
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
else if (skb->protocol == htons(ETH_P_IPV6))
iph->ttl = ((struct ipv6hdr *)old_iph)->hop_limit;
#endif
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 04b6989..7649d77 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -488,9 +488,8 @@
* we can switch to copy when see the first bad fragment.
*/
if (skb_has_frags(skb)) {
- struct sk_buff *frag;
+ struct sk_buff *frag, *frag2;
int first_len = skb_pagelen(skb);
- int truesizes = 0;
if (first_len - hlen > mtu ||
((first_len - hlen) & 7) ||
@@ -503,18 +502,18 @@
if (frag->len > mtu ||
((frag->len & 7) && frag->next) ||
skb_headroom(frag) < hlen)
- goto slow_path;
+ goto slow_path_clean;
/* Partially cloned skb? */
if (skb_shared(frag))
- goto slow_path;
+ goto slow_path_clean;
BUG_ON(frag->sk);
if (skb->sk) {
frag->sk = skb->sk;
frag->destructor = sock_wfree;
}
- truesizes += frag->truesize;
+ skb->truesize -= frag->truesize;
}
/* Everything is OK. Generate! */
@@ -524,7 +523,6 @@
frag = skb_shinfo(skb)->frag_list;
skb_frag_list_init(skb);
skb->data_len = first_len - skb_headlen(skb);
- skb->truesize -= truesizes;
skb->len = first_len;
iph->tot_len = htons(first_len);
iph->frag_off = htons(IP_MF);
@@ -576,6 +574,15 @@
}
IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
return err;
+
+slow_path_clean:
+ skb_walk_frags(skb, frag2) {
+ if (frag2 == frag)
+ break;
+ frag2->sk = NULL;
+ frag2->destructor = NULL;
+ skb->truesize += frag2->truesize;
+ }
}
slow_path:
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 6c40a8c..64b70ad 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -1129,6 +1129,9 @@
case IP_HDRINCL:
val = inet->hdrincl;
break;
+ case IP_NODEFRAG:
+ val = inet->nodefrag;
+ break;
case IP_MTU_DISCOVER:
val = inet->pmtudisc;
break;
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index b254daf..43eec80 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -112,6 +112,7 @@
/* ip_route_me_harder expects skb->dst to be set */
skb_dst_set_noref(nskb, skb_dst(oldskb));
+ nskb->protocol = htons(ETH_P_IP);
if (ip_route_me_harder(nskb, addr_type))
goto free_nskb;
diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c
index eab8de3..f3a9b42 100644
--- a/net/ipv4/netfilter/nf_defrag_ipv4.c
+++ b/net/ipv4/netfilter/nf_defrag_ipv4.c
@@ -66,9 +66,11 @@
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
+ struct sock *sk = skb->sk;
struct inet_sock *inet = inet_sk(skb->sk);
- if (inet && inet->nodefrag)
+ if (sk && (sk->sk_family == PF_INET) &&
+ inet->nodefrag)
return NF_ACCEPT;
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c
index 1679e2c..ee5f419 100644
--- a/net/ipv4/netfilter/nf_nat_snmp_basic.c
+++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c
@@ -893,13 +893,15 @@
unsigned char s[4];
if (offset & 1) {
- s[0] = s[2] = 0;
+ s[0] = ~0;
s[1] = ~*optr;
+ s[2] = 0;
s[3] = *nptr;
} else {
- s[1] = s[3] = 0;
s[0] = ~*optr;
+ s[1] = ~0;
s[2] = *nptr;
+ s[3] = 0;
}
*csum = csum_fold(csum_partial(s, 4, ~csum_unfold(*csum)));
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 6298f75..ac6559c 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1231,7 +1231,7 @@
}
if (net_ratelimit())
- printk(KERN_WARNING "Neighbour table overflow.\n");
+ printk(KERN_WARNING "ipv4: Neighbour table overflow.\n");
rt_drop(rt);
return -ENOBUFS;
}
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 3fb1428..f115ea6 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -386,8 +386,6 @@
*/
mask = 0;
- if (sk->sk_err)
- mask = POLLERR;
/*
* POLLHUP is certainly not done right. But poll() doesn't
@@ -457,6 +455,11 @@
if (tp->urg_data & TCP_URG_VALID)
mask |= POLLPRI;
}
+ /* This barrier is coupled with smp_wmb() in tcp_reset() */
+ smp_rmb();
+ if (sk->sk_err)
+ mask |= POLLERR;
+
return mask;
}
EXPORT_SYMBOL(tcp_poll);
@@ -940,7 +943,7 @@
sg = sk->sk_route_caps & NETIF_F_SG;
while (--iovlen >= 0) {
- int seglen = iov->iov_len;
+ size_t seglen = iov->iov_len;
unsigned char __user *from = iov->iov_base;
iov++;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index e663b78..b55f60f 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -2545,7 +2545,8 @@
cnt += tcp_skb_pcount(skb);
if (cnt > packets) {
- if (tcp_is_sack(tp) || (oldcnt >= packets))
+ if ((tcp_is_sack(tp) && !tcp_is_fack(tp)) ||
+ (oldcnt >= packets))
break;
mss = skb_shinfo(skb)->gso_size;
@@ -4048,6 +4049,8 @@
default:
sk->sk_err = ECONNRESET;
}
+ /* This barrier is coupled with smp_rmb() in tcp_poll() */
+ smp_wmb();
if (!sock_flag(sk, SOCK_DEAD))
sk->sk_error_report(sk);
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index c35b469..74c54b3 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -135,13 +135,16 @@
/* This function calculates a "timeout" which is equivalent to the timeout of a
* TCP connection after "boundary" unsuccessful, exponentially backed-off
- * retransmissions with an initial RTO of TCP_RTO_MIN.
+ * retransmissions with an initial RTO of TCP_RTO_MIN or TCP_TIMEOUT_INIT if
+ * syn_set flag is set.
*/
static bool retransmits_timed_out(struct sock *sk,
- unsigned int boundary)
+ unsigned int boundary,
+ bool syn_set)
{
unsigned int timeout, linear_backoff_thresh;
unsigned int start_ts;
+ unsigned int rto_base = syn_set ? TCP_TIMEOUT_INIT : TCP_RTO_MIN;
if (!inet_csk(sk)->icsk_retransmits)
return false;
@@ -151,12 +154,12 @@
else
start_ts = tcp_sk(sk)->retrans_stamp;
- linear_backoff_thresh = ilog2(TCP_RTO_MAX/TCP_RTO_MIN);
+ linear_backoff_thresh = ilog2(TCP_RTO_MAX/rto_base);
if (boundary <= linear_backoff_thresh)
- timeout = ((2 << boundary) - 1) * TCP_RTO_MIN;
+ timeout = ((2 << boundary) - 1) * rto_base;
else
- timeout = ((2 << linear_backoff_thresh) - 1) * TCP_RTO_MIN +
+ timeout = ((2 << linear_backoff_thresh) - 1) * rto_base +
(boundary - linear_backoff_thresh) * TCP_RTO_MAX;
return (tcp_time_stamp - start_ts) >= timeout;
@@ -167,14 +170,15 @@
{
struct inet_connection_sock *icsk = inet_csk(sk);
int retry_until;
- bool do_reset;
+ bool do_reset, syn_set = 0;
if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
if (icsk->icsk_retransmits)
dst_negative_advice(sk);
retry_until = icsk->icsk_syn_retries ? : sysctl_tcp_syn_retries;
+ syn_set = 1;
} else {
- if (retransmits_timed_out(sk, sysctl_tcp_retries1)) {
+ if (retransmits_timed_out(sk, sysctl_tcp_retries1, 0)) {
/* Black hole detection */
tcp_mtu_probing(icsk, sk);
@@ -187,14 +191,14 @@
retry_until = tcp_orphan_retries(sk, alive);
do_reset = alive ||
- !retransmits_timed_out(sk, retry_until);
+ !retransmits_timed_out(sk, retry_until, 0);
if (tcp_out_of_resources(sk, do_reset))
return 1;
}
}
- if (retransmits_timed_out(sk, retry_until)) {
+ if (retransmits_timed_out(sk, retry_until, syn_set)) {
/* Has it gone just too far? */
tcp_write_err(sk);
return 1;
@@ -436,7 +440,7 @@
icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX);
}
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, TCP_RTO_MAX);
- if (retransmits_timed_out(sk, sysctl_tcp_retries1 + 1))
+ if (retransmits_timed_out(sk, sysctl_tcp_retries1 + 1, 0))
__sk_dst_reset(sk);
out:;
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 869078d..a580349 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -61,7 +61,7 @@
static int xfrm4_get_tos(struct flowi *fl)
{
- return fl->fl4_tos;
+ return IPTOS_RT_MASK & fl->fl4_tos; /* Strip ECN bits */
}
static int xfrm4_init_path(struct xfrm_dst *path, struct dst_entry *dst,
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c
index 1ef1366..4794762 100644
--- a/net/ipv4/xfrm4_state.c
+++ b/net/ipv4/xfrm4_state.c
@@ -21,21 +21,25 @@
}
static void
-__xfrm4_init_tempsel(struct xfrm_state *x, struct flowi *fl,
- struct xfrm_tmpl *tmpl,
- xfrm_address_t *daddr, xfrm_address_t *saddr)
+__xfrm4_init_tempsel(struct xfrm_selector *sel, struct flowi *fl)
{
- x->sel.daddr.a4 = fl->fl4_dst;
- x->sel.saddr.a4 = fl->fl4_src;
- x->sel.dport = xfrm_flowi_dport(fl);
- x->sel.dport_mask = htons(0xffff);
- x->sel.sport = xfrm_flowi_sport(fl);
- x->sel.sport_mask = htons(0xffff);
- x->sel.family = AF_INET;
- x->sel.prefixlen_d = 32;
- x->sel.prefixlen_s = 32;
- x->sel.proto = fl->proto;
- x->sel.ifindex = fl->oif;
+ sel->daddr.a4 = fl->fl4_dst;
+ sel->saddr.a4 = fl->fl4_src;
+ sel->dport = xfrm_flowi_dport(fl);
+ sel->dport_mask = htons(0xffff);
+ sel->sport = xfrm_flowi_sport(fl);
+ sel->sport_mask = htons(0xffff);
+ sel->family = AF_INET;
+ sel->prefixlen_d = 32;
+ sel->prefixlen_s = 32;
+ sel->proto = fl->proto;
+ sel->ifindex = fl->oif;
+}
+
+static void
+xfrm4_init_temprop(struct xfrm_state *x, struct xfrm_tmpl *tmpl,
+ xfrm_address_t *daddr, xfrm_address_t *saddr)
+{
x->id = tmpl->id;
if (x->id.daddr.a4 == 0)
x->id.daddr.a4 = daddr->a4;
@@ -70,6 +74,7 @@
.owner = THIS_MODULE,
.init_flags = xfrm4_init_flags,
.init_tempsel = __xfrm4_init_tempsel,
+ .init_temprop = xfrm4_init_temprop,
.output = xfrm4_output,
.extract_input = xfrm4_extract_input,
.extract_output = xfrm4_extract_output,
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index ab70a3f..324fac3 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -4637,10 +4637,12 @@
if (err < 0) {
printk(KERN_CRIT "IPv6 Addrconf:"
" cannot initialize default policy table: %d.\n", err);
- return err;
+ goto out;
}
- register_pernet_subsys(&addrconf_ops);
+ err = register_pernet_subsys(&addrconf_ops);
+ if (err < 0)
+ goto out_addrlabel;
/* The addrconf netdev notifier requires that loopback_dev
* has it's ipv6 private information allocated and setup
@@ -4692,7 +4694,9 @@
unregister_netdevice_notifier(&ipv6_dev_notf);
errlo:
unregister_pernet_subsys(&addrconf_ops);
-
+out_addrlabel:
+ ipv6_addr_label_cleanup();
+out:
return err;
}
@@ -4703,6 +4707,7 @@
unregister_netdevice_notifier(&ipv6_dev_notf);
unregister_pernet_subsys(&addrconf_ops);
+ ipv6_addr_label_cleanup();
rtnl_lock();
diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c
index f0e774c..8175f80 100644
--- a/net/ipv6/addrlabel.c
+++ b/net/ipv6/addrlabel.c
@@ -393,6 +393,11 @@
return register_pernet_subsys(&ipv6_addr_label_ops);
}
+void ipv6_addr_label_cleanup(void)
+{
+ unregister_pernet_subsys(&ipv6_addr_label_ops);
+}
+
static const struct nla_policy ifal_policy[IFAL_MAX+1] = {
[IFAL_ADDRESS] = { .len = sizeof(struct in6_addr), },
[IFAL_LABEL] = { .len = sizeof(u32), },
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index d40b330..980912e 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -639,7 +639,7 @@
if (skb_has_frags(skb)) {
int first_len = skb_pagelen(skb);
- int truesizes = 0;
+ struct sk_buff *frag2;
if (first_len - hlen > mtu ||
((first_len - hlen) & 7) ||
@@ -651,18 +651,18 @@
if (frag->len > mtu ||
((frag->len & 7) && frag->next) ||
skb_headroom(frag) < hlen)
- goto slow_path;
+ goto slow_path_clean;
/* Partially cloned skb? */
if (skb_shared(frag))
- goto slow_path;
+ goto slow_path_clean;
BUG_ON(frag->sk);
if (skb->sk) {
frag->sk = skb->sk;
frag->destructor = sock_wfree;
- truesizes += frag->truesize;
}
+ skb->truesize -= frag->truesize;
}
err = 0;
@@ -693,7 +693,6 @@
first_len = skb_pagelen(skb);
skb->data_len = first_len - skb_headlen(skb);
- skb->truesize -= truesizes;
skb->len = first_len;
ipv6_hdr(skb)->payload_len = htons(first_len -
sizeof(struct ipv6hdr));
@@ -756,6 +755,15 @@
IPSTATS_MIB_FRAGFAILS);
dst_release(&rt->dst);
return err;
+
+slow_path_clean:
+ skb_walk_frags(skb, frag2) {
+ if (frag2 == frag)
+ break;
+ frag2->sk = NULL;
+ frag2->destructor = NULL;
+ skb->truesize += frag2->truesize;
+ }
}
slow_path:
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index d126365..a275c6e 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -670,7 +670,7 @@
if (net_ratelimit())
printk(KERN_WARNING
- "Neighbour table overflow.\n");
+ "ipv6: Neighbour table overflow.\n");
dst_free(&rt->dst);
return NULL;
}
@@ -1556,14 +1556,13 @@
* i.e. Path MTU discovery
*/
-void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
- struct net_device *dev, u32 pmtu)
+static void rt6_do_pmtu_disc(struct in6_addr *daddr, struct in6_addr *saddr,
+ struct net *net, u32 pmtu, int ifindex)
{
struct rt6_info *rt, *nrt;
- struct net *net = dev_net(dev);
int allfrag = 0;
- rt = rt6_lookup(net, daddr, saddr, dev->ifindex, 0);
+ rt = rt6_lookup(net, daddr, saddr, ifindex, 0);
if (rt == NULL)
return;
@@ -1631,6 +1630,27 @@
dst_release(&rt->dst);
}
+void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
+ struct net_device *dev, u32 pmtu)
+{
+ struct net *net = dev_net(dev);
+
+ /*
+ * RFC 1981 states that a node "MUST reduce the size of the packets it
+ * is sending along the path" that caused the Packet Too Big message.
+ * Since it's not possible in the general case to determine which
+ * interface was used to send the original packet, we update the MTU
+ * on the interface that will be used to send future packets. We also
+ * update the MTU on the interface that received the Packet Too Big in
+ * case the original packet was forced out that interface with
+ * SO_BINDTODEVICE or similar. This is the next best thing to the
+ * correct behaviour, which would be to update the MTU on all
+ * interfaces.
+ */
+ rt6_do_pmtu_disc(daddr, saddr, net, pmtu, 0);
+ rt6_do_pmtu_disc(daddr, saddr, net, pmtu, dev->ifindex);
+}
+
/*
* Misc support functions
*/
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index f417b77..a67575d 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -20,23 +20,27 @@
#include <net/addrconf.h>
static void
-__xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl,
- struct xfrm_tmpl *tmpl,
- xfrm_address_t *daddr, xfrm_address_t *saddr)
+__xfrm6_init_tempsel(struct xfrm_selector *sel, struct flowi *fl)
{
/* Initialize temporary selector matching only
* to current session. */
- ipv6_addr_copy((struct in6_addr *)&x->sel.daddr, &fl->fl6_dst);
- ipv6_addr_copy((struct in6_addr *)&x->sel.saddr, &fl->fl6_src);
- x->sel.dport = xfrm_flowi_dport(fl);
- x->sel.dport_mask = htons(0xffff);
- x->sel.sport = xfrm_flowi_sport(fl);
- x->sel.sport_mask = htons(0xffff);
- x->sel.family = AF_INET6;
- x->sel.prefixlen_d = 128;
- x->sel.prefixlen_s = 128;
- x->sel.proto = fl->proto;
- x->sel.ifindex = fl->oif;
+ ipv6_addr_copy((struct in6_addr *)&sel->daddr, &fl->fl6_dst);
+ ipv6_addr_copy((struct in6_addr *)&sel->saddr, &fl->fl6_src);
+ sel->dport = xfrm_flowi_dport(fl);
+ sel->dport_mask = htons(0xffff);
+ sel->sport = xfrm_flowi_sport(fl);
+ sel->sport_mask = htons(0xffff);
+ sel->family = AF_INET6;
+ sel->prefixlen_d = 128;
+ sel->prefixlen_s = 128;
+ sel->proto = fl->proto;
+ sel->ifindex = fl->oif;
+}
+
+static void
+xfrm6_init_temprop(struct xfrm_state *x, struct xfrm_tmpl *tmpl,
+ xfrm_address_t *daddr, xfrm_address_t *saddr)
+{
x->id = tmpl->id;
if (ipv6_addr_any((struct in6_addr*)&x->id.daddr))
memcpy(&x->id.daddr, daddr, sizeof(x->sel.daddr));
@@ -168,6 +172,7 @@
.eth_proto = htons(ETH_P_IPV6),
.owner = THIS_MODULE,
.init_tempsel = __xfrm6_init_tempsel,
+ .init_temprop = xfrm6_init_temprop,
.tmpl_sort = __xfrm6_tmpl_sort,
.state_sort = __xfrm6_state_sort,
.output = xfrm6_output,
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index 023ba82..5826129 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -1024,7 +1024,8 @@
{
struct sock *sk = sock->sk;
struct llc_sock *llc = llc_sk(sk);
- int rc = -EINVAL, opt;
+ unsigned int opt;
+ int rc = -EINVAL;
lock_sock(sk);
if (unlikely(level != SOL_LLC || optlen != sizeof(int)))
diff --git a/net/llc/llc_station.c b/net/llc/llc_station.c
index e4dae02..cf4aea3 100644
--- a/net/llc/llc_station.c
+++ b/net/llc/llc_station.c
@@ -689,7 +689,7 @@
int __init llc_station_init(void)
{
- u16 rc = -ENOBUFS;
+ int rc = -ENOBUFS;
struct sk_buff *skb;
struct llc_station_state_ev *ev;
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index c893f23..8f23401 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -175,6 +175,8 @@
set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state);
+ del_timer_sync(&tid_tx->addba_resp_timer);
+
/*
* After this packets are no longer handed right through
* to the driver but are put onto tid_tx->pending instead,
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index fa0f37e..28624282 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2199,9 +2199,6 @@
struct net_device *prev_dev = NULL;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
- if (status->flag & RX_FLAG_INTERNAL_CMTR)
- goto out_free_skb;
-
if (skb_headroom(skb) < sizeof(*rthdr) &&
pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC))
goto out_free_skb;
@@ -2260,7 +2257,6 @@
} else
goto out_free_skb;
- status->flag |= RX_FLAG_INTERNAL_CMTR;
return;
out_free_skb:
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 10caec5..34da679 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -377,7 +377,7 @@
skb2 = skb_clone(skb, GFP_ATOMIC);
if (skb2) {
skb2->dev = prev_dev;
- netif_receive_skb(skb2);
+ netif_rx(skb2);
}
}
@@ -386,7 +386,7 @@
}
if (prev_dev) {
skb->dev = prev_dev;
- netif_receive_skb(skb);
+ netif_rx(skb);
skb = NULL;
}
rcu_read_unlock();
diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c
index 7dcf7a4..8d9e4c9 100644
--- a/net/netfilter/nf_conntrack_extend.c
+++ b/net/netfilter/nf_conntrack_extend.c
@@ -48,15 +48,17 @@
{
unsigned int off, len;
struct nf_ct_ext_type *t;
+ size_t alloc_size;
rcu_read_lock();
t = rcu_dereference(nf_ct_ext_types[id]);
BUG_ON(t == NULL);
off = ALIGN(sizeof(struct nf_ct_ext), t->align);
len = off + t->len;
+ alloc_size = t->alloc_size;
rcu_read_unlock();
- *ext = kzalloc(t->alloc_size, gfp);
+ *ext = kzalloc(alloc_size, gfp);
if (!*ext)
return NULL;
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 53d8922..f64de95 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -1376,7 +1376,7 @@
unsigned int msglen, origlen;
const char *dptr, *end;
s16 diff, tdiff = 0;
- int ret;
+ int ret = NF_ACCEPT;
typeof(nf_nat_sip_seq_adjust_hook) nf_nat_sip_seq_adjust;
if (ctinfo != IP_CT_ESTABLISHED &&
diff --git a/net/netfilter/nf_tproxy_core.c b/net/netfilter/nf_tproxy_core.c
index 5490fc3..daab8c4 100644
--- a/net/netfilter/nf_tproxy_core.c
+++ b/net/netfilter/nf_tproxy_core.c
@@ -70,7 +70,11 @@
int
nf_tproxy_assign_sock(struct sk_buff *skb, struct sock *sk)
{
- if (inet_sk(sk)->transparent) {
+ bool transparent = (sk->sk_state == TCP_TIME_WAIT) ?
+ inet_twsk(sk)->tw_transparent :
+ inet_sk(sk)->transparent;
+
+ if (transparent) {
skb_orphan(skb);
skb->sk = sk;
skb->destructor = nf_tproxy_destructor;
diff --git a/net/phonet/pep.c b/net/phonet/pep.c
index b2a3ae6..1500302 100644
--- a/net/phonet/pep.c
+++ b/net/phonet/pep.c
@@ -225,12 +225,13 @@
static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb)
{
struct pep_sock *pn = pep_sk(sk);
- struct pnpipehdr *hdr = pnp_hdr(skb);
+ struct pnpipehdr *hdr;
int wake = 0;
if (!pskb_may_pull(skb, sizeof(*hdr) + 4))
return -EINVAL;
+ hdr = pnp_hdr(skb);
if (hdr->data[0] != PN_PEP_TYPE_COMMON) {
LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP type: %u\n",
(unsigned)hdr->data[0]);
diff --git a/net/rds/page.c b/net/rds/page.c
index 595a952..1dfbfea 100644
--- a/net/rds/page.c
+++ b/net/rds/page.c
@@ -57,30 +57,17 @@
unsigned long ret;
void *addr;
- if (to_user)
+ addr = kmap(page);
+ if (to_user) {
rds_stats_add(s_copy_to_user, bytes);
- else
+ ret = copy_to_user(ptr, addr + offset, bytes);
+ } else {
rds_stats_add(s_copy_from_user, bytes);
-
- addr = kmap_atomic(page, KM_USER0);
- if (to_user)
- ret = __copy_to_user_inatomic(ptr, addr + offset, bytes);
- else
- ret = __copy_from_user_inatomic(addr + offset, ptr, bytes);
- kunmap_atomic(addr, KM_USER0);
-
- if (ret) {
- addr = kmap(page);
- if (to_user)
- ret = copy_to_user(ptr, addr + offset, bytes);
- else
- ret = copy_from_user(addr + offset, ptr, bytes);
- kunmap(page);
- if (ret)
- return -EFAULT;
+ ret = copy_from_user(addr + offset, ptr, bytes);
}
+ kunmap(page);
- return 0;
+ return ret ? -EFAULT : 0;
}
EXPORT_SYMBOL_GPL(rds_page_copy_user);
diff --git a/net/rds/tcp_connect.c b/net/rds/tcp_connect.c
index c397524..c519939 100644
--- a/net/rds/tcp_connect.c
+++ b/net/rds/tcp_connect.c
@@ -43,7 +43,7 @@
struct rds_connection *conn;
struct rds_tcp_connection *tc;
- read_lock(&sk->sk_callback_lock);
+ read_lock_bh(&sk->sk_callback_lock);
conn = sk->sk_user_data;
if (conn == NULL) {
state_change = sk->sk_state_change;
@@ -68,7 +68,7 @@
break;
}
out:
- read_unlock(&sk->sk_callback_lock);
+ read_unlock_bh(&sk->sk_callback_lock);
state_change(sk);
}
diff --git a/net/rds/tcp_listen.c b/net/rds/tcp_listen.c
index 975183f..27844f2 100644
--- a/net/rds/tcp_listen.c
+++ b/net/rds/tcp_listen.c
@@ -114,7 +114,7 @@
rdsdebug("listen data ready sk %p\n", sk);
- read_lock(&sk->sk_callback_lock);
+ read_lock_bh(&sk->sk_callback_lock);
ready = sk->sk_user_data;
if (ready == NULL) { /* check for teardown race */
ready = sk->sk_data_ready;
@@ -131,7 +131,7 @@
queue_work(rds_wq, &rds_tcp_listen_work);
out:
- read_unlock(&sk->sk_callback_lock);
+ read_unlock_bh(&sk->sk_callback_lock);
ready(sk, bytes);
}
diff --git a/net/rds/tcp_recv.c b/net/rds/tcp_recv.c
index 1aba687..e437974 100644
--- a/net/rds/tcp_recv.c
+++ b/net/rds/tcp_recv.c
@@ -324,7 +324,7 @@
rdsdebug("data ready sk %p bytes %d\n", sk, bytes);
- read_lock(&sk->sk_callback_lock);
+ read_lock_bh(&sk->sk_callback_lock);
conn = sk->sk_user_data;
if (conn == NULL) { /* check for teardown race */
ready = sk->sk_data_ready;
@@ -338,7 +338,7 @@
if (rds_tcp_read_sock(conn, GFP_ATOMIC, KM_SOFTIRQ0) == -ENOMEM)
queue_delayed_work(rds_wq, &conn->c_recv_w, 0);
out:
- read_unlock(&sk->sk_callback_lock);
+ read_unlock_bh(&sk->sk_callback_lock);
ready(sk, bytes);
}
diff --git a/net/rds/tcp_send.c b/net/rds/tcp_send.c
index a28b895..2f012a0 100644
--- a/net/rds/tcp_send.c
+++ b/net/rds/tcp_send.c
@@ -224,7 +224,7 @@
struct rds_connection *conn;
struct rds_tcp_connection *tc;
- read_lock(&sk->sk_callback_lock);
+ read_lock_bh(&sk->sk_callback_lock);
conn = sk->sk_user_data;
if (conn == NULL) {
write_space = sk->sk_write_space;
@@ -244,7 +244,7 @@
queue_delayed_work(rds_wq, &conn->c_send_w, 0);
out:
- read_unlock(&sk->sk_callback_lock);
+ read_unlock_bh(&sk->sk_callback_lock);
/*
* write_space is only called when data leaves tcp's send queue if
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index 8e45e76..d952e7e 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -679,7 +679,7 @@
if (addr_len == sizeof(struct sockaddr_rose) && addr->srose_ndigis > 1)
return -EINVAL;
- if (addr->srose_ndigis > ROSE_MAX_DIGIS)
+ if ((unsigned int) addr->srose_ndigis > ROSE_MAX_DIGIS)
return -EINVAL;
if ((dev = rose_dev_get(&addr->srose_addr)) == NULL) {
@@ -739,7 +739,7 @@
if (addr_len == sizeof(struct sockaddr_rose) && addr->srose_ndigis > 1)
return -EINVAL;
- if (addr->srose_ndigis > ROSE_MAX_DIGIS)
+ if ((unsigned int) addr->srose_ndigis > ROSE_MAX_DIGIS)
return -EINVAL;
/* Source + Destination digis should not exceed ROSE_MAX_DIGIS */
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index 7416a5c..b0c2a82 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -137,7 +137,7 @@
int toff = off + key->off + (off2 & key->offmask);
__be32 *data, _data;
- if (skb_headroom(skb) + toff < 0)
+ if (skb_headroom(skb) + toff > INT_MAX)
goto out;
data = skb_header_pointer(skb, toff, 4, &_data);
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index 3406627..6318e11 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -255,10 +255,6 @@
error = -EINVAL;
goto err_out;
}
- if (!list_empty(&flow->list)) {
- error = -EEXIST;
- goto err_out;
- }
} else {
int i;
unsigned long cl;
diff --git a/net/sctp/auth.c b/net/sctp/auth.c
index 8636639..ddbbf7c 100644
--- a/net/sctp/auth.c
+++ b/net/sctp/auth.c
@@ -543,16 +543,20 @@
id = ntohs(hmacs->hmac_ids[i]);
/* Check the id is in the supported range */
- if (id > SCTP_AUTH_HMAC_ID_MAX)
+ if (id > SCTP_AUTH_HMAC_ID_MAX) {
+ id = 0;
continue;
+ }
/* See is we support the id. Supported IDs have name and
* length fields set, so that we can allocated and use
* them. We can safely just check for name, for without the
* name, we can't allocate the TFM.
*/
- if (!sctp_hmac_list[id].hmac_name)
+ if (!sctp_hmac_list[id].hmac_name) {
+ id = 0;
continue;
+ }
break;
}
diff --git a/net/sctp/output.c b/net/sctp/output.c
index a646681..bcc4590 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -92,7 +92,6 @@
SCTP_DEBUG_PRINTK("%s: packet:%p vtag:0x%x\n", __func__,
packet, vtag);
- sctp_packet_reset(packet);
packet->vtag = vtag;
if (ecn_capable && sctp_packet_empty(packet)) {
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index ca44917..fbb7077 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -916,6 +916,11 @@
/* Walk through the addrs buffer and count the number of addresses. */
addr_buf = kaddrs;
while (walk_size < addrs_size) {
+ if (walk_size + sizeof(sa_family_t) > addrs_size) {
+ kfree(kaddrs);
+ return -EINVAL;
+ }
+
sa_addr = (struct sockaddr *)addr_buf;
af = sctp_get_af_specific(sa_addr->sa_family);
@@ -1002,9 +1007,13 @@
/* Walk through the addrs buffer and count the number of addresses. */
addr_buf = kaddrs;
while (walk_size < addrs_size) {
+ if (walk_size + sizeof(sa_family_t) > addrs_size) {
+ err = -EINVAL;
+ goto out_free;
+ }
+
sa_addr = (union sctp_addr *)addr_buf;
af = sctp_get_af_specific(sa_addr->sa.sa_family);
- port = ntohs(sa_addr->v4.sin_port);
/* If the address family is not supported or if this address
* causes the address buffer to overflow return EINVAL.
@@ -1014,6 +1023,8 @@
goto out_free;
}
+ port = ntohs(sa_addr->v4.sin_port);
+
/* Save current address so we can work with it */
memcpy(&to, sa_addr, af->sockaddr_len);
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index 36cb660..e9eaaf7 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -38,7 +38,7 @@
static LIST_HEAD(cred_unused);
static unsigned long number_cred_unused;
-#define MAX_HASHTABLE_BITS (10)
+#define MAX_HASHTABLE_BITS (14)
static int param_set_hashtbl_sz(const char *val, const struct kernel_param *kp)
{
unsigned long num;
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index dcfc66b..12c4859 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -745,17 +745,18 @@
struct rpc_inode *rpci = RPC_I(inode);
struct gss_upcall_msg *gss_msg;
+restart:
spin_lock(&inode->i_lock);
- while (!list_empty(&rpci->in_downcall)) {
+ list_for_each_entry(gss_msg, &rpci->in_downcall, list) {
- gss_msg = list_entry(rpci->in_downcall.next,
- struct gss_upcall_msg, list);
+ if (!list_empty(&gss_msg->msg.list))
+ continue;
gss_msg->msg.errno = -EPIPE;
atomic_inc(&gss_msg->count);
__gss_unhash_msg(gss_msg);
spin_unlock(&inode->i_lock);
gss_release_msg(gss_msg);
- spin_lock(&inode->i_lock);
+ goto restart;
}
spin_unlock(&inode->i_lock);
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index 0326446..778e5df 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -237,6 +237,7 @@
if (!supported_gss_krb5_enctype(alg)) {
printk(KERN_WARNING "gss_kerberos_mech: unsupported "
"encryption key algorithm %d\n", alg);
+ p = ERR_PTR(-EINVAL);
goto out_err;
}
p = simple_get_netobj(p, end, &key);
@@ -282,15 +283,19 @@
ctx->enctype = ENCTYPE_DES_CBC_RAW;
ctx->gk5e = get_gss_krb5_enctype(ctx->enctype);
- if (ctx->gk5e == NULL)
+ if (ctx->gk5e == NULL) {
+ p = ERR_PTR(-EINVAL);
goto out_err;
+ }
/* The downcall format was designed before we completely understood
* the uses of the context fields; so it includes some stuff we
* just give some minimal sanity-checking, and some we ignore
* completely (like the next twenty bytes): */
- if (unlikely(p + 20 > end || p + 20 < p))
+ if (unlikely(p + 20 > end || p + 20 < p)) {
+ p = ERR_PTR(-EFAULT);
goto out_err;
+ }
p += 20;
p = simple_get_bytes(p, end, &tmp, sizeof(tmp));
if (IS_ERR(p))
@@ -619,6 +624,7 @@
if (ctx->seq_send64 != ctx->seq_send) {
dprintk("%s: seq_send64 %lx, seq_send %x overflow?\n", __func__,
(long unsigned)ctx->seq_send64, ctx->seq_send);
+ p = ERR_PTR(-EINVAL);
goto out_err;
}
p = simple_get_bytes(p, end, &ctx->enctype, sizeof(ctx->enctype));
diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c
index dc3f1f5..adade3d 100644
--- a/net/sunrpc/auth_gss/gss_spkm3_mech.c
+++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c
@@ -100,6 +100,7 @@
if (version != 1) {
dprintk("RPC: unknown spkm3 token format: "
"obsolete nfs-utils?\n");
+ p = ERR_PTR(-EINVAL);
goto out_err_free_ctx;
}
@@ -135,8 +136,10 @@
if (IS_ERR(p))
goto out_err_free_intg_alg;
- if (p != end)
+ if (p != end) {
+ p = ERR_PTR(-EFAULT);
goto out_err_free_intg_key;
+ }
ctx_id->internal_ctx_id = ctx;
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 2388d83..fa55490 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -226,7 +226,7 @@
goto out_no_principal;
}
- kref_init(&clnt->cl_kref);
+ atomic_set(&clnt->cl_count, 1);
err = rpc_setup_pipedir(clnt, program->pipe_dir_name);
if (err < 0)
@@ -390,14 +390,14 @@
if (new->cl_principal == NULL)
goto out_no_principal;
}
- kref_init(&new->cl_kref);
+ atomic_set(&new->cl_count, 1);
err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name);
if (err != 0)
goto out_no_path;
if (new->cl_auth)
atomic_inc(&new->cl_auth->au_count);
xprt_get(clnt->cl_xprt);
- kref_get(&clnt->cl_kref);
+ atomic_inc(&clnt->cl_count);
rpc_register_client(new);
rpciod_up();
return new;
@@ -465,10 +465,8 @@
* Free an RPC client
*/
static void
-rpc_free_client(struct kref *kref)
+rpc_free_client(struct rpc_clnt *clnt)
{
- struct rpc_clnt *clnt = container_of(kref, struct rpc_clnt, cl_kref);
-
dprintk("RPC: destroying %s client for %s\n",
clnt->cl_protname, clnt->cl_server);
if (!IS_ERR(clnt->cl_path.dentry)) {
@@ -495,12 +493,10 @@
* Free an RPC client
*/
static void
-rpc_free_auth(struct kref *kref)
+rpc_free_auth(struct rpc_clnt *clnt)
{
- struct rpc_clnt *clnt = container_of(kref, struct rpc_clnt, cl_kref);
-
if (clnt->cl_auth == NULL) {
- rpc_free_client(kref);
+ rpc_free_client(clnt);
return;
}
@@ -509,10 +505,11 @@
* release remaining GSS contexts. This mechanism ensures
* that it can do so safely.
*/
- kref_init(kref);
+ atomic_inc(&clnt->cl_count);
rpcauth_release(clnt->cl_auth);
clnt->cl_auth = NULL;
- kref_put(kref, rpc_free_client);
+ if (atomic_dec_and_test(&clnt->cl_count))
+ rpc_free_client(clnt);
}
/*
@@ -525,7 +522,8 @@
if (list_empty(&clnt->cl_tasks))
wake_up(&destroy_wait);
- kref_put(&clnt->cl_kref, rpc_free_auth);
+ if (atomic_dec_and_test(&clnt->cl_count))
+ rpc_free_auth(clnt);
}
/**
@@ -588,7 +586,7 @@
if (clnt != NULL) {
rpc_task_release_client(task);
task->tk_client = clnt;
- kref_get(&clnt->cl_kref);
+ atomic_inc(&clnt->cl_count);
if (clnt->cl_softrtry)
task->tk_flags |= RPC_TASK_SOFT;
/* Add to the client's list of all tasks */
@@ -931,7 +929,7 @@
task->tk_status = 0;
if (status >= 0) {
if (task->tk_rqstp) {
- task->tk_action = call_allocate;
+ task->tk_action = call_refresh;
return;
}
@@ -966,13 +964,54 @@
}
/*
- * 2. Allocate the buffer. For details, see sched.c:rpc_malloc.
+ * 2. Bind and/or refresh the credentials
+ */
+static void
+call_refresh(struct rpc_task *task)
+{
+ dprint_status(task);
+
+ task->tk_action = call_refreshresult;
+ task->tk_status = 0;
+ task->tk_client->cl_stats->rpcauthrefresh++;
+ rpcauth_refreshcred(task);
+}
+
+/*
+ * 2a. Process the results of a credential refresh
+ */
+static void
+call_refreshresult(struct rpc_task *task)
+{
+ int status = task->tk_status;
+
+ dprint_status(task);
+
+ task->tk_status = 0;
+ task->tk_action = call_allocate;
+ if (status >= 0 && rpcauth_uptodatecred(task))
+ return;
+ switch (status) {
+ case -EACCES:
+ rpc_exit(task, -EACCES);
+ return;
+ case -ENOMEM:
+ rpc_exit(task, -ENOMEM);
+ return;
+ case -ETIMEDOUT:
+ rpc_delay(task, 3*HZ);
+ }
+ task->tk_action = call_refresh;
+}
+
+/*
+ * 2b. Allocate the buffer. For details, see sched.c:rpc_malloc.
* (Note: buffer memory is freed in xprt_release).
*/
static void
call_allocate(struct rpc_task *task)
{
- unsigned int slack = task->tk_client->cl_auth->au_cslack;
+ unsigned int slack = task->tk_rqstp->rq_cred->cr_auth->au_cslack;
struct rpc_rqst *req = task->tk_rqstp;
struct rpc_xprt *xprt = task->tk_xprt;
struct rpc_procinfo *proc = task->tk_msg.rpc_proc;
@@ -980,7 +1019,7 @@
dprint_status(task);
task->tk_status = 0;
- task->tk_action = call_refresh;
+ task->tk_action = call_bind;
if (req->rq_buffer)
return;
@@ -1017,47 +1056,6 @@
rpc_exit(task, -ERESTARTSYS);
}
-/*
- * 2a. Bind and/or refresh the credentials
- */
-static void
-call_refresh(struct rpc_task *task)
-{
- dprint_status(task);
-
- task->tk_action = call_refreshresult;
- task->tk_status = 0;
- task->tk_client->cl_stats->rpcauthrefresh++;
- rpcauth_refreshcred(task);
-}
-
-/*
- * 2b. Process the results of a credential refresh
- */
-static void
-call_refreshresult(struct rpc_task *task)
-{
- int status = task->tk_status;
-
- dprint_status(task);
-
- task->tk_status = 0;
- task->tk_action = call_bind;
- if (status >= 0 && rpcauth_uptodatecred(task))
- return;
- switch (status) {
- case -EACCES:
- rpc_exit(task, -EACCES);
- return;
- case -ENOMEM:
- rpc_exit(task, -ENOMEM);
- return;
- case -ETIMEDOUT:
- rpc_delay(task, 3*HZ);
- }
- task->tk_action = call_refresh;
-}
-
static inline int
rpc_task_need_encode(struct rpc_task *task)
{
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 95ccbcf..8c8eef2 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -48,7 +48,7 @@
return;
do {
msg = list_entry(head->next, struct rpc_pipe_msg, list);
- list_del(&msg->list);
+ list_del_init(&msg->list);
msg->errno = err;
destroy_msg(msg);
} while (!list_empty(head));
@@ -208,7 +208,7 @@
if (msg != NULL) {
spin_lock(&inode->i_lock);
msg->errno = -EAGAIN;
- list_del(&msg->list);
+ list_del_init(&msg->list);
spin_unlock(&inode->i_lock);
rpci->ops->destroy_msg(msg);
}
@@ -268,7 +268,7 @@
if (res < 0 || msg->len == msg->copied) {
filp->private_data = NULL;
spin_lock(&inode->i_lock);
- list_del(&msg->list);
+ list_del_init(&msg->list);
spin_unlock(&inode->i_lock);
rpci->ops->destroy_msg(msg);
}
@@ -371,21 +371,23 @@
static int
rpc_info_open(struct inode *inode, struct file *file)
{
- struct rpc_clnt *clnt;
+ struct rpc_clnt *clnt = NULL;
int ret = single_open(file, rpc_show_info, NULL);
if (!ret) {
struct seq_file *m = file->private_data;
- mutex_lock(&inode->i_mutex);
- clnt = RPC_I(inode)->private;
- if (clnt) {
- kref_get(&clnt->cl_kref);
+
+ spin_lock(&file->f_path.dentry->d_lock);
+ if (!d_unhashed(file->f_path.dentry))
+ clnt = RPC_I(inode)->private;
+ if (clnt != NULL && atomic_inc_not_zero(&clnt->cl_count)) {
+ spin_unlock(&file->f_path.dentry->d_lock);
m->private = clnt;
} else {
+ spin_unlock(&file->f_path.dentry->d_lock);
single_release(inode, file);
ret = -EINVAL;
}
- mutex_unlock(&inode->i_mutex);
}
return ret;
}
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index b6309db..fe9306b 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -800,7 +800,7 @@
u32 _xid;
__be32 *xp;
- read_lock(&sk->sk_callback_lock);
+ read_lock_bh(&sk->sk_callback_lock);
dprintk("RPC: xs_udp_data_ready...\n");
if (!(xprt = xprt_from_sock(sk)))
goto out;
@@ -852,7 +852,7 @@
dropit:
skb_free_datagram(sk, skb);
out:
- read_unlock(&sk->sk_callback_lock);
+ read_unlock_bh(&sk->sk_callback_lock);
}
static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, struct xdr_skb_reader *desc)
@@ -1229,7 +1229,7 @@
dprintk("RPC: xs_tcp_data_ready...\n");
- read_lock(&sk->sk_callback_lock);
+ read_lock_bh(&sk->sk_callback_lock);
if (!(xprt = xprt_from_sock(sk)))
goto out;
if (xprt->shutdown)
@@ -1248,7 +1248,7 @@
read = tcp_read_sock(sk, &rd_desc, xs_tcp_data_recv);
} while (read > 0);
out:
- read_unlock(&sk->sk_callback_lock);
+ read_unlock_bh(&sk->sk_callback_lock);
}
/*
@@ -1301,7 +1301,7 @@
{
struct rpc_xprt *xprt;
- read_lock(&sk->sk_callback_lock);
+ read_lock_bh(&sk->sk_callback_lock);
if (!(xprt = xprt_from_sock(sk)))
goto out;
dprintk("RPC: xs_tcp_state_change client %p...\n", xprt);
@@ -1313,7 +1313,7 @@
switch (sk->sk_state) {
case TCP_ESTABLISHED:
- spin_lock_bh(&xprt->transport_lock);
+ spin_lock(&xprt->transport_lock);
if (!xprt_test_and_set_connected(xprt)) {
struct sock_xprt *transport = container_of(xprt,
struct sock_xprt, xprt);
@@ -1327,7 +1327,7 @@
xprt_wake_pending_tasks(xprt, -EAGAIN);
}
- spin_unlock_bh(&xprt->transport_lock);
+ spin_unlock(&xprt->transport_lock);
break;
case TCP_FIN_WAIT1:
/* The client initiated a shutdown of the socket */
@@ -1365,7 +1365,7 @@
xs_sock_mark_closed(xprt);
}
out:
- read_unlock(&sk->sk_callback_lock);
+ read_unlock_bh(&sk->sk_callback_lock);
}
/**
@@ -1376,7 +1376,7 @@
{
struct rpc_xprt *xprt;
- read_lock(&sk->sk_callback_lock);
+ read_lock_bh(&sk->sk_callback_lock);
if (!(xprt = xprt_from_sock(sk)))
goto out;
dprintk("RPC: %s client %p...\n"
@@ -1384,7 +1384,7 @@
__func__, xprt, sk->sk_err);
xprt_wake_pending_tasks(xprt, -EAGAIN);
out:
- read_unlock(&sk->sk_callback_lock);
+ read_unlock_bh(&sk->sk_callback_lock);
}
static void xs_write_space(struct sock *sk)
@@ -1416,13 +1416,13 @@
*/
static void xs_udp_write_space(struct sock *sk)
{
- read_lock(&sk->sk_callback_lock);
+ read_lock_bh(&sk->sk_callback_lock);
/* from net/core/sock.c:sock_def_write_space */
if (sock_writeable(sk))
xs_write_space(sk);
- read_unlock(&sk->sk_callback_lock);
+ read_unlock_bh(&sk->sk_callback_lock);
}
/**
@@ -1437,13 +1437,13 @@
*/
static void xs_tcp_write_space(struct sock *sk)
{
- read_lock(&sk->sk_callback_lock);
+ read_lock_bh(&sk->sk_callback_lock);
/* from net/core/stream.c:sk_stream_write_space */
if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk))
xs_write_space(sk);
- read_unlock(&sk->sk_callback_lock);
+ read_unlock_bh(&sk->sk_callback_lock);
}
static void xs_udp_do_set_buffer_size(struct rpc_xprt *xprt)
diff --git a/net/wireless/wext-priv.c b/net/wireless/wext-priv.c
index 3feb28e..674d426 100644
--- a/net/wireless/wext-priv.c
+++ b/net/wireless/wext-priv.c
@@ -152,7 +152,7 @@
} else if (!iwp->pointer)
return -EFAULT;
- extra = kmalloc(extra_size, GFP_KERNEL);
+ extra = kzalloc(extra_size, GFP_KERNEL);
if (!extra)
return -ENOMEM;
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index a3cca0a..64f2ae1 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -101,7 +101,7 @@
err = -EHOSTUNREACH;
goto error_nolock;
}
- skb_dst_set_noref(skb, dst);
+ skb_dst_set(skb, dst_clone(dst));
x = dst->xfrm;
} while (x && !(x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL));
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 2b3ed7a..cbab6e1 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1175,9 +1175,8 @@
tmpl->mode == XFRM_MODE_BEET) {
remote = &tmpl->id.daddr;
local = &tmpl->saddr;
- family = tmpl->encap_family;
- if (xfrm_addr_any(local, family)) {
- error = xfrm_get_saddr(net, &tmp, remote, family);
+ if (xfrm_addr_any(local, tmpl->encap_family)) {
+ error = xfrm_get_saddr(net, &tmp, remote, tmpl->encap_family);
if (error)
goto fail;
local = &tmp;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 5208b12f..eb96ce5 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -656,15 +656,23 @@
EXPORT_SYMBOL(xfrm_sad_getinfo);
static int
-xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl,
- struct xfrm_tmpl *tmpl,
- xfrm_address_t *daddr, xfrm_address_t *saddr,
- unsigned short family)
+xfrm_init_tempstate(struct xfrm_state *x, struct flowi *fl,
+ struct xfrm_tmpl *tmpl,
+ xfrm_address_t *daddr, xfrm_address_t *saddr,
+ unsigned short family)
{
struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
if (!afinfo)
return -1;
- afinfo->init_tempsel(x, fl, tmpl, daddr, saddr);
+ afinfo->init_tempsel(&x->sel, fl);
+
+ if (family != tmpl->encap_family) {
+ xfrm_state_put_afinfo(afinfo);
+ afinfo = xfrm_state_get_afinfo(tmpl->encap_family);
+ if (!afinfo)
+ return -1;
+ }
+ afinfo->init_temprop(x, tmpl, daddr, saddr);
xfrm_state_put_afinfo(afinfo);
return 0;
}
@@ -790,37 +798,38 @@
int error = 0;
struct xfrm_state *best = NULL;
u32 mark = pol->mark.v & pol->mark.m;
+ unsigned short encap_family = tmpl->encap_family;
to_put = NULL;
spin_lock_bh(&xfrm_state_lock);
- h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, family);
+ h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family);
hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) {
- if (x->props.family == family &&
+ if (x->props.family == encap_family &&
x->props.reqid == tmpl->reqid &&
(mark & x->mark.m) == x->mark.v &&
!(x->props.flags & XFRM_STATE_WILDRECV) &&
- xfrm_state_addr_check(x, daddr, saddr, family) &&
+ xfrm_state_addr_check(x, daddr, saddr, encap_family) &&
tmpl->mode == x->props.mode &&
tmpl->id.proto == x->id.proto &&
(tmpl->id.spi == x->id.spi || !tmpl->id.spi))
- xfrm_state_look_at(pol, x, fl, family, daddr, saddr,
+ xfrm_state_look_at(pol, x, fl, encap_family, daddr, saddr,
&best, &acquire_in_progress, &error);
}
if (best)
goto found;
- h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, family);
+ h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, encap_family);
hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h_wildcard, bydst) {
- if (x->props.family == family &&
+ if (x->props.family == encap_family &&
x->props.reqid == tmpl->reqid &&
(mark & x->mark.m) == x->mark.v &&
!(x->props.flags & XFRM_STATE_WILDRECV) &&
- xfrm_state_addr_check(x, daddr, saddr, family) &&
+ xfrm_state_addr_check(x, daddr, saddr, encap_family) &&
tmpl->mode == x->props.mode &&
tmpl->id.proto == x->id.proto &&
(tmpl->id.spi == x->id.spi || !tmpl->id.spi))
- xfrm_state_look_at(pol, x, fl, family, daddr, saddr,
+ xfrm_state_look_at(pol, x, fl, encap_family, daddr, saddr,
&best, &acquire_in_progress, &error);
}
@@ -829,7 +838,7 @@
if (!x && !error && !acquire_in_progress) {
if (tmpl->id.spi &&
(x0 = __xfrm_state_lookup(net, mark, daddr, tmpl->id.spi,
- tmpl->id.proto, family)) != NULL) {
+ tmpl->id.proto, encap_family)) != NULL) {
to_put = x0;
error = -EEXIST;
goto out;
@@ -839,9 +848,9 @@
error = -ENOMEM;
goto out;
}
- /* Initialize temporary selector matching only
+ /* Initialize temporary state matching only
* to current session. */
- xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family);
+ xfrm_init_tempstate(x, fl, tmpl, daddr, saddr, family);
memcpy(&x->mark, &pol->mark, sizeof(x->mark));
error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid);
@@ -856,10 +865,10 @@
x->km.state = XFRM_STATE_ACQ;
list_add(&x->km.all, &net->xfrm.state_all);
hlist_add_head(&x->bydst, net->xfrm.state_bydst+h);
- h = xfrm_src_hash(net, daddr, saddr, family);
+ h = xfrm_src_hash(net, daddr, saddr, encap_family);
hlist_add_head(&x->bysrc, net->xfrm.state_bysrc+h);
if (x->id.spi) {
- h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, family);
+ h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, encap_family);
hlist_add_head(&x->byspi, net->xfrm.state_byspi+h);
}
x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;
diff --git a/samples/kfifo/dma-example.c b/samples/kfifo/dma-example.c
index ee03a4f..0647379 100644
--- a/samples/kfifo/dma-example.c
+++ b/samples/kfifo/dma-example.c
@@ -24,6 +24,7 @@
{
int i;
unsigned int ret;
+ unsigned int nents;
struct scatterlist sg[10];
printk(KERN_INFO "DMA fifo test start\n");
@@ -61,9 +62,9 @@
* byte at the beginning, after the kfifo_skip().
*/
sg_init_table(sg, ARRAY_SIZE(sg));
- ret = kfifo_dma_in_prepare(&fifo, sg, ARRAY_SIZE(sg), FIFO_SIZE);
- printk(KERN_INFO "DMA sgl entries: %d\n", ret);
- if (!ret) {
+ nents = kfifo_dma_in_prepare(&fifo, sg, ARRAY_SIZE(sg), FIFO_SIZE);
+ printk(KERN_INFO "DMA sgl entries: %d\n", nents);
+ if (!nents) {
/* fifo is full and no sgl was created */
printk(KERN_WARNING "error kfifo_dma_in_prepare\n");
return -EIO;
@@ -71,7 +72,7 @@
/* receive data */
printk(KERN_INFO "scatterlist for receive:\n");
- for (i = 0; i < ARRAY_SIZE(sg); i++) {
+ for (i = 0; i < nents; i++) {
printk(KERN_INFO
"sg[%d] -> "
"page_link 0x%.8lx offset 0x%.8x length 0x%.8x\n",
@@ -91,16 +92,16 @@
kfifo_dma_in_finish(&fifo, ret);
/* Prepare to transmit data, example: 8 bytes */
- ret = kfifo_dma_out_prepare(&fifo, sg, ARRAY_SIZE(sg), 8);
- printk(KERN_INFO "DMA sgl entries: %d\n", ret);
- if (!ret) {
+ nents = kfifo_dma_out_prepare(&fifo, sg, ARRAY_SIZE(sg), 8);
+ printk(KERN_INFO "DMA sgl entries: %d\n", nents);
+ if (!nents) {
/* no data was available and no sgl was created */
printk(KERN_WARNING "error kfifo_dma_out_prepare\n");
return -EIO;
}
printk(KERN_INFO "scatterlist for transmit:\n");
- for (i = 0; i < ARRAY_SIZE(sg); i++) {
+ for (i = 0; i < nents; i++) {
printk(KERN_INFO
"sg[%d] -> "
"page_link 0x%.8lx offset 0x%.8x length 0x%.8x\n",
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index 5b7c86e..7ef429c 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -427,7 +427,7 @@
if (sym->name && !sym_is_choice_value(sym)) {
printf("CONFIG_%s\n", sym->name);
}
- } else {
+ } else if (input_mode != oldnoconfig) {
if (!conf_cnt++)
printf(_("*\n* Restart config...\n*\n"));
rootEntry = menu_get_parent_menu(menu);
diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h
index 6ee2e4f..170459c 100644
--- a/scripts/kconfig/expr.h
+++ b/scripts/kconfig/expr.h
@@ -165,7 +165,6 @@
struct symbol *sym;
struct property *prompt;
struct expr *dep;
- struct expr *dir_dep;
unsigned int flags;
char *help;
struct file *file;
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index 4fb5902..edda8b4 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -107,7 +107,6 @@
void menu_add_dep(struct expr *dep)
{
current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
- current_entry->dir_dep = current_entry->dep;
}
void menu_set_type(int type)
@@ -291,10 +290,6 @@
for (menu = parent->list; menu; menu = menu->next)
menu_finalize(menu);
} else if (sym) {
- /* ignore inherited dependencies for dir_dep */
- sym->dir_dep.expr = expr_transform(expr_copy(parent->dir_dep));
- sym->dir_dep.expr = expr_eliminate_dups(sym->dir_dep.expr);
-
basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
basedep = expr_eliminate_dups(expr_transform(basedep));
@@ -325,6 +320,8 @@
parent->next = last_menu->next;
last_menu->next = NULL;
}
+
+ sym->dir_dep.expr = parent->dep;
}
for (menu = parent->list; menu; menu = menu->next) {
if (sym && sym_is_choice(sym) &&
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index 943712c..1f8b305 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -350,6 +350,7 @@
}
}
calc_newval:
+#if 0
if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {
fprintf(stderr, "warning: (");
expr_fprint(sym->rev_dep.expr, stderr);
@@ -358,6 +359,7 @@
expr_fprint(sym->dir_dep.expr, stderr);
fprintf(stderr, ")\n");
}
+#endif
newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
}
if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c
index ef43995..c668b44 100644
--- a/security/tomoyo/common.c
+++ b/security/tomoyo/common.c
@@ -1416,15 +1416,19 @@
const pid_t gpid = task_pid_nr(current);
static const int tomoyo_buffer_len = 4096;
char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS);
+ pid_t ppid;
if (!buffer)
return NULL;
do_gettimeofday(&tv);
+ rcu_read_lock();
+ ppid = task_tgid_vnr(current->real_parent);
+ rcu_read_unlock();
snprintf(buffer, tomoyo_buffer_len - 1,
"#timestamp=%lu profile=%u mode=%s (global-pid=%u)"
" task={ pid=%u ppid=%u uid=%u gid=%u euid=%u"
" egid=%u suid=%u sgid=%u fsuid=%u fsgid=%u }",
tv.tv_sec, r->profile, tomoyo_mode[r->mode], gpid,
- (pid_t) sys_getpid(), (pid_t) sys_getppid(),
+ task_tgid_vnr(current), ppid,
current_uid(), current_gid(), current_euid(),
current_egid(), current_suid(), current_sgid(),
current_fsuid(), current_fsgid());
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index 04454cb..7c66bd8 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -689,9 +689,6 @@
/********** Function prototypes. **********/
-extern asmlinkage long sys_getpid(void);
-extern asmlinkage long sys_getppid(void);
-
/* Check whether the given string starts with the given keyword. */
bool tomoyo_str_starts(char **src, const char *find);
/* Get tomoyo_realpath() of current process. */
diff --git a/sound/core/control.c b/sound/core/control.c
index 070aab4..45a8180 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -31,6 +31,7 @@
/* max number of user-defined controls */
#define MAX_USER_CONTROLS 32
+#define MAX_CONTROL_COUNT 1028
struct snd_kctl_ioctl {
struct list_head list; /* list of all ioctls */
@@ -195,6 +196,10 @@
if (snd_BUG_ON(!control || !control->count))
return NULL;
+
+ if (control->count > MAX_CONTROL_COUNT)
+ return NULL;
+
kctl = kzalloc(sizeof(*kctl) + sizeof(struct snd_kcontrol_volatile) * control->count, GFP_KERNEL);
if (kctl == NULL) {
snd_printk(KERN_ERR "Cannot allocate control instance\n");
diff --git a/sound/core/init.c b/sound/core/init.c
index ec4a50c..2de45fb 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -607,11 +607,16 @@
return -EEXIST;
}
for (idx = 0; idx < snd_ecards_limit; idx++) {
- if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1))
- goto __exist;
+ if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) {
+ if (card == snd_cards[idx])
+ goto __ok;
+ else
+ goto __exist;
+ }
}
strcpy(card->id, buf1);
snd_info_card_id_change(card);
+__ok:
mutex_unlock(&snd_card_mutex);
return count;
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index f50ebf2..822dd56 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -77,7 +77,7 @@
struct snd_mixer_oss_file *fmixer;
if (file->private_data) {
- fmixer = (struct snd_mixer_oss_file *) file->private_data;
+ fmixer = file->private_data;
module_put(fmixer->card->module);
snd_card_file_remove(fmixer->card, file);
kfree(fmixer);
@@ -368,7 +368,7 @@
static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- return snd_mixer_oss_ioctl1((struct snd_mixer_oss_file *) file->private_data, cmd, arg);
+ return snd_mixer_oss_ioctl1(file->private_data, cmd, arg);
}
int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg)
@@ -582,7 +582,7 @@
struct snd_mixer_oss_slot *pslot,
int *left, int *right)
{
- struct slot *slot = (struct slot *)pslot->private_data;
+ struct slot *slot = pslot->private_data;
*left = *right = 100;
if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
@@ -618,8 +618,10 @@
if (numid == ID_UNKNOWN)
return;
down_read(&card->controls_rwsem);
- if ((kctl = snd_ctl_find_numid(card, numid)) == NULL)
+ if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
+ up_read(&card->controls_rwsem);
return;
+ }
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL)
@@ -658,7 +660,7 @@
return;
down_read(&card->controls_rwsem);
if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
- up_read(&fmixer->card->controls_rwsem);
+ up_read(&card->controls_rwsem);
return;
}
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
@@ -691,7 +693,7 @@
struct snd_mixer_oss_slot *pslot,
int left, int right)
{
- struct slot *slot = (struct slot *)pslot->private_data;
+ struct slot *slot = pslot->private_data;
if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right);
@@ -740,7 +742,7 @@
struct snd_mixer_oss_slot *pslot,
int *active)
{
- struct slot *slot = (struct slot *)pslot->private_data;
+ struct slot *slot = pslot->private_data;
int left, right;
left = right = 1;
@@ -753,7 +755,7 @@
struct snd_mixer_oss_slot *pslot,
int *active)
{
- struct slot *slot = (struct slot *)pslot->private_data;
+ struct slot *slot = pslot->private_data;
int left, right;
left = right = 1;
@@ -766,7 +768,7 @@
struct snd_mixer_oss_slot *pslot,
int active)
{
- struct slot *slot = (struct slot *)pslot->private_data;
+ struct slot *slot = pslot->private_data;
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0);
return 0;
@@ -776,7 +778,7 @@
struct snd_mixer_oss_slot *pslot,
int active)
{
- struct slot *slot = (struct slot *)pslot->private_data;
+ struct slot *slot = pslot->private_data;
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1);
return 0;
@@ -797,7 +799,7 @@
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL) {
err = -ENOMEM;
- goto __unlock;
+ goto __free_only;
}
down_read(&card->controls_rwsem);
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
@@ -813,7 +815,7 @@
if (!(mixer->mask_recsrc & (1 << idx)))
continue;
pslot = &mixer->slots[idx];
- slot = (struct slot *)pslot->private_data;
+ slot = pslot->private_data;
if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
continue;
if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
@@ -826,6 +828,7 @@
err = 0;
__unlock:
up_read(&card->controls_rwsem);
+ __free_only:
kfree(uctl);
kfree(uinfo);
return err;
@@ -847,7 +850,7 @@
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL) {
err = -ENOMEM;
- goto __unlock;
+ goto __free_only;
}
down_read(&card->controls_rwsem);
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
@@ -861,7 +864,7 @@
if (!(mixer->mask_recsrc & (1 << idx)))
continue;
pslot = &mixer->slots[idx];
- slot = (struct slot *)pslot->private_data;
+ slot = pslot->private_data;
if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
continue;
if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
@@ -880,6 +883,7 @@
err = 0;
__unlock:
up_read(&card->controls_rwsem);
+ __free_only:
kfree(uctl);
kfree(uinfo);
return err;
@@ -925,7 +929,7 @@
static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn)
{
- struct slot *p = (struct slot *)chn->private_data;
+ struct slot *p = chn->private_data;
if (p) {
if (p->allocated && p->assigned) {
kfree(p->assigned->name);
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 204af48..6b4b128 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -364,22 +364,24 @@
static void snd_pcm_substream_proc_info_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
- snd_pcm_proc_info_read((struct snd_pcm_substream *)entry->private_data,
- buffer);
+ snd_pcm_proc_info_read(entry->private_data, buffer);
}
static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct snd_pcm_substream *substream = entry->private_data;
- struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime;
+
+ mutex_lock(&substream->pcm->open_mutex);
+ runtime = substream->runtime;
if (!runtime) {
snd_iprintf(buffer, "closed\n");
- return;
+ goto unlock;
}
if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
snd_iprintf(buffer, "no setup\n");
- return;
+ goto unlock;
}
snd_iprintf(buffer, "access: %s\n", snd_pcm_access_name(runtime->access));
snd_iprintf(buffer, "format: %s\n", snd_pcm_format_name(runtime->format));
@@ -398,20 +400,25 @@
snd_iprintf(buffer, "OSS period frames: %lu\n", (unsigned long)runtime->oss.period_frames);
}
#endif
+ unlock:
+ mutex_unlock(&substream->pcm->open_mutex);
}
static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct snd_pcm_substream *substream = entry->private_data;
- struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime;
+
+ mutex_lock(&substream->pcm->open_mutex);
+ runtime = substream->runtime;
if (!runtime) {
snd_iprintf(buffer, "closed\n");
- return;
+ goto unlock;
}
if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
snd_iprintf(buffer, "no setup\n");
- return;
+ goto unlock;
}
snd_iprintf(buffer, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(runtime->tstamp_mode));
snd_iprintf(buffer, "period_step: %u\n", runtime->period_step);
@@ -421,24 +428,29 @@
snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold);
snd_iprintf(buffer, "silence_size: %lu\n", runtime->silence_size);
snd_iprintf(buffer, "boundary: %lu\n", runtime->boundary);
+ unlock:
+ mutex_unlock(&substream->pcm->open_mutex);
}
static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct snd_pcm_substream *substream = entry->private_data;
- struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime;
struct snd_pcm_status status;
int err;
+
+ mutex_lock(&substream->pcm->open_mutex);
+ runtime = substream->runtime;
if (!runtime) {
snd_iprintf(buffer, "closed\n");
- return;
+ goto unlock;
}
memset(&status, 0, sizeof(status));
err = snd_pcm_status(substream, &status);
if (err < 0) {
snd_iprintf(buffer, "error %d\n", err);
- return;
+ goto unlock;
}
snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state));
snd_iprintf(buffer, "owner_pid : %d\n", pid_vnr(substream->pid));
@@ -452,6 +464,8 @@
snd_iprintf(buffer, "-----\n");
snd_iprintf(buffer, "hw_ptr : %ld\n", runtime->status->hw_ptr);
snd_iprintf(buffer, "appl_ptr : %ld\n", runtime->control->appl_ptr);
+ unlock:
+ mutex_unlock(&substream->pcm->open_mutex);
}
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index e23e0e7..a1707cc 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -334,11 +334,15 @@
/* delta = "expected next hw_ptr" for in_interrupt != 0 */
delta = runtime->hw_ptr_interrupt + runtime->period_size;
if (delta > new_hw_ptr) {
- hw_base += runtime->buffer_size;
- if (hw_base >= runtime->boundary)
- hw_base = 0;
- new_hw_ptr = hw_base + pos;
- goto __delta;
+ /* check for double acknowledged interrupts */
+ hdelta = jiffies - runtime->hw_ptr_jiffies;
+ if (hdelta > runtime->hw_ptr_buffer_jiffies/2) {
+ hw_base += runtime->buffer_size;
+ if (hw_base >= runtime->boundary)
+ hw_base = 0;
+ new_hw_ptr = hw_base + pos;
+ goto __delta;
+ }
}
}
/* new_hw_ptr might be lower than old_hw_ptr in case when */
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 134fc6c..8bc7cb3 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -142,7 +142,7 @@
#ifdef RULES_DEBUG
#define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v
-char *snd_pcm_hw_param_names[] = {
+static const char * const snd_pcm_hw_param_names[] = {
HW_PARAM(ACCESS),
HW_PARAM(FORMAT),
HW_PARAM(SUBFORMAT),
@@ -864,6 +864,8 @@
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_trigger_tstamp(substream);
runtime->hw_ptr_jiffies = jiffies;
+ runtime->hw_ptr_buffer_jiffies = (runtime->buffer_size * HZ) /
+ runtime->rate;
runtime->status->state = state;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0)
@@ -1992,6 +1994,8 @@
substream->ops->close(substream);
substream->hw_opened = 0;
}
+ if (pm_qos_request_active(&substream->latency_pm_qos_req))
+ pm_qos_remove_request(&substream->latency_pm_qos_req);
if (substream->pcm_release) {
substream->pcm_release(substream);
substream->pcm_release = NULL;
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index a7868ad..cbbed0d 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -535,13 +535,15 @@
{
struct snd_rawmidi_file *rfile;
struct snd_rawmidi *rmidi;
+ struct module *module;
rfile = file->private_data;
rmidi = rfile->rmidi;
rawmidi_release_priv(rfile);
kfree(rfile);
+ module = rmidi->card->module;
snd_card_file_remove(rmidi->card, file);
- module_put(rmidi->card->module);
+ module_put(module);
return 0;
}
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig
index 480c386..c896116 100644
--- a/sound/drivers/Kconfig
+++ b/sound/drivers/Kconfig
@@ -74,6 +74,25 @@
To compile this driver as a module, choose M here: the module
will be called snd-dummy.
+config SND_ALOOP
+ tristate "Generic loopback driver (PCM)"
+ select SND_PCM
+ help
+ Say 'Y' or 'M' to include support for the PCM loopback device.
+ This module returns played samples back to the user space using
+ the standard ALSA PCM device. The devices are routed 0->1 and
+ 1->0, where first number is the playback PCM device and second
+ number is the capture device. Module creates two PCM devices and
+ configured number of substreams (see the pcm_substreams module
+ parameter).
+
+ The looback device allow time sychronization with an external
+ timing source using the time shift universal control (+-20%
+ of system time).
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-aloop.
+
config SND_VIRMIDI
tristate "Virtual MIDI soundcard"
depends on SND_SEQUENCER
diff --git a/sound/drivers/Makefile b/sound/drivers/Makefile
index d4a07f9..1a8440c 100644
--- a/sound/drivers/Makefile
+++ b/sound/drivers/Makefile
@@ -4,6 +4,7 @@
#
snd-dummy-objs := dummy.o
+snd-aloop-objs := aloop.o
snd-mtpav-objs := mtpav.o
snd-mts64-objs := mts64.o
snd-portman2x4-objs := portman2x4.o
@@ -13,6 +14,7 @@
# Toplevel Module Dependency
obj-$(CONFIG_SND_DUMMY) += snd-dummy.o
+obj-$(CONFIG_SND_ALOOP) += snd-aloop.o
obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o
obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o
obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
new file mode 100644
index 0000000..12b44b0
--- /dev/null
+++ b/sound/drivers/aloop.c
@@ -0,0 +1,1258 @@
+/*
+ * Loopback soundcard
+ *
+ * Original code:
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
+ *
+ * More accurate positioning and full-duplex support:
+ * Copyright (c) Ahmet Ä°nan <ainan at mathematik.uni-freiburg.de>
+ *
+ * Major (almost complete) rewrite:
+ * Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ * A next major update in 2010 (separate timers for playback and capture):
+ * Copyright (c) Jaroslav Kysela <perex@perex.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/init.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/info.h>
+#include <sound/initval.h>
+
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
+MODULE_DESCRIPTION("A loopback soundcard");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{ALSA,Loopback soundcard}}");
+
+#define MAX_PCM_SUBSTREAMS 8
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
+static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
+static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8};
+static int pcm_notify[SNDRV_CARDS];
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for loopback soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for loopback soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable this loopback soundcard.");
+module_param_array(pcm_substreams, int, NULL, 0444);
+MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-8) for loopback driver.");
+module_param_array(pcm_notify, int, NULL, 0444);
+MODULE_PARM_DESC(pcm_notify, "Break capture when PCM format/rate/channels changes.");
+
+#define NO_PITCH 100000
+
+struct loopback_pcm;
+
+struct loopback_cable {
+ spinlock_t lock;
+ struct loopback_pcm *streams[2];
+ struct snd_pcm_hardware hw;
+ /* flags */
+ unsigned int valid;
+ unsigned int running;
+ unsigned int pause;
+};
+
+struct loopback_setup {
+ unsigned int notify: 1;
+ unsigned int rate_shift;
+ unsigned int format;
+ unsigned int rate;
+ unsigned int channels;
+ struct snd_ctl_elem_id active_id;
+ struct snd_ctl_elem_id format_id;
+ struct snd_ctl_elem_id rate_id;
+ struct snd_ctl_elem_id channels_id;
+};
+
+struct loopback {
+ struct snd_card *card;
+ struct mutex cable_lock;
+ struct loopback_cable *cables[MAX_PCM_SUBSTREAMS][2];
+ struct snd_pcm *pcm[2];
+ struct loopback_setup setup[MAX_PCM_SUBSTREAMS][2];
+};
+
+struct loopback_pcm {
+ struct loopback *loopback;
+ struct snd_pcm_substream *substream;
+ struct loopback_cable *cable;
+ unsigned int pcm_buffer_size;
+ unsigned int buf_pos; /* position in buffer */
+ unsigned int silent_size;
+ /* PCM parameters */
+ unsigned int pcm_period_size;
+ unsigned int pcm_bps; /* bytes per second */
+ unsigned int pcm_salign; /* bytes per sample * channels */
+ unsigned int pcm_rate_shift; /* rate shift value */
+ /* flags */
+ unsigned int period_update_pending :1;
+ /* timer stuff */
+ unsigned int irq_pos; /* fractional IRQ position */
+ unsigned int period_size_frac;
+ unsigned long last_jiffies;
+ struct timer_list timer;
+};
+
+static struct platform_device *devices[SNDRV_CARDS];
+
+static inline unsigned int byte_pos(struct loopback_pcm *dpcm, unsigned int x)
+{
+ if (dpcm->pcm_rate_shift == NO_PITCH) {
+ x /= HZ;
+ } else {
+ x = div_u64(NO_PITCH * (unsigned long long)x,
+ HZ * (unsigned long long)dpcm->pcm_rate_shift);
+ }
+ return x - (x % dpcm->pcm_salign);
+}
+
+static inline unsigned int frac_pos(struct loopback_pcm *dpcm, unsigned int x)
+{
+ if (dpcm->pcm_rate_shift == NO_PITCH) { /* no pitch */
+ return x * HZ;
+ } else {
+ x = div_u64(dpcm->pcm_rate_shift * (unsigned long long)x * HZ,
+ NO_PITCH);
+ }
+ return x;
+}
+
+static inline struct loopback_setup *get_setup(struct loopback_pcm *dpcm)
+{
+ int device = dpcm->substream->pstr->pcm->device;
+
+ if (dpcm->substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ device ^= 1;
+ return &dpcm->loopback->setup[dpcm->substream->number][device];
+}
+
+static inline unsigned int get_notify(struct loopback_pcm *dpcm)
+{
+ return get_setup(dpcm)->notify;
+}
+
+static inline unsigned int get_rate_shift(struct loopback_pcm *dpcm)
+{
+ return get_setup(dpcm)->rate_shift;
+}
+
+static void loopback_timer_start(struct loopback_pcm *dpcm)
+{
+ unsigned long tick;
+ unsigned int rate_shift = get_rate_shift(dpcm);
+
+ if (rate_shift != dpcm->pcm_rate_shift) {
+ dpcm->pcm_rate_shift = rate_shift;
+ dpcm->period_size_frac = frac_pos(dpcm, dpcm->pcm_period_size);
+ }
+ if (dpcm->period_size_frac <= dpcm->irq_pos) {
+ dpcm->irq_pos %= dpcm->period_size_frac;
+ dpcm->period_update_pending = 1;
+ }
+ tick = dpcm->period_size_frac - dpcm->irq_pos;
+ tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps;
+ dpcm->timer.expires = jiffies + tick;
+ add_timer(&dpcm->timer);
+}
+
+static inline void loopback_timer_stop(struct loopback_pcm *dpcm)
+{
+ del_timer(&dpcm->timer);
+ dpcm->timer.expires = 0;
+}
+
+#define CABLE_VALID_PLAYBACK (1 << SNDRV_PCM_STREAM_PLAYBACK)
+#define CABLE_VALID_CAPTURE (1 << SNDRV_PCM_STREAM_CAPTURE)
+#define CABLE_VALID_BOTH (CABLE_VALID_PLAYBACK|CABLE_VALID_CAPTURE)
+
+static int loopback_check_format(struct loopback_cable *cable, int stream)
+{
+ struct snd_pcm_runtime *runtime, *cruntime;
+ struct loopback_setup *setup;
+ struct snd_card *card;
+ int check;
+
+ if (cable->valid != CABLE_VALID_BOTH) {
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ goto __notify;
+ return 0;
+ }
+ runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->
+ substream->runtime;
+ cruntime = cable->streams[SNDRV_PCM_STREAM_CAPTURE]->
+ substream->runtime;
+ check = runtime->format != cruntime->format ||
+ runtime->rate != cruntime->rate ||
+ runtime->channels != cruntime->channels;
+ if (!check)
+ return 0;
+ if (stream == SNDRV_PCM_STREAM_CAPTURE) {
+ return -EIO;
+ } else {
+ snd_pcm_stop(cable->streams[SNDRV_PCM_STREAM_CAPTURE]->
+ substream, SNDRV_PCM_STATE_DRAINING);
+ __notify:
+ runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->
+ substream->runtime;
+ setup = get_setup(cable->streams[SNDRV_PCM_STREAM_PLAYBACK]);
+ card = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->loopback->card;
+ if (setup->format != runtime->format) {
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &setup->format_id);
+ setup->format = runtime->format;
+ }
+ if (setup->rate != runtime->rate) {
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &setup->rate_id);
+ setup->rate = runtime->rate;
+ }
+ if (setup->channels != runtime->channels) {
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &setup->channels_id);
+ setup->channels = runtime->channels;
+ }
+ }
+ return 0;
+}
+
+static void loopback_active_notify(struct loopback_pcm *dpcm)
+{
+ snd_ctl_notify(dpcm->loopback->card,
+ SNDRV_CTL_EVENT_MASK_VALUE,
+ &get_setup(dpcm)->active_id);
+}
+
+static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct loopback_pcm *dpcm = runtime->private_data;
+ struct loopback_cable *cable = dpcm->cable;
+ int err, stream = 1 << substream->stream;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ err = loopback_check_format(cable, substream->stream);
+ if (err < 0)
+ return err;
+ dpcm->last_jiffies = jiffies;
+ dpcm->pcm_rate_shift = 0;
+ spin_lock(&cable->lock);
+ cable->running |= stream;
+ cable->pause &= ~stream;
+ spin_unlock(&cable->lock);
+ loopback_timer_start(dpcm);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ loopback_active_notify(dpcm);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ spin_lock(&cable->lock);
+ cable->running &= ~stream;
+ cable->pause &= ~stream;
+ spin_unlock(&cable->lock);
+ loopback_timer_stop(dpcm);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ loopback_active_notify(dpcm);
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ spin_lock(&cable->lock);
+ cable->pause |= stream;
+ spin_unlock(&cable->lock);
+ loopback_timer_stop(dpcm);
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ spin_lock(&cable->lock);
+ dpcm->last_jiffies = jiffies;
+ cable->pause &= ~stream;
+ spin_unlock(&cable->lock);
+ loopback_timer_start(dpcm);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void params_change_substream(struct loopback_pcm *dpcm,
+ struct snd_pcm_runtime *runtime)
+{
+ struct snd_pcm_runtime *dst_runtime;
+
+ if (dpcm == NULL || dpcm->substream == NULL)
+ return;
+ dst_runtime = dpcm->substream->runtime;
+ if (dst_runtime == NULL)
+ return;
+ dst_runtime->hw = dpcm->cable->hw;
+}
+
+static void params_change(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct loopback_pcm *dpcm = runtime->private_data;
+ struct loopback_cable *cable = dpcm->cable;
+
+ cable->hw.formats = (1ULL << runtime->format);
+ cable->hw.rate_min = runtime->rate;
+ cable->hw.rate_max = runtime->rate;
+ cable->hw.channels_min = runtime->channels;
+ cable->hw.channels_max = runtime->channels;
+ params_change_substream(cable->streams[SNDRV_PCM_STREAM_PLAYBACK],
+ runtime);
+ params_change_substream(cable->streams[SNDRV_PCM_STREAM_CAPTURE],
+ runtime);
+}
+
+static int loopback_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct loopback_pcm *dpcm = runtime->private_data;
+ struct loopback_cable *cable = dpcm->cable;
+ int bps, salign;
+
+ salign = (snd_pcm_format_width(runtime->format) *
+ runtime->channels) / 8;
+ bps = salign * runtime->rate;
+ if (bps <= 0 || salign <= 0)
+ return -EINVAL;
+
+ dpcm->buf_pos = 0;
+ dpcm->pcm_buffer_size = frames_to_bytes(runtime, runtime->buffer_size);
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ /* clear capture buffer */
+ dpcm->silent_size = dpcm->pcm_buffer_size;
+ snd_pcm_format_set_silence(runtime->format, runtime->dma_area,
+ runtime->buffer_size * runtime->channels);
+ }
+
+ dpcm->irq_pos = 0;
+ dpcm->period_update_pending = 0;
+ dpcm->pcm_bps = bps;
+ dpcm->pcm_salign = salign;
+ dpcm->pcm_period_size = frames_to_bytes(runtime, runtime->period_size);
+
+ mutex_lock(&dpcm->loopback->cable_lock);
+ if (!(cable->valid & ~(1 << substream->stream)) ||
+ (get_setup(dpcm)->notify &&
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK))
+ params_change(substream);
+ cable->valid |= 1 << substream->stream;
+ mutex_unlock(&dpcm->loopback->cable_lock);
+
+ return 0;
+}
+
+static void clear_capture_buf(struct loopback_pcm *dpcm, unsigned int bytes)
+{
+ struct snd_pcm_runtime *runtime = dpcm->substream->runtime;
+ char *dst = runtime->dma_area;
+ unsigned int dst_off = dpcm->buf_pos;
+
+ if (dpcm->silent_size >= dpcm->pcm_buffer_size)
+ return;
+ if (dpcm->silent_size + bytes > dpcm->pcm_buffer_size)
+ bytes = dpcm->pcm_buffer_size - dpcm->silent_size;
+
+ for (;;) {
+ unsigned int size = bytes;
+ if (dst_off + size > dpcm->pcm_buffer_size)
+ size = dpcm->pcm_buffer_size - dst_off;
+ snd_pcm_format_set_silence(runtime->format, dst + dst_off,
+ bytes_to_frames(runtime, size) *
+ runtime->channels);
+ dpcm->silent_size += size;
+ bytes -= size;
+ if (!bytes)
+ break;
+ dst_off = 0;
+ }
+}
+
+static void copy_play_buf(struct loopback_pcm *play,
+ struct loopback_pcm *capt,
+ unsigned int bytes)
+{
+ struct snd_pcm_runtime *runtime = play->substream->runtime;
+ char *src = runtime->dma_area;
+ char *dst = capt->substream->runtime->dma_area;
+ unsigned int src_off = play->buf_pos;
+ unsigned int dst_off = capt->buf_pos;
+ unsigned int clear_bytes = 0;
+
+ /* check if playback is draining, trim the capture copy size
+ * when our pointer is at the end of playback ring buffer */
+ if (runtime->status->state == SNDRV_PCM_STATE_DRAINING &&
+ snd_pcm_playback_hw_avail(runtime) < runtime->buffer_size) {
+ snd_pcm_uframes_t appl_ptr, appl_ptr1, diff;
+ appl_ptr = appl_ptr1 = runtime->control->appl_ptr;
+ appl_ptr1 -= appl_ptr1 % runtime->buffer_size;
+ appl_ptr1 += play->buf_pos / play->pcm_salign;
+ if (appl_ptr < appl_ptr1)
+ appl_ptr1 -= runtime->buffer_size;
+ diff = (appl_ptr - appl_ptr1) * play->pcm_salign;
+ if (diff < bytes) {
+ clear_bytes = bytes - diff;
+ bytes = diff;
+ }
+ }
+
+ for (;;) {
+ unsigned int size = bytes;
+ if (src_off + size > play->pcm_buffer_size)
+ size = play->pcm_buffer_size - src_off;
+ if (dst_off + size > capt->pcm_buffer_size)
+ size = capt->pcm_buffer_size - dst_off;
+ memcpy(dst + dst_off, src + src_off, size);
+ capt->silent_size = 0;
+ bytes -= size;
+ if (!bytes)
+ break;
+ src_off = (src_off + size) % play->pcm_buffer_size;
+ dst_off = (dst_off + size) % capt->pcm_buffer_size;
+ }
+
+ if (clear_bytes > 0) {
+ clear_capture_buf(capt, clear_bytes);
+ capt->silent_size = 0;
+ }
+}
+
+#define BYTEPOS_UPDATE_POSONLY 0
+#define BYTEPOS_UPDATE_CLEAR 1
+#define BYTEPOS_UPDATE_COPY 2
+
+static void loopback_bytepos_update(struct loopback_pcm *dpcm,
+ unsigned int delta,
+ unsigned int cmd)
+{
+ unsigned int count;
+ unsigned long last_pos;
+
+ last_pos = byte_pos(dpcm, dpcm->irq_pos);
+ dpcm->irq_pos += delta * dpcm->pcm_bps;
+ count = byte_pos(dpcm, dpcm->irq_pos) - last_pos;
+ if (!count)
+ return;
+ if (cmd == BYTEPOS_UPDATE_CLEAR)
+ clear_capture_buf(dpcm, count);
+ else if (cmd == BYTEPOS_UPDATE_COPY)
+ copy_play_buf(dpcm->cable->streams[SNDRV_PCM_STREAM_PLAYBACK],
+ dpcm->cable->streams[SNDRV_PCM_STREAM_CAPTURE],
+ count);
+ dpcm->buf_pos += count;
+ dpcm->buf_pos %= dpcm->pcm_buffer_size;
+ if (dpcm->irq_pos >= dpcm->period_size_frac) {
+ dpcm->irq_pos %= dpcm->period_size_frac;
+ dpcm->period_update_pending = 1;
+ }
+}
+
+static unsigned int loopback_pos_update(struct loopback_cable *cable)
+{
+ struct loopback_pcm *dpcm_play =
+ cable->streams[SNDRV_PCM_STREAM_PLAYBACK];
+ struct loopback_pcm *dpcm_capt =
+ cable->streams[SNDRV_PCM_STREAM_CAPTURE];
+ unsigned long delta_play = 0, delta_capt = 0;
+ unsigned int running;
+
+ spin_lock(&cable->lock);
+ running = cable->running ^ cable->pause;
+ if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) {
+ delta_play = jiffies - dpcm_play->last_jiffies;
+ dpcm_play->last_jiffies += delta_play;
+ }
+
+ if (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) {
+ delta_capt = jiffies - dpcm_capt->last_jiffies;
+ dpcm_capt->last_jiffies += delta_capt;
+ }
+
+ if (delta_play == 0 && delta_capt == 0) {
+ spin_unlock(&cable->lock);
+ return running;
+ }
+
+ if (delta_play > delta_capt) {
+ loopback_bytepos_update(dpcm_play, delta_play - delta_capt,
+ BYTEPOS_UPDATE_POSONLY);
+ delta_play = delta_capt;
+ } else if (delta_play < delta_capt) {
+ loopback_bytepos_update(dpcm_capt, delta_capt - delta_play,
+ BYTEPOS_UPDATE_CLEAR);
+ delta_capt = delta_play;
+ }
+
+ if (delta_play == 0 && delta_capt == 0) {
+ spin_unlock(&cable->lock);
+ return running;
+ }
+ /* note delta_capt == delta_play at this moment */
+ loopback_bytepos_update(dpcm_capt, delta_capt, BYTEPOS_UPDATE_COPY);
+ loopback_bytepos_update(dpcm_play, delta_play, BYTEPOS_UPDATE_POSONLY);
+ spin_unlock(&cable->lock);
+ return running;
+}
+
+static void loopback_timer_function(unsigned long data)
+{
+ struct loopback_pcm *dpcm = (struct loopback_pcm *)data;
+ unsigned int running;
+
+ running = loopback_pos_update(dpcm->cable);
+ if (running & (1 << dpcm->substream->stream)) {
+ loopback_timer_start(dpcm);
+ if (dpcm->period_update_pending) {
+ dpcm->period_update_pending = 0;
+ snd_pcm_period_elapsed(dpcm->substream);
+ }
+ }
+}
+
+static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct loopback_pcm *dpcm = runtime->private_data;
+
+ loopback_pos_update(dpcm->cable);
+ return bytes_to_frames(runtime, dpcm->buf_pos);
+}
+
+static struct snd_pcm_hardware loopback_pcm_hardware =
+{
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
+ SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |
+ SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE),
+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 32,
+ .buffer_bytes_max = 2 * 1024 * 1024,
+ .period_bytes_min = 64,
+ /* note check overflow in frac_pos() using pcm_rate_shift before
+ changing period_bytes_max value */
+ .period_bytes_max = 1024 * 1024,
+ .periods_min = 1,
+ .periods_max = 1024,
+ .fifo_size = 0,
+};
+
+static void loopback_runtime_free(struct snd_pcm_runtime *runtime)
+{
+ struct loopback_pcm *dpcm = runtime->private_data;
+ kfree(dpcm);
+}
+
+static int loopback_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+}
+
+static int loopback_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct loopback_pcm *dpcm = runtime->private_data;
+ struct loopback_cable *cable = dpcm->cable;
+
+ mutex_lock(&dpcm->loopback->cable_lock);
+ cable->valid &= ~(1 << substream->stream);
+ mutex_unlock(&dpcm->loopback->cable_lock);
+ return snd_pcm_lib_free_pages(substream);
+}
+
+static unsigned int get_cable_index(struct snd_pcm_substream *substream)
+{
+ if (!substream->pcm->device)
+ return substream->stream;
+ else
+ return !substream->stream;
+}
+
+static int rule_format(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+
+ struct snd_pcm_hardware *hw = rule->private;
+ struct snd_mask *maskp = hw_param_mask(params, rule->var);
+
+ maskp->bits[0] &= (u_int32_t)hw->formats;
+ maskp->bits[1] &= (u_int32_t)(hw->formats >> 32);
+ memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */
+ if (! maskp->bits[0] && ! maskp->bits[1])
+ return -EINVAL;
+ return 0;
+}
+
+static int rule_rate(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_pcm_hardware *hw = rule->private;
+ struct snd_interval t;
+
+ t.min = hw->rate_min;
+ t.max = hw->rate_max;
+ t.openmin = t.openmax = 0;
+ t.integer = 0;
+ return snd_interval_refine(hw_param_interval(params, rule->var), &t);
+}
+
+static int rule_channels(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_pcm_hardware *hw = rule->private;
+ struct snd_interval t;
+
+ t.min = hw->channels_min;
+ t.max = hw->channels_max;
+ t.openmin = t.openmax = 0;
+ t.integer = 0;
+ return snd_interval_refine(hw_param_interval(params, rule->var), &t);
+}
+
+static int loopback_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct loopback *loopback = substream->private_data;
+ struct loopback_pcm *dpcm;
+ struct loopback_cable *cable;
+ int err = 0;
+ int dev = get_cable_index(substream);
+
+ mutex_lock(&loopback->cable_lock);
+ dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
+ if (!dpcm) {
+ err = -ENOMEM;
+ goto unlock;
+ }
+ dpcm->loopback = loopback;
+ dpcm->substream = substream;
+ setup_timer(&dpcm->timer, loopback_timer_function,
+ (unsigned long)dpcm);
+
+ cable = loopback->cables[substream->number][dev];
+ if (!cable) {
+ cable = kzalloc(sizeof(*cable), GFP_KERNEL);
+ if (!cable) {
+ kfree(dpcm);
+ err = -ENOMEM;
+ goto unlock;
+ }
+ spin_lock_init(&cable->lock);
+ cable->hw = loopback_pcm_hardware;
+ loopback->cables[substream->number][dev] = cable;
+ }
+ dpcm->cable = cable;
+ cable->streams[substream->stream] = dpcm;
+
+ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+
+ /* use dynamic rules based on actual runtime->hw values */
+ /* note that the default rules created in the PCM midlevel code */
+ /* are cached -> they do not reflect the actual state */
+ err = snd_pcm_hw_rule_add(runtime, 0,
+ SNDRV_PCM_HW_PARAM_FORMAT,
+ rule_format, &runtime->hw,
+ SNDRV_PCM_HW_PARAM_FORMAT, -1);
+ if (err < 0)
+ goto unlock;
+ err = snd_pcm_hw_rule_add(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ rule_rate, &runtime->hw,
+ SNDRV_PCM_HW_PARAM_RATE, -1);
+ if (err < 0)
+ goto unlock;
+ err = snd_pcm_hw_rule_add(runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ rule_channels, &runtime->hw,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+ if (err < 0)
+ goto unlock;
+
+ runtime->private_data = dpcm;
+ runtime->private_free = loopback_runtime_free;
+ if (get_notify(dpcm))
+ runtime->hw = loopback_pcm_hardware;
+ else
+ runtime->hw = cable->hw;
+ unlock:
+ mutex_unlock(&loopback->cable_lock);
+ return err;
+}
+
+static int loopback_close(struct snd_pcm_substream *substream)
+{
+ struct loopback *loopback = substream->private_data;
+ struct loopback_pcm *dpcm = substream->runtime->private_data;
+ struct loopback_cable *cable;
+ int dev = get_cable_index(substream);
+
+ loopback_timer_stop(dpcm);
+ mutex_lock(&loopback->cable_lock);
+ cable = loopback->cables[substream->number][dev];
+ if (cable->streams[!substream->stream]) {
+ /* other stream is still alive */
+ cable->streams[substream->stream] = NULL;
+ } else {
+ /* free the cable */
+ loopback->cables[substream->number][dev] = NULL;
+ kfree(cable);
+ }
+ mutex_unlock(&loopback->cable_lock);
+ return 0;
+}
+
+static struct snd_pcm_ops loopback_playback_ops = {
+ .open = loopback_open,
+ .close = loopback_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = loopback_hw_params,
+ .hw_free = loopback_hw_free,
+ .prepare = loopback_prepare,
+ .trigger = loopback_trigger,
+ .pointer = loopback_pointer,
+};
+
+static struct snd_pcm_ops loopback_capture_ops = {
+ .open = loopback_open,
+ .close = loopback_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = loopback_hw_params,
+ .hw_free = loopback_hw_free,
+ .prepare = loopback_prepare,
+ .trigger = loopback_trigger,
+ .pointer = loopback_pointer,
+};
+
+static int __devinit loopback_pcm_new(struct loopback *loopback,
+ int device, int substreams)
+{
+ struct snd_pcm *pcm;
+ int err;
+
+ err = snd_pcm_new(loopback->card, "Loopback PCM", device,
+ substreams, substreams, &pcm);
+ if (err < 0)
+ return err;
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &loopback_playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &loopback_capture_ops);
+
+ pcm->private_data = loopback;
+ pcm->info_flags = 0;
+ strcpy(pcm->name, "Loopback PCM");
+
+ loopback->pcm[device] = pcm;
+
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data(GFP_KERNEL),
+ 0, 2 * 1024 * 1024);
+ return 0;
+}
+
+static int loopback_rate_shift_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 80000;
+ uinfo->value.integer.max = 120000;
+ uinfo->value.integer.step = 1;
+ return 0;
+}
+
+static int loopback_rate_shift_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] =
+ loopback->setup[kcontrol->id.subdevice]
+ [kcontrol->id.device].rate_shift;
+ return 0;
+}
+
+static int loopback_rate_shift_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+ unsigned int val;
+ int change = 0;
+
+ val = ucontrol->value.integer.value[0];
+ if (val < 80000)
+ val = 80000;
+ if (val > 120000)
+ val = 120000;
+ mutex_lock(&loopback->cable_lock);
+ if (val != loopback->setup[kcontrol->id.subdevice]
+ [kcontrol->id.device].rate_shift) {
+ loopback->setup[kcontrol->id.subdevice]
+ [kcontrol->id.device].rate_shift = val;
+ change = 1;
+ }
+ mutex_unlock(&loopback->cable_lock);
+ return change;
+}
+
+static int loopback_notify_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] =
+ loopback->setup[kcontrol->id.subdevice]
+ [kcontrol->id.device].notify;
+ return 0;
+}
+
+static int loopback_notify_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+ unsigned int val;
+ int change = 0;
+
+ val = ucontrol->value.integer.value[0] ? 1 : 0;
+ if (val != loopback->setup[kcontrol->id.subdevice]
+ [kcontrol->id.device].notify) {
+ loopback->setup[kcontrol->id.subdevice]
+ [kcontrol->id.device].notify = val;
+ change = 1;
+ }
+ return change;
+}
+
+static int loopback_active_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+ struct loopback_cable *cable = loopback->cables
+ [kcontrol->id.subdevice][kcontrol->id.device ^ 1];
+ unsigned int val = 0;
+
+ if (cable != NULL)
+ val = (cable->running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ?
+ 1 : 0;
+ ucontrol->value.integer.value[0] = val;
+ return 0;
+}
+
+static int loopback_format_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = SNDRV_PCM_FORMAT_LAST;
+ uinfo->value.integer.step = 1;
+ return 0;
+}
+
+static int loopback_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] =
+ loopback->setup[kcontrol->id.subdevice]
+ [kcontrol->id.device].format;
+ return 0;
+}
+
+static int loopback_rate_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 192000;
+ uinfo->value.integer.step = 1;
+ return 0;
+}
+
+static int loopback_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] =
+ loopback->setup[kcontrol->id.subdevice]
+ [kcontrol->id.device].rate;
+ return 0;
+}
+
+static int loopback_channels_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 1;
+ uinfo->value.integer.max = 1024;
+ uinfo->value.integer.step = 1;
+ return 0;
+}
+
+static int loopback_channels_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] =
+ loopback->setup[kcontrol->id.subdevice]
+ [kcontrol->id.device].channels;
+ return 0;
+}
+
+static struct snd_kcontrol_new loopback_controls[] __devinitdata = {
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "PCM Rate Shift 100000",
+ .info = loopback_rate_shift_info,
+ .get = loopback_rate_shift_get,
+ .put = loopback_rate_shift_put,
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "PCM Notify",
+ .info = snd_ctl_boolean_mono_info,
+ .get = loopback_notify_get,
+ .put = loopback_notify_put,
+},
+#define ACTIVE_IDX 2
+{
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "PCM Slave Active",
+ .info = snd_ctl_boolean_mono_info,
+ .get = loopback_active_get,
+},
+#define FORMAT_IDX 3
+{
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "PCM Slave Format",
+ .info = loopback_format_info,
+ .get = loopback_format_get
+},
+#define RATE_IDX 4
+{
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "PCM Slave Rate",
+ .info = loopback_rate_info,
+ .get = loopback_rate_get
+},
+#define CHANNELS_IDX 5
+{
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "PCM Slave Channels",
+ .info = loopback_channels_info,
+ .get = loopback_channels_get
+}
+};
+
+static int __devinit loopback_mixer_new(struct loopback *loopback, int notify)
+{
+ struct snd_card *card = loopback->card;
+ struct snd_pcm *pcm;
+ struct snd_kcontrol *kctl;
+ struct loopback_setup *setup;
+ int err, dev, substr, substr_count, idx;
+
+ strcpy(card->mixername, "Loopback Mixer");
+ for (dev = 0; dev < 2; dev++) {
+ pcm = loopback->pcm[dev];
+ substr_count =
+ pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count;
+ for (substr = 0; substr < substr_count; substr++) {
+ setup = &loopback->setup[substr][dev];
+ setup->notify = notify;
+ setup->rate_shift = NO_PITCH;
+ setup->format = SNDRV_PCM_FORMAT_S16_LE;
+ setup->rate = 48000;
+ setup->channels = 2;
+ for (idx = 0; idx < ARRAY_SIZE(loopback_controls);
+ idx++) {
+ kctl = snd_ctl_new1(&loopback_controls[idx],
+ loopback);
+ if (!kctl)
+ return -ENOMEM;
+ kctl->id.device = dev;
+ kctl->id.subdevice = substr;
+ switch (idx) {
+ case ACTIVE_IDX:
+ setup->active_id = kctl->id;
+ break;
+ case FORMAT_IDX:
+ setup->format_id = kctl->id;
+ break;
+ case RATE_IDX:
+ setup->rate_id = kctl->id;
+ break;
+ case CHANNELS_IDX:
+ setup->channels_id = kctl->id;
+ break;
+ default:
+ break;
+ }
+ err = snd_ctl_add(card, kctl);
+ if (err < 0)
+ return err;
+ }
+ }
+ }
+ return 0;
+}
+
+#ifdef CONFIG_PROC_FS
+
+static void print_dpcm_info(struct snd_info_buffer *buffer,
+ struct loopback_pcm *dpcm,
+ const char *id)
+{
+ snd_iprintf(buffer, " %s\n", id);
+ if (dpcm == NULL) {
+ snd_iprintf(buffer, " inactive\n");
+ return;
+ }
+ snd_iprintf(buffer, " buffer_size:\t%u\n", dpcm->pcm_buffer_size);
+ snd_iprintf(buffer, " buffer_pos:\t\t%u\n", dpcm->buf_pos);
+ snd_iprintf(buffer, " silent_size:\t%u\n", dpcm->silent_size);
+ snd_iprintf(buffer, " period_size:\t%u\n", dpcm->pcm_period_size);
+ snd_iprintf(buffer, " bytes_per_sec:\t%u\n", dpcm->pcm_bps);
+ snd_iprintf(buffer, " sample_align:\t%u\n", dpcm->pcm_salign);
+ snd_iprintf(buffer, " rate_shift:\t\t%u\n", dpcm->pcm_rate_shift);
+ snd_iprintf(buffer, " update_pending:\t%u\n",
+ dpcm->period_update_pending);
+ snd_iprintf(buffer, " irq_pos:\t\t%u\n", dpcm->irq_pos);
+ snd_iprintf(buffer, " period_frac:\t%u\n", dpcm->period_size_frac);
+ snd_iprintf(buffer, " last_jiffies:\t%lu (%lu)\n",
+ dpcm->last_jiffies, jiffies);
+ snd_iprintf(buffer, " timer_expires:\t%lu\n", dpcm->timer.expires);
+}
+
+static void print_substream_info(struct snd_info_buffer *buffer,
+ struct loopback *loopback,
+ int sub,
+ int num)
+{
+ struct loopback_cable *cable = loopback->cables[sub][num];
+
+ snd_iprintf(buffer, "Cable %i substream %i:\n", num, sub);
+ if (cable == NULL) {
+ snd_iprintf(buffer, " inactive\n");
+ return;
+ }
+ snd_iprintf(buffer, " valid: %u\n", cable->valid);
+ snd_iprintf(buffer, " running: %u\n", cable->running);
+ snd_iprintf(buffer, " pause: %u\n", cable->pause);
+ print_dpcm_info(buffer, cable->streams[0], "Playback");
+ print_dpcm_info(buffer, cable->streams[1], "Capture");
+}
+
+static void print_cable_info(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct loopback *loopback = entry->private_data;
+ int sub, num;
+
+ mutex_lock(&loopback->cable_lock);
+ num = entry->name[strlen(entry->name)-1];
+ num = num == '0' ? 0 : 1;
+ for (sub = 0; sub < MAX_PCM_SUBSTREAMS; sub++)
+ print_substream_info(buffer, loopback, sub, num);
+ mutex_unlock(&loopback->cable_lock);
+}
+
+static int __devinit loopback_proc_new(struct loopback *loopback, int cidx)
+{
+ char name[32];
+ struct snd_info_entry *entry;
+ int err;
+
+ snprintf(name, sizeof(name), "cable#%d", cidx);
+ err = snd_card_proc_new(loopback->card, name, &entry);
+ if (err < 0)
+ return err;
+
+ snd_info_set_text_ops(entry, loopback, print_cable_info);
+ return 0;
+}
+
+#else /* !CONFIG_PROC_FS */
+
+#define loopback_proc_new(loopback, cidx) do { } while (0)
+
+#endif
+
+static int __devinit loopback_probe(struct platform_device *devptr)
+{
+ struct snd_card *card;
+ struct loopback *loopback;
+ int dev = devptr->id;
+ int err;
+
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct loopback), &card);
+ if (err < 0)
+ return err;
+ loopback = card->private_data;
+
+ if (pcm_substreams[dev] < 1)
+ pcm_substreams[dev] = 1;
+ if (pcm_substreams[dev] > MAX_PCM_SUBSTREAMS)
+ pcm_substreams[dev] = MAX_PCM_SUBSTREAMS;
+
+ loopback->card = card;
+ mutex_init(&loopback->cable_lock);
+
+ err = loopback_pcm_new(loopback, 0, pcm_substreams[dev]);
+ if (err < 0)
+ goto __nodev;
+ err = loopback_pcm_new(loopback, 1, pcm_substreams[dev]);
+ if (err < 0)
+ goto __nodev;
+ err = loopback_mixer_new(loopback, pcm_notify[dev] ? 1 : 0);
+ if (err < 0)
+ goto __nodev;
+ loopback_proc_new(loopback, 0);
+ loopback_proc_new(loopback, 1);
+ strcpy(card->driver, "Loopback");
+ strcpy(card->shortname, "Loopback");
+ sprintf(card->longname, "Loopback %i", dev + 1);
+ err = snd_card_register(card);
+ if (!err) {
+ platform_set_drvdata(devptr, card);
+ return 0;
+ }
+ __nodev:
+ snd_card_free(card);
+ return err;
+}
+
+static int __devexit loopback_remove(struct platform_device *devptr)
+{
+ snd_card_free(platform_get_drvdata(devptr));
+ platform_set_drvdata(devptr, NULL);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int loopback_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct snd_card *card = platform_get_drvdata(pdev);
+ struct loopback *loopback = card->private_data;
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+
+ snd_pcm_suspend_all(loopback->pcm[0]);
+ snd_pcm_suspend_all(loopback->pcm[1]);
+ return 0;
+}
+
+static int loopback_resume(struct platform_device *pdev)
+{
+ struct snd_card *card = platform_get_drvdata(pdev);
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+ return 0;
+}
+#endif
+
+#define SND_LOOPBACK_DRIVER "snd_aloop"
+
+static struct platform_driver loopback_driver = {
+ .probe = loopback_probe,
+ .remove = __devexit_p(loopback_remove),
+#ifdef CONFIG_PM
+ .suspend = loopback_suspend,
+ .resume = loopback_resume,
+#endif
+ .driver = {
+ .name = SND_LOOPBACK_DRIVER
+ },
+};
+
+static void loopback_unregister_all(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(devices); ++i)
+ platform_device_unregister(devices[i]);
+ platform_driver_unregister(&loopback_driver);
+}
+
+static int __init alsa_card_loopback_init(void)
+{
+ int i, err, cards;
+
+ err = platform_driver_register(&loopback_driver);
+ if (err < 0)
+ return err;
+
+
+ cards = 0;
+ for (i = 0; i < SNDRV_CARDS; i++) {
+ struct platform_device *device;
+ if (!enable[i])
+ continue;
+ device = platform_device_register_simple(SND_LOOPBACK_DRIVER,
+ i, NULL, 0);
+ if (IS_ERR(device))
+ continue;
+ if (!platform_get_drvdata(device)) {
+ platform_device_unregister(device);
+ continue;
+ }
+ devices[i] = device;
+ cards++;
+ }
+ if (!cards) {
+#ifdef MODULE
+ printk(KERN_ERR "aloop: No loopback enabled\n");
+#endif
+ loopback_unregister_all();
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void __exit alsa_card_loopback_exit(void)
+{
+ loopback_unregister_all();
+}
+
+module_init(alsa_card_loopback_init)
+module_exit(alsa_card_loopback_exit)
diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c
index 0e631c3..f4cd493 100644
--- a/sound/drivers/virmidi.c
+++ b/sound/drivers/virmidi.c
@@ -94,7 +94,7 @@
sizeof(struct snd_card_virmidi), &card);
if (err < 0)
return err;
- vmidi = (struct snd_card_virmidi *)card->private_data;
+ vmidi = card->private_data;
vmidi->card = card;
if (midi_devs[dev] > MAX_MIDI_DEVICES) {
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
index 1adb8a3..57ccba8 100644
--- a/sound/i2c/other/ak4xxx-adda.c
+++ b/sound/i2c/other/ak4xxx-adda.c
@@ -878,7 +878,7 @@
static void proc_regs_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
- struct snd_akm4xxx *ak = (struct snd_akm4xxx *)entry->private_data;
+ struct snd_akm4xxx *ak = entry->private_data;
int reg, val, chip;
for (chip = 0; chip < ak->num_chips; chip++) {
for (reg = 0; reg < ak->total_regs; reg++) {
@@ -900,7 +900,7 @@
return 0;
}
#else /* !CONFIG_PROC_FS */
-static int proc_init(struct snd_akm4xxx *ak) {}
+static int proc_init(struct snd_akm4xxx *ak) { return 0; }
#endif
int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
index c6990c6..52064cf 100644
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -77,6 +77,32 @@
To compile this driver as a module, choose M here: the module
will be called snd-als100.
+config SND_AZT1605
+ tristate "Aztech AZT1605 Driver"
+ depends on SND
+ select SND_WSS_LIB
+ select SND_MPU401_UART
+ select SND_OPL3_LIB
+ help
+ Say Y here to include support for Aztech Sound Galaxy cards
+ based on the AZT1605 chipset.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-azt1605.
+
+config SND_AZT2316
+ tristate "Aztech AZT2316 Driver"
+ depends on SND
+ select SND_WSS_LIB
+ select SND_MPU401_UART
+ select SND_OPL3_LIB
+ help
+ Say Y here to include support for Aztech Sound Galaxy cards
+ based on the AZT2316 chipset.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-azt2316.
+
config SND_AZT2320
tristate "Aztech Systems AZT2320"
depends on PNP
@@ -351,16 +377,6 @@
coprocessor can do variable tasks like various compression and
decompression algorithms.
-config SND_SGALAXY
- tristate "Aztech Sound Galaxy"
- select SND_WSS_LIB
- help
- Say Y here to include support for Aztech Sound Galaxy
- soundcards.
-
- To compile this driver as a module, choose M here: the module
- will be called snd-sgalaxy.
-
config SND_SSCAPE
tristate "Ensoniq SoundScape driver"
select SND_MPU401_UART
diff --git a/sound/isa/Makefile b/sound/isa/Makefile
index c73d30c..8d781e4 100644
--- a/sound/isa/Makefile
+++ b/sound/isa/Makefile
@@ -10,7 +10,6 @@
snd-es18xx-objs := es18xx.o
snd-opl3sa2-objs := opl3sa2.o
snd-sc6000-objs := sc6000.o
-snd-sgalaxy-objs := sgalaxy.o
snd-sscape-objs := sscape.o
# Toplevel Module Dependency
@@ -21,8 +20,7 @@
obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o
obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o
obj-$(CONFIG_SND_SC6000) += snd-sc6000.o
-obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o
obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o
-obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ gus/ msnd/ opti9xx/ \
+obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ galaxy/ gus/ msnd/ opti9xx/ \
sb/ wavefront/ wss/
diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c
index bbcbf92..3cb75bc 100644
--- a/sound/isa/ad1816a/ad1816a.c
+++ b/sound/isa/ad1816a/ad1816a.c
@@ -162,7 +162,7 @@
sizeof(struct snd_card_ad1816a), &card);
if (error < 0)
return error;
- acard = (struct snd_card_ad1816a *)card->private_data;
+ acard = card->private_data;
if ((error = snd_card_ad1816a_pnp(dev, acard, pcard, pid))) {
snd_card_free(card);
diff --git a/sound/isa/azt2320.c b/sound/isa/azt2320.c
index f7aa637..aac8dc1 100644
--- a/sound/isa/azt2320.c
+++ b/sound/isa/azt2320.c
@@ -188,7 +188,7 @@
sizeof(struct snd_card_azt2320), &card);
if (error < 0)
return error;
- acard = (struct snd_card_azt2320 *)card->private_data;
+ acard = card->private_data;
if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) {
snd_card_free(card);
diff --git a/sound/isa/galaxy/Makefile b/sound/isa/galaxy/Makefile
new file mode 100644
index 0000000..e307066
--- /dev/null
+++ b/sound/isa/galaxy/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for ALSA
+# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
+#
+
+snd-azt1605-objs := azt1605.o
+snd-azt2316-objs := azt2316.o
+
+obj-$(CONFIG_SND_AZT1605) += snd-azt1605.o
+obj-$(CONFIG_SND_AZT2316) += snd-azt2316.o
diff --git a/sound/isa/galaxy/azt1605.c b/sound/isa/galaxy/azt1605.c
new file mode 100644
index 0000000..9a97643
--- /dev/null
+++ b/sound/isa/galaxy/azt1605.c
@@ -0,0 +1,91 @@
+/*
+ * Aztech AZT1605 Driver
+ * Copyright (C) 2007,2010 Rene Herman
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#define AZT1605
+
+#define CRD_NAME "Aztech AZT1605"
+#define DRV_NAME "AZT1605"
+#define DEV_NAME "azt1605"
+
+#define GALAXY_DSP_MAJOR 2
+#define GALAXY_DSP_MINOR 1
+
+#define GALAXY_CONFIG_SIZE 3
+
+/*
+ * 24-bit config register
+ */
+
+#define GALAXY_CONFIG_SBA_220 (0 << 0)
+#define GALAXY_CONFIG_SBA_240 (1 << 0)
+#define GALAXY_CONFIG_SBA_260 (2 << 0)
+#define GALAXY_CONFIG_SBA_280 (3 << 0)
+#define GALAXY_CONFIG_SBA_MASK GALAXY_CONFIG_SBA_280
+
+#define GALAXY_CONFIG_MPUA_300 (0 << 2)
+#define GALAXY_CONFIG_MPUA_330 (1 << 2)
+
+#define GALAXY_CONFIG_MPU_ENABLE (1 << 3)
+
+#define GALAXY_CONFIG_GAME_ENABLE (1 << 4)
+
+#define GALAXY_CONFIG_CD_PANASONIC (1 << 5)
+#define GALAXY_CONFIG_CD_MITSUMI (1 << 6)
+#define GALAXY_CONFIG_CD_MASK (\
+ GALAXY_CONFIG_CD_PANASONIC | GALAXY_CONFIG_CD_MITSUMI)
+
+#define GALAXY_CONFIG_UNUSED (1 << 7)
+#define GALAXY_CONFIG_UNUSED_MASK GALAXY_CONFIG_UNUSED
+
+#define GALAXY_CONFIG_SBIRQ_2 (1 << 8)
+#define GALAXY_CONFIG_SBIRQ_3 (1 << 9)
+#define GALAXY_CONFIG_SBIRQ_5 (1 << 10)
+#define GALAXY_CONFIG_SBIRQ_7 (1 << 11)
+
+#define GALAXY_CONFIG_MPUIRQ_2 (1 << 12)
+#define GALAXY_CONFIG_MPUIRQ_3 (1 << 13)
+#define GALAXY_CONFIG_MPUIRQ_5 (1 << 14)
+#define GALAXY_CONFIG_MPUIRQ_7 (1 << 15)
+
+#define GALAXY_CONFIG_WSSA_530 (0 << 16)
+#define GALAXY_CONFIG_WSSA_604 (1 << 16)
+#define GALAXY_CONFIG_WSSA_E80 (2 << 16)
+#define GALAXY_CONFIG_WSSA_F40 (3 << 16)
+
+#define GALAXY_CONFIG_WSS_ENABLE (1 << 18)
+
+#define GALAXY_CONFIG_CDIRQ_11 (1 << 19)
+#define GALAXY_CONFIG_CDIRQ_12 (1 << 20)
+#define GALAXY_CONFIG_CDIRQ_15 (1 << 21)
+#define GALAXY_CONFIG_CDIRQ_MASK (\
+ GALAXY_CONFIG_CDIRQ_11 | GALAXY_CONFIG_CDIRQ_12 |\
+ GALAXY_CONFIG_CDIRQ_15)
+
+#define GALAXY_CONFIG_CDDMA_DISABLE (0 << 22)
+#define GALAXY_CONFIG_CDDMA_0 (1 << 22)
+#define GALAXY_CONFIG_CDDMA_1 (2 << 22)
+#define GALAXY_CONFIG_CDDMA_3 (3 << 22)
+#define GALAXY_CONFIG_CDDMA_MASK GALAXY_CONFIG_CDDMA_3
+
+#define GALAXY_CONFIG_MASK (\
+ GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CD_MASK |\
+ GALAXY_CONFIG_UNUSED_MASK | GALAXY_CONFIG_CDIRQ_MASK |\
+ GALAXY_CONFIG_CDDMA_MASK)
+
+#include "galaxy.c"
diff --git a/sound/isa/galaxy/azt2316.c b/sound/isa/galaxy/azt2316.c
new file mode 100644
index 0000000..1894411
--- /dev/null
+++ b/sound/isa/galaxy/azt2316.c
@@ -0,0 +1,111 @@
+/*
+ * Aztech AZT2316 Driver
+ * Copyright (C) 2007,2010 Rene Herman
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#define AZT2316
+
+#define CRD_NAME "Aztech AZT2316"
+#define DRV_NAME "AZT2316"
+#define DEV_NAME "azt2316"
+
+#define GALAXY_DSP_MAJOR 3
+#define GALAXY_DSP_MINOR 1
+
+#define GALAXY_CONFIG_SIZE 4
+
+/*
+ * 32-bit config register
+ */
+
+#define GALAXY_CONFIG_SBA_220 (0 << 0)
+#define GALAXY_CONFIG_SBA_240 (1 << 0)
+#define GALAXY_CONFIG_SBA_260 (2 << 0)
+#define GALAXY_CONFIG_SBA_280 (3 << 0)
+#define GALAXY_CONFIG_SBA_MASK GALAXY_CONFIG_SBA_280
+
+#define GALAXY_CONFIG_SBIRQ_2 (1 << 2)
+#define GALAXY_CONFIG_SBIRQ_5 (1 << 3)
+#define GALAXY_CONFIG_SBIRQ_7 (1 << 4)
+#define GALAXY_CONFIG_SBIRQ_10 (1 << 5)
+
+#define GALAXY_CONFIG_SBDMA_DISABLE (0 << 6)
+#define GALAXY_CONFIG_SBDMA_0 (1 << 6)
+#define GALAXY_CONFIG_SBDMA_1 (2 << 6)
+#define GALAXY_CONFIG_SBDMA_3 (3 << 6)
+
+#define GALAXY_CONFIG_WSSA_530 (0 << 8)
+#define GALAXY_CONFIG_WSSA_604 (1 << 8)
+#define GALAXY_CONFIG_WSSA_E80 (2 << 8)
+#define GALAXY_CONFIG_WSSA_F40 (3 << 8)
+
+#define GALAXY_CONFIG_WSS_ENABLE (1 << 10)
+
+#define GALAXY_CONFIG_GAME_ENABLE (1 << 11)
+
+#define GALAXY_CONFIG_MPUA_300 (0 << 12)
+#define GALAXY_CONFIG_MPUA_330 (1 << 12)
+
+#define GALAXY_CONFIG_MPU_ENABLE (1 << 13)
+
+#define GALAXY_CONFIG_CDA_310 (0 << 14)
+#define GALAXY_CONFIG_CDA_320 (1 << 14)
+#define GALAXY_CONFIG_CDA_340 (2 << 14)
+#define GALAXY_CONFIG_CDA_350 (3 << 14)
+#define GALAXY_CONFIG_CDA_MASK GALAXY_CONFIG_CDA_350
+
+#define GALAXY_CONFIG_CD_DISABLE (0 << 16)
+#define GALAXY_CONFIG_CD_PANASONIC (1 << 16)
+#define GALAXY_CONFIG_CD_SONY (2 << 16)
+#define GALAXY_CONFIG_CD_MITSUMI (3 << 16)
+#define GALAXY_CONFIG_CD_AZTECH (4 << 16)
+#define GALAXY_CONFIG_CD_UNUSED_5 (5 << 16)
+#define GALAXY_CONFIG_CD_UNUSED_6 (6 << 16)
+#define GALAXY_CONFIG_CD_UNUSED_7 (7 << 16)
+#define GALAXY_CONFIG_CD_MASK GALAXY_CONFIG_CD_UNUSED_7
+
+#define GALAXY_CONFIG_CDDMA8_DISABLE (0 << 20)
+#define GALAXY_CONFIG_CDDMA8_0 (1 << 20)
+#define GALAXY_CONFIG_CDDMA8_1 (2 << 20)
+#define GALAXY_CONFIG_CDDMA8_3 (3 << 20)
+#define GALAXY_CONFIG_CDDMA8_MASK GALAXY_CONFIG_CDDMA8_3
+
+#define GALAXY_CONFIG_CDDMA16_DISABLE (0 << 22)
+#define GALAXY_CONFIG_CDDMA16_5 (1 << 22)
+#define GALAXY_CONFIG_CDDMA16_6 (2 << 22)
+#define GALAXY_CONFIG_CDDMA16_7 (3 << 22)
+#define GALAXY_CONFIG_CDDMA16_MASK GALAXY_CONFIG_CDDMA16_7
+
+#define GALAXY_CONFIG_MPUIRQ_2 (1 << 24)
+#define GALAXY_CONFIG_MPUIRQ_5 (1 << 25)
+#define GALAXY_CONFIG_MPUIRQ_7 (1 << 26)
+#define GALAXY_CONFIG_MPUIRQ_10 (1 << 27)
+
+#define GALAXY_CONFIG_CDIRQ_5 (1 << 28)
+#define GALAXY_CONFIG_CDIRQ_11 (1 << 29)
+#define GALAXY_CONFIG_CDIRQ_12 (1 << 30)
+#define GALAXY_CONFIG_CDIRQ_15 (1 << 31)
+#define GALAXY_CONFIG_CDIRQ_MASK (\
+ GALAXY_CONFIG_CDIRQ_5 | GALAXY_CONFIG_CDIRQ_11 |\
+ GALAXY_CONFIG_CDIRQ_12 | GALAXY_CONFIG_CDIRQ_15)
+
+#define GALAXY_CONFIG_MASK (\
+ GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CDA_MASK |\
+ GALAXY_CONFIG_CD_MASK | GALAXY_CONFIG_CDDMA16_MASK |\
+ GALAXY_CONFIG_CDDMA8_MASK | GALAXY_CONFIG_CDIRQ_MASK)
+
+#include "galaxy.c"
diff --git a/sound/isa/galaxy/galaxy.c b/sound/isa/galaxy/galaxy.c
new file mode 100644
index 0000000..ee54df0
--- /dev/null
+++ b/sound/isa/galaxy/galaxy.c
@@ -0,0 +1,652 @@
+/*
+ * Aztech AZT1605/AZT2316 Driver
+ * Copyright (C) 2007,2010 Rene Herman
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/isa.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <asm/processor.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/wss.h>
+#include <sound/mpu401.h>
+#include <sound/opl3.h>
+
+MODULE_DESCRIPTION(CRD_NAME);
+MODULE_AUTHOR("Rene Herman");
+MODULE_LICENSE("GPL");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
+
+static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+
+module_param_array(port, long, NULL, 0444);
+MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
+module_param_array(wss_port, long, NULL, 0444);
+MODULE_PARM_DESC(wss_port, "WSS port # for " CRD_NAME " driver.");
+module_param_array(mpu_port, long, NULL, 0444);
+MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver.");
+module_param_array(fm_port, long, NULL, 0444);
+MODULE_PARM_DESC(fm_port, "FM port # for " CRD_NAME " driver.");
+module_param_array(irq, int, NULL, 0444);
+MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver.");
+module_param_array(mpu_irq, int, NULL, 0444);
+MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver.");
+module_param_array(dma1, int, NULL, 0444);
+MODULE_PARM_DESC(dma1, "Playback DMA # for " CRD_NAME " driver.");
+module_param_array(dma2, int, NULL, 0444);
+MODULE_PARM_DESC(dma2, "Capture DMA # for " CRD_NAME " driver.");
+
+/*
+ * Generic SB DSP support routines
+ */
+
+#define DSP_PORT_RESET 0x6
+#define DSP_PORT_READ 0xa
+#define DSP_PORT_COMMAND 0xc
+#define DSP_PORT_STATUS 0xc
+#define DSP_PORT_DATA_AVAIL 0xe
+
+#define DSP_SIGNATURE 0xaa
+
+#define DSP_COMMAND_GET_VERSION 0xe1
+
+static int __devinit dsp_get_byte(void __iomem *port, u8 *val)
+{
+ int loops = 1000;
+
+ while (!(ioread8(port + DSP_PORT_DATA_AVAIL) & 0x80)) {
+ if (!loops--)
+ return -EIO;
+ cpu_relax();
+ }
+ *val = ioread8(port + DSP_PORT_READ);
+ return 0;
+}
+
+static int __devinit dsp_reset(void __iomem *port)
+{
+ u8 val;
+
+ iowrite8(1, port + DSP_PORT_RESET);
+ udelay(10);
+ iowrite8(0, port + DSP_PORT_RESET);
+
+ if (dsp_get_byte(port, &val) < 0 || val != DSP_SIGNATURE)
+ return -ENODEV;
+
+ return 0;
+}
+
+static int __devinit dsp_command(void __iomem *port, u8 cmd)
+{
+ int loops = 1000;
+
+ while (ioread8(port + DSP_PORT_STATUS) & 0x80) {
+ if (!loops--)
+ return -EIO;
+ cpu_relax();
+ }
+ iowrite8(cmd, port + DSP_PORT_COMMAND);
+ return 0;
+}
+
+static int __devinit dsp_get_version(void __iomem *port, u8 *major, u8 *minor)
+{
+ int err;
+
+ err = dsp_command(port, DSP_COMMAND_GET_VERSION);
+ if (err < 0)
+ return err;
+
+ err = dsp_get_byte(port, major);
+ if (err < 0)
+ return err;
+
+ err = dsp_get_byte(port, minor);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+/*
+ * Generic WSS support routines
+ */
+
+#define WSS_CONFIG_DMA_0 (1 << 0)
+#define WSS_CONFIG_DMA_1 (2 << 0)
+#define WSS_CONFIG_DMA_3 (3 << 0)
+#define WSS_CONFIG_DUPLEX (1 << 2)
+#define WSS_CONFIG_IRQ_7 (1 << 3)
+#define WSS_CONFIG_IRQ_9 (2 << 3)
+#define WSS_CONFIG_IRQ_10 (3 << 3)
+#define WSS_CONFIG_IRQ_11 (4 << 3)
+
+#define WSS_PORT_CONFIG 0
+#define WSS_PORT_SIGNATURE 3
+
+#define WSS_SIGNATURE 4
+
+static int __devinit wss_detect(void __iomem *wss_port)
+{
+ if ((ioread8(wss_port + WSS_PORT_SIGNATURE) & 0x3f) != WSS_SIGNATURE)
+ return -ENODEV;
+
+ return 0;
+}
+
+static void wss_set_config(void __iomem *wss_port, u8 wss_config)
+{
+ iowrite8(wss_config, wss_port + WSS_PORT_CONFIG);
+}
+
+/*
+ * Aztech Sound Galaxy specifics
+ */
+
+#define GALAXY_PORT_CONFIG 1024
+#define CONFIG_PORT_SET 4
+
+#define DSP_COMMAND_GALAXY_8 8
+#define GALAXY_COMMAND_GET_TYPE 5
+
+#define DSP_COMMAND_GALAXY_9 9
+#define GALAXY_COMMAND_WSSMODE 0
+#define GALAXY_COMMAND_SB8MODE 1
+
+#define GALAXY_MODE_WSS GALAXY_COMMAND_WSSMODE
+#define GALAXY_MODE_SB8 GALAXY_COMMAND_SB8MODE
+
+struct snd_galaxy {
+ void __iomem *port;
+ void __iomem *config_port;
+ void __iomem *wss_port;
+ u32 config;
+ struct resource *res_port;
+ struct resource *res_config_port;
+ struct resource *res_wss_port;
+};
+
+static u32 config[SNDRV_CARDS];
+static u8 wss_config[SNDRV_CARDS];
+
+static int __devinit snd_galaxy_match(struct device *dev, unsigned int n)
+{
+ if (!enable[n])
+ return 0;
+
+ switch (port[n]) {
+ case SNDRV_AUTO_PORT:
+ dev_err(dev, "please specify port\n");
+ return 0;
+ case 0x220:
+ config[n] |= GALAXY_CONFIG_SBA_220;
+ break;
+ case 0x240:
+ config[n] |= GALAXY_CONFIG_SBA_240;
+ break;
+ case 0x260:
+ config[n] |= GALAXY_CONFIG_SBA_260;
+ break;
+ case 0x280:
+ config[n] |= GALAXY_CONFIG_SBA_280;
+ break;
+ default:
+ dev_err(dev, "invalid port %#lx\n", port[n]);
+ return 0;
+ }
+
+ switch (wss_port[n]) {
+ case SNDRV_AUTO_PORT:
+ dev_err(dev, "please specify wss_port\n");
+ return 0;
+ case 0x530:
+ config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_530;
+ break;
+ case 0x604:
+ config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_604;
+ break;
+ case 0xe80:
+ config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_E80;
+ break;
+ case 0xf40:
+ config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_F40;
+ break;
+ default:
+ dev_err(dev, "invalid WSS port %#lx\n", wss_port[n]);
+ return 0;
+ }
+
+ switch (irq[n]) {
+ case SNDRV_AUTO_IRQ:
+ dev_err(dev, "please specify irq\n");
+ return 0;
+ case 7:
+ wss_config[n] |= WSS_CONFIG_IRQ_7;
+ break;
+ case 2:
+ irq[n] = 9;
+ case 9:
+ wss_config[n] |= WSS_CONFIG_IRQ_9;
+ break;
+ case 10:
+ wss_config[n] |= WSS_CONFIG_IRQ_10;
+ break;
+ case 11:
+ wss_config[n] |= WSS_CONFIG_IRQ_11;
+ break;
+ default:
+ dev_err(dev, "invalid IRQ %d\n", irq[n]);
+ return 0;
+ }
+
+ switch (dma1[n]) {
+ case SNDRV_AUTO_DMA:
+ dev_err(dev, "please specify dma1\n");
+ return 0;
+ case 0:
+ wss_config[n] |= WSS_CONFIG_DMA_0;
+ break;
+ case 1:
+ wss_config[n] |= WSS_CONFIG_DMA_1;
+ break;
+ case 3:
+ wss_config[n] |= WSS_CONFIG_DMA_3;
+ break;
+ default:
+ dev_err(dev, "invalid playback DMA %d\n", dma1[n]);
+ return 0;
+ }
+
+ if (dma2[n] == SNDRV_AUTO_DMA || dma2[n] == dma1[n]) {
+ dma2[n] = -1;
+ goto mpu;
+ }
+
+ wss_config[n] |= WSS_CONFIG_DUPLEX;
+ switch (dma2[n]) {
+ case 0:
+ break;
+ case 1:
+ if (dma1[n] == 0)
+ break;
+ default:
+ dev_err(dev, "invalid capture DMA %d\n", dma2[n]);
+ return 0;
+ }
+
+mpu:
+ switch (mpu_port[n]) {
+ case SNDRV_AUTO_PORT:
+ dev_warn(dev, "mpu_port not specified; not using MPU-401\n");
+ mpu_port[n] = -1;
+ goto fm;
+ case 0x300:
+ config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_300;
+ break;
+ case 0x330:
+ config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_330;
+ break;
+ default:
+ dev_err(dev, "invalid MPU port %#lx\n", mpu_port[n]);
+ return 0;
+ }
+
+ switch (mpu_irq[n]) {
+ case SNDRV_AUTO_IRQ:
+ dev_warn(dev, "mpu_irq not specified: using polling mode\n");
+ mpu_irq[n] = -1;
+ break;
+ case 2:
+ mpu_irq[n] = 9;
+ case 9:
+ config[n] |= GALAXY_CONFIG_MPUIRQ_2;
+ break;
+#ifdef AZT1605
+ case 3:
+ config[n] |= GALAXY_CONFIG_MPUIRQ_3;
+ break;
+#endif
+ case 5:
+ config[n] |= GALAXY_CONFIG_MPUIRQ_5;
+ break;
+ case 7:
+ config[n] |= GALAXY_CONFIG_MPUIRQ_7;
+ break;
+#ifdef AZT2316
+ case 10:
+ config[n] |= GALAXY_CONFIG_MPUIRQ_10;
+ break;
+#endif
+ default:
+ dev_err(dev, "invalid MPU IRQ %d\n", mpu_irq[n]);
+ return 0;
+ }
+
+ if (mpu_irq[n] == irq[n]) {
+ dev_err(dev, "cannot share IRQ between WSS and MPU-401\n");
+ return 0;
+ }
+
+fm:
+ switch (fm_port[n]) {
+ case SNDRV_AUTO_PORT:
+ dev_warn(dev, "fm_port not specified: not using OPL3\n");
+ fm_port[n] = -1;
+ break;
+ case 0x388:
+ break;
+ default:
+ dev_err(dev, "illegal FM port %#lx\n", fm_port[n]);
+ return 0;
+ }
+
+ config[n] |= GALAXY_CONFIG_GAME_ENABLE;
+ return 1;
+}
+
+static int __devinit galaxy_init(struct snd_galaxy *galaxy, u8 *type)
+{
+ u8 major;
+ u8 minor;
+ int err;
+
+ err = dsp_reset(galaxy->port);
+ if (err < 0)
+ return err;
+
+ err = dsp_get_version(galaxy->port, &major, &minor);
+ if (err < 0)
+ return err;
+
+ if (major != GALAXY_DSP_MAJOR || minor != GALAXY_DSP_MINOR)
+ return -ENODEV;
+
+ err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_8);
+ if (err < 0)
+ return err;
+
+ err = dsp_command(galaxy->port, GALAXY_COMMAND_GET_TYPE);
+ if (err < 0)
+ return err;
+
+ err = dsp_get_byte(galaxy->port, type);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int __devinit galaxy_set_mode(struct snd_galaxy *galaxy, u8 mode)
+{
+ int err;
+
+ err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_9);
+ if (err < 0)
+ return err;
+
+ err = dsp_command(galaxy->port, mode);
+ if (err < 0)
+ return err;
+
+#ifdef AZT1605
+ /*
+ * Needed for MPU IRQ on AZT1605, but AZT2316 loses WSS again
+ */
+ err = dsp_reset(galaxy->port);
+ if (err < 0)
+ return err;
+#endif
+
+ return 0;
+}
+
+static void galaxy_set_config(struct snd_galaxy *galaxy, u32 config)
+{
+ u8 tmp = ioread8(galaxy->config_port + CONFIG_PORT_SET);
+ int i;
+
+ iowrite8(tmp | 0x80, galaxy->config_port + CONFIG_PORT_SET);
+ for (i = 0; i < GALAXY_CONFIG_SIZE; i++) {
+ iowrite8(config, galaxy->config_port + i);
+ config >>= 8;
+ }
+ iowrite8(tmp & 0x7f, galaxy->config_port + CONFIG_PORT_SET);
+ msleep(10);
+}
+
+static void __devinit galaxy_config(struct snd_galaxy *galaxy, u32 config)
+{
+ int i;
+
+ for (i = GALAXY_CONFIG_SIZE; i; i--) {
+ u8 tmp = ioread8(galaxy->config_port + i - 1);
+ galaxy->config = (galaxy->config << 8) | tmp;
+ }
+ config |= galaxy->config & GALAXY_CONFIG_MASK;
+ galaxy_set_config(galaxy, config);
+}
+
+static int __devinit galaxy_wss_config(struct snd_galaxy *galaxy, u8 wss_config)
+{
+ int err;
+
+ err = wss_detect(galaxy->wss_port);
+ if (err < 0)
+ return err;
+
+ wss_set_config(galaxy->wss_port, wss_config);
+
+ err = galaxy_set_mode(galaxy, GALAXY_MODE_WSS);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static void snd_galaxy_free(struct snd_card *card)
+{
+ struct snd_galaxy *galaxy = card->private_data;
+
+ if (galaxy->wss_port) {
+ wss_set_config(galaxy->wss_port, 0);
+ ioport_unmap(galaxy->wss_port);
+ release_and_free_resource(galaxy->res_wss_port);
+ }
+ if (galaxy->config_port) {
+ galaxy_set_config(galaxy, galaxy->config);
+ ioport_unmap(galaxy->config_port);
+ release_and_free_resource(galaxy->res_config_port);
+ }
+ if (galaxy->port) {
+ ioport_unmap(galaxy->port);
+ release_and_free_resource(galaxy->res_port);
+ }
+}
+
+static int __devinit snd_galaxy_probe(struct device *dev, unsigned int n)
+{
+ struct snd_galaxy *galaxy;
+ struct snd_wss *chip;
+ struct snd_card *card;
+ u8 type;
+ int err;
+
+ err = snd_card_create(index[n], id[n], THIS_MODULE, sizeof *galaxy,
+ &card);
+ if (err < 0)
+ return err;
+
+ snd_card_set_dev(card, dev);
+
+ card->private_free = snd_galaxy_free;
+ galaxy = card->private_data;
+
+ galaxy->res_port = request_region(port[n], 16, DRV_NAME);
+ if (!galaxy->res_port) {
+ dev_err(dev, "could not grab ports %#lx-%#lx\n", port[n],
+ port[n] + 15);
+ err = -EBUSY;
+ goto error;
+ }
+ galaxy->port = ioport_map(port[n], 16);
+
+ err = galaxy_init(galaxy, &type);
+ if (err < 0) {
+ dev_err(dev, "did not find a Sound Galaxy at %#lx\n", port[n]);
+ goto error;
+ }
+ dev_info(dev, "Sound Galaxy (type %d) found at %#lx\n", type, port[n]);
+
+ galaxy->res_config_port = request_region(port[n] + GALAXY_PORT_CONFIG,
+ 16, DRV_NAME);
+ if (!galaxy->res_config_port) {
+ dev_err(dev, "could not grab ports %#lx-%#lx\n",
+ port[n] + GALAXY_PORT_CONFIG,
+ port[n] + GALAXY_PORT_CONFIG + 15);
+ err = -EBUSY;
+ goto error;
+ }
+ galaxy->config_port = ioport_map(port[n] + GALAXY_PORT_CONFIG, 16);
+
+ galaxy_config(galaxy, config[n]);
+
+ galaxy->res_wss_port = request_region(wss_port[n], 4, DRV_NAME);
+ if (!galaxy->res_wss_port) {
+ dev_err(dev, "could not grab ports %#lx-%#lx\n", wss_port[n],
+ wss_port[n] + 3);
+ err = -EBUSY;
+ goto error;
+ }
+ galaxy->wss_port = ioport_map(wss_port[n], 4);
+
+ err = galaxy_wss_config(galaxy, wss_config[n]);
+ if (err < 0) {
+ dev_err(dev, "could not configure WSS\n");
+ goto error;
+ }
+
+ strcpy(card->driver, DRV_NAME);
+ strcpy(card->shortname, DRV_NAME);
+ sprintf(card->longname, "%s at %#lx/%#lx, irq %d, dma %d/%d",
+ card->shortname, port[n], wss_port[n], irq[n], dma1[n],
+ dma2[n]);
+
+ err = snd_wss_create(card, wss_port[n] + 4, -1, irq[n], dma1[n],
+ dma2[n], WSS_HW_DETECT, 0, &chip);
+ if (err < 0)
+ goto error;
+
+ err = snd_wss_pcm(chip, 0, NULL);
+ if (err < 0)
+ goto error;
+
+ err = snd_wss_mixer(chip);
+ if (err < 0)
+ goto error;
+
+ err = snd_wss_timer(chip, 0, NULL);
+ if (err < 0)
+ goto error;
+
+ if (mpu_port[n] >= 0) {
+ err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
+ mpu_port[n], 0, mpu_irq[n],
+ IRQF_DISABLED, NULL);
+ if (err < 0)
+ goto error;
+ }
+
+ if (fm_port[n] >= 0) {
+ struct snd_opl3 *opl3;
+
+ err = snd_opl3_create(card, fm_port[n], fm_port[n] + 2,
+ OPL3_HW_AUTO, 0, &opl3);
+ if (err < 0) {
+ dev_err(dev, "no OPL device at %#lx\n", fm_port[n]);
+ goto error;
+ }
+ err = snd_opl3_timer_new(opl3, 1, 2);
+ if (err < 0)
+ goto error;
+
+ err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+ if (err < 0)
+ goto error;
+ }
+
+ err = snd_card_register(card);
+ if (err < 0)
+ goto error;
+
+ dev_set_drvdata(dev, card);
+ return 0;
+
+error:
+ snd_card_free(card);
+ return err;
+}
+
+static int __devexit snd_galaxy_remove(struct device *dev, unsigned int n)
+{
+ snd_card_free(dev_get_drvdata(dev));
+ dev_set_drvdata(dev, NULL);
+ return 0;
+}
+
+static struct isa_driver snd_galaxy_driver = {
+ .match = snd_galaxy_match,
+ .probe = snd_galaxy_probe,
+ .remove = __devexit_p(snd_galaxy_remove),
+
+ .driver = {
+ .name = DEV_NAME
+ }
+};
+
+static int __init alsa_card_galaxy_init(void)
+{
+ return isa_register_driver(&snd_galaxy_driver, SNDRV_CARDS);
+}
+
+static void __exit alsa_card_galaxy_exit(void)
+{
+ isa_unregister_driver(&snd_galaxy_driver);
+}
+
+module_init(alsa_card_galaxy_init);
+module_exit(alsa_card_galaxy_exit);
diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c
index f26eac8..3e4a58b 100644
--- a/sound/isa/gus/gusmax.c
+++ b/sound/isa/gus/gusmax.c
@@ -191,7 +191,7 @@
static void snd_gusmax_free(struct snd_card *card)
{
- struct snd_gusmax *maxcard = (struct snd_gusmax *)card->private_data;
+ struct snd_gusmax *maxcard = card->private_data;
if (maxcard == NULL)
return;
@@ -219,7 +219,7 @@
if (err < 0)
return err;
card->private_free = snd_gusmax_free;
- maxcard = (struct snd_gusmax *)card->private_data;
+ maxcard = card->private_data;
maxcard->card = card;
maxcard->irq = -1;
diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c
index 81284a8..2259e3f 100644
--- a/sound/isa/sb/sb8.c
+++ b/sound/isa/sb/sb8.c
@@ -72,7 +72,7 @@
static void snd_sb8_free(struct snd_card *card)
{
- struct snd_sb8 *acard = (struct snd_sb8 *)card->private_data;
+ struct snd_sb8 *acard = card->private_data;
if (acard == NULL)
return;
diff --git a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c
deleted file mode 100644
index 6fe27b9..0000000
--- a/sound/isa/sgalaxy.c
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * Driver for Aztech Sound Galaxy cards
- * Copyright (c) by Christopher Butler <chrisb@sandy.force9.co.uk.
- *
- * I don't have documentation for this card, I based this driver on the
- * driver for OSS/Free included in the kernel source (drivers/sound/sgalaxy.c)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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/init.h>
-#include <linux/err.h>
-#include <linux/isa.h>
-#include <linux/delay.h>
-#include <linux/time.h>
-#include <linux/interrupt.h>
-#include <linux/moduleparam.h>
-#include <asm/dma.h>
-#include <sound/core.h>
-#include <sound/sb.h>
-#include <sound/wss.h>
-#include <sound/control.h>
-#define SNDRV_LEGACY_FIND_FREE_IRQ
-#define SNDRV_LEGACY_FIND_FREE_DMA
-#include <sound/initval.h>
-
-MODULE_AUTHOR("Christopher Butler <chrisb@sandy.force9.co.uk>");
-MODULE_DESCRIPTION("Aztech Sound Galaxy");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Aztech Systems,Sound Galaxy}}");
-
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
-static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
-static long sbport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240 */
-static long wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x530,0xe80,0xf40,0x604 */
-static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 7,9,10,11 */
-static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3 */
-
-module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for Sound Galaxy soundcard.");
-module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string for Sound Galaxy soundcard.");
-module_param_array(sbport, long, NULL, 0444);
-MODULE_PARM_DESC(sbport, "Port # for Sound Galaxy SB driver.");
-module_param_array(wssport, long, NULL, 0444);
-MODULE_PARM_DESC(wssport, "Port # for Sound Galaxy WSS driver.");
-module_param_array(irq, int, NULL, 0444);
-MODULE_PARM_DESC(irq, "IRQ # for Sound Galaxy driver.");
-module_param_array(dma1, int, NULL, 0444);
-MODULE_PARM_DESC(dma1, "DMA1 # for Sound Galaxy driver.");
-
-#define SGALAXY_AUXC_LEFT 18
-#define SGALAXY_AUXC_RIGHT 19
-
-#define PFX "sgalaxy: "
-
-/*
-
- */
-
-#define AD1848P1( port, x ) ( port + c_d_c_AD1848##x )
-
-/* from lowlevel/sb/sb.c - to avoid having to allocate a struct snd_sb for the */
-/* short time we actually need it.. */
-
-static int snd_sgalaxy_sbdsp_reset(unsigned long port)
-{
- int i;
-
- outb(1, SBP1(port, RESET));
- udelay(10);
- outb(0, SBP1(port, RESET));
- udelay(30);
- for (i = 0; i < 1000 && !(inb(SBP1(port, DATA_AVAIL)) & 0x80); i++);
- if (inb(SBP1(port, READ)) != 0xaa) {
- snd_printd("sb_reset: failed at 0x%lx!!!\n", port);
- return -ENODEV;
- }
- return 0;
-}
-
-static int __devinit snd_sgalaxy_sbdsp_command(unsigned long port,
- unsigned char val)
-{
- int i;
-
- for (i = 10000; i; i--)
- if ((inb(SBP1(port, STATUS)) & 0x80) == 0) {
- outb(val, SBP1(port, COMMAND));
- return 1;
- }
-
- return 0;
-}
-
-static irqreturn_t snd_sgalaxy_dummy_interrupt(int irq, void *dev_id)
-{
- return IRQ_NONE;
-}
-
-static int __devinit snd_sgalaxy_setup_wss(unsigned long port, int irq, int dma)
-{
- static int interrupt_bits[] = {-1, -1, -1, -1, -1, -1, -1, 0x08, -1,
- 0x10, 0x18, 0x20, -1, -1, -1, -1};
- static int dma_bits[] = {1, 2, 0, 3};
- int tmp, tmp1;
-
- if ((tmp = inb(port + 3)) == 0xff)
- {
- snd_printdd("I/O address dead (0x%lx)\n", port);
- return 0;
- }
-#if 0
- snd_printdd("WSS signature = 0x%x\n", tmp);
-#endif
-
- if ((tmp & 0x3f) != 0x04 &&
- (tmp & 0x3f) != 0x0f &&
- (tmp & 0x3f) != 0x00) {
- snd_printdd("No WSS signature detected on port 0x%lx\n",
- port + 3);
- return 0;
- }
-
-#if 0
- snd_printdd(PFX "setting up IRQ/DMA for WSS\n");
-#endif
-
- /* initialize IRQ for WSS codec */
- tmp = interrupt_bits[irq % 16];
- if (tmp < 0)
- return -EINVAL;
-
- if (request_irq(irq, snd_sgalaxy_dummy_interrupt, IRQF_DISABLED, "sgalaxy", NULL)) {
- snd_printk(KERN_ERR "sgalaxy: can't grab irq %d\n", irq);
- return -EIO;
- }
-
- outb(tmp | 0x40, port);
- tmp1 = dma_bits[dma % 4];
- outb(tmp | tmp1, port);
-
- free_irq(irq, NULL);
-
- return 0;
-}
-
-static int __devinit snd_sgalaxy_detect(int dev, int irq, int dma)
-{
-#if 0
- snd_printdd(PFX "switching to WSS mode\n");
-#endif
-
- /* switch to WSS mode */
- snd_sgalaxy_sbdsp_reset(sbport[dev]);
-
- snd_sgalaxy_sbdsp_command(sbport[dev], 9);
- snd_sgalaxy_sbdsp_command(sbport[dev], 0);
-
- udelay(400);
- return snd_sgalaxy_setup_wss(wssport[dev], irq, dma);
-}
-
-static struct snd_kcontrol_new snd_sgalaxy_controls[] = {
-WSS_DOUBLE("Aux Playback Switch", 0,
- SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 7, 7, 1, 1),
-WSS_DOUBLE("Aux Playback Volume", 0,
- SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 0, 0, 31, 0)
-};
-
-static int __devinit snd_sgalaxy_mixer(struct snd_wss *chip)
-{
- struct snd_card *card = chip->card;
- struct snd_ctl_elem_id id1, id2;
- unsigned int idx;
- int err;
-
- memset(&id1, 0, sizeof(id1));
- memset(&id2, 0, sizeof(id2));
- id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- /* reassign AUX0 to LINE */
- strcpy(id1.name, "Aux Playback Switch");
- strcpy(id2.name, "Line Playback Switch");
- if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
- return err;
- strcpy(id1.name, "Aux Playback Volume");
- strcpy(id2.name, "Line Playback Volume");
- if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
- return err;
- /* reassign AUX1 to FM */
- strcpy(id1.name, "Aux Playback Switch"); id1.index = 1;
- strcpy(id2.name, "FM Playback Switch");
- if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
- return err;
- strcpy(id1.name, "Aux Playback Volume");
- strcpy(id2.name, "FM Playback Volume");
- if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
- return err;
- /* build AUX2 input */
- for (idx = 0; idx < ARRAY_SIZE(snd_sgalaxy_controls); idx++) {
- err = snd_ctl_add(card,
- snd_ctl_new1(&snd_sgalaxy_controls[idx], chip));
- if (err < 0)
- return err;
- }
- return 0;
-}
-
-static int __devinit snd_sgalaxy_match(struct device *devptr, unsigned int dev)
-{
- if (!enable[dev])
- return 0;
- if (sbport[dev] == SNDRV_AUTO_PORT) {
- snd_printk(KERN_ERR PFX "specify SB port\n");
- return 0;
- }
- if (wssport[dev] == SNDRV_AUTO_PORT) {
- snd_printk(KERN_ERR PFX "specify WSS port\n");
- return 0;
- }
- return 1;
-}
-
-static int __devinit snd_sgalaxy_probe(struct device *devptr, unsigned int dev)
-{
- static int possible_irqs[] = {7, 9, 10, 11, -1};
- static int possible_dmas[] = {1, 3, 0, -1};
- int err, xirq, xdma1;
- struct snd_card *card;
- struct snd_wss *chip;
-
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
- if (err < 0)
- return err;
-
- xirq = irq[dev];
- if (xirq == SNDRV_AUTO_IRQ) {
- if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free IRQ\n");
- err = -EBUSY;
- goto _err;
- }
- }
- xdma1 = dma1[dev];
- if (xdma1 == SNDRV_AUTO_DMA) {
- if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free DMA\n");
- err = -EBUSY;
- goto _err;
- }
- }
-
- if ((err = snd_sgalaxy_detect(dev, xirq, xdma1)) < 0)
- goto _err;
-
- err = snd_wss_create(card, wssport[dev] + 4, -1,
- xirq, xdma1, -1,
- WSS_HW_DETECT, 0, &chip);
- if (err < 0)
- goto _err;
- card->private_data = chip;
-
- err = snd_wss_pcm(chip, 0, NULL);
- if (err < 0) {
- snd_printdd(PFX "error creating new WSS PCM device\n");
- goto _err;
- }
- err = snd_wss_mixer(chip);
- if (err < 0) {
- snd_printdd(PFX "error creating new WSS mixer\n");
- goto _err;
- }
- if ((err = snd_sgalaxy_mixer(chip)) < 0) {
- snd_printdd(PFX "the mixer rewrite failed\n");
- goto _err;
- }
-
- strcpy(card->driver, "Sound Galaxy");
- strcpy(card->shortname, "Sound Galaxy");
- sprintf(card->longname, "Sound Galaxy at 0x%lx, irq %d, dma %d",
- wssport[dev], xirq, xdma1);
-
- snd_card_set_dev(card, devptr);
-
- if ((err = snd_card_register(card)) < 0)
- goto _err;
-
- dev_set_drvdata(devptr, card);
- return 0;
-
- _err:
- snd_card_free(card);
- return err;
-}
-
-static int __devexit snd_sgalaxy_remove(struct device *devptr, unsigned int dev)
-{
- snd_card_free(dev_get_drvdata(devptr));
- dev_set_drvdata(devptr, NULL);
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int snd_sgalaxy_suspend(struct device *pdev, unsigned int n,
- pm_message_t state)
-{
- struct snd_card *card = dev_get_drvdata(pdev);
- struct snd_wss *chip = card->private_data;
-
- snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
- chip->suspend(chip);
- return 0;
-}
-
-static int snd_sgalaxy_resume(struct device *pdev, unsigned int n)
-{
- struct snd_card *card = dev_get_drvdata(pdev);
- struct snd_wss *chip = card->private_data;
-
- chip->resume(chip);
- snd_wss_out(chip, SGALAXY_AUXC_LEFT, chip->image[SGALAXY_AUXC_LEFT]);
- snd_wss_out(chip, SGALAXY_AUXC_RIGHT, chip->image[SGALAXY_AUXC_RIGHT]);
-
- snd_power_change_state(card, SNDRV_CTL_POWER_D0);
- return 0;
-}
-#endif
-
-#define DEV_NAME "sgalaxy"
-
-static struct isa_driver snd_sgalaxy_driver = {
- .match = snd_sgalaxy_match,
- .probe = snd_sgalaxy_probe,
- .remove = __devexit_p(snd_sgalaxy_remove),
-#ifdef CONFIG_PM
- .suspend = snd_sgalaxy_suspend,
- .resume = snd_sgalaxy_resume,
-#endif
- .driver = {
- .name = DEV_NAME
- },
-};
-
-static int __init alsa_card_sgalaxy_init(void)
-{
- return isa_register_driver(&snd_sgalaxy_driver, SNDRV_CARDS);
-}
-
-static void __exit alsa_card_sgalaxy_exit(void)
-{
- isa_unregister_driver(&snd_sgalaxy_driver);
-}
-
-module_init(alsa_card_sgalaxy_init)
-module_exit(alsa_card_sgalaxy_exit)
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index a513651..76c0902 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -545,11 +545,3 @@
endif # SOUND_OSS
-config SOUND_SH_DAC_AUDIO
- tristate "SuperH DAC audio support"
- depends on CPU_SH3 && HIGH_RES_TIMERS
-
-config SOUND_SH_DAC_AUDIO_CHANNEL
- int "DAC channel"
- default "1"
- depends on SOUND_SH_DAC_AUDIO
diff --git a/sound/oss/Makefile b/sound/oss/Makefile
index 567b8a7..96f14dc 100644
--- a/sound/oss/Makefile
+++ b/sound/oss/Makefile
@@ -9,7 +9,6 @@
# Please leave it as is, cause the link order is significant !
-obj-$(CONFIG_SOUND_SH_DAC_AUDIO) += sh_dac_audio.o
obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o
obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o
obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o
diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c
index c6f2621..a8f626d 100644
--- a/sound/oss/au1550_ac97.c
+++ b/sound/oss/au1550_ac97.c
@@ -43,7 +43,6 @@
#include <linux/sound.h>
#include <linux/slab.h>
#include <linux/soundcard.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
@@ -77,6 +76,7 @@
/* Boot options
* 0 = no VRA, 1 = use VRA if codec supports it
*/
+static DEFINE_MUTEX(au1550_ac97_mutex);
static int vra = 1;
module_param(vra, bool, 0);
MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it");
@@ -171,7 +171,7 @@
static u16
rdcodec(struct ac97_codec *codec, u8 addr)
{
- struct au1550_state *s = (struct au1550_state *)codec->private_data;
+ struct au1550_state *s = codec->private_data;
unsigned long flags;
u32 cmd, val;
u16 data;
@@ -239,7 +239,7 @@
static void
wrcodec(struct ac97_codec *codec, u8 addr, u16 data)
{
- struct au1550_state *s = (struct au1550_state *)codec->private_data;
+ struct au1550_state *s = codec->private_data;
unsigned long flags;
u32 cmd, val;
int i;
@@ -798,9 +798,9 @@
static int
au1550_open_mixdev(struct inode *inode, struct file *file)
{
- lock_kernel();
+ mutex_lock(&au1550_ac97_mutex);
file->private_data = &au1550_state;
- unlock_kernel();
+ mutex_unlock(&au1550_ac97_mutex);
return 0;
}
@@ -820,13 +820,13 @@
static long
au1550_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct au1550_state *s = (struct au1550_state *)file->private_data;
+ struct au1550_state *s = file->private_data;
struct ac97_codec *codec = s->codec;
int ret;
- lock_kernel();
+ mutex_lock(&au1550_ac97_mutex);
ret = mixdev_ioctl(codec, cmd, arg);
- unlock_kernel();
+ mutex_unlock(&au1550_ac97_mutex);
return ret;
}
@@ -1031,7 +1031,7 @@
static ssize_t
au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
{
- struct au1550_state *s = (struct au1550_state *)file->private_data;
+ struct au1550_state *s = file->private_data;
struct dmabuf *db = &s->dma_adc;
DECLARE_WAITQUEUE(wait, current);
ssize_t ret;
@@ -1111,7 +1111,7 @@
static ssize_t
au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
{
- struct au1550_state *s = (struct au1550_state *)file->private_data;
+ struct au1550_state *s = file->private_data;
struct dmabuf *db = &s->dma_dac;
DECLARE_WAITQUEUE(wait, current);
ssize_t ret = 0;
@@ -1211,7 +1211,7 @@
static unsigned int
au1550_poll(struct file *file, struct poll_table_struct *wait)
{
- struct au1550_state *s = (struct au1550_state *)file->private_data;
+ struct au1550_state *s = file->private_data;
unsigned long flags;
unsigned int mask = 0;
@@ -1250,12 +1250,12 @@
static int
au1550_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct au1550_state *s = (struct au1550_state *)file->private_data;
+ struct au1550_state *s = file->private_data;
struct dmabuf *db;
unsigned long size;
int ret = 0;
- lock_kernel();
+ mutex_lock(&au1550_ac97_mutex);
mutex_lock(&s->sem);
if (vma->vm_flags & VM_WRITE)
db = &s->dma_dac;
@@ -1283,7 +1283,7 @@
db->mapped = 1;
out:
mutex_unlock(&s->sem);
- unlock_kernel();
+ mutex_unlock(&au1550_ac97_mutex);
return ret;
}
@@ -1342,7 +1342,7 @@
static int
au1550_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct au1550_state *s = (struct au1550_state *)file->private_data;
+ struct au1550_state *s = file->private_data;
unsigned long flags;
audio_buf_info abinfo;
count_info cinfo;
@@ -1781,9 +1781,9 @@
{
int ret;
- lock_kernel();
+ mutex_lock(&au1550_ac97_mutex);
ret = au1550_ioctl(file, cmd, arg);
- unlock_kernel();
+ mutex_unlock(&au1550_ac97_mutex);
return ret;
}
@@ -1804,7 +1804,7 @@
#endif
file->private_data = s;
- lock_kernel();
+ mutex_lock(&au1550_ac97_mutex);
/* wait for device to become free */
mutex_lock(&s->open_mutex);
while (s->open_mode & file->f_mode) {
@@ -1861,21 +1861,21 @@
out:
mutex_unlock(&s->open_mutex);
out2:
- unlock_kernel();
+ mutex_unlock(&au1550_ac97_mutex);
return ret;
}
static int
au1550_release(struct inode *inode, struct file *file)
{
- struct au1550_state *s = (struct au1550_state *)file->private_data;
+ struct au1550_state *s = file->private_data;
- lock_kernel();
+ mutex_lock(&au1550_ac97_mutex);
if (file->f_mode & FMODE_WRITE) {
- unlock_kernel();
+ mutex_unlock(&au1550_ac97_mutex);
drain_dac(s, file->f_flags & O_NONBLOCK);
- lock_kernel();
+ mutex_lock(&au1550_ac97_mutex);
}
mutex_lock(&s->open_mutex);
@@ -1892,7 +1892,7 @@
s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE));
mutex_unlock(&s->open_mutex);
wake_up(&s->open_wait);
- unlock_kernel();
+ mutex_unlock(&au1550_ac97_mutex);
return 0;
}
diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c
index 6ecd41a..87e2c72 100644
--- a/sound/oss/dmasound/dmasound_core.c
+++ b/sound/oss/dmasound/dmasound_core.c
@@ -181,7 +181,7 @@
#include <linux/init.h>
#include <linux/soundcard.h>
#include <linux/poll.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
@@ -194,6 +194,7 @@
* Declarations
*/
+static DEFINE_MUTEX(dmasound_core_mutex);
int dmasound_catchRadius = 0;
module_param(dmasound_catchRadius, int, 0);
@@ -323,22 +324,22 @@
static int mixer_open(struct inode *inode, struct file *file)
{
- lock_kernel();
+ mutex_lock(&dmasound_core_mutex);
if (!try_module_get(dmasound.mach.owner)) {
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return -ENODEV;
}
mixer.busy = 1;
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return 0;
}
static int mixer_release(struct inode *inode, struct file *file)
{
- lock_kernel();
+ mutex_lock(&dmasound_core_mutex);
mixer.busy = 0;
module_put(dmasound.mach.owner);
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return 0;
}
@@ -370,9 +371,9 @@
{
int ret;
- lock_kernel();
+ mutex_lock(&dmasound_core_mutex);
ret = mixer_ioctl(file, cmd, arg);
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return ret;
}
@@ -752,9 +753,9 @@
{
int rc;
- lock_kernel();
+ mutex_lock(&dmasound_core_mutex);
if (!try_module_get(dmasound.mach.owner)) {
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return -ENODEV;
}
@@ -799,11 +800,11 @@
sound_set_format(AFMT_MU_LAW);
}
#endif
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return 0;
out:
module_put(dmasound.mach.owner);
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return rc;
}
@@ -869,7 +870,7 @@
{
int rc = 0;
- lock_kernel();
+ mutex_lock(&dmasound_core_mutex);
if (file->f_mode & FMODE_WRITE) {
if (write_sq.busy)
@@ -900,7 +901,7 @@
write_sq_wake_up(file); /* checks f_mode */
#endif /* blocking open() */
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return rc;
}
@@ -1141,9 +1142,9 @@
{
int ret;
- lock_kernel();
+ mutex_lock(&dmasound_core_mutex);
ret = sq_ioctl(file, cmd, arg);
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return ret;
}
@@ -1257,7 +1258,7 @@
int len = 0;
int ret;
- lock_kernel();
+ mutex_lock(&dmasound_core_mutex);
ret = -EBUSY;
if (state.busy)
goto out;
@@ -1329,16 +1330,16 @@
state.len = len;
ret = 0;
out:
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return ret;
}
static int state_release(struct inode *inode, struct file *file)
{
- lock_kernel();
+ mutex_lock(&dmasound_core_mutex);
state.busy = 0;
module_put(dmasound.mach.owner);
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return 0;
}
diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c
index 2e48b17..b4c1eb5 100644
--- a/sound/oss/msnd_pinnacle.c
+++ b/sound/oss/msnd_pinnacle.c
@@ -39,7 +39,7 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/interrupt.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <linux/gfp.h>
#include <asm/irq.h>
#include <asm/io.h>
@@ -79,6 +79,7 @@
dev.rec_sample_rate / \
dev.rec_channels)
+static DEFINE_MUTEX(msnd_pinnacle_mutex);
static multisound_dev_t dev;
#ifndef HAVE_DSPCODEH
@@ -651,12 +652,12 @@
ret = -EINVAL;
- lock_kernel();
+ mutex_lock(&msnd_pinnacle_mutex);
if (minor == dev.dsp_minor)
ret = dsp_ioctl(file, cmd, arg);
else if (minor == dev.mixer_minor)
ret = mixer_ioctl(cmd, arg);
- unlock_kernel();
+ mutex_unlock(&msnd_pinnacle_mutex);
return ret;
}
@@ -761,7 +762,7 @@
int minor = iminor(inode);
int err = 0;
- lock_kernel();
+ mutex_lock(&msnd_pinnacle_mutex);
if (minor == dev.dsp_minor) {
if ((file->f_mode & FMODE_WRITE &&
test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) ||
@@ -791,7 +792,7 @@
} else
err = -EINVAL;
out:
- unlock_kernel();
+ mutex_unlock(&msnd_pinnacle_mutex);
return err;
}
@@ -800,14 +801,14 @@
int minor = iminor(inode);
int err = 0;
- lock_kernel();
+ mutex_lock(&msnd_pinnacle_mutex);
if (minor == dev.dsp_minor)
err = dsp_release(file);
else if (minor == dev.mixer_minor) {
/* nothing */
} else
err = -EINVAL;
- unlock_kernel();
+ mutex_unlock(&msnd_pinnacle_mutex);
return err;
}
diff --git a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c
deleted file mode 100644
index 479e302..0000000
--- a/sound/oss/sh_dac_audio.c
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * sound/oss/sh_dac_audio.c
- *
- * SH DAC based sound :(
- *
- * Copyright (C) 2004,2005 Andriy Skulysh
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/linkage.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/sound.h>
-#include <linux/smp_lock.h>
-#include <linux/soundcard.h>
-#include <linux/interrupt.h>
-#include <linux/hrtimer.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/irq.h>
-#include <asm/delay.h>
-#include <asm/clock.h>
-#include <cpu/dac.h>
-#include <asm/machvec.h>
-#include <mach/hp6xx.h>
-#include <asm/hd64461.h>
-
-#define MODNAME "sh_dac_audio"
-
-#define BUFFER_SIZE 48000
-
-static int rate;
-static int empty;
-static char *data_buffer, *buffer_begin, *buffer_end;
-static int in_use, device_major;
-static struct hrtimer hrtimer;
-static ktime_t wakeups_per_second;
-
-static void dac_audio_start_timer(void)
-{
- hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL);
-}
-
-static void dac_audio_stop_timer(void)
-{
- hrtimer_cancel(&hrtimer);
-}
-
-static void dac_audio_reset(void)
-{
- dac_audio_stop_timer();
- buffer_begin = buffer_end = data_buffer;
- empty = 1;
-}
-
-static void dac_audio_sync(void)
-{
- while (!empty)
- schedule();
-}
-
-static void dac_audio_start(void)
-{
- if (mach_is_hp6xx()) {
- u16 v = __raw_readw(HD64461_GPADR);
- v &= ~HD64461_GPADR_SPEAKER;
- __raw_writew(v, HD64461_GPADR);
- }
-
- sh_dac_enable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
-}
-static void dac_audio_stop(void)
-{
- dac_audio_stop_timer();
-
- if (mach_is_hp6xx()) {
- u16 v = __raw_readw(HD64461_GPADR);
- v |= HD64461_GPADR_SPEAKER;
- __raw_writew(v, HD64461_GPADR);
- }
-
- sh_dac_output(0, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
- sh_dac_disable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
-}
-
-static void dac_audio_set_rate(void)
-{
- wakeups_per_second = ktime_set(0, 1000000000 / rate);
-}
-
-static int dac_audio_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int val;
-
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, (int *)arg);
-
- case SNDCTL_DSP_SYNC:
- dac_audio_sync();
- return 0;
-
- case SNDCTL_DSP_RESET:
- dac_audio_reset();
- return 0;
-
- case SNDCTL_DSP_GETFMTS:
- return put_user(AFMT_U8, (int *)arg);
-
- case SNDCTL_DSP_SETFMT:
- return put_user(AFMT_U8, (int *)arg);
-
- case SNDCTL_DSP_NONBLOCK:
- spin_lock(&file->f_lock);
- file->f_flags |= O_NONBLOCK;
- spin_unlock(&file->f_lock);
- return 0;
-
- case SNDCTL_DSP_GETCAPS:
- return 0;
-
- case SOUND_PCM_WRITE_RATE:
- val = *(int *)arg;
- if (val > 0) {
- rate = val;
- dac_audio_set_rate();
- }
- return put_user(rate, (int *)arg);
-
- case SNDCTL_DSP_STEREO:
- return put_user(0, (int *)arg);
-
- case SOUND_PCM_WRITE_CHANNELS:
- return put_user(1, (int *)arg);
-
- case SNDCTL_DSP_SETDUPLEX:
- return -EINVAL;
-
- case SNDCTL_DSP_PROFILE:
- return -EINVAL;
-
- case SNDCTL_DSP_GETBLKSIZE:
- return put_user(BUFFER_SIZE, (int *)arg);
-
- case SNDCTL_DSP_SETFRAGMENT:
- return 0;
-
- default:
- printk(KERN_ERR "sh_dac_audio: unimplemented ioctl=0x%x\n",
- cmd);
- return -EINVAL;
- }
- return -EINVAL;
-}
-
-static long dac_audio_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
-{
- int ret;
-
- lock_kernel();
- ret = dac_audio_ioctl(file, cmd, arg);
- unlock_kernel();
-
- return ret;
-}
-
-static ssize_t dac_audio_write(struct file *file, const char *buf, size_t count,
- loff_t * ppos)
-{
- int free;
- int nbytes;
-
- if (!count) {
- dac_audio_sync();
- return 0;
- }
-
- free = buffer_begin - buffer_end;
-
- if (free < 0)
- free += BUFFER_SIZE;
- if ((free == 0) && (empty))
- free = BUFFER_SIZE;
- if (count > free)
- count = free;
- if (buffer_begin > buffer_end) {
- if (copy_from_user((void *)buffer_end, buf, count))
- return -EFAULT;
-
- buffer_end += count;
- } else {
- nbytes = data_buffer + BUFFER_SIZE - buffer_end;
- if (nbytes > count) {
- if (copy_from_user((void *)buffer_end, buf, count))
- return -EFAULT;
- buffer_end += count;
- } else {
- if (copy_from_user((void *)buffer_end, buf, nbytes))
- return -EFAULT;
- if (copy_from_user
- ((void *)data_buffer, buf + nbytes, count - nbytes))
- return -EFAULT;
- buffer_end = data_buffer + count - nbytes;
- }
- }
-
- if (empty) {
- empty = 0;
- dac_audio_start_timer();
- }
-
- return count;
-}
-
-static ssize_t dac_audio_read(struct file *file, char *buf, size_t count,
- loff_t * ppos)
-{
- return -EINVAL;
-}
-
-static int dac_audio_open(struct inode *inode, struct file *file)
-{
- if (file->f_mode & FMODE_READ)
- return -ENODEV;
-
- lock_kernel();
- if (in_use) {
- unlock_kernel();
- return -EBUSY;
- }
-
- in_use = 1;
-
- dac_audio_start();
- unlock_kernel();
- return 0;
-}
-
-static int dac_audio_release(struct inode *inode, struct file *file)
-{
- dac_audio_sync();
- dac_audio_stop();
- in_use = 0;
-
- return 0;
-}
-
-const struct file_operations dac_audio_fops = {
- .read = dac_audio_read,
- .write = dac_audio_write,
- .unlocked_ioctl = dac_audio_unlocked_ioctl,
- .open = dac_audio_open,
- .release = dac_audio_release,
-};
-
-static enum hrtimer_restart sh_dac_audio_timer(struct hrtimer *handle)
-{
- if (!empty) {
- sh_dac_output(*buffer_begin, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
- buffer_begin++;
-
- if (buffer_begin == data_buffer + BUFFER_SIZE)
- buffer_begin = data_buffer;
- if (buffer_begin == buffer_end)
- empty = 1;
- }
-
- if (!empty)
- hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL);
-
- return HRTIMER_NORESTART;
-}
-
-static int __init dac_audio_init(void)
-{
- if ((device_major = register_sound_dsp(&dac_audio_fops, -1)) < 0) {
- printk(KERN_ERR "Cannot register dsp device");
- return device_major;
- }
-
- in_use = 0;
-
- data_buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
- if (data_buffer == NULL)
- return -ENOMEM;
-
- dac_audio_reset();
- rate = 8000;
- dac_audio_set_rate();
-
- /* Today: High Resolution Timer driven DAC playback.
- * The timer callback gets called once per sample. Ouch.
- *
- * Future: A much better approach would be to use the
- * SH7720 CMT+DMAC+DAC hardware combination like this:
- * - Program sample rate using CMT0 or CMT1
- * - Program DMAC to use CMT for timing and output to DAC
- * - Play sound using DMAC, let CPU sleep.
- * - While at it, rewrite this driver to use ALSA.
- */
-
- hrtimer_init(&hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- hrtimer.function = sh_dac_audio_timer;
-
- return 0;
-}
-
-static void __exit dac_audio_exit(void)
-{
- unregister_sound_dsp(device_major);
- kfree((void *)data_buffer);
-}
-
-module_init(dac_audio_init);
-module_exit(dac_audio_exit);
-
-MODULE_AUTHOR("Andriy Skulysh, askulysh@image.kiev.ua");
-MODULE_DESCRIPTION("SH DAC sound driver");
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c
index 92aa762..46c0d03 100644
--- a/sound/oss/soundcard.c
+++ b/sound/oss/soundcard.c
@@ -40,7 +40,7 @@
#include <linux/major.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/device.h>
@@ -56,6 +56,7 @@
* Table for permanently allocated memory (used when unloading the module)
*/
void * sound_mem_blocks[MAX_MEM_BLOCKS];
+static DEFINE_MUTEX(soundcard_mutex);
int sound_nblocks = 0;
/* Persistent DMA buffers */
@@ -151,7 +152,7 @@
* big one anyway, we might as well bandage here..
*/
- lock_kernel();
+ mutex_lock(&soundcard_mutex);
DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count));
switch (dev & 0x0f) {
@@ -169,7 +170,7 @@
case SND_DEV_MIDIN:
ret = MIDIbuf_read(dev, file, buf, count);
}
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return ret;
}
@@ -178,7 +179,7 @@
int dev = iminor(file->f_path.dentry->d_inode);
int ret = -EINVAL;
- lock_kernel();
+ mutex_lock(&soundcard_mutex);
DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count));
switch (dev & 0x0f) {
case SND_DEV_SEQ:
@@ -196,7 +197,7 @@
ret = MIDIbuf_write(dev, file, buf, count);
break;
}
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return ret;
}
@@ -210,7 +211,7 @@
printk(KERN_ERR "Invalid minor device %d\n", dev);
return -ENXIO;
}
- lock_kernel();
+ mutex_lock(&soundcard_mutex);
switch (dev & 0x0f) {
case SND_DEV_CTL:
dev >>= 4;
@@ -247,15 +248,15 @@
retval = -ENXIO;
}
- unlock_kernel();
- return 0;
+ mutex_unlock(&soundcard_mutex);
+ return retval;
}
static int sound_release(struct inode *inode, struct file *file)
{
int dev = iminor(inode);
- lock_kernel();
+ mutex_lock(&soundcard_mutex);
DEB(printk("sound_release(dev=%d)\n", dev));
switch (dev & 0x0f) {
case SND_DEV_CTL:
@@ -280,7 +281,7 @@
default:
printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev);
}
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return 0;
}
@@ -354,7 +355,7 @@
if (cmd == OSS_GETVERSION)
return __put_user(SOUND_VERSION, (int __user *)p);
- lock_kernel();
+ mutex_lock(&soundcard_mutex);
if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */
(dev & 0x0f) != SND_DEV_CTL) {
dtype = dev & 0x0f;
@@ -369,7 +370,7 @@
ret = sound_mixer_ioctl(dev >> 4, cmd, p);
break;
}
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return ret;
}
@@ -391,15 +392,15 @@
case SND_DEV_DSP:
case SND_DEV_DSP16:
case SND_DEV_AUDIO:
- return audio_ioctl(dev, file, cmd, p);
+ ret = audio_ioctl(dev, file, cmd, p);
break;
case SND_DEV_MIDIN:
- return MIDIbuf_ioctl(dev, file, cmd, p);
+ ret = MIDIbuf_ioctl(dev, file, cmd, p);
break;
}
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return ret;
}
@@ -439,35 +440,35 @@
printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n");
return -EINVAL;
}
- lock_kernel();
+ mutex_lock(&soundcard_mutex);
if (vma->vm_flags & VM_WRITE) /* Map write and read/write to the output buf */
dmap = audio_devs[dev]->dmap_out;
else if (vma->vm_flags & VM_READ)
dmap = audio_devs[dev]->dmap_in;
else {
printk(KERN_ERR "Sound: Undefined mmap() access\n");
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return -EINVAL;
}
if (dmap == NULL) {
printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n");
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return -EIO;
}
if (dmap->raw_buf == NULL) {
printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n");
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return -EIO;
}
if (dmap->mapping_flags) {
printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n");
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return -EIO;
}
if (vma->vm_pgoff != 0) {
printk(KERN_ERR "Sound: mmap() offset must be 0.\n");
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return -EINVAL;
}
size = vma->vm_end - vma->vm_start;
@@ -478,7 +479,7 @@
if (remap_pfn_range(vma, vma->vm_start,
virt_to_phys(dmap->raw_buf) >> PAGE_SHIFT,
vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return -EAGAIN;
}
@@ -490,7 +491,7 @@
memset(dmap->raw_buf,
dmap->neutral_byte,
dmap->bytes_in_use);
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return 0;
}
diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c
index b15840a..44357d8 100644
--- a/sound/oss/swarm_cs4297a.c
+++ b/sound/oss/swarm_cs4297a.c
@@ -68,7 +68,6 @@
#include <linux/delay.h>
#include <linux/sound.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/soundcard.h>
#include <linux/ac97_codec.h>
#include <linux/pci.h>
@@ -94,6 +93,7 @@
struct cs4297a_state;
+static DEFINE_MUTEX(swarm_cs4297a_mutex);
static void stop_dac(struct cs4297a_state *s);
static void stop_adc(struct cs4297a_state *s);
static void start_dac(struct cs4297a_state *s);
@@ -1535,7 +1535,7 @@
CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()+\n"));
- lock_kernel();
+ mutex_lock(&swarm_cs4297a_mutex);
list_for_each(entry, &cs4297a_devs)
{
s = list_entry(entry, struct cs4297a_state, list);
@@ -1547,7 +1547,7 @@
CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- -ENODEV\n"));
- unlock_kernel();
+ mutex_unlock(&swarm_cs4297a_mutex);
return -ENODEV;
}
VALIDATE_STATE(s);
@@ -1555,7 +1555,7 @@
CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- 0\n"));
- unlock_kernel();
+ mutex_unlock(&swarm_cs4297a_mutex);
return nonseekable_open(inode, file);
}
@@ -1575,10 +1575,10 @@
unsigned int cmd, unsigned long arg)
{
int ret;
- lock_kernel();
+ mutex_lock(&swarm_cs4297a_mutex);
ret = mixer_ioctl((struct cs4297a_state *) file->private_data, cmd,
arg);
- unlock_kernel();
+ mutex_unlock(&swarm_cs4297a_mutex);
return ret;
}
@@ -2350,9 +2350,9 @@
{
int ret;
- lock_kernel();
+ mutex_lock(&swarm_cs4297a_mutex);
ret = cs4297a_ioctl(file, cmd, arg);
- unlock_kernel();
+ mutex_unlock(&swarm_cs4297a_mutex);
return ret;
}
@@ -2509,9 +2509,9 @@
{
int ret;
- lock_kernel();
+ mutex_lock(&swarm_cs4297a_mutex);
ret = cs4297a_open(inode, file);
- unlock_kernel();
+ mutex_unlock(&swarm_cs4297a_mutex);
return ret;
}
diff --git a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c
index 8cd73cd..643f111 100644
--- a/sound/oss/vwsnd.c
+++ b/sound/oss/vwsnd.c
@@ -145,7 +145,6 @@
#include <linux/init.h>
#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
#include <linux/wait.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
@@ -160,6 +159,7 @@
#ifdef VWSND_DEBUG
+static DEFINE_MUTEX(vwsnd_mutex);
static int shut_up = 1;
/*
@@ -2891,11 +2891,11 @@
vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data;
int ret;
- lock_kernel();
+ mutex_lock(&vwsnd_mutex);
mutex_lock(&devc->io_mutex);
ret = vwsnd_audio_do_ioctl(file, cmd, arg);
mutex_unlock(&devc->io_mutex);
- unlock_kernel();
+ mutex_unlock(&vwsnd_mutex);
return ret;
}
@@ -2922,7 +2922,7 @@
DBGE("(inode=0x%p, file=0x%p)\n", inode, file);
- lock_kernel();
+ mutex_lock(&vwsnd_mutex);
INC_USE_COUNT;
for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
if ((devc->audio_minor & ~0x0F) == (minor & ~0x0F))
@@ -2930,7 +2930,7 @@
if (devc == NULL) {
DEC_USE_COUNT;
- unlock_kernel();
+ mutex_unlock(&vwsnd_mutex);
return -ENODEV;
}
@@ -2939,13 +2939,13 @@
mutex_unlock(&devc->open_mutex);
if (file->f_flags & O_NONBLOCK) {
DEC_USE_COUNT;
- unlock_kernel();
+ mutex_unlock(&vwsnd_mutex);
return -EBUSY;
}
interruptible_sleep_on(&devc->open_wait);
if (signal_pending(current)) {
DEC_USE_COUNT;
- unlock_kernel();
+ mutex_unlock(&vwsnd_mutex);
return -ERESTARTSYS;
}
mutex_lock(&devc->open_mutex);
@@ -2998,7 +2998,7 @@
file->private_data = devc;
DBGRV();
- unlock_kernel();
+ mutex_unlock(&vwsnd_mutex);
return 0;
}
@@ -3012,7 +3012,7 @@
vwsnd_port_t *wport = NULL, *rport = NULL;
int err = 0;
- lock_kernel();
+ mutex_lock(&vwsnd_mutex);
mutex_lock(&devc->io_mutex);
{
DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
@@ -3040,7 +3040,7 @@
wake_up(&devc->open_wait);
DEC_USE_COUNT;
DBGR();
- unlock_kernel();
+ mutex_unlock(&vwsnd_mutex);
return err;
}
@@ -3068,18 +3068,18 @@
DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
INC_USE_COUNT;
- lock_kernel();
+ mutex_lock(&vwsnd_mutex);
for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
if (devc->mixer_minor == iminor(inode))
break;
if (devc == NULL) {
DEC_USE_COUNT;
- unlock_kernel();
+ mutex_unlock(&vwsnd_mutex);
return -ENODEV;
}
file->private_data = devc;
- unlock_kernel();
+ mutex_unlock(&vwsnd_mutex);
return 0;
}
@@ -3223,7 +3223,7 @@
DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg);
- lock_kernel();
+ mutex_lock(&vwsnd_mutex);
mutex_lock(&devc->mix_mutex);
{
if ((cmd & ~nrmask) == MIXER_READ(0))
@@ -3234,7 +3234,7 @@
retval = -EINVAL;
}
mutex_unlock(&devc->mix_mutex);
- unlock_kernel();
+ mutex_unlock(&vwsnd_mutex);
return retval;
}
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index e7a8cd0..12e3465 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -207,12 +207,12 @@
config SND_OXYGEN_LIB
tristate
- select SND_PCM
- select SND_MPU401_UART
config SND_OXYGEN
tristate "C-Media 8788 (Oxygen)"
select SND_OXYGEN_LIB
+ select SND_PCM
+ select SND_MPU401_UART
help
Say Y here to include support for sound cards based on the
C-Media CMI8788 (Oxygen HD Audio) chip:
@@ -581,6 +581,8 @@
config SND_HIFIER
tristate "TempoTec HiFier Fantasia"
select SND_OXYGEN_LIB
+ select SND_PCM
+ select SND_MPU401_UART
help
Say Y here to include support for the MediaTek/TempoTec HiFier
Fantasia sound card.
@@ -815,14 +817,17 @@
will be called snd-via82xx-modem.
config SND_VIRTUOSO
- tristate "Asus Virtuoso 100/200 (Xonar)"
+ tristate "Asus Virtuoso 66/100/200 (Xonar)"
select SND_OXYGEN_LIB
+ select SND_PCM
+ select SND_MPU401_UART
+ select SND_JACK if INPUT=y || INPUT=SND
help
Say Y here to include support for sound cards based on the
- Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X,
+ Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS,
Essence ST (Deluxe), and Essence STX.
- Support for the DS is experimental.
- Support for the HDAV1.3 (Deluxe) is very experimental.
+ Support for the HDAV1.3 (Deluxe) is incomplete; for the
+ HDAV1.3 Slim and Xense, missing.
To compile this driver as a module, choose M here: the module
will be called snd-virtuoso.
diff --git a/sound/pci/au88x0/au88x0_mixer.c b/sound/pci/au88x0/au88x0_mixer.c
index c92f493..557c782 100644
--- a/sound/pci/au88x0/au88x0_mixer.c
+++ b/sound/pci/au88x0/au88x0_mixer.c
@@ -23,7 +23,7 @@
if ((err = snd_ac97_bus(vortex->card, 0, &ops, NULL, &pbus)) < 0)
return err;
memset(&ac97, 0, sizeof(ac97));
- // Intialize AC97 codec stuff.
+ // Initialize AC97 codec stuff.
ac97.private_data = vortex;
ac97.scaps = AC97_SCAP_NO_SPDIF;
err = snd_ac97_mixer(pbus, &ac97, &vortex->codec);
diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h
index 14b8d9a..f19c110 100644
--- a/sound/pci/ca0106/ca0106.h
+++ b/sound/pci/ca0106/ca0106.h
@@ -670,8 +670,9 @@
gpio_type = 2 -> shared side-out/line-in. */
int i2c_adc; /* with i2c_adc=1, the driver adds some capture volume
controls, phone, mic, line-in and aux. */
- int spi_dac; /* spi_dac=1 adds the mute switch for each analog
- output, front, rear, etc. */
+ u16 spi_dac; /* spi_dac = 0 -> no spi interface for DACs
+ spi_dac = 0x<front><rear><center-lfe><side>
+ -> specifies DAC id for each channel pair. */
};
// definition of the chip-specific record
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index 0a3d3d6..d2d12c0 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -227,7 +227,7 @@
.name = "Audigy SE [SB0570]",
.gpio_type = 1,
.i2c_adc = 1,
- .spi_dac = 1 } ,
+ .spi_dac = 0x4021 } ,
/* New Audigy LS. Has a different DAC. */
/* SB0570:
* CTRL:CA0106-DAT
@@ -238,7 +238,17 @@
.name = "Audigy SE OEM [SB0570a]",
.gpio_type = 1,
.i2c_adc = 1,
- .spi_dac = 1 } ,
+ .spi_dac = 0x4021 } ,
+ /* Sound Blaster 5.1vx
+ * Tested: Playback on front, rear, center/lfe speakers
+ * Not-Tested: Capture
+ */
+ { .serial = 0x10041102,
+ .name = "Sound Blaster 5.1vx [SB1070]",
+ .gpio_type = 1,
+ .i2c_adc = 0,
+ .spi_dac = 0x0124
+ } ,
/* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */
/* SB0438
* CTRL:CA0106-DAT
@@ -254,7 +264,7 @@
.name = "MSI K8N Diamond MB",
.gpio_type = 2,
.i2c_adc = 1,
- .spi_dac = 1 } ,
+ .spi_dac = 0x4021 } ,
/* Giga-byte GA-G1975X mobo
* Novell bnc#395807
*/
@@ -483,16 +493,18 @@
}
static const int spi_dacd_reg[] = {
- [PCM_FRONT_CHANNEL] = SPI_DACD4_REG,
- [PCM_REAR_CHANNEL] = SPI_DACD0_REG,
- [PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_REG,
- [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_REG,
+ SPI_DACD0_REG,
+ SPI_DACD1_REG,
+ SPI_DACD2_REG,
+ 0,
+ SPI_DACD4_REG,
};
static const int spi_dacd_bit[] = {
- [PCM_FRONT_CHANNEL] = SPI_DACD4_BIT,
- [PCM_REAR_CHANNEL] = SPI_DACD0_BIT,
- [PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_BIT,
- [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_BIT,
+ SPI_DACD0_BIT,
+ SPI_DACD1_BIT,
+ SPI_DACD2_BIT,
+ 0,
+ SPI_DACD4_BIT,
};
static void restore_spdif_bits(struct snd_ca0106 *chip, int idx)
@@ -504,6 +516,45 @@
}
}
+static int snd_ca0106_channel_dac(struct snd_ca0106_details *details,
+ int channel_id)
+{
+ switch (channel_id) {
+ case PCM_FRONT_CHANNEL:
+ return (details->spi_dac & 0xf000) >> (4 * 3);
+ case PCM_REAR_CHANNEL:
+ return (details->spi_dac & 0x0f00) >> (4 * 2);
+ case PCM_CENTER_LFE_CHANNEL:
+ return (details->spi_dac & 0x00f0) >> (4 * 1);
+ case PCM_UNKNOWN_CHANNEL:
+ return (details->spi_dac & 0x000f) >> (4 * 0);
+ default:
+ snd_printk(KERN_DEBUG "ca0106: unknown channel_id %d\n",
+ channel_id);
+ }
+ return 0;
+}
+
+static int snd_ca0106_pcm_power_dac(struct snd_ca0106 *chip, int channel_id,
+ int power)
+{
+ if (chip->details->spi_dac) {
+ const int dac = snd_ca0106_channel_dac(chip->details,
+ channel_id);
+ const int reg = spi_dacd_reg[dac];
+ const int bit = spi_dacd_bit[dac];
+
+ if (power)
+ /* Power up */
+ chip->spi_dac_reg[reg] &= ~bit;
+ else
+ /* Power down */
+ chip->spi_dac_reg[reg] |= bit;
+ return snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
+ }
+ return 0;
+}
+
/* open_playback callback */
static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream,
int channel_id)
@@ -543,12 +594,9 @@
return err;
snd_pcm_set_sync(substream);
- if (chip->details->spi_dac && channel_id != PCM_FRONT_CHANNEL) {
- const int reg = spi_dacd_reg[channel_id];
-
- /* Power up dac */
- chip->spi_dac_reg[reg] &= ~spi_dacd_bit[channel_id];
- err = snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
+ /* Front channel dac should already be on */
+ if (channel_id != PCM_FRONT_CHANNEL) {
+ err = snd_ca0106_pcm_power_dac(chip, channel_id, 1);
if (err < 0)
return err;
}
@@ -568,13 +616,14 @@
restore_spdif_bits(chip, epcm->channel_id);
- if (chip->details->spi_dac && epcm->channel_id != PCM_FRONT_CHANNEL) {
- const int reg = spi_dacd_reg[epcm->channel_id];
-
- /* Power down DAC */
- chip->spi_dac_reg[reg] |= spi_dacd_bit[epcm->channel_id];
- snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
+ /* Front channel dac should stay on */
+ if (epcm->channel_id != PCM_FRONT_CHANNEL) {
+ int err;
+ err = snd_ca0106_pcm_power_dac(chip, epcm->channel_id, 0);
+ if (err < 0)
+ return err;
}
+
/* FIXME: maybe zero others */
return 0;
}
@@ -1002,29 +1051,27 @@
struct snd_ca0106 *emu = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_ca0106_pcm *epcm = runtime->private_data;
- snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0;
+ unsigned int ptr, prev_ptr;
int channel = epcm->channel_id;
+ int timeout = 10;
if (!epcm->running)
return 0;
- ptr3 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
- ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel);
- ptr4 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
- if (ptr3 != ptr4) ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel);
- ptr2 = bytes_to_frames(runtime, ptr1);
- ptr2+= (ptr4 >> 3) * runtime->period_size;
- ptr=ptr2;
- if (ptr >= runtime->buffer_size)
- ptr -= runtime->buffer_size;
- /*
- printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "
- "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n",
- ptr1, ptr2, ptr, (int)runtime->buffer_size,
- (int)runtime->period_size, (int)runtime->frame_bits,
- (int)runtime->rate);
- */
- return ptr;
+ prev_ptr = -1;
+ do {
+ ptr = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
+ ptr = (ptr >> 3) * runtime->period_size;
+ ptr += bytes_to_frames(runtime,
+ snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel));
+ if (ptr >= runtime->buffer_size)
+ ptr -= runtime->buffer_size;
+ if (prev_ptr == ptr)
+ return ptr;
+ prev_ptr = ptr;
+ } while (--timeout);
+ snd_printk(KERN_WARNING "ca0106: unstable DMA pointer!\n");
+ return 0;
}
/* pointer_capture callback */
@@ -1362,7 +1409,7 @@
SPI_REG(12, 0x00),
SPI_REG(SPI_LDA4_REG, SPI_DA_BIT_0dB),
SPI_REG(SPI_RDA4_REG, SPI_DA_BIT_0dB | SPI_DA_BIT_UPDATE),
- SPI_REG(SPI_DACD4_REG, 0x00),
+ SPI_REG(SPI_DACD4_REG, SPI_DACD4_BIT),
};
static unsigned int i2c_adc_init[][2] = {
@@ -1541,7 +1588,7 @@
/* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */
}
- if (chip->details->spi_dac == 1) {
+ if (chip->details->spi_dac) {
/* The SB0570 use SPI to control DAC. */
int size, n;
@@ -1553,6 +1600,9 @@
if (reg < ARRAY_SIZE(chip->spi_dac_reg))
chip->spi_dac_reg[reg] = spi_dac_init[n];
}
+
+ /* Enable front dac only */
+ snd_ca0106_pcm_power_dac(chip, PCM_FRONT_CHANNEL, 1);
}
}
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index 85fd315..630aa49 100644
--- a/sound/pci/ca0106/ca0106_mixer.c
+++ b/sound/pci/ca0106/ca0106_mixer.c
@@ -676,27 +676,64 @@
I2C_VOLUME("Aux Capture Volume", 3),
};
-#define SPI_SWITCH(xname,reg,bit) \
-{ \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
- .info = spi_mute_info, \
- .get = spi_mute_get, \
- .put = spi_mute_put, \
- .private_value = (reg<<SPI_REG_SHIFT) | (bit) \
-}
-
-static struct snd_kcontrol_new snd_ca0106_volume_spi_dac_ctls[]
-__devinitdata = {
- SPI_SWITCH("Analog Front Playback Switch",
- SPI_DMUTE4_REG, SPI_DMUTE4_BIT),
- SPI_SWITCH("Analog Rear Playback Switch",
- SPI_DMUTE0_REG, SPI_DMUTE0_BIT),
- SPI_SWITCH("Analog Center/LFE Playback Switch",
- SPI_DMUTE2_REG, SPI_DMUTE2_BIT),
- SPI_SWITCH("Analog Side Playback Switch",
- SPI_DMUTE1_REG, SPI_DMUTE1_BIT),
+static const int spi_dmute_reg[] = {
+ SPI_DMUTE0_REG,
+ SPI_DMUTE1_REG,
+ SPI_DMUTE2_REG,
+ 0,
+ SPI_DMUTE4_REG,
};
+static const int spi_dmute_bit[] = {
+ SPI_DMUTE0_BIT,
+ SPI_DMUTE1_BIT,
+ SPI_DMUTE2_BIT,
+ 0,
+ SPI_DMUTE4_BIT,
+};
+
+static struct snd_kcontrol_new __devinit
+snd_ca0106_volume_spi_dac_ctl(struct snd_ca0106_details *details,
+ int channel_id)
+{
+ struct snd_kcontrol_new spi_switch = {0};
+ int reg, bit;
+ int dac_id;
+
+ spi_switch.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ spi_switch.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+ spi_switch.info = spi_mute_info;
+ spi_switch.get = spi_mute_get;
+ spi_switch.put = spi_mute_put;
+
+ switch (channel_id) {
+ case PCM_FRONT_CHANNEL:
+ spi_switch.name = "Analog Front Playback Switch";
+ dac_id = (details->spi_dac & 0xf000) >> (4 * 3);
+ break;
+ case PCM_REAR_CHANNEL:
+ spi_switch.name = "Analog Rear Playback Switch";
+ dac_id = (details->spi_dac & 0x0f00) >> (4 * 2);
+ break;
+ case PCM_CENTER_LFE_CHANNEL:
+ spi_switch.name = "Analog Center/LFE Playback Switch";
+ dac_id = (details->spi_dac & 0x00f0) >> (4 * 1);
+ break;
+ case PCM_UNKNOWN_CHANNEL:
+ spi_switch.name = "Analog Side Playback Switch";
+ dac_id = (details->spi_dac & 0x000f) >> (4 * 0);
+ break;
+ default:
+ /* Unused channel */
+ spi_switch.name = NULL;
+ dac_id = 0;
+ }
+ reg = spi_dmute_reg[dac_id];
+ bit = spi_dmute_bit[dac_id];
+
+ spi_switch.private_value = (reg << SPI_REG_SHIFT) | bit;
+
+ return spi_switch;
+}
static int __devinit remove_ctl(struct snd_card *card, const char *name)
{
@@ -832,8 +869,18 @@
if (err < 0)
return err;
}
- if (emu->details->spi_dac == 1)
- ADD_CTLS(emu, snd_ca0106_volume_spi_dac_ctls);
+ if (emu->details->spi_dac) {
+ int i;
+ for (i = 0;; i++) {
+ struct snd_kcontrol_new ctl;
+ ctl = snd_ca0106_volume_spi_dac_ctl(emu->details, i);
+ if (!ctl.name)
+ break;
+ err = snd_ctl_add(card, snd_ctl_new1(&ctl, emu));
+ if (err < 0)
+ return err;
+ }
+ }
/* Create virtual master controls */
vmaster = snd_ctl_make_virtual_master("Master Playback Volume",
@@ -845,7 +892,7 @@
return err;
add_slaves(card, vmaster, slave_vols);
- if (emu->details->spi_dac == 1) {
+ if (emu->details->spi_dac) {
vmaster = snd_ctl_make_virtual_master("Master Playback Switch",
NULL);
if (!vmaster)
diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c
index 8578c70..bab5648 100644
--- a/sound/pci/emu10k1/emumpu401.c
+++ b/sound/pci/emu10k1/emumpu401.c
@@ -321,7 +321,7 @@
static void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi)
{
- struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)rmidi->private_data;
+ struct snd_emu10k1_midi *midi = rmidi->private_data;
midi->interrupt = NULL;
midi->rmidi = NULL;
}
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 7f487ab..82ebeb9 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -1751,6 +1751,8 @@
"HP dv6", STAC_HP_DV5),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3061,
"HP dv6", STAC_HP_DV5), /* HP dv6-1110ax */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x363e,
+ "HP DV6", STAC_HP_DV5),
SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x7010,
"HP", STAC_HP_DV5),
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c
index d216362..712c171 100644
--- a/sound/pci/ice1712/delta.c
+++ b/sound/pci/ice1712/delta.c
@@ -563,6 +563,7 @@
case ICE1712_SUBDEVICE_DELTA1010E:
case ICE1712_SUBDEVICE_DELTA1010LT:
case ICE1712_SUBDEVICE_MEDIASTATION:
+ case ICE1712_SUBDEVICE_EDIROLDA2496:
ice->num_total_dacs = 8;
ice->num_total_adcs = 8;
break;
@@ -635,6 +636,7 @@
err = snd_ice1712_akm4xxx_init(ak, &akm_delta410, &akm_delta410_priv, ice);
break;
case ICE1712_SUBDEVICE_DELTA1010LT:
+ case ICE1712_SUBDEVICE_EDIROLDA2496:
err = snd_ice1712_akm4xxx_init(ak, &akm_delta1010lt, &akm_delta1010lt_priv, ice);
break;
case ICE1712_SUBDEVICE_DELTA66:
@@ -734,6 +736,7 @@
case ICE1712_SUBDEVICE_DELTA66:
case ICE1712_SUBDEVICE_VX442:
case ICE1712_SUBDEVICE_DELTA66E:
+ case ICE1712_SUBDEVICE_EDIROLDA2496:
err = snd_ice1712_akm4xxx_build_controls(ice);
if (err < 0)
return err;
@@ -813,5 +816,12 @@
.chip_init = snd_ice1712_delta_init,
.build_controls = snd_ice1712_delta_add_controls,
},
+ {
+ .subvendor = ICE1712_SUBDEVICE_EDIROLDA2496,
+ .name = "Edirol DA2496",
+ .model = "da2496",
+ .chip_init = snd_ice1712_delta_init,
+ .build_controls = snd_ice1712_delta_add_controls,
+ },
{ } /* terminator */
};
diff --git a/sound/pci/ice1712/delta.h b/sound/pci/ice1712/delta.h
index f7f14df..1a0ac6c 100644
--- a/sound/pci/ice1712/delta.h
+++ b/sound/pci/ice1712/delta.h
@@ -34,7 +34,8 @@
"{MidiMan M Audio,Delta 410},"\
"{MidiMan M Audio,Audiophile 24/96},"\
"{Digigram,VX442},"\
- "{Lionstracs,Mediastation},"
+ "{Lionstracs,Mediastation},"\
+ "{Edirol,DA2496},"
#define ICE1712_SUBDEVICE_DELTA1010 0x121430d6
#define ICE1712_SUBDEVICE_DELTA1010E 0xff1430d6
@@ -47,6 +48,7 @@
#define ICE1712_SUBDEVICE_DELTA1010LT 0x12143bd6
#define ICE1712_SUBDEVICE_VX442 0x12143cd6
#define ICE1712_SUBDEVICE_MEDIASTATION 0x694c0100
+#define ICE1712_SUBDEVICE_EDIROLDA2496 0xce164010
/* entry point */
extern struct snd_ice1712_card_info snd_ice1712_delta_cards[];
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c
index 6bc3f91..cdb873f 100644
--- a/sound/pci/ice1712/pontis.c
+++ b/sound/pci/ice1712/pontis.c
@@ -638,7 +638,7 @@
*/
static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
{
- struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
+ struct snd_ice1712 *ice = entry->private_data;
char line[64];
unsigned int reg, val;
mutex_lock(&ice->gpio_mutex);
@@ -653,7 +653,7 @@
static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
{
- struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
+ struct snd_ice1712 *ice = entry->private_data;
int reg, val;
mutex_lock(&ice->gpio_mutex);
@@ -676,7 +676,7 @@
static void cs_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
{
- struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
+ struct snd_ice1712 *ice = entry->private_data;
int reg, val;
mutex_lock(&ice->gpio_mutex);
diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c
index 2a8e5cd..e36ddb9 100644
--- a/sound/pci/ice1712/prodigy192.c
+++ b/sound/pci/ice1712/prodigy192.c
@@ -654,7 +654,7 @@
static void stac9460_proc_regs_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
- struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
+ struct snd_ice1712 *ice = entry->private_data;
int reg, val;
/* registers 0x0 - 0x14 */
for (reg = 0; reg <= 0x15; reg++) {
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c
index 289cb4d..98a8eb3 100644
--- a/sound/pci/oxygen/oxygen.c
+++ b/sound/pci/oxygen/oxygen.c
@@ -79,6 +79,7 @@
{ OXYGEN_PCI_SUBID(0x13f6, 0x0001), .driver_data = MODEL_CMEDIA_REF },
{ OXYGEN_PCI_SUBID(0x13f6, 0x0010), .driver_data = MODEL_CMEDIA_REF },
{ OXYGEN_PCI_SUBID(0x13f6, 0x8788), .driver_data = MODEL_CMEDIA_REF },
+ { OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_CMEDIA_REF },
{ OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF },
{ OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF },
{ OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN },
@@ -505,7 +506,8 @@
PLAYBACK_2_TO_AC97_1 |
CAPTURE_0_FROM_I2S_1 |
CAPTURE_1_FROM_SPDIF |
- CAPTURE_2_FROM_AC97_1,
+ CAPTURE_2_FROM_AC97_1 |
+ AC97_CD_INPUT,
.dac_channels = 8,
.dac_volume_min = 0,
.dac_volume_max = 255,
@@ -543,6 +545,10 @@
chip->model.suspend = claro_suspend;
chip->model.resume = claro_resume;
chip->model.set_adc_params = set_ak5385_params;
+ chip->model.device_config = PLAYBACK_0_TO_I2S |
+ PLAYBACK_1_TO_SPDIF |
+ CAPTURE_0_FROM_I2S_2 |
+ CAPTURE_1_FROM_SPDIF;
break;
}
if (id->driver_data == MODEL_MERIDIAN ||
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h
index a3409ed..7d5222c 100644
--- a/sound/pci/oxygen/oxygen.h
+++ b/sound/pci/oxygen/oxygen.h
@@ -34,6 +34,7 @@
/* CAPTURE_3_FROM_I2S_3 not implemented */
#define MIDI_OUTPUT 0x0800
#define MIDI_INPUT 0x1000
+#define AC97_CD_INPUT 0x2000
enum {
CONTROL_SPDIF_PCM,
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c
index 7e93cf8..e5ebe56 100644
--- a/sound/pci/oxygen/oxygen_lib.c
+++ b/sound/pci/oxygen/oxygen_lib.c
@@ -308,25 +308,46 @@
}
}
-static void pci_bridge_magic(void)
+static void configure_pcie_bridge(struct pci_dev *pci)
{
- struct pci_dev *pci = NULL;
+ enum { PEX811X, PI7C9X110 };
+ static const struct pci_device_id bridge_ids[] = {
+ { PCI_VDEVICE(PLX, 0x8111), .driver_data = PEX811X },
+ { PCI_VDEVICE(PLX, 0x8112), .driver_data = PEX811X },
+ { PCI_DEVICE(0x12d8, 0xe110), .driver_data = PI7C9X110 },
+ { }
+ };
+ struct pci_dev *bridge;
+ const struct pci_device_id *id;
u32 tmp;
- for (;;) {
- /* If there is any Pericom PI7C9X110 PCI-E/PCI bridge ... */
- pci = pci_get_device(0x12d8, 0xe110, pci);
- if (!pci)
- break;
- /*
- * ... configure its secondary internal arbiter to park to
- * the secondary port, instead of to the last master.
- */
- if (!pci_read_config_dword(pci, 0x40, &tmp)) {
- tmp |= 1;
- pci_write_config_dword(pci, 0x40, tmp);
- }
- /* Why? Try asking C-Media. */
+ if (!pci->bus || !pci->bus->self)
+ return;
+ bridge = pci->bus->self;
+
+ id = pci_match_id(bridge_ids, bridge);
+ if (!id)
+ return;
+
+ switch (id->driver_data) {
+ case PEX811X: /* PLX PEX8111/PEX8112 PCIe/PCI bridge */
+ pci_read_config_dword(bridge, 0x48, &tmp);
+ tmp |= 1; /* enable blind prefetching */
+ tmp |= 1 << 11; /* enable beacon generation */
+ pci_write_config_dword(bridge, 0x48, tmp);
+
+ pci_write_config_dword(bridge, 0x84, 0x0c);
+ pci_read_config_dword(bridge, 0x88, &tmp);
+ tmp &= ~(7 << 27);
+ tmp |= 2 << 27; /* set prefetch size to 128 bytes */
+ pci_write_config_dword(bridge, 0x88, tmp);
+ break;
+
+ case PI7C9X110: /* Pericom PI7C9X110 PCIe/PCI bridge */
+ pci_read_config_dword(bridge, 0x40, &tmp);
+ tmp |= 1; /* park the PCI arbiter to the sound chip */
+ pci_write_config_dword(bridge, 0x40, tmp);
+ break;
}
}
@@ -613,7 +634,7 @@
snd_card_set_dev(card, &pci->dev);
card->private_free = oxygen_card_free;
- pci_bridge_magic();
+ configure_pcie_bridge(pci);
oxygen_init(chip);
chip->model.init(chip);
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c
index f375b8a..2849b36 100644
--- a/sound/pci/oxygen/oxygen_mixer.c
+++ b/sound/pci/oxygen/oxygen_mixer.c
@@ -708,7 +708,7 @@
.private_value = ((codec) << 24) | ((stereo) << 16) | (index), \
}
-static DECLARE_TLV_DB_SCALE(monitor_db_scale, -1000, 1000, 0);
+static DECLARE_TLV_DB_SCALE(monitor_db_scale, -600, 600, 0);
static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0);
static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0);
@@ -972,6 +972,9 @@
if (!strcmp(template.name, "Stereo Upmixing") &&
chip->model.dac_channels == 2)
continue;
+ if (!strncmp(template.name, "CD Capture ", 11) &&
+ !(chip->model.device_config & AC97_CD_INPUT))
+ continue;
if (!strcmp(template.name, "Master Playback Volume") &&
chip->model.dac_tlv) {
template.tlv.p = chip->model.dac_tlv;
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c
index 9dff695..8146674 100644
--- a/sound/pci/oxygen/oxygen_pcm.c
+++ b/sound/pci/oxygen/oxygen_pcm.c
@@ -56,8 +56,8 @@
.channels_max = 2,
.buffer_bytes_max = BUFFER_BYTES_MAX,
.period_bytes_min = PERIOD_BYTES_MIN,
- .period_bytes_max = BUFFER_BYTES_MAX / 2,
- .periods_min = 2,
+ .period_bytes_max = BUFFER_BYTES_MAX,
+ .periods_min = 1,
.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
};
static const struct snd_pcm_hardware oxygen_multichannel_hardware = {
@@ -82,8 +82,8 @@
.channels_max = 8,
.buffer_bytes_max = BUFFER_BYTES_MAX_MULTICH,
.period_bytes_min = PERIOD_BYTES_MIN,
- .period_bytes_max = BUFFER_BYTES_MAX_MULTICH / 2,
- .periods_min = 2,
+ .period_bytes_max = BUFFER_BYTES_MAX_MULTICH,
+ .periods_min = 1,
.periods_max = BUFFER_BYTES_MAX_MULTICH / PERIOD_BYTES_MIN,
};
static const struct snd_pcm_hardware oxygen_ac97_hardware = {
@@ -100,8 +100,8 @@
.channels_max = 2,
.buffer_bytes_max = BUFFER_BYTES_MAX,
.period_bytes_min = PERIOD_BYTES_MIN,
- .period_bytes_max = BUFFER_BYTES_MAX / 2,
- .periods_min = 2,
+ .period_bytes_max = BUFFER_BYTES_MAX,
+ .periods_min = 1,
.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
};
diff --git a/sound/pci/oxygen/oxygen_regs.h b/sound/pci/oxygen/oxygen_regs.h
index 72de159..4dcd41b 100644
--- a/sound/pci/oxygen/oxygen_regs.h
+++ b/sound/pci/oxygen/oxygen_regs.h
@@ -436,13 +436,15 @@
/* OXYGEN_CHANNEL_* */
#define OXYGEN_CODEC_VERSION 0xe4
-#define OXYGEN_XCID_MASK 0x07
+#define OXYGEN_CODEC_ID_MASK 0x07
#define OXYGEN_REVISION 0xe6
-#define OXYGEN_REVISION_XPKGID_MASK 0x0007
+#define OXYGEN_PACKAGE_ID_MASK 0x0007
+#define OXYGEN_PACKAGE_ID_8786 0x0004
+#define OXYGEN_PACKAGE_ID_8787 0x0006
+#define OXYGEN_PACKAGE_ID_8788 0x0007
#define OXYGEN_REVISION_MASK 0xfff8
-#define OXYGEN_REVISION_2 0x0008 /* bit flag */
-#define OXYGEN_REVISION_8787 0x0014 /* 8 bits */
+#define OXYGEN_REVISION_2 0x0008
#define OXYGEN_OFFSIN_48K 0xe8
#define OXYGEN_OFFSBASE_48K 0xe9
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c
index 06c863e..469010a 100644
--- a/sound/pci/oxygen/virtuoso.c
+++ b/sound/pci/oxygen/virtuoso.c
@@ -25,9 +25,9 @@
#include "xonar.h"
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
-MODULE_DESCRIPTION("Asus AVx00 driver");
+MODULE_DESCRIPTION("Asus Virtuoso driver");
MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("{{Asus,AV100},{Asus,AV200}}");
+MODULE_SUPPORTED_DEVICE("{{Asus,AV66},{Asus,AV100},{Asus,AV200}}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
@@ -49,6 +49,7 @@
{ OXYGEN_PCI_SUBID(0x1043, 0x834f) },
{ OXYGEN_PCI_SUBID(0x1043, 0x835c) },
{ OXYGEN_PCI_SUBID(0x1043, 0x835d) },
+ { OXYGEN_PCI_SUBID(0x1043, 0x835e) },
{ OXYGEN_PCI_SUBID(0x1043, 0x838e) },
{ OXYGEN_PCI_SUBID_BROKEN_EEPROM },
{ }
diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c
index 7c4986b..aa27c31 100644
--- a/sound/pci/oxygen/xonar_cs43xx.c
+++ b/sound/pci/oxygen/xonar_cs43xx.c
@@ -367,13 +367,6 @@
static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0);
-static int xonar_d1_control_filter(struct snd_kcontrol_new *template)
-{
- if (!strncmp(template->name, "CD Capture ", 11))
- return 1; /* no CD input */
- return 0;
-}
-
static int xonar_d1_mixer_init(struct oxygen *chip)
{
int err;
@@ -391,7 +384,6 @@
.longname = "Asus Virtuoso 100",
.chip = "AV200",
.init = xonar_d1_init,
- .control_filter = xonar_d1_control_filter,
.mixer_init = xonar_d1_mixer_init,
.cleanup = xonar_d1_cleanup,
.suspend = xonar_d1_suspend,
diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c
index ba18fb5..d491fd6 100644
--- a/sound/pci/oxygen/xonar_pcm179x.c
+++ b/sound/pci/oxygen/xonar_pcm179x.c
@@ -132,6 +132,18 @@
* GPIO 5 <- 0
*/
+/*
+ * Xonar HDAV1.3 Slim
+ * ------------------
+ *
+ * CMI8788:
+ *
+ * GPIO 1 -> enable output
+ *
+ * TXD -> HDMI controller
+ * RXD <- HDMI controller
+ */
+
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/mutex.h>
@@ -362,7 +374,6 @@
{
struct xonar_pcm179x *data = chip->model_data;
- data->generic.anti_pop_delay = 100;
data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE;
data->dacs = chip->model.private_data ? 4 : 1;
data->hp_gain_offset = 2*-18;
@@ -408,6 +419,7 @@
{
struct xonar_pcm179x *data = chip->model_data;
+ data->generic.anti_pop_delay = 100;
data->has_cs2000 = 1;
data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1;
@@ -428,6 +440,7 @@
struct xonar_pcm179x *data = chip->model_data;
xonar_st_init_i2c(chip);
+ data->generic.anti_pop_delay = 800;
data->generic.ext_power_reg = OXYGEN_GPI_DATA;
data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
data->generic.ext_power_bit = GPI_EXT_POWER;
@@ -915,13 +928,6 @@
return 0;
}
-static int xonar_st_control_filter(struct snd_kcontrol_new *template)
-{
- if (!strncmp(template->name, "CD Capture ", 11))
- return 1; /* no CD input */
- return 0;
-}
-
static int add_pcm1796_controls(struct oxygen *chip)
{
int err;
@@ -991,7 +997,8 @@
CAPTURE_0_FROM_I2S_2 |
CAPTURE_1_FROM_SPDIF |
MIDI_OUTPUT |
- MIDI_INPUT,
+ MIDI_INPUT |
+ AC97_CD_INPUT,
.dac_channels = 8,
.dac_volume_min = 255 - 2*60,
.dac_volume_max = 255,
@@ -1037,7 +1044,6 @@
.longname = "Asus Virtuoso 100",
.chip = "AV200",
.init = xonar_st_init,
- .control_filter = xonar_st_control_filter,
.mixer_init = xonar_st_mixer_init,
.cleanup = xonar_st_cleanup,
.suspend = xonar_st_suspend,
@@ -1108,6 +1114,9 @@
chip->model.resume = xonar_stx_resume;
chip->model.set_dac_params = set_pcm1796_params;
break;
+ case 0x835e:
+ snd_printk(KERN_ERR "the HDAV1.3 Slim is not supported\n");
+ return -ENODEV;
default:
return -EINVAL;
}
diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c
index b82c1cf..200f760 100644
--- a/sound/pci/oxygen/xonar_wm87x6.c
+++ b/sound/pci/oxygen/xonar_wm87x6.c
@@ -25,16 +25,24 @@
* SPI 0 -> WM8766 (surround, center/LFE, back)
* SPI 1 -> WM8776 (front, input)
*
- * GPIO 4 <- headphone detect
- * GPIO 6 -> route input jack to input 1/2 (1/0)
- * GPIO 7 -> enable output to speakers
- * GPIO 8 -> enable output to speakers
+ * GPIO 4 <- headphone detect, 0 = plugged
+ * GPIO 6 -> route input jack to mic-in (0) or line-in (1)
+ * GPIO 7 -> enable output to front L/R speaker channels
+ * GPIO 8 -> enable output to other speaker channels and front panel headphone
+ *
+ * WM8766:
+ *
+ * input 1 <- line
+ * input 2 <- mic
+ * input 3 <- front mic
+ * input 4 <- aux
*/
#include <linux/pci.h>
#include <linux/delay.h>
#include <sound/control.h>
#include <sound/core.h>
+#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/tlv.h>
@@ -44,7 +52,8 @@
#define GPIO_DS_HP_DETECT 0x0010
#define GPIO_DS_INPUT_ROUTE 0x0040
-#define GPIO_DS_OUTPUT_ENABLE 0x0180
+#define GPIO_DS_OUTPUT_FRONTLR 0x0080
+#define GPIO_DS_OUTPUT_ENABLE 0x0100
#define LC_CONTROL_LIMITER 0x40000000
#define LC_CONTROL_ALC 0x20000000
@@ -56,6 +65,7 @@
struct snd_kcontrol *line_adcmux_control;
struct snd_kcontrol *mic_adcmux_control;
struct snd_kcontrol *lc_controls[13];
+ struct snd_jack *hp_jack;
};
static void wm8776_write(struct oxygen *chip,
@@ -97,8 +107,12 @@
(0 << OXYGEN_SPI_CODEC_SHIFT) |
OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
(reg << 9) | value);
- if (reg < ARRAY_SIZE(data->wm8766_regs))
+ if (reg < ARRAY_SIZE(data->wm8766_regs)) {
+ if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) ||
+ (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA))
+ value &= ~WM8766_UPDATE;
data->wm8766_regs[reg] = value;
+ }
}
static void wm8766_write_cached(struct oxygen *chip,
@@ -107,12 +121,8 @@
struct xonar_wm87x6 *data = chip->model_data;
if (reg >= ARRAY_SIZE(data->wm8766_regs) ||
- value != data->wm8766_regs[reg]) {
- if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) ||
- (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA))
- value &= ~WM8766_UPDATE;
+ value != data->wm8766_regs[reg])
wm8766_write(chip, reg, value);
- }
}
static void wm8776_registers_init(struct oxygen *chip)
@@ -141,7 +151,10 @@
static void wm8766_registers_init(struct oxygen *chip)
{
+ struct xonar_wm87x6 *data = chip->model_data;
+
wm8766_write(chip, WM8766_RESET, 0);
+ wm8766_write(chip, WM8766_DAC_CTRL, data->wm8766_regs[WM8766_DAC_CTRL]);
wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24);
wm8766_write(chip, WM8766_DAC_CTRL2,
WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0));
@@ -170,6 +183,40 @@
wm8776_registers_init(chip);
}
+static void wm8766_init(struct oxygen *chip)
+{
+ struct xonar_wm87x6 *data = chip->model_data;
+
+ data->wm8766_regs[WM8766_DAC_CTRL] =
+ WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT;
+ wm8766_registers_init(chip);
+}
+
+static void xonar_ds_handle_hp_jack(struct oxygen *chip)
+{
+ struct xonar_wm87x6 *data = chip->model_data;
+ bool hp_plugged;
+ unsigned int reg;
+
+ mutex_lock(&chip->mutex);
+
+ hp_plugged = !(oxygen_read16(chip, OXYGEN_GPIO_DATA) &
+ GPIO_DS_HP_DETECT);
+
+ oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+ hp_plugged ? 0 : GPIO_DS_OUTPUT_FRONTLR,
+ GPIO_DS_OUTPUT_FRONTLR);
+
+ reg = data->wm8766_regs[WM8766_DAC_CTRL] & ~WM8766_MUTEALL;
+ if (hp_plugged)
+ reg |= WM8766_MUTEALL;
+ wm8766_write_cached(chip, WM8766_DAC_CTRL, reg);
+
+ snd_jack_report(data->hp_jack, hp_plugged ? SND_JACK_HEADPHONE : 0);
+
+ mutex_unlock(&chip->mutex);
+}
+
static void xonar_ds_init(struct oxygen *chip)
{
struct xonar_wm87x6 *data = chip->model_data;
@@ -178,16 +225,22 @@
data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE;
wm8776_init(chip);
- wm8766_registers_init(chip);
+ wm8766_init(chip);
- oxygen_write16_masked(chip, OXYGEN_GPIO_CONTROL, GPIO_DS_INPUT_ROUTE,
- GPIO_DS_HP_DETECT | GPIO_DS_INPUT_ROUTE);
+ oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+ GPIO_DS_INPUT_ROUTE | GPIO_DS_OUTPUT_FRONTLR);
+ oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
+ GPIO_DS_HP_DETECT);
oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE);
oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT);
chip->interrupt_mask |= OXYGEN_INT_GPIO;
xonar_enable_output(chip);
+ snd_jack_new(chip->card, "Headphone",
+ SND_JACK_HEADPHONE, &data->hp_jack);
+ xonar_ds_handle_hp_jack(chip);
+
snd_component_add(chip->card, "WM8776");
snd_component_add(chip->card, "WM8766");
}
@@ -208,6 +261,7 @@
wm8776_registers_init(chip);
wm8766_registers_init(chip);
xonar_enable_output(chip);
+ xonar_ds_handle_hp_jack(chip);
}
static void wm8776_adc_hardware_filter(unsigned int channel,
@@ -323,12 +377,27 @@
(chip->dac_mute ? WM8766_DMUTE_MASK : 0));
}
+static void update_wm8766_center_lfe_mix(struct oxygen *chip, bool mixed)
+{
+ struct xonar_wm87x6 *data = chip->model_data;
+ unsigned int reg;
+
+ /*
+ * The WM8766 can mix left and right channels, but this setting
+ * applies to all three stereo pairs.
+ */
+ reg = data->wm8766_regs[WM8766_DAC_CTRL] &
+ ~(WM8766_PL_LEFT_MASK | WM8766_PL_RIGHT_MASK);
+ if (mixed)
+ reg |= WM8766_PL_LEFT_LRMIX | WM8766_PL_RIGHT_LRMIX;
+ else
+ reg |= WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT;
+ wm8766_write_cached(chip, WM8766_DAC_CTRL, reg);
+}
+
static void xonar_ds_gpio_changed(struct oxygen *chip)
{
- u16 bits;
-
- bits = oxygen_read16(chip, OXYGEN_GPIO_DATA);
- snd_printk(KERN_INFO "HP detect: %d\n", !!(bits & GPIO_DS_HP_DETECT));
+ xonar_ds_handle_hp_jack(chip);
}
static int wm8776_bit_switch_get(struct snd_kcontrol *ctl,
@@ -896,7 +965,10 @@
.put = wm8776_input_mux_put,
.private_value = 1 << 1,
},
- WM8776_BIT_SWITCH("Aux", WM8776_ADCMUX, 1 << 2, 0, 0),
+ WM8776_BIT_SWITCH("Front Mic Capture Switch",
+ WM8776_ADCMUX, 1 << 2, 0, 0),
+ WM8776_BIT_SWITCH("Aux Capture Switch",
+ WM8776_ADCMUX, 1 << 3, 0, 0),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "ADC Filter Capture Enum",
@@ -956,13 +1028,6 @@
LC_CONTROL_ALC, wm8776_ngth_db_scale),
};
-static int xonar_ds_control_filter(struct snd_kcontrol_new *template)
-{
- if (!strncmp(template->name, "CD Capture ", 11))
- return 1; /* no CD input */
- return 0;
-}
-
static int xonar_ds_mixer_init(struct oxygen *chip)
{
struct xonar_wm87x6 *data = chip->model_data;
@@ -999,10 +1064,9 @@
static const struct oxygen_model model_xonar_ds = {
.shortname = "Xonar DS",
- .longname = "Asus Virtuoso 200",
+ .longname = "Asus Virtuoso 66",
.chip = "AV200",
.init = xonar_ds_init,
- .control_filter = xonar_ds_control_filter,
.mixer_init = xonar_ds_mixer_init,
.cleanup = xonar_ds_cleanup,
.suspend = xonar_ds_suspend,
@@ -1013,6 +1077,7 @@
.set_adc_params = set_wm8776_adc_params,
.update_dac_volume = update_wm87x6_volume,
.update_dac_mute = update_wm87x6_mute,
+ .update_center_lfe_mix = update_wm8766_center_lfe_mix,
.gpio_changed = xonar_ds_gpio_changed,
.dac_tlv = wm87x6_dac_db_scale,
.model_data_size = sizeof(struct xonar_wm87x6),
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index d19dc05..d5f5b44 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -1527,14 +1527,14 @@
static void
snd_rme96_free_spdif_pcm(struct snd_pcm *pcm)
{
- struct rme96 *rme96 = (struct rme96 *) pcm->private_data;
+ struct rme96 *rme96 = pcm->private_data;
rme96->spdif_pcm = NULL;
}
static void
snd_rme96_free_adat_pcm(struct snd_pcm *pcm)
{
- struct rme96 *rme96 = (struct rme96 *) pcm->private_data;
+ struct rme96 *rme96 = pcm->private_data;
rme96->adat_pcm = NULL;
}
@@ -1661,7 +1661,7 @@
snd_rme96_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
{
int n;
- struct rme96 *rme96 = (struct rme96 *)entry->private_data;
+ struct rme96 *rme96 = entry->private_data;
rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
@@ -2348,7 +2348,7 @@
if (err < 0)
return err;
card->private_free = snd_rme96_card_free;
- rme96 = (struct rme96 *)card->private_data;
+ rme96 = card->private_data;
rme96->card = card;
rme96->pci = pci;
snd_card_set_dev(card, &pci->dev);
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index b92adef..0b720cf 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -3284,7 +3284,7 @@
static void
snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
{
- struct hdsp *hdsp = (struct hdsp *) entry->private_data;
+ struct hdsp *hdsp = entry->private_data;
unsigned int status;
unsigned int status2;
char *pref_sync_ref;
@@ -4566,7 +4566,7 @@
static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg)
{
- struct hdsp *hdsp = (struct hdsp *)hw->private_data;
+ struct hdsp *hdsp = hw->private_data;
void __user *argp = (void __user *)arg;
int err;
@@ -4609,6 +4609,7 @@
if (err < 0)
return err;
+ memset(&info, 0, sizeof(info));
spin_lock_irqsave(&hdsp->lock, flags);
info.pref_sync_ref = (unsigned char)hdsp_pref_sync_ref(hdsp);
info.wordclock_sync_check = (unsigned char)hdsp_wc_sync_check(hdsp);
@@ -5155,7 +5156,7 @@
static void snd_hdsp_card_free(struct snd_card *card)
{
- struct hdsp *hdsp = (struct hdsp *) card->private_data;
+ struct hdsp *hdsp = card->private_data;
if (hdsp)
snd_hdsp_free(hdsp);
@@ -5181,7 +5182,7 @@
if (err < 0)
return err;
- hdsp = (struct hdsp *) card->private_data;
+ hdsp = card->private_data;
card->private_free = snd_hdsp_card_free;
hdsp->dev = dev;
hdsp->pci = pci;
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 547b713..0c98ef9 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -4127,6 +4127,7 @@
case SNDRV_HDSPM_IOCTL_GET_CONFIG_INFO:
+ memset(&info, 0, sizeof(info));
spin_lock_irq(&hdspm->lock);
info.pref_sync_ref = hdspm_pref_sync_ref(hdspm);
info.wordclock_sync_check = hdspm_wc_sync_check(hdspm);
diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c
index 2f12da4..581a670 100644
--- a/sound/ppc/snd_ps3.c
+++ b/sound/ppc/snd_ps3.c
@@ -579,7 +579,7 @@
rate * delay_ms / 1000)
* substream->runtime->channels;
- pr_debug(KERN_ERR "%s: time=%d rate=%d bytes=%ld, frames=%d, ret=%d\n",
+ pr_debug("%s: time=%d rate=%d bytes=%ld, frames=%d, ret=%d\n",
__func__,
delay_ms,
rate,
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index 20afdf9..961d982 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -785,7 +785,7 @@
if (! mix->i2c.client)
return -ENODEV;
if (mix->capture_source)
- mix->acs = mix->acs |= 2;
+ mix->acs |= 2;
else
mix->acs &= ~2;
return i2c_smbus_write_byte_data(mix->i2c.client, TAS_REG_ACS, mix->acs);
diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c
index dc5249f..d0e7532 100644
--- a/sound/soc/atmel/atmel-pcm.c
+++ b/sound/soc/atmel/atmel-pcm.c
@@ -179,7 +179,7 @@
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
runtime->dma_bytes = params_buffer_bytes(params);
- prtd->params = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ prtd->params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
prtd->params->dma_intr_handler = atmel_pcm_dma_irq;
prtd->dma_buffer = runtime->dma_addr;
@@ -374,14 +374,14 @@
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = 0xffffffff;
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = atmel_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto out;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
pr_debug("at32-pcm:"
"Allocating PCM capture DMA buffer\n");
ret = atmel_pcm_preallocate_dma_buffer(pcm,
@@ -414,12 +414,9 @@
}
#ifdef CONFIG_PM
-static int atmel_pcm_suspend(struct snd_soc_dai_link *dai_link)
+static int atmel_pcm_suspend(struct snd_soc_dai *dai)
{
- struct snd_pcm *pcm = dai_link->pcm;
- struct snd_pcm_str *stream = &pcm->streams[0];
- struct snd_pcm_substream *substream = stream->substream;
- struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = dai->runtime;
struct atmel_runtime_data *prtd;
struct atmel_pcm_dma_params *params;
@@ -441,12 +438,9 @@
return 0;
}
-static int atmel_pcm_resume(struct snd_soc_dai_link *dai_link)
+static int atmel_pcm_resume(struct snd_soc_dai *dai)
{
- struct snd_pcm *pcm = dai_link->pcm;
- struct snd_pcm_str *stream = &pcm->streams[0];
- struct snd_pcm_substream *substream = stream->substream;
- struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = dai->runtime;
struct atmel_runtime_data *prtd;
struct atmel_pcm_dma_params *params;
@@ -470,27 +464,46 @@
#define atmel_pcm_resume NULL
#endif
-struct snd_soc_platform atmel_soc_platform = {
- .name = "atmel-audio",
- .pcm_ops = &atmel_pcm_ops,
+static struct snd_soc_platform_driver atmel_soc_platform = {
+ .ops = &atmel_pcm_ops,
.pcm_new = atmel_pcm_new,
.pcm_free = atmel_pcm_free_dma_buffers,
.suspend = atmel_pcm_suspend,
.resume = atmel_pcm_resume,
};
-EXPORT_SYMBOL_GPL(atmel_soc_platform);
-static int __init atmel_pcm_modinit(void)
+static int __devinit atmel_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&atmel_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &atmel_soc_platform);
}
-module_init(atmel_pcm_modinit);
-static void __exit atmel_pcm_modexit(void)
+static int __devexit atmel_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&atmel_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
}
-module_exit(atmel_pcm_modexit);
+
+static struct platform_driver atmel_pcm_driver = {
+ .driver = {
+ .name = "atmel-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = atmel_soc_platform_probe,
+ .remove = __devexit_p(atmel_soc_platform_remove),
+};
+
+static int __init snd_atmel_pcm_init(void)
+{
+ return platform_driver_register(&atmel_pcm_driver);
+}
+module_init(snd_atmel_pcm_init);
+
+static void __exit snd_atmel_pcm_exit(void)
+{
+ platform_driver_unregister(&atmel_pcm_driver);
+}
+module_exit(snd_atmel_pcm_exit);
MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>");
MODULE_DESCRIPTION("Atmel PCM module");
diff --git a/sound/soc/atmel/atmel-pcm.h b/sound/soc/atmel/atmel-pcm.h
index ec9b282..2597329 100644
--- a/sound/soc/atmel/atmel-pcm.h
+++ b/sound/soc/atmel/atmel-pcm.h
@@ -74,9 +74,6 @@
void (*dma_intr_handler)(u32, struct snd_pcm_substream *);
};
-extern struct snd_soc_platform atmel_soc_platform;
-
-
/*
* SSC register access (since ssc_writel() / ssc_readl() require literal name)
*/
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index c85844d..5d230ce 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -205,8 +205,7 @@
static int atmel_ssc_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
- struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+ struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
int dir_mask;
pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
@@ -235,8 +234,7 @@
static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
- struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+ struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
struct atmel_pcm_dma_params *dma_params;
int dir, dir_mask;
@@ -338,7 +336,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
- int id = rtd->dai->cpu_dai->id;
+ int id = dai->id;
struct atmel_ssc_info *ssc_p = &ssc_info[id];
struct atmel_pcm_dma_params *dma_params;
int dir, channels, bits;
@@ -368,7 +366,7 @@
* function. It should not be used for other purposes
* as it is common to all substreams.
*/
- snd_soc_dai_set_dma_data(rtd->dai->cpu_dai, substream, dma_params);
+ snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_params);
channels = params_channels(params);
@@ -605,8 +603,7 @@
static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
- struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+ struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
struct atmel_pcm_dma_params *dma_params;
int dir;
@@ -690,6 +687,32 @@
# define atmel_ssc_resume NULL
#endif /* CONFIG_PM */
+static int atmel_ssc_probe(struct snd_soc_dai *dai)
+{
+ struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
+ int ret = 0;
+
+ snd_soc_dai_set_drvdata(dai, ssc_p);
+
+ /*
+ * Request SSC device
+ */
+ ssc_p->ssc = ssc_request(dai->id);
+ if (IS_ERR(ssc_p->ssc)) {
+ printk(KERN_ERR "ASoC: Failed to request SSC %d\n", dai->id);
+ ret = PTR_ERR(ssc_p->ssc);
+ }
+
+ return ret;
+}
+
+static int atmel_ssc_remove(struct snd_soc_dai *dai)
+{
+ struct atmel_ssc_info *ssc_p = snd_soc_dai_get_drvdata(dai);
+
+ ssc_free(ssc_p->ssc);
+ return 0;
+}
#define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000)
@@ -705,9 +728,11 @@
.set_clkdiv = atmel_ssc_set_dai_clkdiv,
};
-struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
- { .name = "atmel-ssc0",
- .id = 0,
+static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = {
+ {
+ .name = "atmel-ssc-dai.0",
+ .probe = atmel_ssc_probe,
+ .remove = atmel_ssc_remove,
.suspend = atmel_ssc_suspend,
.resume = atmel_ssc_resume,
.playback = {
@@ -721,11 +746,12 @@
.rates = ATMEL_SSC_RATES,
.formats = ATMEL_SSC_FORMATS,},
.ops = &atmel_ssc_dai_ops,
- .private_data = &ssc_info[0],
},
#if NUM_SSC_DEVICES == 3
- { .name = "atmel-ssc1",
- .id = 1,
+ {
+ .name = "atmel-ssc-dai.1",
+ .probe = atmel_ssc_probe,
+ .remove = atmel_ssc_remove,
.suspend = atmel_ssc_suspend,
.resume = atmel_ssc_resume,
.playback = {
@@ -739,10 +765,11 @@
.rates = ATMEL_SSC_RATES,
.formats = ATMEL_SSC_FORMATS,},
.ops = &atmel_ssc_dai_ops,
- .private_data = &ssc_info[1],
},
- { .name = "atmel-ssc2",
- .id = 2,
+ {
+ .name = "atmel-ssc-dai.2",
+ .probe = atmel_ssc_probe,
+ .remove = atmel_ssc_remove,
.suspend = atmel_ssc_suspend,
.resume = atmel_ssc_resume,
.playback = {
@@ -756,23 +783,94 @@
.rates = ATMEL_SSC_RATES,
.formats = ATMEL_SSC_FORMATS,},
.ops = &atmel_ssc_dai_ops,
- .private_data = &ssc_info[2],
},
#endif
};
-EXPORT_SYMBOL_GPL(atmel_ssc_dai);
-static int __init atmel_ssc_modinit(void)
+static __devinit int asoc_ssc_probe(struct platform_device *pdev)
{
- return snd_soc_register_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai));
+ BUG_ON(pdev->id < 0);
+ BUG_ON(pdev->id >= ARRAY_SIZE(atmel_ssc_dai));
+ return snd_soc_register_dai(&pdev->dev, &atmel_ssc_dai[pdev->id]);
}
-module_init(atmel_ssc_modinit);
-static void __exit atmel_ssc_modexit(void)
+static int __devexit asoc_ssc_remove(struct platform_device *pdev)
{
- snd_soc_unregister_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai));
+ snd_soc_unregister_dai(&pdev->dev);
+ return 0;
}
-module_exit(atmel_ssc_modexit);
+
+static struct platform_driver asoc_ssc_driver = {
+ .driver = {
+ .name = "atmel-ssc-dai",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = asoc_ssc_probe,
+ .remove = __devexit_p(asoc_ssc_remove),
+};
+
+/**
+ * atmel_ssc_set_audio - Allocate the specified SSC for audio use.
+ */
+int atmel_ssc_set_audio(int ssc_id)
+{
+ struct ssc_device *ssc;
+ static struct platform_device *dma_pdev;
+ struct platform_device *ssc_pdev;
+ int ret;
+
+ if (ssc_id < 0 || ssc_id >= ARRAY_SIZE(atmel_ssc_dai))
+ return -EINVAL;
+
+ /* Allocate a dummy device for DMA if we don't have one already */
+ if (!dma_pdev) {
+ dma_pdev = platform_device_alloc("atmel-pcm-audio", -1);
+ if (!dma_pdev)
+ return -ENOMEM;
+
+ ret = platform_device_add(dma_pdev);
+ if (ret < 0) {
+ platform_device_put(dma_pdev);
+ dma_pdev = NULL;
+ return ret;
+ }
+ }
+
+ ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id);
+ if (!ssc_pdev) {
+ ssc_free(ssc);
+ return -ENOMEM;
+ }
+
+ /* If we can grab the SSC briefly to parent the DAI device off it */
+ ssc = ssc_request(ssc_id);
+ if (IS_ERR(ssc))
+ pr_warn("Unable to parent ASoC SSC DAI on SSC: %ld\n",
+ PTR_ERR(ssc));
+ else
+ ssc_pdev->dev.parent = &(ssc->pdev->dev);
+ ssc_free(ssc);
+
+ ret = platform_device_add(ssc_pdev);
+ if (ret < 0)
+ platform_device_put(ssc_pdev);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(atmel_ssc_set_audio);
+
+static int __init snd_atmel_ssc_init(void)
+{
+ return platform_driver_register(&asoc_ssc_driver);
+}
+module_init(snd_atmel_ssc_init);
+
+static void __exit snd_atmel_ssc_exit(void)
+{
+ platform_driver_unregister(&asoc_ssc_driver);
+}
+module_exit(snd_atmel_ssc_exit);
/* Module information */
MODULE_AUTHOR("Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com");
diff --git a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h
index 391135f..5d4f0f9 100644
--- a/sound/soc/atmel/atmel_ssc_dai.h
+++ b/sound/soc/atmel/atmel_ssc_dai.h
@@ -116,6 +116,7 @@
struct atmel_pcm_dma_params *dma_params[2];
struct atmel_ssc_state ssc_state;
};
-extern struct snd_soc_dai atmel_ssc_dai[];
+
+int atmel_ssc_set_audio(int ssc);
#endif /* _AT91_SSC_DAI_H */
diff --git a/sound/soc/atmel/playpaq_wm8510.c b/sound/soc/atmel/playpaq_wm8510.c
index 9df4c68..5f4e59f 100644
--- a/sound/soc/atmel/playpaq_wm8510.c
+++ b/sound/soc/atmel/playpaq_wm8510.c
@@ -83,7 +83,7 @@
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
- struct at32_ssc_info *ssc_p = cpu_dai->private_data;
+ struct at32_ssc_info *ssc_p = snd_soc_dai_get_drvdata(cpu_dai);
struct ssc_device *ssc = ssc_p->ssc;
struct ssc_clock_data cd;
unsigned int rate, width_bits, channels;
@@ -131,9 +131,9 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct at32_ssc_info *ssc_p = cpu_dai->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct at32_ssc_info *ssc_p = snd_soc_dai_get_drvdata(cpu_dai);
struct ssc_device *ssc = ssc_p->ssc;
unsigned int pll_out = 0, bclk = 0, mclk_div = 0;
int ret;
@@ -315,8 +315,9 @@
-static int playpaq_wm8510_init(struct snd_soc_codec *codec)
+static int playpaq_wm8510_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int i;
/*
@@ -342,7 +343,7 @@
/* Make CSB show PLL rate */
- snd_soc_dai_set_clkdiv(codec->dai, WM8510_OPCLKDIV,
+ snd_soc_dai_set_clkdiv(rtd->codec_dai, WM8510_OPCLKDIV,
WM8510_OPCLKDIV_1 | 4);
return 0;
@@ -353,8 +354,10 @@
static struct snd_soc_dai_link playpaq_wm8510_dai = {
.name = "WM8510",
.stream_name = "WM8510 PCM",
- .cpu_dai = &at32_ssc_dai[0],
- .codec_dai = &wm8510_dai,
+ .cpu_dai_name= "atmel-ssc-dai.0",
+ .platform_name = "atmel-pcm-audio",
+ .codec_name = "wm8510-codec.0-0x1a",
+ .codec_dai_name = "wm8510-hifi",
.init = playpaq_wm8510_init,
.ops = &playpaq_wm8510_ops,
};
@@ -363,46 +366,16 @@
static struct snd_soc_card snd_soc_playpaq = {
.name = "LRS_PlayPaq_WM8510",
- .platform = &at32_soc_platform,
.dai_link = &playpaq_wm8510_dai,
.num_links = 1,
};
-
-
-static struct wm8510_setup_data playpaq_wm8510_setup = {
- .i2c_bus = 0,
- .i2c_address = 0x1a,
-};
-
-
-
-static struct snd_soc_device playpaq_wm8510_snd_devdata = {
- .card = &snd_soc_playpaq,
- .codec_dev = &soc_codec_dev_wm8510,
- .codec_data = &playpaq_wm8510_setup,
-};
-
static struct platform_device *playpaq_snd_device;
static int __init playpaq_asoc_init(void)
{
int ret = 0;
- struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data;
- struct ssc_device *ssc = NULL;
-
-
- /*
- * Request SSC device
- */
- ssc = ssc_request(0);
- if (IS_ERR(ssc)) {
- ret = PTR_ERR(ssc);
- goto err_ssc;
- }
- ssc_p->ssc = ssc;
-
/*
* Configure MCLK for WM8510
@@ -439,8 +412,7 @@
goto err_device_alloc;
}
- platform_set_drvdata(playpaq_snd_device, &playpaq_wm8510_snd_devdata);
- playpaq_wm8510_snd_devdata.dev = &playpaq_snd_device->dev;
+ platform_set_drvdata(playpaq_snd_device, &snd_soc_playpaq);
ret = platform_device_add(playpaq_snd_device);
if (ret) {
@@ -468,25 +440,12 @@
clk_put(_gclk0);
_gclk0 = NULL;
}
-err_gclk0:
- ssc_free(ssc);
-err_ssc:
return ret;
}
static void __exit playpaq_asoc_exit(void)
{
- struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data;
- struct ssc_device *ssc;
-
- if (ssc_p != NULL) {
- ssc = ssc_p->ssc;
- if (ssc != NULL)
- ssc_free(ssc);
- ssc_p->ssc = NULL;
- }
-
if (_gclk0 != NULL) {
clk_put(_gclk0);
_gclk0 = NULL;
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c
index e028744..293569d 100644
--- a/sound/soc/atmel/sam9g20_wm8731.c
+++ b/sound/soc/atmel/sam9g20_wm8731.c
@@ -69,8 +69,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* set codec DAI configuration */
@@ -136,16 +136,17 @@
/*
* Logic for a wm8731 as connected on a at91sam9g20ek board.
*/
-static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec)
+static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *codec_dai = &codec->dai[0];
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
printk(KERN_DEBUG
"at91sam9g20ek_wm8731 "
": at91sam9g20ek_wm8731_init() called\n");
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
MCLK_RATE, SND_SOC_CLOCK_IN);
if (ret < 0) {
printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret);
@@ -179,37 +180,37 @@
static struct snd_soc_dai_link at91sam9g20ek_dai = {
.name = "WM8731",
.stream_name = "WM8731 PCM",
- .cpu_dai = &atmel_ssc_dai[0],
- .codec_dai = &wm8731_dai,
+ .cpu_dai_name = "atmel-ssc-dai.0",
+ .codec_dai_name = "wm8731-hifi",
.init = at91sam9g20ek_wm8731_init,
+ .platform_name = "atmel-pcm-audio",
+ .codec_name = "wm8731-codec.0-001b",
.ops = &at91sam9g20ek_ops,
};
static struct snd_soc_card snd_soc_at91sam9g20ek = {
.name = "AT91SAMG20-EK",
- .platform = &atmel_soc_platform,
.dai_link = &at91sam9g20ek_dai,
.num_links = 1,
.set_bias_level = at91sam9g20ek_set_bias_level,
};
-static struct snd_soc_device at91sam9g20ek_snd_devdata = {
- .card = &snd_soc_at91sam9g20ek,
- .codec_dev = &soc_codec_dev_wm8731,
-};
-
static struct platform_device *at91sam9g20ek_snd_device;
static int __init at91sam9g20ek_init(void)
{
- struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data;
- struct ssc_device *ssc = NULL;
struct clk *pllb;
int ret;
if (!(machine_is_at91sam9g20ek() || machine_is_at91sam9g20ek_2mmc()))
return -ENODEV;
+ ret = atmel_ssc_set_audio(0);
+ if (ret != 0) {
+ pr_err("Failed to set SSC 0 for audio: %d\n", ret);
+ return ret;
+ }
+
/*
* Codec MCLK is supplied by PCK0 - set it up.
*/
@@ -235,18 +236,6 @@
clk_set_rate(mclk, MCLK_RATE);
- /*
- * Request SSC device
- */
- ssc = ssc_request(0);
- if (IS_ERR(ssc)) {
- printk(KERN_ERR "ASoC: Failed to request SSC 0\n");
- ret = PTR_ERR(ssc);
- ssc = NULL;
- goto err_ssc;
- }
- ssc_p->ssc = ssc;
-
at91sam9g20ek_snd_device = platform_device_alloc("soc-audio", -1);
if (!at91sam9g20ek_snd_device) {
printk(KERN_ERR "ASoC: Platform device allocation failed\n");
@@ -254,8 +243,7 @@
}
platform_set_drvdata(at91sam9g20ek_snd_device,
- &at91sam9g20ek_snd_devdata);
- at91sam9g20ek_snd_devdata.dev = &at91sam9g20ek_snd_device->dev;
+ &snd_soc_at91sam9g20ek);
ret = platform_device_add(at91sam9g20ek_snd_device);
if (ret) {
@@ -265,9 +253,6 @@
return ret;
-err_ssc:
- ssc_free(ssc);
- ssc_p->ssc = NULL;
err_mclk:
clk_put(mclk);
mclk = NULL;
@@ -277,16 +262,6 @@
static void __exit at91sam9g20ek_exit(void)
{
- struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data;
- struct ssc_device *ssc;
-
- if (ssc_p != NULL) {
- ssc = ssc_p->ssc;
- if (ssc != NULL)
- ssc_free(ssc);
- ssc_p->ssc = NULL;
- }
-
platform_device_unregister(at91sam9g20ek_snd_device);
at91sam9g20ek_snd_device = NULL;
clk_put(mclk);
diff --git a/sound/soc/atmel/snd-soc-afeb9260.c b/sound/soc/atmel/snd-soc-afeb9260.c
index 23349de..e3d2835 100644
--- a/sound/soc/atmel/snd-soc-afeb9260.c
+++ b/sound/soc/atmel/snd-soc-afeb9260.c
@@ -46,8 +46,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int err;
/* Set codec DAI configuration */
@@ -102,8 +102,9 @@
{"MICIN", NULL, "Mic Jack"},
};
-static int afeb9260_tlv320aic23_init(struct snd_soc_codec *codec)
+static int afeb9260_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
/* Add afeb9260 specific widgets */
snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
@@ -125,8 +126,10 @@
static struct snd_soc_dai_link afeb9260_dai = {
.name = "TLV320AIC23",
.stream_name = "AIC23",
- .cpu_dai = &atmel_ssc_dai[0],
- .codec_dai = &tlv320aic23_dai,
+ .cpu_dai_name = "atmel-ssc-dai.0",
+ .codec_dai_name = "tlv320aic23-hifi",
+ .platform_name = "atmel_pcm-audio",
+ .codec_name = "tlv320aic23-codec.0-0x1a",
.init = afeb9260_tlv320aic23_init,
.ops = &afeb9260_ops,
};
@@ -134,37 +137,20 @@
/* Audio machine driver */
static struct snd_soc_card snd_soc_machine_afeb9260 = {
.name = "AFEB9260",
- .platform = &atmel_soc_platform,
.dai_link = &afeb9260_dai,
.num_links = 1,
};
-/* Audio subsystem */
-static struct snd_soc_device afeb9260_snd_devdata = {
- .card = &snd_soc_machine_afeb9260,
- .codec_dev = &soc_codec_dev_tlv320aic23,
-};
-
static struct platform_device *afeb9260_snd_device;
static int __init afeb9260_soc_init(void)
{
int err;
struct device *dev;
- struct atmel_ssc_info *ssc_p = afeb9260_dai.cpu_dai->private_data;
- struct ssc_device *ssc = NULL;
if (!(machine_is_afeb9260()))
return -ENODEV;
- ssc = ssc_request(0);
- if (IS_ERR(ssc)) {
- printk(KERN_ERR "ASoC: Failed to request SSC 0\n");
- err = PTR_ERR(ssc);
- ssc = NULL;
- goto err_ssc;
- }
- ssc_p->ssc = ssc;
afeb9260_snd_device = platform_device_alloc("soc-audio", -1);
if (!afeb9260_snd_device) {
@@ -172,8 +158,7 @@
return -ENOMEM;
}
- platform_set_drvdata(afeb9260_snd_device, &afeb9260_snd_devdata);
- afeb9260_snd_devdata.dev = &afeb9260_snd_device->dev;
+ platform_set_drvdata(afeb9260_snd_device, &snd_soc_machine_afeb9260);
err = platform_device_add(afeb9260_snd_device);
if (err)
goto err1;
@@ -184,9 +169,7 @@
err1:
platform_device_del(afeb9260_snd_device);
platform_device_put(afeb9260_snd_device);
-err_ssc:
return err;
-
}
static void __exit afeb9260_soc_exit(void)
diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c
index cdf7be1..b62fcd3 100644
--- a/sound/soc/au1x/db1200.c
+++ b/sound/soc/au1x/db1200.c
@@ -19,7 +19,6 @@
#include <asm/mach-au1x00/au1xxx_dbdma.h>
#include <asm/mach-db1x00/bcsr.h>
-#include "../codecs/ac97.h"
#include "../codecs/wm8731.h"
#include "psc.h"
@@ -28,20 +27,16 @@
static struct snd_soc_dai_link db1200_ac97_dai = {
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &au1xpsc_ac97_dai,
- .codec_dai = &ac97_dai,
+ .codec_dai_name = "ac97-hifi",
+ .cpu_dai_name = "au1xpsc_ac97.1",
+ .platform_name = "au1xpsc-pcm.1",
+ .codec_name = "ac97-codec.1",
};
static struct snd_soc_card db1200_ac97_machine = {
.name = "DB1200_AC97",
.dai_link = &db1200_ac97_dai,
.num_links = 1,
- .platform = &au1xpsc_soc_platform,
-};
-
-static struct snd_soc_device db1200_ac97_devdata = {
- .card = &db1200_ac97_machine,
- .codec_dev = &soc_codec_dev_ac97,
};
/*------------------------- I2S PART ---------------------------*/
@@ -49,12 +44,12 @@
static int db1200_i2s_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* WM8731 has its own 12MHz crystal */
- snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
+ snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
12000000, SND_SOC_CLOCK_IN);
/* codec is bitclock and lrclk master */
@@ -80,8 +75,10 @@
static struct snd_soc_dai_link db1200_i2s_dai = {
.name = "WM8731",
.stream_name = "WM8731 PCM",
- .cpu_dai = &au1xpsc_i2s_dai,
- .codec_dai = &wm8731_dai,
+ .codec_dai_name = "wm8731-hifi",
+ .cpu_dai_name = "au1xpsc_i2s.1",
+ .platform_name = "au1xpsc-pcm.1",
+ .codec_name = "wm8731-codec.0-001b",
.ops = &db1200_i2s_wm8731_ops,
};
@@ -89,12 +86,6 @@
.name = "DB1200_I2S",
.dai_link = &db1200_i2s_dai,
.num_links = 1,
- .platform = &au1xpsc_soc_platform,
-};
-
-static struct snd_soc_device db1200_i2s_devdata = {
- .card = &db1200_i2s_machine,
- .codec_dev = &soc_codec_dev_wm8731,
};
/*------------------------- COMMON PART ---------------------------*/
@@ -106,18 +97,16 @@
int ret;
ret = -ENOMEM;
- db1200_asoc_dev = platform_device_alloc("soc-audio", -1);
+ db1200_asoc_dev = platform_device_alloc("soc-audio", 1); /* PSC1 */
if (!db1200_asoc_dev)
goto out;
/* DB1200 board setup set PSC1MUX to preferred audio device */
if (bcsr_read(BCSR_RESETS) & BCSR_RESETS_PSC1MUX)
- platform_set_drvdata(db1200_asoc_dev, &db1200_i2s_devdata);
+ platform_set_drvdata(db1200_asoc_dev, &db1200_i2s_machine);
else
- platform_set_drvdata(db1200_asoc_dev, &db1200_ac97_devdata);
+ platform_set_drvdata(db1200_asoc_dev, &db1200_ac97_machine);
- db1200_ac97_devdata.dev = &db1200_asoc_dev->dev;
- db1200_i2s_devdata.dev = &db1200_asoc_dev->dev;
ret = platform_device_add(db1200_asoc_dev);
if (ret) {
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c
index 6d9f4c6..10fdd28 100644
--- a/sound/soc/au1x/dbdma2.c
+++ b/sound/soc/au1x/dbdma2.c
@@ -10,9 +10,6 @@
*
* DMA glue for Au1x-PSC audio.
*
- * NOTE: all of these drivers can only work with a SINGLE instance
- * of a PSC. Multiple independent audio devices are impossible
- * with ASoC v1.
*/
@@ -61,9 +58,6 @@
int msbits;
};
-/* instance data. There can be only one, MacLeod!!!! */
-static struct au1xpsc_audio_dmadata *au1xpsc_audio_pcmdma[2];
-
/*
* These settings are somewhat okay, at least on my machine audio plays
* almost skip-free. Especially the 64kB buffer seems to help a LOT.
@@ -199,6 +193,14 @@
return 0;
}
+static inline struct au1xpsc_audio_dmadata *to_dmadata(struct snd_pcm_substream *ss)
+{
+ struct snd_soc_pcm_runtime *rtd = ss->private_data;
+ struct au1xpsc_audio_dmadata *pcd =
+ snd_soc_platform_get_drvdata(rtd->platform);
+ return &pcd[SUBSTREAM_TYPE(ss)];
+}
+
static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -211,7 +213,7 @@
goto out;
stype = SUBSTREAM_TYPE(substream);
- pcd = au1xpsc_audio_pcmdma[stype];
+ pcd = to_dmadata(substream);
DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d "
"runtime->min_align %d\n",
@@ -249,8 +251,7 @@
static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
{
- struct au1xpsc_audio_dmadata *pcd =
- au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)];
+ struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream);
au1xxx_dbdma_reset(pcd->ddma_chan);
@@ -267,7 +268,7 @@
static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
- u32 c = au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->ddma_chan;
+ u32 c = to_dmadata(substream)->ddma_chan;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -287,8 +288,7 @@
static snd_pcm_uframes_t
au1xpsc_pcm_pointer(struct snd_pcm_substream *substream)
{
- return bytes_to_frames(substream->runtime,
- au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->pos);
+ return bytes_to_frames(substream->runtime, to_dmadata(substream)->pos);
}
static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
@@ -299,7 +299,7 @@
static int au1xpsc_pcm_close(struct snd_pcm_substream *substream)
{
- au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]);
+ au1x_pcm_dbdma_free(to_dmadata(substream));
return 0;
}
@@ -329,42 +329,21 @@
return 0;
}
-static int au1xpsc_pcm_probe(struct platform_device *pdev)
-{
- if (!au1xpsc_audio_pcmdma[PCM_TX] || !au1xpsc_audio_pcmdma[PCM_RX])
- return -ENODEV;
-
- return 0;
-}
-
-static int au1xpsc_pcm_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
/* au1xpsc audio platform */
-struct snd_soc_platform au1xpsc_soc_platform = {
- .name = "au1xpsc-pcm-dbdma",
- .probe = au1xpsc_pcm_probe,
- .remove = au1xpsc_pcm_remove,
- .pcm_ops = &au1xpsc_pcm_ops,
+struct snd_soc_platform_driver au1xpsc_soc_platform = {
+ .ops = &au1xpsc_pcm_ops,
.pcm_new = au1xpsc_pcm_new,
.pcm_free = au1xpsc_pcm_free_dma_buffers,
};
-EXPORT_SYMBOL_GPL(au1xpsc_soc_platform);
static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev)
{
+ struct au1xpsc_audio_dmadata *dmadata;
struct resource *r;
int ret;
- if (au1xpsc_audio_pcmdma[PCM_TX] || au1xpsc_audio_pcmdma[PCM_RX])
- return -EBUSY;
-
- /* TX DMA */
- au1xpsc_audio_pcmdma[PCM_TX]
- = kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
- if (!au1xpsc_audio_pcmdma[PCM_TX])
+ dmadata = kzalloc(2 * sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
+ if (!dmadata)
return -ENOMEM;
r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
@@ -372,47 +351,33 @@
ret = -ENODEV;
goto out1;
}
- (au1xpsc_audio_pcmdma[PCM_TX])->ddma_id = r->start;
+ dmadata[PCM_TX].ddma_id = r->start;
/* RX DMA */
- au1xpsc_audio_pcmdma[PCM_RX]
- = kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
- if (!au1xpsc_audio_pcmdma[PCM_RX])
- return -ENOMEM;
-
r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!r) {
ret = -ENODEV;
- goto out2;
+ goto out1;
}
- (au1xpsc_audio_pcmdma[PCM_RX])->ddma_id = r->start;
+ dmadata[PCM_RX].ddma_id = r->start;
- ret = snd_soc_register_platform(&au1xpsc_soc_platform);
+ platform_set_drvdata(pdev, dmadata);
+
+ ret = snd_soc_register_platform(&pdev->dev, &au1xpsc_soc_platform);
if (!ret)
return ret;
-out2:
- kfree(au1xpsc_audio_pcmdma[PCM_RX]);
- au1xpsc_audio_pcmdma[PCM_RX] = NULL;
out1:
- kfree(au1xpsc_audio_pcmdma[PCM_TX]);
- au1xpsc_audio_pcmdma[PCM_TX] = NULL;
+ kfree(dmadata);
return ret;
}
static int __devexit au1xpsc_pcm_drvremove(struct platform_device *pdev)
{
- int i;
+ struct au1xpsc_audio_dmadata *dmadata = platform_get_drvdata(pdev);
- snd_soc_unregister_platform(&au1xpsc_soc_platform);
-
- for (i = 0; i < 2; i++) {
- if (au1xpsc_audio_pcmdma[i]) {
- au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[i]);
- kfree(au1xpsc_audio_pcmdma[i]);
- au1xpsc_audio_pcmdma[i] = NULL;
- }
- }
+ snd_soc_unregister_platform(&pdev->dev);
+ kfree(dmadata);
return 0;
}
@@ -428,8 +393,6 @@
static int __init au1xpsc_audio_dbdma_load(void)
{
- au1xpsc_audio_pcmdma[PCM_TX] = NULL;
- au1xpsc_audio_pcmdma[PCM_RX] = NULL;
return platform_driver_register(&au1xpsc_pcm_driver);
}
@@ -467,7 +430,7 @@
res[1].start = res[1].end = id[1];
res[0].flags = res[1].flags = IORESOURCE_DMA;
- pd = platform_device_alloc("au1xpsc-pcm", -1);
+ pd = platform_device_alloc("au1xpsc-pcm", pdev->id);
if (!pd)
goto out;
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c
index d14a5a9..d0db66f 100644
--- a/sound/soc/au1x/psc-ac97.c
+++ b/sound/soc/au1x/psc-ac97.c
@@ -10,9 +10,6 @@
*
* Au1xxx-PSC AC97 glue.
*
- * NOTE: all of these drivers can only work with a SINGLE instance
- * of a PSC. Multiple independent audio devices are impossible
- * with ASoC v1.
*/
#include <linux/init.h>
@@ -56,12 +53,29 @@
/* instance data. There can be only one, MacLeod!!!! */
static struct au1xpsc_audio_data *au1xpsc_ac97_workdata;
+#if 0
+
+/* this could theoretically work, but ac97->bus->card->private_data can be NULL
+ * when snd_ac97_mixer() is called; I don't know if the rest further down the
+ * chain are always valid either.
+ */
+static inline struct au1xpsc_audio_data *ac97_to_pscdata(struct snd_ac97 *x)
+{
+ struct snd_soc_card *c = x->bus->card->private_data;
+ return snd_soc_dai_get_drvdata(c->rtd->cpu_dai);
+}
+
+#else
+
+#define ac97_to_pscdata(x) au1xpsc_ac97_workdata
+
+#endif
+
/* AC97 controller reads codec register */
static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97,
unsigned short reg)
{
- /* FIXME */
- struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+ struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
unsigned short retry, tmo;
unsigned long data;
@@ -102,8 +116,7 @@
static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
unsigned short val)
{
- /* FIXME */
- struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+ struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
unsigned int tmo, retry;
au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata));
@@ -134,8 +147,7 @@
/* AC97 controller asserts a warm reset */
static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97)
{
- /* FIXME */
- struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+ struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
au_writel(PSC_AC97RST_SNC, AC97_RST(pscdata));
au_sync();
@@ -146,8 +158,7 @@
static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97)
{
- /* FIXME */
- struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+ struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
int i;
/* disable PSC during cold reset */
@@ -202,8 +213,7 @@
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- /* FIXME */
- struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+ struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
unsigned long r, ro, stat;
int chans, t, stype = SUBSTREAM_TYPE(substream);
@@ -283,8 +293,7 @@
static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
- /* FIXME */
- struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+ struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
int ret, stype = SUBSTREAM_TYPE(substream);
ret = 0;
@@ -315,27 +324,19 @@
return ret;
}
-static int au1xpsc_ac97_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int au1xpsc_ac97_probe(struct snd_soc_dai *dai)
{
return au1xpsc_ac97_workdata ? 0 : -ENODEV;
}
-static void au1xpsc_ac97_remove(struct platform_device *pdev,
- struct snd_soc_dai *dai)
-{
-}
-
static struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
.trigger = au1xpsc_ac97_trigger,
.hw_params = au1xpsc_ac97_hw_params,
};
-struct snd_soc_dai au1xpsc_ac97_dai = {
- .name = "au1xpsc_ac97",
+static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
.ac97_control = 1,
.probe = au1xpsc_ac97_probe,
- .remove = au1xpsc_ac97_remove,
.playback = {
.rates = AC97_RATES,
.formats = AC97_FMTS,
@@ -350,7 +351,6 @@
},
.ops = &au1xpsc_ac97_dai_ops,
};
-EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai);
static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
{
@@ -359,9 +359,6 @@
unsigned long sel;
struct au1xpsc_audio_data *wd;
- if (au1xpsc_ac97_workdata)
- return -EBUSY;
-
wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
if (!wd)
return -ENOMEM;
@@ -395,18 +392,24 @@
au_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(wd));
au_sync();
- ret = snd_soc_register_dai(&au1xpsc_ac97_dai);
+ /* name the DAI like this device instance ("au1xpsc-ac97.PSCINDEX") */
+ memcpy(&wd->dai_drv, &au1xpsc_ac97_dai_template,
+ sizeof(struct snd_soc_dai_driver));
+ wd->dai_drv.name = dev_name(&pdev->dev);
+
+ platform_set_drvdata(pdev, wd);
+
+ ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
if (ret)
goto out1;
wd->dmapd = au1xpsc_pcm_add(pdev);
if (wd->dmapd) {
- platform_set_drvdata(pdev, wd);
- au1xpsc_ac97_workdata = wd; /* MDEV */
+ au1xpsc_ac97_workdata = wd;
return 0;
}
- snd_soc_unregister_dai(&au1xpsc_ac97_dai);
+ snd_soc_unregister_dai(&pdev->dev);
out1:
release_mem_region(r->start, resource_size(r));
out0:
@@ -422,7 +425,7 @@
if (wd->dmapd)
au1xpsc_pcm_destroy(wd->dmapd);
- snd_soc_unregister_dai(&au1xpsc_ac97_dai);
+ snd_soc_unregister_dai(&pdev->dev);
/* disable PSC completely */
au_writel(0, AC97_CFG(wd));
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c
index 6083fe7..fca0912 100644
--- a/sound/soc/au1x/psc-i2s.c
+++ b/sound/soc/au1x/psc-i2s.c
@@ -10,9 +10,6 @@
*
* Au1xxx-PSC I2S glue.
*
- * NOTE: all of these drivers can only work with a SINGLE instance
- * of a PSC. Multiple independent audio devices are impossible
- * with ASoC v1.
* NOTE: so far only PSC slave mode (bit- and frameclock) is supported.
*/
@@ -54,13 +51,10 @@
((stype) == PCM_TX ? PSC_I2SPCR_TC : PSC_I2SPCR_RC)
-/* instance data. There can be only one, MacLeod!!!! */
-static struct au1xpsc_audio_data *au1xpsc_i2s_workdata;
-
static int au1xpsc_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
- struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
+ struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(cpu_dai);
unsigned long ct;
int ret;
@@ -120,7 +114,7 @@
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
+ struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
int cfgbits;
unsigned long stat;
@@ -245,7 +239,7 @@
static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
+ struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
int ret, stype = SUBSTREAM_TYPE(substream);
switch (cmd) {
@@ -263,27 +257,13 @@
return ret;
}
-static int au1xpsc_i2s_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
-{
- return au1xpsc_i2s_workdata ? 0 : -ENODEV;
-}
-
-static void au1xpsc_i2s_remove(struct platform_device *pdev,
- struct snd_soc_dai *dai)
-{
-}
-
static struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = {
.trigger = au1xpsc_i2s_trigger,
.hw_params = au1xpsc_i2s_hw_params,
.set_fmt = au1xpsc_i2s_set_fmt,
};
-struct snd_soc_dai au1xpsc_i2s_dai = {
- .name = "au1xpsc_i2s",
- .probe = au1xpsc_i2s_probe,
- .remove = au1xpsc_i2s_remove,
+static const struct snd_soc_dai_driver au1xpsc_i2s_dai_template = {
.playback = {
.rates = AU1XPSC_I2S_RATES,
.formats = AU1XPSC_I2S_FMTS,
@@ -298,7 +278,6 @@
},
.ops = &au1xpsc_i2s_dai_ops,
};
-EXPORT_SYMBOL(au1xpsc_i2s_dai);
static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
{
@@ -307,9 +286,6 @@
int ret;
struct au1xpsc_audio_data *wd;
- if (au1xpsc_i2s_workdata)
- return -EBUSY;
-
wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
if (!wd)
return -ENOMEM;
@@ -346,19 +322,23 @@
* time out.
*/
- ret = snd_soc_register_dai(&au1xpsc_i2s_dai);
+ /* name the DAI like this device instance ("au1xpsc-i2s.PSCINDEX") */
+ memcpy(&wd->dai_drv, &au1xpsc_i2s_dai_template,
+ sizeof(struct snd_soc_dai_driver));
+ wd->dai_drv.name = dev_name(&pdev->dev);
+
+ platform_set_drvdata(pdev, wd);
+
+ ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
if (ret)
goto out1;
/* finally add the DMA device for this PSC */
wd->dmapd = au1xpsc_pcm_add(pdev);
- if (wd->dmapd) {
- platform_set_drvdata(pdev, wd);
- au1xpsc_i2s_workdata = wd;
+ if (wd->dmapd)
return 0;
- }
- snd_soc_unregister_dai(&au1xpsc_i2s_dai);
+ snd_soc_unregister_dai(&pdev->dev);
out1:
release_mem_region(r->start, resource_size(r));
out0:
@@ -374,7 +354,7 @@
if (wd->dmapd)
au1xpsc_pcm_destroy(wd->dmapd);
- snd_soc_unregister_dai(&au1xpsc_i2s_dai);
+ snd_soc_unregister_dai(&pdev->dev);
au_writel(0, I2S_CFG(wd));
au_sync();
@@ -385,8 +365,6 @@
release_mem_region(r->start, resource_size(r));
kfree(wd);
- au1xpsc_i2s_workdata = NULL; /* MDEV */
-
return 0;
}
@@ -446,7 +424,6 @@
static int __init au1xpsc_i2s_load(void)
{
- au1xpsc_i2s_workdata = NULL;
return platform_driver_register(&au1xpsc_i2s_driver);
}
diff --git a/sound/soc/au1x/psc.h b/sound/soc/au1x/psc.h
index 093775d..b30eadd 100644
--- a/sound/soc/au1x/psc.h
+++ b/sound/soc/au1x/psc.h
@@ -8,19 +8,11 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * NOTE: all of these drivers can only work with a SINGLE instance
- * of a PSC. Multiple independent audio devices are impossible
- * with ASoC v1.
*/
#ifndef _AU1X_PCM_H
#define _AU1X_PCM_H
-extern struct snd_soc_dai au1xpsc_ac97_dai;
-extern struct snd_soc_dai au1xpsc_i2s_dai;
-extern struct snd_soc_platform au1xpsc_soc_platform;
-extern struct snd_ac97_bus_ops soc_ac97_ops;
-
/* DBDMA helpers */
extern struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev);
extern void au1xpsc_pcm_destroy(struct platform_device *dmapd);
@@ -31,6 +23,8 @@
unsigned long cfg;
unsigned long rate;
+ struct snd_soc_dai_driver dai_drv;
+
unsigned long pm[2];
struct mutex lock;
struct platform_device *dmapd;
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c
index 5e7aacf..5a2fd8a 100644
--- a/sound/soc/blackfin/bf5xx-ac97-pcm.c
+++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c
@@ -422,14 +422,14 @@
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto out;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
@@ -439,25 +439,44 @@
return ret;
}
-struct snd_soc_platform bf5xx_ac97_soc_platform = {
- .name = "bf5xx-audio",
- .pcm_ops = &bf5xx_pcm_ac97_ops,
+static struct snd_soc_platform_driver bf5xx_ac97_soc_platform = {
+ .ops = &bf5xx_pcm_ac97_ops,
.pcm_new = bf5xx_pcm_ac97_new,
.pcm_free = bf5xx_pcm_free_dma_buffers,
};
-EXPORT_SYMBOL_GPL(bf5xx_ac97_soc_platform);
-static int __init bfin_ac97_init(void)
+static int __devinit bf5xx_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&bf5xx_ac97_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &bf5xx_ac97_soc_platform);
}
-module_init(bfin_ac97_init);
-static void __exit bfin_ac97_exit(void)
+static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&bf5xx_ac97_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
}
-module_exit(bfin_ac97_exit);
+
+static struct platform_driver bf5xx_pcm_driver = {
+ .driver = {
+ .name = "bf5xx-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = bf5xx_soc_platform_probe,
+ .remove = __devexit_p(bf5xx_soc_platform_remove),
+};
+
+static int __init snd_bf5xx_pcm_init(void)
+{
+ return platform_driver_register(&bf5xx_pcm_driver);
+}
+module_init(snd_bf5xx_pcm_init);
+
+static void __exit snd_bf5xx_pcm_exit(void)
+{
+ platform_driver_unregister(&bf5xx_pcm_driver);
+}
+module_exit(snd_bf5xx_pcm_exit);
MODULE_AUTHOR("Cliff Cai");
MODULE_DESCRIPTION("ADI Blackfin AC97 PCM DMA module");
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.h b/sound/soc/blackfin/bf5xx-ac97-pcm.h
index 350125a..d324d58 100644
--- a/sound/soc/blackfin/bf5xx-ac97-pcm.h
+++ b/sound/soc/blackfin/bf5xx-ac97-pcm.h
@@ -23,7 +23,4 @@
u32 frm;
};
-/* platform data */
-extern struct snd_soc_platform bf5xx_ac97_soc_platform;
-
#endif
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c
index c0eba51..c5f856e 100644
--- a/sound/soc/blackfin/bf5xx-ac97.c
+++ b/sound/soc/blackfin/bf5xx-ac97.c
@@ -255,7 +255,7 @@
#ifdef CONFIG_PM
static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
{
- struct sport_device *sport = dai->private_data;
+ struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
pr_debug("%s : sport %d\n", __func__, dai->id);
if (!dai->active)
@@ -270,7 +270,7 @@
static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
{
int ret;
- struct sport_device *sport = dai->private_data;
+ struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
pr_debug("%s : sport %d\n", __func__, dai->id);
if (!dai->active)
@@ -306,8 +306,7 @@
#define bf5xx_ac97_resume NULL
#endif
-static int bf5xx_ac97_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int bf5xx_ac97_probe(struct snd_soc_dai *dai)
{
int ret = 0;
cmd_count = (int *)get_zeroed_page(GFP_KERNEL);
@@ -379,8 +378,7 @@
return ret;
}
-static void bf5xx_ac97_remove(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int bf5xx_ac97_remove(struct snd_soc_dai *dai)
{
free_page((unsigned long)cmd_count);
cmd_count = NULL;
@@ -388,11 +386,10 @@
#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
#endif
+ return 0;
}
-struct snd_soc_dai bfin_ac97_dai = {
- .name = "bf5xx-ac97",
- .id = 0,
+struct snd_soc_dai_driver bfin_ac97_dai = {
.ac97_control = 1,
.probe = bf5xx_ac97_probe,
.remove = bf5xx_ac97_remove,
@@ -417,18 +414,40 @@
};
EXPORT_SYMBOL_GPL(bfin_ac97_dai);
+static __devinit int asoc_bfin_ac97_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai);
+}
+
+static int __devexit asoc_bfin_ac97_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dai(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver asoc_bfin_ac97_driver = {
+ .driver = {
+ .name = "bfin-ac97",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = asoc_bfin_ac97_probe,
+ .remove = __devexit_p(asoc_bfin_ac97_remove),
+};
+
static int __init bfin_ac97_init(void)
{
- return snd_soc_register_dai(&bfin_ac97_dai);
+ return platform_driver_register(&asoc_bfin_ac97_driver);
}
module_init(bfin_ac97_init);
static void __exit bfin_ac97_exit(void)
{
- snd_soc_unregister_dai(&bfin_ac97_dai);
+ platform_driver_unregister(&asoc_bfin_ac97_driver);
}
module_exit(bfin_ac97_exit);
+
MODULE_AUTHOR("Roy Huang");
MODULE_DESCRIPTION("AC97 driver for ADI Blackfin");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/bf5xx-ac97.h b/sound/soc/blackfin/bf5xx-ac97.h
index a1f97dd..15c635e 100644
--- a/sound/soc/blackfin/bf5xx-ac97.h
+++ b/sound/soc/blackfin/bf5xx-ac97.h
@@ -50,8 +50,6 @@
#define TAG_PCM_SR 0x0080
#define TAG_PCM_LFE 0x0040
-extern struct snd_soc_dai bfin_ac97_dai;
-
void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src, \
size_t count, unsigned int chan_mask);
diff --git a/sound/soc/blackfin/bf5xx-ad1836.c b/sound/soc/blackfin/bf5xx-ad1836.c
index 0f45a3f..2394bff 100644
--- a/sound/soc/blackfin/bf5xx-ad1836.c
+++ b/sound/soc/blackfin/bf5xx-ad1836.c
@@ -40,9 +40,9 @@
static int bf5xx_ad1836_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- cpu_dai->private_data = sport_handle;
+ snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
return 0;
}
@@ -50,8 +50,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
unsigned int channel_map[] = {0, 4, 1, 5, 2, 6, 3, 7};
int ret = 0;
/* set cpu DAI configuration */
@@ -83,23 +83,19 @@
static struct snd_soc_dai_link bf5xx_ad1836_dai = {
.name = "ad1836",
.stream_name = "AD1836",
- .cpu_dai = &bf5xx_tdm_dai,
- .codec_dai = &ad1836_dai,
+ .cpu_dai_name = "bf5xx-tdm",
+ .codec_dai_name = "ad1836-hifi",
+ .platform_name = "bf5xx-tdm-pcm-audio",
+ .codec_name = "ad1836-codec.0",
.ops = &bf5xx_ad1836_ops,
};
static struct snd_soc_card bf5xx_ad1836 = {
.name = "bf5xx_ad1836",
- .platform = &bf5xx_tdm_soc_platform,
.dai_link = &bf5xx_ad1836_dai,
.num_links = 1,
};
-static struct snd_soc_device bf5xx_ad1836_snd_devdata = {
- .card = &bf5xx_ad1836,
- .codec_dev = &soc_codec_dev_ad1836,
-};
-
static struct platform_device *bfxx_ad1836_snd_device;
static int __init bf5xx_ad1836_init(void)
@@ -110,8 +106,7 @@
if (!bfxx_ad1836_snd_device)
return -ENOMEM;
- platform_set_drvdata(bfxx_ad1836_snd_device, &bf5xx_ad1836_snd_devdata);
- bf5xx_ad1836_snd_devdata.dev = &bfxx_ad1836_snd_device->dev;
+ platform_set_drvdata(bfxx_ad1836_snd_device, &bf5xx_ad1836);
ret = platform_device_add(bfxx_ad1836_snd_device);
if (ret)
diff --git a/sound/soc/blackfin/bf5xx-ad193x.c b/sound/soc/blackfin/bf5xx-ad193x.c
index b8c9060..e4a6253 100644
--- a/sound/soc/blackfin/bf5xx-ad193x.c
+++ b/sound/soc/blackfin/bf5xx-ad193x.c
@@ -49,9 +49,9 @@
static int bf5xx_ad193x_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- cpu_dai->private_data = sport_handle;
+ snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
return 0;
}
@@ -59,8 +59,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
unsigned int channel_map[] = {0, 1, 2, 3, 4, 5, 6, 7};
int ret = 0;
/* set cpu DAI configuration */
@@ -97,23 +97,19 @@
static struct snd_soc_dai_link bf5xx_ad193x_dai = {
.name = "ad193x",
.stream_name = "AD193X",
- .cpu_dai = &bf5xx_tdm_dai,
- .codec_dai = &ad193x_dai,
+ .cpu_dai_name = "bf5xx-tdm",
+ .codec_dai_name ="ad193x-hifi",
+ .platform_name = "bf5xx-tdm-pcm-audio",
+ .codec_name = "ad193x-codec.5",
.ops = &bf5xx_ad193x_ops,
};
static struct snd_soc_card bf5xx_ad193x = {
.name = "bf5xx_ad193x",
- .platform = &bf5xx_tdm_soc_platform,
.dai_link = &bf5xx_ad193x_dai,
.num_links = 1,
};
-static struct snd_soc_device bf5xx_ad193x_snd_devdata = {
- .card = &bf5xx_ad193x,
- .codec_dev = &soc_codec_dev_ad193x,
-};
-
static struct platform_device *bfxx_ad193x_snd_device;
static int __init bf5xx_ad193x_init(void)
@@ -124,8 +120,7 @@
if (!bfxx_ad193x_snd_device)
return -ENOMEM;
- platform_set_drvdata(bfxx_ad193x_snd_device, &bf5xx_ad193x_snd_devdata);
- bf5xx_ad193x_snd_devdata.dev = &bfxx_ad193x_snd_device->dev;
+ platform_set_drvdata(bfxx_ad193x_snd_device, &bf5xx_ad193x);
ret = platform_device_add(bfxx_ad193x_snd_device);
if (ret)
diff --git a/sound/soc/blackfin/bf5xx-ad1980.c b/sound/soc/blackfin/bf5xx-ad1980.c
index 92f7c32..d57c9c9 100644
--- a/sound/soc/blackfin/bf5xx-ad1980.c
+++ b/sound/soc/blackfin/bf5xx-ad1980.c
@@ -56,10 +56,10 @@
static int bf5xx_board_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
pr_debug("%s enter\n", __func__);
- cpu_dai->private_data = sport_handle;
+ snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
return 0;
}
@@ -70,23 +70,19 @@
static struct snd_soc_dai_link bf5xx_board_dai = {
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &bfin_ac97_dai,
- .codec_dai = &ad1980_dai,
+ .cpu_dai_name = "bfin-ac97",
+ .codec_dai_name = "ad1980-hifi",
+ .platform_name = "bfin-pcm-audio",
+ .codec_name = "ad1980-codec",
.ops = &bf5xx_board_ops,
};
static struct snd_soc_card bf5xx_board = {
.name = "bf5xx-board",
- .platform = &bf5xx_ac97_soc_platform,
.dai_link = &bf5xx_board_dai,
.num_links = 1,
};
-static struct snd_soc_device bf5xx_board_snd_devdata = {
- .card = &bf5xx_board,
- .codec_dev = &soc_codec_dev_ad1980,
-};
-
static struct platform_device *bf5xx_board_snd_device;
static int __init bf5xx_board_init(void)
@@ -97,8 +93,7 @@
if (!bf5xx_board_snd_device)
return -ENOMEM;
- platform_set_drvdata(bf5xx_board_snd_device, &bf5xx_board_snd_devdata);
- bf5xx_board_snd_devdata.dev = &bf5xx_board_snd_device->dev;
+ platform_set_drvdata(bf5xx_board_snd_device, &bf5xx_board);
ret = platform_device_add(bf5xx_board_snd_device);
if (ret)
diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c
index 9825b71..900ced5 100644
--- a/sound/soc/blackfin/bf5xx-ad73311.c
+++ b/sound/soc/blackfin/bf5xx-ad73311.c
@@ -47,7 +47,6 @@
#include "../codecs/ad73311.h"
#include "bf5xx-sport.h"
#include "bf5xx-i2s-pcm.h"
-#include "bf5xx-i2s.h"
#if CONFIG_SND_BF5XX_SPORT_NUM == 0
#define bfin_write_SPORT_TCR1 bfin_write_SPORT0_TCR1
@@ -150,10 +149,10 @@
static int bf5xx_ad73311_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
pr_debug("%s enter\n", __func__);
- cpu_dai->private_data = sport_handle;
+ snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
return 0;
}
@@ -161,7 +160,7 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret = 0;
pr_debug("%s rate %d format %x\n", __func__, params_rate(params),
@@ -185,24 +184,20 @@
static struct snd_soc_dai_link bf5xx_ad73311_dai = {
.name = "ad73311",
.stream_name = "AD73311",
- .cpu_dai = &bf5xx_i2s_dai,
- .codec_dai = &ad73311_dai,
+ .cpu_dai_name = "bf5xx-i2s",
+ .codec_dai_name = "ad73311-hifi",
+ .platform_name = "bfin-pcm-audio",
+ .codec_name = "ad73311-codec",
.ops = &bf5xx_ad73311_ops,
};
static struct snd_soc_card bf5xx_ad73311 = {
.name = "bf5xx_ad73311",
- .platform = &bf5xx_i2s_soc_platform,
.probe = bf5xx_probe,
.dai_link = &bf5xx_ad73311_dai,
.num_links = 1,
};
-static struct snd_soc_device bf5xx_ad73311_snd_devdata = {
- .card = &bf5xx_ad73311,
- .codec_dev = &soc_codec_dev_ad73311,
-};
-
static struct platform_device *bf5xx_ad73311_snd_device;
static int __init bf5xx_ad73311_init(void)
@@ -214,8 +209,7 @@
if (!bf5xx_ad73311_snd_device)
return -ENOMEM;
- platform_set_drvdata(bf5xx_ad73311_snd_device, &bf5xx_ad73311_snd_devdata);
- bf5xx_ad73311_snd_devdata.dev = &bf5xx_ad73311_snd_device->dev;
+ platform_set_drvdata(bf5xx_ad73311_snd_device, &bf5xx_ad73311);
ret = platform_device_add(bf5xx_ad73311_snd_device);
if (ret)
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c
index 1d2a1ad..890a0dc 100644
--- a/sound/soc/blackfin/bf5xx-i2s-pcm.c
+++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c
@@ -40,7 +40,6 @@
#include <asm/dma.h>
#include "bf5xx-i2s-pcm.h"
-#include "bf5xx-i2s.h"
#include "bf5xx-sport.h"
static void bf5xx_dma_irq(void *data)
@@ -257,14 +256,14 @@
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto out;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
@@ -274,25 +273,44 @@
return ret;
}
-struct snd_soc_platform bf5xx_i2s_soc_platform = {
- .name = "bf5xx-audio",
- .pcm_ops = &bf5xx_pcm_i2s_ops,
+static struct snd_soc_platform_driver bf5xx_i2s_soc_platform = {
+ .ops = &bf5xx_pcm_i2s_ops,
.pcm_new = bf5xx_pcm_i2s_new,
.pcm_free = bf5xx_pcm_free_dma_buffers,
};
-EXPORT_SYMBOL_GPL(bf5xx_i2s_soc_platform);
-static int __init bfin_i2s_init(void)
+static int __devinit bfin_i2s_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&bf5xx_i2s_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &bf5xx_i2s_soc_platform);
}
-module_init(bfin_i2s_init);
-static void __exit bfin_i2s_exit(void)
+static int __devexit bfin_i2s_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&bf5xx_i2s_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
}
-module_exit(bfin_i2s_exit);
+
+static struct platform_driver bfin_i2s_pcm_driver = {
+ .driver = {
+ .name = "bfin-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = bfin_i2s_soc_platform_probe,
+ .remove = __devexit_p(bfin_i2s_soc_platform_remove),
+};
+
+static int __init snd_bfin_i2s_pcm_init(void)
+{
+ return platform_driver_register(&bfin_i2s_pcm_driver);
+}
+module_init(snd_bfin_i2s_pcm_init);
+
+static void __exit snd_bfin_i2s_pcm_exit(void)
+{
+ platform_driver_unregister(&bfin_i2s_pcm_driver);
+}
+module_exit(snd_bfin_i2s_pcm_exit);
MODULE_AUTHOR("Cliff Cai");
MODULE_DESCRIPTION("ADI Blackfin I2S PCM DMA module");
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.h b/sound/soc/blackfin/bf5xx-i2s-pcm.h
index 4d4609a..0c2c5a6 100644
--- a/sound/soc/blackfin/bf5xx-i2s-pcm.h
+++ b/sound/soc/blackfin/bf5xx-i2s-pcm.h
@@ -23,7 +23,4 @@
u32 frm;
};
-/* platform data */
-extern struct snd_soc_platform bf5xx_i2s_soc_platform;
-
#endif
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c
index 3e6ada0..d453b1e 100644
--- a/sound/soc/blackfin/bf5xx-i2s.c
+++ b/sound/soc/blackfin/bf5xx-i2s.c
@@ -42,7 +42,6 @@
#include <linux/gpio.h>
#include "bf5xx-sport.h"
-#include "bf5xx-i2s.h"
struct bf5xx_i2s_port {
u16 tcr1;
@@ -195,8 +194,7 @@
bf5xx_i2s.configured = 0;
}
-static int bf5xx_i2s_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int bf5xx_i2s_probe(struct snd_soc_dai *dai)
{
pr_debug("%s enter\n", __func__);
if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
@@ -215,11 +213,11 @@
return 0;
}
-static void bf5xx_i2s_remove(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int bf5xx_i2s_remove(struct snd_soc_dai *dai)
{
pr_debug("%s enter\n", __func__);
peripheral_free_list(&sport_req[sport_num][0]);
+ return 0;
}
#ifdef CONFIG_PM
@@ -228,9 +226,9 @@
pr_debug("%s : sport %d\n", __func__, dai->id);
- if (dai->capture.active)
+ if (dai->capture_active)
sport_rx_stop(sport_handle);
- if (dai->playback.active)
+ if (dai->playback_active)
sport_tx_stop(sport_handle);
return 0;
}
@@ -277,9 +275,7 @@
.set_fmt = bf5xx_i2s_set_dai_fmt,
};
-struct snd_soc_dai bf5xx_i2s_dai = {
- .name = "bf5xx-i2s",
- .id = 0,
+static struct snd_soc_dai_driver bf5xx_i2s_dai = {
.probe = bf5xx_i2s_probe,
.remove = bf5xx_i2s_remove,
.suspend = bf5xx_i2s_suspend,
@@ -296,18 +292,39 @@
.formats = BF5XX_I2S_FORMATS,},
.ops = &bf5xx_i2s_dai_ops,
};
-EXPORT_SYMBOL_GPL(bf5xx_i2s_dai);
+
+static int bfin_i2s_drv_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai);
+}
+
+static int __devexit bfin_i2s_drv_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dai(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver bfin_i2s_driver = {
+ .probe = bfin_i2s_drv_probe,
+ .remove = __devexit_p(bfin_i2s_drv_remove),
+
+ .driver = {
+ .name = "bf5xx-i2s",
+ .owner = THIS_MODULE,
+ },
+};
static int __init bfin_i2s_init(void)
{
- return snd_soc_register_dai(&bf5xx_i2s_dai);
+ return platform_driver_register(&bfin_i2s_driver);
}
-module_init(bfin_i2s_init);
static void __exit bfin_i2s_exit(void)
{
- snd_soc_unregister_dai(&bf5xx_i2s_dai);
+ platform_driver_unregister(&bfin_i2s_driver);
}
+
+module_init(bfin_i2s_init);
module_exit(bfin_i2s_exit);
/* Module information */
diff --git a/sound/soc/blackfin/bf5xx-i2s.h b/sound/soc/blackfin/bf5xx-i2s.h
deleted file mode 100644
index 264ecdc..0000000
--- a/sound/soc/blackfin/bf5xx-i2s.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * sound/soc/blackfin/bf5xx-i2s.h
- *
- * 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 _BF5XX_I2S_H
-#define _BF5XX_I2S_H
-
-extern struct snd_soc_dai bf5xx_i2s_dai;
-
-#endif
diff --git a/sound/soc/blackfin/bf5xx-ssm2602.c b/sound/soc/blackfin/bf5xx-ssm2602.c
index 3a00fa4..36f2769 100644
--- a/sound/soc/blackfin/bf5xx-ssm2602.c
+++ b/sound/soc/blackfin/bf5xx-ssm2602.c
@@ -42,17 +42,16 @@
#include "../codecs/ssm2602.h"
#include "bf5xx-sport.h"
#include "bf5xx-i2s-pcm.h"
-#include "bf5xx-i2s.h"
static struct snd_soc_card bf5xx_ssm2602;
static int bf5xx_ssm2602_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
pr_debug("%s enter\n", __func__);
- cpu_dai->private_data = sport_handle;
+ snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
return 0;
}
@@ -60,8 +59,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int clk = 0;
int ret = 0;
@@ -118,36 +117,19 @@
static struct snd_soc_dai_link bf5xx_ssm2602_dai = {
.name = "ssm2602",
.stream_name = "SSM2602",
- .cpu_dai = &bf5xx_i2s_dai,
- .codec_dai = &ssm2602_dai,
+ .cpu_dai_name = "bf5xx-i2s",
+ .codec_dai_name = "ssm2602-hifi",
+ .platform_name = "bf5xx-pcm-audio",
+ .codec_name = "ssm2602-codec.0-0x1b",
.ops = &bf5xx_ssm2602_ops,
};
-/*
- * SSM2602 2 wire address is determined by CSB
- * state during powerup.
- * low = 0x1a
- * high = 0x1b
- */
-
-static struct ssm2602_setup_data bf5xx_ssm2602_setup = {
- .i2c_bus = 0,
- .i2c_address = 0x1b,
-};
-
static struct snd_soc_card bf5xx_ssm2602 = {
.name = "bf5xx_ssm2602",
- .platform = &bf5xx_i2s_soc_platform,
.dai_link = &bf5xx_ssm2602_dai,
.num_links = 1,
};
-static struct snd_soc_device bf5xx_ssm2602_snd_devdata = {
- .card = &bf5xx_ssm2602,
- .codec_dev = &soc_codec_dev_ssm2602,
- .codec_data = &bf5xx_ssm2602_setup,
-};
-
static struct platform_device *bf5xx_ssm2602_snd_device;
static int __init bf5xx_ssm2602_init(void)
@@ -159,9 +141,7 @@
if (!bf5xx_ssm2602_snd_device)
return -ENOMEM;
- platform_set_drvdata(bf5xx_ssm2602_snd_device,
- &bf5xx_ssm2602_snd_devdata);
- bf5xx_ssm2602_snd_devdata.dev = &bf5xx_ssm2602_snd_device->dev;
+ platform_set_drvdata(bf5xx_ssm2602_snd_device, &bf5xx_ssm2602);
ret = platform_device_add(bf5xx_ssm2602_snd_device);
if (ret)
diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.c b/sound/soc/blackfin/bf5xx-tdm-pcm.c
index 6bac1ac..74cf759 100644
--- a/sound/soc/blackfin/bf5xx-tdm-pcm.c
+++ b/sound/soc/blackfin/bf5xx-tdm-pcm.c
@@ -290,14 +290,14 @@
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto out;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
@@ -307,25 +307,44 @@
return ret;
}
-struct snd_soc_platform bf5xx_tdm_soc_platform = {
- .name = "bf5xx-audio",
- .pcm_ops = &bf5xx_pcm_tdm_ops,
+static struct snd_soc_platform_driver bf5xx_tdm_soc_platform = {
+ .ops = &bf5xx_pcm_tdm_ops,
.pcm_new = bf5xx_pcm_tdm_new,
.pcm_free = bf5xx_pcm_free_dma_buffers,
};
-EXPORT_SYMBOL_GPL(bf5xx_tdm_soc_platform);
-static int __init bfin_pcm_tdm_init(void)
+static int __devinit bf5xx_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&bf5xx_tdm_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &bf5xx_tdm_soc_platform);
}
-module_init(bfin_pcm_tdm_init);
-static void __exit bfin_pcm_tdm_exit(void)
+static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&bf5xx_tdm_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
}
-module_exit(bfin_pcm_tdm_exit);
+
+static struct platform_driver bfin_tdm_driver = {
+ .driver = {
+ .name = "bf5xx-tdm-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = bf5xx_soc_platform_probe,
+ .remove = __devexit_p(bf5xx_soc_platform_remove),
+};
+
+static int __init snd_bfin_tdm_init(void)
+{
+ return platform_driver_register(&bfin_tdm_driver);
+}
+module_init(snd_bfin_tdm_init);
+
+static void __exit snd_bfin_tdm_exit(void)
+{
+ platform_driver_unregister(&bfin_tdm_driver);
+}
+module_exit(snd_bfin_tdm_exit);
MODULE_AUTHOR("Barry Song");
MODULE_DESCRIPTION("ADI Blackfin TDM PCM DMA module");
diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.h b/sound/soc/blackfin/bf5xx-tdm-pcm.h
index ddc5047..7f8cc01 100644
--- a/sound/soc/blackfin/bf5xx-tdm-pcm.h
+++ b/sound/soc/blackfin/bf5xx-tdm-pcm.h
@@ -15,7 +15,4 @@
char *name; /* stream identifier */
};
-/* platform data */
-extern struct snd_soc_platform bf5xx_tdm_soc_platform;
-
#endif
diff --git a/sound/soc/blackfin/bf5xx-tdm.c b/sound/soc/blackfin/bf5xx-tdm.c
index 24c1426..1251239 100644
--- a/sound/soc/blackfin/bf5xx-tdm.c
+++ b/sound/soc/blackfin/bf5xx-tdm.c
@@ -214,9 +214,9 @@
if (!dai->active)
return 0;
- if (dai->capture.active)
+ if (dai->capture_active)
sport_rx_stop(sport);
- if (dai->playback.active)
+ if (dai->playback_active)
sport_tx_stop(sport);
return 0;
}
@@ -224,7 +224,7 @@
static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
{
int ret;
- struct sport_device *sport = dai->private_data;
+ struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
if (!dai->active)
return 0;
@@ -262,9 +262,7 @@
.set_channel_map = bf5xx_tdm_set_channel_map,
};
-struct snd_soc_dai bf5xx_tdm_dai = {
- .name = "bf5xx-tdm",
- .id = 0,
+static struct snd_soc_dai_driver bf5xx_tdm_dai = {
.suspend = bf5xx_tdm_suspend,
.resume = bf5xx_tdm_resume,
.playback = {
@@ -279,7 +277,6 @@
.formats = SNDRV_PCM_FMTBIT_S32_LE,},
.ops = &bf5xx_tdm_dai_ops,
};
-EXPORT_SYMBOL_GPL(bf5xx_tdm_dai);
static int __devinit bfin_tdm_probe(struct platform_device *pdev)
{
@@ -320,7 +317,7 @@
goto sport_config_err;
}
- ret = snd_soc_register_dai(&bf5xx_tdm_dai);
+ ret = snd_soc_register_dai(&pdev->dev, &bf5xx_tdm_dai);
if (ret) {
pr_err("Failed to register DAI: %d\n", ret);
goto sport_config_err;
@@ -337,7 +334,7 @@
static int __devexit bfin_tdm_remove(struct platform_device *pdev)
{
peripheral_free_list(&sport_req[sport_num][0]);
- snd_soc_unregister_dai(&bf5xx_tdm_dai);
+ snd_soc_unregister_dai(&pdev->dev);
return 0;
}
diff --git a/sound/soc/blackfin/bf5xx-tdm.h b/sound/soc/blackfin/bf5xx-tdm.h
index 04189a1..e986a3e 100644
--- a/sound/soc/blackfin/bf5xx-tdm.h
+++ b/sound/soc/blackfin/bf5xx-tdm.h
@@ -20,6 +20,4 @@
int configured;
};
-extern struct snd_soc_dai bf5xx_tdm_dai;
-
#endif
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
new file mode 100644
index 0000000..01d19e9
--- /dev/null
+++ b/sound/soc/codecs/88pm860x-codec.c
@@ -0,0 +1,1486 @@
+/*
+ * 88pm860x-codec.c -- 88PM860x ALSA SoC Audio Driver
+ *
+ * Copyright 2010 Marvell International Ltd.
+ * Author: Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/88pm860x.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+#include <sound/jack.h>
+
+#include "88pm860x-codec.h"
+
+#define MAX_NAME_LEN 20
+#define REG_CACHE_SIZE 0x40
+#define REG_CACHE_BASE 0xb0
+
+/* Status Register 1 (0x01) */
+#define REG_STATUS_1 0x01
+#define MIC_STATUS (1 << 7)
+#define HOOK_STATUS (1 << 6)
+#define HEADSET_STATUS (1 << 5)
+
+/* Mic Detection Register (0x37) */
+#define REG_MIC_DET 0x37
+#define CONTINUOUS_POLLING (3 << 1)
+#define EN_MIC_DET (1 << 0)
+#define MICDET_MASK 0x07
+
+/* Headset Detection Register (0x38) */
+#define REG_HS_DET 0x38
+#define EN_HS_DET (1 << 0)
+
+/* Misc2 Register (0x42) */
+#define REG_MISC2 0x42
+#define AUDIO_PLL (1 << 5)
+#define AUDIO_SECTION_RESET (1 << 4)
+#define AUDIO_SECTION_ON (1 << 3)
+
+/* PCM Interface Register 2 (0xb1) */
+#define PCM_INF2_BCLK (1 << 6) /* Bit clock polarity */
+#define PCM_INF2_FS (1 << 5) /* Frame Sync polarity */
+#define PCM_INF2_MASTER (1 << 4) /* Master / Slave */
+#define PCM_INF2_18WL (1 << 3) /* 18 / 16 bits */
+#define PCM_GENERAL_I2S 0
+#define PCM_EXACT_I2S 1
+#define PCM_LEFT_I2S 2
+#define PCM_RIGHT_I2S 3
+#define PCM_SHORT_FS 4
+#define PCM_LONG_FS 5
+#define PCM_MODE_MASK 7
+
+/* I2S Interface Register 4 (0xbe) */
+#define I2S_EQU_BYP (1 << 6)
+
+/* DAC Offset Register (0xcb) */
+#define DAC_MUTE (1 << 7)
+#define MUTE_LEFT (1 << 6)
+#define MUTE_RIGHT (1 << 2)
+
+/* ADC Analog Register 1 (0xd0) */
+#define REG_ADC_ANA_1 0xd0
+#define MIC1BIAS_MASK 0x60
+
+/* Earpiece/Speaker Control Register 2 (0xda) */
+#define REG_EAR2 0xda
+#define RSYNC_CHANGE (1 << 2)
+
+/* Audio Supplies Register 2 (0xdc) */
+#define REG_SUPPLIES2 0xdc
+#define LDO15_READY (1 << 4)
+#define LDO15_EN (1 << 3)
+#define CPUMP_READY (1 << 2)
+#define CPUMP_EN (1 << 1)
+#define AUDIO_EN (1 << 0)
+#define SUPPLY_MASK (LDO15_EN | CPUMP_EN | AUDIO_EN)
+
+/* Audio Enable Register 1 (0xdd) */
+#define ADC_MOD_RIGHT (1 << 1)
+#define ADC_MOD_LEFT (1 << 0)
+
+/* Audio Enable Register 2 (0xde) */
+#define ADC_LEFT (1 << 5)
+#define ADC_RIGHT (1 << 4)
+
+/* DAC Enable Register 2 (0xe1) */
+#define DAC_LEFT (1 << 5)
+#define DAC_RIGHT (1 << 4)
+#define MODULATOR (1 << 3)
+
+/* Shorts Register (0xeb) */
+#define REG_SHORTS 0xeb
+#define CLR_SHORT_LO2 (1 << 7)
+#define SHORT_LO2 (1 << 6)
+#define CLR_SHORT_LO1 (1 << 5)
+#define SHORT_LO1 (1 << 4)
+#define CLR_SHORT_HS2 (1 << 3)
+#define SHORT_HS2 (1 << 2)
+#define CLR_SHORT_HS1 (1 << 1)
+#define SHORT_HS1 (1 << 0)
+
+/*
+ * This widget should be just after DAC & PGA in DAPM power-on sequence and
+ * before DAC & PGA in DAPM power-off sequence.
+ */
+#define PM860X_DAPM_OUTPUT(wname, wevent) \
+{ .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \
+ .shift = 0, .invert = 0, .kcontrols = NULL, \
+ .num_kcontrols = 0, .event = wevent, \
+ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD, }
+
+struct pm860x_det {
+ struct snd_soc_jack *hp_jack;
+ struct snd_soc_jack *mic_jack;
+ int hp_det;
+ int mic_det;
+ int hook_det;
+ int hs_shrt;
+ int lo_shrt;
+};
+
+struct pm860x_priv {
+ unsigned int sysclk;
+ unsigned int pcmclk;
+ unsigned int dir;
+ unsigned int filter;
+ struct snd_soc_codec *codec;
+ struct i2c_client *i2c;
+ struct pm860x_chip *chip;
+ struct pm860x_det det;
+
+ int irq[4];
+ unsigned char name[4][MAX_NAME_LEN];
+ unsigned char reg_cache[REG_CACHE_SIZE];
+};
+
+/* -9450dB to 0dB in 150dB steps ( mute instead of -9450dB) */
+static const DECLARE_TLV_DB_SCALE(dpga_tlv, -9450, 150, 1);
+
+/* -9dB to 0db in 3dB steps */
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -900, 300, 0);
+
+/* {-23, -17, -13.5, -11, -9, -6, -3, 0}dB */
+static const unsigned int mic_tlv[] = {
+ TLV_DB_RANGE_HEAD(5),
+ 0, 0, TLV_DB_SCALE_ITEM(-2300, 0, 0),
+ 1, 1, TLV_DB_SCALE_ITEM(-1700, 0, 0),
+ 2, 2, TLV_DB_SCALE_ITEM(-1350, 0, 0),
+ 3, 3, TLV_DB_SCALE_ITEM(-1100, 0, 0),
+ 4, 7, TLV_DB_SCALE_ITEM(-900, 300, 0),
+};
+
+/* {0, 0, 0, -6, 0, 6, 12, 18}dB */
+static const unsigned int aux_tlv[] = {
+ TLV_DB_RANGE_HEAD(2),
+ 0, 2, TLV_DB_SCALE_ITEM(0, 0, 0),
+ 3, 7, TLV_DB_SCALE_ITEM(-600, 600, 0),
+};
+
+/* {-16, -13, -10, -7, -5.2, -3,3, -2.2, 0}dB, mute instead of -16dB */
+static const unsigned int out_tlv[] = {
+ TLV_DB_RANGE_HEAD(4),
+ 0, 3, TLV_DB_SCALE_ITEM(-1600, 300, 1),
+ 4, 4, TLV_DB_SCALE_ITEM(-520, 0, 0),
+ 5, 5, TLV_DB_SCALE_ITEM(-330, 0, 0),
+ 6, 7, TLV_DB_SCALE_ITEM(-220, 220, 0),
+};
+
+static const unsigned int st_tlv[] = {
+ TLV_DB_RANGE_HEAD(8),
+ 0, 1, TLV_DB_SCALE_ITEM(-12041, 602, 0),
+ 2, 3, TLV_DB_SCALE_ITEM(-11087, 250, 0),
+ 4, 5, TLV_DB_SCALE_ITEM(-10643, 158, 0),
+ 6, 7, TLV_DB_SCALE_ITEM(-10351, 116, 0),
+ 8, 9, TLV_DB_SCALE_ITEM(-10133, 92, 0),
+ 10, 13, TLV_DB_SCALE_ITEM(-9958, 70, 0),
+ 14, 17, TLV_DB_SCALE_ITEM(-9689, 53, 0),
+ 18, 271, TLV_DB_SCALE_ITEM(-9484, 37, 0),
+};
+
+/* Sidetone Gain = M * 2^(-5-N) */
+struct st_gain {
+ unsigned int db;
+ unsigned int m;
+ unsigned int n;
+};
+
+static struct st_gain st_table[] = {
+ {-12041, 1, 15}, {-11439, 1, 14}, {-11087, 3, 15}, {-10837, 1, 13},
+ {-10643, 5, 15}, {-10485, 3, 14}, {-10351, 7, 15}, {-10235, 1, 12},
+ {-10133, 9, 15}, {-10041, 5, 14}, { -9958, 11, 15}, { -9883, 3, 13},
+ { -9813, 13, 15}, { -9749, 7, 14}, { -9689, 15, 15}, { -9633, 1, 11},
+ { -9580, 17, 15}, { -9531, 9, 14}, { -9484, 19, 15}, { -9439, 5, 13},
+ { -9397, 21, 15}, { -9356, 11, 14}, { -9318, 23, 15}, { -9281, 3, 12},
+ { -9245, 25, 15}, { -9211, 13, 14}, { -9178, 27, 15}, { -9147, 7, 13},
+ { -9116, 29, 15}, { -9087, 15, 14}, { -9058, 31, 15}, { -9031, 1, 10},
+ { -8978, 17, 14}, { -8929, 9, 13}, { -8882, 19, 14}, { -8837, 5, 12},
+ { -8795, 21, 14}, { -8754, 11, 13}, { -8716, 23, 14}, { -8679, 3, 11},
+ { -8643, 25, 14}, { -8609, 13, 13}, { -8576, 27, 14}, { -8545, 7, 12},
+ { -8514, 29, 14}, { -8485, 15, 13}, { -8456, 31, 14}, { -8429, 1, 9},
+ { -8376, 17, 13}, { -8327, 9, 12}, { -8280, 19, 13}, { -8235, 5, 11},
+ { -8193, 21, 13}, { -8152, 11, 12}, { -8114, 23, 13}, { -8077, 3, 10},
+ { -8041, 25, 13}, { -8007, 13, 12}, { -7974, 27, 13}, { -7943, 7, 11},
+ { -7912, 29, 13}, { -7883, 15, 12}, { -7854, 31, 13}, { -7827, 1, 8},
+ { -7774, 17, 12}, { -7724, 9, 11}, { -7678, 19, 12}, { -7633, 5, 10},
+ { -7591, 21, 12}, { -7550, 11, 11}, { -7512, 23, 12}, { -7475, 3, 9},
+ { -7439, 25, 12}, { -7405, 13, 11}, { -7372, 27, 12}, { -7341, 7, 10},
+ { -7310, 29, 12}, { -7281, 15, 11}, { -7252, 31, 12}, { -7225, 1, 7},
+ { -7172, 17, 11}, { -7122, 9, 10}, { -7075, 19, 11}, { -7031, 5, 9},
+ { -6989, 21, 11}, { -6948, 11, 10}, { -6910, 23, 11}, { -6873, 3, 8},
+ { -6837, 25, 11}, { -6803, 13, 10}, { -6770, 27, 11}, { -6739, 7, 9},
+ { -6708, 29, 11}, { -6679, 15, 10}, { -6650, 31, 11}, { -6623, 1, 6},
+ { -6570, 17, 10}, { -6520, 9, 9}, { -6473, 19, 10}, { -6429, 5, 8},
+ { -6386, 21, 10}, { -6346, 11, 9}, { -6307, 23, 10}, { -6270, 3, 7},
+ { -6235, 25, 10}, { -6201, 13, 9}, { -6168, 27, 10}, { -6137, 7, 8},
+ { -6106, 29, 10}, { -6077, 15, 9}, { -6048, 31, 10}, { -6021, 1, 5},
+ { -5968, 17, 9}, { -5918, 9, 8}, { -5871, 19, 9}, { -5827, 5, 7},
+ { -5784, 21, 9}, { -5744, 11, 8}, { -5705, 23, 9}, { -5668, 3, 6},
+ { -5633, 25, 9}, { -5599, 13, 8}, { -5566, 27, 9}, { -5535, 7, 7},
+ { -5504, 29, 9}, { -5475, 15, 8}, { -5446, 31, 9}, { -5419, 1, 4},
+ { -5366, 17, 8}, { -5316, 9, 7}, { -5269, 19, 8}, { -5225, 5, 6},
+ { -5182, 21, 8}, { -5142, 11, 7}, { -5103, 23, 8}, { -5066, 3, 5},
+ { -5031, 25, 8}, { -4997, 13, 7}, { -4964, 27, 8}, { -4932, 7, 6},
+ { -4902, 29, 8}, { -4873, 15, 7}, { -4844, 31, 8}, { -4816, 1, 3},
+ { -4764, 17, 7}, { -4714, 9, 6}, { -4667, 19, 7}, { -4623, 5, 5},
+ { -4580, 21, 7}, { -4540, 11, 6}, { -4501, 23, 7}, { -4464, 3, 4},
+ { -4429, 25, 7}, { -4395, 13, 6}, { -4362, 27, 7}, { -4330, 7, 5},
+ { -4300, 29, 7}, { -4270, 15, 6}, { -4242, 31, 7}, { -4214, 1, 2},
+ { -4162, 17, 6}, { -4112, 9, 5}, { -4065, 19, 6}, { -4021, 5, 4},
+ { -3978, 21, 6}, { -3938, 11, 5}, { -3899, 23, 6}, { -3862, 3, 3},
+ { -3827, 25, 6}, { -3793, 13, 5}, { -3760, 27, 6}, { -3728, 7, 4},
+ { -3698, 29, 6}, { -3668, 15, 5}, { -3640, 31, 6}, { -3612, 1, 1},
+ { -3560, 17, 5}, { -3510, 9, 4}, { -3463, 19, 5}, { -3419, 5, 3},
+ { -3376, 21, 5}, { -3336, 11, 4}, { -3297, 23, 5}, { -3260, 3, 2},
+ { -3225, 25, 5}, { -3191, 13, 4}, { -3158, 27, 5}, { -3126, 7, 3},
+ { -3096, 29, 5}, { -3066, 15, 4}, { -3038, 31, 5}, { -3010, 1, 0},
+ { -2958, 17, 4}, { -2908, 9, 3}, { -2861, 19, 4}, { -2816, 5, 2},
+ { -2774, 21, 4}, { -2734, 11, 3}, { -2695, 23, 4}, { -2658, 3, 1},
+ { -2623, 25, 4}, { -2589, 13, 3}, { -2556, 27, 4}, { -2524, 7, 2},
+ { -2494, 29, 4}, { -2464, 15, 3}, { -2436, 31, 4}, { -2408, 2, 0},
+ { -2356, 17, 3}, { -2306, 9, 2}, { -2259, 19, 3}, { -2214, 5, 1},
+ { -2172, 21, 3}, { -2132, 11, 2}, { -2093, 23, 3}, { -2056, 3, 0},
+ { -2021, 25, 3}, { -1987, 13, 2}, { -1954, 27, 3}, { -1922, 7, 1},
+ { -1892, 29, 3}, { -1862, 15, 2}, { -1834, 31, 3}, { -1806, 4, 0},
+ { -1754, 17, 2}, { -1704, 9, 1}, { -1657, 19, 2}, { -1612, 5, 0},
+ { -1570, 21, 2}, { -1530, 11, 1}, { -1491, 23, 2}, { -1454, 6, 0},
+ { -1419, 25, 2}, { -1384, 13, 1}, { -1352, 27, 2}, { -1320, 7, 0},
+ { -1290, 29, 2}, { -1260, 15, 1}, { -1232, 31, 2}, { -1204, 8, 0},
+ { -1151, 17, 1}, { -1102, 9, 0}, { -1055, 19, 1}, { -1010, 10, 0},
+ { -968, 21, 1}, { -928, 11, 0}, { -889, 23, 1}, { -852, 12, 0},
+ { -816, 25, 1}, { -782, 13, 0}, { -750, 27, 1}, { -718, 14, 0},
+ { -688, 29, 1}, { -658, 15, 0}, { -630, 31, 1}, { -602, 16, 0},
+ { -549, 17, 0}, { -500, 18, 0}, { -453, 19, 0}, { -408, 20, 0},
+ { -366, 21, 0}, { -325, 22, 0}, { -287, 23, 0}, { -250, 24, 0},
+ { -214, 25, 0}, { -180, 26, 0}, { -148, 27, 0}, { -116, 28, 0},
+ { -86, 29, 0}, { -56, 30, 0}, { -28, 31, 0}, { 0, 0, 0},
+};
+
+static int pm860x_volatile(unsigned int reg)
+{
+ BUG_ON(reg >= REG_CACHE_SIZE);
+
+ switch (reg) {
+ case PM860X_AUDIO_SUPPLIES_2:
+ return 1;
+ }
+
+ return 0;
+}
+
+static unsigned int pm860x_read_reg_cache(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ unsigned char *cache = codec->reg_cache;
+
+ BUG_ON(reg >= REG_CACHE_SIZE);
+
+ if (pm860x_volatile(reg))
+ return cache[reg];
+
+ reg += REG_CACHE_BASE;
+
+ return pm860x_reg_read(codec->control_data, reg);
+}
+
+static int pm860x_write_reg_cache(struct snd_soc_codec *codec,
+ unsigned int reg, unsigned int value)
+{
+ unsigned char *cache = codec->reg_cache;
+
+ BUG_ON(reg >= REG_CACHE_SIZE);
+
+ if (!pm860x_volatile(reg))
+ cache[reg] = (unsigned char)value;
+
+ reg += REG_CACHE_BASE;
+
+ return pm860x_reg_write(codec->control_data, reg, value);
+}
+
+static int snd_soc_get_volsw_2r_st(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned int reg = mc->reg;
+ unsigned int reg2 = mc->rreg;
+ int val[2], val2[2], i;
+
+ val[0] = snd_soc_read(codec, reg) & 0x3f;
+ val[1] = (snd_soc_read(codec, PM860X_SIDETONE_SHIFT) >> 4) & 0xf;
+ val2[0] = snd_soc_read(codec, reg2) & 0x3f;
+ val2[1] = (snd_soc_read(codec, PM860X_SIDETONE_SHIFT)) & 0xf;
+
+ for (i = 0; i < ARRAY_SIZE(st_table); i++) {
+ if ((st_table[i].m == val[0]) && (st_table[i].n == val[1]))
+ ucontrol->value.integer.value[0] = i;
+ if ((st_table[i].m == val2[0]) && (st_table[i].n == val2[1]))
+ ucontrol->value.integer.value[1] = i;
+ }
+ return 0;
+}
+
+static int snd_soc_put_volsw_2r_st(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned int reg = mc->reg;
+ unsigned int reg2 = mc->rreg;
+ int err;
+ unsigned int val, val2;
+
+ val = ucontrol->value.integer.value[0];
+ val2 = ucontrol->value.integer.value[1];
+
+ err = snd_soc_update_bits(codec, reg, 0x3f, st_table[val].m);
+ if (err < 0)
+ return err;
+ err = snd_soc_update_bits(codec, PM860X_SIDETONE_SHIFT, 0xf0,
+ st_table[val].n << 4);
+ if (err < 0)
+ return err;
+
+ err = snd_soc_update_bits(codec, reg2, 0x3f, st_table[val2].m);
+ if (err < 0)
+ return err;
+ err = snd_soc_update_bits(codec, PM860X_SIDETONE_SHIFT, 0x0f,
+ st_table[val2].n);
+ return err;
+}
+
+static int snd_soc_get_volsw_2r_out(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned int reg = mc->reg;
+ unsigned int reg2 = mc->rreg;
+ unsigned int shift = mc->shift;
+ int max = mc->max, val, val2;
+ unsigned int mask = (1 << fls(max)) - 1;
+
+ val = snd_soc_read(codec, reg) >> shift;
+ val2 = snd_soc_read(codec, reg2) >> shift;
+ ucontrol->value.integer.value[0] = (max - val) & mask;
+ ucontrol->value.integer.value[1] = (max - val2) & mask;
+
+ return 0;
+}
+
+static int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned int reg = mc->reg;
+ unsigned int reg2 = mc->rreg;
+ unsigned int shift = mc->shift;
+ int max = mc->max;
+ unsigned int mask = (1 << fls(max)) - 1;
+ int err;
+ unsigned int val, val2, val_mask;
+
+ val_mask = mask << shift;
+ val = ((max - ucontrol->value.integer.value[0]) & mask);
+ val2 = ((max - ucontrol->value.integer.value[1]) & mask);
+
+ val = val << shift;
+ val2 = val2 << shift;
+
+ err = snd_soc_update_bits(codec, reg, val_mask, val);
+ if (err < 0)
+ return err;
+
+ err = snd_soc_update_bits(codec, reg2, val_mask, val2);
+ return err;
+}
+
+/* DAPM Widget Events */
+/*
+ * A lot registers are belong to RSYNC domain. It requires enabling RSYNC bit
+ * after updating these registers. Otherwise, these updated registers won't
+ * be effective.
+ */
+static int pm860x_rsync_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+
+ /*
+ * In order to avoid current on the load, mute power-on and power-off
+ * should be transients.
+ * Unmute by DAC_MUTE. It should be unmuted when DAPM sequence is
+ * finished.
+ */
+ snd_soc_update_bits(codec, PM860X_DAC_OFFSET, DAC_MUTE, 0);
+ snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
+ RSYNC_CHANGE, RSYNC_CHANGE);
+ return 0;
+}
+
+static int pm860x_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ unsigned int dac = 0;
+ int data;
+
+ if (!strcmp(w->name, "Left DAC"))
+ dac = DAC_LEFT;
+ if (!strcmp(w->name, "Right DAC"))
+ dac = DAC_RIGHT;
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (dac) {
+ /* Auto mute in power-on sequence. */
+ dac |= MODULATOR;
+ snd_soc_update_bits(codec, PM860X_DAC_OFFSET,
+ DAC_MUTE, DAC_MUTE);
+ snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
+ RSYNC_CHANGE, RSYNC_CHANGE);
+ /* update dac */
+ snd_soc_update_bits(codec, PM860X_DAC_EN_2,
+ dac, dac);
+ }
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ if (dac) {
+ /* Auto mute in power-off sequence. */
+ snd_soc_update_bits(codec, PM860X_DAC_OFFSET,
+ DAC_MUTE, DAC_MUTE);
+ snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
+ RSYNC_CHANGE, RSYNC_CHANGE);
+ /* update dac */
+ data = snd_soc_read(codec, PM860X_DAC_EN_2);
+ data &= ~dac;
+ if (!(data & (DAC_LEFT | DAC_RIGHT)))
+ data &= ~MODULATOR;
+ snd_soc_write(codec, PM860X_DAC_EN_2, data);
+ }
+ break;
+ }
+ return 0;
+}
+
+static const char *pm860x_opamp_texts[] = {"-50%", "-25%", "0%", "75%"};
+
+static const char *pm860x_pa_texts[] = {"-33%", "0%", "33%", "66%"};
+
+static const struct soc_enum pm860x_hs1_opamp_enum =
+ SOC_ENUM_SINGLE(PM860X_HS1_CTRL, 5, 4, pm860x_opamp_texts);
+
+static const struct soc_enum pm860x_hs2_opamp_enum =
+ SOC_ENUM_SINGLE(PM860X_HS2_CTRL, 5, 4, pm860x_opamp_texts);
+
+static const struct soc_enum pm860x_hs1_pa_enum =
+ SOC_ENUM_SINGLE(PM860X_HS1_CTRL, 3, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_hs2_pa_enum =
+ SOC_ENUM_SINGLE(PM860X_HS2_CTRL, 3, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_lo1_opamp_enum =
+ SOC_ENUM_SINGLE(PM860X_LO1_CTRL, 5, 4, pm860x_opamp_texts);
+
+static const struct soc_enum pm860x_lo2_opamp_enum =
+ SOC_ENUM_SINGLE(PM860X_LO2_CTRL, 5, 4, pm860x_opamp_texts);
+
+static const struct soc_enum pm860x_lo1_pa_enum =
+ SOC_ENUM_SINGLE(PM860X_LO1_CTRL, 3, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_lo2_pa_enum =
+ SOC_ENUM_SINGLE(PM860X_LO2_CTRL, 3, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_spk_pa_enum =
+ SOC_ENUM_SINGLE(PM860X_EAR_CTRL_1, 5, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_ear_pa_enum =
+ SOC_ENUM_SINGLE(PM860X_EAR_CTRL_2, 0, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_spk_ear_opamp_enum =
+ SOC_ENUM_SINGLE(PM860X_EAR_CTRL_1, 3, 4, pm860x_opamp_texts);
+
+static const struct snd_kcontrol_new pm860x_snd_controls[] = {
+ SOC_DOUBLE_R_TLV("ADC Capture Volume", PM860X_ADC_ANA_2,
+ PM860X_ADC_ANA_3, 6, 3, 0, adc_tlv),
+ SOC_DOUBLE_TLV("AUX Capture Volume", PM860X_ADC_ANA_3, 0, 3, 7, 0,
+ aux_tlv),
+ SOC_SINGLE_TLV("MIC1 Capture Volume", PM860X_ADC_ANA_2, 0, 7, 0,
+ mic_tlv),
+ SOC_SINGLE_TLV("MIC3 Capture Volume", PM860X_ADC_ANA_2, 3, 7, 0,
+ mic_tlv),
+ SOC_DOUBLE_R_EXT_TLV("Sidetone Volume", PM860X_SIDETONE_L_GAIN,
+ PM860X_SIDETONE_R_GAIN, 0, ARRAY_SIZE(st_table)-1,
+ 0, snd_soc_get_volsw_2r_st,
+ snd_soc_put_volsw_2r_st, st_tlv),
+ SOC_SINGLE_TLV("Speaker Playback Volume", PM860X_EAR_CTRL_1,
+ 0, 7, 0, out_tlv),
+ SOC_DOUBLE_R_TLV("Line Playback Volume", PM860X_LO1_CTRL,
+ PM860X_LO2_CTRL, 0, 7, 0, out_tlv),
+ SOC_DOUBLE_R_TLV("Headset Playback Volume", PM860X_HS1_CTRL,
+ PM860X_HS2_CTRL, 0, 7, 0, out_tlv),
+ SOC_DOUBLE_R_EXT_TLV("Hifi Left Playback Volume",
+ PM860X_HIFIL_GAIN_LEFT,
+ PM860X_HIFIL_GAIN_RIGHT, 0, 63, 0,
+ snd_soc_get_volsw_2r_out,
+ snd_soc_put_volsw_2r_out, dpga_tlv),
+ SOC_DOUBLE_R_EXT_TLV("Hifi Right Playback Volume",
+ PM860X_HIFIR_GAIN_LEFT,
+ PM860X_HIFIR_GAIN_RIGHT, 0, 63, 0,
+ snd_soc_get_volsw_2r_out,
+ snd_soc_put_volsw_2r_out, dpga_tlv),
+ SOC_DOUBLE_R_EXT_TLV("Lofi Playback Volume", PM860X_LOFI_GAIN_LEFT,
+ PM860X_LOFI_GAIN_RIGHT, 0, 63, 0,
+ snd_soc_get_volsw_2r_out,
+ snd_soc_put_volsw_2r_out, dpga_tlv),
+ SOC_ENUM("Headset1 Operational Amplifier Current",
+ pm860x_hs1_opamp_enum),
+ SOC_ENUM("Headset2 Operational Amplifier Current",
+ pm860x_hs2_opamp_enum),
+ SOC_ENUM("Headset1 Amplifier Current", pm860x_hs1_pa_enum),
+ SOC_ENUM("Headset2 Amplifier Current", pm860x_hs2_pa_enum),
+ SOC_ENUM("Lineout1 Operational Amplifier Current",
+ pm860x_lo1_opamp_enum),
+ SOC_ENUM("Lineout2 Operational Amplifier Current",
+ pm860x_lo2_opamp_enum),
+ SOC_ENUM("Lineout1 Amplifier Current", pm860x_lo1_pa_enum),
+ SOC_ENUM("Lineout2 Amplifier Current", pm860x_lo2_pa_enum),
+ SOC_ENUM("Speaker Operational Amplifier Current",
+ pm860x_spk_ear_opamp_enum),
+ SOC_ENUM("Speaker Amplifier Current", pm860x_spk_pa_enum),
+ SOC_ENUM("Earpiece Amplifier Current", pm860x_ear_pa_enum),
+};
+
+/*
+ * DAPM Controls
+ */
+
+/* PCM Switch / PCM Interface */
+static const struct snd_kcontrol_new pcm_switch_controls =
+ SOC_DAPM_SINGLE("Switch", PM860X_ADC_EN_2, 0, 1, 0);
+
+/* AUX1 Switch */
+static const struct snd_kcontrol_new aux1_switch_controls =
+ SOC_DAPM_SINGLE("Switch", PM860X_ANA_TO_ANA, 4, 1, 0);
+
+/* AUX2 Switch */
+static const struct snd_kcontrol_new aux2_switch_controls =
+ SOC_DAPM_SINGLE("Switch", PM860X_ANA_TO_ANA, 5, 1, 0);
+
+/* Left Ex. PA Switch */
+static const struct snd_kcontrol_new lepa_switch_controls =
+ SOC_DAPM_SINGLE("Switch", PM860X_DAC_EN_2, 2, 1, 0);
+
+/* Right Ex. PA Switch */
+static const struct snd_kcontrol_new repa_switch_controls =
+ SOC_DAPM_SINGLE("Switch", PM860X_DAC_EN_2, 1, 1, 0);
+
+/* PCM Mux / Mux7 */
+static const char *aif1_text[] = {
+ "PCM L", "PCM R",
+};
+
+static const struct soc_enum aif1_enum =
+ SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 6, 2, aif1_text);
+
+static const struct snd_kcontrol_new aif1_mux =
+ SOC_DAPM_ENUM("PCM Mux", aif1_enum);
+
+/* I2S Mux / Mux9 */
+static const char *i2s_din_text[] = {
+ "DIN", "DIN1",
+};
+
+static const struct soc_enum i2s_din_enum =
+ SOC_ENUM_SINGLE(PM860X_I2S_IFACE_3, 1, 2, i2s_din_text);
+
+static const struct snd_kcontrol_new i2s_din_mux =
+ SOC_DAPM_ENUM("I2S DIN Mux", i2s_din_enum);
+
+/* I2S Mic Mux / Mux8 */
+static const char *i2s_mic_text[] = {
+ "Ex PA", "ADC",
+};
+
+static const struct soc_enum i2s_mic_enum =
+ SOC_ENUM_SINGLE(PM860X_I2S_IFACE_3, 4, 2, i2s_mic_text);
+
+static const struct snd_kcontrol_new i2s_mic_mux =
+ SOC_DAPM_ENUM("I2S Mic Mux", i2s_mic_enum);
+
+/* ADCL Mux / Mux2 */
+static const char *adcl_text[] = {
+ "ADCR", "ADCL",
+};
+
+static const struct soc_enum adcl_enum =
+ SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 4, 2, adcl_text);
+
+static const struct snd_kcontrol_new adcl_mux =
+ SOC_DAPM_ENUM("ADC Left Mux", adcl_enum);
+
+/* ADCR Mux / Mux3 */
+static const char *adcr_text[] = {
+ "ADCL", "ADCR",
+};
+
+static const struct soc_enum adcr_enum =
+ SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 2, 2, adcr_text);
+
+static const struct snd_kcontrol_new adcr_mux =
+ SOC_DAPM_ENUM("ADC Right Mux", adcr_enum);
+
+/* ADCR EC Mux / Mux6 */
+static const char *adcr_ec_text[] = {
+ "ADCR", "EC",
+};
+
+static const struct soc_enum adcr_ec_enum =
+ SOC_ENUM_SINGLE(PM860X_ADC_EN_2, 3, 2, adcr_ec_text);
+
+static const struct snd_kcontrol_new adcr_ec_mux =
+ SOC_DAPM_ENUM("ADCR EC Mux", adcr_ec_enum);
+
+/* EC Mux / Mux4 */
+static const char *ec_text[] = {
+ "Left", "Right", "Left + Right",
+};
+
+static const struct soc_enum ec_enum =
+ SOC_ENUM_SINGLE(PM860X_EC_PATH, 1, 3, ec_text);
+
+static const struct snd_kcontrol_new ec_mux =
+ SOC_DAPM_ENUM("EC Mux", ec_enum);
+
+static const char *dac_text[] = {
+ "No input", "Right", "Left", "No input",
+};
+
+/* DAC Headset 1 Mux / Mux10 */
+static const struct soc_enum dac_hs1_enum =
+ SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 0, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_hs1_mux =
+ SOC_DAPM_ENUM("DAC HS1 Mux", dac_hs1_enum);
+
+/* DAC Headset 2 Mux / Mux11 */
+static const struct soc_enum dac_hs2_enum =
+ SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 2, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_hs2_mux =
+ SOC_DAPM_ENUM("DAC HS2 Mux", dac_hs2_enum);
+
+/* DAC Lineout 1 Mux / Mux12 */
+static const struct soc_enum dac_lo1_enum =
+ SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 4, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_lo1_mux =
+ SOC_DAPM_ENUM("DAC LO1 Mux", dac_lo1_enum);
+
+/* DAC Lineout 2 Mux / Mux13 */
+static const struct soc_enum dac_lo2_enum =
+ SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 6, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_lo2_mux =
+ SOC_DAPM_ENUM("DAC LO2 Mux", dac_lo2_enum);
+
+/* DAC Spearker Earphone Mux / Mux14 */
+static const struct soc_enum dac_spk_ear_enum =
+ SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_2, 0, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_spk_ear_mux =
+ SOC_DAPM_ENUM("DAC SP Mux", dac_spk_ear_enum);
+
+/* Headset 1 Mux / Mux15 */
+static const char *in_text[] = {
+ "Digital", "Analog",
+};
+
+static const struct soc_enum hs1_enum =
+ SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 0, 2, in_text);
+
+static const struct snd_kcontrol_new hs1_mux =
+ SOC_DAPM_ENUM("Headset1 Mux", hs1_enum);
+
+/* Headset 2 Mux / Mux16 */
+static const struct soc_enum hs2_enum =
+ SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 1, 2, in_text);
+
+static const struct snd_kcontrol_new hs2_mux =
+ SOC_DAPM_ENUM("Headset2 Mux", hs2_enum);
+
+/* Lineout 1 Mux / Mux17 */
+static const struct soc_enum lo1_enum =
+ SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 2, 2, in_text);
+
+static const struct snd_kcontrol_new lo1_mux =
+ SOC_DAPM_ENUM("Lineout1 Mux", lo1_enum);
+
+/* Lineout 2 Mux / Mux18 */
+static const struct soc_enum lo2_enum =
+ SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 3, 2, in_text);
+
+static const struct snd_kcontrol_new lo2_mux =
+ SOC_DAPM_ENUM("Lineout2 Mux", lo2_enum);
+
+/* Speaker Earpiece Demux */
+static const char *spk_text[] = {
+ "Earpiece", "Speaker",
+};
+
+static const struct soc_enum spk_enum =
+ SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 6, 2, spk_text);
+
+static const struct snd_kcontrol_new spk_demux =
+ SOC_DAPM_ENUM("Speaker Earpiece Demux", spk_enum);
+
+/* MIC Mux / Mux1 */
+static const char *mic_text[] = {
+ "Mic 1", "Mic 2",
+};
+
+static const struct soc_enum mic_enum =
+ SOC_ENUM_SINGLE(PM860X_ADC_ANA_4, 4, 2, mic_text);
+
+static const struct snd_kcontrol_new mic_mux =
+ SOC_DAPM_ENUM("MIC Mux", mic_enum);
+
+static const struct snd_soc_dapm_widget pm860x_dapm_widgets[] = {
+ SND_SOC_DAPM_AIF_IN("PCM SDI", "PCM Playback", 0,
+ PM860X_ADC_EN_2, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PCM SDO", "PCM Capture", 0,
+ PM860X_PCM_IFACE_3, 1, 1),
+
+
+ SND_SOC_DAPM_AIF_IN("I2S DIN", "I2S Playback", 0,
+ PM860X_DAC_EN_2, 0, 0),
+ SND_SOC_DAPM_AIF_IN("I2S DIN1", "I2S Playback", 0,
+ PM860X_DAC_EN_2, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("I2S DOUT", "I2S Capture", 0,
+ PM860X_I2S_IFACE_3, 5, 1),
+ SND_SOC_DAPM_MUX("I2S Mic Mux", SND_SOC_NOPM, 0, 0, &i2s_mic_mux),
+ SND_SOC_DAPM_MUX("ADC Left Mux", SND_SOC_NOPM, 0, 0, &adcl_mux),
+ SND_SOC_DAPM_MUX("ADC Right Mux", SND_SOC_NOPM, 0, 0, &adcr_mux),
+ SND_SOC_DAPM_MUX("EC Mux", SND_SOC_NOPM, 0, 0, &ec_mux),
+ SND_SOC_DAPM_MUX("ADCR EC Mux", SND_SOC_NOPM, 0, 0, &adcr_ec_mux),
+ SND_SOC_DAPM_SWITCH("Left EPA", SND_SOC_NOPM, 0, 0,
+ &lepa_switch_controls),
+ SND_SOC_DAPM_SWITCH("Right EPA", SND_SOC_NOPM, 0, 0,
+ &repa_switch_controls),
+
+ SND_SOC_DAPM_REG(snd_soc_dapm_supply, "Left ADC MOD", PM860X_ADC_EN_1,
+ 0, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_supply, "Right ADC MOD", PM860X_ADC_EN_1,
+ 1, 1, 1, 0),
+ SND_SOC_DAPM_ADC("Left ADC", NULL, PM860X_ADC_EN_2, 5, 0),
+ SND_SOC_DAPM_ADC("Right ADC", NULL, PM860X_ADC_EN_2, 4, 0),
+
+ SND_SOC_DAPM_SWITCH("AUX1 Switch", SND_SOC_NOPM, 0, 0,
+ &aux1_switch_controls),
+ SND_SOC_DAPM_SWITCH("AUX2 Switch", SND_SOC_NOPM, 0, 0,
+ &aux2_switch_controls),
+
+ SND_SOC_DAPM_MUX("MIC Mux", SND_SOC_NOPM, 0, 0, &mic_mux),
+ SND_SOC_DAPM_MICBIAS("Mic1 Bias", PM860X_ADC_ANA_1, 2, 0),
+ SND_SOC_DAPM_MICBIAS("Mic3 Bias", PM860X_ADC_ANA_1, 7, 0),
+ SND_SOC_DAPM_PGA("MIC1 Volume", PM860X_ADC_EN_1, 2, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("MIC3 Volume", PM860X_ADC_EN_1, 3, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("AUX1 Volume", PM860X_ADC_EN_1, 4, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("AUX2 Volume", PM860X_ADC_EN_1, 5, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Sidetone PGA", PM860X_ADC_EN_2, 1, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Lofi PGA", PM860X_ADC_EN_2, 2, 0, NULL, 0),
+
+ SND_SOC_DAPM_INPUT("AUX1"),
+ SND_SOC_DAPM_INPUT("AUX2"),
+ SND_SOC_DAPM_INPUT("MIC1P"),
+ SND_SOC_DAPM_INPUT("MIC1N"),
+ SND_SOC_DAPM_INPUT("MIC2P"),
+ SND_SOC_DAPM_INPUT("MIC2N"),
+ SND_SOC_DAPM_INPUT("MIC3P"),
+ SND_SOC_DAPM_INPUT("MIC3N"),
+
+ SND_SOC_DAPM_DAC_E("Left DAC", NULL, SND_SOC_NOPM, 0, 0,
+ pm860x_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_DAC_E("Right DAC", NULL, SND_SOC_NOPM, 0, 0,
+ pm860x_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_MUX("I2S DIN Mux", SND_SOC_NOPM, 0, 0, &i2s_din_mux),
+ SND_SOC_DAPM_MUX("DAC HS1 Mux", SND_SOC_NOPM, 0, 0, &dac_hs1_mux),
+ SND_SOC_DAPM_MUX("DAC HS2 Mux", SND_SOC_NOPM, 0, 0, &dac_hs2_mux),
+ SND_SOC_DAPM_MUX("DAC LO1 Mux", SND_SOC_NOPM, 0, 0, &dac_lo1_mux),
+ SND_SOC_DAPM_MUX("DAC LO2 Mux", SND_SOC_NOPM, 0, 0, &dac_lo2_mux),
+ SND_SOC_DAPM_MUX("DAC SP Mux", SND_SOC_NOPM, 0, 0, &dac_spk_ear_mux),
+ SND_SOC_DAPM_MUX("Headset1 Mux", SND_SOC_NOPM, 0, 0, &hs1_mux),
+ SND_SOC_DAPM_MUX("Headset2 Mux", SND_SOC_NOPM, 0, 0, &hs2_mux),
+ SND_SOC_DAPM_MUX("Lineout1 Mux", SND_SOC_NOPM, 0, 0, &lo1_mux),
+ SND_SOC_DAPM_MUX("Lineout2 Mux", SND_SOC_NOPM, 0, 0, &lo2_mux),
+ SND_SOC_DAPM_MUX("Speaker Earpiece Demux", SND_SOC_NOPM, 0, 0,
+ &spk_demux),
+
+
+ SND_SOC_DAPM_PGA("Headset1 PGA", PM860X_DAC_EN_1, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Headset2 PGA", PM860X_DAC_EN_1, 1, 0, NULL, 0),
+ SND_SOC_DAPM_OUTPUT("HS1"),
+ SND_SOC_DAPM_OUTPUT("HS2"),
+ SND_SOC_DAPM_PGA("Lineout1 PGA", PM860X_DAC_EN_1, 2, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Lineout2 PGA", PM860X_DAC_EN_1, 3, 0, NULL, 0),
+ SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+ SND_SOC_DAPM_OUTPUT("LINEOUT2"),
+ SND_SOC_DAPM_PGA("Earpiece PGA", PM860X_DAC_EN_1, 4, 0, NULL, 0),
+ SND_SOC_DAPM_OUTPUT("EARP"),
+ SND_SOC_DAPM_OUTPUT("EARN"),
+ SND_SOC_DAPM_PGA("Speaker PGA", PM860X_DAC_EN_1, 5, 0, NULL, 0),
+ SND_SOC_DAPM_OUTPUT("LSP"),
+ SND_SOC_DAPM_OUTPUT("LSN"),
+ SND_SOC_DAPM_REG(snd_soc_dapm_supply, "VCODEC", PM860X_AUDIO_SUPPLIES_2,
+ 0, SUPPLY_MASK, SUPPLY_MASK, 0),
+
+ PM860X_DAPM_OUTPUT("RSYNC", pm860x_rsync_event),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* supply */
+ {"Left DAC", NULL, "VCODEC"},
+ {"Right DAC", NULL, "VCODEC"},
+ {"Left ADC", NULL, "VCODEC"},
+ {"Right ADC", NULL, "VCODEC"},
+ {"Left ADC", NULL, "Left ADC MOD"},
+ {"Right ADC", NULL, "Right ADC MOD"},
+
+ /* PCM/AIF1 Inputs */
+ {"PCM SDO", NULL, "ADC Left Mux"},
+ {"PCM SDO", NULL, "ADCR EC Mux"},
+
+ /* PCM/AFI2 Outputs */
+ {"Lofi PGA", NULL, "PCM SDI"},
+ {"Lofi PGA", NULL, "Sidetone PGA"},
+ {"Left DAC", NULL, "Lofi PGA"},
+ {"Right DAC", NULL, "Lofi PGA"},
+
+ /* I2S/AIF2 Inputs */
+ {"MIC Mux", "Mic 1", "MIC1P"},
+ {"MIC Mux", "Mic 1", "MIC1N"},
+ {"MIC Mux", "Mic 2", "MIC2P"},
+ {"MIC Mux", "Mic 2", "MIC2N"},
+ {"MIC1 Volume", NULL, "MIC Mux"},
+ {"MIC3 Volume", NULL, "MIC3P"},
+ {"MIC3 Volume", NULL, "MIC3N"},
+ {"Left ADC", NULL, "MIC1 Volume"},
+ {"Right ADC", NULL, "MIC3 Volume"},
+ {"ADC Left Mux", "ADCR", "Right ADC"},
+ {"ADC Left Mux", "ADCL", "Left ADC"},
+ {"ADC Right Mux", "ADCL", "Left ADC"},
+ {"ADC Right Mux", "ADCR", "Right ADC"},
+ {"Left EPA", "Switch", "Left DAC"},
+ {"Right EPA", "Switch", "Right DAC"},
+ {"EC Mux", "Left", "Left DAC"},
+ {"EC Mux", "Right", "Right DAC"},
+ {"EC Mux", "Left + Right", "Left DAC"},
+ {"EC Mux", "Left + Right", "Right DAC"},
+ {"ADCR EC Mux", "ADCR", "ADC Right Mux"},
+ {"ADCR EC Mux", "EC", "EC Mux"},
+ {"I2S Mic Mux", "Ex PA", "Left EPA"},
+ {"I2S Mic Mux", "Ex PA", "Right EPA"},
+ {"I2S Mic Mux", "ADC", "ADC Left Mux"},
+ {"I2S Mic Mux", "ADC", "ADCR EC Mux"},
+ {"I2S DOUT", NULL, "I2S Mic Mux"},
+
+ /* I2S/AIF2 Outputs */
+ {"I2S DIN Mux", "DIN", "I2S DIN"},
+ {"I2S DIN Mux", "DIN1", "I2S DIN1"},
+ {"Left DAC", NULL, "I2S DIN Mux"},
+ {"Right DAC", NULL, "I2S DIN Mux"},
+ {"DAC HS1 Mux", "Left", "Left DAC"},
+ {"DAC HS1 Mux", "Right", "Right DAC"},
+ {"DAC HS2 Mux", "Left", "Left DAC"},
+ {"DAC HS2 Mux", "Right", "Right DAC"},
+ {"DAC LO1 Mux", "Left", "Left DAC"},
+ {"DAC LO1 Mux", "Right", "Right DAC"},
+ {"DAC LO2 Mux", "Left", "Left DAC"},
+ {"DAC LO2 Mux", "Right", "Right DAC"},
+ {"Headset1 Mux", "Digital", "DAC HS1 Mux"},
+ {"Headset2 Mux", "Digital", "DAC HS2 Mux"},
+ {"Lineout1 Mux", "Digital", "DAC LO1 Mux"},
+ {"Lineout2 Mux", "Digital", "DAC LO2 Mux"},
+ {"Headset1 PGA", NULL, "Headset1 Mux"},
+ {"Headset2 PGA", NULL, "Headset2 Mux"},
+ {"Lineout1 PGA", NULL, "Lineout1 Mux"},
+ {"Lineout2 PGA", NULL, "Lineout2 Mux"},
+ {"DAC SP Mux", "Left", "Left DAC"},
+ {"DAC SP Mux", "Right", "Right DAC"},
+ {"Speaker Earpiece Demux", "Speaker", "DAC SP Mux"},
+ {"Speaker PGA", NULL, "Speaker Earpiece Demux"},
+ {"Earpiece PGA", NULL, "Speaker Earpiece Demux"},
+
+ {"RSYNC", NULL, "Headset1 PGA"},
+ {"RSYNC", NULL, "Headset2 PGA"},
+ {"RSYNC", NULL, "Lineout1 PGA"},
+ {"RSYNC", NULL, "Lineout2 PGA"},
+ {"RSYNC", NULL, "Speaker PGA"},
+ {"RSYNC", NULL, "Speaker PGA"},
+ {"RSYNC", NULL, "Earpiece PGA"},
+ {"RSYNC", NULL, "Earpiece PGA"},
+
+ {"HS1", NULL, "RSYNC"},
+ {"HS2", NULL, "RSYNC"},
+ {"LINEOUT1", NULL, "RSYNC"},
+ {"LINEOUT2", NULL, "RSYNC"},
+ {"LSP", NULL, "RSYNC"},
+ {"LSN", NULL, "RSYNC"},
+ {"EARP", NULL, "RSYNC"},
+ {"EARN", NULL, "RSYNC"},
+};
+
+/*
+ * Use MUTE_LEFT & MUTE_RIGHT to implement digital mute.
+ * These bits can also be used to mute.
+ */
+static int pm860x_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ int data = 0, mask = MUTE_LEFT | MUTE_RIGHT;
+
+ if (mute)
+ data = mask;
+ snd_soc_update_bits(codec, PM860X_DAC_OFFSET, mask, data);
+ snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
+ RSYNC_CHANGE, RSYNC_CHANGE);
+ return 0;
+}
+
+static int pm860x_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ unsigned char inf = 0, mask = 0;
+
+ /* bit size */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ inf &= ~PCM_INF2_18WL;
+ break;
+ case SNDRV_PCM_FORMAT_S18_3LE:
+ inf |= PCM_INF2_18WL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ mask |= PCM_INF2_18WL;
+ snd_soc_update_bits(codec, PM860X_PCM_IFACE_2, mask, inf);
+
+ /* sample rate */
+ switch (params_rate(params)) {
+ case 8000:
+ inf = 0;
+ break;
+ case 16000:
+ inf = 3;
+ break;
+ case 32000:
+ inf = 6;
+ break;
+ case 48000:
+ inf = 8;
+ break;
+ default:
+ return -EINVAL;
+ }
+ snd_soc_update_bits(codec, PM860X_PCM_RATE, 0x0f, inf);
+
+ return 0;
+}
+
+static int pm860x_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+ unsigned char inf = 0, mask = 0;
+ int ret = -EINVAL;
+
+ mask |= PCM_INF2_BCLK | PCM_INF2_FS | PCM_INF2_MASTER;
+
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBM_CFS:
+ if (pm860x->dir == PM860X_CLK_DIR_OUT) {
+ inf |= PCM_INF2_MASTER;
+ ret = 0;
+ }
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ if (pm860x->dir == PM860X_CLK_DIR_IN) {
+ inf &= ~PCM_INF2_MASTER;
+ ret = 0;
+ }
+ break;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ inf |= PCM_EXACT_I2S;
+ ret = 0;
+ break;
+ }
+ mask |= PCM_MODE_MASK;
+ if (ret)
+ return ret;
+ snd_soc_update_bits(codec, PM860X_PCM_IFACE_2, mask, inf);
+ return 0;
+}
+
+static int pm860x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+
+ if (dir == PM860X_CLK_DIR_OUT)
+ pm860x->dir = PM860X_CLK_DIR_OUT;
+ else {
+ pm860x->dir = PM860X_CLK_DIR_IN;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int pm860x_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ unsigned char inf;
+
+ /* bit size */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ inf = 0;
+ break;
+ case SNDRV_PCM_FORMAT_S18_3LE:
+ inf = PCM_INF2_18WL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ snd_soc_update_bits(codec, PM860X_I2S_IFACE_2, PCM_INF2_18WL, inf);
+
+ /* sample rate */
+ switch (params_rate(params)) {
+ case 8000:
+ inf = 0;
+ break;
+ case 11025:
+ inf = 1;
+ break;
+ case 16000:
+ inf = 3;
+ break;
+ case 22050:
+ inf = 4;
+ break;
+ case 32000:
+ inf = 6;
+ break;
+ case 44100:
+ inf = 7;
+ break;
+ case 48000:
+ inf = 8;
+ break;
+ default:
+ return -EINVAL;
+ }
+ snd_soc_update_bits(codec, PM860X_I2S_IFACE_4, 0xf, inf);
+
+ return 0;
+}
+
+static int pm860x_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+ unsigned char inf = 0, mask = 0;
+
+ mask |= PCM_INF2_BCLK | PCM_INF2_FS | PCM_INF2_MASTER;
+
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ if (pm860x->dir == PM860X_CLK_DIR_OUT)
+ inf |= PCM_INF2_MASTER;
+ else
+ return -EINVAL;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ if (pm860x->dir == PM860X_CLK_DIR_IN)
+ inf &= ~PCM_INF2_MASTER;
+ else
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ inf |= PCM_EXACT_I2S;
+ break;
+ default:
+ return -EINVAL;
+ }
+ mask |= PCM_MODE_MASK;
+ snd_soc_update_bits(codec, PM860X_I2S_IFACE_2, mask, inf);
+ return 0;
+}
+
+static int pm860x_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ int data;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+
+ case SND_SOC_BIAS_PREPARE:
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->bias_level == SND_SOC_BIAS_OFF) {
+ /* Enable Audio PLL & Audio section */
+ data = AUDIO_PLL | AUDIO_SECTION_RESET
+ | AUDIO_SECTION_ON;
+ pm860x_reg_write(codec->control_data, REG_MISC2, data);
+ }
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ data = AUDIO_PLL | AUDIO_SECTION_RESET | AUDIO_SECTION_ON;
+ pm860x_set_bits(codec->control_data, REG_MISC2, data, 0);
+ break;
+ }
+ codec->bias_level = level;
+ return 0;
+}
+
+static struct snd_soc_dai_ops pm860x_pcm_dai_ops = {
+ .digital_mute = pm860x_digital_mute,
+ .hw_params = pm860x_pcm_hw_params,
+ .set_fmt = pm860x_pcm_set_dai_fmt,
+ .set_sysclk = pm860x_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_ops pm860x_i2s_dai_ops = {
+ .digital_mute = pm860x_digital_mute,
+ .hw_params = pm860x_i2s_hw_params,
+ .set_fmt = pm860x_i2s_set_dai_fmt,
+ .set_sysclk = pm860x_set_dai_sysclk,
+};
+
+#define PM860X_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
+
+static struct snd_soc_dai_driver pm860x_dai[] = {
+ {
+ /* DAI PCM */
+ .name = "88pm860x-pcm",
+ .id = 1,
+ .playback = {
+ .stream_name = "PCM Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = PM860X_RATES,
+ .formats = SNDRV_PCM_FORMAT_S16_LE | \
+ SNDRV_PCM_FORMAT_S18_3LE,
+ },
+ .capture = {
+ .stream_name = "PCM Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = PM860X_RATES,
+ .formats = SNDRV_PCM_FORMAT_S16_LE | \
+ SNDRV_PCM_FORMAT_S18_3LE,
+ },
+ .ops = &pm860x_pcm_dai_ops,
+ }, {
+ /* DAI I2S */
+ .name = "88pm860x-i2s",
+ .id = 2,
+ .playback = {
+ .stream_name = "I2S Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FORMAT_S16_LE | \
+ SNDRV_PCM_FORMAT_S18_3LE,
+ },
+ .capture = {
+ .stream_name = "I2S Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FORMAT_S16_LE | \
+ SNDRV_PCM_FORMAT_S18_3LE,
+ },
+ .ops = &pm860x_i2s_dai_ops,
+ },
+};
+
+static irqreturn_t pm860x_codec_handler(int irq, void *data)
+{
+ struct pm860x_priv *pm860x = data;
+ int status, shrt, report = 0, mic_report = 0;
+ int mask;
+
+ status = pm860x_reg_read(pm860x->i2c, REG_STATUS_1);
+ shrt = pm860x_reg_read(pm860x->i2c, REG_SHORTS);
+ mask = pm860x->det.hs_shrt | pm860x->det.hook_det | pm860x->det.lo_shrt
+ | pm860x->det.hp_det;
+
+ if ((pm860x->det.hp_det & SND_JACK_HEADPHONE)
+ && (status & HEADSET_STATUS))
+ report |= SND_JACK_HEADPHONE;
+
+ if ((pm860x->det.mic_det & SND_JACK_MICROPHONE)
+ && (status & MIC_STATUS))
+ mic_report |= SND_JACK_MICROPHONE;
+
+ if (pm860x->det.hs_shrt && (shrt & (SHORT_HS1 | SHORT_HS2)))
+ report |= pm860x->det.hs_shrt;
+
+ if (pm860x->det.hook_det && (status & HOOK_STATUS))
+ report |= pm860x->det.hook_det;
+
+ if (pm860x->det.lo_shrt && (shrt & (SHORT_LO1 | SHORT_LO2)))
+ report |= pm860x->det.lo_shrt;
+
+ if (report)
+ snd_soc_jack_report(pm860x->det.hp_jack, report, mask);
+ if (mic_report)
+ snd_soc_jack_report(pm860x->det.mic_jack, SND_JACK_MICROPHONE,
+ SND_JACK_MICROPHONE);
+
+ dev_dbg(pm860x->codec->dev, "headphone report:0x%x, mask:%x\n",
+ report, mask);
+ dev_dbg(pm860x->codec->dev, "microphone report:0x%x\n", mic_report);
+ return IRQ_HANDLED;
+}
+
+int pm860x_hs_jack_detect(struct snd_soc_codec *codec,
+ struct snd_soc_jack *jack,
+ int det, int hook, int hs_shrt, int lo_shrt)
+{
+ struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+ int data;
+
+ pm860x->det.hp_jack = jack;
+ pm860x->det.hp_det = det;
+ pm860x->det.hook_det = hook;
+ pm860x->det.hs_shrt = hs_shrt;
+ pm860x->det.lo_shrt = lo_shrt;
+
+ if (det & SND_JACK_HEADPHONE)
+ pm860x_set_bits(codec->control_data, REG_HS_DET,
+ EN_HS_DET, EN_HS_DET);
+ /* headset short detect */
+ if (hs_shrt) {
+ data = CLR_SHORT_HS2 | CLR_SHORT_HS1;
+ pm860x_set_bits(codec->control_data, REG_SHORTS, data, data);
+ }
+ /* Lineout short detect */
+ if (lo_shrt) {
+ data = CLR_SHORT_LO2 | CLR_SHORT_LO1;
+ pm860x_set_bits(codec->control_data, REG_SHORTS, data, data);
+ }
+
+ /* sync status */
+ pm860x_codec_handler(0, pm860x);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pm860x_hs_jack_detect);
+
+int pm860x_mic_jack_detect(struct snd_soc_codec *codec,
+ struct snd_soc_jack *jack, int det)
+{
+ struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+
+ pm860x->det.mic_jack = jack;
+ pm860x->det.mic_det = det;
+
+ if (det & SND_JACK_MICROPHONE)
+ pm860x_set_bits(codec->control_data, REG_MIC_DET,
+ MICDET_MASK, MICDET_MASK);
+
+ /* sync status */
+ pm860x_codec_handler(0, pm860x);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pm860x_mic_jack_detect);
+
+static int pm860x_probe(struct snd_soc_codec *codec)
+{
+ struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+ int i, ret;
+
+ pm860x->codec = codec;
+
+ codec->control_data = pm860x->i2c;
+
+ for (i = 0; i < 4; i++) {
+ ret = request_threaded_irq(pm860x->irq[i], NULL,
+ pm860x_codec_handler, IRQF_ONESHOT,
+ pm860x->name[i], pm860x);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to request IRQ!\n");
+ goto out_irq;
+ }
+ }
+
+ pm860x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ ret = pm860x_bulk_read(codec->control_data, REG_CACHE_BASE,
+ REG_CACHE_SIZE, codec->reg_cache);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to fill register cache: %d\n",
+ ret);
+ goto out_codec;
+ }
+
+ snd_soc_add_controls(codec, pm860x_snd_controls,
+ ARRAY_SIZE(pm860x_snd_controls));
+ snd_soc_dapm_new_controls(codec, pm860x_dapm_widgets,
+ ARRAY_SIZE(pm860x_dapm_widgets));
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+ return 0;
+
+out_codec:
+ i = 3;
+out_irq:
+ for (; i >= 0; i--)
+ free_irq(pm860x->irq[i], pm860x);
+ return -EINVAL;
+}
+
+static int pm860x_remove(struct snd_soc_codec *codec)
+{
+ struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+ int i;
+
+ for (i = 3; i >= 0; i--)
+ free_irq(pm860x->irq[i], pm860x);
+ pm860x_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_pm860x = {
+ .probe = pm860x_probe,
+ .remove = pm860x_remove,
+ .read = pm860x_read_reg_cache,
+ .write = pm860x_write_reg_cache,
+ .reg_cache_size = REG_CACHE_SIZE,
+ .reg_word_size = sizeof(u8),
+ .set_bias_level = pm860x_set_bias_level,
+};
+
+static int __devinit pm860x_codec_probe(struct platform_device *pdev)
+{
+ struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct pm860x_priv *pm860x;
+ struct resource *res;
+ int i, ret;
+
+ pm860x = kzalloc(sizeof(struct pm860x_priv), GFP_KERNEL);
+ if (pm860x == NULL)
+ return -ENOMEM;
+
+ pm860x->chip = chip;
+ pm860x->i2c = (chip->id == CHIP_PM8607) ? chip->client
+ : chip->companion;
+ platform_set_drvdata(pdev, pm860x);
+
+ for (i = 0; i < 4; i++) {
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get IRQ resources\n");
+ goto out;
+ }
+ pm860x->irq[i] = res->start + chip->irq_base;
+ strncpy(pm860x->name[i], res->name, MAX_NAME_LEN);
+ }
+
+ ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_pm860x,
+ pm860x_dai, ARRAY_SIZE(pm860x_dai));
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register codec\n");
+ goto out;
+ }
+ return ret;
+
+out:
+ platform_set_drvdata(pdev, NULL);
+ kfree(pm860x);
+ return -EINVAL;
+}
+
+static int __devexit pm860x_codec_remove(struct platform_device *pdev)
+{
+ struct pm860x_priv *pm860x = platform_get_drvdata(pdev);
+
+ snd_soc_unregister_codec(&pdev->dev);
+ platform_set_drvdata(pdev, NULL);
+ kfree(pm860x);
+ return 0;
+}
+
+static struct platform_driver pm860x_codec_driver = {
+ .driver = {
+ .name = "88pm860x-codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = pm860x_codec_probe,
+ .remove = __devexit_p(pm860x_codec_remove),
+};
+
+static __init int pm860x_init(void)
+{
+ return platform_driver_register(&pm860x_codec_driver);
+}
+module_init(pm860x_init);
+
+static __exit void pm860x_exit(void)
+{
+ platform_driver_unregister(&pm860x_codec_driver);
+}
+module_exit(pm860x_exit);
+
+MODULE_DESCRIPTION("ASoC 88PM860x driver");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:88pm860x-codec");
+
diff --git a/sound/soc/codecs/88pm860x-codec.h b/sound/soc/codecs/88pm860x-codec.h
new file mode 100644
index 0000000..3364ba4
--- /dev/null
+++ b/sound/soc/codecs/88pm860x-codec.h
@@ -0,0 +1,97 @@
+/*
+ * 88pm860x-codec.h -- 88PM860x ALSA SoC Audio Driver
+ *
+ * Copyright 2010 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * 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 __88PM860X_H
+#define __88PM860X_H
+
+/* The offset of these registers are 0xb0 */
+#define PM860X_PCM_IFACE_1 0x00
+#define PM860X_PCM_IFACE_2 0x01
+#define PM860X_PCM_IFACE_3 0x02
+#define PM860X_PCM_RATE 0x03
+#define PM860X_EC_PATH 0x04
+#define PM860X_SIDETONE_L_GAIN 0x05
+#define PM860X_SIDETONE_R_GAIN 0x06
+#define PM860X_SIDETONE_SHIFT 0x07
+#define PM860X_ADC_OFFSET_1 0x08
+#define PM860X_ADC_OFFSET_2 0x09
+#define PM860X_DMIC_DELAY 0x0a
+
+#define PM860X_I2S_IFACE_1 0x0b
+#define PM860X_I2S_IFACE_2 0x0c
+#define PM860X_I2S_IFACE_3 0x0d
+#define PM860X_I2S_IFACE_4 0x0e
+#define PM860X_EQUALIZER_N0_1 0x0f
+#define PM860X_EQUALIZER_N0_2 0x10
+#define PM860X_EQUALIZER_N1_1 0x11
+#define PM860X_EQUALIZER_N1_2 0x12
+#define PM860X_EQUALIZER_D1_1 0x13
+#define PM860X_EQUALIZER_D1_2 0x14
+#define PM860X_LOFI_GAIN_LEFT 0x15
+#define PM860X_LOFI_GAIN_RIGHT 0x16
+#define PM860X_HIFIL_GAIN_LEFT 0x17
+#define PM860X_HIFIL_GAIN_RIGHT 0x18
+#define PM860X_HIFIR_GAIN_LEFT 0x19
+#define PM860X_HIFIR_GAIN_RIGHT 0x1a
+#define PM860X_DAC_OFFSET 0x1b
+#define PM860X_OFFSET_LEFT_1 0x1c
+#define PM860X_OFFSET_LEFT_2 0x1d
+#define PM860X_OFFSET_RIGHT_1 0x1e
+#define PM860X_OFFSET_RIGHT_2 0x1f
+#define PM860X_ADC_ANA_1 0x20
+#define PM860X_ADC_ANA_2 0x21
+#define PM860X_ADC_ANA_3 0x22
+#define PM860X_ADC_ANA_4 0x23
+#define PM860X_ANA_TO_ANA 0x24
+#define PM860X_HS1_CTRL 0x25
+#define PM860X_HS2_CTRL 0x26
+#define PM860X_LO1_CTRL 0x27
+#define PM860X_LO2_CTRL 0x28
+#define PM860X_EAR_CTRL_1 0x29
+#define PM860X_EAR_CTRL_2 0x2a
+#define PM860X_AUDIO_SUPPLIES_1 0x2b
+#define PM860X_AUDIO_SUPPLIES_2 0x2c
+#define PM860X_ADC_EN_1 0x2d
+#define PM860X_ADC_EN_2 0x2e
+#define PM860X_DAC_EN_1 0x2f
+#define PM860X_DAC_EN_2 0x31
+#define PM860X_AUDIO_CAL_1 0x32
+#define PM860X_AUDIO_CAL_2 0x33
+#define PM860X_AUDIO_CAL_3 0x34
+#define PM860X_AUDIO_CAL_4 0x35
+#define PM860X_AUDIO_CAL_5 0x36
+#define PM860X_ANA_INPUT_SEL_1 0x37
+#define PM860X_ANA_INPUT_SEL_2 0x38
+
+#define PM860X_PCM_IFACE_4 0x39
+#define PM860X_I2S_IFACE_5 0x3a
+
+#define PM860X_SHORTS 0x3b
+#define PM860X_PLL_ADJ_1 0x3c
+#define PM860X_PLL_ADJ_2 0x3d
+
+/* bits definition */
+#define PM860X_CLK_DIR_IN 0
+#define PM860X_CLK_DIR_OUT 1
+
+#define PM860X_DET_HEADSET (1 << 0)
+#define PM860X_DET_MIC (1 << 1)
+#define PM860X_DET_HOOK (1 << 2)
+#define PM860X_SHORT_HEADSET (1 << 3)
+#define PM860X_SHORT_LINEOUT (1 << 4)
+#define PM860X_DET_MASK 0x1F
+
+extern int pm860x_hs_jack_detect(struct snd_soc_codec *, struct snd_soc_jack *,
+ int, int, int, int);
+extern int pm860x_mic_jack_detect(struct snd_soc_codec *, struct snd_soc_jack *,
+ int);
+
+#endif /* __88PM860X_H */
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 83f5c67..94a9d06 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -10,6 +10,7 @@
config SND_SOC_ALL_CODECS
tristate "Build all ASoC CODEC drivers"
+ select SND_SOC_88PM860X if MFD_88PM860X
select SND_SOC_L3
select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
select SND_SOC_AD1836 if SPI_MASTER
@@ -26,6 +27,7 @@
select SND_SOC_CS4270 if I2C
select SND_SOC_DA7210 if I2C
select SND_SOC_JZ4740 if SOC_JZ4740
+ select SND_SOC_MAX98088 if I2C
select SND_SOC_MAX9877 if I2C
select SND_SOC_PCM3008
select SND_SOC_SPDIF
@@ -40,6 +42,7 @@
select SND_SOC_TWL6040 if TWL4030_CORE
select SND_SOC_UDA134X
select SND_SOC_UDA1380 if I2C
+ select SND_SOC_WL1273 if WL1273_CORE
select SND_SOC_WM2000 if I2C
select SND_SOC_WM8350 if MFD_WM8350
select SND_SOC_WM8400 if MFD_WM8400
@@ -54,6 +57,7 @@
select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
+ select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8900 if I2C
select SND_SOC_WM8903 if I2C
select SND_SOC_WM8904 if I2C
@@ -61,9 +65,11 @@
select SND_SOC_WM8955 if I2C
select SND_SOC_WM8960 if I2C
select SND_SOC_WM8961 if I2C
+ select SND_SOC_WM8962 if I2C
select SND_SOC_WM8971 if I2C
select SND_SOC_WM8974 if I2C
select SND_SOC_WM8978 if I2C
+ select SND_SOC_WM8985 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8990 if I2C
select SND_SOC_WM8993 if I2C
@@ -84,6 +90,9 @@
If unsure select "N".
+config SND_SOC_88PM860X
+ tristate
+
config SND_SOC_WM_HUBS
tristate
default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y
@@ -150,6 +159,9 @@
config SND_SOC_DA7210
tristate
+config SND_SOC_MAX98088
+ tristate
+
config SND_SOC_PCM3008
tristate
@@ -188,6 +200,9 @@
config SND_SOC_UDA1380
tristate
+config SND_SOC_WL1273
+ tristate
+
config SND_SOC_WM8350
tristate
@@ -227,6 +242,9 @@
config SND_SOC_WM8776
tristate
+config SND_SOC_WM8804
+ tristate
+
config SND_SOC_WM8900
tristate
@@ -248,6 +266,9 @@
config SND_SOC_WM8961
tristate
+config SND_SOC_WM8962
+ tristate
+
config SND_SOC_WM8971
tristate
@@ -257,6 +278,9 @@
config SND_SOC_WM8978
tristate
+config SND_SOC_WM8985
+ tristate
+
config SND_SOC_WM8988
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 5352409..f67a2d6 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -1,3 +1,4 @@
+snd-soc-88pm860x-objs := 88pm860x-codec.o
snd-soc-ac97-objs := ac97.o
snd-soc-ad1836-objs := ad1836.o
snd-soc-ad193x-objs := ad193x.o
@@ -14,6 +15,7 @@
snd-soc-cx20442-objs := cx20442.o
snd-soc-da7210-objs := da7210.o
snd-soc-l3-objs := l3.o
+snd-soc-max98088-objs := max98088.o
snd-soc-pcm3008-objs := pcm3008.o
snd-soc-spdif-objs := spdif_transciever.o
snd-soc-ssm2602-objs := ssm2602.o
@@ -26,6 +28,7 @@
snd-soc-twl6040-objs := twl6040.o
snd-soc-uda134x-objs := uda134x.o
snd-soc-uda1380-objs := uda1380.o
+snd-soc-wl1273-objs := wl1273.o
snd-soc-wm8350-objs := wm8350.o
snd-soc-wm8400-objs := wm8400.o
snd-soc-wm8510-objs := wm8510.o
@@ -39,6 +42,7 @@
snd-soc-wm8750-objs := wm8750.o
snd-soc-wm8753-objs := wm8753.o
snd-soc-wm8776-objs := wm8776.o
+snd-soc-wm8804-objs := wm8804.o
snd-soc-wm8900-objs := wm8900.o
snd-soc-wm8903-objs := wm8903.o
snd-soc-wm8904-objs := wm8904.o
@@ -46,9 +50,11 @@
snd-soc-wm8955-objs := wm8955.o
snd-soc-wm8960-objs := wm8960.o
snd-soc-wm8961-objs := wm8961.o
+snd-soc-wm8962-objs := wm8962.o
snd-soc-wm8971-objs := wm8971.o
snd-soc-wm8974-objs := wm8974.o
snd-soc-wm8978-objs := wm8978.o
+snd-soc-wm8985-objs := wm8985.o
snd-soc-wm8988-objs := wm8988.o
snd-soc-wm8990-objs := wm8990.o
snd-soc-wm8993-objs := wm8993.o
@@ -66,6 +72,7 @@
snd-soc-wm2000-objs := wm2000.o
snd-soc-wm9090-objs := wm9090.o
+obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o
obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o
obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o
@@ -83,6 +90,7 @@
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
+obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o
obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
@@ -95,6 +103,7 @@
obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o
obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o
obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o
+obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o
obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o
obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o
obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o
@@ -108,6 +117,7 @@
obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o
obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o
obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o
+obj-$(CONFIG_SND_SOC_WM8804) += snd-soc-wm8804.o
obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o
obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o
obj-$(CONFIG_SND_SOC_WM8904) += snd-soc-wm8904.o
@@ -115,9 +125,11 @@
obj-$(CONFIG_SND_SOC_WM8955) += snd-soc-wm8955.o
obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o
obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o
+obj-$(CONFIG_SND_SOC_WM8962) += snd-soc-wm8962.o
obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o
obj-$(CONFIG_SND_SOC_WM8974) += snd-soc-wm8974.o
obj-$(CONFIG_SND_SOC_WM8978) += snd-soc-wm8978.o
+obj-$(CONFIG_SND_SOC_WM8985) += snd-soc-wm8985.o
obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o
obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o
obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index 1f5e57a..3c08793 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -21,17 +21,13 @@
#include <sound/ac97_codec.h>
#include <sound/initval.h>
#include <sound/soc.h>
-#include "ac97.h"
-
-#define AC97_VERSION "0.6"
static int ac97_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
@@ -46,8 +42,8 @@
.prepare = ac97_prepare,
};
-struct snd_soc_dai ac97_dai = {
- .name = "AC97 HiFi",
+static struct snd_soc_dai_driver ac97_dai = {
+ .name = "ac97-hifi",
.ac97_control = 1,
.playback = {
.stream_name = "AC97 Playback",
@@ -63,7 +59,6 @@
.formats = SND_SOC_STD_AC97_FMTS,},
.ops = &ac97_dai_ops,
};
-EXPORT_SYMBOL_GPL(ac97_dai);
static unsigned int ac97_read(struct snd_soc_codec *codec,
unsigned int reg)
@@ -78,95 +73,41 @@
return 0;
}
-static int ac97_soc_probe(struct platform_device *pdev)
+static int ac97_soc_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_codec *codec;
struct snd_ac97_bus *ac97_bus;
struct snd_ac97_template ac97_template;
- int i;
- int ret = 0;
-
- printk(KERN_INFO "AC97 SoC Audio Codec %s\n", AC97_VERSION);
-
- socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (!socdev->card->codec)
- return -ENOMEM;
- codec = socdev->card->codec;
- mutex_init(&codec->mutex);
-
- codec->name = "AC97";
- codec->owner = THIS_MODULE;
- codec->dai = &ac97_dai;
- codec->num_dai = 1;
- codec->write = ac97_write;
- codec->read = ac97_read;
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0)
- goto err;
+ int ret;
/* add codec as bus device for standard ac97 */
- ret = snd_ac97_bus(codec->card, 0, &soc_ac97_ops, NULL, &ac97_bus);
+ ret = snd_ac97_bus(codec->card->snd_card, 0, &soc_ac97_ops, NULL, &ac97_bus);
if (ret < 0)
- goto bus_err;
+ return ret;
memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
ret = snd_ac97_mixer(ac97_bus, &ac97_template, &codec->ac97);
if (ret < 0)
- goto bus_err;
-
- for (i = 0; i < card->num_links; i++) {
- if (card->dai_link[i].codec_dai->ac97_control) {
- snd_ac97_dev_add_pdata(codec->ac97,
- card->dai_link[i].cpu_dai->ac97_pdata);
- }
- }
+ return ret;
return 0;
-
-bus_err:
- snd_soc_free_pcms(socdev);
-
-err:
- kfree(socdev->card->codec);
- socdev->card->codec = NULL;
- return ret;
}
-static int ac97_soc_remove(struct platform_device *pdev)
+static int ac97_soc_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (!codec)
- return 0;
-
- snd_soc_free_pcms(socdev);
- kfree(socdev->card->codec);
-
return 0;
}
#ifdef CONFIG_PM
-static int ac97_soc_suspend(struct platform_device *pdev, pm_message_t msg)
+static int ac97_soc_suspend(struct snd_soc_codec *codec, pm_message_t msg)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_ac97_suspend(socdev->card->codec->ac97);
+ snd_ac97_suspend(codec->ac97);
return 0;
}
-static int ac97_soc_resume(struct platform_device *pdev)
+static int ac97_soc_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_ac97_resume(socdev->card->codec->ac97);
+ snd_ac97_resume(codec->ac97);
return 0;
}
@@ -175,14 +116,50 @@
#define ac97_soc_resume NULL
#endif
-struct snd_soc_codec_device soc_codec_dev_ac97 = {
+static struct snd_soc_codec_driver soc_codec_dev_ac97 = {
+ .write = ac97_write,
+ .read = ac97_read,
.probe = ac97_soc_probe,
.remove = ac97_soc_remove,
.suspend = ac97_soc_suspend,
.resume = ac97_soc_resume,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ac97);
+
+static __devinit int ac97_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_ac97, &ac97_dai, 1);
+}
+
+static int __devexit ac97_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver ac97_codec_driver = {
+ .driver = {
+ .name = "ac97-codec",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = ac97_probe,
+ .remove = __devexit_p(ac97_remove),
+};
+
+static int __init ac97_init(void)
+{
+ return platform_driver_register(&ac97_codec_driver);
+}
+module_init(ac97_init);
+
+static void __exit ac97_exit(void)
+{
+ platform_driver_unregister(&ac97_codec_driver);
+}
+module_exit(ac97_exit);
MODULE_DESCRIPTION("Soc Generic AC97 driver");
MODULE_AUTHOR("Liam Girdwood");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ac97-codec");
diff --git a/sound/soc/codecs/ac97.h b/sound/soc/codecs/ac97.h
deleted file mode 100644
index 281aa42..0000000
--- a/sound/soc/codecs/ac97.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * linux/sound/codecs/ac97.h -- ALSA SoC Layer
- *
- * Author: Liam Girdwood
- * Created: Dec 1st 2005
- * Copyright: Wolfson Microelectronics. PLC.
- *
- * 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 __LINUX_SND_SOC_AC97_H
-#define __LINUX_SND_SOC_AC97_H
-
-extern struct snd_soc_codec_device soc_codec_dev_ac97;
-extern struct snd_soc_dai ac97_dai;
-
-#endif
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index a01006c..d272534 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -33,15 +33,10 @@
/* codec private data */
struct ad1836_priv {
- struct snd_soc_codec codec;
- u16 reg_cache[AD1836_NUM_REGS];
+ enum snd_soc_control_type control_type;
+ void *control_data;
};
-static struct snd_soc_codec *ad1836_codec;
-struct snd_soc_codec_device soc_codec_dev_ad1836;
-static int ad1836_register(struct ad1836_priv *ad1836);
-static void ad1836_unregister(struct ad1836_priv *ad1836);
-
/*
* AD1836 volume/mute/de-emphasis etc. controls
*/
@@ -146,8 +141,7 @@
int word_len = 0;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
/* bit size */
switch (params_format(params)) {
@@ -173,12 +167,9 @@
}
#ifdef CONFIG_PM
-static int ad1836_soc_suspend(struct platform_device *pdev,
+static int ad1836_soc_suspend(struct snd_soc_codec *codec,
pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
/* reset clock control mode */
u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK;
@@ -186,11 +177,8 @@
return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2);
}
-static int ad1836_soc_resume(struct platform_device *pdev)
+static int ad1836_soc_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
/* restore clock control mode */
u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
adc_ctrl2 |= AD1836_ADC_AUX;
@@ -202,49 +190,14 @@
#define ad1836_soc_resume NULL
#endif
-static int __devinit ad1836_spi_probe(struct spi_device *spi)
-{
- struct snd_soc_codec *codec;
- struct ad1836_priv *ad1836;
-
- ad1836 = kzalloc(sizeof(struct ad1836_priv), GFP_KERNEL);
- if (ad1836 == NULL)
- return -ENOMEM;
-
- codec = &ad1836->codec;
- codec->control_data = spi;
- codec->dev = &spi->dev;
-
- dev_set_drvdata(&spi->dev, ad1836);
-
- return ad1836_register(ad1836);
-}
-
-static int __devexit ad1836_spi_remove(struct spi_device *spi)
-{
- struct ad1836_priv *ad1836 = dev_get_drvdata(&spi->dev);
-
- ad1836_unregister(ad1836);
- return 0;
-}
-
-static struct spi_driver ad1836_spi_driver = {
- .driver = {
- .name = "ad1836",
- .owner = THIS_MODULE,
- },
- .probe = ad1836_spi_probe,
- .remove = __devexit_p(ad1836_spi_remove),
-};
-
static struct snd_soc_dai_ops ad1836_dai_ops = {
.hw_params = ad1836_hw_params,
.set_fmt = ad1836_set_dai_fmt,
};
/* codec DAI instance */
-struct snd_soc_dai ad1836_dai = {
- .name = "AD1836",
+static struct snd_soc_dai_driver ad1836_dai = {
+ .name = "ad1836-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -263,35 +216,13 @@
},
.ops = &ad1836_dai_ops,
};
-EXPORT_SYMBOL_GPL(ad1836_dai);
-static int ad1836_register(struct ad1836_priv *ad1836)
+static int ad1836_probe(struct snd_soc_codec *codec)
{
- int ret;
- struct snd_soc_codec *codec = &ad1836->codec;
+ struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
- if (ad1836_codec) {
- dev_err(codec->dev, "Another ad1836 is registered\n");
- kfree(ad1836);
- return -EINVAL;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
- snd_soc_codec_set_drvdata(codec, ad1836);
- codec->reg_cache = ad1836->reg_cache;
- codec->reg_cache_size = AD1836_NUM_REGS;
- codec->name = "AD1836";
- codec->owner = THIS_MODULE;
- codec->dai = &ad1836_dai;
- codec->num_dai = 1;
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- ad1836_dai.dev = codec->dev;
- ad1836_codec = codec;
-
+ codec->control_data = ad1836->control_data;
ret = snd_soc_codec_set_cache_io(codec, 4, 12, SND_SOC_SPI);
if (ret < 0) {
dev_err(codec->dev, "failed to set cache I/O: %d\n",
@@ -319,81 +250,69 @@
snd_soc_write(codec, AD1836_DAC_L3_VOL, 0x3FF);
snd_soc_write(codec, AD1836_DAC_R3_VOL, 0x3FF);
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- kfree(ad1836);
- return ret;
- }
-
- ret = snd_soc_register_dai(&ad1836_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- snd_soc_unregister_codec(codec);
- kfree(ad1836);
- return ret;
- }
-
- return 0;
-}
-
-static void ad1836_unregister(struct ad1836_priv *ad1836)
-{
- snd_soc_unregister_dai(&ad1836_dai);
- snd_soc_unregister_codec(&ad1836->codec);
- kfree(ad1836);
- ad1836_codec = NULL;
-}
-
-static int ad1836_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- if (ad1836_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = ad1836_codec;
- codec = ad1836_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
snd_soc_add_controls(codec, ad1836_snd_controls,
ARRAY_SIZE(ad1836_snd_controls));
snd_soc_dapm_new_controls(codec, ad1836_dapm_widgets,
ARRAY_SIZE(ad1836_dapm_widgets));
snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
-pcm_err:
return ret;
}
/* power down chip */
-static int ad1836_remove(struct platform_device *pdev)
+static int ad1836_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ /* reset clock control mode */
+ u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
+ adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK;
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
+ return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2);
}
-struct snd_soc_codec_device soc_codec_dev_ad1836 = {
+static struct snd_soc_codec_driver soc_codec_dev_ad1836 = {
.probe = ad1836_probe,
.remove = ad1836_remove,
.suspend = ad1836_soc_suspend,
.resume = ad1836_soc_resume,
+ .reg_cache_size = AD1836_NUM_REGS,
+ .reg_word_size = sizeof(u16),
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ad1836);
+
+static int __devinit ad1836_spi_probe(struct spi_device *spi)
+{
+ struct ad1836_priv *ad1836;
+ int ret;
+
+ ad1836 = kzalloc(sizeof(struct ad1836_priv), GFP_KERNEL);
+ if (ad1836 == NULL)
+ return -ENOMEM;
+
+ spi_set_drvdata(spi, ad1836);
+ ad1836->control_data = spi;
+ ad1836->control_type = SND_SOC_SPI;
+
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_ad1836, &ad1836_dai, 1);
+ if (ret < 0)
+ kfree(ad1836);
+ return ret;
+}
+
+static int __devexit ad1836_spi_remove(struct spi_device *spi)
+{
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
+ return 0;
+}
+
+static struct spi_driver ad1836_spi_driver = {
+ .driver = {
+ .name = "ad1836-codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = ad1836_spi_probe,
+ .remove = __devexit_p(ad1836_spi_remove),
+};
static int __init ad1836_init(void)
{
diff --git a/sound/soc/codecs/ad1836.h b/sound/soc/codecs/ad1836.h
index e9d90d3..8455967 100644
--- a/sound/soc/codecs/ad1836.h
+++ b/sound/soc/codecs/ad1836.h
@@ -60,6 +60,4 @@
#define AD1836_NUM_REGS 16
-extern struct snd_soc_dai ad1836_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ad1836;
#endif
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index 1def75e..fa2834c 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -24,9 +24,10 @@
/* codec private data */
struct ad193x_priv {
- unsigned int sysclk;
- struct snd_soc_codec codec;
u8 reg_cache[AD193X_NUM_REGS];
+ enum snd_soc_control_type bus_type;
+ void *control_data;
+ int sysclk;
};
/* ad193x register cache & default register settings */
@@ -34,9 +35,6 @@
0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0,
};
-static struct snd_soc_codec *ad193x_codec;
-struct snd_soc_codec_device soc_codec_dev_ad193x;
-
/*
* AD193X volume/mute/de-emphasis etc. controls
*/
@@ -275,8 +273,7 @@
int word_len = 0, reg = 0, master_rate = 0;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
/* bit size */
@@ -323,46 +320,46 @@
return 0;
}
-static int ad193x_bus_probe(struct device *dev, void *ctrl_data, int bus_type)
+static struct snd_soc_dai_ops ad193x_dai_ops = {
+ .hw_params = ad193x_hw_params,
+ .digital_mute = ad193x_mute,
+ .set_tdm_slot = ad193x_set_tdm_slot,
+ .set_sysclk = ad193x_set_dai_sysclk,
+ .set_fmt = ad193x_set_dai_fmt,
+};
+
+/* codec DAI instance */
+static struct snd_soc_dai_driver ad193x_dai = {
+ .name = "ad193x-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 4,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
+ },
+ .ops = &ad193x_dai_ops,
+};
+
+static int ad193x_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec;
- struct ad193x_priv *ad193x;
+ struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
int ret;
- if (ad193x_codec) {
- dev_err(dev, "Another ad193x is registered\n");
- return -EINVAL;
- }
-
- ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL);
- if (ad193x == NULL)
- return -ENOMEM;
-
- dev_set_drvdata(dev, ad193x);
-
- codec = &ad193x->codec;
- mutex_init(&codec->mutex);
- codec->control_data = ctrl_data;
- codec->dev = dev;
- snd_soc_codec_set_drvdata(codec, ad193x);
- codec->reg_cache = ad193x->reg_cache;
- codec->reg_cache_size = AD193X_NUM_REGS;
- codec->name = "AD193X";
- codec->owner = THIS_MODULE;
- codec->dai = &ad193x_dai;
- codec->num_dai = 1;
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- ad193x_dai.dev = codec->dev;
- ad193x_codec = codec;
-
- memcpy(codec->reg_cache, ad193x_reg, AD193X_NUM_REGS);
-
- if (bus_type == SND_SOC_I2C)
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, bus_type);
+ codec->control_data = ad193x->control_data;
+ if (ad193x->bus_type == SND_SOC_I2C)
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, ad193x->bus_type);
else
- ret = snd_soc_codec_set_cache_io(codec, 16, 8, bus_type);
+ ret = snd_soc_codec_set_cache_io(codec, 16, 8, ad193x->bus_type);
if (ret < 0) {
dev_err(codec->dev, "failed to set cache I/O: %d\n",
ret);
@@ -385,89 +382,6 @@
/* pll input: mclki/xi */
snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04);
- ad193x->sysclk = 12288000;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- kfree(ad193x);
- return ret;
- }
-
- ret = snd_soc_register_dai(&ad193x_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- snd_soc_unregister_codec(codec);
- kfree(ad193x);
- return ret;
- }
-
- return 0;
-}
-
-static int ad193x_bus_remove(struct device *dev)
-{
- struct ad193x_priv *ad193x = dev_get_drvdata(dev);
-
- snd_soc_unregister_dai(&ad193x_dai);
- snd_soc_unregister_codec(&ad193x->codec);
- kfree(ad193x);
- ad193x_codec = NULL;
-
- return 0;
-}
-
-static struct snd_soc_dai_ops ad193x_dai_ops = {
- .hw_params = ad193x_hw_params,
- .digital_mute = ad193x_mute,
- .set_tdm_slot = ad193x_set_tdm_slot,
- .set_sysclk = ad193x_set_dai_sysclk,
- .set_fmt = ad193x_set_dai_fmt,
-};
-
-/* codec DAI instance */
-struct snd_soc_dai ad193x_dai = {
- .name = "AD193X",
- .playback = {
- .stream_name = "Playback",
- .channels_min = 2,
- .channels_max = 8,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
- },
- .capture = {
- .stream_name = "Capture",
- .channels_min = 2,
- .channels_max = 4,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
- },
- .ops = &ad193x_dai_ops,
-};
-EXPORT_SYMBOL_GPL(ad193x_dai);
-
-static int ad193x_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- if (ad193x_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = ad193x_codec;
- codec = ad193x_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
snd_soc_add_controls(codec, ad193x_snd_controls,
ARRAY_SIZE(ad193x_snd_controls));
@@ -475,41 +389,47 @@
ARRAY_SIZE(ad193x_dapm_widgets));
snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
-pcm_err:
return ret;
}
-/* power down chip */
-static int ad193x_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_ad193x = {
+static struct snd_soc_codec_driver soc_codec_dev_ad193x = {
.probe = ad193x_probe,
- .remove = ad193x_remove,
+ .reg_cache_default = ad193x_reg,
+ .reg_cache_size = AD193X_NUM_REGS,
+ .reg_word_size = sizeof(u16),
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ad193x);
#if defined(CONFIG_SPI_MASTER)
static int __devinit ad193x_spi_probe(struct spi_device *spi)
{
- return ad193x_bus_probe(&spi->dev, spi, SND_SOC_SPI);
+ struct ad193x_priv *ad193x;
+ int ret;
+
+ ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL);
+ if (ad193x == NULL)
+ return -ENOMEM;
+
+ spi_set_drvdata(spi, ad193x);
+ ad193x->control_data = spi;
+ ad193x->bus_type = SND_SOC_SPI;
+
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_ad193x, &ad193x_dai, 1);
+ if (ret < 0)
+ kfree(ad193x);
+ return ret;
}
static int __devexit ad193x_spi_remove(struct spi_device *spi)
{
- return ad193x_bus_remove(&spi->dev);
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
+ return 0;
}
static struct spi_driver ad193x_spi_driver = {
.driver = {
- .name = "ad193x",
+ .name = "ad193x-codec",
.owner = THIS_MODULE,
},
.probe = ad193x_spi_probe,
@@ -528,17 +448,34 @@
static int __devinit ad193x_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- return ad193x_bus_probe(&client->dev, client, SND_SOC_I2C);
+ struct ad193x_priv *ad193x;
+ int ret;
+
+ ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL);
+ if (ad193x == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, ad193x);
+ ad193x->control_data = client;
+ ad193x->bus_type = SND_SOC_I2C;
+
+ ret = snd_soc_register_codec(&client->dev,
+ &soc_codec_dev_ad193x, &ad193x_dai, 1);
+ if (ret < 0)
+ kfree(ad193x);
+ return ret;
}
static int __devexit ad193x_i2c_remove(struct i2c_client *client)
{
- return ad193x_bus_remove(&client->dev);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
+ return 0;
}
static struct i2c_driver ad193x_i2c_driver = {
.driver = {
- .name = "ad193x",
+ .name = "ad193x-codec",
},
.probe = ad193x_i2c_probe,
.remove = __devexit_p(ad193x_i2c_remove),
diff --git a/sound/soc/codecs/ad193x.h b/sound/soc/codecs/ad193x.h
index 654ba64..9747b54 100644
--- a/sound/soc/codecs/ad193x.h
+++ b/sound/soc/codecs/ad193x.h
@@ -80,7 +80,4 @@
#define AD193X_NUM_REGS 17
-extern struct snd_soc_dai ad193x_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ad193x;
-
#endif
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index 70cfaec..410ccd5 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -33,11 +33,6 @@
#include "ad1980.h"
-static unsigned int ac97_read(struct snd_soc_codec *codec,
- unsigned int reg);
-static int ac97_write(struct snd_soc_codec *codec,
- unsigned int reg, unsigned int val);
-
/*
* AD1980 register cache
*/
@@ -138,8 +133,8 @@
return 0;
}
-struct snd_soc_dai ad1980_dai = {
- .name = "AC97",
+static struct snd_soc_dai_driver ad1980_dai = {
+ .name = "ad1980-hifi",
.ac97_control = 1,
.playback = {
.stream_name = "Playback",
@@ -185,53 +180,20 @@
return -EIO;
}
-static int ad1980_soc_probe(struct platform_device *pdev)
+static int ad1980_soc_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
+ int ret;
u16 vendor_id2;
u16 ext_status;
printk(KERN_INFO "AD1980 SoC Audio Codec\n");
- socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (socdev->card->codec == NULL)
- return -ENOMEM;
- codec = socdev->card->codec;
- mutex_init(&codec->mutex);
-
- codec->reg_cache =
- kzalloc(sizeof(u16) * ARRAY_SIZE(ad1980_reg), GFP_KERNEL);
- if (codec->reg_cache == NULL) {
- ret = -ENOMEM;
- goto cache_err;
- }
- memcpy(codec->reg_cache, ad1980_reg, sizeof(u16) * \
- ARRAY_SIZE(ad1980_reg));
- codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(ad1980_reg);
- codec->reg_cache_step = 2;
- codec->name = "AD1980";
- codec->owner = THIS_MODULE;
- codec->dai = &ad1980_dai;
- codec->num_dai = 1;
- codec->write = ac97_write;
- codec->read = ac97_read;
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
if (ret < 0) {
printk(KERN_ERR "ad1980: failed to register AC97 codec\n");
- goto codec_err;
+ return ret;
}
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0)
- goto pcm_err;
-
-
ret = ad1980_reset(codec, 0);
if (ret < 0) {
printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n");
@@ -270,41 +232,60 @@
return 0;
reset_err:
- snd_soc_free_pcms(socdev);
-
-pcm_err:
snd_soc_free_ac97_codec(codec);
-
-codec_err:
- kfree(codec->reg_cache);
-
-cache_err:
- kfree(socdev->card->codec);
- socdev->card->codec = NULL;
return ret;
}
-static int ad1980_soc_remove(struct platform_device *pdev)
+static int ad1980_soc_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec == NULL)
- return 0;
-
- snd_soc_dapm_free(socdev);
- snd_soc_free_pcms(socdev);
snd_soc_free_ac97_codec(codec);
- kfree(codec->reg_cache);
- kfree(codec);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_ad1980 = {
+static struct snd_soc_codec_driver soc_codec_dev_ad1980 = {
.probe = ad1980_soc_probe,
.remove = ad1980_soc_remove,
+ .reg_cache_size = ARRAY_SIZE(ad1980_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = ad1980_reg,
+ .reg_cache_step = 2,
+ .write = ac97_write,
+ .read = ac97_read,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ad1980);
+
+static __devinit int ad1980_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_ad1980, &ad1980_dai, 1);
+}
+
+static int __devexit ad1980_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver ad1980_codec_driver = {
+ .driver = {
+ .name = "ad1980-codec",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = ad1980_probe,
+ .remove = __devexit_p(ad1980_remove),
+};
+
+static int __init ad1980_init(void)
+{
+ return platform_driver_register(&ad1980_codec_driver);
+}
+module_init(ad1980_init);
+
+static void __exit ad1980_exit(void)
+{
+ platform_driver_unregister(&ad1980_codec_driver);
+}
+module_exit(ad1980_exit);
MODULE_DESCRIPTION("ASoC ad1980 driver (Obsolete)");
MODULE_AUTHOR("Roy Huang, Cliff Cai");
diff --git a/sound/soc/codecs/ad1980.h b/sound/soc/codecs/ad1980.h
index 538f37c..eb0af44 100644
--- a/sound/soc/codecs/ad1980.h
+++ b/sound/soc/codecs/ad1980.h
@@ -23,7 +23,4 @@
#define PR5 0x2000
#define PR6 0x4000
-extern struct snd_soc_dai ad1980_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ad1980;
-
#endif
diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c
index 475807b..c53955f 100644
--- a/sound/soc/codecs/ad73311.c
+++ b/sound/soc/codecs/ad73311.c
@@ -23,8 +23,8 @@
#include "ad73311.h"
-struct snd_soc_dai ad73311_dai = {
- .name = "AD73311",
+static struct snd_soc_dai_driver ad73311_dai = {
+ .name = "ad73311-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -38,68 +38,40 @@
.rates = SNDRV_PCM_RATE_8000,
.formats = SNDRV_PCM_FMTBIT_S16_LE, },
};
-EXPORT_SYMBOL_GPL(ad73311_dai);
-static int ad73311_soc_probe(struct platform_device *pdev)
+static struct snd_soc_codec_driver soc_codec_dev_ad73311;
+
+static int ad73311_probe(struct platform_device *pdev)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
- mutex_init(&codec->mutex);
- codec->name = "AD73311";
- codec->owner = THIS_MODULE;
- codec->dai = &ad73311_dai;
- codec->num_dai = 1;
- socdev->card->codec = codec;
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "ad73311: failed to create pcms\n");
- goto pcm_err;
- }
-
- return ret;
-
-pcm_err:
- kfree(socdev->card->codec);
- socdev->card->codec = NULL;
- return ret;
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_ad73311, &ad73311_dai, 1);
}
-static int ad73311_soc_remove(struct platform_device *pdev)
+static int ad73311_remove(struct platform_device *pdev)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec == NULL)
- return 0;
- snd_soc_free_pcms(socdev);
- kfree(codec);
+ snd_soc_unregister_codec(&pdev->dev);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_ad73311 = {
- .probe = ad73311_soc_probe,
- .remove = ad73311_soc_remove,
+static struct platform_driver ad73311_codec_driver = {
+ .driver = {
+ .name = "ad73311-codec",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = ad73311_probe,
+ .remove = __devexit_p(ad73311_remove),
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ad73311);
static int __init ad73311_init(void)
{
- return snd_soc_register_dai(&ad73311_dai);
+ return platform_driver_register(&ad73311_codec_driver);
}
module_init(ad73311_init);
static void __exit ad73311_exit(void)
{
- snd_soc_unregister_dai(&ad73311_dai);
+ platform_driver_unregister(&ad73311_codec_driver);
}
module_exit(ad73311_exit);
diff --git a/sound/soc/codecs/ad73311.h b/sound/soc/codecs/ad73311.h
index 569573d..4b353ee 100644
--- a/sound/soc/codecs/ad73311.h
+++ b/sound/soc/codecs/ad73311.h
@@ -85,6 +85,4 @@
#define REGF_INV (1 << 6)
#define REGF_ALB (1 << 7)
-extern struct snd_soc_dai ad73311_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ad73311;
#endif
diff --git a/sound/soc/codecs/ads117x.c b/sound/soc/codecs/ads117x.c
index f8e75ed..8402854 100644
--- a/sound/soc/codecs/ads117x.c
+++ b/sound/soc/codecs/ads117x.c
@@ -19,16 +19,12 @@
#include <sound/initval.h>
#include <sound/soc.h>
-#include "ads117x.h"
-
#define ADS117X_RATES (SNDRV_PCM_RATE_8000_48000)
-
#define ADS117X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
-struct snd_soc_dai ads117x_dai = {
+static struct snd_soc_dai_driver ads117x_dai = {
/* ADC */
- .name = "ADS117X ADC",
- .id = 1,
+ .name = "ads117x-hifi",
.capture = {
.stream_name = "Capture",
.channels_min = 1,
@@ -36,75 +32,29 @@
.rates = ADS117X_RATES,
.formats = ADS117X_FORMATS,},
};
-EXPORT_SYMBOL_GPL(ads117x_dai);
-static int ads117x_probe(struct platform_device *pdev)
+static struct snd_soc_codec_driver soc_codec_dev_ads117x;
+
+static __devinit int ads117x_probe(struct platform_device *pdev)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret;
-
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
-
- socdev->card->codec = codec;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
- codec->name = "ADS117X";
- codec->owner = THIS_MODULE;
- codec->dai = &ads117x_dai;
- codec->num_dai = 1;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "ads117x: failed to create pcms\n");
- kfree(codec);
- return ret;
- }
-
- return 0;
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_ads117x, &ads117x_dai, 1);
}
-static int ads117x_remove(struct platform_device *pdev)
+static int __devexit ads117x_remove(struct platform_device *pdev)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- snd_soc_free_pcms(socdev);
- kfree(codec);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_ads117x = {
- .probe = ads117x_probe,
- .remove = ads117x_remove,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ads117x);
-
-static __devinit int ads117x_platform_probe(struct platform_device *pdev)
-{
- ads117x_dai.dev = &pdev->dev;
- return snd_soc_register_dai(&ads117x_dai);
-}
-
-static int __devexit ads117x_platform_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_dai(&ads117x_dai);
+ snd_soc_unregister_codec(&pdev->dev);
return 0;
}
static struct platform_driver ads117x_codec_driver = {
.driver = {
- .name = "ads117x",
+ .name = "ads117x-codec",
.owner = THIS_MODULE,
},
- .probe = ads117x_platform_probe,
- .remove = __devexit_p(ads117x_platform_remove),
+ .probe = ads117x_probe,
+ .remove = __devexit_p(ads117x_remove),
};
static int __init ads117x_init(void)
diff --git a/sound/soc/codecs/ads117x.h b/sound/soc/codecs/ads117x.h
index dbcf50e..3ce0286 100644
--- a/sound/soc/codecs/ads117x.h
+++ b/sound/soc/codecs/ads117x.h
@@ -9,5 +9,5 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
-extern struct snd_soc_dai ads117x_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ads117x;
+extern struct snd_soc_dai_driver ads117x_dai;
+extern struct snd_soc_codec_driver soc_codec_dev_ads117x;
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
index 192aebd..c27f8f5 100644
--- a/sound/soc/codecs/ak4104.c
+++ b/sound/soc/codecs/ak4104.c
@@ -17,8 +17,6 @@
#include <linux/spi/spi.h>
#include <sound/asoundef.h>
-#include "ak4104.h"
-
/* AK4104 registers addresses */
#define AK4104_REG_CONTROL1 0x00
#define AK4104_REG_RESERVED 0x01
@@ -45,11 +43,11 @@
#define AK4104_TX_TXE (1 << 0)
#define AK4104_TX_V (1 << 1)
-#define DRV_NAME "ak4104"
+#define DRV_NAME "ak4104-codec"
struct ak4104_private {
- struct snd_soc_codec codec;
- u8 reg_cache[AK4104_NUM_REGS];
+ enum snd_soc_control_type control_type;
+ void *control_data;
};
static int ak4104_fill_cache(struct snd_soc_codec *codec)
@@ -58,7 +56,7 @@
u8 *reg_cache = codec->reg_cache;
struct spi_device *spi = codec->control_data;
- for (i = 0; i < codec->reg_cache_size; i++) {
+ for (i = 0; i < codec->driver->reg_cache_size; i++) {
int ret = spi_w8r8(spi, i | AK4104_READ);
if (ret < 0) {
dev_err(&spi->dev, "SPI write failure\n");
@@ -76,7 +74,7 @@
{
u8 *reg_cache = codec->reg_cache;
- if (reg >= codec->reg_cache_size)
+ if (reg >= codec->driver->reg_cache_size)
return -EINVAL;
return reg_cache[reg];
@@ -88,7 +86,7 @@
u8 *cache = codec->reg_cache;
struct spi_device *spi = codec->control_data;
- if (reg >= codec->reg_cache_size)
+ if (reg >= codec->driver->reg_cache_size)
return -EINVAL;
/* only write to the hardware if value has changed */
@@ -145,8 +143,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
int val = 0;
/* set the IEC958 bits: consumer mode, no copyright bit */
@@ -178,8 +175,8 @@
.set_fmt = ak4104_set_dai_fmt,
};
-struct snd_soc_dai ak4104_dai = {
- .name = DRV_NAME,
+static struct snd_soc_dai_driver ak4104_dai = {
+ .name = "ak4104-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -192,13 +189,71 @@
.ops = &ak4101_dai_ops,
};
-static struct snd_soc_codec *ak4104_codec;
+static int ak4104_probe(struct snd_soc_codec *codec)
+{
+ struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
+ int ret, val;
+
+ codec->control_data = ak4104->control_data;
+
+ /* read all regs and fill the cache */
+ ret = ak4104_fill_cache(codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "failed to fill register cache\n");
+ return ret;
+ }
+
+ /* read the 'reserved' register - according to the datasheet, it
+ * should contain 0x5b. Not a good way to verify the presence of
+ * the device, but there is no hardware ID register. */
+ if (ak4104_read_reg_cache(codec, AK4104_REG_RESERVED) !=
+ AK4104_RESERVED_VAL)
+ return -ENODEV;
+
+ /* set power-up and non-reset bits */
+ val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
+ val |= AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN;
+ ret = ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
+ if (ret < 0)
+ return ret;
+
+ /* enable transmitter */
+ val = ak4104_read_reg_cache(codec, AK4104_REG_TX);
+ val |= AK4104_TX_TXE;
+ ret = ak4104_spi_write(codec, AK4104_REG_TX, val);
+ if (ret < 0)
+ return ret;
+
+ dev_info(codec->dev, "SPI device initialized\n");
+ return 0;
+}
+
+static int ak4104_remove(struct snd_soc_codec *codec)
+{
+ int val, ret;
+
+ val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
+ if (val < 0)
+ return val;
+
+ /* clear power-up and non-reset bits */
+ val &= ~(AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
+ ret = ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
+
+ return ret;
+}
+
+static struct snd_soc_codec_driver soc_codec_device_ak4104 = {
+ .probe = ak4104_probe,
+ .remove = ak4104_remove,
+ .reg_cache_size = AK4104_NUM_REGS,
+ .reg_word_size = sizeof(u16),
+};
static int ak4104_spi_probe(struct spi_device *spi)
{
- struct snd_soc_codec *codec;
struct ak4104_private *ak4104;
- int ret, val;
+ int ret;
spi->bits_per_word = 8;
spi->mode = SPI_MODE_0;
@@ -207,125 +262,27 @@
return ret;
ak4104 = kzalloc(sizeof(struct ak4104_private), GFP_KERNEL);
- if (!ak4104) {
- dev_err(&spi->dev, "could not allocate codec\n");
+ if (ak4104 == NULL)
return -ENOMEM;
- }
- codec = &ak4104->codec;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->dev = &spi->dev;
- codec->name = DRV_NAME;
- codec->owner = THIS_MODULE;
- codec->dai = &ak4104_dai;
- codec->num_dai = 1;
- snd_soc_codec_set_drvdata(codec, ak4104);
- codec->control_data = spi;
- codec->reg_cache = ak4104->reg_cache;
- codec->reg_cache_size = AK4104_NUM_REGS;
-
- /* read all regs and fill the cache */
- ret = ak4104_fill_cache(codec);
- if (ret < 0) {
- dev_err(&spi->dev, "failed to fill register cache\n");
- return ret;
- }
-
- /* read the 'reserved' register - according to the datasheet, it
- * should contain 0x5b. Not a good way to verify the presence of
- * the device, but there is no hardware ID register. */
- if (ak4104_read_reg_cache(codec, AK4104_REG_RESERVED) !=
- AK4104_RESERVED_VAL) {
- ret = -ENODEV;
- goto error_free_codec;
- }
-
- /* set power-up and non-reset bits */
- val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
- val |= AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN;
- ret = ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
- if (ret < 0)
- goto error_free_codec;
-
- /* enable transmitter */
- val = ak4104_read_reg_cache(codec, AK4104_REG_TX);
- val |= AK4104_TX_TXE;
- ret = ak4104_spi_write(codec, AK4104_REG_TX, val);
- if (ret < 0)
- goto error_free_codec;
-
- ak4104_codec = codec;
- ret = snd_soc_register_dai(&ak4104_dai);
- if (ret < 0) {
- dev_err(&spi->dev, "failed to register DAI\n");
- goto error_free_codec;
- }
-
+ ak4104->control_data = spi;
+ ak4104->control_type = SND_SOC_SPI;
spi_set_drvdata(spi, ak4104);
- dev_info(&spi->dev, "SPI device initialized\n");
- return 0;
-error_free_codec:
- kfree(ak4104);
- ak4104_dai.dev = NULL;
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_device_ak4104, &ak4104_dai, 1);
+ if (ret < 0)
+ kfree(ak4104);
return ret;
}
static int __devexit ak4104_spi_remove(struct spi_device *spi)
{
- int ret, val;
- struct ak4104_private *ak4104 = spi_get_drvdata(spi);
-
- val = ak4104_read_reg_cache(&ak4104->codec, AK4104_REG_CONTROL1);
- if (val < 0)
- return val;
-
- /* clear power-up and non-reset bits */
- val &= ~(AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
- ret = ak4104_spi_write(&ak4104->codec, AK4104_REG_CONTROL1, val);
- if (ret < 0)
- return ret;
-
- ak4104_codec = NULL;
- kfree(ak4104);
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
return 0;
}
-static int ak4104_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = ak4104_codec;
- int ret;
-
- /* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */
- socdev->card->codec = codec;
-
- /* Register PCMs */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms\n");
- return ret;
- }
-
- return 0;
-}
-
-static int ak4104_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- snd_soc_free_pcms(socdev);
- return 0;
-};
-
-struct snd_soc_codec_device soc_codec_device_ak4104 = {
- .probe = ak4104_probe,
- .remove = ak4104_remove
-};
-EXPORT_SYMBOL_GPL(soc_codec_device_ak4104);
-
static struct spi_driver ak4104_spi_driver = {
.driver = {
.name = DRV_NAME,
diff --git a/sound/soc/codecs/ak4104.h b/sound/soc/codecs/ak4104.h
deleted file mode 100644
index eb88fe7..0000000
--- a/sound/soc/codecs/ak4104.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef _AK4104_H
-#define _AK4104_H
-
-extern struct snd_soc_dai ak4104_dai;
-extern struct snd_soc_codec_device soc_codec_device_ak4104;
-
-#endif
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index d425367..cd88c8f 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -31,11 +31,11 @@
#define AK4535_VERSION "0.3"
-struct snd_soc_codec_device soc_codec_dev_ak4535;
-
/* codec private data */
struct ak4535_priv {
unsigned int sysclk;
+ enum snd_soc_control_type control_type;
+ void *control_data;
};
/*
@@ -313,8 +313,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
u8 mode2 = ak4535_read_reg_cache(codec, AK4535_MODE2) & ~(0x3 << 5);
int rate = params_rate(params), fs = 256;
@@ -378,14 +377,16 @@
static int ak4535_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- u16 i;
+ u16 i, mute_reg;
switch (level) {
case SND_SOC_BIAS_ON:
- ak4535_mute(codec->dai, 0);
+ mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf;
+ ak4535_write(codec, AK4535_DAC, mute_reg);
break;
case SND_SOC_BIAS_PREPARE:
- ak4535_mute(codec->dai, 1);
+ mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf;
+ ak4535_write(codec, AK4535_DAC, mute_reg | 0x20);
break;
case SND_SOC_BIAS_STANDBY:
i = ak4535_read_reg_cache(codec, AK4535_PM1);
@@ -413,8 +414,8 @@
.set_sysclk = ak4535_set_dai_sysclk,
};
-struct snd_soc_dai ak4535_dai = {
- .name = "AK4535",
+static struct snd_soc_dai_driver ak4535_dai = {
+ .name = "ak4535-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -429,54 +430,27 @@
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
.ops = &ak4535_dai_ops,
};
-EXPORT_SYMBOL_GPL(ak4535_dai);
-static int ak4535_suspend(struct platform_device *pdev, pm_message_t state)
+static int ak4535_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int ak4535_resume(struct platform_device *pdev)
+static int ak4535_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
ak4535_sync(codec);
ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
-/*
- * initialise the AK4535 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int ak4535_init(struct snd_soc_device *socdev)
+static int ak4535_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = socdev->card->codec;
- int ret = 0;
+ struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
- codec->name = "AK4535";
- codec->owner = THIS_MODULE;
- codec->read = ak4535_read_reg_cache;
- codec->write = ak4535_write;
- codec->set_bias_level = ak4535_set_bias_level;
- codec->dai = &ak4535_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(ak4535_reg);
- codec->reg_cache = kmemdup(ak4535_reg, sizeof(ak4535_reg), GFP_KERNEL);
+ printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION);
- if (codec->reg_cache == NULL)
- return -ENOMEM;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "ak4535: failed to create pcms\n");
- goto pcm_err;
- }
+ codec->control_data = ak4535->control_data;
/* power on device */
ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -485,39 +459,55 @@
ARRAY_SIZE(ak4535_snd_controls));
ak4535_add_widgets(codec);
- return ret;
-
-pcm_err:
- kfree(codec->reg_cache);
-
- return ret;
+ return 0;
}
-static struct snd_soc_device *ak4535_socdev;
+/* power down chip */
+static int ak4535_remove(struct snd_soc_codec *codec)
+{
+ ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
+ .probe = ak4535_probe,
+ .remove = ak4535_remove,
+ .suspend = ak4535_suspend,
+ .resume = ak4535_resume,
+ .read = ak4535_read_reg_cache,
+ .write = ak4535_write,
+ .set_bias_level = ak4535_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(ak4535_reg),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = ak4535_reg,
+};
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-
-static int ak4535_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static __devinit int ak4535_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
{
- struct snd_soc_device *socdev = ak4535_socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct ak4535_priv *ak4535;
int ret;
- i2c_set_clientdata(i2c, codec);
- codec->control_data = i2c;
+ ak4535 = kzalloc(sizeof(struct ak4535_priv), GFP_KERNEL);
+ if (ak4535 == NULL)
+ return -ENOMEM;
- ret = ak4535_init(socdev);
+ i2c_set_clientdata(i2c, ak4535);
+ ak4535->control_data = i2c;
+ ak4535->control_type = SND_SOC_I2C;
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_ak4535, &ak4535_dai, 1);
if (ret < 0)
- printk(KERN_ERR "failed to initialise AK4535\n");
-
+ kfree(ak4535);
return ret;
}
-static int ak4535_i2c_remove(struct i2c_client *client)
+static __devexit int ak4535_i2c_remove(struct i2c_client *client)
{
- struct snd_soc_codec *codec = i2c_get_clientdata(client);
- kfree(codec->reg_cache);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -529,138 +519,34 @@
static struct i2c_driver ak4535_i2c_driver = {
.driver = {
- .name = "AK4535 I2C Codec",
+ .name = "ak4535-codec",
.owner = THIS_MODULE,
},
.probe = ak4535_i2c_probe,
- .remove = ak4535_i2c_remove,
+ .remove = __devexit_p(ak4535_i2c_remove),
.id_table = ak4535_i2c_id,
};
-
-static int ak4535_add_i2c_device(struct platform_device *pdev,
- const struct ak4535_setup_data *setup)
-{
- struct i2c_board_info info;
- struct i2c_adapter *adapter;
- struct i2c_client *client;
- int ret;
-
- ret = i2c_add_driver(&ak4535_i2c_driver);
- if (ret != 0) {
- dev_err(&pdev->dev, "can't add i2c driver\n");
- return ret;
- }
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = setup->i2c_address;
- strlcpy(info.type, "ak4535", I2C_NAME_SIZE);
-
- adapter = i2c_get_adapter(setup->i2c_bus);
- if (!adapter) {
- dev_err(&pdev->dev, "can't get i2c adapter %d\n",
- setup->i2c_bus);
- goto err_driver;
- }
-
- client = i2c_new_device(adapter, &info);
- i2c_put_adapter(adapter);
- if (!client) {
- dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
- (unsigned int)info.addr);
- goto err_driver;
- }
-
- return 0;
-
-err_driver:
- i2c_del_driver(&ak4535_i2c_driver);
- return -ENODEV;
-}
#endif
-static int ak4535_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct ak4535_setup_data *setup;
- struct snd_soc_codec *codec;
- struct ak4535_priv *ak4535;
- int ret;
-
- printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION);
-
- setup = socdev->codec_data;
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
-
- ak4535 = kzalloc(sizeof(struct ak4535_priv), GFP_KERNEL);
- if (ak4535 == NULL) {
- kfree(codec);
- return -ENOMEM;
- }
-
- snd_soc_codec_set_drvdata(codec, ak4535);
- socdev->card->codec = codec;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- ak4535_socdev = socdev;
- ret = -ENODEV;
-
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- if (setup->i2c_address) {
- codec->hw_write = (hw_write_t)i2c_master_send;
- ret = ak4535_add_i2c_device(pdev, setup);
- }
-#endif
-
- if (ret != 0) {
- kfree(snd_soc_codec_get_drvdata(codec));
- kfree(codec);
- }
- return ret;
-}
-
-/* power down chip */
-static int ak4535_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec->control_data)
- ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- if (codec->control_data)
- i2c_unregister_device(codec->control_data);
- i2c_del_driver(&ak4535_i2c_driver);
-#endif
- kfree(snd_soc_codec_get_drvdata(codec));
- kfree(codec);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_ak4535 = {
- .probe = ak4535_probe,
- .remove = ak4535_remove,
- .suspend = ak4535_suspend,
- .resume = ak4535_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ak4535);
-
static int __init ak4535_modinit(void)
{
- return snd_soc_register_dai(&ak4535_dai);
+ int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&ak4535_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register AK4535 I2C driver: %d\n",
+ ret);
+ }
+#endif
+ return ret;
}
module_init(ak4535_modinit);
static void __exit ak4535_exit(void)
{
- snd_soc_unregister_dai(&ak4535_dai);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&ak4535_i2c_driver);
+#endif
}
module_exit(ak4535_exit);
diff --git a/sound/soc/codecs/ak4535.h b/sound/soc/codecs/ak4535.h
index c7a5870..0431e5f 100644
--- a/sound/soc/codecs/ak4535.h
+++ b/sound/soc/codecs/ak4535.h
@@ -36,12 +36,4 @@
#define AK4535_CACHEREGNUM 0x10
-struct ak4535_setup_data {
- int i2c_bus;
- unsigned short i2c_address;
-};
-
-extern struct snd_soc_dai ak4535_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ak4535;
-
#endif
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 3d7dc55..90c90b7 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -30,8 +30,6 @@
#include <sound/initval.h>
#include <sound/tlv.h>
-#include "ak4642.h"
-
#define AK4642_VERSION "0.0.1"
#define PW_MGMT1 0x00
@@ -74,6 +72,12 @@
#define AK4642_CACHEREGNUM 0x25
+/* PW_MGMT1*/
+#define PMVCM (1 << 6) /* VCOM Power Management */
+#define PMMIN (1 << 5) /* MIN Input Power Management */
+#define PMDAC (1 << 2) /* DAC Power Management */
+#define PMADL (1 << 0) /* MIC Amp Lch and ADC Lch Power Management */
+
/* PW_MGMT2 */
#define HPMTN (1 << 6)
#define PMHPL (1 << 5)
@@ -85,6 +89,23 @@
#define PMHP_MASK (PMHPL | PMHPR)
#define PMHP PMHP_MASK
+/* PW_MGMT3 */
+#define PMADR (1 << 0) /* MIC L / ADC R Power Management */
+
+/* SG_SL1 */
+#define MINS (1 << 6) /* Switch from MIN to Speaker */
+#define DACL (1 << 4) /* Switch from DAC to Stereo or Receiver */
+#define PMMP (1 << 2) /* MPWR pin Power Management */
+#define MGAIN0 (1 << 0) /* MIC amp gain*/
+
+/* TIMER */
+#define ZTM(param) ((param & 0x3) << 4) /* ALC Zoro Crossing TimeOut */
+#define WTM(param) (((param & 0x4) << 4) | ((param & 0x3) << 2))
+
+/* ALC_CTL1 */
+#define ALC (1 << 5) /* ALC Enable */
+#define LMTH0 (1 << 0) /* ALC Limiter / Recovery Level */
+
/* MD_CTL1 */
#define PLL3 (1 << 7)
#define PLL2 (1 << 6)
@@ -102,7 +123,11 @@
#define FS3 (1 << 5)
#define FS_MASK (FS0 | FS1 | FS2 | FS3)
-struct snd_soc_codec_device soc_codec_dev_ak4642;
+/* MD_CTL3 */
+#define BST1 (1 << 3)
+
+/* MD_CTL4 */
+#define DACH (1 << 0)
/*
* Playback Volume (table 39)
@@ -123,11 +148,11 @@
/* codec private data */
struct ak4642_priv {
- struct snd_soc_codec codec;
+ unsigned int sysclk;
+ enum snd_soc_control_type control_type;
+ void *control_data;
};
-static struct snd_soc_codec *ak4642_codec;
-
/*
* ak4642 register cache
*/
@@ -219,11 +244,12 @@
* This operation came from example code of
* "ASAHI KASEI AK4642" (japanese) manual p97.
*/
- ak4642_write(codec, 0x0f, 0x09);
- ak4642_write(codec, 0x0e, 0x19);
- ak4642_write(codec, 0x09, 0x91);
- ak4642_write(codec, 0x0c, 0x91);
- ak4642_write(codec, 0x00, 0x64);
+ snd_soc_update_bits(codec, MD_CTL4, DACH, DACH);
+ snd_soc_update_bits(codec, MD_CTL3, BST1, BST1);
+ ak4642_write(codec, L_IVC, 0x91); /* volume */
+ ak4642_write(codec, R_IVC, 0x91); /* volume */
+ snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMMIN | PMDAC,
+ PMVCM | PMMIN | PMDAC);
snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP);
snd_soc_update_bits(codec, PW_MGMT2, HPMTN, HPMTN);
} else {
@@ -240,13 +266,12 @@
* This operation came from example code of
* "ASAHI KASEI AK4642" (japanese) manual p94.
*/
- ak4642_write(codec, 0x02, 0x05);
- ak4642_write(codec, 0x06, 0x3c);
- ak4642_write(codec, 0x08, 0xe1);
- ak4642_write(codec, 0x0b, 0x00);
- ak4642_write(codec, 0x07, 0x21);
- ak4642_write(codec, 0x00, 0x41);
- ak4642_write(codec, 0x10, 0x01);
+ ak4642_write(codec, SG_SL1, PMMP | MGAIN0);
+ ak4642_write(codec, TIMER, ZTM(0x3) | WTM(0x3));
+ ak4642_write(codec, ALC_CTL1, ALC | LMTH0);
+ snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMADL,
+ PMVCM | PMADL);
+ snd_soc_update_bits(codec, PW_MGMT3, PMADR, PMADR);
}
return 0;
@@ -262,14 +287,14 @@
/* stop headphone output */
snd_soc_update_bits(codec, PW_MGMT2, HPMTN, 0);
snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, 0);
- ak4642_write(codec, 0x00, 0x40);
- ak4642_write(codec, 0x0e, 0x11);
- ak4642_write(codec, 0x0f, 0x08);
+ snd_soc_update_bits(codec, PW_MGMT1, PMMIN | PMDAC, 0);
+ snd_soc_update_bits(codec, MD_CTL3, BST1, 0);
+ snd_soc_update_bits(codec, MD_CTL4, DACH, 0);
} else {
/* stop stereo input */
- ak4642_write(codec, 0x00, 0x40);
- ak4642_write(codec, 0x10, 0x00);
- ak4642_write(codec, 0x07, 0x01);
+ snd_soc_update_bits(codec, PW_MGMT1, PMADL, 0);
+ snd_soc_update_bits(codec, PW_MGMT3, PMADR, 0);
+ snd_soc_update_bits(codec, ALC_CTL1, ALC, 0);
}
}
@@ -393,8 +418,8 @@
.hw_params = ak4642_dai_hw_params,
};
-struct snd_soc_dai ak4642_dai = {
- .name = "AK4642",
+static struct snd_soc_dai_driver ak4642_dai = {
+ .name = "ak4642-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -410,112 +435,65 @@
.ops = &ak4642_dai_ops,
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(ak4642_dai);
-static int ak4642_resume(struct platform_device *pdev)
+static int ak4642_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
ak4642_sync(codec);
return 0;
}
-/*
- * initialise the AK4642 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int ak4642_init(struct ak4642_priv *ak4642)
+
+static int ak4642_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = &ak4642->codec;
- int ret = 0;
+ struct ak4642_priv *ak4642 = snd_soc_codec_get_drvdata(codec);
- if (ak4642_codec) {
- dev_err(codec->dev, "Another ak4642 is registered\n");
- return -EINVAL;
- }
+ dev_info(codec->dev, "AK4642 Audio Codec %s", AK4642_VERSION);
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, ak4642);
- codec->name = "AK4642";
- codec->owner = THIS_MODULE;
- codec->read = ak4642_read_reg_cache;
- codec->write = ak4642_write;
- codec->dai = &ak4642_dai;
- codec->num_dai = 1;
codec->hw_write = (hw_write_t)i2c_master_send;
- codec->reg_cache_size = ARRAY_SIZE(ak4642_reg);
- codec->reg_cache = kmemdup(ak4642_reg,
- sizeof(ak4642_reg), GFP_KERNEL);
+ codec->control_data = ak4642->control_data;
- if (!codec->reg_cache)
- return -ENOMEM;
+ snd_soc_add_controls(codec, ak4642_snd_controls,
+ ARRAY_SIZE(ak4642_snd_controls));
- ak4642_dai.dev = codec->dev;
- ak4642_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto reg_cache_err;
- }
-
- ret = snd_soc_register_dai(&ak4642_dai);
- if (ret) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- snd_soc_unregister_codec(codec);
- goto reg_cache_err;
- }
-
- return ret;
-
-reg_cache_err:
- kfree(codec->reg_cache);
- codec->reg_cache = NULL;
-
- return ret;
+ return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
+ .probe = ak4642_probe,
+ .resume = ak4642_resume,
+ .read = ak4642_read_reg_cache,
+ .write = ak4642_write,
+ .reg_cache_size = ARRAY_SIZE(ak4642_reg),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = ak4642_reg,
+};
+
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-static int ak4642_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static __devinit int ak4642_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
{
struct ak4642_priv *ak4642;
- struct snd_soc_codec *codec;
int ret;
ak4642 = kzalloc(sizeof(struct ak4642_priv), GFP_KERNEL);
if (!ak4642)
return -ENOMEM;
- codec = &ak4642->codec;
- codec->dev = &i2c->dev;
-
i2c_set_clientdata(i2c, ak4642);
- codec->control_data = i2c;
+ ak4642->control_data = i2c;
+ ak4642->control_type = SND_SOC_I2C;
- ret = ak4642_init(ak4642);
- if (ret < 0) {
- printk(KERN_ERR "failed to initialise AK4642\n");
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_ak4642, &ak4642_dai, 1);
+ if (ret < 0)
kfree(ak4642);
- }
-
return ret;
}
-static int ak4642_i2c_remove(struct i2c_client *client)
+static __devexit int ak4642_i2c_remove(struct i2c_client *client)
{
- struct ak4642_priv *ak4642 = i2c_get_clientdata(client);
-
- snd_soc_unregister_dai(&ak4642_dai);
- snd_soc_unregister_codec(&ak4642->codec);
- kfree(ak4642->codec.reg_cache);
- kfree(ak4642);
- ak4642_codec = NULL;
-
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -528,64 +506,15 @@
static struct i2c_driver ak4642_i2c_driver = {
.driver = {
- .name = "AK4642 I2C Codec",
+ .name = "ak4642-codec",
.owner = THIS_MODULE,
},
.probe = ak4642_i2c_probe,
- .remove = ak4642_i2c_remove,
+ .remove = __devexit_p(ak4642_i2c_remove),
.id_table = ak4642_i2c_id,
};
-
#endif
-static int ak4642_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- int ret;
-
- if (!ak4642_codec) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = ak4642_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "ak4642: failed to create pcms\n");
- goto pcm_err;
- }
-
- snd_soc_add_controls(ak4642_codec, ak4642_snd_controls,
- ARRAY_SIZE(ak4642_snd_controls));
-
- dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION);
- return ret;
-
-pcm_err:
- return ret;
-
-}
-
-/* power down chip */
-static int ak4642_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_ak4642 = {
- .probe = ak4642_probe,
- .remove = ak4642_remove,
- .resume = ak4642_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ak4642);
-
static int __init ak4642_modinit(void)
{
int ret = 0;
diff --git a/sound/soc/codecs/ak4642.h b/sound/soc/codecs/ak4642.h
deleted file mode 100644
index e476833..0000000
--- a/sound/soc/codecs/ak4642.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * ak4642.h -- AK4642 Soc Audio driver
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * Based on ak4535.c
- *
- * 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 _AK4642_H
-#define _AK4642_H
-
-extern struct snd_soc_dai ak4642_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ak4642;
-
-#endif
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c
index 8756693..24f5f49 100644
--- a/sound/soc/codecs/ak4671.c
+++ b/sound/soc/codecs/ak4671.c
@@ -23,11 +23,11 @@
#include "ak4671.h"
-static struct snd_soc_codec *ak4671_codec;
/* codec private data */
struct ak4671_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
+ void *control_data;
u8 reg_cache[AK4671_CACHEREGNUM];
};
@@ -619,8 +619,8 @@
.set_fmt = ak4671_set_dai_fmt,
};
-struct snd_soc_dai ak4671_dai = {
- .name = "AK4671",
+static struct snd_soc_dai_driver ak4671_dai = {
+ .name = "ak4671-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -635,27 +635,18 @@
.formats = AK4671_FORMATS,},
.ops = &ak4671_dai_ops,
};
-EXPORT_SYMBOL_GPL(ak4671_dai);
-static int ak4671_probe(struct platform_device *pdev)
+static int ak4671_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
+ struct ak4671_priv *ak4671 = snd_soc_codec_get_drvdata(codec);
+ int ret;
- if (ak4671_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
+ codec->hw_write = (hw_write_t)i2c_master_send;
- socdev->card->codec = ak4671_codec;
- codec = ak4671_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4671->control_type);
if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
}
snd_soc_add_controls(codec, ak4671_snd_controls,
@@ -665,121 +656,48 @@
ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return ret;
-
-pcm_err:
- return ret;
}
-static int ak4671_remove(struct platform_device *pdev)
+static int ak4671_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
+ ak4671_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_ak4671 = {
+static struct snd_soc_codec_driver soc_codec_dev_ak4671 = {
.probe = ak4671_probe,
.remove = ak4671_remove,
+ .set_bias_level = ak4671_set_bias_level,
+ .reg_cache_size = AK4671_CACHEREGNUM,
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = ak4671_reg,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ak4671);
-
-static int ak4671_register(struct ak4671_priv *ak4671,
- enum snd_soc_control_type control)
-{
- int ret;
- struct snd_soc_codec *codec = &ak4671->codec;
-
- if (ak4671_codec) {
- dev_err(codec->dev, "Another AK4671 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, ak4671);
- codec->name = "AK4671";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = ak4671_set_bias_level;
- codec->dai = &ak4671_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = AK4671_CACHEREGNUM;
- codec->reg_cache = &ak4671->reg_cache;
-
- memcpy(codec->reg_cache, ak4671_reg, sizeof(ak4671_reg));
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, control);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
- }
-
- ak4671_dai.dev = codec->dev;
- ak4671_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dai(&ak4671_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
-
- return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- kfree(ak4671);
- return ret;
-}
-
-static void ak4671_unregister(struct ak4671_priv *ak4671)
-{
- ak4671_set_bias_level(&ak4671->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dai(&ak4671_dai);
- snd_soc_unregister_codec(&ak4671->codec);
- kfree(ak4671);
- ak4671_codec = NULL;
-}
static int __devinit ak4671_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct ak4671_priv *ak4671;
- struct snd_soc_codec *codec;
+ int ret;
ak4671 = kzalloc(sizeof(struct ak4671_priv), GFP_KERNEL);
if (ak4671 == NULL)
return -ENOMEM;
- codec = &ak4671->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
-
i2c_set_clientdata(client, ak4671);
- codec->control_data = client;
+ ak4671->control_data = client;
+ ak4671->control_type = SND_SOC_I2C;
- codec->dev = &client->dev;
-
- return ak4671_register(ak4671, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&client->dev,
+ &soc_codec_dev_ak4671, &ak4671_dai, 1);
+ if (ret < 0)
+ kfree(ak4671);
+ return ret;
}
static __devexit int ak4671_i2c_remove(struct i2c_client *client)
{
- struct ak4671_priv *ak4671 = i2c_get_clientdata(client);
-
- ak4671_unregister(ak4671);
-
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -791,7 +709,7 @@
static struct i2c_driver ak4671_i2c_driver = {
.driver = {
- .name = "ak4671",
+ .name = "ak4671-codec",
.owner = THIS_MODULE,
},
.probe = ak4671_i2c_probe,
diff --git a/sound/soc/codecs/ak4671.h b/sound/soc/codecs/ak4671.h
index e2fad96..61cb7ab 100644
--- a/sound/soc/codecs/ak4671.h
+++ b/sound/soc/codecs/ak4671.h
@@ -150,7 +150,4 @@
/* AK4671_LOUT2_POWER_MANAGEMENT (0x10) Fields */
#define AK4671_MUTEN 0x04
-extern struct snd_soc_dai ak4671_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ak4671;
-
#endif
diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c
index a320fb5..8236439 100644
--- a/sound/soc/codecs/cq93vc.c
+++ b/sound/soc/codecs/cq93vc.c
@@ -30,6 +30,7 @@
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/mfd/davinci_voicecodec.h>
+#include <linux/spi/spi.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -41,8 +42,6 @@
#include <mach/dm365.h>
-#include "cq93vc.h"
-
static inline unsigned int cq93vc_read(struct snd_soc_codec *codec,
unsigned int reg)
{
@@ -130,8 +129,8 @@
.set_sysclk = cq93vc_set_dai_sysclk,
};
-struct snd_soc_dai cq93vc_dai = {
- .name = "CQ93VC",
+static struct snd_soc_dai_driver cq93vc_dai = {
+ .name = "cq93vc-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -146,36 +145,20 @@
.formats = CQ93VC_FORMATS,},
.ops = &cq93vc_dai_ops,
};
-EXPORT_SYMBOL_GPL(cq93vc_dai);
-static int cq93vc_resume(struct platform_device *pdev)
+static int cq93vc_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
-static struct snd_soc_codec *cq93vc_codec;
-
-static int cq93vc_probe(struct platform_device *pdev)
+static int cq93vc_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct device *dev = &pdev->dev;
- struct snd_soc_codec *codec;
- int ret;
+ struct davinci_vc *davinci_vc = codec->dev->platform_data;
- socdev->card->codec = cq93vc_codec;
- codec = socdev->card->codec;
-
- /* Register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(dev, "%s: failed to create pcms\n", pdev->name);
- return ret;
- }
+ davinci_vc->cq93vc.codec = codec;
+ codec->control_data = davinci_vc;
/* Set controls */
snd_soc_add_controls(codec, cq93vc_snd_controls,
@@ -187,108 +170,51 @@
return 0;
}
-static int cq93vc_remove(struct platform_device *pdev)
+static int cq93vc_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
+ cq93vc_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_cq93vc = {
+static struct snd_soc_codec_driver soc_codec_dev_cq93vc = {
+ .read = cq93vc_read,
+ .write = cq93vc_write,
+ .set_bias_level = cq93vc_set_bias_level,
.probe = cq93vc_probe,
.remove = cq93vc_remove,
.resume = cq93vc_resume,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_cq93vc);
-static __init int cq93vc_codec_probe(struct platform_device *pdev)
+static int cq93vc_platform_probe(struct platform_device *pdev)
{
- struct davinci_vc *davinci_vc = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret;
-
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL) {
- dev_dbg(davinci_vc->dev,
- "could not allocate memory for codec data\n");
- return -ENOMEM;
- }
-
- davinci_vc->cq93vc.codec = codec;
-
- cq93vc_dai.dev = &pdev->dev;
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
- codec->dev = &pdev->dev;
- codec->name = "CQ93VC";
- codec->owner = THIS_MODULE;
- codec->read = cq93vc_read;
- codec->write = cq93vc_write;
- codec->set_bias_level = cq93vc_set_bias_level;
- codec->dai = &cq93vc_dai;
- codec->num_dai = 1;
- codec->control_data = davinci_vc;
-
- cq93vc_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret) {
- dev_err(davinci_vc->dev, "failed to register codec\n");
- goto fail1;
- }
-
- ret = snd_soc_register_dai(&cq93vc_dai);
- if (ret) {
- dev_err(davinci_vc->dev, "could register dai\n");
- goto fail2;
- }
- return 0;
-
-fail2:
- snd_soc_unregister_codec(codec);
-
-fail1:
- kfree(codec);
- cq93vc_codec = NULL;
-
- return ret;
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_cq93vc, &cq93vc_dai, 1);
}
-static int __devexit cq93vc_codec_remove(struct platform_device *pdev)
+static int cq93vc_platform_remove(struct platform_device *pdev)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- snd_soc_unregister_dai(&cq93vc_dai);
- snd_soc_unregister_codec(&codec);
-
- kfree(codec);
- cq93vc_codec = NULL;
-
+ snd_soc_unregister_codec(&pdev->dev);
return 0;
}
static struct platform_driver cq93vc_codec_driver = {
.driver = {
- .name = "cq93vc",
- .owner = THIS_MODULE,
- },
- .probe = cq93vc_codec_probe,
- .remove = __devexit_p(cq93vc_codec_remove),
+ .name = "cq93vc-codec",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = cq93vc_platform_probe,
+ .remove = __devexit_p(cq93vc_platform_remove),
};
-static __init int cq93vc_init(void)
+static int __init cq93vc_init(void)
{
- return platform_driver_probe(&cq93vc_codec_driver, cq93vc_codec_probe);
+ return platform_driver_register(&cq93vc_codec_driver);
}
module_init(cq93vc_init);
-static __exit void cq93vc_exit(void)
+static void __exit cq93vc_exit(void)
{
platform_driver_unregister(&cq93vc_codec_driver);
}
diff --git a/sound/soc/codecs/cq93vc.h b/sound/soc/codecs/cq93vc.h
deleted file mode 100644
index 845b196..0000000
--- a/sound/soc/codecs/cq93vc.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * ALSA SoC CQ0093 Voice Codec Driver for DaVinci platforms
- *
- * Copyright (C) 2010 Texas Instruments, Inc
- *
- * Author: Miguel Aguilar <miguel.aguilar@ridgerun.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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 _CQ93VC_H
-#define _CQ93VC_H
-
-extern struct snd_soc_dai cq93vc_dai;
-extern struct snd_soc_codec_device soc_codec_dev_cq93vc;
-
-#endif
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 30d9492..6d4bdc6 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -31,8 +31,6 @@
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
-#include "cs4270.h"
-
/*
* The codec isn't really big-endian or little-endian, since the I2S
* interface requires data to be sent serially with the MSbit first.
@@ -114,7 +112,8 @@
/* Private data for the CS4270 */
struct cs4270_private {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
+ void *control_data;
u8 reg_cache[CS4270_NUMREGS];
unsigned int mclk; /* Input frequency of the MCLK pin */
unsigned int mode; /* The mode (I2S or left-justified) */
@@ -212,44 +211,8 @@
{
struct snd_soc_codec *codec = codec_dai->codec;
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
- unsigned int rates = 0;
- unsigned int rate_min = -1;
- unsigned int rate_max = 0;
- unsigned int i;
cs4270->mclk = freq;
-
- if (cs4270->mclk) {
- for (i = 0; i < NUM_MCLK_RATIOS; i++) {
- unsigned int rate = freq / cs4270_mode_ratios[i].ratio;
- rates |= snd_pcm_rate_to_rate_bit(rate);
- if (rate < rate_min)
- rate_min = rate;
- if (rate > rate_max)
- rate_max = rate;
- }
- /* FIXME: soc should support a rate list */
- rates &= ~SNDRV_PCM_RATE_KNOT;
-
- if (!rates) {
- dev_err(codec->dev, "could not find a valid sample rate\n");
- return -EINVAL;
- }
- } else {
- /* enable all possible rates */
- rates = SNDRV_PCM_RATE_8000_192000;
- rate_min = 8000;
- rate_max = 192000;
- }
-
- codec_dai->playback.rates = rates;
- codec_dai->playback.rate_min = rate_min;
- codec_dai->playback.rate_max = rate_max;
-
- codec_dai->capture.rates = rates;
- codec_dai->capture.rate_min = rate_min;
- codec_dai->capture.rate_max = rate_max;
-
return 0;
}
@@ -410,8 +373,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
int ret;
unsigned int i;
@@ -549,19 +511,6 @@
snd_soc_get_volsw, cs4270_soc_put_mute),
};
-/*
- * cs4270_codec - global variable to store codec for the ASoC probe function
- *
- * If struct i2c_driver had a private_data field, we wouldn't need to use
- * cs4270_codec. This is the only way to pass the codec structure from
- * cs4270_i2c_probe() to cs4270_probe(). Unfortunately, there is no good
- * way to synchronize these two functions. cs4270_i2c_probe() can be called
- * multiple times before cs4270_probe() is called even once. So for now, we
- * also only allow cs4270_i2c_probe() to be run once. That means that we do
- * not support more than one cs4270 device in the system, at least for now.
- */
-static struct snd_soc_codec *cs4270_codec;
-
static struct snd_soc_dai_ops cs4270_dai_ops = {
.hw_params = cs4270_hw_params,
.set_sysclk = cs4270_set_dai_sysclk,
@@ -569,25 +518,28 @@
.digital_mute = cs4270_dai_mute,
};
-struct snd_soc_dai cs4270_dai = {
- .name = "cs4270",
+static struct snd_soc_dai_driver cs4270_dai = {
+ .name = "cs4270-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
- .rates = 0,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 4000,
+ .rate_max = 216000,
.formats = CS4270_FORMATS,
},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 2,
- .rates = 0,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 4000,
+ .rate_max = 216000,
.formats = CS4270_FORMATS,
},
.ops = &cs4270_dai_ops,
};
-EXPORT_SYMBOL_GPL(cs4270_dai);
/**
* cs4270_probe - ASoC probe function
@@ -596,153 +548,19 @@
* This function is called when ASoC has all the pieces it needs to
* instantiate a sound driver.
*/
-static int cs4270_probe(struct platform_device *pdev)
+static int cs4270_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = cs4270_codec;
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
- int i, ret;
+ int i, ret, reg;
- /* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */
- socdev->card->codec = codec;
-
- /* Register PCMs */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms\n");
- return ret;
- }
-
- /* Add the non-DAPM controls */
- ret = snd_soc_add_controls(codec, cs4270_snd_controls,
- ARRAY_SIZE(cs4270_snd_controls));
- if (ret < 0) {
- dev_err(codec->dev, "failed to add controls\n");
- goto error_free_pcms;
- }
-
- /* get the power supply regulators */
- for (i = 0; i < ARRAY_SIZE(supply_names); i++)
- cs4270->supplies[i].supply = supply_names[i];
-
- ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(cs4270->supplies),
- cs4270->supplies);
- if (ret < 0)
- goto error_free_pcms;
-
- ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
- cs4270->supplies);
- if (ret < 0)
- goto error_free_regulators;
-
- return 0;
-
-error_free_regulators:
- regulator_bulk_free(ARRAY_SIZE(cs4270->supplies),
- cs4270->supplies);
-
-error_free_pcms:
- snd_soc_free_pcms(socdev);
-
- return ret;
-}
-
-/**
- * cs4270_remove - ASoC remove function
- * @pdev: platform device
- *
- * This function is the counterpart to cs4270_probe().
- */
-static int cs4270_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = cs4270_codec;
- struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
-
- snd_soc_free_pcms(socdev);
- regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
- regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
-
- return 0;
-};
-
-/**
- * cs4270_i2c_probe - initialize the I2C interface of the CS4270
- * @i2c_client: the I2C client object
- * @id: the I2C device ID (ignored)
- *
- * This function is called whenever the I2C subsystem finds a device that
- * matches the device ID given via a prior call to i2c_add_driver().
- */
-static int cs4270_i2c_probe(struct i2c_client *i2c_client,
- const struct i2c_device_id *id)
-{
- struct snd_soc_codec *codec;
- struct cs4270_private *cs4270;
- unsigned int reg;
- int ret;
-
- /* For now, we only support one cs4270 device in the system. See the
- * comment for cs4270_codec.
- */
- if (cs4270_codec) {
- dev_err(&i2c_client->dev, "ignoring CS4270 at addr %X\n",
- i2c_client->addr);
- dev_err(&i2c_client->dev, "only one per board allowed\n");
- /* Should we return something other than ENODEV here? */
- return -ENODEV;
- }
-
- /* Verify that we have a CS4270 */
-
- ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID);
- if (ret < 0) {
- dev_err(&i2c_client->dev, "failed to read i2c at addr %X\n",
- i2c_client->addr);
- return ret;
- }
- /* The top four bits of the chip ID should be 1100. */
- if ((ret & 0xF0) != 0xC0) {
- dev_err(&i2c_client->dev, "device at addr %X is not a CS4270\n",
- i2c_client->addr);
- return -ENODEV;
- }
-
- dev_info(&i2c_client->dev, "found device at i2c address %X\n",
- i2c_client->addr);
- dev_info(&i2c_client->dev, "hardware revision %X\n", ret & 0xF);
-
- /* Allocate enough space for the snd_soc_codec structure
- and our private data together. */
- cs4270 = kzalloc(sizeof(struct cs4270_private), GFP_KERNEL);
- if (!cs4270) {
- dev_err(&i2c_client->dev, "could not allocate codec\n");
- return -ENOMEM;
- }
- codec = &cs4270->codec;
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->dev = &i2c_client->dev;
- codec->name = "CS4270";
- codec->owner = THIS_MODULE;
- codec->dai = &cs4270_dai;
- codec->num_dai = 1;
- snd_soc_codec_set_drvdata(codec, cs4270);
- codec->control_data = i2c_client;
- codec->read = cs4270_read_reg_cache;
- codec->write = cs4270_i2c_write;
- codec->reg_cache = cs4270->reg_cache;
- codec->reg_cache_size = CS4270_NUMREGS;
+ codec->control_data = cs4270->control_data;
/* The I2C interface is set up, so pre-fill our register cache */
ret = cs4270_fill_cache(codec);
if (ret < 0) {
- dev_err(&i2c_client->dev, "failed to fill register cache\n");
- goto error_free_codec;
+ dev_err(codec->dev, "failed to fill register cache\n");
+ return ret;
}
/* Disable auto-mute. This feature appears to be buggy. In some
@@ -755,7 +573,7 @@
reg &= ~CS4270_MUTE_AUTO;
ret = cs4270_i2c_write(codec, CS4270_MUTE, reg);
if (ret < 0) {
- dev_err(&i2c_client->dev, "i2c write failed\n");
+ dev_err(codec->dev, "i2c write failed\n");
return ret;
}
@@ -769,65 +587,56 @@
reg &= ~(CS4270_TRANS_SOFT | CS4270_TRANS_ZERO);
ret = cs4270_i2c_write(codec, CS4270_TRANS, reg);
if (ret < 0) {
- dev_err(&i2c_client->dev, "i2c write failed\n");
+ dev_err(codec->dev, "i2c write failed\n");
return ret;
}
- /* Initialize the DAI. Normally, we'd prefer to have a kmalloc'd DAI
- * structure for each CS4270 device, but the machine driver needs to
- * have a pointer to the DAI structure, so for now it must be a global
- * variable.
- */
- cs4270_dai.dev = &i2c_client->dev;
-
- /* Register the DAI. If all the other ASoC driver have already
- * registered, then this will call our probe function, so
- * cs4270_codec needs to be ready.
- */
- cs4270_codec = codec;
- ret = snd_soc_register_dai(&cs4270_dai);
+ /* Add the non-DAPM controls */
+ ret = snd_soc_add_controls(codec, cs4270_snd_controls,
+ ARRAY_SIZE(cs4270_snd_controls));
if (ret < 0) {
- dev_err(&i2c_client->dev, "failed to register DAIe\n");
- goto error_free_codec;
+ dev_err(codec->dev, "failed to add controls\n");
+ return ret;
}
- i2c_set_clientdata(i2c_client, cs4270);
+ /* get the power supply regulators */
+ for (i = 0; i < ARRAY_SIZE(supply_names); i++)
+ cs4270->supplies[i].supply = supply_names[i];
+
+ ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(cs4270->supplies),
+ cs4270->supplies);
+ if (ret < 0)
+ return ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
+ cs4270->supplies);
+ if (ret < 0)
+ goto error_free_regulators;
return 0;
-error_free_codec:
- kfree(cs4270);
- cs4270_codec = NULL;
- cs4270_dai.dev = NULL;
+error_free_regulators:
+ regulator_bulk_free(ARRAY_SIZE(cs4270->supplies),
+ cs4270->supplies);
return ret;
}
/**
- * cs4270_i2c_remove - remove an I2C device
- * @i2c_client: the I2C client object
+ * cs4270_remove - ASoC remove function
+ * @pdev: platform device
*
- * This function is the counterpart to cs4270_i2c_probe().
+ * This function is the counterpart to cs4270_probe().
*/
-static int cs4270_i2c_remove(struct i2c_client *i2c_client)
+static int cs4270_remove(struct snd_soc_codec *codec)
{
- struct cs4270_private *cs4270 = i2c_get_clientdata(i2c_client);
+ struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
- kfree(cs4270);
- cs4270_codec = NULL;
- cs4270_dai.dev = NULL;
+ regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
+ regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
return 0;
-}
-
-/*
- * cs4270_id - I2C device IDs supported by this driver
- */
-static struct i2c_device_id cs4270_id[] = {
- {"cs4270", 0},
- {}
};
-MODULE_DEVICE_TABLE(i2c, cs4270_id);
#ifdef CONFIG_PM
@@ -840,9 +649,8 @@
* and all registers are written back to the hardware when resuming.
*/
-static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg)
+static int cs4270_soc_suspend(struct snd_soc_codec *codec, pm_message_t mesg)
{
- struct snd_soc_codec *codec = cs4270_codec;
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
int reg, ret;
@@ -860,9 +668,8 @@
return 0;
}
-static int cs4270_soc_resume(struct platform_device *pdev)
+static int cs4270_soc_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = cs4270_codec;
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
struct i2c_client *i2c_client = codec->control_data;
int reg;
@@ -896,6 +703,95 @@
#endif /* CONFIG_PM */
/*
+ * ASoC codec device structure
+ *
+ * Assign this variable to the codec_dev field of the machine driver's
+ * snd_soc_device structure.
+ */
+static struct snd_soc_codec_driver soc_codec_device_cs4270 = {
+ .probe = cs4270_probe,
+ .remove = cs4270_remove,
+ .suspend = cs4270_soc_suspend,
+ .resume = cs4270_soc_resume,
+ .read = cs4270_read_reg_cache,
+ .write = cs4270_i2c_write,
+ .reg_cache_size = CS4270_NUMREGS,
+ .reg_word_size = sizeof(u8),
+};
+
+/**
+ * cs4270_i2c_probe - initialize the I2C interface of the CS4270
+ * @i2c_client: the I2C client object
+ * @id: the I2C device ID (ignored)
+ *
+ * This function is called whenever the I2C subsystem finds a device that
+ * matches the device ID given via a prior call to i2c_add_driver().
+ */
+static int cs4270_i2c_probe(struct i2c_client *i2c_client,
+ const struct i2c_device_id *id)
+{
+ struct cs4270_private *cs4270;
+ int ret;
+
+ /* Verify that we have a CS4270 */
+
+ ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID);
+ if (ret < 0) {
+ dev_err(&i2c_client->dev, "failed to read i2c at addr %X\n",
+ i2c_client->addr);
+ return ret;
+ }
+ /* The top four bits of the chip ID should be 1100. */
+ if ((ret & 0xF0) != 0xC0) {
+ dev_err(&i2c_client->dev, "device at addr %X is not a CS4270\n",
+ i2c_client->addr);
+ return -ENODEV;
+ }
+
+ dev_info(&i2c_client->dev, "found device at i2c address %X\n",
+ i2c_client->addr);
+ dev_info(&i2c_client->dev, "hardware revision %X\n", ret & 0xF);
+
+ cs4270 = kzalloc(sizeof(struct cs4270_private), GFP_KERNEL);
+ if (!cs4270) {
+ dev_err(&i2c_client->dev, "could not allocate codec\n");
+ return -ENOMEM;
+ }
+
+ i2c_set_clientdata(i2c_client, cs4270);
+ cs4270->control_data = i2c_client;
+ cs4270->control_type = SND_SOC_I2C;
+
+ ret = snd_soc_register_codec(&i2c_client->dev,
+ &soc_codec_device_cs4270, &cs4270_dai, 1);
+ if (ret < 0)
+ kfree(cs4270);
+ return ret;
+}
+
+/**
+ * cs4270_i2c_remove - remove an I2C device
+ * @i2c_client: the I2C client object
+ *
+ * This function is the counterpart to cs4270_i2c_probe().
+ */
+static int cs4270_i2c_remove(struct i2c_client *i2c_client)
+{
+ snd_soc_unregister_codec(&i2c_client->dev);
+ kfree(i2c_get_clientdata(i2c_client));
+ return 0;
+}
+
+/*
+ * cs4270_id - I2C device IDs supported by this driver
+ */
+static struct i2c_device_id cs4270_id[] = {
+ {"cs4270", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, cs4270_id);
+
+/*
* cs4270_i2c_driver - I2C device identification
*
* This structure tells the I2C subsystem how to identify and support a
@@ -903,7 +799,7 @@
*/
static struct i2c_driver cs4270_i2c_driver = {
.driver = {
- .name = "cs4270",
+ .name = "cs4270-codec",
.owner = THIS_MODULE,
},
.id_table = cs4270_id,
@@ -911,20 +807,6 @@
.remove = cs4270_i2c_remove,
};
-/*
- * ASoC codec device structure
- *
- * Assign this variable to the codec_dev field of the machine driver's
- * snd_soc_device structure.
- */
-struct snd_soc_codec_device soc_codec_device_cs4270 = {
- .probe = cs4270_probe,
- .remove = cs4270_remove,
- .suspend = cs4270_soc_suspend,
- .resume = cs4270_soc_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_device_cs4270);
-
static int __init cs4270_init(void)
{
pr_info("Cirrus Logic CS4270 ALSA SoC Codec Driver\n");
diff --git a/sound/soc/codecs/cs4270.h b/sound/soc/codecs/cs4270.h
deleted file mode 100644
index adc6cd9..0000000
--- a/sound/soc/codecs/cs4270.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Cirrus Logic CS4270 ALSA SoC Codec Driver
- *
- * Author: Timur Tabi <timur@freescale.com>
- *
- * Copyright 2007 Freescale Semiconductor, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifndef _CS4270_H
-#define _CS4270_H
-
-/*
- * The ASoC codec DAI structure for the CS4270. Assign this structure to
- * the .codec_dai field of your machine driver's snd_soc_dai_link structure.
- */
-extern struct snd_soc_dai cs4270_dai;
-
-/*
- * The ASoC codec device structure for the CS4270. Assign this structure
- * to the .codec_dev field of your machine driver's snd_soc_device
- * structure.
- */
-extern struct snd_soc_codec_device soc_codec_device_cs4270;
-
-#endif
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index dd9b855..cb086ea 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -42,15 +42,14 @@
};
struct cs42l51_private {
+ enum snd_soc_control_type control_type;
+ void *control_data;
unsigned int mclk;
unsigned int audio_mode; /* The mode (I2S or left-justified) */
enum master_slave_mode func;
- struct snd_soc_codec codec;
u8 reg_cache[CS42L51_NUMREGS];
};
-static struct snd_soc_codec *cs42l51_codec;
-
#define CS42L51_FORMATS ( \
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
@@ -75,134 +74,6 @@
return 0;
}
-static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
- const struct i2c_device_id *id)
-{
- struct snd_soc_codec *codec;
- struct cs42l51_private *cs42l51;
- int ret = 0;
- int reg;
-
- if (cs42l51_codec)
- return -EBUSY;
-
- /* Verify that we have a CS42L51 */
- ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID);
- if (ret < 0) {
- dev_err(&i2c_client->dev, "failed to read I2C\n");
- goto error;
- }
-
- if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
- (ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
- dev_err(&i2c_client->dev, "Invalid chip id\n");
- ret = -ENODEV;
- goto error;
- }
-
- dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n",
- ret & 7);
-
- cs42l51 = kzalloc(sizeof(struct cs42l51_private), GFP_KERNEL);
- if (!cs42l51) {
- dev_err(&i2c_client->dev, "could not allocate codec\n");
- return -ENOMEM;
- }
- codec = &cs42l51->codec;
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->dev = &i2c_client->dev;
- codec->name = "CS42L51";
- codec->owner = THIS_MODULE;
- codec->dai = &cs42l51_dai;
- codec->num_dai = 1;
- snd_soc_codec_set_drvdata(codec, cs42l51);
-
- codec->control_data = i2c_client;
- codec->reg_cache = cs42l51->reg_cache;
- codec->reg_cache_size = CS42L51_NUMREGS;
- i2c_set_clientdata(i2c_client, codec);
-
- ret = cs42l51_fill_cache(codec);
- if (ret < 0) {
- dev_err(&i2c_client->dev, "failed to fill register cache\n");
- goto error_alloc;
- }
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
- if (ret < 0) {
- dev_err(&i2c_client->dev, "Failed to set cache I/O: %d\n", ret);
- goto error_alloc;
- }
-
- /*
- * DAC configuration
- * - Use signal processor
- * - auto mute
- * - vol changes immediate
- * - no de-emphasize
- */
- reg = CS42L51_DAC_CTL_DATA_SEL(1)
- | CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0);
- ret = snd_soc_write(codec, CS42L51_DAC_CTL, reg);
- if (ret < 0)
- goto error_alloc;
-
- cs42l51_dai.dev = codec->dev;
- cs42l51_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto error_alloc;
- }
-
- ret = snd_soc_register_dai(&cs42l51_dai);
- if (ret < 0) {
- dev_err(&i2c_client->dev, "failed to register DAIe\n");
- goto error_reg;
- }
-
- return 0;
-
-error_reg:
- snd_soc_unregister_codec(codec);
-error_alloc:
- kfree(cs42l51);
-error:
- return ret;
-}
-
-static int cs42l51_i2c_remove(struct i2c_client *client)
-{
- struct cs42l51_private *cs42l51 = i2c_get_clientdata(client);
- snd_soc_unregister_dai(&cs42l51_dai);
- snd_soc_unregister_codec(cs42l51_codec);
- cs42l51_codec = NULL;
- kfree(cs42l51);
- return 0;
-}
-
-
-static const struct i2c_device_id cs42l51_id[] = {
- {"cs42l51", 0},
- {}
-};
-MODULE_DEVICE_TABLE(i2c, cs42l51_id);
-
-static struct i2c_driver cs42l51_i2c_driver = {
- .driver = {
- .name = "CS42L51 I2C",
- .owner = THIS_MODULE,
- },
- .id_table = cs42l51_id,
- .probe = cs42l51_i2c_probe,
- .remove = cs42l51_i2c_remove,
-};
-
static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -484,51 +355,8 @@
{
struct snd_soc_codec *codec = codec_dai->codec;
struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
- struct cs42l51_ratios *ratios = NULL;
- int nr_ratios = 0;
- unsigned int rates = 0;
- unsigned int rate_min = -1;
- unsigned int rate_max = 0;
- int i;
cs42l51->mclk = freq;
-
- switch (cs42l51->func) {
- case MODE_MASTER:
- return -EINVAL;
- case MODE_SLAVE:
- ratios = slave_ratios;
- nr_ratios = ARRAY_SIZE(slave_ratios);
- break;
- case MODE_SLAVE_AUTO:
- ratios = slave_auto_ratios;
- nr_ratios = ARRAY_SIZE(slave_auto_ratios);
- break;
- }
-
- for (i = 0; i < nr_ratios; i++) {
- unsigned int rate = freq / ratios[i].ratio;
- rates |= snd_pcm_rate_to_rate_bit(rate);
- if (rate < rate_min)
- rate_min = rate;
- if (rate > rate_max)
- rate_max = rate;
- }
- rates &= ~SNDRV_PCM_RATE_KNOT;
-
- if (!rates) {
- dev_err(codec->dev, "could not find a valid sample rate\n");
- return -EINVAL;
- }
-
- codec_dai->playback.rates = rates;
- codec_dai->playback.rate_min = rate_min;
- codec_dai->playback.rate_max = rate_max;
-
- codec_dai->capture.rates = rates;
- codec_dai->capture.rate_min = rate_min;
- codec_dai->capture.rate_max = rate_max;
-
return 0;
}
@@ -537,8 +365,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
int ret;
unsigned int i;
@@ -670,8 +497,8 @@
.digital_mute = cs42l51_dai_mute,
};
-struct snd_soc_dai cs42l51_dai = {
- .name = "CS42L51 HiFi",
+static struct snd_soc_dai_driver cs42l51_dai = {
+ .name = "cs42l51-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -688,30 +515,39 @@
},
.ops = &cs42l51_dai_ops,
};
-EXPORT_SYMBOL_GPL(cs42l51_dai);
-
-static int cs42l51_probe(struct platform_device *pdev)
+static int cs42l51_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
+ struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
+ int ret, reg;
- if (!cs42l51_codec) {
- dev_err(&pdev->dev, "CS42L51 codec not yet registered\n");
- return -EINVAL;
- }
+ codec->control_data = cs42l51->control_data;
- socdev->card->codec = cs42l51_codec;
- codec = socdev->card->codec;
-
- /* Register PCMs */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ ret = cs42l51_fill_cache(codec);
if (ret < 0) {
- dev_err(&pdev->dev, "failed to create PCMs\n");
+ dev_err(codec->dev, "failed to fill register cache\n");
return ret;
}
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, cs42l51->control_type);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * DAC configuration
+ * - Use signal processor
+ * - auto mute
+ * - vol changes immediate
+ * - no de-emphasize
+ */
+ reg = CS42L51_DAC_CTL_DATA_SEL(1)
+ | CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0);
+ ret = snd_soc_write(codec, CS42L51_DAC_CTL, reg);
+ if (ret < 0)
+ return ret;
+
snd_soc_add_controls(codec, cs42l51_snd_controls,
ARRAY_SIZE(cs42l51_snd_controls));
snd_soc_dapm_new_controls(codec, cs42l51_dapm_widgets,
@@ -722,22 +558,77 @@
return 0;
}
+static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
+ .probe = cs42l51_probe,
+ .reg_cache_size = CS42L51_NUMREGS,
+ .reg_word_size = sizeof(u8),
+};
-static int cs42l51_remove(struct platform_device *pdev)
+static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
+ const struct i2c_device_id *id)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct cs42l51_private *cs42l51;
+ int ret;
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
+ /* Verify that we have a CS42L51 */
+ ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID);
+ if (ret < 0) {
+ dev_err(&i2c_client->dev, "failed to read I2C\n");
+ goto error;
+ }
+ if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
+ (ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
+ dev_err(&i2c_client->dev, "Invalid chip id\n");
+ ret = -ENODEV;
+ goto error;
+ }
+
+ dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n",
+ ret & 7);
+
+ cs42l51 = kzalloc(sizeof(struct cs42l51_private), GFP_KERNEL);
+ if (!cs42l51) {
+ dev_err(&i2c_client->dev, "could not allocate codec\n");
+ return -ENOMEM;
+ }
+
+ i2c_set_clientdata(i2c_client, cs42l51);
+ cs42l51->control_data = i2c_client;
+ cs42l51->control_type = SND_SOC_I2C;
+
+ ret = snd_soc_register_codec(&i2c_client->dev,
+ &soc_codec_device_cs42l51, &cs42l51_dai, 1);
+ if (ret < 0)
+ kfree(cs42l51);
+error:
+ return ret;
+}
+
+static int cs42l51_i2c_remove(struct i2c_client *client)
+{
+ struct cs42l51_private *cs42l51 = i2c_get_clientdata(client);
+
+ snd_soc_unregister_codec(&client->dev);
+ kfree(cs42l51);
return 0;
}
-struct snd_soc_codec_device soc_codec_device_cs42l51 = {
- .probe = cs42l51_probe,
- .remove = cs42l51_remove
+static const struct i2c_device_id cs42l51_id[] = {
+ {"cs42l51", 0},
+ {}
};
-EXPORT_SYMBOL_GPL(soc_codec_device_cs42l51);
+MODULE_DEVICE_TABLE(i2c, cs42l51_id);
+
+static struct i2c_driver cs42l51_i2c_driver = {
+ .driver = {
+ .name = "cs42l51-codec",
+ .owner = THIS_MODULE,
+ },
+ .id_table = cs42l51_id,
+ .probe = cs42l51_i2c_probe,
+ .remove = cs42l51_i2c_remove,
+};
static int __init cs42l51_init(void)
{
@@ -758,6 +649,6 @@
}
module_exit(cs42l51_exit);
-MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l51.h b/sound/soc/codecs/cs42l51.h
index 8f0bd97..2beeb17 100644
--- a/sound/soc/codecs/cs42l51.h
+++ b/sound/soc/codecs/cs42l51.h
@@ -158,6 +158,4 @@
#define CS42L51_LASTREG 0x20
#define CS42L51_NUMREGS (CS42L51_LASTREG - CS42L51_FIRSTREG + 1)
-extern struct snd_soc_dai cs42l51_dai;
-extern struct snd_soc_codec_device soc_codec_device_cs42l51;
#endif
diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c
index f07a415..e8d27c8 100644
--- a/sound/soc/codecs/cx20442.c
+++ b/sound/soc/codecs/cx20442.c
@@ -24,7 +24,8 @@
struct cx20442_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
+ void *control_data;
u8 reg_cache[1];
};
@@ -102,7 +103,7 @@
{
u8 *reg_cache = codec->reg_cache;
- if (reg >= codec->reg_cache_size)
+ if (reg >= codec->driver->reg_cache_size)
return -EINVAL;
return reg_cache[reg];
@@ -164,16 +165,17 @@
static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
+ struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
u8 *reg_cache = codec->reg_cache;
int vls, vsp, old, len;
char buf[18];
- if (reg >= codec->reg_cache_size)
+ if (reg >= codec->driver->reg_cache_size)
return -EINVAL;
/* hw_write and control_data pointers required for talking to the modem
* are expected to be set by the line discipline initialization code */
- if (!codec->hw_write || !codec->control_data)
+ if (!codec->hw_write || !cx20442->control_data)
return -EIO;
old = reg_cache[reg];
@@ -202,17 +204,13 @@
return -ENOMEM;
dev_dbg(codec->dev, "%s: %s\n", __func__, buf);
- if (codec->hw_write(codec->control_data, buf, len) != len)
+ if (codec->hw_write(cx20442->control_data, buf, len) != len)
return -EIO;
return 0;
}
-/* Moved up here as line discipline referres it during initialization */
-static struct snd_soc_codec *cx20442_codec;
-
-
/*
* Line discpline related code
*
@@ -228,15 +226,15 @@
/* Line discipline .open() */
static int v253_open(struct tty_struct *tty)
{
- struct snd_soc_codec *codec = cx20442_codec;
int ret, len = strlen(v253_init);
/* Doesn't make sense without write callback */
if (!tty->ops->write)
return -EINVAL;
- /* Pass the codec structure address for use by other ldisc callbacks */
- tty->disc_data = codec;
+ /* Won't work if no codec pointer has been passed by a card driver */
+ if (!tty->disc_data)
+ return -ENODEV;
if (tty->ops->write(tty, v253_init, len) != len) {
ret = -EIO;
@@ -253,15 +251,18 @@
static void v253_close(struct tty_struct *tty)
{
struct snd_soc_codec *codec = tty->disc_data;
+ struct cx20442_priv *cx20442;
tty->disc_data = NULL;
if (!codec)
return;
+ cx20442 = snd_soc_codec_get_drvdata(codec);
+
/* Prevent the codec driver from further accessing the modem */
codec->hw_write = NULL;
- codec->control_data = NULL;
+ cx20442->control_data = NULL;
codec->pop_time = 0;
}
@@ -277,15 +278,18 @@
const unsigned char *cp, char *fp, int count)
{
struct snd_soc_codec *codec = tty->disc_data;
+ struct cx20442_priv *cx20442;
if (!codec)
return;
- if (!codec->control_data) {
+ cx20442 = snd_soc_codec_get_drvdata(codec);
+
+ if (!cx20442->control_data) {
/* First modem response, complete setup procedure */
/* Set up codec driver access to modem controls */
- codec->control_data = tty;
+ cx20442->control_data = tty;
codec->hw_write = (hw_write_t)tty->ops->write;
codec->pop_time = 1;
}
@@ -313,8 +317,8 @@
* Codec DAI
*/
-struct snd_soc_dai cx20442_dai = {
- .name = "CX20442",
+static struct snd_soc_dai_driver cx20442_dai = {
+ .name = "cx20442-voice",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -330,142 +334,63 @@
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
};
-EXPORT_SYMBOL_GPL(cx20442_dai);
-static int cx20442_codec_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret;
-
- if (!cx20442_codec) {
- dev_err(&pdev->dev, "cx20442 not yet discovered\n");
- return -ENODEV;
- }
- codec = cx20442_codec;
-
- socdev->card->codec = codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to create pcms\n");
- goto pcm_err;
- }
-
- cx20442_add_widgets(codec);
-
-pcm_err:
- return ret;
-}
-
-/* power down chip */
-static int cx20442_codec_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device cx20442_codec_dev = {
- .probe = cx20442_codec_probe,
- .remove = cx20442_codec_remove,
-};
-EXPORT_SYMBOL_GPL(cx20442_codec_dev);
-
-static int cx20442_register(struct cx20442_priv *cx20442)
-{
- struct snd_soc_codec *codec = &cx20442->codec;
- int ret;
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->name = "CX20442";
- codec->owner = THIS_MODULE;
- snd_soc_codec_set_drvdata(codec, cx20442);
-
- codec->dai = &cx20442_dai;
- codec->num_dai = 1;
-
- codec->reg_cache = &cx20442->reg_cache;
- codec->reg_cache_size = ARRAY_SIZE(cx20442->reg_cache);
- codec->read = cx20442_read_reg_cache;
- codec->write = cx20442_write;
-
- codec->bias_level = SND_SOC_BIAS_OFF;
-
- cx20442_dai.dev = codec->dev;
-
- cx20442_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dai(&cx20442_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
-
- return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- cx20442_codec = NULL;
- kfree(cx20442);
- return ret;
-}
-
-static void cx20442_unregister(struct cx20442_priv *cx20442)
-{
- snd_soc_unregister_dai(&cx20442_dai);
- snd_soc_unregister_codec(&cx20442->codec);
-
- cx20442_codec = NULL;
- kfree(cx20442);
-}
-
-static int cx20442_platform_probe(struct platform_device *pdev)
+static int cx20442_codec_probe(struct snd_soc_codec *codec)
{
struct cx20442_priv *cx20442;
- struct snd_soc_codec *codec;
cx20442 = kzalloc(sizeof(struct cx20442_priv), GFP_KERNEL);
if (cx20442 == NULL)
return -ENOMEM;
+ snd_soc_codec_set_drvdata(codec, cx20442);
- codec = &cx20442->codec;
+ cx20442_add_widgets(codec);
- codec->control_data = NULL;
+ cx20442->control_data = NULL;
codec->hw_write = NULL;
codec->pop_time = 0;
- codec->dev = &pdev->dev;
- platform_set_drvdata(pdev, cx20442);
+ return 0;
+}
- return cx20442_register(cx20442);
+/* power down chip */
+static int cx20442_codec_remove(struct snd_soc_codec *codec)
+{
+ struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
+
+ if (cx20442->control_data) {
+ struct tty_struct *tty = cx20442->control_data;
+ tty_hangup(tty);
+ }
+
+ kfree(cx20442);
+ return 0;
+}
+
+static struct snd_soc_codec_driver cx20442_codec_dev = {
+ .probe = cx20442_codec_probe,
+ .remove = cx20442_codec_remove,
+ .reg_cache_size = 1,
+ .reg_word_size = sizeof(u8),
+ .read = cx20442_read_reg_cache,
+ .write = cx20442_write,
+};
+
+static int cx20442_platform_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev,
+ &cx20442_codec_dev, &cx20442_dai, 1);
}
static int __exit cx20442_platform_remove(struct platform_device *pdev)
{
- struct cx20442_priv *cx20442 = platform_get_drvdata(pdev);
-
- cx20442_unregister(cx20442);
+ snd_soc_unregister_codec(&pdev->dev);
return 0;
}
static struct platform_driver cx20442_platform_driver = {
.driver = {
- .name = "cx20442",
+ .name = "cx20442-codec",
.owner = THIS_MODULE,
},
.probe = cx20442_platform_probe,
@@ -487,4 +412,4 @@
MODULE_DESCRIPTION("ASoC CX20442-11 voice modem codec driver");
MODULE_AUTHOR("Janusz Krzysztofik");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:cx20442");
+MODULE_ALIAS("platform:cx20442-codec");
diff --git a/sound/soc/codecs/cx20442.h b/sound/soc/codecs/cx20442.h
index 688a5eb..c7a7c79 100644
--- a/sound/soc/codecs/cx20442.h
+++ b/sound/soc/codecs/cx20442.h
@@ -13,8 +13,6 @@
#ifndef _CX20442_CODEC_H
#define _CX20442_CODEC_H
-extern struct snd_soc_dai cx20442_dai;
-extern struct snd_soc_codec_device cx20442_codec_dev;
extern struct tty_ldisc_ops v253_ops;
#endif
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index 3c51d6a..58bb9b9 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -25,8 +25,6 @@
#include <sound/initval.h>
#include <sound/tlv.h>
-#include "da7210.h"
-
/* DA7210 register space */
#define DA7210_STATUS 0x02
#define DA7210_STARTUP1 0x03
@@ -162,11 +160,10 @@
/* Codec private data */
struct da7210_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
+ void *control_data;
};
-static struct snd_soc_codec *da7210_codec;
-
/*
* Register cache
*/
@@ -209,12 +206,12 @@
u8 *cache = codec->reg_cache;
u8 data[2];
- BUG_ON(codec->volatile_register);
+ BUG_ON(codec->driver->volatile_register);
data[0] = reg & 0xff;
data[1] = value & 0xff;
- if (reg >= codec->reg_cache_size)
+ if (reg >= codec->driver->reg_cache_size)
return -EIO;
if (2 != codec->hw_write(codec->control_data, data, 2))
@@ -267,8 +264,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
u32 dai_cfg1;
u32 hpf_reg, hpf_mask, hpf_value;
u32 fs, bypass;
@@ -430,9 +426,8 @@
.set_fmt = da7210_set_dai_fmt,
};
-struct snd_soc_dai da7210_dai = {
- .name = "DA7210 IIS",
- .id = 0,
+static struct snd_soc_dai_driver da7210_dai = {
+ .name = "da7210-hifi",
/* playback capabilities */
.playback = {
.stream_name = "Playback",
@@ -452,55 +447,15 @@
.ops = &da7210_dai_ops,
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(da7210_dai);
-/*
- * Initialize the DA7210 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int da7210_init(struct da7210_priv *da7210)
+static int da7210_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = &da7210->codec;
- int ret = 0;
+ struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
- if (da7210_codec) {
- dev_err(codec->dev, "Another da7210 is registered\n");
- return -EINVAL;
- }
+ dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, da7210);
- codec->name = "DA7210";
- codec->owner = THIS_MODULE;
- codec->read = da7210_read;
- codec->write = da7210_write;
- codec->dai = &da7210_dai;
- codec->num_dai = 1;
+ codec->control_data = da7210->control_data;
codec->hw_write = (hw_write_t)i2c_master_send;
- codec->reg_cache_size = ARRAY_SIZE(da7210_reg);
- codec->reg_cache = kmemdup(da7210_reg,
- sizeof(da7210_reg), GFP_KERNEL);
-
- if (!codec->reg_cache)
- return -ENOMEM;
-
- da7210_dai.dev = codec->dev;
- da7210_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret) {
- dev_err(codec->dev, "Failed to register CODEC: %d\n", ret);
- goto init_err;
- }
-
- ret = snd_soc_register_dai(&da7210_dai);
- if (ret) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto codec_err;
- }
/* FIXME
*
@@ -583,54 +538,50 @@
/* Activate all enabled subsystem */
da7210_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN);
- return ret;
+ snd_soc_add_controls(codec, da7210_snd_controls,
+ ARRAY_SIZE(da7210_snd_controls));
-codec_err:
- snd_soc_unregister_codec(codec);
-init_err:
- kfree(codec->reg_cache);
- codec->reg_cache = NULL;
+ dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
- return ret;
-
+ return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_da7210 = {
+ .probe = da7210_probe,
+ .read = da7210_read,
+ .write = da7210_write,
+ .reg_cache_size = ARRAY_SIZE(da7210_reg),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = da7210_reg,
+};
+
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static int __devinit da7210_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct da7210_priv *da7210;
- struct snd_soc_codec *codec;
int ret;
da7210 = kzalloc(sizeof(struct da7210_priv), GFP_KERNEL);
if (!da7210)
return -ENOMEM;
- codec = &da7210->codec;
- codec->dev = &i2c->dev;
-
i2c_set_clientdata(i2c, da7210);
- codec->control_data = i2c;
+ da7210->control_data = i2c;
+ da7210->control_type = SND_SOC_I2C;
- ret = da7210_init(da7210);
- if (ret < 0) {
- pr_err("Failed to initialise da7210 audio codec\n");
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_da7210, &da7210_dai, 1);
+ if (ret < 0)
kfree(da7210);
- }
return ret;
}
static int __devexit da7210_i2c_remove(struct i2c_client *client)
{
- struct da7210_priv *da7210 = i2c_get_clientdata(client);
-
- snd_soc_unregister_dai(&da7210_dai);
- kfree(da7210->codec.reg_cache);
- kfree(da7210);
- da7210_codec = NULL;
-
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -643,59 +594,15 @@
/* I2C codec control layer */
static struct i2c_driver da7210_i2c_driver = {
.driver = {
- .name = "DA7210 I2C Codec",
+ .name = "da7210-codec",
.owner = THIS_MODULE,
},
- .probe = da7210_i2c_probe,
- .remove = __devexit_p(da7210_i2c_remove),
- .id_table = da7210_i2c_id,
+ .probe = da7210_i2c_probe,
+ .remove = __devexit_p(da7210_i2c_remove),
+ .id_table = da7210_i2c_id,
};
#endif
-static int da7210_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret;
-
- if (!da7210_codec) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = da7210_codec;
- codec = da7210_codec;
-
- /* Register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0)
- goto pcm_err;
-
- snd_soc_add_controls(da7210_codec, da7210_snd_controls,
- ARRAY_SIZE(da7210_snd_controls));
-
- dev_info(&pdev->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
-
-pcm_err:
- return ret;
-}
-
-static int da7210_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_da7210 = {
- .probe = da7210_probe,
- .remove = da7210_remove,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_da7210);
-
static int __init da7210_modinit(void)
{
int ret = 0;
diff --git a/sound/soc/codecs/da7210.h b/sound/soc/codecs/da7210.h
deleted file mode 100644
index 390d621..0000000
--- a/sound/soc/codecs/da7210.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * da7210.h -- audio driver for da7210
- *
- * Copyright (c) 2009 Dialog Semiconductor
- * Written by David Chen <Dajun.chen@diasemi.com>
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * Cleanups by Kuninori Morimoto <morimoto.kuninori@renesas.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; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
-
-#ifndef _DA7210_H
-#define _DA7210_H
-
-extern struct snd_soc_dai da7210_dai;
-extern struct snd_soc_codec_device soc_codec_dev_da7210;
-
-#endif
-
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c
index 66557de..16253ec 100644
--- a/sound/soc/codecs/jz4740.c
+++ b/sound/soc/codecs/jz4740.c
@@ -74,29 +74,22 @@
struct jz4740_codec {
void __iomem *base;
struct resource *mem;
-
- uint32_t reg_cache[2];
- struct snd_soc_codec codec;
};
-static inline struct jz4740_codec *codec_to_jz4740(struct snd_soc_codec *codec)
-{
- return container_of(codec, struct jz4740_codec, codec);
-}
-
static unsigned int jz4740_codec_read(struct snd_soc_codec *codec,
unsigned int reg)
{
- struct jz4740_codec *jz4740_codec = codec_to_jz4740(codec);
+ struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec);
return readl(jz4740_codec->base + (reg << 2));
}
static int jz4740_codec_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int val)
{
- struct jz4740_codec *jz4740_codec = codec_to_jz4740(codec);
+ struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec);
+ u32 *cache = codec->reg_cache;
- jz4740_codec->reg_cache[reg] = val;
+ cache[reg] = val;
writel(val, jz4740_codec->base + (reg << 2));
return 0;
@@ -172,8 +165,7 @@
{
uint32_t val;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec =rtd->codec;
switch (params_rate(params)) {
case 8000:
@@ -219,8 +211,8 @@
.hw_params = jz4740_codec_hw_params,
};
-struct snd_soc_dai jz4740_codec_dai = {
- .name = "jz4740",
+static struct snd_soc_dai_driver jz4740_codec_dai = {
+ .name = "jz4740-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -238,7 +230,6 @@
.ops = &jz4740_codec_dai_ops,
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(jz4740_codec_dai);
static void jz4740_codec_wakeup(struct snd_soc_codec *codec)
{
@@ -302,23 +293,10 @@
return 0;
}
-static struct snd_soc_codec *jz4740_codec_codec;
-
-static int jz4740_codec_dev_probe(struct platform_device *pdev)
+static int jz4740_codec_dev_probe(struct snd_soc_codec *codec)
{
- int ret;
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = jz4740_codec_codec;
-
- BUG_ON(!codec);
-
- socdev->card->codec = codec;
-
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret) {
- dev_err(&pdev->dev, "Failed to create pcms: %d\n", ret);
- return ret;
- }
+ snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
+ JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
snd_soc_add_controls(codec, jz4740_codec_controls,
ARRAY_SIZE(jz4740_codec_controls));
@@ -331,34 +309,27 @@
snd_soc_dapm_new_widgets(codec);
+ jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
return 0;
}
-static int jz4740_codec_dev_remove(struct platform_device *pdev)
+static int jz4740_codec_dev_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
+ jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
#ifdef CONFIG_PM_SLEEP
-static int jz4740_codec_suspend(struct platform_device *pdev, pm_message_t state)
+static int jz4740_codec_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF);
}
-static int jz4740_codec_resume(struct platform_device *pdev)
+static int jz4740_codec_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
}
@@ -367,19 +338,23 @@
#define jz4740_codec_resume NULL
#endif
-struct snd_soc_codec_device soc_codec_dev_jz4740_codec = {
+static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = {
.probe = jz4740_codec_dev_probe,
.remove = jz4740_codec_dev_remove,
.suspend = jz4740_codec_suspend,
.resume = jz4740_codec_resume,
+ .read = jz4740_codec_read,
+ .write = jz4740_codec_write,
+ .set_bias_level = jz4740_codec_set_bias_level,
+ .reg_cache_default = jz4740_codec_regs,
+ .reg_word_size = sizeof(u32),
+ .reg_cache_size = 2,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_jz4740_codec);
static int __devinit jz4740_codec_probe(struct platform_device *pdev)
{
int ret;
struct jz4740_codec *jz4740_codec;
- struct snd_soc_codec *codec;
struct resource *mem;
jz4740_codec = kzalloc(sizeof(*jz4740_codec), GFP_KERNEL);
@@ -408,55 +383,17 @@
}
jz4740_codec->mem = mem;
- jz4740_codec_dai.dev = &pdev->dev;
-
- codec = &jz4740_codec->codec;
-
- codec->dev = &pdev->dev;
- codec->name = "jz4740";
- codec->owner = THIS_MODULE;
-
- codec->read = jz4740_codec_read;
- codec->write = jz4740_codec_write;
- codec->set_bias_level = jz4740_codec_set_bias_level;
- codec->bias_level = SND_SOC_BIAS_OFF;
-
- codec->dai = &jz4740_codec_dai;
- codec->num_dai = 1;
-
- codec->reg_cache = jz4740_codec->reg_cache;
- codec->reg_cache_size = 2;
- memcpy(codec->reg_cache, jz4740_codec_regs, sizeof(jz4740_codec_regs));
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- jz4740_codec_codec = codec;
-
- snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
- JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
-
platform_set_drvdata(pdev, jz4740_codec);
- ret = snd_soc_register_codec(codec);
+ ret = snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_jz4740_codec, &jz4740_codec_dai, 1);
if (ret) {
dev_err(&pdev->dev, "Failed to register codec\n");
goto err_iounmap;
}
- ret = snd_soc_register_dai(&jz4740_codec_dai);
- if (ret) {
- dev_err(&pdev->dev, "Failed to register codec dai\n");
- goto err_unregister_codec;
- }
-
- jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
return 0;
-err_unregister_codec:
- snd_soc_unregister_codec(codec);
err_iounmap:
iounmap(jz4740_codec->base);
err_release_mem_region:
@@ -472,8 +409,7 @@
struct jz4740_codec *jz4740_codec = platform_get_drvdata(pdev);
struct resource *mem = jz4740_codec->mem;
- snd_soc_unregister_dai(&jz4740_codec_dai);
- snd_soc_unregister_codec(&jz4740_codec->codec);
+ snd_soc_unregister_codec(&pdev->dev);
iounmap(jz4740_codec->base);
release_mem_region(mem->start, resource_size(mem));
diff --git a/sound/soc/codecs/jz4740.h b/sound/soc/codecs/jz4740.h
deleted file mode 100644
index b5a0691..0000000
--- a/sound/soc/codecs/jz4740.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.de>
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef __SND_SOC_CODECS_JZ4740_CODEC_H__
-#define __SND_SOC_CODECS_JZ4740_CODEC_H__
-
-extern struct snd_soc_dai jz4740_codec_dai;
-extern struct snd_soc_codec_device soc_codec_dev_jz4740_codec;
-
-#endif
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
new file mode 100644
index 0000000..e7a40d1
--- /dev/null
+++ b/sound/soc/codecs/max98088.c
@@ -0,0 +1,2097 @@
+/*
+ * max98088.c -- MAX98088 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Maxim Integrated Products
+ *
+ * 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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <linux/slab.h>
+#include <asm/div64.h>
+#include <sound/max98088.h>
+#include "max98088.h"
+
+struct max98088_cdata {
+ unsigned int rate;
+ unsigned int fmt;
+ int eq_sel;
+};
+
+struct max98088_priv {
+ u8 reg_cache[M98088_REG_CNT];
+ void *control_data;
+ struct max98088_pdata *pdata;
+ unsigned int sysclk;
+ struct max98088_cdata dai[2];
+ int eq_textcnt;
+ const char **eq_texts;
+ struct soc_enum eq_enum;
+ u8 ina_state;
+ u8 inb_state;
+ unsigned int ex_mode;
+ unsigned int digmic;
+ unsigned int mic1pre;
+ unsigned int mic2pre;
+ unsigned int extmic_mode;
+};
+
+static const u8 max98088_reg[M98088_REG_CNT] = {
+ 0x00, /* 00 IRQ status */
+ 0x00, /* 01 MIC status */
+ 0x00, /* 02 jack status */
+ 0x00, /* 03 battery voltage */
+ 0x00, /* 04 */
+ 0x00, /* 05 */
+ 0x00, /* 06 */
+ 0x00, /* 07 */
+ 0x00, /* 08 */
+ 0x00, /* 09 */
+ 0x00, /* 0A */
+ 0x00, /* 0B */
+ 0x00, /* 0C */
+ 0x00, /* 0D */
+ 0x00, /* 0E */
+ 0x00, /* 0F interrupt enable */
+
+ 0x00, /* 10 master clock */
+ 0x00, /* 11 DAI1 clock mode */
+ 0x00, /* 12 DAI1 clock control */
+ 0x00, /* 13 DAI1 clock control */
+ 0x00, /* 14 DAI1 format */
+ 0x00, /* 15 DAI1 clock */
+ 0x00, /* 16 DAI1 config */
+ 0x00, /* 17 DAI1 TDM */
+ 0x00, /* 18 DAI1 filters */
+ 0x00, /* 19 DAI2 clock mode */
+ 0x00, /* 1A DAI2 clock control */
+ 0x00, /* 1B DAI2 clock control */
+ 0x00, /* 1C DAI2 format */
+ 0x00, /* 1D DAI2 clock */
+ 0x00, /* 1E DAI2 config */
+ 0x00, /* 1F DAI2 TDM */
+
+ 0x00, /* 20 DAI2 filters */
+ 0x00, /* 21 data config */
+ 0x00, /* 22 DAC mixer */
+ 0x00, /* 23 left ADC mixer */
+ 0x00, /* 24 right ADC mixer */
+ 0x00, /* 25 left HP mixer */
+ 0x00, /* 26 right HP mixer */
+ 0x00, /* 27 HP control */
+ 0x00, /* 28 left REC mixer */
+ 0x00, /* 29 right REC mixer */
+ 0x00, /* 2A REC control */
+ 0x00, /* 2B left SPK mixer */
+ 0x00, /* 2C right SPK mixer */
+ 0x00, /* 2D SPK control */
+ 0x00, /* 2E sidetone */
+ 0x00, /* 2F DAI1 playback level */
+
+ 0x00, /* 30 DAI1 playback level */
+ 0x00, /* 31 DAI2 playback level */
+ 0x00, /* 32 DAI2 playbakc level */
+ 0x00, /* 33 left ADC level */
+ 0x00, /* 34 right ADC level */
+ 0x00, /* 35 MIC1 level */
+ 0x00, /* 36 MIC2 level */
+ 0x00, /* 37 INA level */
+ 0x00, /* 38 INB level */
+ 0x00, /* 39 left HP volume */
+ 0x00, /* 3A right HP volume */
+ 0x00, /* 3B left REC volume */
+ 0x00, /* 3C right REC volume */
+ 0x00, /* 3D left SPK volume */
+ 0x00, /* 3E right SPK volume */
+ 0x00, /* 3F MIC config */
+
+ 0x00, /* 40 MIC threshold */
+ 0x00, /* 41 excursion limiter filter */
+ 0x00, /* 42 excursion limiter threshold */
+ 0x00, /* 43 ALC */
+ 0x00, /* 44 power limiter threshold */
+ 0x00, /* 45 power limiter config */
+ 0x00, /* 46 distortion limiter config */
+ 0x00, /* 47 audio input */
+ 0x00, /* 48 microphone */
+ 0x00, /* 49 level control */
+ 0x00, /* 4A bypass switches */
+ 0x00, /* 4B jack detect */
+ 0x00, /* 4C input enable */
+ 0x00, /* 4D output enable */
+ 0xF0, /* 4E bias control */
+ 0x00, /* 4F DAC power */
+
+ 0x0F, /* 50 DAC power */
+ 0x00, /* 51 system */
+ 0x00, /* 52 DAI1 EQ1 */
+ 0x00, /* 53 DAI1 EQ1 */
+ 0x00, /* 54 DAI1 EQ1 */
+ 0x00, /* 55 DAI1 EQ1 */
+ 0x00, /* 56 DAI1 EQ1 */
+ 0x00, /* 57 DAI1 EQ1 */
+ 0x00, /* 58 DAI1 EQ1 */
+ 0x00, /* 59 DAI1 EQ1 */
+ 0x00, /* 5A DAI1 EQ1 */
+ 0x00, /* 5B DAI1 EQ1 */
+ 0x00, /* 5C DAI1 EQ2 */
+ 0x00, /* 5D DAI1 EQ2 */
+ 0x00, /* 5E DAI1 EQ2 */
+ 0x00, /* 5F DAI1 EQ2 */
+
+ 0x00, /* 60 DAI1 EQ2 */
+ 0x00, /* 61 DAI1 EQ2 */
+ 0x00, /* 62 DAI1 EQ2 */
+ 0x00, /* 63 DAI1 EQ2 */
+ 0x00, /* 64 DAI1 EQ2 */
+ 0x00, /* 65 DAI1 EQ2 */
+ 0x00, /* 66 DAI1 EQ3 */
+ 0x00, /* 67 DAI1 EQ3 */
+ 0x00, /* 68 DAI1 EQ3 */
+ 0x00, /* 69 DAI1 EQ3 */
+ 0x00, /* 6A DAI1 EQ3 */
+ 0x00, /* 6B DAI1 EQ3 */
+ 0x00, /* 6C DAI1 EQ3 */
+ 0x00, /* 6D DAI1 EQ3 */
+ 0x00, /* 6E DAI1 EQ3 */
+ 0x00, /* 6F DAI1 EQ3 */
+
+ 0x00, /* 70 DAI1 EQ4 */
+ 0x00, /* 71 DAI1 EQ4 */
+ 0x00, /* 72 DAI1 EQ4 */
+ 0x00, /* 73 DAI1 EQ4 */
+ 0x00, /* 74 DAI1 EQ4 */
+ 0x00, /* 75 DAI1 EQ4 */
+ 0x00, /* 76 DAI1 EQ4 */
+ 0x00, /* 77 DAI1 EQ4 */
+ 0x00, /* 78 DAI1 EQ4 */
+ 0x00, /* 79 DAI1 EQ4 */
+ 0x00, /* 7A DAI1 EQ5 */
+ 0x00, /* 7B DAI1 EQ5 */
+ 0x00, /* 7C DAI1 EQ5 */
+ 0x00, /* 7D DAI1 EQ5 */
+ 0x00, /* 7E DAI1 EQ5 */
+ 0x00, /* 7F DAI1 EQ5 */
+
+ 0x00, /* 80 DAI1 EQ5 */
+ 0x00, /* 81 DAI1 EQ5 */
+ 0x00, /* 82 DAI1 EQ5 */
+ 0x00, /* 83 DAI1 EQ5 */
+ 0x00, /* 84 DAI2 EQ1 */
+ 0x00, /* 85 DAI2 EQ1 */
+ 0x00, /* 86 DAI2 EQ1 */
+ 0x00, /* 87 DAI2 EQ1 */
+ 0x00, /* 88 DAI2 EQ1 */
+ 0x00, /* 89 DAI2 EQ1 */
+ 0x00, /* 8A DAI2 EQ1 */
+ 0x00, /* 8B DAI2 EQ1 */
+ 0x00, /* 8C DAI2 EQ1 */
+ 0x00, /* 8D DAI2 EQ1 */
+ 0x00, /* 8E DAI2 EQ2 */
+ 0x00, /* 8F DAI2 EQ2 */
+
+ 0x00, /* 90 DAI2 EQ2 */
+ 0x00, /* 91 DAI2 EQ2 */
+ 0x00, /* 92 DAI2 EQ2 */
+ 0x00, /* 93 DAI2 EQ2 */
+ 0x00, /* 94 DAI2 EQ2 */
+ 0x00, /* 95 DAI2 EQ2 */
+ 0x00, /* 96 DAI2 EQ2 */
+ 0x00, /* 97 DAI2 EQ2 */
+ 0x00, /* 98 DAI2 EQ3 */
+ 0x00, /* 99 DAI2 EQ3 */
+ 0x00, /* 9A DAI2 EQ3 */
+ 0x00, /* 9B DAI2 EQ3 */
+ 0x00, /* 9C DAI2 EQ3 */
+ 0x00, /* 9D DAI2 EQ3 */
+ 0x00, /* 9E DAI2 EQ3 */
+ 0x00, /* 9F DAI2 EQ3 */
+
+ 0x00, /* A0 DAI2 EQ3 */
+ 0x00, /* A1 DAI2 EQ3 */
+ 0x00, /* A2 DAI2 EQ4 */
+ 0x00, /* A3 DAI2 EQ4 */
+ 0x00, /* A4 DAI2 EQ4 */
+ 0x00, /* A5 DAI2 EQ4 */
+ 0x00, /* A6 DAI2 EQ4 */
+ 0x00, /* A7 DAI2 EQ4 */
+ 0x00, /* A8 DAI2 EQ4 */
+ 0x00, /* A9 DAI2 EQ4 */
+ 0x00, /* AA DAI2 EQ4 */
+ 0x00, /* AB DAI2 EQ4 */
+ 0x00, /* AC DAI2 EQ5 */
+ 0x00, /* AD DAI2 EQ5 */
+ 0x00, /* AE DAI2 EQ5 */
+ 0x00, /* AF DAI2 EQ5 */
+
+ 0x00, /* B0 DAI2 EQ5 */
+ 0x00, /* B1 DAI2 EQ5 */
+ 0x00, /* B2 DAI2 EQ5 */
+ 0x00, /* B3 DAI2 EQ5 */
+ 0x00, /* B4 DAI2 EQ5 */
+ 0x00, /* B5 DAI2 EQ5 */
+ 0x00, /* B6 DAI1 biquad */
+ 0x00, /* B7 DAI1 biquad */
+ 0x00, /* B8 DAI1 biquad */
+ 0x00, /* B9 DAI1 biquad */
+ 0x00, /* BA DAI1 biquad */
+ 0x00, /* BB DAI1 biquad */
+ 0x00, /* BC DAI1 biquad */
+ 0x00, /* BD DAI1 biquad */
+ 0x00, /* BE DAI1 biquad */
+ 0x00, /* BF DAI1 biquad */
+
+ 0x00, /* C0 DAI2 biquad */
+ 0x00, /* C1 DAI2 biquad */
+ 0x00, /* C2 DAI2 biquad */
+ 0x00, /* C3 DAI2 biquad */
+ 0x00, /* C4 DAI2 biquad */
+ 0x00, /* C5 DAI2 biquad */
+ 0x00, /* C6 DAI2 biquad */
+ 0x00, /* C7 DAI2 biquad */
+ 0x00, /* C8 DAI2 biquad */
+ 0x00, /* C9 DAI2 biquad */
+ 0x00, /* CA */
+ 0x00, /* CB */
+ 0x00, /* CC */
+ 0x00, /* CD */
+ 0x00, /* CE */
+ 0x00, /* CF */
+
+ 0x00, /* D0 */
+ 0x00, /* D1 */
+ 0x00, /* D2 */
+ 0x00, /* D3 */
+ 0x00, /* D4 */
+ 0x00, /* D5 */
+ 0x00, /* D6 */
+ 0x00, /* D7 */
+ 0x00, /* D8 */
+ 0x00, /* D9 */
+ 0x00, /* DA */
+ 0x70, /* DB */
+ 0x00, /* DC */
+ 0x00, /* DD */
+ 0x00, /* DE */
+ 0x00, /* DF */
+
+ 0x00, /* E0 */
+ 0x00, /* E1 */
+ 0x00, /* E2 */
+ 0x00, /* E3 */
+ 0x00, /* E4 */
+ 0x00, /* E5 */
+ 0x00, /* E6 */
+ 0x00, /* E7 */
+ 0x00, /* E8 */
+ 0x00, /* E9 */
+ 0x00, /* EA */
+ 0x00, /* EB */
+ 0x00, /* EC */
+ 0x00, /* ED */
+ 0x00, /* EE */
+ 0x00, /* EF */
+
+ 0x00, /* F0 */
+ 0x00, /* F1 */
+ 0x00, /* F2 */
+ 0x00, /* F3 */
+ 0x00, /* F4 */
+ 0x00, /* F5 */
+ 0x00, /* F6 */
+ 0x00, /* F7 */
+ 0x00, /* F8 */
+ 0x00, /* F9 */
+ 0x00, /* FA */
+ 0x00, /* FB */
+ 0x00, /* FC */
+ 0x00, /* FD */
+ 0x00, /* FE */
+ 0x00, /* FF */
+};
+
+static struct {
+ int readable;
+ int writable;
+ int vol;
+} max98088_access[M98088_REG_CNT] = {
+ { 0xFF, 0xFF, 1 }, /* 00 IRQ status */
+ { 0xFF, 0x00, 1 }, /* 01 MIC status */
+ { 0xFF, 0x00, 1 }, /* 02 jack status */
+ { 0x1F, 0x1F, 1 }, /* 03 battery voltage */
+ { 0xFF, 0xFF, 0 }, /* 04 */
+ { 0xFF, 0xFF, 0 }, /* 05 */
+ { 0xFF, 0xFF, 0 }, /* 06 */
+ { 0xFF, 0xFF, 0 }, /* 07 */
+ { 0xFF, 0xFF, 0 }, /* 08 */
+ { 0xFF, 0xFF, 0 }, /* 09 */
+ { 0xFF, 0xFF, 0 }, /* 0A */
+ { 0xFF, 0xFF, 0 }, /* 0B */
+ { 0xFF, 0xFF, 0 }, /* 0C */
+ { 0xFF, 0xFF, 0 }, /* 0D */
+ { 0xFF, 0xFF, 0 }, /* 0E */
+ { 0xFF, 0xFF, 0 }, /* 0F interrupt enable */
+
+ { 0xFF, 0xFF, 0 }, /* 10 master clock */
+ { 0xFF, 0xFF, 0 }, /* 11 DAI1 clock mode */
+ { 0xFF, 0xFF, 0 }, /* 12 DAI1 clock control */
+ { 0xFF, 0xFF, 0 }, /* 13 DAI1 clock control */
+ { 0xFF, 0xFF, 0 }, /* 14 DAI1 format */
+ { 0xFF, 0xFF, 0 }, /* 15 DAI1 clock */
+ { 0xFF, 0xFF, 0 }, /* 16 DAI1 config */
+ { 0xFF, 0xFF, 0 }, /* 17 DAI1 TDM */
+ { 0xFF, 0xFF, 0 }, /* 18 DAI1 filters */
+ { 0xFF, 0xFF, 0 }, /* 19 DAI2 clock mode */
+ { 0xFF, 0xFF, 0 }, /* 1A DAI2 clock control */
+ { 0xFF, 0xFF, 0 }, /* 1B DAI2 clock control */
+ { 0xFF, 0xFF, 0 }, /* 1C DAI2 format */
+ { 0xFF, 0xFF, 0 }, /* 1D DAI2 clock */
+ { 0xFF, 0xFF, 0 }, /* 1E DAI2 config */
+ { 0xFF, 0xFF, 0 }, /* 1F DAI2 TDM */
+
+ { 0xFF, 0xFF, 0 }, /* 20 DAI2 filters */
+ { 0xFF, 0xFF, 0 }, /* 21 data config */
+ { 0xFF, 0xFF, 0 }, /* 22 DAC mixer */
+ { 0xFF, 0xFF, 0 }, /* 23 left ADC mixer */
+ { 0xFF, 0xFF, 0 }, /* 24 right ADC mixer */
+ { 0xFF, 0xFF, 0 }, /* 25 left HP mixer */
+ { 0xFF, 0xFF, 0 }, /* 26 right HP mixer */
+ { 0xFF, 0xFF, 0 }, /* 27 HP control */
+ { 0xFF, 0xFF, 0 }, /* 28 left REC mixer */
+ { 0xFF, 0xFF, 0 }, /* 29 right REC mixer */
+ { 0xFF, 0xFF, 0 }, /* 2A REC control */
+ { 0xFF, 0xFF, 0 }, /* 2B left SPK mixer */
+ { 0xFF, 0xFF, 0 }, /* 2C right SPK mixer */
+ { 0xFF, 0xFF, 0 }, /* 2D SPK control */
+ { 0xFF, 0xFF, 0 }, /* 2E sidetone */
+ { 0xFF, 0xFF, 0 }, /* 2F DAI1 playback level */
+
+ { 0xFF, 0xFF, 0 }, /* 30 DAI1 playback level */
+ { 0xFF, 0xFF, 0 }, /* 31 DAI2 playback level */
+ { 0xFF, 0xFF, 0 }, /* 32 DAI2 playbakc level */
+ { 0xFF, 0xFF, 0 }, /* 33 left ADC level */
+ { 0xFF, 0xFF, 0 }, /* 34 right ADC level */
+ { 0xFF, 0xFF, 0 }, /* 35 MIC1 level */
+ { 0xFF, 0xFF, 0 }, /* 36 MIC2 level */
+ { 0xFF, 0xFF, 0 }, /* 37 INA level */
+ { 0xFF, 0xFF, 0 }, /* 38 INB level */
+ { 0xFF, 0xFF, 0 }, /* 39 left HP volume */
+ { 0xFF, 0xFF, 0 }, /* 3A right HP volume */
+ { 0xFF, 0xFF, 0 }, /* 3B left REC volume */
+ { 0xFF, 0xFF, 0 }, /* 3C right REC volume */
+ { 0xFF, 0xFF, 0 }, /* 3D left SPK volume */
+ { 0xFF, 0xFF, 0 }, /* 3E right SPK volume */
+ { 0xFF, 0xFF, 0 }, /* 3F MIC config */
+
+ { 0xFF, 0xFF, 0 }, /* 40 MIC threshold */
+ { 0xFF, 0xFF, 0 }, /* 41 excursion limiter filter */
+ { 0xFF, 0xFF, 0 }, /* 42 excursion limiter threshold */
+ { 0xFF, 0xFF, 0 }, /* 43 ALC */
+ { 0xFF, 0xFF, 0 }, /* 44 power limiter threshold */
+ { 0xFF, 0xFF, 0 }, /* 45 power limiter config */
+ { 0xFF, 0xFF, 0 }, /* 46 distortion limiter config */
+ { 0xFF, 0xFF, 0 }, /* 47 audio input */
+ { 0xFF, 0xFF, 0 }, /* 48 microphone */
+ { 0xFF, 0xFF, 0 }, /* 49 level control */
+ { 0xFF, 0xFF, 0 }, /* 4A bypass switches */
+ { 0xFF, 0xFF, 0 }, /* 4B jack detect */
+ { 0xFF, 0xFF, 0 }, /* 4C input enable */
+ { 0xFF, 0xFF, 0 }, /* 4D output enable */
+ { 0xFF, 0xFF, 0 }, /* 4E bias control */
+ { 0xFF, 0xFF, 0 }, /* 4F DAC power */
+
+ { 0xFF, 0xFF, 0 }, /* 50 DAC power */
+ { 0xFF, 0xFF, 0 }, /* 51 system */
+ { 0xFF, 0xFF, 0 }, /* 52 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 53 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 54 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 55 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 56 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 57 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 58 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 59 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 5A DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 5B DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 5C DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 5D DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 5E DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 5F DAI1 EQ2 */
+
+ { 0xFF, 0xFF, 0 }, /* 60 DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 61 DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 62 DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 63 DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 64 DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 65 DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 66 DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 67 DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 68 DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 69 DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 6A DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 6B DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 6C DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 6D DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 6E DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 6F DAI1 EQ3 */
+
+ { 0xFF, 0xFF, 0 }, /* 70 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 71 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 72 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 73 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 74 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 75 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 76 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 77 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 78 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 79 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 7A DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 7B DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 7C DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 7D DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 7E DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 7F DAI1 EQ5 */
+
+ { 0xFF, 0xFF, 0 }, /* 80 DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 81 DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 82 DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 83 DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 84 DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 85 DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 86 DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 87 DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 88 DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 89 DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 8A DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 8B DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 8C DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 8D DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 8E DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 8F DAI2 EQ2 */
+
+ { 0xFF, 0xFF, 0 }, /* 90 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 91 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 92 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 93 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 94 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 95 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 96 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 97 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 98 DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 99 DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 9A DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 9B DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 9C DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 9D DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 9E DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 9F DAI2 EQ3 */
+
+ { 0xFF, 0xFF, 0 }, /* A0 DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* A1 DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* A2 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A3 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A4 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A5 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A6 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A7 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A8 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A9 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* AA DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* AB DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* AC DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* AD DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* AE DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* AF DAI2 EQ5 */
+
+ { 0xFF, 0xFF, 0 }, /* B0 DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* B1 DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* B2 DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* B3 DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* B4 DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* B5 DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* B6 DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* B7 DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* B8 DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* B9 DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* BA DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* BB DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* BC DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* BD DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* BE DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* BF DAI1 biquad */
+
+ { 0xFF, 0xFF, 0 }, /* C0 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C1 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C2 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C3 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C4 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C5 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C6 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C7 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C8 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C9 DAI2 biquad */
+ { 0x00, 0x00, 0 }, /* CA */
+ { 0x00, 0x00, 0 }, /* CB */
+ { 0x00, 0x00, 0 }, /* CC */
+ { 0x00, 0x00, 0 }, /* CD */
+ { 0x00, 0x00, 0 }, /* CE */
+ { 0x00, 0x00, 0 }, /* CF */
+
+ { 0x00, 0x00, 0 }, /* D0 */
+ { 0x00, 0x00, 0 }, /* D1 */
+ { 0x00, 0x00, 0 }, /* D2 */
+ { 0x00, 0x00, 0 }, /* D3 */
+ { 0x00, 0x00, 0 }, /* D4 */
+ { 0x00, 0x00, 0 }, /* D5 */
+ { 0x00, 0x00, 0 }, /* D6 */
+ { 0x00, 0x00, 0 }, /* D7 */
+ { 0x00, 0x00, 0 }, /* D8 */
+ { 0x00, 0x00, 0 }, /* D9 */
+ { 0x00, 0x00, 0 }, /* DA */
+ { 0x00, 0x00, 0 }, /* DB */
+ { 0x00, 0x00, 0 }, /* DC */
+ { 0x00, 0x00, 0 }, /* DD */
+ { 0x00, 0x00, 0 }, /* DE */
+ { 0x00, 0x00, 0 }, /* DF */
+
+ { 0x00, 0x00, 0 }, /* E0 */
+ { 0x00, 0x00, 0 }, /* E1 */
+ { 0x00, 0x00, 0 }, /* E2 */
+ { 0x00, 0x00, 0 }, /* E3 */
+ { 0x00, 0x00, 0 }, /* E4 */
+ { 0x00, 0x00, 0 }, /* E5 */
+ { 0x00, 0x00, 0 }, /* E6 */
+ { 0x00, 0x00, 0 }, /* E7 */
+ { 0x00, 0x00, 0 }, /* E8 */
+ { 0x00, 0x00, 0 }, /* E9 */
+ { 0x00, 0x00, 0 }, /* EA */
+ { 0x00, 0x00, 0 }, /* EB */
+ { 0x00, 0x00, 0 }, /* EC */
+ { 0x00, 0x00, 0 }, /* ED */
+ { 0x00, 0x00, 0 }, /* EE */
+ { 0x00, 0x00, 0 }, /* EF */
+
+ { 0x00, 0x00, 0 }, /* F0 */
+ { 0x00, 0x00, 0 }, /* F1 */
+ { 0x00, 0x00, 0 }, /* F2 */
+ { 0x00, 0x00, 0 }, /* F3 */
+ { 0x00, 0x00, 0 }, /* F4 */
+ { 0x00, 0x00, 0 }, /* F5 */
+ { 0x00, 0x00, 0 }, /* F6 */
+ { 0x00, 0x00, 0 }, /* F7 */
+ { 0x00, 0x00, 0 }, /* F8 */
+ { 0x00, 0x00, 0 }, /* F9 */
+ { 0x00, 0x00, 0 }, /* FA */
+ { 0x00, 0x00, 0 }, /* FB */
+ { 0x00, 0x00, 0 }, /* FC */
+ { 0x00, 0x00, 0 }, /* FD */
+ { 0x00, 0x00, 0 }, /* FE */
+ { 0xFF, 0x00, 1 }, /* FF */
+};
+
+static int max98088_volatile_register(unsigned int reg)
+{
+ return max98088_access[reg].vol;
+}
+
+
+/*
+ * Load equalizer DSP coefficient configurations registers
+ */
+static void m98088_eq_band(struct snd_soc_codec *codec, unsigned int dai,
+ unsigned int band, u16 *coefs)
+{
+ unsigned int eq_reg;
+ unsigned int i;
+
+ BUG_ON(band > 4);
+ BUG_ON(dai > 1);
+
+ /* Load the base register address */
+ eq_reg = dai ? M98088_REG_84_DAI2_EQ_BASE : M98088_REG_52_DAI1_EQ_BASE;
+
+ /* Add the band address offset, note adjustment for word address */
+ eq_reg += band * (M98088_COEFS_PER_BAND << 1);
+
+ /* Step through the registers and coefs */
+ for (i = 0; i < M98088_COEFS_PER_BAND; i++) {
+ snd_soc_write(codec, eq_reg++, M98088_BYTE1(coefs[i]));
+ snd_soc_write(codec, eq_reg++, M98088_BYTE0(coefs[i]));
+ }
+}
+
+/*
+ * Excursion limiter modes
+ */
+static const char *max98088_exmode_texts[] = {
+ "Off", "100Hz", "400Hz", "600Hz", "800Hz", "1000Hz", "200-400Hz",
+ "400-600Hz", "400-800Hz",
+};
+
+static const unsigned int max98088_exmode_values[] = {
+ 0x00, 0x43, 0x10, 0x20, 0x30, 0x40, 0x11, 0x22, 0x32
+};
+
+static const struct soc_enum max98088_exmode_enum =
+ SOC_VALUE_ENUM_SINGLE(M98088_REG_41_SPKDHP, 0, 127,
+ ARRAY_SIZE(max98088_exmode_texts),
+ max98088_exmode_texts,
+ max98088_exmode_values);
+static const struct snd_kcontrol_new max98088_exmode_controls =
+ SOC_DAPM_VALUE_ENUM("Route", max98088_exmode_enum);
+
+static const char *max98088_ex_thresh[] = { /* volts PP */
+ "0.6", "1.2", "1.8", "2.4", "3.0", "3.6", "4.2", "4.8"};
+static const struct soc_enum max98088_ex_thresh_enum[] = {
+ SOC_ENUM_SINGLE(M98088_REG_42_SPKDHP_THRESH, 0, 8,
+ max98088_ex_thresh),
+};
+
+static const char *max98088_fltr_mode[] = {"Voice", "Music" };
+static const struct soc_enum max98088_filter_mode_enum[] = {
+ SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 7, 2, max98088_fltr_mode),
+};
+
+static const char *max98088_extmic_text[] = { "None", "MIC1", "MIC2" };
+
+static const struct soc_enum max98088_extmic_enum =
+ SOC_ENUM_SINGLE(M98088_REG_48_CFG_MIC, 0, 3, max98088_extmic_text);
+
+static const struct snd_kcontrol_new max98088_extmic_mux =
+ SOC_DAPM_ENUM("External MIC Mux", max98088_extmic_enum);
+
+static const char *max98088_dai1_fltr[] = {
+ "Off", "fc=258/fs=16k", "fc=500/fs=16k",
+ "fc=258/fs=8k", "fc=500/fs=8k", "fc=200"};
+static const struct soc_enum max98088_dai1_dac_filter_enum[] = {
+ SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 0, 6, max98088_dai1_fltr),
+};
+static const struct soc_enum max98088_dai1_adc_filter_enum[] = {
+ SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 4, 6, max98088_dai1_fltr),
+};
+
+static int max98088_mic1pre_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ unsigned int sel = ucontrol->value.integer.value[0];
+
+ max98088->mic1pre = sel;
+ snd_soc_update_bits(codec, M98088_REG_35_LVL_MIC1, M98088_MICPRE_MASK,
+ (1+sel)<<M98088_MICPRE_SHIFT);
+
+ return 0;
+}
+
+static int max98088_mic1pre_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = max98088->mic1pre;
+ return 0;
+}
+
+static int max98088_mic2pre_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ unsigned int sel = ucontrol->value.integer.value[0];
+
+ max98088->mic2pre = sel;
+ snd_soc_update_bits(codec, M98088_REG_36_LVL_MIC2, M98088_MICPRE_MASK,
+ (1+sel)<<M98088_MICPRE_SHIFT);
+
+ return 0;
+}
+
+static int max98088_mic2pre_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = max98088->mic2pre;
+ return 0;
+}
+
+static const unsigned int max98088_micboost_tlv[] = {
+ TLV_DB_RANGE_HEAD(2),
+ 0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
+ 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
+};
+
+static const struct snd_kcontrol_new max98088_snd_controls[] = {
+
+ SOC_DOUBLE_R("Headphone Volume", M98088_REG_39_LVL_HP_L,
+ M98088_REG_3A_LVL_HP_R, 0, 31, 0),
+ SOC_DOUBLE_R("Speaker Volume", M98088_REG_3D_LVL_SPK_L,
+ M98088_REG_3E_LVL_SPK_R, 0, 31, 0),
+ SOC_DOUBLE_R("Receiver Volume", M98088_REG_3B_LVL_REC_L,
+ M98088_REG_3C_LVL_REC_R, 0, 31, 0),
+
+ SOC_DOUBLE_R("Headphone Switch", M98088_REG_39_LVL_HP_L,
+ M98088_REG_3A_LVL_HP_R, 7, 1, 1),
+ SOC_DOUBLE_R("Speaker Switch", M98088_REG_3D_LVL_SPK_L,
+ M98088_REG_3E_LVL_SPK_R, 7, 1, 1),
+ SOC_DOUBLE_R("Receiver Switch", M98088_REG_3B_LVL_REC_L,
+ M98088_REG_3C_LVL_REC_R, 7, 1, 1),
+
+ SOC_SINGLE("MIC1 Volume", M98088_REG_35_LVL_MIC1, 0, 31, 1),
+ SOC_SINGLE("MIC2 Volume", M98088_REG_36_LVL_MIC2, 0, 31, 1),
+
+ SOC_SINGLE_EXT_TLV("MIC1 Boost Volume",
+ M98088_REG_35_LVL_MIC1, 5, 2, 0,
+ max98088_mic1pre_get, max98088_mic1pre_set,
+ max98088_micboost_tlv),
+ SOC_SINGLE_EXT_TLV("MIC2 Boost Volume",
+ M98088_REG_36_LVL_MIC2, 5, 2, 0,
+ max98088_mic2pre_get, max98088_mic2pre_set,
+ max98088_micboost_tlv),
+
+ SOC_SINGLE("INA Volume", M98088_REG_37_LVL_INA, 0, 7, 1),
+ SOC_SINGLE("INB Volume", M98088_REG_38_LVL_INB, 0, 7, 1),
+
+ SOC_SINGLE("ADCL Volume", M98088_REG_33_LVL_ADC_L, 0, 15, 0),
+ SOC_SINGLE("ADCR Volume", M98088_REG_34_LVL_ADC_R, 0, 15, 0),
+
+ SOC_SINGLE("ADCL Boost Volume", M98088_REG_33_LVL_ADC_L, 4, 3, 0),
+ SOC_SINGLE("ADCR Boost Volume", M98088_REG_34_LVL_ADC_R, 4, 3, 0),
+
+ SOC_SINGLE("EQ1 Switch", M98088_REG_49_CFG_LEVEL, 0, 1, 0),
+ SOC_SINGLE("EQ2 Switch", M98088_REG_49_CFG_LEVEL, 1, 1, 0),
+
+ SOC_ENUM("EX Limiter Threshold", max98088_ex_thresh_enum),
+
+ SOC_ENUM("DAI1 Filter Mode", max98088_filter_mode_enum),
+ SOC_ENUM("DAI1 DAC Filter", max98088_dai1_dac_filter_enum),
+ SOC_ENUM("DAI1 ADC Filter", max98088_dai1_adc_filter_enum),
+ SOC_SINGLE("DAI2 DC Block Switch", M98088_REG_20_DAI2_FILTERS,
+ 0, 1, 0),
+
+ SOC_SINGLE("ALC Switch", M98088_REG_43_SPKALC_COMP, 7, 1, 0),
+ SOC_SINGLE("ALC Threshold", M98088_REG_43_SPKALC_COMP, 0, 7, 0),
+ SOC_SINGLE("ALC Multiband", M98088_REG_43_SPKALC_COMP, 3, 1, 0),
+ SOC_SINGLE("ALC Release Time", M98088_REG_43_SPKALC_COMP, 4, 7, 0),
+
+ SOC_SINGLE("PWR Limiter Threshold", M98088_REG_44_PWRLMT_CFG,
+ 4, 15, 0),
+ SOC_SINGLE("PWR Limiter Weight", M98088_REG_44_PWRLMT_CFG, 0, 7, 0),
+ SOC_SINGLE("PWR Limiter Time1", M98088_REG_45_PWRLMT_TIME, 0, 15, 0),
+ SOC_SINGLE("PWR Limiter Time2", M98088_REG_45_PWRLMT_TIME, 4, 15, 0),
+
+ SOC_SINGLE("THD Limiter Threshold", M98088_REG_46_THDLMT_CFG, 4, 15, 0),
+ SOC_SINGLE("THD Limiter Time", M98088_REG_46_THDLMT_CFG, 0, 7, 0),
+};
+
+/* Left speaker mixer switch */
+static const struct snd_kcontrol_new max98088_left_speaker_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 5, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 4, 1, 0),
+};
+
+/* Right speaker mixer switch */
+static const struct snd_kcontrol_new max98088_right_speaker_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 5, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 4, 1, 0),
+};
+
+/* Left headphone mixer switch */
+static const struct snd_kcontrol_new max98088_left_hp_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_25_MIX_HP_LEFT, 5, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_25_MIX_HP_LEFT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_25_MIX_HP_LEFT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_25_MIX_HP_LEFT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_25_MIX_HP_LEFT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_25_MIX_HP_LEFT, 4, 1, 0),
+};
+
+/* Right headphone mixer switch */
+static const struct snd_kcontrol_new max98088_right_hp_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 5, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_26_MIX_HP_RIGHT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_26_MIX_HP_RIGHT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_26_MIX_HP_RIGHT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_26_MIX_HP_RIGHT, 4, 1, 0),
+};
+
+/* Left earpiece/receiver mixer switch */
+static const struct snd_kcontrol_new max98088_left_rec_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_28_MIX_REC_LEFT, 5, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_28_MIX_REC_LEFT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_28_MIX_REC_LEFT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_28_MIX_REC_LEFT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_28_MIX_REC_LEFT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_28_MIX_REC_LEFT, 4, 1, 0),
+};
+
+/* Right earpiece/receiver mixer switch */
+static const struct snd_kcontrol_new max98088_right_rec_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 5, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_29_MIX_REC_RIGHT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_29_MIX_REC_RIGHT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_29_MIX_REC_RIGHT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_29_MIX_REC_RIGHT, 4, 1, 0),
+};
+
+/* Left ADC mixer switch */
+static const struct snd_kcontrol_new max98088_left_ADC_mixer_controls[] = {
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_23_MIX_ADC_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_23_MIX_ADC_LEFT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_23_MIX_ADC_LEFT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_23_MIX_ADC_LEFT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_23_MIX_ADC_LEFT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_23_MIX_ADC_LEFT, 0, 1, 0),
+};
+
+/* Right ADC mixer switch */
+static const struct snd_kcontrol_new max98088_right_ADC_mixer_controls[] = {
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_24_MIX_ADC_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_24_MIX_ADC_RIGHT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_24_MIX_ADC_RIGHT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_24_MIX_ADC_RIGHT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_24_MIX_ADC_RIGHT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_24_MIX_ADC_RIGHT, 0, 1, 0),
+};
+
+static int max98088_mic_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ if (w->reg == M98088_REG_35_LVL_MIC1) {
+ snd_soc_update_bits(codec, w->reg, M98088_MICPRE_MASK,
+ (1+max98088->mic1pre)<<M98088_MICPRE_SHIFT);
+ } else {
+ snd_soc_update_bits(codec, w->reg, M98088_MICPRE_MASK,
+ (1+max98088->mic2pre)<<M98088_MICPRE_SHIFT);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, w->reg, M98088_MICPRE_MASK, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * The line inputs are 2-channel stereo inputs with the left
+ * and right channels sharing a common PGA power control signal.
+ */
+static int max98088_line_pga(struct snd_soc_dapm_widget *w,
+ int event, int line, u8 channel)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ u8 *state;
+
+ BUG_ON(!((channel == 1) || (channel == 2)));
+
+ switch (line) {
+ case LINE_INA:
+ state = &max98088->ina_state;
+ break;
+ case LINE_INB:
+ state = &max98088->inb_state;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ *state |= channel;
+ snd_soc_update_bits(codec, w->reg,
+ (1 << w->shift), (1 << w->shift));
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ *state &= ~channel;
+ if (*state == 0) {
+ snd_soc_update_bits(codec, w->reg,
+ (1 << w->shift), 0);
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int max98088_pga_ina1_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ return max98088_line_pga(w, event, LINE_INA, 1);
+}
+
+static int max98088_pga_ina2_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ return max98088_line_pga(w, event, LINE_INA, 2);
+}
+
+static int max98088_pga_inb1_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ return max98088_line_pga(w, event, LINE_INB, 1);
+}
+
+static int max98088_pga_inb2_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ return max98088_line_pga(w, event, LINE_INB, 2);
+}
+
+static const struct snd_soc_dapm_widget max98088_dapm_widgets[] = {
+
+ SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", M98088_REG_4C_PWR_EN_IN, 1, 0),
+ SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", M98088_REG_4C_PWR_EN_IN, 0, 0),
+
+ SND_SOC_DAPM_DAC("DACL1", "HiFi Playback",
+ M98088_REG_4D_PWR_EN_OUT, 1, 0),
+ SND_SOC_DAPM_DAC("DACR1", "HiFi Playback",
+ M98088_REG_4D_PWR_EN_OUT, 0, 0),
+ SND_SOC_DAPM_DAC("DACL2", "Aux Playback",
+ M98088_REG_4D_PWR_EN_OUT, 1, 0),
+ SND_SOC_DAPM_DAC("DACR2", "Aux Playback",
+ M98088_REG_4D_PWR_EN_OUT, 0, 0),
+
+ SND_SOC_DAPM_PGA("HP Left Out", M98088_REG_4D_PWR_EN_OUT,
+ 7, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("HP Right Out", M98088_REG_4D_PWR_EN_OUT,
+ 6, 0, NULL, 0),
+
+ SND_SOC_DAPM_PGA("SPK Left Out", M98088_REG_4D_PWR_EN_OUT,
+ 5, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("SPK Right Out", M98088_REG_4D_PWR_EN_OUT,
+ 4, 0, NULL, 0),
+
+ SND_SOC_DAPM_PGA("REC Left Out", M98088_REG_4D_PWR_EN_OUT,
+ 3, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("REC Right Out", M98088_REG_4D_PWR_EN_OUT,
+ 2, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX("External MIC", SND_SOC_NOPM, 0, 0,
+ &max98088_extmic_mux),
+
+ SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_left_hp_mixer_controls[0],
+ ARRAY_SIZE(max98088_left_hp_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Right HP Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_right_hp_mixer_controls[0],
+ ARRAY_SIZE(max98088_right_hp_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Left SPK Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_left_speaker_mixer_controls[0],
+ ARRAY_SIZE(max98088_left_speaker_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Right SPK Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_right_speaker_mixer_controls[0],
+ ARRAY_SIZE(max98088_right_speaker_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Left REC Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_left_rec_mixer_controls[0],
+ ARRAY_SIZE(max98088_left_rec_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Right REC Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_right_rec_mixer_controls[0],
+ ARRAY_SIZE(max98088_right_rec_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_left_ADC_mixer_controls[0],
+ ARRAY_SIZE(max98088_left_ADC_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_right_ADC_mixer_controls[0],
+ ARRAY_SIZE(max98088_right_ADC_mixer_controls)),
+
+ SND_SOC_DAPM_PGA_E("MIC1 Input", M98088_REG_35_LVL_MIC1,
+ 5, 0, NULL, 0, max98088_mic_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("MIC2 Input", M98088_REG_36_LVL_MIC2,
+ 5, 0, NULL, 0, max98088_mic_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("INA1 Input", M98088_REG_4C_PWR_EN_IN,
+ 7, 0, NULL, 0, max98088_pga_ina1_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("INA2 Input", M98088_REG_4C_PWR_EN_IN,
+ 7, 0, NULL, 0, max98088_pga_ina2_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("INB1 Input", M98088_REG_4C_PWR_EN_IN,
+ 6, 0, NULL, 0, max98088_pga_inb1_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("INB2 Input", M98088_REG_4C_PWR_EN_IN,
+ 6, 0, NULL, 0, max98088_pga_inb2_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MICBIAS("MICBIAS", M98088_REG_4C_PWR_EN_IN, 3, 0),
+
+ SND_SOC_DAPM_MUX("EX Limiter Mode", SND_SOC_NOPM, 0, 0,
+ &max98088_exmode_controls),
+
+ SND_SOC_DAPM_OUTPUT("HPL"),
+ SND_SOC_DAPM_OUTPUT("HPR"),
+ SND_SOC_DAPM_OUTPUT("SPKL"),
+ SND_SOC_DAPM_OUTPUT("SPKR"),
+ SND_SOC_DAPM_OUTPUT("RECL"),
+ SND_SOC_DAPM_OUTPUT("RECR"),
+
+ SND_SOC_DAPM_INPUT("MIC1"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+ SND_SOC_DAPM_INPUT("INA1"),
+ SND_SOC_DAPM_INPUT("INA2"),
+ SND_SOC_DAPM_INPUT("INB1"),
+ SND_SOC_DAPM_INPUT("INB2"),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* Left headphone output mixer */
+ {"Left HP Mixer", "Left DAC1 Switch", "DACL1"},
+ {"Left HP Mixer", "Left DAC2 Switch", "DACL2"},
+ {"Left HP Mixer", "Right DAC1 Switch", "DACR1"},
+ {"Left HP Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Left HP Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Left HP Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Left HP Mixer", "INA1 Switch", "INA1 Input"},
+ {"Left HP Mixer", "INA2 Switch", "INA2 Input"},
+ {"Left HP Mixer", "INB1 Switch", "INB1 Input"},
+ {"Left HP Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Right headphone output mixer */
+ {"Right HP Mixer", "Left DAC1 Switch", "DACL1"},
+ {"Right HP Mixer", "Left DAC2 Switch", "DACL2" },
+ {"Right HP Mixer", "Right DAC1 Switch", "DACR1"},
+ {"Right HP Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Right HP Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Right HP Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Right HP Mixer", "INA1 Switch", "INA1 Input"},
+ {"Right HP Mixer", "INA2 Switch", "INA2 Input"},
+ {"Right HP Mixer", "INB1 Switch", "INB1 Input"},
+ {"Right HP Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Left speaker output mixer */
+ {"Left SPK Mixer", "Left DAC1 Switch", "DACL1"},
+ {"Left SPK Mixer", "Left DAC2 Switch", "DACL2"},
+ {"Left SPK Mixer", "Right DAC1 Switch", "DACR1"},
+ {"Left SPK Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Left SPK Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Left SPK Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Left SPK Mixer", "INA1 Switch", "INA1 Input"},
+ {"Left SPK Mixer", "INA2 Switch", "INA2 Input"},
+ {"Left SPK Mixer", "INB1 Switch", "INB1 Input"},
+ {"Left SPK Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Right speaker output mixer */
+ {"Right SPK Mixer", "Left DAC1 Switch", "DACL1"},
+ {"Right SPK Mixer", "Left DAC2 Switch", "DACL2"},
+ {"Right SPK Mixer", "Right DAC1 Switch", "DACR1"},
+ {"Right SPK Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Right SPK Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Right SPK Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Right SPK Mixer", "INA1 Switch", "INA1 Input"},
+ {"Right SPK Mixer", "INA2 Switch", "INA2 Input"},
+ {"Right SPK Mixer", "INB1 Switch", "INB1 Input"},
+ {"Right SPK Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Earpiece/Receiver output mixer */
+ {"Left REC Mixer", "Left DAC1 Switch", "DACL1"},
+ {"Left REC Mixer", "Left DAC2 Switch", "DACL2"},
+ {"Left REC Mixer", "Right DAC1 Switch", "DACR1"},
+ {"Left REC Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Left REC Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Left REC Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Left REC Mixer", "INA1 Switch", "INA1 Input"},
+ {"Left REC Mixer", "INA2 Switch", "INA2 Input"},
+ {"Left REC Mixer", "INB1 Switch", "INB1 Input"},
+ {"Left REC Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Earpiece/Receiver output mixer */
+ {"Right REC Mixer", "Left DAC1 Switch", "DACL1"},
+ {"Right REC Mixer", "Left DAC2 Switch", "DACL2"},
+ {"Right REC Mixer", "Right DAC1 Switch", "DACR1"},
+ {"Right REC Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Right REC Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Right REC Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Right REC Mixer", "INA1 Switch", "INA1 Input"},
+ {"Right REC Mixer", "INA2 Switch", "INA2 Input"},
+ {"Right REC Mixer", "INB1 Switch", "INB1 Input"},
+ {"Right REC Mixer", "INB2 Switch", "INB2 Input"},
+
+ {"HP Left Out", NULL, "Left HP Mixer"},
+ {"HP Right Out", NULL, "Right HP Mixer"},
+ {"SPK Left Out", NULL, "Left SPK Mixer"},
+ {"SPK Right Out", NULL, "Right SPK Mixer"},
+ {"REC Left Out", NULL, "Left REC Mixer"},
+ {"REC Right Out", NULL, "Right REC Mixer"},
+
+ {"HPL", NULL, "HP Left Out"},
+ {"HPR", NULL, "HP Right Out"},
+ {"SPKL", NULL, "SPK Left Out"},
+ {"SPKR", NULL, "SPK Right Out"},
+ {"RECL", NULL, "REC Left Out"},
+ {"RECR", NULL, "REC Right Out"},
+
+ /* Left ADC input mixer */
+ {"Left ADC Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Left ADC Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Left ADC Mixer", "INA1 Switch", "INA1 Input"},
+ {"Left ADC Mixer", "INA2 Switch", "INA2 Input"},
+ {"Left ADC Mixer", "INB1 Switch", "INB1 Input"},
+ {"Left ADC Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Right ADC input mixer */
+ {"Right ADC Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Right ADC Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Right ADC Mixer", "INA1 Switch", "INA1 Input"},
+ {"Right ADC Mixer", "INA2 Switch", "INA2 Input"},
+ {"Right ADC Mixer", "INB1 Switch", "INB1 Input"},
+ {"Right ADC Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Inputs */
+ {"ADCL", NULL, "Left ADC Mixer"},
+ {"ADCR", NULL, "Right ADC Mixer"},
+ {"INA1 Input", NULL, "INA1"},
+ {"INA2 Input", NULL, "INA2"},
+ {"INB1 Input", NULL, "INB1"},
+ {"INB2 Input", NULL, "INB2"},
+ {"MIC1 Input", NULL, "MIC1"},
+ {"MIC2 Input", NULL, "MIC2"},
+};
+
+static int max98088_add_widgets(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_new_controls(codec, max98088_dapm_widgets,
+ ARRAY_SIZE(max98088_dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ snd_soc_add_controls(codec, max98088_snd_controls,
+ ARRAY_SIZE(max98088_snd_controls));
+
+ snd_soc_dapm_new_widgets(codec);
+ return 0;
+}
+
+/* codec mclk clock divider coefficients */
+static const struct {
+ u32 rate;
+ u8 sr;
+} rate_table[] = {
+ {8000, 0x10},
+ {11025, 0x20},
+ {16000, 0x30},
+ {22050, 0x40},
+ {24000, 0x50},
+ {32000, 0x60},
+ {44100, 0x70},
+ {48000, 0x80},
+ {88200, 0x90},
+ {96000, 0xA0},
+};
+
+static inline int rate_value(int rate, u8 *value)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(rate_table); i++) {
+ if (rate_table[i].rate >= rate) {
+ *value = rate_table[i].sr;
+ return 0;
+ }
+ }
+ *value = rate_table[0].sr;
+ return -EINVAL;
+}
+
+static int max98088_dai1_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_cdata *cdata;
+ unsigned long long ni;
+ unsigned int rate;
+ u8 regval;
+
+ cdata = &max98088->dai[0];
+
+ rate = params_rate(params);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
+ M98088_DAI_WS, 0);
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
+ M98088_DAI_WS, M98088_DAI_WS);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, M98088_SHDNRUN, 0);
+
+ if (rate_value(rate, ®val))
+ return -EINVAL;
+
+ snd_soc_update_bits(codec, M98088_REG_11_DAI1_CLKMODE,
+ M98088_CLKMODE_MASK, regval);
+ cdata->rate = rate;
+
+ /* Configure NI when operating as master */
+ if (snd_soc_read(codec, M98088_REG_14_DAI1_FORMAT)
+ & M98088_DAI_MAS) {
+ if (max98088->sysclk == 0) {
+ dev_err(codec->dev, "Invalid system clock frequency\n");
+ return -EINVAL;
+ }
+ ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+ * (unsigned long long int)rate;
+ do_div(ni, (unsigned long long int)max98088->sysclk);
+ snd_soc_write(codec, M98088_REG_12_DAI1_CLKCFG_HI,
+ (ni >> 8) & 0x7F);
+ snd_soc_write(codec, M98088_REG_13_DAI1_CLKCFG_LO,
+ ni & 0xFF);
+ }
+
+ /* Update sample rate mode */
+ if (rate < 50000)
+ snd_soc_update_bits(codec, M98088_REG_18_DAI1_FILTERS,
+ M98088_DAI_DHF, 0);
+ else
+ snd_soc_update_bits(codec, M98088_REG_18_DAI1_FILTERS,
+ M98088_DAI_DHF, M98088_DAI_DHF);
+
+ snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, M98088_SHDNRUN,
+ M98088_SHDNRUN);
+
+ return 0;
+}
+
+static int max98088_dai2_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_cdata *cdata;
+ unsigned long long ni;
+ unsigned int rate;
+ u8 regval;
+
+ cdata = &max98088->dai[1];
+
+ rate = params_rate(params);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ snd_soc_update_bits(codec, M98088_REG_1C_DAI2_FORMAT,
+ M98088_DAI_WS, 0);
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ snd_soc_update_bits(codec, M98088_REG_1C_DAI2_FORMAT,
+ M98088_DAI_WS, M98088_DAI_WS);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, M98088_SHDNRUN, 0);
+
+ if (rate_value(rate, ®val))
+ return -EINVAL;
+
+ snd_soc_update_bits(codec, M98088_REG_19_DAI2_CLKMODE,
+ M98088_CLKMODE_MASK, regval);
+ cdata->rate = rate;
+
+ /* Configure NI when operating as master */
+ if (snd_soc_read(codec, M98088_REG_1C_DAI2_FORMAT)
+ & M98088_DAI_MAS) {
+ if (max98088->sysclk == 0) {
+ dev_err(codec->dev, "Invalid system clock frequency\n");
+ return -EINVAL;
+ }
+ ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+ * (unsigned long long int)rate;
+ do_div(ni, (unsigned long long int)max98088->sysclk);
+ snd_soc_write(codec, M98088_REG_1A_DAI2_CLKCFG_HI,
+ (ni >> 8) & 0x7F);
+ snd_soc_write(codec, M98088_REG_1B_DAI2_CLKCFG_LO,
+ ni & 0xFF);
+ }
+
+ /* Update sample rate mode */
+ if (rate < 50000)
+ snd_soc_update_bits(codec, M98088_REG_20_DAI2_FILTERS,
+ M98088_DAI_DHF, 0);
+ else
+ snd_soc_update_bits(codec, M98088_REG_20_DAI2_FILTERS,
+ M98088_DAI_DHF, M98088_DAI_DHF);
+
+ snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, M98088_SHDNRUN,
+ M98088_SHDNRUN);
+
+ return 0;
+}
+
+static int max98088_dai_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+
+ /* Requested clock frequency is already setup */
+ if (freq == max98088->sysclk)
+ return 0;
+
+ max98088->sysclk = freq; /* remember current sysclk */
+
+ /* Setup clocks for slave mode, and using the PLL
+ * PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
+ * 0x02 (when master clk is 20MHz to 30MHz)..
+ */
+ if ((freq >= 10000000) && (freq < 20000000)) {
+ snd_soc_write(codec, M98088_REG_10_SYS_CLK, 0x10);
+ } else if ((freq >= 20000000) && (freq < 30000000)) {
+ snd_soc_write(codec, M98088_REG_10_SYS_CLK, 0x20);
+ } else {
+ dev_err(codec->dev, "Invalid master clock frequency\n");
+ return -EINVAL;
+ }
+
+ if (snd_soc_read(codec, M98088_REG_51_PWR_SYS) & M98088_SHDNRUN) {
+ snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS,
+ M98088_SHDNRUN, 0);
+ snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS,
+ M98088_SHDNRUN, M98088_SHDNRUN);
+ }
+
+ dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq);
+
+ max98088->sysclk = freq;
+ return 0;
+}
+
+static int max98088_dai1_set_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_cdata *cdata;
+ u8 reg15val;
+ u8 reg14val = 0;
+
+ cdata = &max98088->dai[0];
+
+ if (fmt != cdata->fmt) {
+ cdata->fmt = fmt;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* Slave mode PLL */
+ snd_soc_write(codec, M98088_REG_12_DAI1_CLKCFG_HI,
+ 0x80);
+ snd_soc_write(codec, M98088_REG_13_DAI1_CLKCFG_LO,
+ 0x00);
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* Set to master mode */
+ reg14val |= M98088_DAI_MAS;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBM_CFS:
+ default:
+ dev_err(codec->dev, "Clock mode unsupported");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ reg14val |= M98088_DAI_DLY;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ reg14val |= M98088_DAI_WCI;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ reg14val |= M98088_DAI_BCI;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ reg14val |= M98088_DAI_BCI|M98088_DAI_WCI;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
+ M98088_DAI_MAS | M98088_DAI_DLY | M98088_DAI_BCI |
+ M98088_DAI_WCI, reg14val);
+
+ reg15val = M98088_DAI_BSEL64;
+ if (max98088->digmic)
+ reg15val |= M98088_DAI_OSR64;
+ snd_soc_write(codec, M98088_REG_15_DAI1_CLOCK, reg15val);
+ }
+
+ return 0;
+}
+
+static int max98088_dai2_set_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_cdata *cdata;
+ u8 reg1Cval = 0;
+
+ cdata = &max98088->dai[1];
+
+ if (fmt != cdata->fmt) {
+ cdata->fmt = fmt;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* Slave mode PLL */
+ snd_soc_write(codec, M98088_REG_1A_DAI2_CLKCFG_HI,
+ 0x80);
+ snd_soc_write(codec, M98088_REG_1B_DAI2_CLKCFG_LO,
+ 0x00);
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* Set to master mode */
+ reg1Cval |= M98088_DAI_MAS;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBM_CFS:
+ default:
+ dev_err(codec->dev, "Clock mode unsupported");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ reg1Cval |= M98088_DAI_DLY;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ reg1Cval |= M98088_DAI_WCI;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ reg1Cval |= M98088_DAI_BCI;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ reg1Cval |= M98088_DAI_BCI|M98088_DAI_WCI;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, M98088_REG_1C_DAI2_FORMAT,
+ M98088_DAI_MAS | M98088_DAI_DLY | M98088_DAI_BCI |
+ M98088_DAI_WCI, reg1Cval);
+
+ snd_soc_write(codec, M98088_REG_1D_DAI2_CLOCK,
+ M98088_DAI_BSEL64);
+ }
+
+ return 0;
+}
+
+static void max98088_sync_cache(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ int i;
+
+ if (!codec->cache_sync)
+ return;
+
+ codec->cache_only = 0;
+
+ /* write back cached values if they're writeable and
+ * different from the hardware default.
+ */
+ for (i = 1; i < ARRAY_SIZE(max98088->reg_cache); i++) {
+ if (!max98088_access[i].writable)
+ continue;
+
+ if (max98088->reg_cache[i] == max98088_reg[i])
+ continue;
+
+ snd_soc_write(codec, i, max98088->reg_cache[i]);
+ }
+
+ codec->cache_sync = 0;
+}
+
+static int max98088_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+
+ case SND_SOC_BIAS_PREPARE:
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->bias_level == SND_SOC_BIAS_OFF)
+ max98088_sync_cache(codec);
+
+ snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
+ M98088_MBEN, M98088_MBEN);
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
+ M98088_MBEN, 0);
+ codec->cache_sync = 1;
+ break;
+ }
+ codec->bias_level = level;
+ return 0;
+}
+
+#define MAX98088_RATES SNDRV_PCM_RATE_8000_96000
+#define MAX98088_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops max98088_dai1_ops = {
+ .set_sysclk = max98088_dai_set_sysclk,
+ .set_fmt = max98088_dai1_set_fmt,
+ .hw_params = max98088_dai1_hw_params,
+};
+
+static struct snd_soc_dai_ops max98088_dai2_ops = {
+ .set_sysclk = max98088_dai_set_sysclk,
+ .set_fmt = max98088_dai2_set_fmt,
+ .hw_params = max98088_dai2_hw_params,
+};
+
+static struct snd_soc_dai_driver max98088_dai[] = {
+{
+ .name = "HiFi",
+ .playback = {
+ .stream_name = "HiFi Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MAX98088_RATES,
+ .formats = MAX98088_FORMATS,
+ },
+ .capture = {
+ .stream_name = "HiFi Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MAX98088_RATES,
+ .formats = MAX98088_FORMATS,
+ },
+ .ops = &max98088_dai1_ops,
+},
+{
+ .name = "Aux",
+ .playback = {
+ .stream_name = "Aux Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MAX98088_RATES,
+ .formats = MAX98088_FORMATS,
+ },
+ .ops = &max98088_dai2_ops,
+}
+};
+
+static int max98088_get_channel(const char *name)
+{
+ if (strcmp(name, "EQ1 Mode") == 0)
+ return 0;
+ if (strcmp(name, "EQ2 Mode") == 0)
+ return 1;
+ return -EINVAL;
+}
+
+static void max98088_setup_eq1(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_pdata *pdata = max98088->pdata;
+ struct max98088_eq_cfg *coef_set;
+ int best, best_val, save, i, sel, fs;
+ struct max98088_cdata *cdata;
+
+ cdata = &max98088->dai[0];
+
+ if (!pdata || !max98088->eq_textcnt)
+ return;
+
+ /* Find the selected configuration with nearest sample rate */
+ fs = cdata->rate;
+ sel = cdata->eq_sel;
+
+ best = 0;
+ best_val = INT_MAX;
+ for (i = 0; i < pdata->eq_cfgcnt; i++) {
+ if (strcmp(pdata->eq_cfg[i].name, max98088->eq_texts[sel]) == 0 &&
+ abs(pdata->eq_cfg[i].rate - fs) < best_val) {
+ best = i;
+ best_val = abs(pdata->eq_cfg[i].rate - fs);
+ }
+ }
+
+ dev_dbg(codec->dev, "Selected %s/%dHz for %dHz sample rate\n",
+ pdata->eq_cfg[best].name,
+ pdata->eq_cfg[best].rate, fs);
+
+ /* Disable EQ while configuring, and save current on/off state */
+ save = snd_soc_read(codec, M98088_REG_49_CFG_LEVEL);
+ snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ1EN, 0);
+
+ coef_set = &pdata->eq_cfg[sel];
+
+ m98088_eq_band(codec, 0, 0, coef_set->band1);
+ m98088_eq_band(codec, 0, 1, coef_set->band2);
+ m98088_eq_band(codec, 0, 2, coef_set->band3);
+ m98088_eq_band(codec, 0, 3, coef_set->band4);
+ m98088_eq_band(codec, 0, 4, coef_set->band5);
+
+ /* Restore the original on/off state */
+ snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ1EN, save);
+}
+
+static void max98088_setup_eq2(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_pdata *pdata = max98088->pdata;
+ struct max98088_eq_cfg *coef_set;
+ int best, best_val, save, i, sel, fs;
+ struct max98088_cdata *cdata;
+
+ cdata = &max98088->dai[1];
+
+ if (!pdata || !max98088->eq_textcnt)
+ return;
+
+ /* Find the selected configuration with nearest sample rate */
+ fs = cdata->rate;
+
+ sel = cdata->eq_sel;
+ best = 0;
+ best_val = INT_MAX;
+ for (i = 0; i < pdata->eq_cfgcnt; i++) {
+ if (strcmp(pdata->eq_cfg[i].name, max98088->eq_texts[sel]) == 0 &&
+ abs(pdata->eq_cfg[i].rate - fs) < best_val) {
+ best = i;
+ best_val = abs(pdata->eq_cfg[i].rate - fs);
+ }
+ }
+
+ dev_dbg(codec->dev, "Selected %s/%dHz for %dHz sample rate\n",
+ pdata->eq_cfg[best].name,
+ pdata->eq_cfg[best].rate, fs);
+
+ /* Disable EQ while configuring, and save current on/off state */
+ save = snd_soc_read(codec, M98088_REG_49_CFG_LEVEL);
+ snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ2EN, 0);
+
+ coef_set = &pdata->eq_cfg[sel];
+
+ m98088_eq_band(codec, 1, 0, coef_set->band1);
+ m98088_eq_band(codec, 1, 1, coef_set->band2);
+ m98088_eq_band(codec, 1, 2, coef_set->band3);
+ m98088_eq_band(codec, 1, 3, coef_set->band4);
+ m98088_eq_band(codec, 1, 4, coef_set->band5);
+
+ /* Restore the original on/off state */
+ snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ2EN,
+ save);
+}
+
+static int max98088_put_eq_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_pdata *pdata = max98088->pdata;
+ int channel = max98088_get_channel(kcontrol->id.name);
+ struct max98088_cdata *cdata;
+ int sel = ucontrol->value.integer.value[0];
+
+ cdata = &max98088->dai[channel];
+
+ if (sel >= pdata->eq_cfgcnt)
+ return -EINVAL;
+
+ cdata->eq_sel = sel;
+
+ switch (channel) {
+ case 0:
+ max98088_setup_eq1(codec);
+ break;
+ case 1:
+ max98088_setup_eq2(codec);
+ break;
+ }
+
+ return 0;
+}
+
+static int max98088_get_eq_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ int channel = max98088_get_channel(kcontrol->id.name);
+ struct max98088_cdata *cdata;
+
+ cdata = &max98088->dai[channel];
+ ucontrol->value.enumerated.item[0] = cdata->eq_sel;
+ return 0;
+}
+
+static void max98088_handle_eq_pdata(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_pdata *pdata = max98088->pdata;
+ struct max98088_eq_cfg *cfg;
+ unsigned int cfgcnt;
+ int i, j;
+ const char **t;
+ int ret;
+
+ struct snd_kcontrol_new controls[] = {
+ SOC_ENUM_EXT("EQ1 Mode",
+ max98088->eq_enum,
+ max98088_get_eq_enum,
+ max98088_put_eq_enum),
+ SOC_ENUM_EXT("EQ2 Mode",
+ max98088->eq_enum,
+ max98088_get_eq_enum,
+ max98088_put_eq_enum),
+ };
+
+ cfg = pdata->eq_cfg;
+ cfgcnt = pdata->eq_cfgcnt;
+
+ /* Setup an array of texts for the equalizer enum.
+ * This is based on Mark Brown's equalizer driver code.
+ */
+ max98088->eq_textcnt = 0;
+ max98088->eq_texts = NULL;
+ for (i = 0; i < cfgcnt; i++) {
+ for (j = 0; j < max98088->eq_textcnt; j++) {
+ if (strcmp(cfg[i].name, max98088->eq_texts[j]) == 0)
+ break;
+ }
+
+ if (j != max98088->eq_textcnt)
+ continue;
+
+ /* Expand the array */
+ t = krealloc(max98088->eq_texts,
+ sizeof(char *) * (max98088->eq_textcnt + 1),
+ GFP_KERNEL);
+ if (t == NULL)
+ continue;
+
+ /* Store the new entry */
+ t[max98088->eq_textcnt] = cfg[i].name;
+ max98088->eq_textcnt++;
+ max98088->eq_texts = t;
+ }
+
+ /* Now point the soc_enum to .texts array items */
+ max98088->eq_enum.texts = max98088->eq_texts;
+ max98088->eq_enum.max = max98088->eq_textcnt;
+
+ ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls));
+ if (ret != 0)
+ dev_err(codec->dev, "Failed to add EQ control: %d\n", ret);
+}
+
+static void max98088_handle_pdata(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_pdata *pdata = max98088->pdata;
+ u8 regval = 0;
+
+ if (!pdata) {
+ dev_dbg(codec->dev, "No platform data\n");
+ return;
+ }
+
+ /* Configure mic for analog/digital mic mode */
+ if (pdata->digmic_left_mode)
+ regval |= M98088_DIGMIC_L;
+
+ if (pdata->digmic_right_mode)
+ regval |= M98088_DIGMIC_R;
+
+ max98088->digmic = (regval ? 1 : 0);
+
+ snd_soc_write(codec, M98088_REG_48_CFG_MIC, regval);
+
+ /* Configure receiver output */
+ regval = ((pdata->receiver_mode) ? M98088_REC_LINEMODE : 0);
+ snd_soc_update_bits(codec, M98088_REG_2A_MIC_REC_CNTL,
+ M98088_REC_LINEMODE_MASK, regval);
+
+ /* Configure equalizers */
+ if (pdata->eq_cfgcnt)
+ max98088_handle_eq_pdata(codec);
+}
+
+#ifdef CONFIG_PM
+static int max98088_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+ max98088_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+static int max98088_resume(struct snd_soc_codec *codec)
+{
+ max98088_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ return 0;
+}
+#else
+#define max98088_suspend NULL
+#define max98088_resume NULL
+#endif
+
+static int max98088_probe(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_cdata *cdata;
+ int ret = 0;
+
+ codec->cache_sync = 1;
+ memcpy(codec->reg_cache, max98088_reg, sizeof(max98088_reg));
+
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
+
+ /* initalize private data */
+
+ max98088->sysclk = (unsigned)-1;
+ max98088->eq_textcnt = 0;
+
+ cdata = &max98088->dai[0];
+ cdata->rate = (unsigned)-1;
+ cdata->fmt = (unsigned)-1;
+ cdata->eq_sel = 0;
+
+ cdata = &max98088->dai[1];
+ cdata->rate = (unsigned)-1;
+ cdata->fmt = (unsigned)-1;
+ cdata->eq_sel = 0;
+
+ max98088->ina_state = 0;
+ max98088->inb_state = 0;
+ max98088->ex_mode = 0;
+ max98088->digmic = 0;
+ max98088->mic1pre = 0;
+ max98088->mic2pre = 0;
+
+ ret = snd_soc_read(codec, M98088_REG_FF_REV_ID);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to read device revision: %d\n",
+ ret);
+ goto err_access;
+ }
+ dev_info(codec->dev, "revision %c\n", ret + 'A');
+
+ snd_soc_write(codec, M98088_REG_51_PWR_SYS, M98088_PWRSV);
+
+ /* initialize registers cache to hardware default */
+ max98088_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ snd_soc_write(codec, M98088_REG_0F_IRQ_ENABLE, 0x00);
+
+ snd_soc_write(codec, M98088_REG_22_MIX_DAC,
+ M98088_DAI1L_TO_DACL|M98088_DAI2L_TO_DACL|
+ M98088_DAI1R_TO_DACR|M98088_DAI2R_TO_DACR);
+
+ snd_soc_write(codec, M98088_REG_4E_BIAS_CNTL, 0xF0);
+ snd_soc_write(codec, M98088_REG_50_DAC_BIAS2, 0x0F);
+
+ snd_soc_write(codec, M98088_REG_16_DAI1_IOCFG,
+ M98088_S1NORMAL|M98088_SDATA);
+
+ snd_soc_write(codec, M98088_REG_1E_DAI2_IOCFG,
+ M98088_S2NORMAL|M98088_SDATA);
+
+ max98088_handle_pdata(codec);
+
+ max98088_add_widgets(codec);
+
+err_access:
+ return ret;
+}
+
+static int max98088_remove(struct snd_soc_codec *codec)
+{
+ max98088_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_max98088 = {
+ .probe = max98088_probe,
+ .remove = max98088_remove,
+ .suspend = max98088_suspend,
+ .resume = max98088_resume,
+ .set_bias_level = max98088_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(max98088_reg),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = max98088_reg,
+ .volatile_register = max98088_volatile_register,
+};
+
+static int max98088_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct max98088_priv *max98088;
+ int ret;
+
+ max98088 = kzalloc(sizeof(struct max98088_priv), GFP_KERNEL);
+ if (max98088 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, max98088);
+ max98088->control_data = i2c;
+ max98088->pdata = i2c->dev.platform_data;
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_max98088, &max98088_dai[0], 2);
+ if (ret < 0)
+ kfree(max98088);
+ return ret;
+}
+
+static int max98088_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+static const struct i2c_device_id max98088_i2c_id[] = {
+ { "max98088", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max98088_i2c_id);
+
+static struct i2c_driver max98088_i2c_driver = {
+ .driver = {
+ .name = "max98088",
+ .owner = THIS_MODULE,
+ },
+ .probe = max98088_i2c_probe,
+ .remove = __devexit_p(max98088_i2c_remove),
+ .id_table = max98088_i2c_id,
+};
+
+static int __init max98088_init(void)
+{
+ int ret;
+
+ ret = i2c_add_driver(&max98088_i2c_driver);
+ if (ret)
+ pr_err("Failed to register max98088 I2C driver: %d\n", ret);
+
+ return ret;
+}
+module_init(max98088_init);
+
+static void __exit max98088_exit(void)
+{
+ i2c_del_driver(&max98088_i2c_driver);
+}
+module_exit(max98088_exit);
+
+MODULE_DESCRIPTION("ALSA SoC MAX98088 driver");
+MODULE_AUTHOR("Peter Hsiang, Jesse Marroquin");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98088.h b/sound/soc/codecs/max98088.h
new file mode 100644
index 0000000..56554c7
--- /dev/null
+++ b/sound/soc/codecs/max98088.h
@@ -0,0 +1,193 @@
+/*
+ * max98088.h -- MAX98088 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Maxim Integrated Products
+ *
+ * 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 _MAX98088_H
+#define _MAX98088_H
+
+/*
+ * MAX98088 Registers Definition
+ */
+#define M98088_REG_00_IRQ_STATUS 0x00
+#define M98088_REG_01_MIC_STATUS 0x01
+#define M98088_REG_02_JACK_STAUS 0x02
+#define M98088_REG_03_BATTERY_VOLTAGE 0x03
+#define M98088_REG_0F_IRQ_ENABLE 0x0F
+#define M98088_REG_10_SYS_CLK 0x10
+#define M98088_REG_11_DAI1_CLKMODE 0x11
+#define M98088_REG_12_DAI1_CLKCFG_HI 0x12
+#define M98088_REG_13_DAI1_CLKCFG_LO 0x13
+#define M98088_REG_14_DAI1_FORMAT 0x14
+#define M98088_REG_15_DAI1_CLOCK 0x15
+#define M98088_REG_16_DAI1_IOCFG 0x16
+#define M98088_REG_17_DAI1_TDM 0x17
+#define M98088_REG_18_DAI1_FILTERS 0x18
+#define M98088_REG_19_DAI2_CLKMODE 0x19
+#define M98088_REG_1A_DAI2_CLKCFG_HI 0x1A
+#define M98088_REG_1B_DAI2_CLKCFG_LO 0x1B
+#define M98088_REG_1C_DAI2_FORMAT 0x1C
+#define M98088_REG_1D_DAI2_CLOCK 0x1D
+#define M98088_REG_1E_DAI2_IOCFG 0x1E
+#define M98088_REG_1F_DAI2_TDM 0x1F
+#define M98088_REG_20_DAI2_FILTERS 0x20
+#define M98088_REG_21_SRC 0x21
+#define M98088_REG_22_MIX_DAC 0x22
+#define M98088_REG_23_MIX_ADC_LEFT 0x23
+#define M98088_REG_24_MIX_ADC_RIGHT 0x24
+#define M98088_REG_25_MIX_HP_LEFT 0x25
+#define M98088_REG_26_MIX_HP_RIGHT 0x26
+#define M98088_REG_27_MIX_HP_CNTL 0x27
+#define M98088_REG_28_MIX_REC_LEFT 0x28
+#define M98088_REG_29_MIX_REC_RIGHT 0x29
+#define M98088_REG_2A_MIC_REC_CNTL 0x2A
+#define M98088_REG_2B_MIX_SPK_LEFT 0x2B
+#define M98088_REG_2C_MIX_SPK_RIGHT 0x2C
+#define M98088_REG_2D_MIX_SPK_CNTL 0x2D
+#define M98088_REG_2E_LVL_SIDETONE 0x2E
+#define M98088_REG_2F_LVL_DAI1_PLAY 0x2F
+#define M98088_REG_30_LVL_DAI1_PLAY_EQ 0x30
+#define M98088_REG_31_LVL_DAI2_PLAY 0x31
+#define M98088_REG_32_LVL_DAI2_PLAY_EQ 0x32
+#define M98088_REG_33_LVL_ADC_L 0x33
+#define M98088_REG_34_LVL_ADC_R 0x34
+#define M98088_REG_35_LVL_MIC1 0x35
+#define M98088_REG_36_LVL_MIC2 0x36
+#define M98088_REG_37_LVL_INA 0x37
+#define M98088_REG_38_LVL_INB 0x38
+#define M98088_REG_39_LVL_HP_L 0x39
+#define M98088_REG_3A_LVL_HP_R 0x3A
+#define M98088_REG_3B_LVL_REC_L 0x3B
+#define M98088_REG_3C_LVL_REC_R 0x3C
+#define M98088_REG_3D_LVL_SPK_L 0x3D
+#define M98088_REG_3E_LVL_SPK_R 0x3E
+#define M98088_REG_3F_MICAGC_CFG 0x3F
+#define M98088_REG_40_MICAGC_THRESH 0x40
+#define M98088_REG_41_SPKDHP 0x41
+#define M98088_REG_42_SPKDHP_THRESH 0x42
+#define M98088_REG_43_SPKALC_COMP 0x43
+#define M98088_REG_44_PWRLMT_CFG 0x44
+#define M98088_REG_45_PWRLMT_TIME 0x45
+#define M98088_REG_46_THDLMT_CFG 0x46
+#define M98088_REG_47_CFG_AUDIO_IN 0x47
+#define M98088_REG_48_CFG_MIC 0x48
+#define M98088_REG_49_CFG_LEVEL 0x49
+#define M98088_REG_4A_CFG_BYPASS 0x4A
+#define M98088_REG_4B_CFG_JACKDET 0x4B
+#define M98088_REG_4C_PWR_EN_IN 0x4C
+#define M98088_REG_4D_PWR_EN_OUT 0x4D
+#define M98088_REG_4E_BIAS_CNTL 0x4E
+#define M98088_REG_4F_DAC_BIAS1 0x4F
+#define M98088_REG_50_DAC_BIAS2 0x50
+#define M98088_REG_51_PWR_SYS 0x51
+#define M98088_REG_52_DAI1_EQ_BASE 0x52
+#define M98088_REG_84_DAI2_EQ_BASE 0x84
+#define M98088_REG_B6_DAI1_BIQUAD_BASE 0xB6
+#define M98088_REG_C0_DAI2_BIQUAD_BASE 0xC0
+#define M98088_REG_FF_REV_ID 0xFF
+
+#define M98088_REG_CNT (0xFF+1)
+
+/* MAX98088 Registers Bit Fields */
+
+/* M98088_REG_11_DAI1_CLKMODE, M98088_REG_19_DAI2_CLKMODE */
+ #define M98088_CLKMODE_MASK 0xFF
+
+/* M98088_REG_14_DAI1_FORMAT, M98088_REG_1C_DAI2_FORMAT */
+ #define M98088_DAI_MAS (1<<7)
+ #define M98088_DAI_WCI (1<<6)
+ #define M98088_DAI_BCI (1<<5)
+ #define M98088_DAI_DLY (1<<4)
+ #define M98088_DAI_TDM (1<<2)
+ #define M98088_DAI_FSW (1<<1)
+ #define M98088_DAI_WS (1<<0)
+
+/* M98088_REG_15_DAI1_CLOCK, M98088_REG_1D_DAI2_CLOCK */
+ #define M98088_DAI_BSEL64 (1<<0)
+ #define M98088_DAI_OSR64 (1<<6)
+
+/* M98088_REG_16_DAI1_IOCFG, M98088_REG_1E_DAI2_IOCFG */
+ #define M98088_S1NORMAL (1<<6)
+ #define M98088_S2NORMAL (2<<6)
+ #define M98088_SDATA (3<<0)
+
+/* M98088_REG_18_DAI1_FILTERS, M98088_REG_20_DAI2_FILTERS */
+ #define M98088_DAI_DHF (1<<3)
+
+/* M98088_REG_22_MIX_DAC */
+ #define M98088_DAI1L_TO_DACL (1<<7)
+ #define M98088_DAI1R_TO_DACL (1<<6)
+ #define M98088_DAI2L_TO_DACL (1<<5)
+ #define M98088_DAI2R_TO_DACL (1<<4)
+ #define M98088_DAI1L_TO_DACR (1<<3)
+ #define M98088_DAI1R_TO_DACR (1<<2)
+ #define M98088_DAI2L_TO_DACR (1<<1)
+ #define M98088_DAI2R_TO_DACR (1<<0)
+
+/* M98088_REG_2A_MIC_REC_CNTL */
+ #define M98088_REC_LINEMODE (1<<7)
+ #define M98088_REC_LINEMODE_MASK (1<<7)
+
+/* M98088_REG_35_LVL_MIC1, M98088_REG_36_LVL_MIC2 */
+ #define M98088_MICPRE_MASK (3<<5)
+ #define M98088_MICPRE_SHIFT 5
+
+/* M98088_REG_3A_LVL_HP_R */
+ #define M98088_HP_MUTE (1<<7)
+
+/* M98088_REG_3C_LVL_REC_R */
+ #define M98088_REC_MUTE (1<<7)
+
+/* M98088_REG_3E_LVL_SPK_R */
+ #define M98088_SP_MUTE (1<<7)
+
+/* M98088_REG_48_CFG_MIC */
+ #define M98088_EXTMIC_MASK (3<<0)
+ #define M98088_DIGMIC_L (1<<5)
+ #define M98088_DIGMIC_R (1<<4)
+
+/* M98088_REG_49_CFG_LEVEL */
+ #define M98088_VSEN (1<<6)
+ #define M98088_ZDEN (1<<5)
+ #define M98088_EQ2EN (1<<1)
+ #define M98088_EQ1EN (1<<0)
+
+/* M98088_REG_4C_PWR_EN_IN */
+ #define M98088_INAEN (1<<7)
+ #define M98088_INBEN (1<<6)
+ #define M98088_MBEN (1<<3)
+ #define M98088_ADLEN (1<<1)
+ #define M98088_ADREN (1<<0)
+
+/* M98088_REG_4D_PWR_EN_OUT */
+ #define M98088_HPLEN (1<<7)
+ #define M98088_HPREN (1<<6)
+ #define M98088_HPEN ((1<<7)|(1<<6))
+ #define M98088_SPLEN (1<<5)
+ #define M98088_SPREN (1<<4)
+ #define M98088_RECEN (1<<3)
+ #define M98088_DALEN (1<<1)
+ #define M98088_DAREN (1<<0)
+
+/* M98088_REG_51_PWR_SYS */
+ #define M98088_SHDNRUN (1<<7)
+ #define M98088_PERFMODE (1<<3)
+ #define M98088_HPPLYBACK (1<<2)
+ #define M98088_PWRSV8K (1<<1)
+ #define M98088_PWRSV (1<<0)
+
+/* Line inputs */
+#define LINE_INA 0
+#define LINE_INB 1
+
+#define M98088_COEFS_PER_BAND 5
+
+#define M98088_BYTE1(w) ((w >> 8) & 0xff)
+#define M98088_BYTE0(w) (w & 0xff)
+
+#endif
diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c
index 5a5f187..bd8f26e 100644
--- a/sound/soc/codecs/pcm3008.c
+++ b/sound/soc/codecs/pcm3008.c
@@ -32,8 +32,8 @@
#define PCM3008_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000)
-struct snd_soc_dai pcm3008_dai = {
- .name = "PCM3008 HiFi",
+static struct snd_soc_dai_driver pcm3008_dai = {
+ .name = "pcm3008-hifi",
.playback = {
.stream_name = "PCM3008 Playback",
.channels_min = 1,
@@ -49,7 +49,6 @@
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
};
-EXPORT_SYMBOL_GPL(pcm3008_dai);
static void pcm3008_gpio_free(struct pcm3008_setup_data *setup)
{
@@ -59,38 +58,13 @@
gpio_free(setup->pdda_pin);
}
-static int pcm3008_soc_probe(struct platform_device *pdev)
+static int pcm3008_soc_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- struct pcm3008_setup_data *setup = socdev->codec_data;
+ struct pcm3008_setup_data *setup = codec->dev->platform_data;
int ret = 0;
printk(KERN_INFO "PCM3008 SoC Audio Codec %s\n", PCM3008_VERSION);
- socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (!socdev->card->codec)
- return -ENOMEM;
-
- codec = socdev->card->codec;
- mutex_init(&codec->mutex);
-
- codec->name = "PCM3008";
- codec->owner = THIS_MODULE;
- codec->dai = &pcm3008_dai;
- codec->num_dai = 1;
- codec->write = NULL;
- codec->read = NULL;
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- /* Register PCMs. */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "pcm3008: failed to create pcms\n");
- goto pcm_err;
- }
-
/* DEM1 DEM0 DE-EMPHASIS_MODE
* Low Low De-emphasis 44.1 kHz ON
* Low High De-emphasis OFF
@@ -130,33 +104,22 @@
gpio_err:
pcm3008_gpio_free(setup);
-pcm_err:
- kfree(socdev->card->codec);
return ret;
}
-static int pcm3008_soc_remove(struct platform_device *pdev)
+static int pcm3008_soc_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
- struct pcm3008_setup_data *setup = socdev->codec_data;
-
- if (!codec)
- return 0;
+ struct pcm3008_setup_data *setup = codec->dev->platform_data;
pcm3008_gpio_free(setup);
- snd_soc_free_pcms(socdev);
- kfree(socdev->card->codec);
-
return 0;
}
#ifdef CONFIG_PM
-static int pcm3008_soc_suspend(struct platform_device *pdev, pm_message_t msg)
+static int pcm3008_soc_suspend(struct snd_soc_codec *codec, pm_message_t msg)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct pcm3008_setup_data *setup = socdev->codec_data;
+ struct pcm3008_setup_data *setup = codec->dev->platform_data;
gpio_set_value(setup->pdad_pin, 0);
gpio_set_value(setup->pdda_pin, 0);
@@ -164,10 +127,9 @@
return 0;
}
-static int pcm3008_soc_resume(struct platform_device *pdev)
+static int pcm3008_soc_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct pcm3008_setup_data *setup = socdev->codec_data;
+ struct pcm3008_setup_data *setup = codec->dev->platform_data;
gpio_set_value(setup->pdad_pin, 1);
gpio_set_value(setup->pdda_pin, 1);
@@ -179,23 +141,45 @@
#define pcm3008_soc_resume NULL
#endif
-struct snd_soc_codec_device soc_codec_dev_pcm3008 = {
+static struct snd_soc_codec_driver soc_codec_dev_pcm3008 = {
.probe = pcm3008_soc_probe,
.remove = pcm3008_soc_remove,
.suspend = pcm3008_soc_suspend,
.resume = pcm3008_soc_resume,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_pcm3008);
-static int __init pcm3008_init(void)
+static int __devinit pcm3008_codec_probe(struct platform_device *pdev)
{
- return snd_soc_register_dai(&pcm3008_dai);
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_pcm3008, &pcm3008_dai, 1);
}
-module_init(pcm3008_init);
+
+static int __devexit pcm3008_codec_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+MODULE_ALIAS("platform:pcm3008-codec");
+
+static struct platform_driver pcm3008_codec_driver = {
+ .probe = pcm3008_codec_probe,
+ .remove = __devexit_p(pcm3008_codec_remove),
+ .driver = {
+ .name = "pcm3008-codec",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pcm3008_modinit(void)
+{
+ return platform_driver_register(&pcm3008_codec_driver);
+}
+module_init(pcm3008_modinit);
static void __exit pcm3008_exit(void)
{
- snd_soc_unregister_dai(&pcm3008_dai);
+ platform_driver_unregister(&pcm3008_codec_driver);
}
module_exit(pcm3008_exit);
diff --git a/sound/soc/codecs/pcm3008.h b/sound/soc/codecs/pcm3008.h
index d04e87d..7e5489a 100644
--- a/sound/soc/codecs/pcm3008.h
+++ b/sound/soc/codecs/pcm3008.h
@@ -19,7 +19,4 @@
unsigned pdda_pin;
};
-extern struct snd_soc_codec_device soc_codec_dev_pcm3008;
-extern struct snd_soc_dai pcm3008_dai;
-
#endif
diff --git a/sound/soc/codecs/spdif_transciever.c b/sound/soc/codecs/spdif_transciever.c
index 9119836..4c32b54 100644
--- a/sound/soc/codecs/spdif_transciever.c
+++ b/sound/soc/codecs/spdif_transciever.c
@@ -21,57 +21,16 @@
#include <sound/pcm.h>
#include <sound/initval.h>
-#include "spdif_transciever.h"
-
MODULE_LICENSE("GPL");
#define STUB_RATES SNDRV_PCM_RATE_8000_96000
#define STUB_FORMATS SNDRV_PCM_FMTBIT_S16_LE
-static struct snd_soc_codec *spdif_dit_codec;
-static int spdif_dit_codec_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret;
+static struct snd_soc_codec_driver soc_codec_spdif_dit;
- if (spdif_dit_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = spdif_dit_codec;
- codec = spdif_dit_codec;
-
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto err_create_pcms;
- }
-
- return 0;
-
-err_create_pcms:
- return ret;
-}
-
-static int spdif_dit_codec_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_spdif_dit = {
- .probe = spdif_dit_codec_probe,
- .remove = spdif_dit_codec_remove,
-}; EXPORT_SYMBOL_GPL(soc_codec_dev_spdif_dit);
-
-struct snd_soc_dai dit_stub_dai = {
- .name = "DIT",
+static struct snd_soc_dai_driver dit_stub_dai = {
+ .name = "dit-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -80,65 +39,16 @@
.formats = STUB_FORMATS,
},
};
-EXPORT_SYMBOL_GPL(dit_stub_dai);
static int spdif_dit_probe(struct platform_device *pdev)
{
- struct snd_soc_codec *codec;
- int ret;
-
- if (spdif_dit_codec) {
- dev_err(&pdev->dev, "Another Codec is registered\n");
- ret = -EINVAL;
- goto err_reg_codec;
- }
-
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
-
- codec->dev = &pdev->dev;
-
- mutex_init(&codec->mutex);
-
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->name = "spdif-dit";
- codec->owner = THIS_MODULE;
- codec->dai = &dit_stub_dai;
- codec->num_dai = 1;
-
- spdif_dit_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err_reg_codec;
- }
-
- dit_stub_dai.dev = &pdev->dev;
- ret = snd_soc_register_dai(&dit_stub_dai);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to register dai: %d\n", ret);
- goto err_reg_dai;
- }
-
- return 0;
-
-err_reg_dai:
- snd_soc_unregister_codec(codec);
-err_reg_codec:
- kfree(spdif_dit_codec);
- return ret;
+ return snd_soc_register_codec(&pdev->dev, &soc_codec_spdif_dit,
+ &dit_stub_dai, 1);
}
static int spdif_dit_remove(struct platform_device *pdev)
{
- snd_soc_unregister_dai(&dit_stub_dai);
- snd_soc_unregister_codec(spdif_dit_codec);
- kfree(spdif_dit_codec);
- spdif_dit_codec = NULL;
+ snd_soc_unregister_codec(&pdev->dev);
return 0;
}
diff --git a/sound/soc/codecs/spdif_transciever.h b/sound/soc/codecs/spdif_transciever.h
deleted file mode 100644
index 1e10212..0000000
--- a/sound/soc/codecs/spdif_transciever.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * ALSA SoC DIT/DIR driver header
- *
- * Author: Steve Chen, <schen@mvista.com>
- * Copyright: (C) 2008 MontaVista Software, Inc., <source@mvista.com>
- *
- * 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 CODEC_STUBS_H
-#define CODEC_STUBS_H
-
-extern struct snd_soc_codec_device soc_codec_dev_spdif_dit;
-extern struct snd_soc_dai dit_stub_dai;
-
-#endif /* CODEC_STUBS_H */
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index b47ed4f..6f38d61 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -45,11 +45,11 @@
#define SSM2602_VERSION "0.1"
-struct snd_soc_codec_device soc_codec_dev_ssm2602;
-
/* codec private data */
struct ssm2602_priv {
unsigned int sysclk;
+ enum snd_soc_control_type control_type;
+ void *control_data;
struct snd_pcm_substream *master_substream;
struct snd_pcm_substream *slave_substream;
};
@@ -276,8 +276,7 @@
{
u16 srate;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
struct i2c_client *i2c = codec->control_data;
u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3;
@@ -321,8 +320,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
struct i2c_client *i2c = codec->control_data;
struct snd_pcm_runtime *master_runtime;
@@ -360,8 +358,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
/* set active */
ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
@@ -372,8 +369,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
/* deactivate */
@@ -518,8 +514,8 @@
.set_fmt = ssm2602_set_dai_fmt,
};
-struct snd_soc_dai ssm2602_dai = {
- .name = "SSM2602",
+static struct snd_soc_dai_driver ssm2602_dai = {
+ .name = "ssm2602-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -534,21 +530,15 @@
.formats = SSM2602_FORMATS,},
.ops = &ssm2602_dai_ops,
};
-EXPORT_SYMBOL_GPL(ssm2602_dai);
-static int ssm2602_suspend(struct platform_device *pdev, pm_message_t state)
+static int ssm2602_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int ssm2602_resume(struct platform_device *pdev)
+static int ssm2602_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -563,36 +553,17 @@
return 0;
}
-/*
- * initialise the ssm2602 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int ssm2602_init(struct snd_soc_device *socdev)
+static int ssm2602_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = socdev->card->codec;
- int reg, ret = 0;
+ struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0, reg;
- codec->name = "SSM2602";
- codec->owner = THIS_MODULE;
- codec->read = ssm2602_read_reg_cache;
- codec->write = ssm2602_write;
- codec->set_bias_level = ssm2602_set_bias_level;
- codec->dai = &ssm2602_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = sizeof(ssm2602_reg);
- codec->reg_cache = kmemdup(ssm2602_reg, sizeof(ssm2602_reg),
- GFP_KERNEL);
- if (codec->reg_cache == NULL)
- return -ENOMEM;
+ pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
+
+ codec->control_data = ssm2602->control_data;
ssm2602_reset(codec);
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- pr_err("ssm2602: failed to create pcms\n");
- goto pcm_err;
- }
/*power on device*/
ssm2602_write(codec, SSM2602_ACTIVE, 0);
/* set the update bits */
@@ -614,13 +585,27 @@
ssm2602_add_widgets(codec);
return ret;
-
-pcm_err:
- kfree(codec->reg_cache);
- return ret;
}
-static struct snd_soc_device *ssm2602_socdev;
+/* remove everything here */
+static int ssm2602_remove(struct snd_soc_codec *codec)
+{
+ ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
+ .probe = ssm2602_probe,
+ .remove = ssm2602_remove,
+ .suspend = ssm2602_suspend,
+ .resume = ssm2602_resume,
+ .read = ssm2602_read_reg_cache,
+ .write = ssm2602_write,
+ .set_bias_level = ssm2602_set_bias_level,
+ .reg_cache_size = sizeof(ssm2602_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = ssm2602_reg,
+};
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
/*
@@ -632,24 +617,28 @@
static int ssm2602_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
- struct snd_soc_device *socdev = ssm2602_socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct ssm2602_priv *ssm2602;
int ret;
- i2c_set_clientdata(i2c, codec);
- codec->control_data = i2c;
+ ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL);
+ if (ssm2602 == NULL)
+ return -ENOMEM;
- ret = ssm2602_init(socdev);
+ i2c_set_clientdata(i2c, ssm2602);
+ ssm2602->control_data = i2c;
+ ssm2602->control_type = SND_SOC_I2C;
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_ssm2602, &ssm2602_dai, 1);
if (ret < 0)
- pr_err("failed to initialise SSM2602\n");
-
+ kfree(ssm2602);
return ret;
}
static int ssm2602_i2c_remove(struct i2c_client *client)
{
- struct snd_soc_codec *codec = i2c_get_clientdata(client);
- kfree(codec->reg_cache);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -658,130 +647,39 @@
{ }
};
MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
+
/* corgi i2c codec control layer */
static struct i2c_driver ssm2602_i2c_driver = {
.driver = {
- .name = "SSM2602 I2C Codec",
+ .name = "ssm2602-codec",
.owner = THIS_MODULE,
},
.probe = ssm2602_i2c_probe,
.remove = ssm2602_i2c_remove,
.id_table = ssm2602_i2c_id,
};
-
-static int ssm2602_add_i2c_device(struct platform_device *pdev,
- const struct ssm2602_setup_data *setup)
-{
- struct i2c_board_info info;
- struct i2c_adapter *adapter;
- struct i2c_client *client;
- int ret;
-
- ret = i2c_add_driver(&ssm2602_i2c_driver);
- if (ret != 0) {
- dev_err(&pdev->dev, "can't add i2c driver\n");
- return ret;
- }
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = setup->i2c_address;
- strlcpy(info.type, "ssm2602", I2C_NAME_SIZE);
- adapter = i2c_get_adapter(setup->i2c_bus);
- if (!adapter) {
- dev_err(&pdev->dev, "can't get i2c adapter %d\n",
- setup->i2c_bus);
- goto err_driver;
- }
- client = i2c_new_device(adapter, &info);
- i2c_put_adapter(adapter);
- if (!client) {
- dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
- (unsigned int)info.addr);
- goto err_driver;
- }
- return 0;
-err_driver:
- i2c_del_driver(&ssm2602_i2c_driver);
- return -ENODEV;
-}
#endif
-static int ssm2602_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct ssm2602_setup_data *setup;
- struct snd_soc_codec *codec;
- struct ssm2602_priv *ssm2602;
- int ret = 0;
-
- pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
-
- setup = socdev->codec_data;
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
-
- ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL);
- if (ssm2602 == NULL) {
- kfree(codec);
- return -ENOMEM;
- }
-
- snd_soc_codec_set_drvdata(codec, ssm2602);
- socdev->card->codec = codec;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- ssm2602_socdev = socdev;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- if (setup->i2c_address) {
- codec->hw_write = (hw_write_t)i2c_master_send;
- ret = ssm2602_add_i2c_device(pdev, setup);
- }
-#else
- /* other interfaces */
-#endif
- return ret;
-}
-
-/* remove everything here */
-static int ssm2602_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec->control_data)
- ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- i2c_unregister_device(codec->control_data);
- i2c_del_driver(&ssm2602_i2c_driver);
-#endif
- kfree(snd_soc_codec_get_drvdata(codec));
- kfree(codec);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_ssm2602 = {
- .probe = ssm2602_probe,
- .remove = ssm2602_remove,
- .suspend = ssm2602_suspend,
- .resume = ssm2602_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ssm2602);
static int __init ssm2602_modinit(void)
{
- return snd_soc_register_dai(&ssm2602_dai);
+ int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&ssm2602_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register SSM2602 I2C driver: %d\n",
+ ret);
+ }
+#endif
+ return ret;
}
module_init(ssm2602_modinit);
static void __exit ssm2602_exit(void)
{
- snd_soc_unregister_dai(&ssm2602_dai);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&ssm2602_i2c_driver);
+#endif
}
module_exit(ssm2602_exit);
diff --git a/sound/soc/codecs/ssm2602.h b/sound/soc/codecs/ssm2602.h
index f344e6d..42a47d0 100644
--- a/sound/soc/codecs/ssm2602.h
+++ b/sound/soc/codecs/ssm2602.h
@@ -124,7 +124,4 @@
unsigned short i2c_address;
};
-extern struct snd_soc_dai ssm2602_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ssm2602;
-
#endif
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c
index ee86568..00d67cc 100644
--- a/sound/soc/codecs/stac9766.c
+++ b/sound/soc/codecs/stac9766.c
@@ -25,7 +25,6 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/tlv.h>
-#include <sound/soc-of-simple.h>
#include "stac9766.h"
@@ -257,20 +256,15 @@
return 0;
}
-static int stac9766_codec_suspend(struct platform_device *pdev,
+static int stac9766_codec_suspend(struct snd_soc_codec *codec,
pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
stac9766_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int stac9766_codec_resume(struct platform_device *pdev)
+static int stac9766_codec_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
u16 id, reset;
reset = 0;
@@ -300,10 +294,9 @@
.prepare = ac97_digital_prepare,
};
-struct snd_soc_dai stac9766_dai[] = {
+static struct snd_soc_dai_driver stac9766_dai[] = {
{
- .name = "stac9766 analog",
- .id = 0,
+ .name = "stac9766-hifi-analog",
.ac97_control = 1,
/* stream cababilities */
@@ -325,8 +318,7 @@
.ops = &stac9766_dai_ops_analog,
},
{
- .name = "stac9766 IEC958",
- .id = 1,
+ .name = "stac9766-hifi-IEC958",
.ac97_control = 1,
/* stream cababilities */
@@ -342,57 +334,24 @@
.ops = &stac9766_dai_ops_digital,
}
};
-EXPORT_SYMBOL_GPL(stac9766_dai);
-static int stac9766_codec_probe(struct platform_device *pdev)
+static int stac9766_codec_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
int ret = 0;
printk(KERN_INFO "STAC9766 SoC Audio Codec %s\n", STAC9766_VERSION);
- socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (socdev->card->codec == NULL)
- return -ENOMEM;
- codec = socdev->card->codec;
- mutex_init(&codec->mutex);
-
- codec->reg_cache = kmemdup(stac9766_reg, sizeof(stac9766_reg),
- GFP_KERNEL);
- if (codec->reg_cache == NULL) {
- ret = -ENOMEM;
- goto cache_err;
- }
- codec->reg_cache_size = sizeof(stac9766_reg);
- codec->reg_cache_step = 2;
-
- codec->name = "STAC9766";
- codec->owner = THIS_MODULE;
- codec->dai = stac9766_dai;
- codec->num_dai = ARRAY_SIZE(stac9766_dai);
- codec->write = stac9766_ac97_write;
- codec->read = stac9766_ac97_read;
- codec->set_bias_level = stac9766_set_bias_level;
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
if (ret < 0)
goto codec_err;
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0)
- goto pcm_err;
-
/* do a cold reset for the controller and then try
* a warm reset followed by an optional cold reset for codec */
stac9766_reset(codec, 0);
ret = stac9766_reset(codec, 1);
if (ret < 0) {
printk(KERN_ERR "Failed to reset STAC9766: AC97 link error\n");
- goto reset_err;
+ goto codec_err;
}
stac9766_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -402,40 +361,63 @@
return 0;
-reset_err:
- snd_soc_free_pcms(socdev);
-pcm_err:
- snd_soc_free_ac97_codec(codec);
codec_err:
- kfree(snd_soc_codec_get_drvdata(codec));
-cache_err:
- kfree(socdev->card->codec);
- socdev->card->codec = NULL;
+ snd_soc_free_ac97_codec(codec);
return ret;
}
-static int stac9766_codec_remove(struct platform_device *pdev)
+static int stac9766_codec_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec == NULL)
- return 0;
-
- snd_soc_free_pcms(socdev);
snd_soc_free_ac97_codec(codec);
- kfree(codec->reg_cache);
- kfree(codec);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_stac9766 = {
+static struct snd_soc_codec_driver soc_codec_dev_stac9766 = {
+ .write = stac9766_ac97_write,
+ .read = stac9766_ac97_read,
+ .set_bias_level = stac9766_set_bias_level,
.probe = stac9766_codec_probe,
.remove = stac9766_codec_remove,
.suspend = stac9766_codec_suspend,
.resume = stac9766_codec_resume,
+ .reg_cache_size = sizeof(stac9766_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_step = 2,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_stac9766);
+
+static __devinit int stac9766_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_stac9766, stac9766_dai, ARRAY_SIZE(stac9766_dai));
+}
+
+static int __devexit stac9766_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver stac9766_codec_driver = {
+ .driver = {
+ .name = "stac9766-codec",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = stac9766_probe,
+ .remove = __devexit_p(stac9766_remove),
+};
+
+static int __init stac9766_init(void)
+{
+ return platform_driver_register(&stac9766_codec_driver);
+}
+module_init(stac9766_init);
+
+static void __exit stac9766_exit(void)
+{
+ platform_driver_unregister(&stac9766_codec_driver);
+}
+module_exit(stac9766_exit);
MODULE_DESCRIPTION("ASoC stac9766 driver");
MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
diff --git a/sound/soc/codecs/stac9766.h b/sound/soc/codecs/stac9766.h
index 65642eb..c726f90 100644
--- a/sound/soc/codecs/stac9766.h
+++ b/sound/soc/codecs/stac9766.h
@@ -14,8 +14,4 @@
#define STAC9766_DAI_AC97_ANALOG 0
#define STAC9766_DAI_AC97_DIGITAL 1
-extern struct snd_soc_dai stac9766_dai[];
-extern struct snd_soc_codec_device soc_codec_dev_stac9766;
-
-
#endif
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index 0a4b0fe..e8652b1 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -240,7 +240,8 @@
/* AIC23 driver data */
struct aic23 {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
+ void *control_data;
int mclk;
int requested_adc;
int requested_dac;
@@ -404,11 +405,10 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
u16 iface_reg;
int ret;
- struct aic23 *aic23 = container_of(codec, struct aic23, codec);
+ struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
u32 sample_rate_adc = aic23->requested_adc;
u32 sample_rate_dac = aic23->requested_dac;
u32 sample_rate = params_rate(params);
@@ -452,8 +452,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
/* set active */
tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0001);
@@ -465,9 +464,8 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
- struct aic23 *aic23 = container_of(codec, struct aic23, codec);
+ struct snd_soc_codec *codec = rtd->codec;
+ struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
/* deactivate */
if (!codec->active) {
@@ -546,8 +544,7 @@
static int tlv320aic23_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
- struct snd_soc_codec *codec = codec_dai->codec;
- struct aic23 *aic23 = container_of(codec, struct aic23, codec);
+ struct aic23 *aic23 = snd_soc_dai_get_drvdata(codec_dai);
aic23->mclk = freq;
return 0;
}
@@ -594,8 +591,8 @@
.set_sysclk = tlv320aic23_set_dai_sysclk,
};
-struct snd_soc_dai tlv320aic23_dai = {
- .name = "tlv320aic23",
+static struct snd_soc_dai_driver tlv320aic23_dai = {
+ .name = "tlv320aic23-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -610,23 +607,17 @@
.formats = AIC23_FORMATS,},
.ops = &tlv320aic23_dai_ops,
};
-EXPORT_SYMBOL_GPL(tlv320aic23_dai);
-static int tlv320aic23_suspend(struct platform_device *pdev,
+static int tlv320aic23_suspend(struct snd_soc_codec *codec,
pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int tlv320aic23_resume(struct platform_device *pdev)
+static int tlv320aic23_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
u16 reg;
/* Sync reg_cache with the hardware */
@@ -639,39 +630,19 @@
return 0;
}
-/*
- * initialise the AIC23 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int tlv320aic23_init(struct snd_soc_device *socdev)
+static int tlv320aic23_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = socdev->card->codec;
- int ret = 0;
- u16 reg;
+ struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
+ int reg;
- codec->name = "tlv320aic23";
- codec->owner = THIS_MODULE;
- codec->read = tlv320aic23_read_reg_cache;
- codec->write = tlv320aic23_write;
- codec->set_bias_level = tlv320aic23_set_bias_level;
- codec->dai = &tlv320aic23_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(tlv320aic23_reg);
- codec->reg_cache =
- kmemdup(tlv320aic23_reg, sizeof(tlv320aic23_reg), GFP_KERNEL);
- if (codec->reg_cache == NULL)
- return -ENOMEM;
+ printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
+ codec->control_data = aic23->control_data;
+ codec->hw_write = (hw_write_t)i2c_master_send;
+ codec->hw_read = NULL;
/* Reset codec */
tlv320aic23_write(codec, TLV320AIC23_RESET, 0);
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "tlv320aic23: failed to create pcms\n");
- goto pcm_err;
- }
-
/* power on device */
tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -707,13 +678,27 @@
ARRAY_SIZE(tlv320aic23_snd_controls));
tlv320aic23_add_widgets(codec);
- return ret;
-
-pcm_err:
- kfree(codec->reg_cache);
- return ret;
+ return 0;
}
-static struct snd_soc_device *tlv320aic23_socdev;
+
+static int tlv320aic23_remove(struct snd_soc_codec *codec)
+{
+ tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
+ .reg_cache_size = ARRAY_SIZE(tlv320aic23_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = tlv320aic23_reg,
+ .probe = tlv320aic23_probe,
+ .remove = tlv320aic23_remove,
+ .suspend = tlv320aic23_suspend,
+ .resume = tlv320aic23_resume,
+ .read = tlv320aic23_read_reg_cache,
+ .write = tlv320aic23_write,
+ .set_bias_level = tlv320aic23_set_bias_level,
+};
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
/*
@@ -723,31 +708,30 @@
static int tlv320aic23_codec_probe(struct i2c_client *i2c,
const struct i2c_device_id *i2c_id)
{
- struct snd_soc_device *socdev = tlv320aic23_socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct aic23 *aic23;
int ret;
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EINVAL;
- i2c_set_clientdata(i2c, codec);
- codec->control_data = i2c;
+ aic23 = kzalloc(sizeof(struct aic23), GFP_KERNEL);
+ if (aic23 == NULL)
+ return -ENOMEM;
- ret = tlv320aic23_init(socdev);
- if (ret < 0) {
- printk(KERN_ERR "tlv320aic23: failed to initialise AIC23\n");
- goto err;
- }
- return ret;
+ i2c_set_clientdata(i2c, aic23);
+ aic23->control_data = i2c;
+ aic23->control_type = SND_SOC_I2C;
-err:
- kfree(codec);
- kfree(i2c);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_tlv320aic23, &tlv320aic23_dai, 1);
+ if (ret < 0)
+ kfree(aic23);
return ret;
}
static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c)
{
- put_device(&i2c->dev);
+ snd_soc_unregister_codec(&i2c->dev);
+ kfree(i2c_get_clientdata(i2c));
return 0;
}
@@ -760,7 +744,7 @@
static struct i2c_driver tlv320aic23_i2c_driver = {
.driver = {
- .name = "tlv320aic23",
+ .name = "tlv320aic23-codec",
},
.probe = tlv320aic23_codec_probe,
.remove = __exit_p(tlv320aic23_i2c_remove),
@@ -769,71 +753,25 @@
#endif
-static int tlv320aic23_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- struct aic23 *aic23;
- int ret = 0;
-
- printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
-
- aic23 = kzalloc(sizeof(struct aic23), GFP_KERNEL);
- if (aic23 == NULL)
- return -ENOMEM;
- codec = &aic23->codec;
- socdev->card->codec = codec;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- tlv320aic23_socdev = socdev;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- codec->hw_write = (hw_write_t) i2c_master_send;
- codec->hw_read = NULL;
- ret = i2c_add_driver(&tlv320aic23_i2c_driver);
- if (ret != 0)
- printk(KERN_ERR "can't add i2c driver");
-#endif
- return ret;
-}
-
-static int tlv320aic23_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
- struct aic23 *aic23 = container_of(codec, struct aic23, codec);
-
- if (codec->control_data)
- tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- i2c_del_driver(&tlv320aic23_i2c_driver);
-#endif
- kfree(codec->reg_cache);
- kfree(aic23);
-
- return 0;
-}
-struct snd_soc_codec_device soc_codec_dev_tlv320aic23 = {
- .probe = tlv320aic23_probe,
- .remove = tlv320aic23_remove,
- .suspend = tlv320aic23_suspend,
- .resume = tlv320aic23_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320aic23);
-
static int __init tlv320aic23_modinit(void)
{
- return snd_soc_register_dai(&tlv320aic23_dai);
+ int ret;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&tlv320aic23_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register TLV320AIC23 I2C driver: %d\n",
+ ret);
+ }
+#endif
+ return ret;
}
module_init(tlv320aic23_modinit);
static void __exit tlv320aic23_exit(void)
{
- snd_soc_unregister_dai(&tlv320aic23_dai);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&tlv320aic23_i2c_driver);
+#endif
}
module_exit(tlv320aic23_exit);
diff --git a/sound/soc/codecs/tlv320aic23.h b/sound/soc/codecs/tlv320aic23.h
index 79d1faf..e804120 100644
--- a/sound/soc/codecs/tlv320aic23.h
+++ b/sound/soc/codecs/tlv320aic23.h
@@ -116,7 +116,4 @@
#define TLV320AIC23_SIDETONE_12 0x080
#define TLV320AIC23_SIDETONE_18 0x0c0
-extern struct snd_soc_dai tlv320aic23_dai;
-extern struct snd_soc_codec_device soc_codec_dev_tlv320aic23;
-
#endif /* _TLV320AIC23_H */
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
index f0e00fd..6b7d71e 100644
--- a/sound/soc/codecs/tlv320aic26.c
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -19,7 +19,6 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
-#include <sound/soc-of-simple.h>
#include <sound/initval.h>
#include "tlv320aic26.h"
@@ -130,8 +129,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
int fsref, divisor, wlen, pval, jval, dval, qval;
u16 reg;
@@ -278,8 +276,8 @@
.set_fmt = aic26_set_fmt,
};
-struct snd_soc_dai aic26_dai = {
- .name = "tlv320aic26",
+static struct snd_soc_dai_driver aic26_dai = {
+ .name = "tlv320aic26-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -296,7 +294,6 @@
},
.ops = &aic26_dai_ops,
};
-EXPORT_SYMBOL_GPL(aic26_dai);
/* ---------------------------------------------------------------------
* ALSA controls
@@ -319,61 +316,6 @@
};
/* ---------------------------------------------------------------------
- * SoC CODEC portion of driver: probe and release routines
- */
-static int aic26_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- struct aic26 *aic26;
- int ret, err;
-
- dev_info(&pdev->dev, "Probing AIC26 SoC CODEC driver\n");
- dev_dbg(&pdev->dev, "socdev=%p\n", socdev);
- dev_dbg(&pdev->dev, "codec_data=%p\n", socdev->codec_data);
-
- /* Fetch the relevant aic26 private data here (it's already been
- * stored in the .codec pointer) */
- aic26 = socdev->codec_data;
- if (aic26 == NULL) {
- dev_err(&pdev->dev, "aic26: missing codec pointer\n");
- return -ENODEV;
- }
- codec = &aic26->codec;
- socdev->card->codec = codec;
-
- dev_dbg(&pdev->dev, "Registering PCMs, dev=%p, socdev->dev=%p\n",
- &pdev->dev, socdev->dev);
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(&pdev->dev, "aic26: failed to create pcms\n");
- return -ENODEV;
- }
-
- /* register controls */
- dev_dbg(&pdev->dev, "Registering controls\n");
- err = snd_soc_add_controls(codec, aic26_snd_controls,
- ARRAY_SIZE(aic26_snd_controls));
- WARN_ON(err < 0);
-
- return 0;
-}
-
-static int aic26_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- snd_soc_free_pcms(socdev);
- return 0;
-}
-
-struct snd_soc_codec_device aic26_soc_codec_dev = {
- .probe = aic26_probe,
- .remove = aic26_remove,
-};
-EXPORT_SYMBOL_GPL(aic26_soc_codec_dev);
-
-/* ---------------------------------------------------------------------
* SPI device portion of driver: sysfs files for debugging
*/
@@ -409,13 +351,62 @@
static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set);
/* ---------------------------------------------------------------------
+ * SoC CODEC portion of driver: probe and release routines
+ */
+static int aic26_probe(struct snd_soc_codec *codec)
+{
+ struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
+ int ret, err, i, reg;
+
+ dev_info(codec->dev, "Probing AIC26 SoC CODEC driver\n");
+
+ /* Reset the codec to power on defaults */
+ aic26_reg_write(codec, AIC26_REG_RESET, 0xBB00);
+
+ /* Power up CODEC */
+ aic26_reg_write(codec, AIC26_REG_POWER_CTRL, 0);
+
+ /* Audio Control 3 (master mode, fsref rate) */
+ reg = aic26_reg_read(codec, AIC26_REG_AUDIO_CTRL3);
+ reg &= ~0xf800;
+ reg |= 0x0800; /* set master mode */
+ aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL3, reg);
+
+ /* Fill register cache */
+ for (i = 0; i < ARRAY_SIZE(aic26->reg_cache); i++)
+ aic26_reg_read(codec, i);
+
+ /* Register the sysfs files for debugging */
+ /* Create SysFS files */
+ ret = device_create_file(codec->dev, &dev_attr_keyclick);
+ if (ret)
+ dev_info(codec->dev, "error creating sysfs files\n");
+
+ /* register controls */
+ dev_dbg(codec->dev, "Registering controls\n");
+ err = snd_soc_add_controls(codec, aic26_snd_controls,
+ ARRAY_SIZE(aic26_snd_controls));
+ WARN_ON(err < 0);
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver aic26_soc_codec_dev = {
+ .probe = aic26_probe,
+ .read = aic26_reg_read,
+ .write = aic26_reg_write,
+ .reg_cache_size = AIC26_NUM_REGS,
+ .reg_word_size = sizeof(u16),
+};
+
+/* ---------------------------------------------------------------------
* SPI device portion of driver: probe and release routines and SPI
* driver registration.
*/
static int aic26_spi_probe(struct spi_device *spi)
{
struct aic26 *aic26;
- int ret, i, reg;
+ int ret;
dev_dbg(&spi->dev, "probing tlv320aic26 spi device\n");
@@ -427,59 +418,13 @@
/* Initialize the driver data */
aic26->spi = spi;
dev_set_drvdata(&spi->dev, aic26);
-
- /* Setup what we can in the codec structure so that the register
- * access functions will work as expected. More will be filled
- * out when it is probed by the SoC CODEC part of this driver */
- snd_soc_codec_set_drvdata(&aic26->codec, aic26);
- aic26->codec.name = "aic26";
- aic26->codec.owner = THIS_MODULE;
- aic26->codec.dai = &aic26_dai;
- aic26->codec.num_dai = 1;
- aic26->codec.read = aic26_reg_read;
- aic26->codec.write = aic26_reg_write;
aic26->master = 1;
- mutex_init(&aic26->codec.mutex);
- INIT_LIST_HEAD(&aic26->codec.dapm_widgets);
- INIT_LIST_HEAD(&aic26->codec.dapm_paths);
- aic26->codec.reg_cache_size = AIC26_NUM_REGS;
- aic26->codec.reg_cache = aic26->reg_cache;
- aic26_dai.dev = &spi->dev;
- ret = snd_soc_register_dai(&aic26_dai);
- if (ret != 0) {
- dev_err(&spi->dev, "Failed to register DAI: %d\n", ret);
+ ret = snd_soc_register_codec(&spi->dev,
+ &aic26_soc_codec_dev, &aic26_dai, 1);
+ if (ret < 0)
kfree(aic26);
- return ret;
- }
-
- /* Reset the codec to power on defaults */
- aic26_reg_write(&aic26->codec, AIC26_REG_RESET, 0xBB00);
-
- /* Power up CODEC */
- aic26_reg_write(&aic26->codec, AIC26_REG_POWER_CTRL, 0);
-
- /* Audio Control 3 (master mode, fsref rate) */
- reg = aic26_reg_read(&aic26->codec, AIC26_REG_AUDIO_CTRL3);
- reg &= ~0xf800;
- reg |= 0x0800; /* set master mode */
- aic26_reg_write(&aic26->codec, AIC26_REG_AUDIO_CTRL3, reg);
-
- /* Fill register cache */
- for (i = 0; i < ARRAY_SIZE(aic26->reg_cache); i++)
- aic26_reg_read(&aic26->codec, i);
-
- /* Register the sysfs files for debugging */
- /* Create SysFS files */
- ret = device_create_file(&spi->dev, &dev_attr_keyclick);
- if (ret)
- dev_info(&spi->dev, "error creating sysfs files\n");
-
-#if defined(CONFIG_SND_SOC_OF_SIMPLE)
- /* Tell the of_soc helper about this codec */
- of_snd_soc_register_codec(&aic26_soc_codec_dev, aic26, &aic26_dai,
- spi->dev.archdata.of_node);
-#endif
+ return ret;
dev_dbg(&spi->dev, "SPI device initialized\n");
return 0;
@@ -487,17 +432,14 @@
static int aic26_spi_remove(struct spi_device *spi)
{
- struct aic26 *aic26 = dev_get_drvdata(&spi->dev);
-
- snd_soc_unregister_dai(&aic26_dai);
- kfree(aic26);
-
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
return 0;
}
static struct spi_driver aic26_spi = {
.driver = {
- .name = "tlv320aic26",
+ .name = "tlv320aic26-codec",
.owner = THIS_MODULE,
},
.probe = aic26_spi_probe,
diff --git a/sound/soc/codecs/tlv320aic26.h b/sound/soc/codecs/tlv320aic26.h
index 786ba16..62b1f22 100644
--- a/sound/soc/codecs/tlv320aic26.h
+++ b/sound/soc/codecs/tlv320aic26.h
@@ -90,7 +90,4 @@
AIC26_WLEN_32 = 3 << 10,
};
-extern struct snd_soc_dai aic26_dai;
-extern struct snd_soc_codec_device aic26_soc_codec_dev;
-
#endif /* _TLV320AIC16_H_ */
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 71a6990..fc68779 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -12,11 +12,11 @@
*
* Notes:
* The AIC3X is a driver for a low power stereo audio
- * codecs aic31, aic32, aic33.
+ * codecs aic31, aic32, aic33, aic3007.
*
* It supports full aic33 codec functionality.
- * The compatibility with aic32, aic31 is as follows:
- * aic32 | aic31
+ * The compatibility with aic32, aic31 and aic3007 is as follows:
+ * aic32/aic3007 | aic31
* ---------------------------------------
* MONO_LOUT -> N/A | MONO_LOUT -> N/A
* | IN1L -> LINE1L
@@ -61,13 +61,29 @@
"DRVDD", /* ADC Analog and Output Driver Voltage */
};
+struct aic3x_priv;
+
+struct aic3x_disable_nb {
+ struct notifier_block nb;
+ struct aic3x_priv *aic3x;
+};
+
/* codec private data */
struct aic3x_priv {
- struct snd_soc_codec codec;
+ struct snd_soc_codec *codec;
struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES];
+ struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES];
+ enum snd_soc_control_type control_type;
+ struct aic3x_setup_data *setup;
+ void *control_data;
unsigned int sysclk;
int master;
int gpio_reset;
+ int power;
+#define AIC3X_MODEL_3X 0
+#define AIC3X_MODEL_33 1
+#define AIC3X_MODEL_3007 2
+ u16 model;
};
/*
@@ -106,62 +122,23 @@
};
/*
- * read aic3x register cache
- */
-static inline unsigned int aic3x_read_reg_cache(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- u8 *cache = codec->reg_cache;
- if (reg >= AIC3X_CACHEREGNUM)
- return -1;
- return cache[reg];
-}
-
-/*
- * write aic3x register cache
- */
-static inline void aic3x_write_reg_cache(struct snd_soc_codec *codec,
- u8 reg, u8 value)
-{
- u8 *cache = codec->reg_cache;
- if (reg >= AIC3X_CACHEREGNUM)
- return;
- cache[reg] = value;
-}
-
-/*
- * write to the aic3x register space
- */
-static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int value)
-{
- u8 data[2];
-
- /* data is
- * D15..D8 aic3x register offset
- * D7...D0 register data
- */
- data[0] = reg & 0xff;
- data[1] = value & 0xff;
-
- aic3x_write_reg_cache(codec, data[0], data[1]);
- if (codec->hw_write(codec->control_data, data, 2) == 2)
- return 0;
- else
- return -EIO;
-}
-
-/*
- * read from the aic3x register space
+ * read from the aic3x register space. Only use for this function is if
+ * wanting to read volatile bits from those registers that has both read-only
+ * and read/write bits. All other cases should use snd_soc_read.
*/
static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg,
u8 *value)
{
- *value = reg & 0xff;
+ u8 *cache = codec->reg_cache;
- value[0] = i2c_smbus_read_byte_data(codec->control_data, value[0]);
+ if (codec->cache_only)
+ return -EINVAL;
+ if (reg >= AIC3X_CACHEREGNUM)
+ return -1;
- aic3x_write_reg_cache(codec, reg, *value);
+ *value = codec->hw_read(codec, reg);
+ cache[reg] = *value;
+
return 0;
}
@@ -286,64 +263,102 @@
SOC_DOUBLE_R_TLV("PCM Playback Volume",
LDAC_VOL, RDAC_VOL, 0, 0x7f, 1, dac_tlv),
+ /*
+ * Output controls that map to output mixer switches. Note these are
+ * only for swapped L-to-R and R-to-L routes. See below stereo controls
+ * for direct L-to-L and R-to-R routes.
+ */
+ SOC_SINGLE_TLV("Left Line Mixer Line2R Bypass Volume",
+ LINE2R_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("Left Line Mixer PGAR Bypass Volume",
+ PGAR_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("Left Line Mixer DACR1 Playback Volume",
+ DACR1_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
+
+ SOC_SINGLE_TLV("Right Line Mixer Line2L Bypass Volume",
+ LINE2L_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("Right Line Mixer PGAL Bypass Volume",
+ PGAL_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("Right Line Mixer DACL1 Playback Volume",
+ DACL1_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
+
+ SOC_SINGLE_TLV("Left HP Mixer Line2R Bypass Volume",
+ LINE2R_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("Left HP Mixer PGAR Bypass Volume",
+ PGAR_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("Left HP Mixer DACR1 Playback Volume",
+ DACR1_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
+
+ SOC_SINGLE_TLV("Right HP Mixer Line2L Bypass Volume",
+ LINE2L_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("Right HP Mixer PGAL Bypass Volume",
+ PGAL_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("Right HP Mixer DACL1 Playback Volume",
+ DACL1_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
+
+ SOC_SINGLE_TLV("Left HPCOM Mixer Line2R Bypass Volume",
+ LINE2R_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("Left HPCOM Mixer PGAR Bypass Volume",
+ PGAR_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("Left HPCOM Mixer DACR1 Playback Volume",
+ DACR1_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
+
+ SOC_SINGLE_TLV("Right HPCOM Mixer Line2L Bypass Volume",
+ LINE2L_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("Right HPCOM Mixer PGAL Bypass Volume",
+ PGAL_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("Right HPCOM Mixer DACL1 Playback Volume",
+ DACL1_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
+
+ /* Stereo output controls for direct L-to-L and R-to-R routes */
+ SOC_DOUBLE_R_TLV("Line Line2 Bypass Volume",
+ LINE2L_2_LLOPM_VOL, LINE2R_2_RLOPM_VOL,
+ 0, 118, 1, output_stage_tlv),
+ SOC_DOUBLE_R_TLV("Line PGA Bypass Volume",
+ PGAL_2_LLOPM_VOL, PGAR_2_RLOPM_VOL,
+ 0, 118, 1, output_stage_tlv),
SOC_DOUBLE_R_TLV("Line DAC Playback Volume",
DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL,
0, 118, 1, output_stage_tlv),
- SOC_SINGLE("LineL Playback Switch", LLOPM_CTRL, 3, 0x01, 0),
- SOC_SINGLE("LineR Playback Switch", RLOPM_CTRL, 3, 0x01, 0),
- SOC_DOUBLE_R_TLV("LineL DAC Playback Volume",
- DACL1_2_LLOPM_VOL, DACR1_2_LLOPM_VOL,
- 0, 118, 1, output_stage_tlv),
- SOC_SINGLE_TLV("LineL Left PGA Bypass Playback Volume",
- PGAL_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
- SOC_SINGLE_TLV("LineR Right PGA Bypass Playback Volume",
- PGAR_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
- SOC_DOUBLE_R_TLV("LineL Line2 Bypass Playback Volume",
- LINE2L_2_LLOPM_VOL, LINE2R_2_LLOPM_VOL,
- 0, 118, 1, output_stage_tlv),
- SOC_DOUBLE_R_TLV("LineR Line2 Bypass Playback Volume",
- LINE2L_2_RLOPM_VOL, LINE2R_2_RLOPM_VOL,
- 0, 118, 1, output_stage_tlv),
+ SOC_DOUBLE_R_TLV("Mono Line2 Bypass Volume",
+ LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL,
+ 0, 118, 1, output_stage_tlv),
+ SOC_DOUBLE_R_TLV("Mono PGA Bypass Volume",
+ PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL,
+ 0, 118, 1, output_stage_tlv),
SOC_DOUBLE_R_TLV("Mono DAC Playback Volume",
DACL1_2_MONOLOPM_VOL, DACR1_2_MONOLOPM_VOL,
0, 118, 1, output_stage_tlv),
- SOC_SINGLE("Mono DAC Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),
- SOC_DOUBLE_R_TLV("Mono PGA Bypass Playback Volume",
- PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL,
- 0, 118, 1, output_stage_tlv),
- SOC_DOUBLE_R_TLV("Mono Line2 Bypass Playback Volume",
- LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL,
- 0, 118, 1, output_stage_tlv),
+ SOC_DOUBLE_R_TLV("HP Line2 Bypass Volume",
+ LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL,
+ 0, 118, 1, output_stage_tlv),
+ SOC_DOUBLE_R_TLV("HP PGA Bypass Volume",
+ PGAL_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL,
+ 0, 118, 1, output_stage_tlv),
SOC_DOUBLE_R_TLV("HP DAC Playback Volume",
DACL1_2_HPLOUT_VOL, DACR1_2_HPROUT_VOL,
0, 118, 1, output_stage_tlv),
- SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3,
- 0x01, 0),
- SOC_DOUBLE_R_TLV("HP Right PGA Bypass Playback Volume",
- PGAR_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL,
- 0, 118, 1, output_stage_tlv),
- SOC_SINGLE_TLV("HPL PGA Bypass Playback Volume",
- PGAL_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
- SOC_SINGLE_TLV("HPR PGA Bypass Playback Volume",
- PGAL_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
- SOC_DOUBLE_R_TLV("HP Line2 Bypass Playback Volume",
- LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL,
- 0, 118, 1, output_stage_tlv),
+ SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Volume",
+ LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL,
+ 0, 118, 1, output_stage_tlv),
+ SOC_DOUBLE_R_TLV("HPCOM PGA Bypass Volume",
+ PGAL_2_HPLCOM_VOL, PGAR_2_HPRCOM_VOL,
+ 0, 118, 1, output_stage_tlv),
SOC_DOUBLE_R_TLV("HPCOM DAC Playback Volume",
DACL1_2_HPLCOM_VOL, DACR1_2_HPRCOM_VOL,
0, 118, 1, output_stage_tlv),
- SOC_DOUBLE_R("HPCOM DAC Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3,
+
+ /* Output pin mute controls */
+ SOC_DOUBLE_R("Line Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3,
0x01, 0),
- SOC_SINGLE_TLV("HPLCOM PGA Bypass Playback Volume",
- PGAL_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
- SOC_SINGLE_TLV("HPRCOM PGA Bypass Playback Volume",
- PGAL_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
- SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Playback Volume",
- LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL,
- 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE("Mono Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),
+ SOC_DOUBLE_R("HP Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3,
+ 0x01, 0),
+ SOC_DOUBLE_R("HPCOM Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3,
+ 0x01, 0),
/*
* Note: enable Automatic input Gain Controller with care. It can
@@ -359,6 +374,14 @@
SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]),
};
+/*
+ * Class-D amplifier gain. From 0 to 18 dB in 6 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(classd_amp_tlv, 0, 600, 0);
+
+static const struct snd_kcontrol_new aic3x_classd_amp_gain_ctrl =
+ SOC_DOUBLE_TLV("Class-D Amplifier Gain", CLASSD_CTRL, 6, 4, 3, 0, classd_amp_tlv);
+
/* Left DAC Mux */
static const struct snd_kcontrol_new aic3x_left_dac_mux_controls =
SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]);
@@ -375,22 +398,74 @@
static const struct snd_kcontrol_new aic3x_right_hpcom_mux_controls =
SOC_DAPM_ENUM("Route", aic3x_enum[RHPCOM_ENUM]);
-/* Left DAC_L1 Mixer */
-static const struct snd_kcontrol_new aic3x_left_dac_mixer_controls[] = {
- SOC_DAPM_SINGLE("LineL Switch", DACL1_2_LLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("LineR Switch", DACL1_2_RLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("Mono Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HP Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HPCOM Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0),
+/* Left Line Mixer */
+static const struct snd_kcontrol_new aic3x_left_line_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_LLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_LLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_LLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_LLOPM_VOL, 7, 1, 0),
};
-/* Right DAC_R1 Mixer */
-static const struct snd_kcontrol_new aic3x_right_dac_mixer_controls[] = {
- SOC_DAPM_SINGLE("LineL Switch", DACR1_2_LLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("LineR Switch", DACR1_2_RLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("Mono Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HP Switch", DACR1_2_HPROUT_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HPCOM Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0),
+/* Right Line Mixer */
+static const struct snd_kcontrol_new aic3x_right_line_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_RLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_RLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_RLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_RLOPM_VOL, 7, 1, 0),
+};
+
+/* Mono Mixer */
+static const struct snd_kcontrol_new aic3x_mono_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0),
+};
+
+/* Left HP Mixer */
+static const struct snd_kcontrol_new aic3x_left_hp_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLOUT_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPLOUT_VOL, 7, 1, 0),
+};
+
+/* Right HP Mixer */
+static const struct snd_kcontrol_new aic3x_right_hp_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPROUT_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPROUT_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPROUT_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPROUT_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPROUT_VOL, 7, 1, 0),
+};
+
+/* Left HPCOM Mixer */
+static const struct snd_kcontrol_new aic3x_left_hpcom_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLCOM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPLCOM_VOL, 7, 1, 0),
+};
+
+/* Right HPCOM Mixer */
+static const struct snd_kcontrol_new aic3x_right_hpcom_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPRCOM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPRCOM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0),
};
/* Left PGA Mixer */
@@ -427,54 +502,11 @@
static const struct snd_kcontrol_new aic3x_right_line2_mux_controls =
SOC_DAPM_ENUM("Route", aic3x_enum[LINE2R_ENUM]);
-/* Left PGA Bypass Mixer */
-static const struct snd_kcontrol_new aic3x_left_pga_bp_mixer_controls[] = {
- SOC_DAPM_SINGLE("LineL Switch", PGAL_2_LLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("LineR Switch", PGAL_2_RLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("Mono Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HPL Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HPR Switch", PGAL_2_HPROUT_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HPLCOM Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HPRCOM Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0),
-};
-
-/* Right PGA Bypass Mixer */
-static const struct snd_kcontrol_new aic3x_right_pga_bp_mixer_controls[] = {
- SOC_DAPM_SINGLE("LineL Switch", PGAR_2_LLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("LineR Switch", PGAR_2_RLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("Mono Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HPL Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HPR Switch", PGAR_2_HPROUT_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HPLCOM Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HPRCOM Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0),
-};
-
-/* Left Line2 Bypass Mixer */
-static const struct snd_kcontrol_new aic3x_left_line2_bp_mixer_controls[] = {
- SOC_DAPM_SINGLE("LineL Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("LineR Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("Mono Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HP Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HPLCOM Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0),
-};
-
-/* Right Line2 Bypass Mixer */
-static const struct snd_kcontrol_new aic3x_right_line2_bp_mixer_controls[] = {
- SOC_DAPM_SINGLE("LineL Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("LineR Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("Mono Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HP Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HPRCOM Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0),
-};
-
static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
/* Left DAC to Left Outputs */
SND_SOC_DAPM_DAC("Left DAC", "Left Playback", DAC_PWR, 7, 0),
SND_SOC_DAPM_MUX("Left DAC Mux", SND_SOC_NOPM, 0, 0,
&aic3x_left_dac_mux_controls),
- SND_SOC_DAPM_MIXER("Left DAC_L1 Mixer", SND_SOC_NOPM, 0, 0,
- &aic3x_left_dac_mixer_controls[0],
- ARRAY_SIZE(aic3x_left_dac_mixer_controls)),
SND_SOC_DAPM_MUX("Left HPCOM Mux", SND_SOC_NOPM, 0, 0,
&aic3x_left_hpcom_mux_controls),
SND_SOC_DAPM_PGA("Left Line Out", LLOPM_CTRL, 0, 0, NULL, 0),
@@ -485,9 +517,6 @@
SND_SOC_DAPM_DAC("Right DAC", "Right Playback", DAC_PWR, 6, 0),
SND_SOC_DAPM_MUX("Right DAC Mux", SND_SOC_NOPM, 0, 0,
&aic3x_right_dac_mux_controls),
- SND_SOC_DAPM_MIXER("Right DAC_R1 Mixer", SND_SOC_NOPM, 0, 0,
- &aic3x_right_dac_mixer_controls[0],
- ARRAY_SIZE(aic3x_right_dac_mixer_controls)),
SND_SOC_DAPM_MUX("Right HPCOM Mux", SND_SOC_NOPM, 0, 0,
&aic3x_right_hpcom_mux_controls),
SND_SOC_DAPM_PGA("Right Line Out", RLOPM_CTRL, 0, 0, NULL, 0),
@@ -551,25 +580,28 @@
SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias AVDD",
MICBIAS_CTRL, 6, 3, 3, 0),
- /* Left PGA to Left Output bypass */
- SND_SOC_DAPM_MIXER("Left PGA Bypass Mixer", SND_SOC_NOPM, 0, 0,
- &aic3x_left_pga_bp_mixer_controls[0],
- ARRAY_SIZE(aic3x_left_pga_bp_mixer_controls)),
-
- /* Right PGA to Right Output bypass */
- SND_SOC_DAPM_MIXER("Right PGA Bypass Mixer", SND_SOC_NOPM, 0, 0,
- &aic3x_right_pga_bp_mixer_controls[0],
- ARRAY_SIZE(aic3x_right_pga_bp_mixer_controls)),
-
- /* Left Line2 to Left Output bypass */
- SND_SOC_DAPM_MIXER("Left Line2 Bypass Mixer", SND_SOC_NOPM, 0, 0,
- &aic3x_left_line2_bp_mixer_controls[0],
- ARRAY_SIZE(aic3x_left_line2_bp_mixer_controls)),
-
- /* Right Line2 to Right Output bypass */
- SND_SOC_DAPM_MIXER("Right Line2 Bypass Mixer", SND_SOC_NOPM, 0, 0,
- &aic3x_right_line2_bp_mixer_controls[0],
- ARRAY_SIZE(aic3x_right_line2_bp_mixer_controls)),
+ /* Output mixers */
+ SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0,
+ &aic3x_left_line_mixer_controls[0],
+ ARRAY_SIZE(aic3x_left_line_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Right Line Mixer", SND_SOC_NOPM, 0, 0,
+ &aic3x_right_line_mixer_controls[0],
+ ARRAY_SIZE(aic3x_right_line_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0,
+ &aic3x_mono_mixer_controls[0],
+ ARRAY_SIZE(aic3x_mono_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0,
+ &aic3x_left_hp_mixer_controls[0],
+ ARRAY_SIZE(aic3x_left_hp_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Right HP Mixer", SND_SOC_NOPM, 0, 0,
+ &aic3x_right_hp_mixer_controls[0],
+ ARRAY_SIZE(aic3x_right_hp_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Left HPCOM Mixer", SND_SOC_NOPM, 0, 0,
+ &aic3x_left_hpcom_mixer_controls[0],
+ ARRAY_SIZE(aic3x_left_hpcom_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Right HPCOM Mixer", SND_SOC_NOPM, 0, 0,
+ &aic3x_right_hpcom_mixer_controls[0],
+ ARRAY_SIZE(aic3x_right_hpcom_mixer_controls)),
SND_SOC_DAPM_OUTPUT("LLOUT"),
SND_SOC_DAPM_OUTPUT("RLOUT"),
@@ -585,69 +617,26 @@
SND_SOC_DAPM_INPUT("LINE1R"),
SND_SOC_DAPM_INPUT("LINE2L"),
SND_SOC_DAPM_INPUT("LINE2R"),
+
+ /*
+ * Virtual output pin to detection block inside codec. This can be
+ * used to keep codec bias on if gpio or detection features are needed.
+ * Force pin on or construct a path with an input jack and mic bias
+ * widgets.
+ */
+ SND_SOC_DAPM_OUTPUT("Detection"),
+};
+
+static const struct snd_soc_dapm_widget aic3007_dapm_widgets[] = {
+ /* Class-D outputs */
+ SND_SOC_DAPM_PGA("Left Class-D Out", CLASSD_CTRL, 3, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Right Class-D Out", CLASSD_CTRL, 2, 0, NULL, 0),
+
+ SND_SOC_DAPM_OUTPUT("SPOP"),
+ SND_SOC_DAPM_OUTPUT("SPOM"),
};
static const struct snd_soc_dapm_route intercon[] = {
- /* Left Output */
- {"Left DAC Mux", "DAC_L1", "Left DAC"},
- {"Left DAC Mux", "DAC_L2", "Left DAC"},
- {"Left DAC Mux", "DAC_L3", "Left DAC"},
-
- {"Left DAC_L1 Mixer", "LineL Switch", "Left DAC Mux"},
- {"Left DAC_L1 Mixer", "LineR Switch", "Left DAC Mux"},
- {"Left DAC_L1 Mixer", "Mono Switch", "Left DAC Mux"},
- {"Left DAC_L1 Mixer", "HP Switch", "Left DAC Mux"},
- {"Left DAC_L1 Mixer", "HPCOM Switch", "Left DAC Mux"},
- {"Left Line Out", NULL, "Left DAC Mux"},
- {"Left HP Out", NULL, "Left DAC Mux"},
-
- {"Left HPCOM Mux", "differential of HPLOUT", "Left DAC_L1 Mixer"},
- {"Left HPCOM Mux", "constant VCM", "Left DAC_L1 Mixer"},
- {"Left HPCOM Mux", "single-ended", "Left DAC_L1 Mixer"},
-
- {"Left Line Out", NULL, "Left DAC_L1 Mixer"},
- {"Mono Out", NULL, "Left DAC_L1 Mixer"},
- {"Left HP Out", NULL, "Left DAC_L1 Mixer"},
- {"Left HP Com", NULL, "Left HPCOM Mux"},
-
- {"LLOUT", NULL, "Left Line Out"},
- {"LLOUT", NULL, "Left Line Out"},
- {"HPLOUT", NULL, "Left HP Out"},
- {"HPLCOM", NULL, "Left HP Com"},
-
- /* Right Output */
- {"Right DAC Mux", "DAC_R1", "Right DAC"},
- {"Right DAC Mux", "DAC_R2", "Right DAC"},
- {"Right DAC Mux", "DAC_R3", "Right DAC"},
-
- {"Right DAC_R1 Mixer", "LineL Switch", "Right DAC Mux"},
- {"Right DAC_R1 Mixer", "LineR Switch", "Right DAC Mux"},
- {"Right DAC_R1 Mixer", "Mono Switch", "Right DAC Mux"},
- {"Right DAC_R1 Mixer", "HP Switch", "Right DAC Mux"},
- {"Right DAC_R1 Mixer", "HPCOM Switch", "Right DAC Mux"},
- {"Right Line Out", NULL, "Right DAC Mux"},
- {"Right HP Out", NULL, "Right DAC Mux"},
-
- {"Right HPCOM Mux", "differential of HPROUT", "Right DAC_R1 Mixer"},
- {"Right HPCOM Mux", "constant VCM", "Right DAC_R1 Mixer"},
- {"Right HPCOM Mux", "single-ended", "Right DAC_R1 Mixer"},
- {"Right HPCOM Mux", "differential of HPLCOM", "Right DAC_R1 Mixer"},
- {"Right HPCOM Mux", "external feedback", "Right DAC_R1 Mixer"},
-
- {"Right Line Out", NULL, "Right DAC_R1 Mixer"},
- {"Mono Out", NULL, "Right DAC_R1 Mixer"},
- {"Right HP Out", NULL, "Right DAC_R1 Mixer"},
- {"Right HP Com", NULL, "Right HPCOM Mux"},
-
- {"RLOUT", NULL, "Right Line Out"},
- {"RLOUT", NULL, "Right Line Out"},
- {"HPROUT", NULL, "Right HP Out"},
- {"HPRCOM", NULL, "Right HP Com"},
-
- /* Mono Output */
- {"MONO_LOUT", NULL, "Mono Out"},
- {"MONO_LOUT", NULL, "Mono Out"},
-
/* Left Input */
{"Left Line1L Mux", "single-ended", "LINE1L"},
{"Left Line1L Mux", "differential", "LINE1L"},
@@ -680,74 +669,6 @@
{"Right ADC", NULL, "Right PGA Mixer"},
{"Right ADC", NULL, "GPIO1 dmic modclk"},
- /* Left PGA Bypass */
- {"Left PGA Bypass Mixer", "LineL Switch", "Left PGA Mixer"},
- {"Left PGA Bypass Mixer", "LineR Switch", "Left PGA Mixer"},
- {"Left PGA Bypass Mixer", "Mono Switch", "Left PGA Mixer"},
- {"Left PGA Bypass Mixer", "HPL Switch", "Left PGA Mixer"},
- {"Left PGA Bypass Mixer", "HPR Switch", "Left PGA Mixer"},
- {"Left PGA Bypass Mixer", "HPLCOM Switch", "Left PGA Mixer"},
- {"Left PGA Bypass Mixer", "HPRCOM Switch", "Left PGA Mixer"},
-
- {"Left HPCOM Mux", "differential of HPLOUT", "Left PGA Bypass Mixer"},
- {"Left HPCOM Mux", "constant VCM", "Left PGA Bypass Mixer"},
- {"Left HPCOM Mux", "single-ended", "Left PGA Bypass Mixer"},
-
- {"Left Line Out", NULL, "Left PGA Bypass Mixer"},
- {"Mono Out", NULL, "Left PGA Bypass Mixer"},
- {"Left HP Out", NULL, "Left PGA Bypass Mixer"},
-
- /* Right PGA Bypass */
- {"Right PGA Bypass Mixer", "LineL Switch", "Right PGA Mixer"},
- {"Right PGA Bypass Mixer", "LineR Switch", "Right PGA Mixer"},
- {"Right PGA Bypass Mixer", "Mono Switch", "Right PGA Mixer"},
- {"Right PGA Bypass Mixer", "HPL Switch", "Right PGA Mixer"},
- {"Right PGA Bypass Mixer", "HPR Switch", "Right PGA Mixer"},
- {"Right PGA Bypass Mixer", "HPLCOM Switch", "Right PGA Mixer"},
- {"Right PGA Bypass Mixer", "HPRCOM Switch", "Right PGA Mixer"},
-
- {"Right HPCOM Mux", "differential of HPROUT", "Right PGA Bypass Mixer"},
- {"Right HPCOM Mux", "constant VCM", "Right PGA Bypass Mixer"},
- {"Right HPCOM Mux", "single-ended", "Right PGA Bypass Mixer"},
- {"Right HPCOM Mux", "differential of HPLCOM", "Right PGA Bypass Mixer"},
- {"Right HPCOM Mux", "external feedback", "Right PGA Bypass Mixer"},
-
- {"Right Line Out", NULL, "Right PGA Bypass Mixer"},
- {"Mono Out", NULL, "Right PGA Bypass Mixer"},
- {"Right HP Out", NULL, "Right PGA Bypass Mixer"},
-
- /* Left Line2 Bypass */
- {"Left Line2 Bypass Mixer", "LineL Switch", "Left Line2L Mux"},
- {"Left Line2 Bypass Mixer", "LineR Switch", "Left Line2L Mux"},
- {"Left Line2 Bypass Mixer", "Mono Switch", "Left Line2L Mux"},
- {"Left Line2 Bypass Mixer", "HP Switch", "Left Line2L Mux"},
- {"Left Line2 Bypass Mixer", "HPLCOM Switch", "Left Line2L Mux"},
-
- {"Left HPCOM Mux", "differential of HPLOUT", "Left Line2 Bypass Mixer"},
- {"Left HPCOM Mux", "constant VCM", "Left Line2 Bypass Mixer"},
- {"Left HPCOM Mux", "single-ended", "Left Line2 Bypass Mixer"},
-
- {"Left Line Out", NULL, "Left Line2 Bypass Mixer"},
- {"Mono Out", NULL, "Left Line2 Bypass Mixer"},
- {"Left HP Out", NULL, "Left Line2 Bypass Mixer"},
-
- /* Right Line2 Bypass */
- {"Right Line2 Bypass Mixer", "LineL Switch", "Right Line2R Mux"},
- {"Right Line2 Bypass Mixer", "LineR Switch", "Right Line2R Mux"},
- {"Right Line2 Bypass Mixer", "Mono Switch", "Right Line2R Mux"},
- {"Right Line2 Bypass Mixer", "HP Switch", "Right Line2R Mux"},
- {"Right Line2 Bypass Mixer", "HPRCOM Switch", "Right Line2R Mux"},
-
- {"Right HPCOM Mux", "differential of HPROUT", "Right Line2 Bypass Mixer"},
- {"Right HPCOM Mux", "constant VCM", "Right Line2 Bypass Mixer"},
- {"Right HPCOM Mux", "single-ended", "Right Line2 Bypass Mixer"},
- {"Right HPCOM Mux", "differential of HPLCOM", "Right Line2 Bypass Mixer"},
- {"Right HPCOM Mux", "external feedback", "Right Line2 Bypass Mixer"},
-
- {"Right Line Out", NULL, "Right Line2 Bypass Mixer"},
- {"Mono Out", NULL, "Right Line2 Bypass Mixer"},
- {"Right HP Out", NULL, "Right Line2 Bypass Mixer"},
-
/*
* Logical path between digital mic enable and GPIO1 modulator clock
* output function
@@ -755,16 +676,131 @@
{"GPIO1 dmic modclk", NULL, "DMic Rate 128"},
{"GPIO1 dmic modclk", NULL, "DMic Rate 64"},
{"GPIO1 dmic modclk", NULL, "DMic Rate 32"},
+
+ /* Left DAC Output */
+ {"Left DAC Mux", "DAC_L1", "Left DAC"},
+ {"Left DAC Mux", "DAC_L2", "Left DAC"},
+ {"Left DAC Mux", "DAC_L3", "Left DAC"},
+
+ /* Right DAC Output */
+ {"Right DAC Mux", "DAC_R1", "Right DAC"},
+ {"Right DAC Mux", "DAC_R2", "Right DAC"},
+ {"Right DAC Mux", "DAC_R3", "Right DAC"},
+
+ /* Left Line Output */
+ {"Left Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+ {"Left Line Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+ {"Left Line Mixer", "DACL1 Switch", "Left DAC Mux"},
+ {"Left Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+ {"Left Line Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+ {"Left Line Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+ {"Left Line Out", NULL, "Left Line Mixer"},
+ {"Left Line Out", NULL, "Left DAC Mux"},
+ {"LLOUT", NULL, "Left Line Out"},
+
+ /* Right Line Output */
+ {"Right Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+ {"Right Line Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+ {"Right Line Mixer", "DACL1 Switch", "Left DAC Mux"},
+ {"Right Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+ {"Right Line Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+ {"Right Line Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+ {"Right Line Out", NULL, "Right Line Mixer"},
+ {"Right Line Out", NULL, "Right DAC Mux"},
+ {"RLOUT", NULL, "Right Line Out"},
+
+ /* Mono Output */
+ {"Mono Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+ {"Mono Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+ {"Mono Mixer", "DACL1 Switch", "Left DAC Mux"},
+ {"Mono Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+ {"Mono Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+ {"Mono Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+ {"Mono Out", NULL, "Mono Mixer"},
+ {"MONO_LOUT", NULL, "Mono Out"},
+
+ /* Left HP Output */
+ {"Left HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+ {"Left HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+ {"Left HP Mixer", "DACL1 Switch", "Left DAC Mux"},
+ {"Left HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+ {"Left HP Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+ {"Left HP Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+ {"Left HP Out", NULL, "Left HP Mixer"},
+ {"Left HP Out", NULL, "Left DAC Mux"},
+ {"HPLOUT", NULL, "Left HP Out"},
+
+ /* Right HP Output */
+ {"Right HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+ {"Right HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+ {"Right HP Mixer", "DACL1 Switch", "Left DAC Mux"},
+ {"Right HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+ {"Right HP Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+ {"Right HP Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+ {"Right HP Out", NULL, "Right HP Mixer"},
+ {"Right HP Out", NULL, "Right DAC Mux"},
+ {"HPROUT", NULL, "Right HP Out"},
+
+ /* Left HPCOM Output */
+ {"Left HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+ {"Left HPCOM Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+ {"Left HPCOM Mixer", "DACL1 Switch", "Left DAC Mux"},
+ {"Left HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+ {"Left HPCOM Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+ {"Left HPCOM Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+ {"Left HPCOM Mux", "differential of HPLOUT", "Left HP Mixer"},
+ {"Left HPCOM Mux", "constant VCM", "Left HPCOM Mixer"},
+ {"Left HPCOM Mux", "single-ended", "Left HPCOM Mixer"},
+ {"Left HP Com", NULL, "Left HPCOM Mux"},
+ {"HPLCOM", NULL, "Left HP Com"},
+
+ /* Right HPCOM Output */
+ {"Right HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+ {"Right HPCOM Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+ {"Right HPCOM Mixer", "DACL1 Switch", "Left DAC Mux"},
+ {"Right HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+ {"Right HPCOM Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+ {"Right HPCOM Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+ {"Right HPCOM Mux", "differential of HPROUT", "Right HP Mixer"},
+ {"Right HPCOM Mux", "constant VCM", "Right HPCOM Mixer"},
+ {"Right HPCOM Mux", "single-ended", "Right HPCOM Mixer"},
+ {"Right HPCOM Mux", "differential of HPLCOM", "Left HPCOM Mixer"},
+ {"Right HPCOM Mux", "external feedback", "Right HPCOM Mixer"},
+ {"Right HP Com", NULL, "Right HPCOM Mux"},
+ {"HPRCOM", NULL, "Right HP Com"},
+};
+
+static const struct snd_soc_dapm_route intercon_3007[] = {
+ /* Class-D outputs */
+ {"Left Class-D Out", NULL, "Left Line Out"},
+ {"Right Class-D Out", NULL, "Left Line Out"},
+ {"SPOP", NULL, "Left Class-D Out"},
+ {"SPOM", NULL, "Right Class-D Out"},
};
static int aic3x_add_widgets(struct snd_soc_codec *codec)
{
+ struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+
snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets,
ARRAY_SIZE(aic3x_dapm_widgets));
/* set up audio path interconnects */
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+ if (aic3x->model == AIC3X_MODEL_3007) {
+ snd_soc_dapm_new_controls(codec, aic3007_dapm_widgets,
+ ARRAY_SIZE(aic3007_dapm_widgets));
+ snd_soc_dapm_add_routes(codec, intercon_3007, ARRAY_SIZE(intercon_3007));
+ }
+
return 0;
}
@@ -773,8 +809,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec =rtd->codec;
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
@@ -783,8 +818,7 @@
int clk;
/* select data word length */
- data =
- aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4));
+ data = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4));
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
break;
@@ -798,7 +832,7 @@
data |= (0x03 << 4);
break;
}
- aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data);
+ snd_soc_write(codec, AIC3X_ASD_INTF_CTRLB, data);
/* Fsref can be 44100 or 48000 */
fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000;
@@ -813,17 +847,17 @@
if (bypass_pll) {
pll_q &= 0xf;
- aic3x_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT);
- aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV);
+ snd_soc_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT);
+ snd_soc_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV);
/* disable PLL if it is bypassed */
- reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
- aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg & ~PLL_ENABLE);
+ reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
+ snd_soc_write(codec, AIC3X_PLL_PROGA_REG, reg & ~PLL_ENABLE);
} else {
- aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV);
+ snd_soc_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV);
/* enable PLL when it is used */
- reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
- aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg | PLL_ENABLE);
+ reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
+ snd_soc_write(codec, AIC3X_PLL_PROGA_REG, reg | PLL_ENABLE);
}
/* Route Left DAC to left channel input and
@@ -832,7 +866,7 @@
data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000;
if (params_rate(params) >= 64000)
data |= DUAL_RATE_MODE;
- aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data);
+ snd_soc_write(codec, AIC3X_CODEC_DATAPATH_REG, data);
/* codec sample rate select */
data = (fsref * 20) / params_rate(params);
@@ -841,7 +875,7 @@
data /= 5;
data -= 2;
data |= (data << 4);
- aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data);
+ snd_soc_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data);
if (bypass_pll)
return 0;
@@ -910,13 +944,16 @@
}
found:
- data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
- aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT));
- aic3x_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, pll_r << PLLR_SHIFT);
- aic3x_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT);
- aic3x_write(codec, AIC3X_PLL_PROGC_REG, (pll_d >> 6) << PLLD_MSB_SHIFT);
- aic3x_write(codec, AIC3X_PLL_PROGD_REG,
- (pll_d & 0x3F) << PLLD_LSB_SHIFT);
+ data = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
+ snd_soc_write(codec, AIC3X_PLL_PROGA_REG,
+ data | (pll_p << PLLP_SHIFT));
+ snd_soc_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG,
+ pll_r << PLLR_SHIFT);
+ snd_soc_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT);
+ snd_soc_write(codec, AIC3X_PLL_PROGC_REG,
+ (pll_d >> 6) << PLLD_MSB_SHIFT);
+ snd_soc_write(codec, AIC3X_PLL_PROGD_REG,
+ (pll_d & 0x3F) << PLLD_LSB_SHIFT);
return 0;
}
@@ -924,15 +961,15 @@
static int aic3x_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
- u8 ldac_reg = aic3x_read_reg_cache(codec, LDAC_VOL) & ~MUTE_ON;
- u8 rdac_reg = aic3x_read_reg_cache(codec, RDAC_VOL) & ~MUTE_ON;
+ u8 ldac_reg = snd_soc_read(codec, LDAC_VOL) & ~MUTE_ON;
+ u8 rdac_reg = snd_soc_read(codec, RDAC_VOL) & ~MUTE_ON;
if (mute) {
- aic3x_write(codec, LDAC_VOL, ldac_reg | MUTE_ON);
- aic3x_write(codec, RDAC_VOL, rdac_reg | MUTE_ON);
+ snd_soc_write(codec, LDAC_VOL, ldac_reg | MUTE_ON);
+ snd_soc_write(codec, RDAC_VOL, rdac_reg | MUTE_ON);
} else {
- aic3x_write(codec, LDAC_VOL, ldac_reg);
- aic3x_write(codec, RDAC_VOL, rdac_reg);
+ snd_soc_write(codec, LDAC_VOL, ldac_reg);
+ snd_soc_write(codec, RDAC_VOL, rdac_reg);
}
return 0;
@@ -956,8 +993,8 @@
u8 iface_areg, iface_breg;
int delay = 0;
- iface_areg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f;
- iface_breg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f;
+ iface_areg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f;
+ iface_breg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f;
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -996,13 +1033,98 @@
}
/* set iface */
- aic3x_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg);
- aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg);
- aic3x_write(codec, AIC3X_ASD_INTF_CTRLC, delay);
+ snd_soc_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg);
+ snd_soc_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg);
+ snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, delay);
return 0;
}
+static int aic3x_init_3007(struct snd_soc_codec *codec)
+{
+ u8 tmp1, tmp2, *cache = codec->reg_cache;
+
+ /*
+ * There is no need to cache writes to undocumented page 0xD but
+ * respective page 0 register cache entries must be preserved
+ */
+ tmp1 = cache[0xD];
+ tmp2 = cache[0x8];
+ /* Class-D speaker driver init; datasheet p. 46 */
+ snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x0D);
+ snd_soc_write(codec, 0xD, 0x0D);
+ snd_soc_write(codec, 0x8, 0x5C);
+ snd_soc_write(codec, 0x8, 0x5D);
+ snd_soc_write(codec, 0x8, 0x5C);
+ snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x00);
+ cache[0xD] = tmp1;
+ cache[0x8] = tmp2;
+
+ return 0;
+}
+
+static int aic3x_regulator_event(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct aic3x_disable_nb *disable_nb =
+ container_of(nb, struct aic3x_disable_nb, nb);
+ struct aic3x_priv *aic3x = disable_nb->aic3x;
+
+ if (event & REGULATOR_EVENT_DISABLE) {
+ /*
+ * Put codec to reset and require cache sync as at least one
+ * of the supplies was disabled
+ */
+ if (aic3x->gpio_reset >= 0)
+ gpio_set_value(aic3x->gpio_reset, 0);
+ aic3x->codec->cache_sync = 1;
+ }
+
+ return 0;
+}
+
+static int aic3x_set_power(struct snd_soc_codec *codec, int power)
+{
+ struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+ int i, ret;
+ u8 *cache = codec->reg_cache;
+
+ if (power) {
+ ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies),
+ aic3x->supplies);
+ if (ret)
+ goto out;
+ aic3x->power = 1;
+ /*
+ * Reset release and cache sync is necessary only if some
+ * supply was off or if there were cached writes
+ */
+ if (!codec->cache_sync)
+ goto out;
+
+ if (aic3x->gpio_reset >= 0) {
+ udelay(1);
+ gpio_set_value(aic3x->gpio_reset, 1);
+ }
+
+ /* Sync reg_cache with the hardware */
+ codec->cache_only = 0;
+ for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++)
+ snd_soc_write(codec, i, cache[i]);
+ if (aic3x->model == AIC3X_MODEL_3007)
+ aic3x_init_3007(codec);
+ codec->cache_sync = 0;
+ } else {
+ aic3x->power = 0;
+ /* HW writes are needless when bias is off */
+ codec->cache_only = 1;
+ ret = regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies),
+ aic3x->supplies);
+ }
+out:
+ return ret;
+}
+
static int aic3x_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
@@ -1013,23 +1135,29 @@
case SND_SOC_BIAS_ON:
break;
case SND_SOC_BIAS_PREPARE:
- if (aic3x->master) {
+ if (codec->bias_level == SND_SOC_BIAS_STANDBY &&
+ aic3x->master) {
/* enable pll */
- reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
- aic3x_write(codec, AIC3X_PLL_PROGA_REG,
- reg | PLL_ENABLE);
+ reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
+ snd_soc_write(codec, AIC3X_PLL_PROGA_REG,
+ reg | PLL_ENABLE);
}
break;
case SND_SOC_BIAS_STANDBY:
- /* fall through and disable pll */
- case SND_SOC_BIAS_OFF:
- if (aic3x->master) {
+ if (!aic3x->power)
+ aic3x_set_power(codec, 1);
+ if (codec->bias_level == SND_SOC_BIAS_PREPARE &&
+ aic3x->master) {
/* disable pll */
- reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
- aic3x_write(codec, AIC3X_PLL_PROGA_REG,
- reg & ~PLL_ENABLE);
+ reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
+ snd_soc_write(codec, AIC3X_PLL_PROGA_REG,
+ reg & ~PLL_ENABLE);
}
break;
+ case SND_SOC_BIAS_OFF:
+ if (aic3x->power)
+ aic3x_set_power(codec, 0);
+ break;
}
codec->bias_level = level;
@@ -1040,8 +1168,8 @@
{
u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG;
u8 bit = gpio ? 3: 0;
- u8 val = aic3x_read_reg_cache(codec, reg) & ~(1 << bit);
- aic3x_write(codec, reg, val | (!!state << bit));
+ u8 val = snd_soc_read(codec, reg) & ~(1 << bit);
+ snd_soc_write(codec, reg, val | (!!state << bit));
}
EXPORT_SYMBOL_GPL(aic3x_set_gpio);
@@ -1070,7 +1198,7 @@
if (detect & AIC3X_HEADSET_DETECT_MASK)
val |= AIC3X_HEADSET_DETECT_ENABLED;
- aic3x_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val);
+ snd_soc_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val);
}
EXPORT_SYMBOL_GPL(aic3x_set_headset_detection);
@@ -1101,8 +1229,8 @@
.set_fmt = aic3x_set_dai_fmt,
};
-struct snd_soc_dai aic3x_dai = {
- .name = "tlv320aic3x",
+static struct snd_soc_dai_driver aic3x_dai = {
+ .name = "tlv320aic3x-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -1116,34 +1244,18 @@
.rates = AIC3X_RATES,
.formats = AIC3X_FORMATS,},
.ops = &aic3x_dai_ops,
+ .symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(aic3x_dai);
-static int aic3x_suspend(struct platform_device *pdev, pm_message_t state)
+static int aic3x_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int aic3x_resume(struct platform_device *pdev)
+static int aic3x_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
- int i;
- u8 data[2];
- u8 *cache = codec->reg_cache;
-
- /* Sync reg_cache with the hardware */
- for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++) {
- data[0] = i;
- data[1] = cache[i];
- codec->hw_write(codec->control_data, data, 2);
- }
-
aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
@@ -1155,184 +1267,102 @@
*/
static int aic3x_init(struct snd_soc_codec *codec)
{
+ struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
int reg;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->name = "tlv320aic3x";
- codec->owner = THIS_MODULE;
- codec->read = aic3x_read_reg_cache;
- codec->write = aic3x_write;
- codec->set_bias_level = aic3x_set_bias_level;
- codec->dai = &aic3x_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(aic3x_reg);
- codec->reg_cache = kmemdup(aic3x_reg, sizeof(aic3x_reg), GFP_KERNEL);
- if (codec->reg_cache == NULL)
- return -ENOMEM;
-
- aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT);
- aic3x_write(codec, AIC3X_RESET, SOFT_RESET);
+ snd_soc_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT);
+ snd_soc_write(codec, AIC3X_RESET, SOFT_RESET);
/* DAC default volume and mute */
- aic3x_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON);
- aic3x_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON);
+ snd_soc_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON);
+ snd_soc_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON);
/* DAC to HP default volume and route to Output mixer */
- aic3x_write(codec, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON);
- aic3x_write(codec, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON);
- aic3x_write(codec, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON);
- aic3x_write(codec, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON);
+ snd_soc_write(codec, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON);
+ snd_soc_write(codec, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON);
+ snd_soc_write(codec, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON);
+ snd_soc_write(codec, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON);
/* DAC to Line Out default volume and route to Output mixer */
- aic3x_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
- aic3x_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+ snd_soc_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+ snd_soc_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
/* DAC to Mono Line Out default volume and route to Output mixer */
- aic3x_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
- aic3x_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+ snd_soc_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+ snd_soc_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
/* unmute all outputs */
- reg = aic3x_read_reg_cache(codec, LLOPM_CTRL);
- aic3x_write(codec, LLOPM_CTRL, reg | UNMUTE);
- reg = aic3x_read_reg_cache(codec, RLOPM_CTRL);
- aic3x_write(codec, RLOPM_CTRL, reg | UNMUTE);
- reg = aic3x_read_reg_cache(codec, MONOLOPM_CTRL);
- aic3x_write(codec, MONOLOPM_CTRL, reg | UNMUTE);
- reg = aic3x_read_reg_cache(codec, HPLOUT_CTRL);
- aic3x_write(codec, HPLOUT_CTRL, reg | UNMUTE);
- reg = aic3x_read_reg_cache(codec, HPROUT_CTRL);
- aic3x_write(codec, HPROUT_CTRL, reg | UNMUTE);
- reg = aic3x_read_reg_cache(codec, HPLCOM_CTRL);
- aic3x_write(codec, HPLCOM_CTRL, reg | UNMUTE);
- reg = aic3x_read_reg_cache(codec, HPRCOM_CTRL);
- aic3x_write(codec, HPRCOM_CTRL, reg | UNMUTE);
+ reg = snd_soc_read(codec, LLOPM_CTRL);
+ snd_soc_write(codec, LLOPM_CTRL, reg | UNMUTE);
+ reg = snd_soc_read(codec, RLOPM_CTRL);
+ snd_soc_write(codec, RLOPM_CTRL, reg | UNMUTE);
+ reg = snd_soc_read(codec, MONOLOPM_CTRL);
+ snd_soc_write(codec, MONOLOPM_CTRL, reg | UNMUTE);
+ reg = snd_soc_read(codec, HPLOUT_CTRL);
+ snd_soc_write(codec, HPLOUT_CTRL, reg | UNMUTE);
+ reg = snd_soc_read(codec, HPROUT_CTRL);
+ snd_soc_write(codec, HPROUT_CTRL, reg | UNMUTE);
+ reg = snd_soc_read(codec, HPLCOM_CTRL);
+ snd_soc_write(codec, HPLCOM_CTRL, reg | UNMUTE);
+ reg = snd_soc_read(codec, HPRCOM_CTRL);
+ snd_soc_write(codec, HPRCOM_CTRL, reg | UNMUTE);
/* ADC default volume and unmute */
- aic3x_write(codec, LADC_VOL, DEFAULT_GAIN);
- aic3x_write(codec, RADC_VOL, DEFAULT_GAIN);
+ snd_soc_write(codec, LADC_VOL, DEFAULT_GAIN);
+ snd_soc_write(codec, RADC_VOL, DEFAULT_GAIN);
/* By default route Line1 to ADC PGA mixer */
- aic3x_write(codec, LINE1L_2_LADC_CTRL, 0x0);
- aic3x_write(codec, LINE1R_2_RADC_CTRL, 0x0);
+ snd_soc_write(codec, LINE1L_2_LADC_CTRL, 0x0);
+ snd_soc_write(codec, LINE1R_2_RADC_CTRL, 0x0);
/* PGA to HP Bypass default volume, disconnect from Output Mixer */
- aic3x_write(codec, PGAL_2_HPLOUT_VOL, DEFAULT_VOL);
- aic3x_write(codec, PGAR_2_HPROUT_VOL, DEFAULT_VOL);
- aic3x_write(codec, PGAL_2_HPLCOM_VOL, DEFAULT_VOL);
- aic3x_write(codec, PGAR_2_HPRCOM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, PGAL_2_HPLOUT_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, PGAR_2_HPROUT_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, PGAL_2_HPLCOM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, PGAR_2_HPRCOM_VOL, DEFAULT_VOL);
/* PGA to Line Out default volume, disconnect from Output Mixer */
- aic3x_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL);
- aic3x_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL);
/* PGA to Mono Line Out default volume, disconnect from Output Mixer */
- aic3x_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL);
- aic3x_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL);
/* Line2 to HP Bypass default volume, disconnect from Output Mixer */
- aic3x_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL);
- aic3x_write(codec, LINE2R_2_HPROUT_VOL, DEFAULT_VOL);
- aic3x_write(codec, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL);
- aic3x_write(codec, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, LINE2R_2_HPROUT_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL);
/* Line2 Line Out default volume, disconnect from Output Mixer */
- aic3x_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL);
- aic3x_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL);
/* Line2 to Mono Out default volume, disconnect from Output Mixer */
- aic3x_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL);
- aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
- /* off, with power on */
- aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-
-static struct snd_soc_codec *aic3x_codec;
-
-static int aic3x_register(struct snd_soc_codec *codec)
-{
- int ret;
-
- ret = aic3x_init(codec);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to initialise device\n");
- return ret;
- }
-
- aic3x_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret) {
- dev_err(codec->dev, "Failed to register codec\n");
- return ret;
- }
-
- ret = snd_soc_register_dai(&aic3x_dai);
- if (ret) {
- dev_err(codec->dev, "Failed to register dai\n");
- snd_soc_unregister_codec(codec);
- return ret;
+ if (aic3x->model == AIC3X_MODEL_3007) {
+ aic3x_init_3007(codec);
+ snd_soc_write(codec, CLASSD_CTRL, 0);
}
return 0;
}
-static int aic3x_unregister(struct aic3x_priv *aic3x)
+static int aic3x_probe(struct snd_soc_codec *codec)
{
- aic3x_set_bias_level(&aic3x->codec, SND_SOC_BIAS_OFF);
-
- snd_soc_unregister_dai(&aic3x_dai);
- snd_soc_unregister_codec(&aic3x->codec);
-
- if (aic3x->gpio_reset >= 0) {
- gpio_set_value(aic3x->gpio_reset, 0);
- gpio_free(aic3x->gpio_reset);
- }
- regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
- regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
-
- kfree(aic3x);
- aic3x_codec = NULL;
-
- return 0;
-}
-
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-/*
- * AIC3X 2 wire address can be up to 4 devices with device addresses
- * 0x18, 0x19, 0x1A, 0x1B
- */
-
-/*
- * If the i2c layer weren't so broken, we could pass this kind of data
- * around
- */
-static int aic3x_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
-{
- struct snd_soc_codec *codec;
- struct aic3x_priv *aic3x;
- struct aic3x_pdata *pdata = i2c->dev.platform_data;
+ struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
int ret, i;
- aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL);
- if (aic3x == NULL) {
- dev_err(&i2c->dev, "failed to create private data\n");
- return -ENOMEM;
+ codec->control_data = aic3x->control_data;
+ aic3x->codec = codec;
+ codec->idle_bias_off = 1;
+
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
}
- codec = &aic3x->codec;
- codec->dev = &i2c->dev;
- snd_soc_codec_set_drvdata(codec, aic3x);
- codec->control_data = i2c;
- codec->hw_write = (hw_write_t) i2c_master_send;
-
- i2c_set_clientdata(i2c, aic3x);
-
- aic3x->gpio_reset = -1;
- if (pdata && pdata->gpio_reset >= 0) {
- ret = gpio_request(pdata->gpio_reset, "tlv320aic3x reset");
+ if (aic3x->gpio_reset >= 0) {
+ ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset");
if (ret != 0)
goto err_gpio;
- aic3x->gpio_reset = pdata->gpio_reset;
gpio_direction_output(aic3x->gpio_reset, 0);
}
@@ -1345,22 +1375,43 @@
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
goto err_get;
}
-
- ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies),
- aic3x->supplies);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
- goto err_enable;
+ for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) {
+ aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event;
+ aic3x->disable_nb[i].aic3x = aic3x;
+ ret = regulator_register_notifier(aic3x->supplies[i].consumer,
+ &aic3x->disable_nb[i].nb);
+ if (ret) {
+ dev_err(codec->dev,
+ "Failed to request regulator notifier: %d\n",
+ ret);
+ goto err_notif;
+ }
}
- if (aic3x->gpio_reset >= 0) {
- udelay(1);
- gpio_set_value(aic3x->gpio_reset, 1);
+ codec->cache_only = 1;
+ aic3x_init(codec);
+
+ if (aic3x->setup) {
+ /* setup GPIO functions */
+ snd_soc_write(codec, AIC3X_GPIO1_REG,
+ (aic3x->setup->gpio_func[0] & 0xf) << 4);
+ snd_soc_write(codec, AIC3X_GPIO2_REG,
+ (aic3x->setup->gpio_func[1] & 0xf) << 4);
}
- return aic3x_register(codec);
+ snd_soc_add_controls(codec, aic3x_snd_controls,
+ ARRAY_SIZE(aic3x_snd_controls));
+ if (aic3x->model == AIC3X_MODEL_3007)
+ snd_soc_add_controls(codec, &aic3x_classd_amp_gain_ctrl, 1);
-err_enable:
+ aic3x_add_widgets(codec);
+
+ return 0;
+
+err_notif:
+ while (i--)
+ regulator_unregister_notifier(aic3x->supplies[i].consumer,
+ &aic3x->disable_nb[i].nb);
regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
err_get:
if (aic3x->gpio_reset >= 0)
@@ -1370,24 +1421,102 @@
return ret;
}
-static int aic3x_i2c_remove(struct i2c_client *client)
+static int aic3x_remove(struct snd_soc_codec *codec)
{
- struct aic3x_priv *aic3x = i2c_get_clientdata(client);
+ struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+ int i;
- return aic3x_unregister(aic3x);
+ aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ if (aic3x->gpio_reset >= 0) {
+ gpio_set_value(aic3x->gpio_reset, 0);
+ gpio_free(aic3x->gpio_reset);
+ }
+ for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
+ regulator_unregister_notifier(aic3x->supplies[i].consumer,
+ &aic3x->disable_nb[i].nb);
+ regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
+
+ return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_aic3x = {
+ .set_bias_level = aic3x_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(aic3x_reg),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = aic3x_reg,
+ .probe = aic3x_probe,
+ .remove = aic3x_remove,
+ .suspend = aic3x_suspend,
+ .resume = aic3x_resume,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+/*
+ * AIC3X 2 wire address can be up to 4 devices with device addresses
+ * 0x18, 0x19, 0x1A, 0x1B
+ */
+
static const struct i2c_device_id aic3x_i2c_id[] = {
- { "tlv320aic3x", 0 },
- { "tlv320aic33", 0 },
+ [AIC3X_MODEL_3X] = { "tlv320aic3x", 0 },
+ [AIC3X_MODEL_33] = { "tlv320aic33", 0 },
+ [AIC3X_MODEL_3007] = { "tlv320aic3007", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
+/*
+ * If the i2c layer weren't so broken, we could pass this kind of data
+ * around
+ */
+static int aic3x_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct aic3x_pdata *pdata = i2c->dev.platform_data;
+ struct aic3x_priv *aic3x;
+ int ret;
+ const struct i2c_device_id *tbl;
+
+ aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL);
+ if (aic3x == NULL) {
+ dev_err(&i2c->dev, "failed to create private data\n");
+ return -ENOMEM;
+ }
+
+ aic3x->control_data = i2c;
+ aic3x->control_type = SND_SOC_I2C;
+
+ i2c_set_clientdata(i2c, aic3x);
+ if (pdata) {
+ aic3x->gpio_reset = pdata->gpio_reset;
+ aic3x->setup = pdata->setup;
+ } else {
+ aic3x->gpio_reset = -1;
+ }
+
+ for (tbl = aic3x_i2c_id; tbl->name[0]; tbl++) {
+ if (!strcmp(tbl->name, id->name))
+ break;
+ }
+ aic3x->model = tbl - aic3x_i2c_id;
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_aic3x, &aic3x_dai, 1);
+ if (ret < 0)
+ kfree(aic3x);
+ return ret;
+}
+
+static int aic3x_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
/* machine i2c codec control layer */
static struct i2c_driver aic3x_i2c_driver = {
.driver = {
- .name = "aic3x I2C Codec",
+ .name = "tlv320aic3x-codec",
.owner = THIS_MODULE,
},
.probe = aic3x_i2c_probe,
@@ -1409,90 +1538,27 @@
{
i2c_del_driver(&aic3x_i2c_driver);
}
-#else
-static inline void aic3x_i2c_init(void) { }
-static inline void aic3x_i2c_exit(void) { }
#endif
-static int aic3x_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct aic3x_setup_data *setup;
- struct snd_soc_codec *codec;
- int ret = 0;
-
- codec = aic3x_codec;
- if (!codec) {
- dev_err(&pdev->dev, "Codec not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = codec;
- setup = socdev->codec_data;
-
- if (setup) {
- /* setup GPIO functions */
- aic3x_write(codec, AIC3X_GPIO1_REG,
- (setup->gpio_func[0] & 0xf) << 4);
- aic3x_write(codec, AIC3X_GPIO2_REG,
- (setup->gpio_func[1] & 0xf) << 4);
- }
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "aic3x: failed to create pcms\n");
- goto pcm_err;
- }
-
- snd_soc_add_controls(codec, aic3x_snd_controls,
- ARRAY_SIZE(aic3x_snd_controls));
-
- aic3x_add_widgets(codec);
-
- return ret;
-
-pcm_err:
- kfree(codec->reg_cache);
- return ret;
-}
-
-static int aic3x_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- /* power down chip */
- if (codec->control_data)
- aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- kfree(codec->reg_cache);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_aic3x = {
- .probe = aic3x_probe,
- .remove = aic3x_remove,
- .suspend = aic3x_suspend,
- .resume = aic3x_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_aic3x);
-
static int __init aic3x_modinit(void)
{
- aic3x_i2c_init();
-
- return 0;
+ int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&aic3x_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register TLV320AIC3x I2C driver: %d\n",
+ ret);
+ }
+#endif
+ return ret;
}
module_init(aic3x_modinit);
static void __exit aic3x_exit(void)
{
- aic3x_i2c_exit();
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&aic3x_i2c_driver);
+#endif
}
module_exit(aic3x_exit);
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h
index 9af1c88..06a1978 100644
--- a/sound/soc/codecs/tlv320aic3x.h
+++ b/sound/soc/codecs/tlv320aic3x.h
@@ -81,50 +81,63 @@
/* DAC Digital control registers */
#define LDAC_VOL 43
#define RDAC_VOL 44
-/* High Power Output control registers */
+/* Left High Power Output control registers */
#define LINE2L_2_HPLOUT_VOL 45
-#define LINE2R_2_HPROUT_VOL 62
#define PGAL_2_HPLOUT_VOL 46
-#define PGAL_2_HPROUT_VOL 60
-#define PGAR_2_HPLOUT_VOL 49
-#define PGAR_2_HPROUT_VOL 63
#define DACL1_2_HPLOUT_VOL 47
-#define DACR1_2_HPROUT_VOL 64
+#define LINE2R_2_HPLOUT_VOL 48
+#define PGAR_2_HPLOUT_VOL 49
+#define DACR1_2_HPLOUT_VOL 50
#define HPLOUT_CTRL 51
-#define HPROUT_CTRL 65
-/* High Power COM control registers */
+/* Left High Power COM control registers */
#define LINE2L_2_HPLCOM_VOL 52
-#define LINE2R_2_HPRCOM_VOL 69
#define PGAL_2_HPLCOM_VOL 53
-#define PGAR_2_HPLCOM_VOL 56
-#define PGAL_2_HPRCOM_VOL 67
-#define PGAR_2_HPRCOM_VOL 70
#define DACL1_2_HPLCOM_VOL 54
-#define DACR1_2_HPRCOM_VOL 71
+#define LINE2R_2_HPLCOM_VOL 55
+#define PGAR_2_HPLCOM_VOL 56
+#define DACR1_2_HPLCOM_VOL 57
#define HPLCOM_CTRL 58
+/* Right High Power Output control registers */
+#define LINE2L_2_HPROUT_VOL 59
+#define PGAL_2_HPROUT_VOL 60
+#define DACL1_2_HPROUT_VOL 61
+#define LINE2R_2_HPROUT_VOL 62
+#define PGAR_2_HPROUT_VOL 63
+#define DACR1_2_HPROUT_VOL 64
+#define HPROUT_CTRL 65
+/* Right High Power COM control registers */
+#define LINE2L_2_HPRCOM_VOL 66
+#define PGAL_2_HPRCOM_VOL 67
+#define DACL1_2_HPRCOM_VOL 68
+#define LINE2R_2_HPRCOM_VOL 69
+#define PGAR_2_HPRCOM_VOL 70
+#define DACR1_2_HPRCOM_VOL 71
#define HPRCOM_CTRL 72
/* Mono Line Output Plus/Minus control registers */
#define LINE2L_2_MONOLOPM_VOL 73
-#define LINE2R_2_MONOLOPM_VOL 76
#define PGAL_2_MONOLOPM_VOL 74
-#define PGAR_2_MONOLOPM_VOL 77
#define DACL1_2_MONOLOPM_VOL 75
+#define LINE2R_2_MONOLOPM_VOL 76
+#define PGAR_2_MONOLOPM_VOL 77
#define DACR1_2_MONOLOPM_VOL 78
#define MONOLOPM_CTRL 79
-/* Line Output Plus/Minus control registers */
+/* Class-D speaker driver on tlv320aic3007 */
+#define CLASSD_CTRL 73
+/* Left Line Output Plus/Minus control registers */
#define LINE2L_2_LLOPM_VOL 80
-#define LINE2L_2_RLOPM_VOL 87
-#define LINE2R_2_LLOPM_VOL 83
-#define LINE2R_2_RLOPM_VOL 90
#define PGAL_2_LLOPM_VOL 81
-#define PGAL_2_RLOPM_VOL 88
-#define PGAR_2_LLOPM_VOL 84
-#define PGAR_2_RLOPM_VOL 91
#define DACL1_2_LLOPM_VOL 82
-#define DACL1_2_RLOPM_VOL 89
-#define DACR1_2_RLOPM_VOL 92
+#define LINE2R_2_LLOPM_VOL 83
+#define PGAR_2_LLOPM_VOL 84
#define DACR1_2_LLOPM_VOL 85
#define LLOPM_CTRL 86
+/* Right Line Output Plus/Minus control registers */
+#define LINE2L_2_RLOPM_VOL 87
+#define PGAL_2_RLOPM_VOL 88
+#define DACL1_2_RLOPM_VOL 89
+#define LINE2R_2_RLOPM_VOL 90
+#define PGAR_2_RLOPM_VOL 91
+#define DACR1_2_RLOPM_VOL 92
#define RLOPM_CTRL 93
/* GPIO/IRQ registers */
#define AIC3X_STICKY_IRQ_FLAGS_REG 96
@@ -199,42 +212,6 @@
/* Default input volume */
#define DEFAULT_GAIN 0x20
-/* GPIO API */
-enum {
- AIC3X_GPIO1_FUNC_DISABLED = 0,
- AIC3X_GPIO1_FUNC_AUDIO_WORDCLK_ADC = 1,
- AIC3X_GPIO1_FUNC_CLOCK_MUX = 2,
- AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV2 = 3,
- AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV4 = 4,
- AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV8 = 5,
- AIC3X_GPIO1_FUNC_SHORT_CIRCUIT_IRQ = 6,
- AIC3X_GPIO1_FUNC_AGC_NOISE_IRQ = 7,
- AIC3X_GPIO1_FUNC_INPUT = 8,
- AIC3X_GPIO1_FUNC_OUTPUT = 9,
- AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK = 10,
- AIC3X_GPIO1_FUNC_AUDIO_WORDCLK = 11,
- AIC3X_GPIO1_FUNC_BUTTON_IRQ = 12,
- AIC3X_GPIO1_FUNC_HEADSET_DETECT_IRQ = 13,
- AIC3X_GPIO1_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 14,
- AIC3X_GPIO1_FUNC_ALL_IRQ = 16
-};
-
-enum {
- AIC3X_GPIO2_FUNC_DISABLED = 0,
- AIC3X_GPIO2_FUNC_HEADSET_DETECT_IRQ = 2,
- AIC3X_GPIO2_FUNC_INPUT = 3,
- AIC3X_GPIO2_FUNC_OUTPUT = 4,
- AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT = 5,
- AIC3X_GPIO2_FUNC_AUDIO_BITCLK = 8,
- AIC3X_GPIO2_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 9,
- AIC3X_GPIO2_FUNC_ALL_IRQ = 10,
- AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_OR_AGC_IRQ = 11,
- AIC3X_GPIO2_FUNC_HEADSET_OR_BUTTON_PRESS_OR_SHORT_CIRCUIT_IRQ = 12,
- AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_IRQ = 13,
- AIC3X_GPIO2_FUNC_AGC_NOISE_IRQ = 14,
- AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ = 15
-};
-
void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state);
int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio);
@@ -281,11 +258,4 @@
int aic3x_headset_detected(struct snd_soc_codec *codec);
int aic3x_button_pressed(struct snd_soc_codec *codec);
-struct aic3x_setup_data {
- unsigned int gpio_func[2];
-};
-
-extern struct snd_soc_dai aic3x_dai;
-extern struct snd_soc_codec_device soc_codec_dev_aic3x;
-
#endif /* _AIC3X_H */
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 8651b01..d251ff5 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -66,8 +66,6 @@
static void dac33_calculate_times(struct snd_pcm_substream *substream);
static int dac33_prepare_chip(struct snd_pcm_substream *substream);
-static struct snd_soc_codec *tlv320dac33_codec;
-
enum dac33_state {
DAC33_IDLE = 0,
DAC33_PREFILL,
@@ -93,7 +91,7 @@
struct mutex mutex;
struct workqueue_struct *dac33_wq;
struct work_struct work;
- struct snd_soc_codec codec;
+ struct snd_soc_codec *codec;
struct regulator_bulk_data supplies[DAC33_NUM_SUPPLIES];
struct snd_pcm_substream *substream;
int power_gpio;
@@ -128,6 +126,8 @@
unsigned int uthr;
enum dac33_state state;
+ enum snd_soc_control_type control_type;
+ void *control_data;
};
static const u8 dac33_reg[DAC33_CACHEREGNUM] = {
@@ -524,6 +524,22 @@
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dac33_fifo_mode_texts),
dac33_fifo_mode_texts);
+/* L/R Line Output Gain */
+static const char *lr_lineout_gain_texts[] = {
+ "Line -12dB DAC 0dB", "Line -6dB DAC 6dB",
+ "Line 0dB DAC 12dB", "Line 6dB DAC 18dB",
+};
+
+static const struct soc_enum l_lineout_gain_enum =
+ SOC_ENUM_SINGLE(DAC33_LDAC_PWR_CTRL, 0,
+ ARRAY_SIZE(lr_lineout_gain_texts),
+ lr_lineout_gain_texts);
+
+static const struct soc_enum r_lineout_gain_enum =
+ SOC_ENUM_SINGLE(DAC33_RDAC_PWR_CTRL, 0,
+ ARRAY_SIZE(lr_lineout_gain_texts),
+ lr_lineout_gain_texts);
+
/*
* DACL/R digital volume control:
* from 0 dB to -63.5 in 0.5 dB steps
@@ -541,6 +557,8 @@
DAC33_LDAC_DIG_VOL_CTRL, DAC33_RDAC_DIG_VOL_CTRL, 7, 1, 1),
SOC_DOUBLE_R("Line to Line Out Volume",
DAC33_LINEL_TO_LLO_VOL, DAC33_LINER_TO_RLO_VOL, 0, 127, 1),
+ SOC_ENUM("Left Line Output Gain", l_lineout_gain_enum),
+ SOC_ENUM("Right Line Output Gain", r_lineout_gain_enum),
};
static const struct snd_kcontrol_new dac33_mode_snd_controls[] = {
@@ -650,9 +668,8 @@
static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
{
- struct snd_soc_codec *codec;
-
- codec = &dac33->codec;
+ struct snd_soc_codec *codec = dac33->codec;
+ unsigned int delay;
switch (dac33->fifo_mode) {
case DAC33_FIFO_MODE1:
@@ -668,8 +685,9 @@
dac33_write16(codec, DAC33_PREFILL_MSB,
DAC33_THRREG(dac33->alarm_threshold));
/* Enable Alarm Threshold IRQ with a delay */
- udelay(SAMPLES_TO_US(dac33->burst_rate,
- dac33->alarm_threshold));
+ delay = SAMPLES_TO_US(dac33->burst_rate,
+ dac33->alarm_threshold) + 1000;
+ usleep_range(delay, delay + 500);
dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MAT);
break;
case DAC33_FIFO_MODE7:
@@ -695,9 +713,7 @@
static inline void dac33_playback_handler(struct tlv320dac33_priv *dac33)
{
- struct snd_soc_codec *codec;
-
- codec = &dac33->codec;
+ struct snd_soc_codec *codec = dac33->codec;
switch (dac33->fifo_mode) {
case DAC33_FIFO_MODE1:
@@ -726,7 +742,7 @@
u8 reg;
dac33 = container_of(work, struct tlv320dac33_priv, work);
- codec = &dac33->codec;
+ codec = dac33->codec;
mutex_lock(&dac33->mutex);
switch (dac33->state) {
@@ -771,11 +787,11 @@
static void dac33_oscwait(struct snd_soc_codec *codec)
{
- int timeout = 20;
+ int timeout = 60;
u8 reg;
do {
- msleep(1);
+ usleep_range(1000, 2000);
dac33_read(codec, DAC33_INT_OSC_STATUS, ®);
} while (((reg & 0x03) != DAC33_OSCSTATUS_NORMAL) && timeout--);
if ((reg & 0x03) != DAC33_OSCSTATUS_NORMAL)
@@ -787,8 +803,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
/* Stream started, save the substream pointer */
@@ -801,8 +816,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
dac33->substream = NULL;
@@ -817,8 +831,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
/* Check parameters for validity */
switch (params_rate(params)) {
@@ -856,8 +869,7 @@
static int dac33_prepare_chip(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
unsigned int oscset, ratioset, pwr_ctrl, reg_tmp;
u8 aictrl_a, aictrl_b, fifoctrl_a;
@@ -1049,8 +1061,7 @@
static void dac33_calculate_times(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
unsigned int period_size = substream->runtime->period_size;
unsigned int rate = substream->runtime->rate;
@@ -1129,8 +1140,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
@@ -1163,8 +1173,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
unsigned long long t0, t1, t_now;
unsigned int time_delta, uthr;
@@ -1389,24 +1398,46 @@
return 0;
}
-static int dac33_soc_probe(struct platform_device *pdev)
+static int dac33_soc_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- struct tlv320dac33_priv *dac33;
+ struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
- BUG_ON(!tlv320dac33_codec);
+ codec->control_data = dac33->control_data;
+ codec->hw_write = (hw_write_t) i2c_master_send;
+ codec->idle_bias_off = 1;
+ dac33->codec = codec;
- codec = tlv320dac33_codec;
- socdev->card->codec = codec;
- dac33 = snd_soc_codec_get_drvdata(codec);
+ /* Read the tlv320dac33 ID registers */
+ ret = dac33_hard_power(codec, 1);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to power up codec: %d\n", ret);
+ goto err_power;
+ }
+ dac33_read_id(codec);
+ dac33_hard_power(codec, 0);
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms\n");
- goto pcm_err;
+ /* Check if the IRQ number is valid and request it */
+ if (dac33->irq >= 0) {
+ ret = request_irq(dac33->irq, dac33_interrupt_handler,
+ IRQF_TRIGGER_RISING | IRQF_DISABLED,
+ codec->name, codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Could not request IRQ%d (%d)\n",
+ dac33->irq, ret);
+ dac33->irq = -1;
+ }
+ if (dac33->irq != -1) {
+ /* Setup work queue */
+ dac33->dac33_wq =
+ create_singlethread_workqueue("tlv320dac33");
+ if (dac33->dac33_wq == NULL) {
+ free_irq(dac33->irq, codec);
+ return -ENOMEM;
+ }
+
+ INIT_WORK(&dac33->work, dac33_work);
+ }
}
snd_soc_add_controls(codec, dac33_snd_controls,
@@ -1420,56 +1451,51 @@
snd_soc_add_controls(codec, dac33_fifo_snd_controls,
ARRAY_SIZE(dac33_fifo_snd_controls));
}
-
dac33_add_widgets(codec);
- return 0;
-
-pcm_err:
- dac33_hard_power(codec, 0);
+err_power:
return ret;
}
-static int dac33_soc_remove(struct platform_device *pdev)
+static int dac33_soc_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
dac33_set_bias_level(codec, SND_SOC_BIAS_OFF);
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
+ if (dac33->irq >= 0) {
+ free_irq(dac33->irq, dac33->codec);
+ destroy_workqueue(dac33->dac33_wq);
+ }
return 0;
}
-static int dac33_soc_suspend(struct platform_device *pdev, pm_message_t state)
+static int dac33_soc_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
dac33_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int dac33_soc_resume(struct platform_device *pdev)
+static int dac33_soc_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_tlv320dac33 = {
+static struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = {
+ .read = dac33_read_reg_cache,
+ .write = dac33_write_locked,
+ .set_bias_level = dac33_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(dac33_reg),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = dac33_reg,
.probe = dac33_soc_probe,
.remove = dac33_soc_remove,
.suspend = dac33_soc_suspend,
.resume = dac33_soc_resume,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320dac33);
#define DAC33_RATES (SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000)
@@ -1485,8 +1511,8 @@
.set_fmt = dac33_set_dai_fmt,
};
-struct snd_soc_dai dac33_dai = {
- .name = "tlv320dac33",
+static struct snd_soc_dai_driver dac33_dai = {
+ .name = "tlv320dac33-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -1495,14 +1521,12 @@
.formats = DAC33_FORMATS,},
.ops = &dac33_dai_ops,
};
-EXPORT_SYMBOL_GPL(dac33_dai);
static int __devinit dac33_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct tlv320dac33_platform_data *pdata;
struct tlv320dac33_priv *dac33;
- struct snd_soc_codec *codec;
int ret, i;
if (client->dev.platform_data == NULL) {
@@ -1515,33 +1539,9 @@
if (dac33 == NULL)
return -ENOMEM;
- codec = &dac33->codec;
- snd_soc_codec_set_drvdata(codec, dac33);
- codec->control_data = client;
-
- mutex_init(&codec->mutex);
+ dac33->control_data = client;
mutex_init(&dac33->mutex);
spin_lock_init(&dac33->lock);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->name = "tlv320dac33";
- codec->owner = THIS_MODULE;
- codec->read = dac33_read_reg_cache;
- codec->write = dac33_write_locked;
- codec->hw_write = (hw_write_t) i2c_master_send;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = dac33_set_bias_level;
- codec->idle_bias_off = 1;
- codec->dai = &dac33_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(dac33_reg);
- codec->reg_cache = kmemdup(dac33_reg, ARRAY_SIZE(dac33_reg),
- GFP_KERNEL);
- if (codec->reg_cache == NULL) {
- ret = -ENOMEM;
- goto error_reg;
- }
i2c_set_clientdata(client, dac33);
@@ -1561,125 +1561,59 @@
/* Disable FIFO use by default */
dac33->fifo_mode = DAC33_FIFO_BYPASS;
- tlv320dac33_codec = codec;
-
- codec->dev = &client->dev;
- dac33_dai.dev = codec->dev;
-
/* Check if the reset GPIO number is valid and request it */
if (dac33->power_gpio >= 0) {
ret = gpio_request(dac33->power_gpio, "tlv320dac33 reset");
if (ret < 0) {
- dev_err(codec->dev,
+ dev_err(&client->dev,
"Failed to request reset GPIO (%d)\n",
dac33->power_gpio);
- snd_soc_unregister_dai(&dac33_dai);
- snd_soc_unregister_codec(codec);
- goto error_gpio;
+ goto err_gpio;
}
gpio_direction_output(dac33->power_gpio, 0);
}
- /* Check if the IRQ number is valid and request it */
- if (dac33->irq >= 0) {
- ret = request_irq(dac33->irq, dac33_interrupt_handler,
- IRQF_TRIGGER_RISING | IRQF_DISABLED,
- codec->name, codec);
- if (ret < 0) {
- dev_err(codec->dev, "Could not request IRQ%d (%d)\n",
- dac33->irq, ret);
- dac33->irq = -1;
- }
- if (dac33->irq != -1) {
- /* Setup work queue */
- dac33->dac33_wq =
- create_singlethread_workqueue("tlv320dac33");
- if (dac33->dac33_wq == NULL) {
- free_irq(dac33->irq, &dac33->codec);
- ret = -ENOMEM;
- goto error_wq;
- }
-
- INIT_WORK(&dac33->work, dac33_work);
- }
- }
-
for (i = 0; i < ARRAY_SIZE(dac33->supplies); i++)
dac33->supplies[i].supply = dac33_supply_names[i];
- ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(dac33->supplies),
+ ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(dac33->supplies),
dac33->supplies);
if (ret != 0) {
- dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+ dev_err(&client->dev, "Failed to request supplies: %d\n", ret);
goto err_get;
}
- /* Read the tlv320dac33 ID registers */
- ret = dac33_hard_power(codec, 1);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to power up codec: %d\n", ret);
- goto error_codec;
- }
- dac33_read_id(codec);
- dac33_hard_power(codec, 0);
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto error_codec;
- }
-
- ret = snd_soc_register_dai(&dac33_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- snd_soc_unregister_codec(codec);
- goto error_codec;
- }
+ ret = snd_soc_register_codec(&client->dev,
+ &soc_codec_dev_tlv320dac33, &dac33_dai, 1);
+ if (ret < 0)
+ goto err_register;
return ret;
-
-error_codec:
+err_register:
regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);
err_get:
- if (dac33->irq >= 0) {
- free_irq(dac33->irq, &dac33->codec);
- destroy_workqueue(dac33->dac33_wq);
- }
-error_wq:
if (dac33->power_gpio >= 0)
gpio_free(dac33->power_gpio);
-error_gpio:
- kfree(codec->reg_cache);
-error_reg:
- tlv320dac33_codec = NULL;
+err_gpio:
kfree(dac33);
-
return ret;
}
static int __devexit dac33_i2c_remove(struct i2c_client *client)
{
- struct tlv320dac33_priv *dac33;
-
- dac33 = i2c_get_clientdata(client);
+ struct tlv320dac33_priv *dac33 = i2c_get_clientdata(client);
if (unlikely(dac33->chip_power))
- dac33_hard_power(&dac33->codec, 0);
+ dac33_hard_power(dac33->codec, 0);
if (dac33->power_gpio >= 0)
gpio_free(dac33->power_gpio);
- if (dac33->irq >= 0)
- free_irq(dac33->irq, &dac33->codec);
regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);
- destroy_workqueue(dac33->dac33_wq);
- snd_soc_unregister_dai(&dac33_dai);
- snd_soc_unregister_codec(&dac33->codec);
- kfree(dac33->codec.reg_cache);
+ snd_soc_unregister_codec(&client->dev);
kfree(dac33);
- tlv320dac33_codec = NULL;
return 0;
}
@@ -1694,7 +1628,7 @@
static struct i2c_driver tlv320dac33_i2c_driver = {
.driver = {
- .name = "tlv320dac33",
+ .name = "tlv320dac33-codec",
.owner = THIS_MODULE,
},
.probe = dac33_i2c_probe,
diff --git a/sound/soc/codecs/tlv320dac33.h b/sound/soc/codecs/tlv320dac33.h
index eb8ae07..7c318b5 100644
--- a/sound/soc/codecs/tlv320dac33.h
+++ b/sound/soc/codecs/tlv320dac33.h
@@ -261,7 +261,4 @@
#define TLV320DAC33_MCLK 0
#define TLV320DAC33_SLEEPCLK 1
-extern struct snd_soc_dai dac33_dai;
-extern struct snd_soc_codec_device soc_codec_dev_tlv320dac33;
-
#endif /* __TLV320DAC33_H */
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c
index 99b70e5..329acc1 100644
--- a/sound/soc/codecs/tpa6130a2.c
+++ b/sound/soc/codecs/tpa6130a2.c
@@ -98,16 +98,21 @@
return data->regs[reg];
}
-static void tpa6130a2_initialize(void)
+static int tpa6130a2_initialize(void)
{
struct tpa6130a2_data *data;
- int i;
+ int i, ret = 0;
BUG_ON(tpa6130a2_client == NULL);
data = i2c_get_clientdata(tpa6130a2_client);
- for (i = 1; i < TPA6130A2_REG_VERSION; i++)
- tpa6130a2_i2c_write(i, data->regs[i]);
+ for (i = 1; i < TPA6130A2_REG_VERSION; i++) {
+ ret = tpa6130a2_i2c_write(i, data->regs[i]);
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
}
static int tpa6130a2_power(int power)
@@ -133,7 +138,16 @@
}
data->power_state = 1;
- tpa6130a2_initialize();
+ ret = tpa6130a2_initialize();
+ if (ret < 0) {
+ dev_err(&tpa6130a2_client->dev,
+ "Failed to initialize chip\n");
+ if (data->power_gpio >= 0)
+ gpio_set_value(data->power_gpio, 0);
+ regulator_disable(data->supply);
+ data->power_state = 0;
+ goto exit;
+ }
/* Clear SWS */
val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
@@ -375,7 +389,9 @@
{
struct tpa6130a2_data *data;
- BUG_ON(tpa6130a2_client == NULL);
+ if (tpa6130a2_client == NULL)
+ return -ENODEV;
+
data = i2c_get_clientdata(tpa6130a2_client);
snd_soc_dapm_new_controls(codec, tpa6130a2_dapm_widgets,
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 7b618bb..cbebec6 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -36,7 +36,16 @@
#include <sound/initval.h>
#include <sound/tlv.h>
-#include "twl4030.h"
+/* Register descriptions are here */
+#include <linux/mfd/twl4030-codec.h>
+
+/* Shadow register used by the audio driver */
+#define TWL4030_REG_SW_SHADOW 0x4A
+#define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1)
+
+/* TWL4030_REG_SW_SHADOW (0x4A) Fields */
+#define TWL4030_HFL_EN 0x01
+#define TWL4030_HFR_EN 0x02
/*
* twl4030 register cache & default register settings
@@ -277,21 +286,19 @@
}
-static void twl4030_init_chip(struct platform_device *pdev)
+static void twl4030_init_chip(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct twl4030_setup_data *setup = socdev->codec_data;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct twl4030_codec_audio_data *pdata = dev_get_platdata(codec->dev);
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
u8 reg, byte;
int i = 0;
/* Check defaults, if instructed before anything else */
- if (setup && setup->check_defaults)
+ if (pdata && pdata->check_defaults)
twl4030_check_defaults(codec);
/* Reset registers, if no setup data or if instructed to do so */
- if (!setup || (setup && setup->reset_registers))
+ if (!pdata || (pdata && pdata->reset_registers))
twl4030_reset_registers(codec);
/* Refresh APLL_CTL register from HW */
@@ -312,20 +319,14 @@
twl4030_write(codec, TWL4030_REG_ARXR2_APGA_CTL, 0x32);
/* Machine dependent setup */
- if (!setup)
+ if (!pdata)
return;
- twl4030->digimic_delay = setup->digimic_delay;
-
- /* Configuration for headset ramp delay from setup data */
- if (setup->sysclk != twl4030->sysclk)
- dev_warn(codec->dev,
- "Mismatch in APLL mclk: %u (configured: %u)\n",
- setup->sysclk, twl4030->sysclk);
+ twl4030->digimic_delay = pdata->digimic_delay;
reg = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
reg &= ~TWL4030_RAMP_DELAY;
- reg |= (setup->ramp_delay_value << 2);
+ reg |= (pdata->ramp_delay_value << 2);
twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, reg);
/* initiate offset cancellation */
@@ -333,7 +334,7 @@
reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
reg &= ~TWL4030_OFFSET_CNCL_SEL;
- reg |= setup->offset_cncl_path;
+ reg |= pdata->offset_cncl_path;
twl4030_write(codec, TWL4030_REG_ANAMICL,
reg | TWL4030_CNCL_OFFSET_START);
@@ -718,9 +719,7 @@
static void headset_ramp(struct snd_soc_codec *codec, int ramp)
{
- struct snd_soc_device *socdev = codec->socdev;
- struct twl4030_setup_data *setup = socdev->codec_data;
-
+ struct twl4030_codec_audio_data *pdata = codec->dev->platform_data;
unsigned char hs_gain, hs_pop;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
/* Base values for ramp delay calculation: 2^19 - 2^26 */
@@ -732,9 +731,9 @@
/* Enable external mute control, this dramatically reduces
* the pop-noise */
- if (setup && setup->hs_extmute) {
- if (setup->set_hs_extmute) {
- setup->set_hs_extmute(1);
+ if (pdata && pdata->hs_extmute) {
+ if (pdata->set_hs_extmute) {
+ pdata->set_hs_extmute(1);
} else {
hs_pop |= TWL4030_EXTMUTE;
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
@@ -772,9 +771,9 @@
}
/* Disable external mute */
- if (setup && setup->hs_extmute) {
- if (setup->set_hs_extmute) {
- setup->set_hs_extmute(0);
+ if (pdata && pdata->hs_extmute) {
+ if (pdata->set_hs_extmute) {
+ pdata->set_hs_extmute(0);
} else {
hs_pop &= ~TWL4030_EXTMUTE;
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
@@ -1707,8 +1706,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
if (twl4030->master_substream) {
@@ -1738,8 +1736,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
if (twl4030->master_substream == substream)
@@ -1764,8 +1761,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
u8 mode, old_mode, format, old_format;
@@ -1999,8 +1995,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
u8 mode;
@@ -2033,8 +2028,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
/* Enable voice digital filters */
twl4030_voice_enable(codec, substream->stream, 0);
@@ -2044,8 +2038,7 @@
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
u8 old_mode, mode;
@@ -2175,7 +2168,7 @@
#define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000)
#define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE)
-static struct snd_soc_dai_ops twl4030_dai_ops = {
+static struct snd_soc_dai_ops twl4030_dai_hifi_ops = {
.startup = twl4030_startup,
.shutdown = twl4030_shutdown,
.hw_params = twl4030_hw_params,
@@ -2193,9 +2186,9 @@
.set_tristate = twl4030_voice_set_tristate,
};
-struct snd_soc_dai twl4030_dai[] = {
+static struct snd_soc_dai_driver twl4030_dai[] = {
{
- .name = "twl4030",
+ .name = "twl4030-hifi",
.playback = {
.stream_name = "HiFi Playback",
.channels_min = 2,
@@ -2208,10 +2201,10 @@
.channels_max = 4,
.rates = TWL4030_RATES,
.formats = TWL4030_FORMATS,},
- .ops = &twl4030_dai_ops,
+ .ops = &twl4030_dai_hifi_ops,
},
{
- .name = "twl4030 Voice",
+ .name = "twl4030-voice",
.playback = {
.stream_name = "Voice Playback",
.channels_min = 1,
@@ -2227,164 +2220,91 @@
.ops = &twl4030_dai_voice_ops,
},
};
-EXPORT_SYMBOL_GPL(twl4030_dai);
-static int twl4030_soc_suspend(struct platform_device *pdev, pm_message_t state)
+static int twl4030_soc_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
return 0;
}
-static int twl4030_soc_resume(struct platform_device *pdev)
+static int twl4030_soc_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
-static struct snd_soc_codec *twl4030_codec;
-
-static int twl4030_soc_probe(struct platform_device *pdev)
+static int twl4030_soc_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret;
+ struct twl4030_priv *twl4030;
- BUG_ON(!twl4030_codec);
-
- codec = twl4030_codec;
- socdev->card->codec = codec;
-
- twl4030_init_chip(pdev);
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to create pcms\n");
- return ret;
+ twl4030 = kzalloc(sizeof(struct twl4030_priv), GFP_KERNEL);
+ if (twl4030 == NULL) {
+ printk("Can not allocate memroy\n");
+ return -ENOMEM;
}
+ snd_soc_codec_set_drvdata(codec, twl4030);
+ /* Set the defaults, and power up the codec */
+ twl4030->sysclk = twl4030_codec_get_mclk() / 1000;
+ codec->idle_bias_off = 1;
+
+ twl4030_init_chip(codec);
snd_soc_add_controls(codec, twl4030_snd_controls,
ARRAY_SIZE(twl4030_snd_controls));
twl4030_add_widgets(codec);
-
return 0;
}
-static int twl4030_soc_remove(struct platform_device *pdev)
+static int twl4030_soc_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
/* Reset registers to their chip default before leaving */
twl4030_reset_registers(codec);
twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
+ .probe = twl4030_soc_probe,
+ .remove = twl4030_soc_remove,
+ .suspend = twl4030_soc_suspend,
+ .resume = twl4030_soc_resume,
+ .read = twl4030_read_reg_cache,
+ .write = twl4030_write,
+ .set_bias_level = twl4030_set_bias_level,
+ .reg_cache_size = sizeof(twl4030_reg),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = twl4030_reg,
+};
+
static int __devinit twl4030_codec_probe(struct platform_device *pdev)
{
struct twl4030_codec_audio_data *pdata = pdev->dev.platform_data;
- struct snd_soc_codec *codec;
- struct twl4030_priv *twl4030;
- int ret;
if (!pdata) {
dev_err(&pdev->dev, "platform_data is missing\n");
return -EINVAL;
}
- twl4030 = kzalloc(sizeof(struct twl4030_priv), GFP_KERNEL);
- if (twl4030 == NULL) {
- dev_err(&pdev->dev, "Can not allocate memroy\n");
- return -ENOMEM;
- }
-
- codec = &twl4030->codec;
- snd_soc_codec_set_drvdata(codec, twl4030);
- codec->dev = &pdev->dev;
- twl4030_dai[0].dev = &pdev->dev;
- twl4030_dai[1].dev = &pdev->dev;
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->name = "twl4030";
- codec->owner = THIS_MODULE;
- codec->read = twl4030_read_reg_cache;
- codec->write = twl4030_write;
- codec->set_bias_level = twl4030_set_bias_level;
- codec->idle_bias_off = 1;
- codec->dai = twl4030_dai;
- codec->num_dai = ARRAY_SIZE(twl4030_dai);
- codec->reg_cache_size = sizeof(twl4030_reg);
- codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg),
- GFP_KERNEL);
- if (codec->reg_cache == NULL) {
- ret = -ENOMEM;
- goto error_cache;
- }
-
- platform_set_drvdata(pdev, twl4030);
- twl4030_codec = codec;
-
- /* Set the defaults, and power up the codec */
- twl4030->sysclk = twl4030_codec_get_mclk() / 1000;
- codec->bias_level = SND_SOC_BIAS_OFF;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto error_codec;
- }
-
- ret = snd_soc_register_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai));
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
- snd_soc_unregister_codec(codec);
- goto error_codec;
- }
-
- return 0;
-
-error_codec:
- twl4030_codec_enable(codec, 0);
- kfree(codec->reg_cache);
-error_cache:
- kfree(twl4030);
- return ret;
+ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_twl4030,
+ twl4030_dai, ARRAY_SIZE(twl4030_dai));
}
static int __devexit twl4030_codec_remove(struct platform_device *pdev)
{
- struct twl4030_priv *twl4030 = platform_get_drvdata(pdev);
+ struct twl4030_priv *twl4030 = dev_get_drvdata(&pdev->dev);
- snd_soc_unregister_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai));
- snd_soc_unregister_codec(&twl4030->codec);
- kfree(twl4030->codec.reg_cache);
+ snd_soc_unregister_codec(&pdev->dev);
kfree(twl4030);
-
- twl4030_codec = NULL;
return 0;
}
-MODULE_ALIAS("platform:twl4030_codec_audio");
+MODULE_ALIAS("platform:twl4030-codec");
static struct platform_driver twl4030_codec_driver = {
.probe = twl4030_codec_probe,
.remove = __devexit_p(twl4030_codec_remove),
.driver = {
- .name = "twl4030_codec_audio",
+ .name = "twl4030-codec",
.owner = THIS_MODULE,
},
};
@@ -2401,14 +2321,6 @@
}
module_exit(twl4030_exit);
-struct snd_soc_codec_device soc_codec_dev_twl4030 = {
- .probe = twl4030_soc_probe,
- .remove = twl4030_soc_remove,
- .suspend = twl4030_soc_suspend,
- .resume = twl4030_soc_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030);
-
MODULE_DESCRIPTION("ASoC TWL4030 codec driver");
MODULE_AUTHOR("Steve Sakoman");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h
deleted file mode 100644
index 6c57430..0000000
--- a/sound/soc/codecs/twl4030.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * ALSA SoC TWL4030 codec driver
- *
- * Author: Steve Sakoman <steve@sakoman.com>
- *
- * 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.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __TWL4030_AUDIO_H__
-#define __TWL4030_AUDIO_H__
-
-/* Register descriptions are here */
-#include <linux/mfd/twl4030-codec.h>
-
-/* Shadow register used by the audio driver */
-#define TWL4030_REG_SW_SHADOW 0x4A
-#define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1)
-
-/* TWL4030_REG_SW_SHADOW (0x4A) Fields */
-#define TWL4030_HFL_EN 0x01
-#define TWL4030_HFR_EN 0x02
-
-#define TWL4030_DAI_HIFI 0
-#define TWL4030_DAI_VOICE 1
-
-extern struct snd_soc_dai twl4030_dai[2];
-extern struct snd_soc_codec_device soc_codec_dev_twl4030;
-
-struct twl4030_setup_data {
- unsigned int ramp_delay_value;
- unsigned int digimic_delay; /* in ms */
- unsigned int sysclk;
- unsigned int offset_cncl_path;
- unsigned int check_defaults:1;
- unsigned int reset_registers:1;
- unsigned int hs_extmute:1;
- void (*set_hs_extmute)(int mute);
-};
-
-#endif /* End of __TWL4030_AUDIO_H__ */
-
-
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 64a807f..10f6e52 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -45,7 +45,6 @@
/* codec private data */
struct twl6040_data {
- struct snd_soc_codec codec;
int audpwron;
int naudint;
int codec_powered;
@@ -770,8 +769,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
if (!priv->sysclk) {
@@ -803,8 +801,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
u8 lppllctl;
int rate;
@@ -839,8 +836,7 @@
int cmd, struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
switch (cmd) {
@@ -978,8 +974,8 @@
.set_sysclk = twl6040_set_dai_sysclk,
};
-struct snd_soc_dai twl6040_dai = {
- .name = "twl6040",
+static struct snd_soc_dai_driver twl6040_dai = {
+ .name = "twl6040-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -996,24 +992,17 @@
},
.ops = &twl6040_dai_ops,
};
-EXPORT_SYMBOL_GPL(twl6040_dai);
#ifdef CONFIG_PM
-static int twl6040_suspend(struct platform_device *pdev, pm_message_t state)
+static int twl6040_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int twl6040_resume(struct platform_device *pdev)
+static int twl6040_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
@@ -1023,68 +1012,9 @@
#define twl6040_resume NULL
#endif
-static struct snd_soc_codec *twl6040_codec;
-
-static int twl6040_probe(struct platform_device *pdev)
+static int twl6040_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- BUG_ON(!twl6040_codec);
-
- codec = twl6040_codec;
- socdev->card->codec = codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to create pcms\n");
- return ret;
- }
-
- snd_soc_add_controls(codec, twl6040_snd_controls,
- ARRAY_SIZE(twl6040_snd_controls));
- twl6040_add_widgets(codec);
-
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to register card\n");
- goto card_err;
- }
-
- return ret;
-
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
- return ret;
-}
-
-static int twl6040_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
- kfree(codec);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_twl6040 = {
- .probe = twl6040_probe,
- .remove = twl6040_remove,
- .suspend = twl6040_suspend,
- .resume = twl6040_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_twl6040);
-
-static int __devinit twl6040_codec_probe(struct platform_device *pdev)
-{
- struct twl4030_codec_data *twl_codec = pdev->dev.platform_data;
- struct snd_soc_codec *codec;
+ struct twl4030_codec_data *twl_codec = codec->dev->platform_data;
struct twl6040_data *priv;
int audpwron, naudint;
int ret = 0;
@@ -1092,6 +1022,7 @@
priv = kzalloc(sizeof(struct twl6040_data), GFP_KERNEL);
if (priv == NULL)
return -ENOMEM;
+ snd_soc_codec_set_drvdata(codec, priv);
if (twl_codec) {
audpwron = twl_codec->audpwron_gpio;
@@ -1104,29 +1035,6 @@
priv->audpwron = audpwron;
priv->naudint = naudint;
- codec = &priv->codec;
- codec->dev = &pdev->dev;
- twl6040_dai.dev = &pdev->dev;
-
- codec->name = "twl6040";
- codec->owner = THIS_MODULE;
- codec->read = twl6040_read_reg_cache;
- codec->write = twl6040_write;
- codec->set_bias_level = twl6040_set_bias_level;
- snd_soc_codec_set_drvdata(codec, priv);
- codec->dai = &twl6040_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(twl6040_reg);
- codec->reg_cache = kmemdup(twl6040_reg, sizeof(twl6040_reg),
- GFP_KERNEL);
- if (codec->reg_cache == NULL) {
- ret = -ENOMEM;
- goto cache_err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
init_completion(&priv->ready);
if (gpio_is_valid(audpwron)) {
@@ -1169,23 +1077,12 @@
if (ret)
goto irq_err;
- ret = snd_soc_register_codec(codec);
- if (ret)
- goto reg_err;
-
- twl6040_codec = codec;
-
- ret = snd_soc_register_dai(&twl6040_dai);
- if (ret)
- goto dai_err;
+ snd_soc_add_controls(codec, twl6040_snd_controls,
+ ARRAY_SIZE(twl6040_snd_controls));
+ twl6040_add_widgets(codec);
return 0;
-dai_err:
- snd_soc_unregister_codec(codec);
- twl6040_codec = NULL;
-reg_err:
- twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
irq_err:
if (naudint)
free_irq(naudint, codec);
@@ -1193,36 +1090,57 @@
if (gpio_is_valid(audpwron))
gpio_free(audpwron);
gpio1_err:
- kfree(codec->reg_cache);
-cache_err:
kfree(priv);
return ret;
}
-static int __devexit twl6040_codec_remove(struct platform_device *pdev)
+static int twl6040_remove(struct snd_soc_codec *codec)
{
- struct twl6040_data *priv = snd_soc_codec_get_drvdata(twl6040_codec);
+ struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
int audpwron = priv->audpwron;
int naudint = priv->naudint;
+ twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
if (gpio_is_valid(audpwron))
gpio_free(audpwron);
if (naudint)
- free_irq(naudint, twl6040_codec);
+ free_irq(naudint, codec);
- snd_soc_unregister_dai(&twl6040_dai);
- snd_soc_unregister_codec(twl6040_codec);
+ kfree(priv);
- kfree(twl6040_codec);
- twl6040_codec = NULL;
+ return 0;
+}
+static struct snd_soc_codec_driver soc_codec_dev_twl6040 = {
+ .probe = twl6040_probe,
+ .remove = twl6040_remove,
+ .suspend = twl6040_suspend,
+ .resume = twl6040_resume,
+ .read = twl6040_read_reg_cache,
+ .write = twl6040_write,
+ .set_bias_level = twl6040_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(twl6040_reg),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = twl6040_reg,
+};
+
+static int __devinit twl6040_codec_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_twl6040, &twl6040_dai, 1);
+}
+
+static int __devexit twl6040_codec_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
return 0;
}
static struct platform_driver twl6040_codec_driver = {
.driver = {
- .name = "twl6040_codec",
+ .name = "twl6040-codec",
.owner = THIS_MODULE,
},
.probe = twl6040_codec_probe,
diff --git a/sound/soc/codecs/twl6040.h b/sound/soc/codecs/twl6040.h
index c472070..f7c77fa 100644
--- a/sound/soc/codecs/twl6040.h
+++ b/sound/soc/codecs/twl6040.h
@@ -135,7 +135,4 @@
#define TWL6040_HPPLL_ID 1
#define TWL6040_LPPLL_ID 2
-extern struct snd_soc_dai twl6040_dai;
-extern struct snd_soc_codec_device soc_codec_dev_twl6040;
-
#endif /* End of __TWL6040_H__ */
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
index f3b4c1d..7540a50 100644
--- a/sound/soc/codecs/uda134x.c
+++ b/sound/soc/codecs/uda134x.c
@@ -161,8 +161,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec =rtd->codec;
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
struct snd_pcm_runtime *master_runtime;
@@ -194,8 +193,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
if (uda134x->master_substream == substream)
@@ -209,8 +207,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
u8 hw_params;
@@ -364,7 +361,7 @@
pd->power(1);
/* Sync reg_cache with the hardware */
for (i = 0; i < ARRAY_SIZE(uda134x_reg); i++)
- codec->write(codec, i, *cache++);
+ codec->driver->write(codec, i, *cache++);
}
break;
case SND_SOC_BIAS_STANDBY:
@@ -465,8 +462,8 @@
.set_fmt = uda134x_set_dai_fmt,
};
-struct snd_soc_dai uda134x_dai = {
- .name = "UDA134X",
+static struct snd_soc_dai_driver uda134x_dai = {
+ .name = "uda134x-hifi",
/* playback capabilities */
.playback = {
.stream_name = "Playback",
@@ -486,27 +483,21 @@
/* pcm operations */
.ops = &uda134x_dai_ops,
};
-EXPORT_SYMBOL(uda134x_dai);
-
-static int uda134x_soc_probe(struct platform_device *pdev)
+static int uda134x_soc_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
struct uda134x_priv *uda134x;
- void *codec_setup_data = socdev->codec_data;
- int ret = -ENOMEM;
- struct uda134x_platform_data *pd;
+ struct uda134x_platform_data *pd = dev_get_drvdata(codec->card->dev);
+ int ret;
printk(KERN_INFO "UDA134X SoC Audio Codec\n");
- if (!codec_setup_data) {
+ if (!pd) {
printk(KERN_ERR "UDA134X SoC codec: "
"missing L3 bitbang function\n");
return -ENODEV;
}
- pd = codec_setup_data;
switch (pd->model) {
case UDA134X_UDA1340:
case UDA134X_UDA1341:
@@ -520,58 +511,22 @@
return -EINVAL;
}
- socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (socdev->card->codec == NULL)
- return ret;
-
- codec = socdev->card->codec;
-
uda134x = kzalloc(sizeof(struct uda134x_priv), GFP_KERNEL);
if (uda134x == NULL)
- goto priv_err;
+ return -ENOMEM;
snd_soc_codec_set_drvdata(codec, uda134x);
- codec->reg_cache = kmemdup(uda134x_reg, sizeof(uda134x_reg),
- GFP_KERNEL);
- if (codec->reg_cache == NULL)
- goto reg_err;
-
- mutex_init(&codec->mutex);
-
- codec->reg_cache_size = sizeof(uda134x_reg);
- codec->reg_cache_step = 1;
-
- codec->name = "UDA134X";
- codec->owner = THIS_MODULE;
- codec->dai = &uda134x_dai;
- codec->num_dai = 1;
- codec->read = uda134x_read_reg_cache;
- codec->write = uda134x_write;
-
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->control_data = codec_setup_data;
+ codec->control_data = pd;
if (pd->power)
pd->power(1);
uda134x_reset(codec);
- if (pd->is_powered_on_standby) {
- codec->set_bias_level = NULL;
+ if (pd->is_powered_on_standby)
uda134x_set_bias_level(codec, SND_SOC_BIAS_ON);
- } else {
- codec->set_bias_level = uda134x_set_bias_level;
+ else
uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- }
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "UDA134X: failed to register pcms\n");
- goto pcm_err;
- }
switch (pd->model) {
case UDA134X_UDA1340:
@@ -590,61 +545,42 @@
default:
printk(KERN_ERR "%s unknown codec type: %d",
__func__, pd->model);
- return -EINVAL;
+ kfree(uda134x);
+ return -EINVAL;
}
if (ret < 0) {
printk(KERN_ERR "UDA134X: failed to register controls\n");
- goto pcm_err;
+ kfree(uda134x);
+ return ret;
}
return 0;
-
-pcm_err:
- kfree(codec->reg_cache);
-reg_err:
- kfree(snd_soc_codec_get_drvdata(codec));
-priv_err:
- kfree(codec);
- return ret;
}
/* power down chip */
-static int uda134x_soc_remove(struct platform_device *pdev)
+static int uda134x_soc_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- kfree(snd_soc_codec_get_drvdata(codec));
- kfree(codec->reg_cache);
- kfree(codec);
-
+ kfree(uda134x);
return 0;
}
#if defined(CONFIG_PM)
-static int uda134x_soc_suspend(struct platform_device *pdev,
+static int uda134x_soc_suspend(struct snd_soc_codec *codec,
pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int uda134x_soc_resume(struct platform_device *pdev)
+static int uda134x_soc_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
uda134x_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
uda134x_set_bias_level(codec, SND_SOC_BIAS_ON);
return 0;
@@ -654,25 +590,53 @@
#define uda134x_soc_resume NULL
#endif /* CONFIG_PM */
-struct snd_soc_codec_device soc_codec_dev_uda134x = {
+static struct snd_soc_codec_driver soc_codec_dev_uda134x = {
.probe = uda134x_soc_probe,
.remove = uda134x_soc_remove,
.suspend = uda134x_soc_suspend,
.resume = uda134x_soc_resume,
+ .reg_cache_size = sizeof(uda134x_reg),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_step = 1,
+ .read = uda134x_read_reg_cache,
+ .write = uda134x_write,
+#ifdef POWER_OFF_ON_STANDBY
+ .set_bias_level = uda134x_set_bias_level,
+#endif
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_uda134x);
-static int __init uda134x_init(void)
+static int __devinit uda134x_codec_probe(struct platform_device *pdev)
{
- return snd_soc_register_dai(&uda134x_dai);
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_uda134x, &uda134x_dai, 1);
}
-module_init(uda134x_init);
-static void __exit uda134x_exit(void)
+static int __devexit uda134x_codec_remove(struct platform_device *pdev)
{
- snd_soc_unregister_dai(&uda134x_dai);
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
}
-module_exit(uda134x_exit);
+
+static struct platform_driver uda134x_codec_driver = {
+ .driver = {
+ .name = "uda134x-codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = uda134x_codec_probe,
+ .remove = __devexit_p(uda134x_codec_remove),
+};
+
+static int __init uda134x_codec_init(void)
+{
+ return platform_driver_register(&uda134x_codec_driver);
+}
+module_init(uda134x_codec_init);
+
+static void __exit uda134x_codec_exit(void)
+{
+ platform_driver_unregister(&uda134x_codec_driver);
+}
+module_exit(uda134x_codec_exit);
MODULE_DESCRIPTION("UDA134X ALSA soc codec driver");
MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
diff --git a/sound/soc/codecs/uda134x.h b/sound/soc/codecs/uda134x.h
index 205f03b..9faae06 100644
--- a/sound/soc/codecs/uda134x.h
+++ b/sound/soc/codecs/uda134x.h
@@ -31,7 +31,4 @@
#define STATUS0_DAIFMT_MASK (~(7<<1))
#define STATUS0_SYSCLK_MASK (~(3<<4))
-extern struct snd_soc_dai uda134x_dai;
-extern struct snd_soc_codec_device soc_codec_dev_uda134x;
-
#endif
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index 2f925a2..0c6c725 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -33,14 +33,13 @@
#include "uda1380.h"
-static struct snd_soc_codec *uda1380_codec;
-
/* codec private data */
struct uda1380_priv {
- struct snd_soc_codec codec;
+ struct snd_soc_codec *codec;
u16 reg_cache[UDA1380_CACHEREGNUM];
unsigned int dac_clk;
struct work_struct work;
+ void *control_data;
};
/*
@@ -131,10 +130,51 @@
return -EIO;
}
-#define uda1380_reset(c) uda1380_write(c, UDA1380_RESET, 0)
+static void uda1380_sync_cache(struct snd_soc_codec *codec)
+{
+ int reg;
+ u8 data[3];
+ u16 *cache = codec->reg_cache;
+
+ /* Sync reg_cache with the hardware */
+ for (reg = 0; reg < UDA1380_MVOL; reg++) {
+ data[0] = reg;
+ data[1] = (cache[reg] & 0xff00) >> 8;
+ data[2] = cache[reg] & 0x00ff;
+ if (codec->hw_write(codec->control_data, data, 3) != 3)
+ dev_err(codec->dev, "%s: write to reg 0x%x failed\n",
+ __func__, reg);
+ }
+}
+
+static int uda1380_reset(struct snd_soc_codec *codec)
+{
+ struct uda1380_platform_data *pdata = codec->dev->platform_data;
+
+ if (gpio_is_valid(pdata->gpio_reset)) {
+ gpio_set_value(pdata->gpio_reset, 1);
+ mdelay(1);
+ gpio_set_value(pdata->gpio_reset, 0);
+ } else {
+ u8 data[3];
+
+ data[0] = UDA1380_RESET;
+ data[1] = 0;
+ data[2] = 0;
+
+ if (codec->hw_write(codec->control_data, data, 3) != 3) {
+ dev_err(codec->dev, "%s: failed\n", __func__);
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
static void uda1380_flush_work(struct work_struct *work)
{
+ struct uda1380_priv *uda1380 = container_of(work, struct uda1380_priv, work);
+ struct snd_soc_codec *uda1380_codec = uda1380->codec;
int bit, reg;
for_each_set_bit(bit, &uda1380_cache_dirty, UDA1380_CACHEREGNUM - 0x10) {
@@ -145,6 +185,7 @@
uda1380_read_reg_cache(uda1380_codec, reg));
clear_bit(bit, &uda1380_cache_dirty);
}
+
}
/* declarations of ALSA reg_elem_REAL controls */
@@ -474,8 +515,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
int mixer = uda1380_read_reg_cache(codec, UDA1380_MIXER);
@@ -501,8 +541,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
/* set WSPLL power and divider if running from this clock */
@@ -540,8 +579,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
/* shut down WSPLL power if running from this clock */
@@ -562,18 +600,41 @@
enum snd_soc_bias_level level)
{
int pm = uda1380_read_reg_cache(codec, UDA1380_PM);
+ int reg;
+ struct uda1380_platform_data *pdata = codec->dev->platform_data;
+
+ if (codec->bias_level == level)
+ return 0;
switch (level) {
case SND_SOC_BIAS_ON:
case SND_SOC_BIAS_PREPARE:
+ /* ADC, DAC on */
uda1380_write(codec, UDA1380_PM, R02_PON_BIAS | pm);
break;
case SND_SOC_BIAS_STANDBY:
- uda1380_write(codec, UDA1380_PM, R02_PON_BIAS);
- break;
- case SND_SOC_BIAS_OFF:
+ if (codec->bias_level == SND_SOC_BIAS_OFF) {
+ if (gpio_is_valid(pdata->gpio_power)) {
+ gpio_set_value(pdata->gpio_power, 1);
+ mdelay(1);
+ uda1380_reset(codec);
+ }
+
+ uda1380_sync_cache(codec);
+ }
uda1380_write(codec, UDA1380_PM, 0x0);
break;
+ case SND_SOC_BIAS_OFF:
+ if (!gpio_is_valid(pdata->gpio_power))
+ break;
+
+ gpio_set_value(pdata->gpio_power, 0);
+
+ /* Mark mixer regs cache dirty to sync them with
+ * codec regs on power on.
+ */
+ for (reg = UDA1380_MVOL; reg < UDA1380_CACHEREGNUM; reg++)
+ set_bit(reg - 0x10, &uda1380_cache_dirty);
}
codec->bias_level = level;
return 0;
@@ -604,9 +665,9 @@
.set_fmt = uda1380_set_dai_fmt_capture,
};
-struct snd_soc_dai uda1380_dai[] = {
+static struct snd_soc_dai_driver uda1380_dai[] = {
{
- .name = "UDA1380",
+ .name = "uda1380-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -622,7 +683,7 @@
.ops = &uda1380_dai_ops,
},
{ /* playback only - dual interface */
- .name = "UDA1380",
+ .name = "uda1380-hifi-playback",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -633,7 +694,7 @@
.ops = &uda1380_dai_ops_playback,
},
{ /* capture only - dual interface*/
- .name = "UDA1380",
+ .name = "uda1380-hifi-capture",
.capture = {
.stream_name = "Capture",
.channels_min = 1,
@@ -644,67 +705,69 @@
.ops = &uda1380_dai_ops_capture,
},
};
-EXPORT_SYMBOL_GPL(uda1380_dai);
-static int uda1380_suspend(struct platform_device *pdev, pm_message_t state)
+static int uda1380_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int uda1380_resume(struct platform_device *pdev)
+static int uda1380_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
- int i;
- u8 data[2];
- u16 *cache = codec->reg_cache;
-
- /* Sync reg_cache with the hardware */
- for (i = 0; i < ARRAY_SIZE(uda1380_reg); i++) {
- data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
- data[1] = cache[i] & 0x00ff;
- codec->hw_write(codec->control_data, data, 2);
- }
uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
-static int uda1380_probe(struct platform_device *pdev)
+static int uda1380_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- struct uda1380_platform_data *pdata;
- int ret = 0;
+ struct uda1380_platform_data *pdata =codec->dev->platform_data;
+ struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
+ int ret;
- if (uda1380_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
+ uda1380->codec = codec;
+
+ codec->hw_write = (hw_write_t)i2c_master_send;
+ codec->control_data = uda1380->control_data;
+
+ if (!pdata)
+ return -EINVAL;
+
+ if (gpio_is_valid(pdata->gpio_reset)) {
+ ret = gpio_request(pdata->gpio_reset, "uda1380 reset");
+ if (ret)
+ goto err_out;
+ ret = gpio_direction_output(pdata->gpio_reset, 0);
+ if (ret)
+ goto err_gpio_reset_conf;
}
- socdev->card->codec = uda1380_codec;
- codec = uda1380_codec;
- pdata = codec->dev->platform_data;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
+ if (gpio_is_valid(pdata->gpio_power)) {
+ ret = gpio_request(pdata->gpio_power, "uda1380 power");
+ if (ret)
+ goto err_gpio;
+ ret = gpio_direction_output(pdata->gpio_power, 0);
+ if (ret)
+ goto err_gpio_power_conf;
+ } else {
+ ret = uda1380_reset(codec);
+ if (ret) {
+ dev_err(codec->dev, "Failed to issue reset\n");
+ goto err_reset;
+ }
}
+ INIT_WORK(&uda1380->work, uda1380_flush_work);
+
/* power on device */
uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* set clock input */
switch (pdata->dac_clk) {
case UDA1380_DAC_CLK_SYSCLK:
- uda1380_write(codec, UDA1380_CLK, 0);
+ uda1380_write_reg_cache(codec, UDA1380_CLK, 0);
break;
case UDA1380_DAC_CLK_WSPLL:
- uda1380_write(codec, UDA1380_CLK, R00_DAC_CLK);
+ uda1380_write_reg_cache(codec, UDA1380_CLK,
+ R00_DAC_CLK);
break;
}
@@ -712,167 +775,73 @@
ARRAY_SIZE(uda1380_snd_controls));
uda1380_add_widgets(codec);
- return ret;
-
-pcm_err:
- return ret;
-}
-
-/* power down chip */
-static int uda1380_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec->control_data)
- uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_uda1380 = {
- .probe = uda1380_probe,
- .remove = uda1380_remove,
- .suspend = uda1380_suspend,
- .resume = uda1380_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380);
-
-static int uda1380_register(struct uda1380_priv *uda1380)
-{
- int ret, i;
- struct snd_soc_codec *codec = &uda1380->codec;
- struct uda1380_platform_data *pdata = codec->dev->platform_data;
-
- if (uda1380_codec) {
- dev_err(codec->dev, "Another UDA1380 is registered\n");
- return -EINVAL;
- }
-
- if (!pdata || !pdata->gpio_power || !pdata->gpio_reset)
- return -EINVAL;
-
- ret = gpio_request(pdata->gpio_power, "uda1380 power");
- if (ret)
- goto err_out;
- ret = gpio_request(pdata->gpio_reset, "uda1380 reset");
- if (ret)
- goto err_gpio;
-
- gpio_direction_output(pdata->gpio_power, 1);
-
- /* we may need to have the clock running here - pH5 */
- gpio_direction_output(pdata->gpio_reset, 1);
- udelay(5);
- gpio_set_value(pdata->gpio_reset, 0);
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, uda1380);
- codec->name = "UDA1380";
- codec->owner = THIS_MODULE;
- codec->read = uda1380_read_reg_cache;
- codec->write = uda1380_write;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = uda1380_set_bias_level;
- codec->dai = uda1380_dai;
- codec->num_dai = ARRAY_SIZE(uda1380_dai);
- codec->reg_cache_size = ARRAY_SIZE(uda1380_reg);
- codec->reg_cache = &uda1380->reg_cache;
- codec->reg_cache_step = 1;
-
- memcpy(codec->reg_cache, uda1380_reg, sizeof(uda1380_reg));
-
- ret = uda1380_reset(codec);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to issue reset\n");
- goto err_reset;
- }
-
- INIT_WORK(&uda1380->work, uda1380_flush_work);
-
- for (i = 0; i < ARRAY_SIZE(uda1380_dai); i++)
- uda1380_dai[i].dev = codec->dev;
-
- uda1380_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err_reset;
- }
-
- ret = snd_soc_register_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai));
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
- goto err_dai;
- }
-
return 0;
-err_dai:
- snd_soc_unregister_codec(codec);
err_reset:
- gpio_set_value(pdata->gpio_power, 0);
- gpio_free(pdata->gpio_reset);
+err_gpio_power_conf:
+ if (gpio_is_valid(pdata->gpio_power))
+ gpio_free(pdata->gpio_power);
+
+err_gpio_reset_conf:
err_gpio:
- gpio_free(pdata->gpio_power);
+ if (gpio_is_valid(pdata->gpio_reset))
+ gpio_free(pdata->gpio_reset);
err_out:
return ret;
}
-static void uda1380_unregister(struct uda1380_priv *uda1380)
+/* power down chip */
+static int uda1380_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = &uda1380->codec;
- struct uda1380_platform_data *pdata = codec->dev->platform_data;
+ struct uda1380_platform_data *pdata =codec->dev->platform_data;
- snd_soc_unregister_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai));
- snd_soc_unregister_codec(&uda1380->codec);
+ uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
- gpio_set_value(pdata->gpio_power, 0);
gpio_free(pdata->gpio_reset);
gpio_free(pdata->gpio_power);
- kfree(uda1380);
- uda1380_codec = NULL;
+ return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_uda1380 = {
+ .probe = uda1380_probe,
+ .remove = uda1380_remove,
+ .suspend = uda1380_suspend,
+ .resume = uda1380_resume,
+ .read = uda1380_read_reg_cache,
+ .write = uda1380_write,
+ .set_bias_level = uda1380_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(uda1380_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = uda1380_reg,
+ .reg_cache_step = 1,
+};
+
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static __devinit int uda1380_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct uda1380_priv *uda1380;
- struct snd_soc_codec *codec;
int ret;
uda1380 = kzalloc(sizeof(struct uda1380_priv), GFP_KERNEL);
if (uda1380 == NULL)
return -ENOMEM;
- codec = &uda1380->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
-
i2c_set_clientdata(i2c, uda1380);
- codec->control_data = i2c;
+ uda1380->control_data = i2c;
- codec->dev = &i2c->dev;
-
- ret = uda1380_register(uda1380);
- if (ret != 0)
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_uda1380, uda1380_dai, ARRAY_SIZE(uda1380_dai));
+ if (ret < 0)
kfree(uda1380);
-
return ret;
}
static int __devexit uda1380_i2c_remove(struct i2c_client *i2c)
{
- struct uda1380_priv *uda1380 = i2c_get_clientdata(i2c);
- uda1380_unregister(uda1380);
+ snd_soc_unregister_codec(&i2c->dev);
+ kfree(i2c_get_clientdata(i2c));
return 0;
}
@@ -884,7 +853,7 @@
static struct i2c_driver uda1380_i2c_driver = {
.driver = {
- .name = "UDA1380 I2C Codec",
+ .name = "uda1380-codec",
.owner = THIS_MODULE,
},
.probe = uda1380_i2c_probe,
diff --git a/sound/soc/codecs/uda1380.h b/sound/soc/codecs/uda1380.h
index 9cefa8a..942e392 100644
--- a/sound/soc/codecs/uda1380.h
+++ b/sound/soc/codecs/uda1380.h
@@ -76,7 +76,4 @@
#define UDA1380_DAI_PLAYBACK 1 /* playback DAI */
#define UDA1380_DAI_CAPTURE 2 /* capture DAI */
-extern struct snd_soc_dai uda1380_dai[3];
-extern struct snd_soc_codec_device soc_codec_dev_uda1380;
-
#endif /* _UDA1380_H */
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c
new file mode 100644
index 0000000..0c47c78
--- /dev/null
+++ b/sound/soc/codecs/wl1273.c
@@ -0,0 +1,528 @@
+/*
+ * ALSA SoC WL1273 codec driver
+ *
+ * Author: Matti Aaltonen, <matti.j.aaltonen@nokia.com>
+ *
+ * Copyright: (C) 2010 Nokia Corporation
+ *
+ * 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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/mfd/wl1273-core.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dai.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "wl1273.h"
+
+enum wl1273_mode { WL1273_MODE_BT, WL1273_MODE_FM_RX, WL1273_MODE_FM_TX };
+
+/* codec private data */
+struct wl1273_priv {
+ enum wl1273_mode mode;
+ struct wl1273_core *core;
+ unsigned int channels;
+};
+
+static int snd_wl1273_fm_set_i2s_mode(struct wl1273_core *core,
+ int rate, int width)
+{
+ struct device *dev = &core->i2c_dev->dev;
+ int r = 0;
+ u16 mode;
+
+ dev_dbg(dev, "rate: %d\n", rate);
+ dev_dbg(dev, "width: %d\n", width);
+
+ mutex_lock(&core->lock);
+
+ mode = core->i2s_mode & ~WL1273_IS2_WIDTH & ~WL1273_IS2_RATE;
+
+ switch (rate) {
+ case 48000:
+ mode |= WL1273_IS2_RATE_48K;
+ break;
+ case 44100:
+ mode |= WL1273_IS2_RATE_44_1K;
+ break;
+ case 32000:
+ mode |= WL1273_IS2_RATE_32K;
+ break;
+ case 22050:
+ mode |= WL1273_IS2_RATE_22_05K;
+ break;
+ case 16000:
+ mode |= WL1273_IS2_RATE_16K;
+ break;
+ case 12000:
+ mode |= WL1273_IS2_RATE_12K;
+ break;
+ case 11025:
+ mode |= WL1273_IS2_RATE_11_025;
+ break;
+ case 8000:
+ mode |= WL1273_IS2_RATE_8K;
+ break;
+ default:
+ dev_err(dev, "Sampling rate: %d not supported\n", rate);
+ r = -EINVAL;
+ goto out;
+ }
+
+ switch (width) {
+ case 16:
+ mode |= WL1273_IS2_WIDTH_32;
+ break;
+ case 20:
+ mode |= WL1273_IS2_WIDTH_40;
+ break;
+ case 24:
+ mode |= WL1273_IS2_WIDTH_48;
+ break;
+ case 25:
+ mode |= WL1273_IS2_WIDTH_50;
+ break;
+ case 30:
+ mode |= WL1273_IS2_WIDTH_60;
+ break;
+ case 32:
+ mode |= WL1273_IS2_WIDTH_64;
+ break;
+ case 40:
+ mode |= WL1273_IS2_WIDTH_80;
+ break;
+ case 48:
+ mode |= WL1273_IS2_WIDTH_96;
+ break;
+ case 64:
+ mode |= WL1273_IS2_WIDTH_128;
+ break;
+ default:
+ dev_err(dev, "Data width: %d not supported\n", width);
+ r = -EINVAL;
+ goto out;
+ }
+
+ dev_dbg(dev, "WL1273_I2S_DEF_MODE: 0x%04x\n", WL1273_I2S_DEF_MODE);
+ dev_dbg(dev, "core->i2s_mode: 0x%04x\n", core->i2s_mode);
+ dev_dbg(dev, "mode: 0x%04x\n", mode);
+
+ if (core->i2s_mode != mode) {
+ r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET, mode);
+ if (r)
+ goto out;
+
+ core->i2s_mode = mode;
+ r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE,
+ WL1273_AUDIO_ENABLE_I2S);
+ if (r)
+ goto out;
+ }
+out:
+ mutex_unlock(&core->lock);
+
+ return r;
+}
+
+static int snd_wl1273_fm_set_channel_number(struct wl1273_core *core,
+ int channel_number)
+{
+ struct i2c_client *client = core->i2c_dev;
+ struct device *dev = &client->dev;
+ int r = 0;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ mutex_lock(&core->lock);
+
+ if (core->channel_number == channel_number)
+ goto out;
+
+ if (channel_number == 1 && core->mode == WL1273_MODE_RX)
+ r = wl1273_fm_write_cmd(core, WL1273_MOST_MODE_SET,
+ WL1273_RX_MONO);
+ else if (channel_number == 1 && core->mode == WL1273_MODE_TX)
+ r = wl1273_fm_write_cmd(core, WL1273_MONO_SET,
+ WL1273_TX_MONO);
+ else if (channel_number == 2 && core->mode == WL1273_MODE_RX)
+ r = wl1273_fm_write_cmd(core, WL1273_MOST_MODE_SET,
+ WL1273_RX_STEREO);
+ else if (channel_number == 2 && core->mode == WL1273_MODE_TX)
+ r = wl1273_fm_write_cmd(core, WL1273_MONO_SET,
+ WL1273_TX_STEREO);
+ else
+ r = -EINVAL;
+out:
+ mutex_unlock(&core->lock);
+
+ return r;
+}
+
+static int snd_wl1273_get_audio_route(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = wl1273->mode;
+
+ return 0;
+}
+
+static const char *wl1273_audio_route[] = { "Bt", "FmRx", "FmTx" };
+
+static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+
+ if (wl1273->mode == ucontrol->value.integer.value[0])
+ return 0;
+
+ /* Do not allow changes while stream is running */
+ if (codec->active)
+ return -EPERM;
+
+ if (ucontrol->value.integer.value[0] < 0 ||
+ ucontrol->value.integer.value[0] >= ARRAY_SIZE(wl1273_audio_route))
+ return -EINVAL;
+
+ wl1273->mode = ucontrol->value.integer.value[0];
+
+ return 1;
+}
+
+static const struct soc_enum wl1273_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wl1273_audio_route), wl1273_audio_route);
+
+static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s: enter.\n", __func__);
+
+ ucontrol->value.integer.value[0] = wl1273->core->audio_mode;
+
+ return 0;
+}
+
+static int snd_wl1273_fm_audio_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+ int val, r = 0;
+
+ dev_dbg(codec->dev, "%s: enter.\n", __func__);
+
+ val = ucontrol->value.integer.value[0];
+ if (wl1273->core->audio_mode == val)
+ return 0;
+
+ r = wl1273_fm_set_audio(wl1273->core, val);
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
+static const char *wl1273_audio_strings[] = { "Digital", "Analog" };
+
+static const struct soc_enum wl1273_audio_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wl1273_audio_strings),
+ wl1273_audio_strings);
+
+static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s: enter.\n", __func__);
+
+ ucontrol->value.integer.value[0] = wl1273->core->volume;
+
+ return 0;
+}
+
+static int snd_wl1273_fm_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+ int r;
+
+ dev_dbg(codec->dev, "%s: enter.\n", __func__);
+
+ r = wl1273_fm_set_volume(wl1273->core,
+ ucontrol->value.integer.value[0]);
+ if (r)
+ return r;
+
+ return 1;
+}
+
+static const struct snd_kcontrol_new wl1273_controls[] = {
+ SOC_ENUM_EXT("Codec Mode", wl1273_enum,
+ snd_wl1273_get_audio_route, snd_wl1273_set_audio_route),
+ SOC_ENUM_EXT("Audio Switch", wl1273_audio_enum,
+ snd_wl1273_fm_audio_get, snd_wl1273_fm_audio_put),
+ SOC_SINGLE_EXT("Volume", 0, 0, WL1273_MAX_VOLUME, 0,
+ snd_wl1273_fm_volume_get, snd_wl1273_fm_volume_put),
+};
+
+static int wl1273_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+
+ switch (wl1273->mode) {
+ case WL1273_MODE_BT:
+ snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_RATE,
+ 8000, 8000);
+ snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_CHANNELS, 1, 1);
+ break;
+ case WL1273_MODE_FM_RX:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ pr_err("Cannot play in RX mode.\n");
+ return -EINVAL;
+ }
+ break;
+ case WL1273_MODE_FM_TX:
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ pr_err("Cannot capture in TX mode.\n");
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+static int wl1273_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(rtd->codec);
+ struct wl1273_core *core = wl1273->core;
+ unsigned int rate, width, r;
+
+ if (params_format(params) != SNDRV_PCM_FORMAT_S16_LE) {
+ pr_err("Only SNDRV_PCM_FORMAT_S16_LE supported.\n");
+ return -EINVAL;
+ }
+
+ rate = params_rate(params);
+ width = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min;
+
+ if (wl1273->mode == WL1273_MODE_BT) {
+ if (rate != 8000) {
+ pr_err("Rate %d not supported.\n", params_rate(params));
+ return -EINVAL;
+ }
+
+ if (params_channels(params) != 1) {
+ pr_err("Only mono supported.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+ }
+
+ if (wl1273->mode == WL1273_MODE_FM_TX &&
+ substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ pr_err("Only playback supported with TX.\n");
+ return -EINVAL;
+ }
+
+ if (wl1273->mode == WL1273_MODE_FM_RX &&
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ pr_err("Only capture supported with RX.\n");
+ return -EINVAL;
+ }
+
+ if (wl1273->mode != WL1273_MODE_FM_RX &&
+ wl1273->mode != WL1273_MODE_FM_TX) {
+ pr_err("Unexpected mode: %d.\n", wl1273->mode);
+ return -EINVAL;
+ }
+
+ r = snd_wl1273_fm_set_i2s_mode(core, rate, width);
+ if (r)
+ return r;
+
+ wl1273->channels = params_channels(params);
+ r = snd_wl1273_fm_set_channel_number(core, wl1273->channels);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops wl1273_dai_ops = {
+ .startup = wl1273_startup,
+ .hw_params = wl1273_hw_params,
+};
+
+static struct snd_soc_dai_driver wl1273_dai = {
+ .name = "wl1273-fm",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE},
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE},
+ .ops = &wl1273_dai_ops,
+};
+
+/* Audio interface format for the soc_card driver */
+int wl1273_get_format(struct snd_soc_codec *codec, unsigned int *fmt)
+{
+ struct wl1273_priv *wl1273;
+
+ if (codec == NULL || fmt == NULL)
+ return -EINVAL;
+
+ wl1273 = snd_soc_codec_get_drvdata(codec);
+
+ switch (wl1273->mode) {
+ case WL1273_MODE_FM_RX:
+ case WL1273_MODE_FM_TX:
+ *fmt = SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM;
+
+ break;
+ case WL1273_MODE_BT:
+ *fmt = SND_SOC_DAIFMT_DSP_A |
+ SND_SOC_DAIFMT_IB_NF |
+ SND_SOC_DAIFMT_CBM_CFM;
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wl1273_get_format);
+
+static int wl1273_probe(struct snd_soc_codec *codec)
+{
+ struct wl1273_core **core = codec->dev->platform_data;
+ struct wl1273_priv *wl1273;
+ int r;
+
+ dev_dbg(codec->dev, "%s.\n", __func__);
+
+ if (!core) {
+ dev_err(codec->dev, "Platform data is missing.\n");
+ return -EINVAL;
+ }
+
+ wl1273 = kzalloc(sizeof(struct wl1273_priv), GFP_KERNEL);
+ if (wl1273 == NULL) {
+ dev_err(codec->dev, "Cannot allocate memory.\n");
+ return -ENOMEM;
+ }
+
+ wl1273->mode = WL1273_MODE_BT;
+ wl1273->core = *core;
+
+ snd_soc_codec_set_drvdata(codec, wl1273);
+ mutex_init(&codec->mutex);
+
+ r = snd_soc_add_controls(codec, wl1273_controls,
+ ARRAY_SIZE(wl1273_controls));
+ if (r)
+ kfree(wl1273);
+
+ return r;
+}
+
+static int wl1273_remove(struct snd_soc_codec *codec)
+{
+ struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s\n", __func__);
+ kfree(wl1273);
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wl1273 = {
+ .probe = wl1273_probe,
+ .remove = wl1273_remove,
+};
+
+static int __devinit wl1273_platform_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wl1273,
+ &wl1273_dai, 1);
+}
+
+static int __devexit wl1273_platform_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+MODULE_ALIAS("platform:wl1273-codec");
+
+static struct platform_driver wl1273_platform_driver = {
+ .driver = {
+ .name = "wl1273-codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = wl1273_platform_probe,
+ .remove = __devexit_p(wl1273_platform_remove),
+};
+
+static int __init wl1273_init(void)
+{
+ return platform_driver_register(&wl1273_platform_driver);
+}
+module_init(wl1273_init);
+
+static void __exit wl1273_exit(void)
+{
+ platform_driver_unregister(&wl1273_platform_driver);
+}
+module_exit(wl1273_exit);
+
+MODULE_AUTHOR("Matti Aaltonen <matti.j.aaltonen@nokia.com>");
+MODULE_DESCRIPTION("ASoC WL1273 codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wl1273.h b/sound/soc/codecs/wl1273.h
new file mode 100644
index 0000000..14ed027
--- /dev/null
+++ b/sound/soc/codecs/wl1273.h
@@ -0,0 +1,101 @@
+/*
+ * sound/soc/codec/wl1273.h
+ *
+ * ALSA SoC WL1273 codec driver
+ *
+ * Copyright (C) Nokia Corporation
+ * Author: Matti Aaltonen <matti.j.aaltonen@nokia.com>
+ *
+ * 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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1273_CODEC_H__
+#define __WL1273_CODEC_H__
+
+/* I2S protocol, left channel first, data width 16 bits */
+#define WL1273_PCM_DEF_MODE 0x00
+
+/* Rx */
+#define WL1273_AUDIO_ENABLE_I2S (1 << 0)
+#define WL1273_AUDIO_ENABLE_ANALOG (1 << 1)
+
+/* Tx */
+#define WL1273_AUDIO_IO_SET_ANALOG 0
+#define WL1273_AUDIO_IO_SET_I2S 1
+
+#define WL1273_POWER_SET_OFF 0
+#define WL1273_POWER_SET_FM (1 << 0)
+#define WL1273_POWER_SET_RDS (1 << 1)
+#define WL1273_POWER_SET_RETENTION (1 << 4)
+
+#define WL1273_PUPD_SET_OFF 0x00
+#define WL1273_PUPD_SET_ON 0x01
+#define WL1273_PUPD_SET_RETENTION 0x10
+
+/* I2S mode */
+#define WL1273_IS2_WIDTH_32 0x0
+#define WL1273_IS2_WIDTH_40 0x1
+#define WL1273_IS2_WIDTH_22_23 0x2
+#define WL1273_IS2_WIDTH_23_22 0x3
+#define WL1273_IS2_WIDTH_48 0x4
+#define WL1273_IS2_WIDTH_50 0x5
+#define WL1273_IS2_WIDTH_60 0x6
+#define WL1273_IS2_WIDTH_64 0x7
+#define WL1273_IS2_WIDTH_80 0x8
+#define WL1273_IS2_WIDTH_96 0x9
+#define WL1273_IS2_WIDTH_128 0xa
+#define WL1273_IS2_WIDTH 0xf
+
+#define WL1273_IS2_FORMAT_STD (0x0 << 4)
+#define WL1273_IS2_FORMAT_LEFT (0x1 << 4)
+#define WL1273_IS2_FORMAT_RIGHT (0x2 << 4)
+#define WL1273_IS2_FORMAT_USER (0x3 << 4)
+
+#define WL1273_IS2_MASTER (0x0 << 6)
+#define WL1273_IS2_SLAVEW (0x1 << 6)
+
+#define WL1273_IS2_TRI_AFTER_SENDING (0x0 << 7)
+#define WL1273_IS2_TRI_ALWAYS_ACTIVE (0x1 << 7)
+
+#define WL1273_IS2_SDOWS_RR (0x0 << 8)
+#define WL1273_IS2_SDOWS_RF (0x1 << 8)
+#define WL1273_IS2_SDOWS_FR (0x2 << 8)
+#define WL1273_IS2_SDOWS_FF (0x3 << 8)
+
+#define WL1273_IS2_TRI_OPT (0x0 << 10)
+#define WL1273_IS2_TRI_ALWAYS (0x1 << 10)
+
+#define WL1273_IS2_RATE_48K (0x0 << 12)
+#define WL1273_IS2_RATE_44_1K (0x1 << 12)
+#define WL1273_IS2_RATE_32K (0x2 << 12)
+#define WL1273_IS2_RATE_22_05K (0x4 << 12)
+#define WL1273_IS2_RATE_16K (0x5 << 12)
+#define WL1273_IS2_RATE_12K (0x8 << 12)
+#define WL1273_IS2_RATE_11_025 (0x9 << 12)
+#define WL1273_IS2_RATE_8K (0xa << 12)
+#define WL1273_IS2_RATE (0xf << 12)
+
+#define WL1273_I2S_DEF_MODE (WL1273_IS2_WIDTH_32 | \
+ WL1273_IS2_FORMAT_STD | \
+ WL1273_IS2_MASTER | \
+ WL1273_IS2_TRI_AFTER_SENDING | \
+ WL1273_IS2_SDOWS_RR | \
+ WL1273_IS2_TRI_OPT | \
+ WL1273_IS2_RATE_48K)
+
+int wl1273_get_format(struct snd_soc_codec *codec, unsigned int *fmt);
+
+#endif /* End of __WL1273_CODEC_H__ */
diff --git a/sound/soc/codecs/wm2000.h b/sound/soc/codecs/wm2000.h
index c18e261..0b6f056 100644
--- a/sound/soc/codecs/wm2000.h
+++ b/sound/soc/codecs/wm2000.h
@@ -16,9 +16,6 @@
extern int wm2000_add_controls(struct snd_soc_codec *codec);
-extern struct snd_soc_dai wm2000_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm2000;
-
#define WM2000_REG_SYS_START 0x8000
#define WM2000_REG_SPEECH_CLARITY 0x8fef
#define WM2000_REG_SYS_WATCHDOG 0x8ff6
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index 0221ca7..f4f1fba 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -1321,20 +1321,14 @@
return 0;
}
-static int wm8350_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8350_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8350_resume(struct platform_device *pdev)
+static int wm8350_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
@@ -1489,24 +1483,74 @@
}
EXPORT_SYMBOL_GPL(wm8350_mic_jack_detect);
-static struct snd_soc_codec *wm8350_codec;
+#define WM8350_RATES (SNDRV_PCM_RATE_8000_96000)
-static int wm8350_probe(struct platform_device *pdev)
+#define WM8350_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops wm8350_dai_ops = {
+ .hw_params = wm8350_pcm_hw_params,
+ .digital_mute = wm8350_mute,
+ .trigger = wm8350_pcm_trigger,
+ .set_fmt = wm8350_set_dai_fmt,
+ .set_sysclk = wm8350_set_dai_sysclk,
+ .set_pll = wm8350_set_fll,
+ .set_clkdiv = wm8350_set_clkdiv,
+};
+
+static struct snd_soc_dai_driver wm8350_dai = {
+ .name = "wm8350-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WM8350_RATES,
+ .formats = WM8350_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WM8350_RATES,
+ .formats = WM8350_FORMATS,
+ },
+ .ops = &wm8350_dai_ops,
+};
+
+static int wm8350_codec_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- struct wm8350 *wm8350;
+ struct wm8350 *wm8350 = dev_get_platdata(codec->dev);
struct wm8350_data *priv;
- int ret;
struct wm8350_output *out1;
struct wm8350_output *out2;
+ int ret, i;
- BUG_ON(!wm8350_codec);
+ if (wm8350->codec.platform_data == NULL) {
+ dev_err(codec->dev, "No audio platform data supplied\n");
+ return -EINVAL;
+ }
- socdev->card->codec = wm8350_codec;
- codec = socdev->card->codec;
- wm8350 = codec->control_data;
- priv = snd_soc_codec_get_drvdata(codec);
+ priv = kzalloc(sizeof(struct wm8350_data), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+ snd_soc_codec_set_drvdata(codec, priv);
+
+ for (i = 0; i < ARRAY_SIZE(supply_names); i++)
+ priv->supplies[i].supply = supply_names[i];
+
+ ret = regulator_bulk_get(wm8350->dev, ARRAY_SIZE(priv->supplies),
+ priv->supplies);
+ if (ret != 0)
+ goto err_priv;
+
+ wm8350->codec.codec = codec;
+ codec->control_data = wm8350;
+
+ /* Put the codec into reset if it wasn't already */
+ wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
+
+ INIT_DELAYED_WORK(&codec->delayed_work, wm8350_pga_work);
/* Enable the codec */
wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
@@ -1557,11 +1601,6 @@
wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD,
wm8350_mic_handler, 0, "Microphone detect", priv);
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to create pcms\n");
- return ret;
- }
snd_soc_add_controls(codec, wm8350_snd_controls,
ARRAY_SIZE(wm8350_snd_controls));
@@ -1570,14 +1609,16 @@
wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
+
+err_priv:
+ kfree(priv);
+ return ret;
}
-static int wm8350_remove(struct platform_device *pdev)
+static int wm8350_codec_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
- struct wm8350 *wm8350 = codec->control_data;
struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
+ struct wm8350 *wm8350 = dev_get_platdata(codec->dev);
int ret;
wm8350_clear_bits(wm8350, WM8350_JACK_DETECT,
@@ -1607,134 +1648,30 @@
wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
+ regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies);
+ kfree(priv);
return 0;
}
-#define WM8350_RATES (SNDRV_PCM_RATE_8000_96000)
-
-#define WM8350_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
- SNDRV_PCM_FMTBIT_S20_3LE |\
- SNDRV_PCM_FMTBIT_S24_LE)
-
-static struct snd_soc_dai_ops wm8350_dai_ops = {
- .hw_params = wm8350_pcm_hw_params,
- .digital_mute = wm8350_mute,
- .trigger = wm8350_pcm_trigger,
- .set_fmt = wm8350_set_dai_fmt,
- .set_sysclk = wm8350_set_dai_sysclk,
- .set_pll = wm8350_set_fll,
- .set_clkdiv = wm8350_set_clkdiv,
-};
-
-struct snd_soc_dai wm8350_dai = {
- .name = "WM8350",
- .playback = {
- .stream_name = "Playback",
- .channels_min = 1,
- .channels_max = 2,
- .rates = WM8350_RATES,
- .formats = WM8350_FORMATS,
- },
- .capture = {
- .stream_name = "Capture",
- .channels_min = 1,
- .channels_max = 2,
- .rates = WM8350_RATES,
- .formats = WM8350_FORMATS,
- },
- .ops = &wm8350_dai_ops,
-};
-EXPORT_SYMBOL_GPL(wm8350_dai);
-
-struct snd_soc_codec_device soc_codec_dev_wm8350 = {
- .probe = wm8350_probe,
- .remove = wm8350_remove,
+static struct snd_soc_codec_driver soc_codec_dev_wm8350 = {
+ .probe = wm8350_codec_probe,
+ .remove = wm8350_codec_remove,
.suspend = wm8350_suspend,
.resume = wm8350_resume,
+ .read = wm8350_codec_read,
+ .write = wm8350_codec_write,
+ .set_bias_level = wm8350_set_bias_level,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8350);
-static __devinit int wm8350_codec_probe(struct platform_device *pdev)
+static int __devinit wm8350_probe(struct platform_device *pdev)
{
- struct wm8350 *wm8350 = platform_get_drvdata(pdev);
- struct wm8350_data *priv;
- struct snd_soc_codec *codec;
- int ret, i;
-
- if (wm8350->codec.platform_data == NULL) {
- dev_err(&pdev->dev, "No audio platform data supplied\n");
- return -EINVAL;
- }
-
- priv = kzalloc(sizeof(struct wm8350_data), GFP_KERNEL);
- if (priv == NULL)
- return -ENOMEM;
-
- for (i = 0; i < ARRAY_SIZE(supply_names); i++)
- priv->supplies[i].supply = supply_names[i];
-
- ret = regulator_bulk_get(wm8350->dev, ARRAY_SIZE(priv->supplies),
- priv->supplies);
- if (ret != 0)
- goto err_priv;
-
- codec = &priv->codec;
- wm8350->codec.codec = codec;
-
- wm8350_dai.dev = &pdev->dev;
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
- codec->dev = &pdev->dev;
- codec->name = "WM8350";
- codec->owner = THIS_MODULE;
- codec->read = wm8350_codec_read;
- codec->write = wm8350_codec_write;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8350_set_bias_level;
- codec->dai = &wm8350_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = WM8350_MAX_REGISTER;
- snd_soc_codec_set_drvdata(codec, priv);
- codec->control_data = wm8350;
-
- /* Put the codec into reset if it wasn't already */
- wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
-
- INIT_DELAYED_WORK(&codec->delayed_work, wm8350_pga_work);
- ret = snd_soc_register_codec(codec);
- if (ret != 0)
- goto err_supply;
-
- wm8350_codec = codec;
-
- ret = snd_soc_register_dai(&wm8350_dai);
- if (ret != 0)
- goto err_codec;
- return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err_supply:
- regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies);
-err_priv:
- kfree(priv);
- wm8350_codec = NULL;
- return ret;
+ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8350,
+ &wm8350_dai, 1);
}
-static int __devexit wm8350_codec_remove(struct platform_device *pdev)
+static int __devexit wm8350_remove(struct platform_device *pdev)
{
- struct wm8350 *wm8350 = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = wm8350->codec.codec;
- struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
-
- snd_soc_unregister_dai(&wm8350_dai);
- snd_soc_unregister_codec(codec);
- regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies);
- kfree(priv);
- wm8350_codec = NULL;
+ snd_soc_unregister_codec(&pdev->dev);
return 0;
}
@@ -1743,8 +1680,8 @@
.name = "wm8350-codec",
.owner = THIS_MODULE,
},
- .probe = wm8350_codec_probe,
- .remove = __devexit_p(wm8350_codec_remove),
+ .probe = wm8350_probe,
+ .remove = __devexit_p(wm8350_remove),
};
static __init int wm8350_init(void)
diff --git a/sound/soc/codecs/wm8350.h b/sound/soc/codecs/wm8350.h
index 9ed0467..74108eb 100644
--- a/sound/soc/codecs/wm8350.h
+++ b/sound/soc/codecs/wm8350.h
@@ -15,9 +15,6 @@
#include <sound/soc.h>
#include <linux/mfd/wm8350/audio.h>
-extern struct snd_soc_dai wm8350_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8350;
-
enum wm8350_jack {
WM8350_JDL = 1,
WM8350_JDR = 2,
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index 8f29406..8502997 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -65,7 +65,7 @@
/* codec private data */
struct wm8400_priv {
- struct snd_soc_codec codec;
+ struct snd_soc_codec *codec;
struct wm8400 *wm8400;
u16 fake_register;
unsigned int sysclk;
@@ -1163,8 +1163,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
u16 audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1);
audio1 &= ~WM8400_AIF_WL_MASK;
@@ -1332,10 +1331,9 @@
* 1. ADC/DAC on Primary Interface
* 2. ADC on Primary Interface/DAC on secondary
*/
-struct snd_soc_dai wm8400_dai = {
+static struct snd_soc_dai_driver wm8400_dai = {
/* ADC/DAC on primary */
- .name = "WM8400 ADC/DAC Primary",
- .id = 1,
+ .name = "wm8400-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -1352,147 +1350,53 @@
},
.ops = &wm8400_dai_ops,
};
-EXPORT_SYMBOL_GPL(wm8400_dai);
-static int wm8400_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8400_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8400_resume(struct platform_device *pdev)
+static int wm8400_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
-static struct snd_soc_codec *wm8400_codec;
-
-static int wm8400_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret;
-
- if (!wm8400_codec) {
- dev_err(&pdev->dev, "wm8400 not yet discovered\n");
- return -ENODEV;
- }
- codec = wm8400_codec;
-
- socdev->card->codec = codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to create pcms\n");
- goto pcm_err;
- }
-
- wm8400_add_controls(codec);
- wm8400_add_widgets(codec);
-
-pcm_err:
- return ret;
-}
-
-/* power down chip */
-static int wm8400_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8400 = {
- .probe = wm8400_probe,
- .remove = wm8400_remove,
- .suspend = wm8400_suspend,
- .resume = wm8400_resume,
-};
-
static void wm8400_probe_deferred(struct work_struct *work)
{
struct wm8400_priv *priv = container_of(work, struct wm8400_priv,
work);
- struct snd_soc_codec *codec = &priv->codec;
- int ret;
+ struct snd_soc_codec *codec = priv->codec;
/* charge output caps */
wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- /* We're done, tell the subsystem. */
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(priv->wm8400->dev,
- "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dai(&wm8400_dai);
- if (ret != 0) {
- dev_err(priv->wm8400->dev,
- "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
-
- return;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF);
}
-static int wm8400_codec_probe(struct platform_device *dev)
+static int wm8400_codec_probe(struct snd_soc_codec *codec)
{
+ struct wm8400 *wm8400 = dev_get_platdata(codec->dev);
struct wm8400_priv *priv;
int ret;
u16 reg;
- struct snd_soc_codec *codec;
priv = kzalloc(sizeof(struct wm8400_priv), GFP_KERNEL);
if (priv == NULL)
return -ENOMEM;
- codec = &priv->codec;
snd_soc_codec_set_drvdata(codec, priv);
- codec->control_data = dev_get_drvdata(&dev->dev);
- priv->wm8400 = dev_get_drvdata(&dev->dev);
+ codec->control_data = priv->wm8400 = wm8400;
+ priv->codec = codec;
- ret = regulator_bulk_get(priv->wm8400->dev,
+ ret = regulator_bulk_get(wm8400->dev,
ARRAY_SIZE(power), &power[0]);
if (ret != 0) {
- dev_err(&dev->dev, "Failed to get regulators: %d\n", ret);
+ dev_err(codec->dev, "Failed to get regulators: %d\n", ret);
goto err;
}
- codec->dev = &dev->dev;
- wm8400_dai.dev = &dev->dev;
-
- codec->name = "WM8400";
- codec->owner = THIS_MODULE;
- codec->read = wm8400_read;
- codec->write = wm8400_write;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8400_set_bias_level;
- codec->dai = &wm8400_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = WM8400_REGISTER_COUNT;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
INIT_WORK(&priv->work, wm8400_probe_deferred);
wm8400_codec_reset(codec);
@@ -1511,65 +1415,78 @@
wm8400_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
wm8400_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
- wm8400_codec = codec;
-
if (!schedule_work(&priv->work)) {
ret = -EINVAL;
goto err_regulator;
}
-
+ wm8400_add_controls(codec);
+ wm8400_add_widgets(codec);
return 0;
err_regulator:
- wm8400_codec = NULL;
regulator_bulk_free(ARRAY_SIZE(power), power);
err:
kfree(priv);
return ret;
}
-static int __exit wm8400_codec_remove(struct platform_device *dev)
+static int wm8400_codec_remove(struct snd_soc_codec *codec)
{
- struct wm8400_priv *priv = snd_soc_codec_get_drvdata(wm8400_codec);
+ struct wm8400_priv *priv = snd_soc_codec_get_drvdata(codec);
u16 reg;
- snd_soc_unregister_dai(&wm8400_dai);
- snd_soc_unregister_codec(wm8400_codec);
-
- reg = wm8400_read(wm8400_codec, WM8400_POWER_MANAGEMENT_1);
- wm8400_write(wm8400_codec, WM8400_POWER_MANAGEMENT_1,
+ reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
+ wm8400_write(codec, WM8400_POWER_MANAGEMENT_1,
reg & (~WM8400_CODEC_ENA));
regulator_bulk_free(ARRAY_SIZE(power), power);
kfree(priv);
- wm8400_codec = NULL;
+ return 0;
+}
+static struct snd_soc_codec_driver soc_codec_dev_wm8400 = {
+ .probe = wm8400_codec_probe,
+ .remove = wm8400_codec_remove,
+ .suspend = wm8400_suspend,
+ .resume = wm8400_resume,
+ .read = wm8400_read,
+ .write = wm8400_write,
+ .set_bias_level = wm8400_set_bias_level,
+};
+
+static int __devinit wm8400_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8400,
+ &wm8400_dai, 1);
+}
+
+static int __devexit wm8400_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
return 0;
}
static struct platform_driver wm8400_codec_driver = {
.driver = {
- .name = "wm8400-codec",
- .owner = THIS_MODULE,
- },
- .probe = wm8400_codec_probe,
- .remove = __exit_p(wm8400_codec_remove),
+ .name = "wm8400-codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8400_probe,
+ .remove = __devexit_p(wm8400_remove),
};
-static int __init wm8400_codec_init(void)
+static __init int wm8400_init(void)
{
return platform_driver_register(&wm8400_codec_driver);
}
-module_init(wm8400_codec_init);
+module_init(wm8400_init);
-static void __exit wm8400_codec_exit(void)
+static __exit void wm8400_exit(void)
{
platform_driver_unregister(&wm8400_codec_driver);
}
-module_exit(wm8400_codec_exit);
-
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8400);
+module_exit(wm8400_exit);
MODULE_DESCRIPTION("ASoC WM8400 driver");
MODULE_AUTHOR("Mark Brown");
diff --git a/sound/soc/codecs/wm8400.h b/sound/soc/codecs/wm8400.h
index 79c5934..521adb1 100644
--- a/sound/soc/codecs/wm8400.h
+++ b/sound/soc/codecs/wm8400.h
@@ -56,7 +56,4 @@
#define WM8400_BCLK_DIV_44 (0xE << 1)
#define WM8400_BCLK_DIV_48 (0xF << 1)
-extern struct snd_soc_dai wm8400_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8400;
-
#endif
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index 0f7bcb6..8f10709 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -29,10 +29,6 @@
#include "wm8510.h"
-#define WM8510_VERSION "0.6"
-
-struct snd_soc_codec_device soc_codec_dev_wm8510;
-
/*
* wm8510 register cache
* We can't read the WM8510 register space when we are
@@ -61,6 +57,11 @@
#define wm8510_reset(c) snd_soc_write(c, WM8510_RESET, 0)
+/* codec private data */
+struct wm8510_priv {
+ enum snd_soc_control_type control_type;
+};
+
static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" };
static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" };
static const char *wm8510_alc[] = { "ALC", "Limiter" };
@@ -403,8 +404,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
u16 iface = snd_soc_read(codec, WM8510_IFACE) & 0x19f;
u16 adn = snd_soc_read(codec, WM8510_ADD) & 0x1f1;
@@ -514,8 +514,8 @@
.set_pll = wm8510_set_dai_pll,
};
-struct snd_soc_dai wm8510_dai = {
- .name = "WM8510 HiFi",
+static struct snd_soc_dai_driver wm8510_dai = {
+ .name = "wm8510-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -531,21 +531,15 @@
.ops = &wm8510_dai_ops,
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(wm8510_dai);
-static int wm8510_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8510_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8510_resume(struct platform_device *pdev)
+static int wm8510_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -561,86 +555,109 @@
return 0;
}
-/*
- * initialise the WM8510 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int wm8510_init(struct snd_soc_device *socdev,
- enum snd_soc_control_type control)
+static int wm8510_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = socdev->card->codec;
- int ret = 0;
+ struct wm8510_priv *wm8510 = snd_soc_codec_get_drvdata(codec);
+ int ret;
- codec->name = "WM8510";
- codec->owner = THIS_MODULE;
- codec->set_bias_level = wm8510_set_bias_level;
- codec->dai = &wm8510_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(wm8510_reg);
- codec->reg_cache = kmemdup(wm8510_reg, sizeof(wm8510_reg), GFP_KERNEL);
-
- if (codec->reg_cache == NULL)
- return -ENOMEM;
-
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8510->control_type);
if (ret < 0) {
- printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n",
- ret);
- goto err;
+ printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n", ret);
+ return ret;
}
wm8510_reset(codec);
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "wm8510: failed to create pcms\n");
- goto err;
- }
-
/* power on device */
- codec->bias_level = SND_SOC_BIAS_OFF;
wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
snd_soc_add_controls(codec, wm8510_snd_controls,
ARRAY_SIZE(wm8510_snd_controls));
wm8510_add_widgets(codec);
return ret;
-
-err:
- kfree(codec->reg_cache);
- return ret;
}
-static struct snd_soc_device *wm8510_socdev;
-
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-
-/*
- * WM8510 2 wire address is 0x1a
- */
-
-static int wm8510_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+/* power down chip */
+static int wm8510_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = wm8510_socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct wm8510_priv *wm8510 = snd_soc_codec_get_drvdata(codec);
+
+ wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ kfree(wm8510);
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8510 = {
+ .probe = wm8510_probe,
+ .remove = wm8510_remove,
+ .suspend = wm8510_suspend,
+ .resume = wm8510_resume,
+ .set_bias_level = wm8510_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8510_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default =wm8510_reg,
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8510_spi_probe(struct spi_device *spi)
+{
+ struct wm8510_priv *wm8510;
int ret;
- i2c_set_clientdata(i2c, codec);
- codec->control_data = i2c;
+ wm8510 = kzalloc(sizeof(struct wm8510_priv), GFP_KERNEL);
+ if (wm8510 == NULL)
+ return -ENOMEM;
- ret = wm8510_init(socdev, SND_SOC_I2C);
+ wm8510->control_type = SND_SOC_SPI;
+ spi_set_drvdata(spi, wm8510);
+
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_wm8510, &wm8510_dai, 1);
if (ret < 0)
- pr_err("failed to initialise WM8510\n");
-
+ kfree(wm8510);
return ret;
}
-static int wm8510_i2c_remove(struct i2c_client *client)
+static int __devexit wm8510_spi_remove(struct spi_device *spi)
{
- struct snd_soc_codec *codec = i2c_get_clientdata(client);
- kfree(codec->reg_cache);
+ snd_soc_unregister_codec(&spi->dev);
+ return 0;
+}
+
+static struct spi_driver wm8510_spi_driver = {
+ .driver = {
+ .name = "wm8510",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8510_spi_probe,
+ .remove = __devexit_p(wm8510_spi_remove),
+};
+#endif /* CONFIG_SPI_MASTER */
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8510_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8510_priv *wm8510;
+ int ret;
+
+ wm8510 = kzalloc(sizeof(struct wm8510_priv), GFP_KERNEL);
+ if (wm8510 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, wm8510);
+ wm8510->control_type = SND_SOC_I2C;
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8510, &wm8510_dai, 1);
+ if (ret < 0)
+ kfree(wm8510);
+ return ret;
+}
+
+static __devexit int wm8510_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
return 0;
}
@@ -652,165 +669,44 @@
static struct i2c_driver wm8510_i2c_driver = {
.driver = {
- .name = "WM8510 I2C Codec",
+ .name = "wm8510-codec",
.owner = THIS_MODULE,
},
.probe = wm8510_i2c_probe,
- .remove = wm8510_i2c_remove,
+ .remove = __devexit_p(wm8510_i2c_remove),
.id_table = wm8510_i2c_id,
};
-
-static int wm8510_add_i2c_device(struct platform_device *pdev,
- const struct wm8510_setup_data *setup)
-{
- struct i2c_board_info info;
- struct i2c_adapter *adapter;
- struct i2c_client *client;
- int ret;
-
- ret = i2c_add_driver(&wm8510_i2c_driver);
- if (ret != 0) {
- dev_err(&pdev->dev, "can't add i2c driver\n");
- return ret;
- }
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = setup->i2c_address;
- strlcpy(info.type, "wm8510", I2C_NAME_SIZE);
-
- adapter = i2c_get_adapter(setup->i2c_bus);
- if (!adapter) {
- dev_err(&pdev->dev, "can't get i2c adapter %d\n",
- setup->i2c_bus);
- goto err_driver;
- }
-
- client = i2c_new_device(adapter, &info);
- i2c_put_adapter(adapter);
- if (!client) {
- dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
- (unsigned int)info.addr);
- goto err_driver;
- }
-
- return 0;
-
-err_driver:
- i2c_del_driver(&wm8510_i2c_driver);
- return -ENODEV;
-}
#endif
-#if defined(CONFIG_SPI_MASTER)
-static int __devinit wm8510_spi_probe(struct spi_device *spi)
-{
- struct snd_soc_device *socdev = wm8510_socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
- int ret;
-
- codec->control_data = spi;
-
- ret = wm8510_init(socdev, SND_SOC_SPI);
- if (ret < 0)
- dev_err(&spi->dev, "failed to initialise WM8510\n");
-
- return ret;
-}
-
-static int __devexit wm8510_spi_remove(struct spi_device *spi)
-{
- return 0;
-}
-
-static struct spi_driver wm8510_spi_driver = {
- .driver = {
- .name = "wm8510",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
- },
- .probe = wm8510_spi_probe,
- .remove = __devexit_p(wm8510_spi_remove),
-};
-#endif /* CONFIG_SPI_MASTER */
-
-static int wm8510_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct wm8510_setup_data *setup;
- struct snd_soc_codec *codec;
- int ret = 0;
-
- pr_info("WM8510 Audio Codec %s", WM8510_VERSION);
-
- setup = socdev->codec_data;
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
-
- socdev->card->codec = codec;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- wm8510_socdev = socdev;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- if (setup->i2c_address) {
- ret = wm8510_add_i2c_device(pdev, setup);
- }
-#endif
-#if defined(CONFIG_SPI_MASTER)
- if (setup->spi) {
- ret = spi_register_driver(&wm8510_spi_driver);
- if (ret != 0)
- printk(KERN_ERR "can't add spi driver");
- }
-#endif
-
- if (ret != 0)
- kfree(codec);
- return ret;
-}
-
-/* power down chip */
-static int wm8510_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec->control_data)
- wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- i2c_unregister_device(codec->control_data);
- i2c_del_driver(&wm8510_i2c_driver);
-#endif
-#if defined(CONFIG_SPI_MASTER)
- spi_unregister_driver(&wm8510_spi_driver);
-#endif
- kfree(codec);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8510 = {
- .probe = wm8510_probe,
- .remove = wm8510_remove,
- .suspend = wm8510_suspend,
- .resume = wm8510_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8510);
-
static int __init wm8510_modinit(void)
{
- return snd_soc_register_dai(&wm8510_dai);
+ int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8510_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register WM8510 I2C driver: %d\n",
+ ret);
+ }
+#endif
+#if defined(CONFIG_SPI_MASTER)
+ ret = spi_register_driver(&wm8510_spi_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register WM8510 SPI driver: %d\n",
+ ret);
+ }
+#endif
+ return ret;
}
module_init(wm8510_modinit);
static void __exit wm8510_exit(void)
{
- snd_soc_unregister_dai(&wm8510_dai);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&wm8510_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+ spi_unregister_driver(&wm8510_spi_driver);
+#endif
}
module_exit(wm8510_exit);
diff --git a/sound/soc/codecs/wm8510.h b/sound/soc/codecs/wm8510.h
index bdefcf5..b3e26ed 100644
--- a/sound/soc/codecs/wm8510.h
+++ b/sound/soc/codecs/wm8510.h
@@ -99,7 +99,4 @@
unsigned short i2c_address;
};
-extern struct snd_soc_dai wm8510_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8510;
-
#endif
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index 0ad039b..712ef7c 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -30,9 +30,6 @@
#include "wm8523.h"
-static struct snd_soc_codec *wm8523_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8523;
-
#define WM8523_NUM_SUPPLIES 2
static const char *wm8523_supply_names[WM8523_NUM_SUPPLIES] = {
"AVDD",
@@ -43,7 +40,7 @@
/* codec private data */
struct wm8523_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
u16 reg_cache[WM8523_REGISTER_COUNT];
struct regulator_bulk_data supplies[WM8523_NUM_SUPPLIES];
unsigned int sysclk;
@@ -162,8 +159,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
int i;
u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1);
@@ -387,8 +383,8 @@
.set_fmt = wm8523_set_dai_fmt,
};
-struct snd_soc_dai wm8523_dai = {
- .name = "WM8523",
+static struct snd_soc_dai_driver wm8523_dai = {
+ .name = "wm8523-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2, /* Mono modes not yet supported */
@@ -398,25 +394,17 @@
},
.ops = &wm8523_dai_ops,
};
-EXPORT_SYMBOL_GPL(wm8523_dai);
#ifdef CONFIG_PM
-static int wm8523_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8523_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8523_resume(struct platform_device *pdev)
+static int wm8523_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
return 0;
}
#else
@@ -424,93 +412,20 @@
#define wm8523_resume NULL
#endif
-static int wm8523_probe(struct platform_device *pdev)
+static int wm8523_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
+ struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
+ int ret, i;
- if (wm8523_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8523_codec;
- codec = wm8523_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- snd_soc_add_controls(codec, wm8523_snd_controls,
- ARRAY_SIZE(wm8523_snd_controls));
- wm8523_add_widgets(codec);
-
- return ret;
-
-pcm_err:
- return ret;
-}
-
-static int wm8523_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8523 = {
- .probe = wm8523_probe,
- .remove = wm8523_remove,
- .suspend = wm8523_suspend,
- .resume = wm8523_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8523);
-
-static int wm8523_register(struct wm8523_priv *wm8523,
- enum snd_soc_control_type control)
-{
- int ret;
- struct snd_soc_codec *codec = &wm8523->codec;
- int i;
-
- if (wm8523_codec) {
- dev_err(codec->dev, "Another WM8523 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8523);
- codec->name = "WM8523";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8523_set_bias_level;
- codec->dai = &wm8523_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = WM8523_REGISTER_COUNT;
- codec->reg_cache = &wm8523->reg_cache;
- codec->volatile_register = wm8523_volatile_register;
-
+ codec->hw_write = (hw_write_t)i2c_master_send;
wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0];
wm8523->rate_constraint.count =
ARRAY_SIZE(wm8523->rate_constraint_list);
- memcpy(codec->reg_cache, wm8523_reg, sizeof(wm8523_reg));
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
+ ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8523->control_type);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
for (i = 0; i < ARRAY_SIZE(wm8523->supplies); i++)
@@ -520,7 +435,7 @@
wm8523->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
- goto err;
+ return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies),
@@ -555,8 +470,6 @@
goto err_enable;
}
- wm8523_dai.dev = codec->dev;
-
/* Change some default settings - latch VU and enable ZC */
wm8523->reg_cache[WM8523_DAC_GAINR] |= WM8523_DACR_VU;
wm8523->reg_cache[WM8523_DAC_CTRL3] |= WM8523_ZC;
@@ -566,69 +479,67 @@
/* Bias level configuration will have done an extra enable */
regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
- wm8523_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err_enable;
- }
-
- ret = snd_soc_register_dai(&wm8523_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
+ snd_soc_add_controls(codec, wm8523_snd_controls,
+ ARRAY_SIZE(wm8523_snd_controls));
+ wm8523_add_widgets(codec);
return 0;
-err_codec:
- snd_soc_unregister_codec(codec);
err_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
err_get:
regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
-err:
- kfree(wm8523);
+
return ret;
}
-static void wm8523_unregister(struct wm8523_priv *wm8523)
+static int wm8523_remove(struct snd_soc_codec *codec)
{
- wm8523_set_bias_level(&wm8523->codec, SND_SOC_BIAS_OFF);
+ struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
+
+ wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF);
regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
- snd_soc_unregister_dai(&wm8523_dai);
- snd_soc_unregister_codec(&wm8523->codec);
- kfree(wm8523);
- wm8523_codec = NULL;
+ return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_wm8523 = {
+ .probe = wm8523_probe,
+ .remove = wm8523_remove,
+ .suspend = wm8523_suspend,
+ .resume = wm8523_resume,
+ .set_bias_level = wm8523_set_bias_level,
+ .reg_cache_size = WM8523_REGISTER_COUNT,
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8523_reg,
+ .volatile_register = wm8523_volatile_register,
+};
+
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static __devinit int wm8523_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm8523_priv *wm8523;
- struct snd_soc_codec *codec;
+ int ret;
wm8523 = kzalloc(sizeof(struct wm8523_priv), GFP_KERNEL);
if (wm8523 == NULL)
return -ENOMEM;
- codec = &wm8523->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
-
i2c_set_clientdata(i2c, wm8523);
- codec->control_data = i2c;
+ wm8523->control_type = SND_SOC_I2C;
- codec->dev = &i2c->dev;
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8523, &wm8523_dai, 1);
+ if (ret < 0)
+ kfree(wm8523);
+ return ret;
- return wm8523_register(wm8523, SND_SOC_I2C);
}
static __devexit int wm8523_i2c_remove(struct i2c_client *client)
{
- struct wm8523_priv *wm8523 = i2c_get_clientdata(client);
- wm8523_unregister(wm8523);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -640,7 +551,7 @@
static struct i2c_driver wm8523_i2c_driver = {
.driver = {
- .name = "WM8523",
+ .name = "wm8523-codec",
.owner = THIS_MODULE,
},
.probe = wm8523_i2c_probe,
diff --git a/sound/soc/codecs/wm8523.h b/sound/soc/codecs/wm8523.h
index 1aa9ce3..4d5b1eb 100644
--- a/sound/soc/codecs/wm8523.h
+++ b/sound/soc/codecs/wm8523.h
@@ -154,7 +154,4 @@
#define WM8523_ZD_COUNT_SHIFT 0 /* ZD_COUNT - [1:0] */
#define WM8523_ZD_COUNT_WIDTH 2 /* ZD_COUNT - [1:0] */
-extern struct snd_soc_dai wm8523_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8523;
-
#endif
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index 72deeab..a2e0ed5 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -94,6 +94,8 @@
#define WM8580_MAX_REGISTER 0x35
+#define WM8580_DACOSR 0x40
+
/* PLLB4 (register 7h) */
#define WM8580_PLLB4_MCLKOUTSRC_MASK 0x60
#define WM8580_PLLB4_MCLKOUTSRC_PLLA 0x20
@@ -112,19 +114,7 @@
/* AIF control 1 (registers 9h-bh) */
#define WM8580_AIF_RATE_MASK 0x7
-#define WM8580_AIF_RATE_128 0x0
-#define WM8580_AIF_RATE_192 0x1
-#define WM8580_AIF_RATE_256 0x2
-#define WM8580_AIF_RATE_384 0x3
-#define WM8580_AIF_RATE_512 0x4
-#define WM8580_AIF_RATE_768 0x5
-#define WM8580_AIF_RATE_1152 0x6
-
#define WM8580_AIF_BCLKSEL_MASK 0x18
-#define WM8580_AIF_BCLKSEL_64 0x00
-#define WM8580_AIF_BCLKSEL_128 0x08
-#define WM8580_AIF_BCLKSEL_256 0x10
-#define WM8580_AIF_BCLKSEL_SYSCLK 0x18
#define WM8580_AIF_MS 0x20
@@ -199,11 +189,12 @@
/* codec private data */
struct wm8580_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
struct regulator_bulk_data supplies[WM8580_NUM_SUPPLIES];
u16 reg_cache[WM8580_MAX_REGISTER + 1];
struct pll_state a;
struct pll_state b;
+ int sysclk[2];
};
static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
@@ -273,8 +264,8 @@
SOC_SINGLE("DAC2 Switch", WM8580_DAC_CONTROL5, 1, 1, 1),
SOC_SINGLE("DAC3 Switch", WM8580_DAC_CONTROL5, 2, 1, 1),
-SOC_DOUBLE("ADC Mute Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 0),
-SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0),
+SOC_DOUBLE("Capture Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 1),
+SOC_SINGLE("Capture High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0),
};
static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = {
@@ -476,6 +467,10 @@
return 0;
}
+static const int wm8580_sysclk_ratios[] = {
+ 128, 192, 256, 384, 512, 768, 1152,
+};
+
/*
* Set PCM DAI bit size and sample rate.
*/
@@ -484,29 +479,68 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
- u16 paifb = snd_soc_read(codec, WM8580_PAIF3 + dai->id);
+ struct snd_soc_codec *codec = rtd->codec;
+ struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
+ u16 paifa = 0;
+ u16 paifb = 0;
+ int i, ratio, osr;
- paifb &= ~WM8580_AIF_LENGTH_MASK;
/* bit size */
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
+ paifa |= 0x8;
break;
case SNDRV_PCM_FORMAT_S20_3LE:
+ paifa |= 0x10;
paifb |= WM8580_AIF_LENGTH_20;
break;
case SNDRV_PCM_FORMAT_S24_LE:
+ paifa |= 0x10;
paifb |= WM8580_AIF_LENGTH_24;
break;
case SNDRV_PCM_FORMAT_S32_LE:
+ paifa |= 0x10;
paifb |= WM8580_AIF_LENGTH_24;
break;
default:
return -EINVAL;
}
- snd_soc_write(codec, WM8580_PAIF3 + dai->id, paifb);
+ /* Look up the SYSCLK ratio; accept only exact matches */
+ ratio = wm8580->sysclk[dai->id] / params_rate(params);
+ for (i = 0; i < ARRAY_SIZE(wm8580_sysclk_ratios); i++)
+ if (ratio == wm8580_sysclk_ratios[i])
+ break;
+ if (i == ARRAY_SIZE(wm8580_sysclk_ratios)) {
+ dev_err(codec->dev, "Invalid clock ratio %d/%d\n",
+ wm8580->sysclk[dai->id], params_rate(params));
+ return -EINVAL;
+ }
+ paifa |= i;
+ dev_dbg(codec->dev, "Running at %dfs with %dHz clock\n",
+ wm8580_sysclk_ratios[i], wm8580->sysclk[dai->driver->id]);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ switch (ratio) {
+ case 128:
+ case 192:
+ osr = WM8580_DACOSR;
+ dev_dbg(codec->dev, "Selecting 64x OSR\n");
+ break;
+ default:
+ osr = 0;
+ dev_dbg(codec->dev, "Selecting 128x OSR\n");
+ break;
+ }
+
+ snd_soc_update_bits(codec, WM8580_PAIF3, WM8580_DACOSR, osr);
+ }
+
+ snd_soc_update_bits(codec, WM8580_PAIF1 + dai->driver->id,
+ WM8580_AIF_RATE_MASK | WM8580_AIF_BCLKSEL_MASK,
+ paifa);
+ snd_soc_update_bits(codec, WM8580_PAIF3 + dai->driver->id,
+ WM8580_AIF_LENGTH_MASK, paifb);
return 0;
}
@@ -518,8 +552,8 @@
unsigned int aifb;
int can_invert_lrclk;
- aifa = snd_soc_read(codec, WM8580_PAIF1 + codec_dai->id);
- aifb = snd_soc_read(codec, WM8580_PAIF3 + codec_dai->id);
+ aifa = snd_soc_read(codec, WM8580_PAIF1 + codec_dai->driver->id);
+ aifb = snd_soc_read(codec, WM8580_PAIF3 + codec_dai->driver->id);
aifb &= ~(WM8580_AIF_FMT_MASK | WM8580_AIF_LRP | WM8580_AIF_BCP);
@@ -585,8 +619,8 @@
return -EINVAL;
}
- snd_soc_write(codec, WM8580_PAIF1 + codec_dai->id, aifa);
- snd_soc_write(codec, WM8580_PAIF3 + codec_dai->id, aifb);
+ snd_soc_write(codec, WM8580_PAIF1 + codec_dai->driver->id, aifa);
+ snd_soc_write(codec, WM8580_PAIF3 + codec_dai->driver->id, aifb);
return 0;
}
@@ -624,28 +658,6 @@
snd_soc_write(codec, WM8580_PLLB4, reg);
break;
- case WM8580_DAC_CLKSEL:
- reg = snd_soc_read(codec, WM8580_CLKSEL);
- reg &= ~WM8580_CLKSEL_DAC_CLKSEL_MASK;
-
- switch (div) {
- case WM8580_CLKSRC_MCLK:
- break;
-
- case WM8580_CLKSRC_PLLA:
- reg |= WM8580_CLKSEL_DAC_CLKSEL_PLLA;
- break;
-
- case WM8580_CLKSRC_PLLB:
- reg |= WM8580_CLKSEL_DAC_CLKSEL_PLLB;
- break;
-
- default:
- return -EINVAL;
- }
- snd_soc_write(codec, WM8580_CLKSEL, reg);
- break;
-
case WM8580_CLKOUTSRC:
reg = snd_soc_read(codec, WM8580_PLLB4);
reg &= ~WM8580_PLLB4_CLKOUTSRC_MASK;
@@ -679,6 +691,55 @@
return 0;
}
+static int wm8580_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
+ int sel, sel_mask, sel_shift;
+
+ switch (dai->driver->id) {
+ case WM8580_DAI_PAIFRX:
+ sel_mask = 0x3;
+ sel_shift = 0;
+ break;
+
+ case WM8580_DAI_PAIFTX:
+ sel_mask = 0xc;
+ sel_shift = 2;
+ break;
+
+ default:
+ BUG_ON("Unknown DAI driver ID\n");
+ return -EINVAL;
+ }
+
+ switch (clk_id) {
+ case WM8580_CLKSRC_ADCMCLK:
+ if (dai->id != WM8580_DAI_PAIFTX)
+ return -EINVAL;
+ sel = 0 << sel_shift;
+ break;
+ case WM8580_CLKSRC_PLLA:
+ sel = 1 << sel_shift;
+ break;
+ case WM8580_CLKSRC_PLLB:
+ sel = 2 << sel_shift;
+ break;
+ case WM8580_CLKSRC_MCLK:
+ sel = 3 << sel_shift;
+ break;
+ default:
+ dev_err(codec->dev, "Unknown clock %d\n", clk_id);
+ return -EINVAL;
+ }
+
+ /* We really should validate PLL settings but not yet */
+ wm8580->sysclk[dai->id] = freq;
+
+ return snd_soc_update_bits(codec, WM8580_CLKSEL, sel_mask, sel);
+}
+
static int wm8580_digital_mute(struct snd_soc_dai *codec_dai, int mute)
{
struct snd_soc_codec *codec = codec_dai->codec;
@@ -732,6 +793,7 @@
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_ops wm8580_dai_ops_playback = {
+ .set_sysclk = wm8580_set_sysclk,
.hw_params = wm8580_paif_hw_params,
.set_fmt = wm8580_set_paif_dai_fmt,
.set_clkdiv = wm8580_set_dai_clkdiv,
@@ -740,16 +802,17 @@
};
static struct snd_soc_dai_ops wm8580_dai_ops_capture = {
+ .set_sysclk = wm8580_set_sysclk,
.hw_params = wm8580_paif_hw_params,
.set_fmt = wm8580_set_paif_dai_fmt,
.set_clkdiv = wm8580_set_dai_clkdiv,
.set_pll = wm8580_set_dai_pll,
};
-struct snd_soc_dai wm8580_dai[] = {
+static struct snd_soc_dai_driver wm8580_dai[] = {
{
- .name = "WM8580 PAIFRX",
- .id = 0,
+ .name = "wm8580-hifi-playback",
+ .id = WM8580_DAI_PAIFRX,
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -760,8 +823,8 @@
.ops = &wm8580_dai_ops_playback,
},
{
- .name = "WM8580 PAIFTX",
- .id = 1,
+ .name = "wm8580-hifi-capture",
+ .id = WM8580_DAI_PAIFTX,
.capture = {
.stream_name = "Capture",
.channels_min = 2,
@@ -772,90 +835,16 @@
.ops = &wm8580_dai_ops_capture,
},
};
-EXPORT_SYMBOL_GPL(wm8580_dai);
-static struct snd_soc_codec *wm8580_codec;
-
-static int wm8580_probe(struct platform_device *pdev)
+static int wm8580_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
+ struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0,i;
- if (wm8580_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8580_codec;
- codec = wm8580_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- snd_soc_add_controls(codec, wm8580_snd_controls,
- ARRAY_SIZE(wm8580_snd_controls));
- wm8580_add_widgets(codec);
-
- return ret;
-
-pcm_err:
- return ret;
-}
-
-/* power down chip */
-static int wm8580_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8580 = {
- .probe = wm8580_probe,
- .remove = wm8580_remove,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580);
-
-static int wm8580_register(struct wm8580_priv *wm8580,
- enum snd_soc_control_type control)
-{
- int ret, i;
- struct snd_soc_codec *codec = &wm8580->codec;
-
- if (wm8580_codec) {
- dev_err(codec->dev, "Another WM8580 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8580);
- codec->name = "WM8580";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8580_set_bias_level;
- codec->dai = wm8580_dai;
- codec->num_dai = ARRAY_SIZE(wm8580_dai);
- codec->reg_cache_size = ARRAY_SIZE(wm8580->reg_cache);
- codec->reg_cache = &wm8580->reg_cache;
-
- memcpy(codec->reg_cache, wm8580_reg, sizeof(wm8580_reg));
-
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8580->control_type);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
for (i = 0; i < ARRAY_SIZE(wm8580->supplies); i++)
@@ -865,7 +854,7 @@
wm8580->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
- goto err;
+ return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(wm8580->supplies),
@@ -882,74 +871,68 @@
goto err_regulator_enable;
}
- for (i = 0; i < ARRAY_SIZE(wm8580_dai); i++)
- wm8580_dai[i].dev = codec->dev;
-
wm8580_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- wm8580_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err_regulator_enable;
- }
-
- ret = snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai));
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
+ snd_soc_add_controls(codec, wm8580_snd_controls,
+ ARRAY_SIZE(wm8580_snd_controls));
+ wm8580_add_widgets(codec);
return 0;
-err_codec:
- snd_soc_unregister_codec(codec);
err_regulator_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
err_regulator_get:
regulator_bulk_free(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
-err:
- kfree(wm8580);
return ret;
}
-static void wm8580_unregister(struct wm8580_priv *wm8580)
+/* power down chip */
+static int wm8580_remove(struct snd_soc_codec *codec)
{
- wm8580_set_bias_level(&wm8580->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai));
- snd_soc_unregister_codec(&wm8580->codec);
+ struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
+
+ wm8580_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
regulator_bulk_free(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
- kfree(wm8580);
- wm8580_codec = NULL;
+
+ return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_wm8580 = {
+ .probe = wm8580_probe,
+ .remove = wm8580_remove,
+ .set_bias_level = wm8580_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8580_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = &wm8580_reg,
+};
+
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static int wm8580_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm8580_priv *wm8580;
- struct snd_soc_codec *codec;
+ int ret;
wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL);
if (wm8580 == NULL)
return -ENOMEM;
- codec = &wm8580->codec;
-
i2c_set_clientdata(i2c, wm8580);
- codec->control_data = i2c;
+ wm8580->control_type = SND_SOC_I2C;
- codec->dev = &i2c->dev;
-
- return wm8580_register(wm8580, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8580, wm8580_dai, ARRAY_SIZE(wm8580_dai));
+ if (ret < 0)
+ kfree(wm8580);
+ return ret;
}
static int wm8580_i2c_remove(struct i2c_client *client)
{
- struct wm8580_priv *wm8580 = i2c_get_clientdata(client);
- wm8580_unregister(wm8580);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -961,7 +944,7 @@
static struct i2c_driver wm8580_i2c_driver = {
.driver = {
- .name = "wm8580",
+ .name = "wm8580-codec",
.owner = THIS_MODULE,
},
.probe = wm8580_i2c_probe,
@@ -972,7 +955,7 @@
static int __init wm8580_modinit(void)
{
- int ret;
+ int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8580_i2c_driver);
@@ -981,7 +964,7 @@
}
#endif
- return 0;
+ return ret;
}
module_init(wm8580_modinit);
diff --git a/sound/soc/codecs/wm8580.h b/sound/soc/codecs/wm8580.h
index 0dfb5dd..1d34656 100644
--- a/sound/soc/codecs/wm8580.h
+++ b/sound/soc/codecs/wm8580.h
@@ -19,20 +19,17 @@
#define WM8580_PLLB 2
#define WM8580_MCLK 1
-#define WM8580_DAC_CLKSEL 2
-#define WM8580_CLKOUTSRC 3
+#define WM8580_CLKOUTSRC 2
-#define WM8580_CLKSRC_MCLK 1
-#define WM8580_CLKSRC_PLLA 2
-#define WM8580_CLKSRC_PLLB 3
-#define WM8580_CLKSRC_OSC 4
-#define WM8580_CLKSRC_NONE 5
+#define WM8580_CLKSRC_MCLK 1
+#define WM8580_CLKSRC_PLLA 2
+#define WM8580_CLKSRC_PLLB 3
+#define WM8580_CLKSRC_OSC 4
+#define WM8580_CLKSRC_NONE 5
+#define WM8580_CLKSRC_ADCMCLK 6
#define WM8580_DAI_PAIFRX 0
#define WM8580_DAI_PAIFTX 1
-extern struct snd_soc_dai wm8580_dai[];
-extern struct snd_soc_codec_device soc_codec_dev_wm8580;
-
#endif
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
index e2dba07..54fbd76 100644
--- a/sound/soc/codecs/wm8711.c
+++ b/sound/soc/codecs/wm8711.c
@@ -31,11 +31,9 @@
#include "wm8711.h"
-static struct snd_soc_codec *wm8711_codec;
-
/* codec private data */
struct wm8711_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type bus_type;
u16 reg_cache[WM8711_CACHEREGNUM];
unsigned int sysclk;
};
@@ -163,7 +161,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
- struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
+ struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0xfffc;
int i = get_coeff(wm8711->sysclk, params_rate(params));
u16 srate = (coeff_div[i].sr << 2) |
@@ -227,7 +225,7 @@
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec = codec_dai->codec;
- struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
+ struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
switch (freq) {
case 11289600:
@@ -338,8 +336,8 @@
.set_fmt = wm8711_set_dai_fmt,
};
-struct snd_soc_dai wm8711_dai = {
- .name = "WM8711",
+static struct snd_soc_dai_driver wm8711_dai = {
+ .name = "wm8711-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -349,22 +347,16 @@
},
.ops = &wm8711_ops,
};
-EXPORT_SYMBOL_GPL(wm8711_dai);
-static int wm8711_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8711_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
snd_soc_write(codec, WM8711_ACTIVE, 0x0);
wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8711_resume(struct platform_device *pdev)
+static int wm8711_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -380,99 +372,23 @@
return 0;
}
-static int wm8711_probe(struct platform_device *pdev)
+static int wm8711_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
+ struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
+ int ret, reg;
- if (wm8711_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8711_codec;
- codec = wm8711_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- snd_soc_add_controls(codec, wm8711_snd_controls,
- ARRAY_SIZE(wm8711_snd_controls));
- wm8711_add_widgets(codec);
-
- return ret;
-
-pcm_err:
- return ret;
-}
-
-/* power down chip */
-static int wm8711_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8711 = {
- .probe = wm8711_probe,
- .remove = wm8711_remove,
- .suspend = wm8711_suspend,
- .resume = wm8711_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8711);
-
-static int wm8711_register(struct wm8711_priv *wm8711,
- enum snd_soc_control_type control)
-{
- int ret;
- struct snd_soc_codec *codec = &wm8711->codec;
- u16 reg;
-
- if (wm8711_codec) {
- dev_err(codec->dev, "Another WM8711 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8711);
- codec->name = "WM8711";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8711_set_bias_level;
- codec->dai = &wm8711_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = WM8711_CACHEREGNUM;
- codec->reg_cache = &wm8711->reg_cache;
-
- memcpy(codec->reg_cache, wm8711_reg, sizeof(wm8711_reg));
-
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8711->bus_type);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
ret = wm8711_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
- goto err;
+ return ret;
}
- wm8711_dai.dev = codec->dev;
-
wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Latch the update bits */
@@ -481,70 +397,62 @@
reg = snd_soc_read(codec, WM8711_ROUT1V);
snd_soc_write(codec, WM8711_ROUT1V, reg | 0x0100);
- wm8711_codec = codec;
+ snd_soc_add_controls(codec, wm8711_snd_controls,
+ ARRAY_SIZE(wm8711_snd_controls));
+ wm8711_add_widgets(codec);
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dai(&wm8711_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
-
- return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- kfree(wm8711);
return ret;
+
}
-static void wm8711_unregister(struct wm8711_priv *wm8711)
+/* power down chip */
+static int wm8711_remove(struct snd_soc_codec *codec)
{
- wm8711_set_bias_level(&wm8711->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dai(&wm8711_dai);
- snd_soc_unregister_codec(&wm8711->codec);
- kfree(wm8711);
- wm8711_codec = NULL;
+ wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_wm8711 = {
+ .probe = wm8711_probe,
+ .remove = wm8711_remove,
+ .suspend = wm8711_suspend,
+ .resume = wm8711_resume,
+ .set_bias_level = wm8711_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8711_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8711_reg,
+};
+
#if defined(CONFIG_SPI_MASTER)
static int __devinit wm8711_spi_probe(struct spi_device *spi)
{
- struct snd_soc_codec *codec;
struct wm8711_priv *wm8711;
+ int ret;
wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL);
if (wm8711 == NULL)
return -ENOMEM;
- codec = &wm8711->codec;
- codec->control_data = spi;
- codec->dev = &spi->dev;
+ spi_set_drvdata(spi, wm8711);
+ wm8711->bus_type = SND_SOC_SPI;
- dev_set_drvdata(&spi->dev, wm8711);
-
- return wm8711_register(wm8711, SND_SOC_SPI);
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_wm8711, &wm8711_dai, 1);
+ if (ret < 0)
+ kfree(wm8711);
+ return ret;
}
static int __devexit wm8711_spi_remove(struct spi_device *spi)
{
- struct wm8711_priv *wm8711 = dev_get_drvdata(&spi->dev);
-
- wm8711_unregister(wm8711);
-
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
return 0;
}
static struct spi_driver wm8711_spi_driver = {
.driver = {
- .name = "wm8711",
- .bus = &spi_bus_type,
+ .name = "wm8711-codec",
.owner = THIS_MODULE,
},
.probe = wm8711_spi_probe,
@@ -553,31 +461,30 @@
#endif /* CONFIG_SPI_MASTER */
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-static __devinit int wm8711_i2c_probe(struct i2c_client *i2c,
+static __devinit int wm8711_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct wm8711_priv *wm8711;
- struct snd_soc_codec *codec;
+ int ret;
wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL);
if (wm8711 == NULL)
return -ENOMEM;
- codec = &wm8711->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
+ i2c_set_clientdata(client, wm8711);
+ wm8711->bus_type = SND_SOC_I2C;
- i2c_set_clientdata(i2c, wm8711);
- codec->control_data = i2c;
-
- codec->dev = &i2c->dev;
-
- return wm8711_register(wm8711, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&client->dev,
+ &soc_codec_dev_wm8711, &wm8711_dai, 1);
+ if (ret < 0)
+ kfree(wm8711);
+ return ret;
}
static __devexit int wm8711_i2c_remove(struct i2c_client *client)
{
- struct wm8711_priv *wm8711 = i2c_get_clientdata(client);
- wm8711_unregister(wm8711);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -589,7 +496,7 @@
static struct i2c_driver wm8711_i2c_driver = {
.driver = {
- .name = "WM8711 I2C Codec",
+ .name = "wm8711-codec",
.owner = THIS_MODULE,
},
.probe = wm8711_i2c_probe,
diff --git a/sound/soc/codecs/wm8711.h b/sound/soc/codecs/wm8711.h
index 381e84a..a61db98 100644
--- a/sound/soc/codecs/wm8711.h
+++ b/sound/soc/codecs/wm8711.h
@@ -36,7 +36,4 @@
unsigned short i2c_address;
};
-extern struct snd_soc_dai wm8711_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8711;
-
#endif
diff --git a/sound/soc/codecs/wm8727.c b/sound/soc/codecs/wm8727.c
index 9d1df26..7488082 100644
--- a/sound/soc/codecs/wm8727.c
+++ b/sound/soc/codecs/wm8727.c
@@ -23,7 +23,6 @@
#include <sound/initval.h>
#include <sound/soc.h>
-#include "wm8727.h"
/*
* Note this is a simple chip with no configuration interface, sample rate is
* determined automatically by examining the Master clock and Bit clock ratios
@@ -33,8 +32,8 @@
SNDRV_PCM_RATE_192000)
-struct snd_soc_dai wm8727_dai = {
- .name = "WM8727",
+static struct snd_soc_dai_driver wm8727_dai = {
+ .name = "wm8727-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -43,103 +42,18 @@
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
},
};
-EXPORT_SYMBOL_GPL(wm8727_dai);
-static struct snd_soc_codec *wm8727_codec;
+static struct snd_soc_codec_driver soc_codec_dev_wm8727;
-static int wm8727_soc_probe(struct platform_device *pdev)
+static __devinit int wm8727_probe(struct platform_device *pdev)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- int ret = 0;
-
- BUG_ON(!wm8727_codec);
-
- socdev->card->codec = wm8727_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "wm8727: failed to create pcms\n");
- goto pcm_err;
- }
-
- return ret;
-
-pcm_err:
- kfree(socdev->card->codec);
- socdev->card->codec = NULL;
- return ret;
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_wm8727, &wm8727_dai, 1);
}
-static int wm8727_soc_remove(struct platform_device *pdev)
+static int __devexit wm8727_remove(struct platform_device *pdev)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8727 = {
- .probe = wm8727_soc_probe,
- .remove = wm8727_soc_remove,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8727);
-
-
-static __devinit int wm8727_platform_probe(struct platform_device *pdev)
-{
- struct snd_soc_codec *codec;
- int ret;
-
- if (wm8727_codec) {
- dev_err(&pdev->dev, "Another WM8727 is registered\n");
- return -EBUSY;
- }
-
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
- wm8727_codec = codec;
-
- platform_set_drvdata(pdev, codec);
-
- mutex_init(&codec->mutex);
- codec->dev = &pdev->dev;
- codec->name = "WM8727";
- codec->owner = THIS_MODULE;
- codec->dai = &wm8727_dai;
- codec->num_dai = 1;
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- wm8727_dai.dev = &pdev->dev;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(&pdev->dev, "Failed to register CODEC: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dai(&wm8727_dai);
- if (ret != 0) {
- dev_err(&pdev->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
-
- return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- kfree(codec);
- return ret;
-}
-
-static int __devexit wm8727_platform_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_dai(&wm8727_dai);
- snd_soc_unregister_codec(platform_get_drvdata(pdev));
+ snd_soc_unregister_codec(&pdev->dev);
return 0;
}
@@ -149,8 +63,8 @@
.owner = THIS_MODULE,
},
- .probe = wm8727_platform_probe,
- .remove = __devexit_p(wm8727_platform_remove),
+ .probe = wm8727_probe,
+ .remove = __devexit_p(wm8727_remove),
};
static int __init wm8727_init(void)
diff --git a/sound/soc/codecs/wm8727.h b/sound/soc/codecs/wm8727.h
deleted file mode 100644
index ee19aa7..0000000
--- a/sound/soc/codecs/wm8727.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * wm8727.h
- *
- * Created on: 15-Oct-2009
- * Author: neil.jones@imgtec.com
- *
- * Copyright (C) 2009 Imagination Technologies Ltd.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#ifndef WM8727_H_
-#define WM8727_H_
-
-extern struct snd_soc_dai wm8727_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8727;
-
-#endif /* WM8727_H_ */
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c
index 34be2d2..075f35e 100644
--- a/sound/soc/codecs/wm8728.c
+++ b/sound/soc/codecs/wm8728.c
@@ -29,8 +29,6 @@
#include "wm8728.h"
-struct snd_soc_codec_device soc_codec_dev_wm8728;
-
/*
* We can't read the WM8728 register space so we cache them instead.
* Note that the defaults here aren't the physical defaults, we latch
@@ -44,6 +42,11 @@
0x100,
};
+/* codec private data */
+struct wm8728_priv {
+ enum snd_soc_control_type control_type;
+};
+
static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1);
static const struct snd_kcontrol_new wm8728_snd_controls[] = {
@@ -96,8 +99,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
u16 dac = snd_soc_read(codec, WM8728_DACCTL);
dac &= ~0x18;
@@ -210,8 +212,8 @@
.set_fmt = wm8728_set_dai_fmt,
};
-struct snd_soc_dai wm8728_dai = {
- .name = "WM8728",
+static struct snd_soc_dai_driver wm8728_dai = {
+ .name = "wm8728-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -221,63 +223,31 @@
},
.ops = &wm8728_dai_ops,
};
-EXPORT_SYMBOL_GPL(wm8728_dai);
-static int wm8728_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8728_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8728_resume(struct platform_device *pdev)
+static int wm8728_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
-/*
- * initialise the WM8728 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int wm8728_init(struct snd_soc_device *socdev,
- enum snd_soc_control_type control)
+static int wm8728_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = socdev->card->codec;
- int ret = 0;
+ struct wm8728_priv *wm8728 = snd_soc_codec_get_drvdata(codec);
+ int ret;
- codec->name = "WM8728";
- codec->owner = THIS_MODULE;
- codec->set_bias_level = wm8728_set_bias_level;
- codec->dai = &wm8728_dai;
- codec->num_dai = 1;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults);
- codec->reg_cache = kmemdup(wm8728_reg_defaults,
- sizeof(wm8728_reg_defaults),
- GFP_KERNEL);
- if (codec->reg_cache == NULL)
- return -ENOMEM;
-
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8728->control_type);
if (ret < 0) {
printk(KERN_ERR "wm8728: failed to configure cache I/O: %d\n",
ret);
- goto err;
- }
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "wm8728: failed to create pcms\n");
- goto err;
+ return ret;
}
/* power on device */
@@ -288,44 +258,87 @@
wm8728_add_widgets(codec);
return ret;
-
-err:
- kfree(codec->reg_cache);
- return ret;
}
-static struct snd_soc_device *wm8728_socdev;
-
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-
-/*
- * WM8728 2 wire address is determined by GPIO5
- * state during powerup.
- * low = 0x1a
- * high = 0x1b
- */
-
-static int wm8728_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int wm8728_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = wm8728_socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8728 = {
+ .probe = wm8728_probe,
+ .remove = wm8728_remove,
+ .suspend = wm8728_suspend,
+ .resume = wm8728_resume,
+ .set_bias_level = wm8728_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8728_reg_defaults,
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8728_spi_probe(struct spi_device *spi)
+{
+ struct wm8728_priv *wm8728;
int ret;
- i2c_set_clientdata(i2c, codec);
- codec->control_data = i2c;
+ wm8728 = kzalloc(sizeof(struct wm8728_priv), GFP_KERNEL);
+ if (wm8728 == NULL)
+ return -ENOMEM;
- ret = wm8728_init(socdev, SND_SOC_I2C);
+ wm8728->control_type = SND_SOC_SPI;
+ spi_set_drvdata(spi, wm8728);
+
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_wm8728, &wm8728_dai, 1);
if (ret < 0)
- pr_err("failed to initialise WM8728\n");
-
+ kfree(wm8728);
return ret;
}
-static int wm8728_i2c_remove(struct i2c_client *client)
+static int __devexit wm8728_spi_remove(struct spi_device *spi)
{
- struct snd_soc_codec *codec = i2c_get_clientdata(client);
- kfree(codec->reg_cache);
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
+ return 0;
+}
+
+static struct spi_driver wm8728_spi_driver = {
+ .driver = {
+ .name = "wm8728-codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8728_spi_probe,
+ .remove = __devexit_p(wm8728_spi_remove),
+};
+#endif /* CONFIG_SPI_MASTER */
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8728_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8728_priv *wm8728;
+ int ret;
+
+ wm8728 = kzalloc(sizeof(struct wm8728_priv), GFP_KERNEL);
+ if (wm8728 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, wm8728);
+ wm8728->control_type = SND_SOC_I2C;
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8728, &wm8728_dai, 1);
+ if (ret < 0)
+ kfree(wm8728);
+ return ret;
+}
+
+static __devexit int wm8728_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -337,166 +350,44 @@
static struct i2c_driver wm8728_i2c_driver = {
.driver = {
- .name = "WM8728 I2C Codec",
+ .name = "wm8728-codec",
.owner = THIS_MODULE,
},
.probe = wm8728_i2c_probe,
- .remove = wm8728_i2c_remove,
+ .remove = __devexit_p(wm8728_i2c_remove),
.id_table = wm8728_i2c_id,
};
-
-static int wm8728_add_i2c_device(struct platform_device *pdev,
- const struct wm8728_setup_data *setup)
-{
- struct i2c_board_info info;
- struct i2c_adapter *adapter;
- struct i2c_client *client;
- int ret;
-
- ret = i2c_add_driver(&wm8728_i2c_driver);
- if (ret != 0) {
- dev_err(&pdev->dev, "can't add i2c driver\n");
- return ret;
- }
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = setup->i2c_address;
- strlcpy(info.type, "wm8728", I2C_NAME_SIZE);
-
- adapter = i2c_get_adapter(setup->i2c_bus);
- if (!adapter) {
- dev_err(&pdev->dev, "can't get i2c adapter %d\n",
- setup->i2c_bus);
- goto err_driver;
- }
-
- client = i2c_new_device(adapter, &info);
- i2c_put_adapter(adapter);
- if (!client) {
- dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
- (unsigned int)info.addr);
- goto err_driver;
- }
-
- return 0;
-
-err_driver:
- i2c_del_driver(&wm8728_i2c_driver);
- return -ENODEV;
-}
#endif
-#if defined(CONFIG_SPI_MASTER)
-static int __devinit wm8728_spi_probe(struct spi_device *spi)
-{
- struct snd_soc_device *socdev = wm8728_socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
- int ret;
-
- codec->control_data = spi;
-
- ret = wm8728_init(socdev, SND_SOC_SPI);
- if (ret < 0)
- dev_err(&spi->dev, "failed to initialise WM8728\n");
-
- return ret;
-}
-
-static int __devexit wm8728_spi_remove(struct spi_device *spi)
-{
- return 0;
-}
-
-static struct spi_driver wm8728_spi_driver = {
- .driver = {
- .name = "wm8728",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
- },
- .probe = wm8728_spi_probe,
- .remove = __devexit_p(wm8728_spi_remove),
-};
-#endif /* CONFIG_SPI_MASTER */
-
-static int wm8728_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct wm8728_setup_data *setup;
- struct snd_soc_codec *codec;
- int ret = 0;
-
- setup = socdev->codec_data;
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
-
- socdev->card->codec = codec;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- wm8728_socdev = socdev;
- ret = -ENODEV;
-
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- if (setup->i2c_address) {
- ret = wm8728_add_i2c_device(pdev, setup);
- }
-#endif
-#if defined(CONFIG_SPI_MASTER)
- if (setup->spi) {
- ret = spi_register_driver(&wm8728_spi_driver);
- if (ret != 0)
- printk(KERN_ERR "can't add spi driver");
- }
-#endif
-
- if (ret != 0)
- kfree(codec);
-
- return ret;
-}
-
-/* power down chip */
-static int wm8728_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec->control_data)
- wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- i2c_unregister_device(codec->control_data);
- i2c_del_driver(&wm8728_i2c_driver);
-#endif
-#if defined(CONFIG_SPI_MASTER)
- spi_unregister_driver(&wm8728_spi_driver);
-#endif
- kfree(codec);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8728 = {
- .probe = wm8728_probe,
- .remove = wm8728_remove,
- .suspend = wm8728_suspend,
- .resume = wm8728_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8728);
-
static int __init wm8728_modinit(void)
{
- return snd_soc_register_dai(&wm8728_dai);
+ int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8728_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8728 I2C driver: %d\n",
+ ret);
+ }
+#endif
+#if defined(CONFIG_SPI_MASTER)
+ ret = spi_register_driver(&wm8728_spi_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8728 SPI driver: %d\n",
+ ret);
+ }
+#endif
+ return ret;
}
module_init(wm8728_modinit);
static void __exit wm8728_exit(void)
{
- snd_soc_unregister_dai(&wm8728_dai);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&wm8728_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+ spi_unregister_driver(&wm8728_spi_driver);
+#endif
}
module_exit(wm8728_exit);
diff --git a/sound/soc/codecs/wm8728.h b/sound/soc/codecs/wm8728.h
index d269c13..8aea362 100644
--- a/sound/soc/codecs/wm8728.h
+++ b/sound/soc/codecs/wm8728.h
@@ -18,13 +18,4 @@
#define WM8728_DACCTL 0x02
#define WM8728_IFCTL 0x03
-struct wm8728_setup_data {
- int spi;
- int i2c_bus;
- unsigned short i2c_address;
-};
-
-extern struct snd_soc_dai wm8728_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8728;
-
#endif
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 0ab9b63..6313858 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -32,9 +32,6 @@
#include "wm8731.h"
-static struct snd_soc_codec *wm8731_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8731;
-
#define WM8731_NUM_SUPPLIES 4
static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = {
"AVDD",
@@ -45,10 +42,11 @@
/* codec private data */
struct wm8731_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES];
u16 reg_cache[WM8731_CACHEREGNUM];
unsigned int sysclk;
+ int sysclk_type;
};
@@ -113,6 +111,7 @@
SOC_DAPM_ENUM("Input Select", wm8731_enum[0]);
static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("OSC", WM8731_PWR, 5, 1, NULL, 0),
SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1,
&wm8731_output_mixer_controls[0],
ARRAY_SIZE(wm8731_output_mixer_controls)),
@@ -130,7 +129,18 @@
SND_SOC_DAPM_INPUT("LLINEIN"),
};
+static int wm8731_check_osc(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(source->codec);
+
+ return wm8731->sysclk_type == WM8731_SYSCLK_MCLK;
+}
+
static const struct snd_soc_dapm_route intercon[] = {
+ {"DAC", NULL, "OSC", wm8731_check_osc},
+ {"ADC", NULL, "OSC", wm8731_check_osc},
+
/* output mixer */
{"Output Mixer", "Line Bypass Switch", "Line Input"},
{"Output Mixer", "HiFi Playback Switch", "DAC"},
@@ -222,9 +232,7 @@
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
u16 iface = snd_soc_read(codec, WM8731_IFACE) & 0xfff3;
int i = get_coeff(wm8731->sysclk, params_rate(params));
@@ -252,9 +260,7 @@
static int wm8731_pcm_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = dai->codec;
/* set active */
snd_soc_write(codec, WM8731_ACTIVE, 0x0001);
@@ -265,9 +271,7 @@
static void wm8731_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = dai->codec;
/* deactivate */
if (!codec->active) {
@@ -294,6 +298,15 @@
struct snd_soc_codec *codec = codec_dai->codec;
struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
+ switch (clk_id) {
+ case WM8731_SYSCLK_XTAL:
+ case WM8731_SYSCLK_MCLK:
+ wm8731->sysclk_type = clk_id;
+ break;
+ default:
+ return -EINVAL;
+ }
+
switch (freq) {
case 11289600:
case 12000000:
@@ -301,9 +314,14 @@
case 16934400:
case 18432000:
wm8731->sysclk = freq;
- return 0;
+ break;
+ default:
+ return -EINVAL;
}
- return -EINVAL;
+
+ snd_soc_dapm_sync(codec);
+
+ return 0;
}
@@ -428,8 +446,8 @@
.set_fmt = wm8731_set_dai_fmt,
};
-struct snd_soc_dai wm8731_dai = {
- .name = "WM8731",
+static struct snd_soc_dai_driver wm8731_dai = {
+ .name = "wm8731-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -445,24 +463,17 @@
.ops = &wm8731_dai_ops,
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(wm8731_dai);
#ifdef CONFIG_PM
-static int wm8731_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8731_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8731_resume(struct platform_device *pdev)
+static int wm8731_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
@@ -472,88 +483,15 @@
#define wm8731_resume NULL
#endif
-static int wm8731_probe(struct platform_device *pdev)
+static int wm8731_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
+ struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0, i;
- if (wm8731_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8731_codec;
- codec = wm8731_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- snd_soc_add_controls(codec, wm8731_snd_controls,
- ARRAY_SIZE(wm8731_snd_controls));
- wm8731_add_widgets(codec);
-
- return ret;
-
-pcm_err:
- return ret;
-}
-
-/* power down chip */
-static int wm8731_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8731 = {
- .probe = wm8731_probe,
- .remove = wm8731_remove,
- .suspend = wm8731_suspend,
- .resume = wm8731_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731);
-
-static int wm8731_register(struct wm8731_priv *wm8731,
- enum snd_soc_control_type control)
-{
- int ret, i;
- struct snd_soc_codec *codec = &wm8731->codec;
-
- if (wm8731_codec) {
- dev_err(codec->dev, "Another WM8731 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8731);
- codec->name = "WM8731";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8731_set_bias_level;
- codec->dai = &wm8731_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = WM8731_CACHEREGNUM;
- codec->reg_cache = &wm8731->reg_cache;
-
- memcpy(codec->reg_cache, wm8731_reg, sizeof(wm8731_reg));
-
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8731->control_type);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++)
@@ -563,7 +501,7 @@
wm8731->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
- goto err;
+ return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies),
@@ -579,8 +517,6 @@
goto err_regulator_enable;
}
- wm8731_dai.dev = codec->dev;
-
wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Latch the update bits */
@@ -592,79 +528,78 @@
/* Disable bypass path by default */
snd_soc_update_bits(codec, WM8731_APANA, 0x4, 0);
- wm8731_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err_regulator_enable;
- }
-
- ret = snd_soc_register_dai(&wm8731_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- snd_soc_unregister_codec(codec);
- goto err_codec;
- }
+ snd_soc_add_controls(codec, wm8731_snd_controls,
+ ARRAY_SIZE(wm8731_snd_controls));
+ wm8731_add_widgets(codec);
/* Regulators will have been enabled by bias management */
regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
return 0;
-err_codec:
- snd_soc_unregister_codec(codec);
err_regulator_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
err_regulator_get:
regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
-err:
+
kfree(wm8731);
return ret;
}
-static void wm8731_unregister(struct wm8731_priv *wm8731)
+/* power down chip */
+static int wm8731_remove(struct snd_soc_codec *codec)
{
- wm8731_set_bias_level(&wm8731->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dai(&wm8731_dai);
- snd_soc_unregister_codec(&wm8731->codec);
+ struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
+
+ wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
- kfree(wm8731);
- wm8731_codec = NULL;
+
+ return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_wm8731 = {
+ .probe = wm8731_probe,
+ .remove = wm8731_remove,
+ .suspend = wm8731_suspend,
+ .resume = wm8731_resume,
+ .set_bias_level = wm8731_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8731_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8731_reg,
+};
+
#if defined(CONFIG_SPI_MASTER)
static int __devinit wm8731_spi_probe(struct spi_device *spi)
{
- struct snd_soc_codec *codec;
struct wm8731_priv *wm8731;
+ int ret;
wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL);
if (wm8731 == NULL)
return -ENOMEM;
- codec = &wm8731->codec;
- codec->control_data = spi;
- codec->dev = &spi->dev;
+ wm8731->control_type = SND_SOC_SPI;
+ spi_set_drvdata(spi, wm8731);
- dev_set_drvdata(&spi->dev, wm8731);
-
- return wm8731_register(wm8731, SND_SOC_SPI);
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_wm8731, &wm8731_dai, 1);
+ if (ret < 0)
+ kfree(wm8731);
+ return ret;
}
static int __devexit wm8731_spi_remove(struct spi_device *spi)
{
- struct wm8731_priv *wm8731 = dev_get_drvdata(&spi->dev);
-
- wm8731_unregister(wm8731);
-
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
return 0;
}
static struct spi_driver wm8731_spi_driver = {
.driver = {
- .name = "wm8731",
- .bus = &spi_bus_type,
+ .name = "wm8731-codec",
.owner = THIS_MODULE,
},
.probe = wm8731_spi_probe,
@@ -677,26 +612,26 @@
const struct i2c_device_id *id)
{
struct wm8731_priv *wm8731;
- struct snd_soc_codec *codec;
+ int ret;
wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL);
if (wm8731 == NULL)
return -ENOMEM;
- codec = &wm8731->codec;
-
i2c_set_clientdata(i2c, wm8731);
- codec->control_data = i2c;
+ wm8731->control_type = SND_SOC_I2C;
- codec->dev = &i2c->dev;
-
- return wm8731_register(wm8731, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8731, &wm8731_dai, 1);
+ if (ret < 0)
+ kfree(wm8731);
+ return ret;
}
static __devexit int wm8731_i2c_remove(struct i2c_client *client)
{
- struct wm8731_priv *wm8731 = i2c_get_clientdata(client);
- wm8731_unregister(wm8731);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -708,7 +643,7 @@
static struct i2c_driver wm8731_i2c_driver = {
.driver = {
- .name = "wm8731",
+ .name = "wm8731-codec",
.owner = THIS_MODULE,
},
.probe = wm8731_i2c_probe,
@@ -719,7 +654,7 @@
static int __init wm8731_modinit(void)
{
- int ret;
+ int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8731_i2c_driver);
if (ret != 0) {
@@ -734,7 +669,7 @@
ret);
}
#endif
- return 0;
+ return ret;
}
module_init(wm8731_modinit);
diff --git a/sound/soc/codecs/wm8731.h b/sound/soc/codecs/wm8731.h
index cd7b806..e9c0c76 100644
--- a/sound/soc/codecs/wm8731.h
+++ b/sound/soc/codecs/wm8731.h
@@ -31,10 +31,9 @@
#define WM8731_CACHEREGNUM 10
-#define WM8731_SYSCLK 0
-#define WM8731_DAI 0
+#define WM8731_SYSCLK_XTAL 1
+#define WM8731_SYSCLK_MCLK 2
-extern struct snd_soc_dai wm8731_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8731;
+#define WM8731_DAI 0
#endif
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
index b9ea890..90e31e9 100644
--- a/sound/soc/codecs/wm8741.c
+++ b/sound/soc/codecs/wm8741.c
@@ -30,25 +30,21 @@
#include "wm8741.h"
-static struct snd_soc_codec *wm8741_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8741;
-
#define WM8741_NUM_SUPPLIES 2
static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = {
"AVDD",
"DVDD",
};
-#define WM8741_NUM_RATES 4
+#define WM8741_NUM_RATES 6
/* codec private data */
struct wm8741_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
u16 reg_cache[WM8741_REGISTER_COUNT];
struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES];
unsigned int sysclk;
- unsigned int rate_constraint_list[WM8741_NUM_RATES];
- struct snd_pcm_hw_constraint_list rate_constraint;
+ struct snd_pcm_hw_constraint_list *sysclk_constraints;
};
static const u16 wm8741_reg_defaults[WM8741_REGISTER_COUNT] = {
@@ -111,10 +107,84 @@
int value;
int ratio;
} lrclk_ratios[WM8741_NUM_RATES] = {
- { 1, 256 },
- { 2, 384 },
- { 3, 512 },
- { 4, 768 },
+ { 1, 128 },
+ { 2, 192 },
+ { 3, 256 },
+ { 4, 384 },
+ { 5, 512 },
+ { 6, 768 },
+};
+
+static unsigned int rates_11289[] = {
+ 44100, 88235,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_11289 = {
+ .count = ARRAY_SIZE(rates_11289),
+ .list = rates_11289,
+};
+
+static unsigned int rates_12288[] = {
+ 32000, 48000, 96000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_12288 = {
+ .count = ARRAY_SIZE(rates_12288),
+ .list = rates_12288,
+};
+
+static unsigned int rates_16384[] = {
+ 32000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_16384 = {
+ .count = ARRAY_SIZE(rates_16384),
+ .list = rates_16384,
+};
+
+static unsigned int rates_16934[] = {
+ 44100, 88235,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_16934 = {
+ .count = ARRAY_SIZE(rates_16934),
+ .list = rates_16934,
+};
+
+static unsigned int rates_18432[] = {
+ 48000, 96000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_18432 = {
+ .count = ARRAY_SIZE(rates_18432),
+ .list = rates_18432,
+};
+
+static unsigned int rates_22579[] = {
+ 44100, 88235, 1764000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_22579 = {
+ .count = ARRAY_SIZE(rates_22579),
+ .list = rates_22579,
+};
+
+static unsigned int rates_24576[] = {
+ 32000, 48000, 96000, 192000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_24576 = {
+ .count = ARRAY_SIZE(rates_24576),
+ .list = rates_24576,
+};
+
+static unsigned int rates_36864[] = {
+ 48000, 96000, 19200
+};
+
+static struct snd_pcm_hw_constraint_list constraints_36864 = {
+ .count = ARRAY_SIZE(rates_36864),
+ .list = rates_36864,
};
@@ -135,7 +205,7 @@
snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
- &wm8741->rate_constraint);
+ wm8741->sysclk_constraints);
return 0;
}
@@ -145,8 +215,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1FC;
int i;
@@ -196,47 +265,52 @@
{
struct snd_soc_codec *codec = codec_dai->codec;
struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
- unsigned int val;
- int i;
dev_dbg(codec->dev, "wm8741_set_dai_sysclk info: freq=%dHz\n", freq);
- wm8741->sysclk = freq;
+ switch (freq) {
+ case 11289600:
+ wm8741->sysclk_constraints = &constraints_11289;
+ wm8741->sysclk = freq;
+ return 0;
- wm8741->rate_constraint.count = 0;
+ case 12288000:
+ wm8741->sysclk_constraints = &constraints_12288;
+ wm8741->sysclk = freq;
+ return 0;
- for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) {
- dev_dbg(codec->dev, "index = %d, ratio = %d, freq = %d",
- i, lrclk_ratios[i].ratio, freq);
+ case 16384000:
+ wm8741->sysclk_constraints = &constraints_16384;
+ wm8741->sysclk = freq;
+ return 0;
- val = freq / lrclk_ratios[i].ratio;
- /* Check that it's a standard rate since core can't
- * cope with others and having the odd rates confuses
- * constraint matching.
- */
- switch (val) {
- case 32000:
- case 44100:
- case 48000:
- case 64000:
- case 88200:
- case 96000:
- dev_dbg(codec->dev, "Supported sample rate: %dHz\n",
- val);
- wm8741->rate_constraint_list[i] = val;
- wm8741->rate_constraint.count++;
- break;
- default:
- dev_dbg(codec->dev, "Skipping sample rate: %dHz\n",
- val);
- }
+ case 16934400:
+ wm8741->sysclk_constraints = &constraints_16934;
+ wm8741->sysclk = freq;
+ return 0;
+
+ case 18432000:
+ wm8741->sysclk_constraints = &constraints_18432;
+ wm8741->sysclk = freq;
+ return 0;
+
+ case 22579200:
+ case 33868800:
+ wm8741->sysclk_constraints = &constraints_22579;
+ wm8741->sysclk = freq;
+ return 0;
+
+ case 24576000:
+ wm8741->sysclk_constraints = &constraints_24576;
+ wm8741->sysclk = freq;
+ return 0;
+
+ case 36864000:
+ wm8741->sysclk_constraints = &constraints_36864;
+ wm8741->sysclk = freq;
+ return 0;
}
-
- /* Need at least one supported rate... */
- if (wm8741->rate_constraint.count == 0)
- return -EINVAL;
-
- return 0;
+ return -EINVAL;
}
static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai,
@@ -314,8 +388,8 @@
.set_fmt = wm8741_set_dai_fmt,
};
-struct snd_soc_dai wm8741_dai = {
- .name = "WM8741",
+static struct snd_soc_dai_driver wm8741_dai = {
+ .name = "wm8741",
.playback = {
.stream_name = "Playback",
.channels_min = 2, /* Mono modes not yet supported */
@@ -325,13 +399,10 @@
},
.ops = &wm8741_dai_ops,
};
-EXPORT_SYMBOL_GPL(wm8741_dai);
#ifdef CONFIG_PM
-static int wm8741_resume(struct platform_device *pdev)
+static int wm8741_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
u16 *cache = codec->reg_cache;
int i;
@@ -348,189 +419,99 @@
#define wm8741_resume NULL
#endif
-static int wm8741_probe(struct platform_device *pdev)
+static int wm8741_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
+ struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
- if (wm8741_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8741_codec;
- codec = wm8741_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- snd_soc_add_controls(codec, wm8741_snd_controls,
- ARRAY_SIZE(wm8741_snd_controls));
- wm8741_add_widgets(codec);
-
- return ret;
-
-pcm_err:
- return ret;
-}
-
-static int wm8741_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8741 = {
- .probe = wm8741_probe,
- .remove = wm8741_remove,
- .resume = wm8741_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8741);
-
-static int wm8741_register(struct wm8741_priv *wm8741,
- enum snd_soc_control_type control)
-{
- int ret;
- struct snd_soc_codec *codec = &wm8741->codec;
- int i;
-
- if (wm8741_codec) {
- dev_err(codec->dev, "Another WM8741 is registered\n");
- return -EINVAL;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8741);
- codec->name = "WM8741";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = NULL;
- codec->dai = &wm8741_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = WM8741_REGISTER_COUNT;
- codec->reg_cache = &wm8741->reg_cache;
-
- wm8741->rate_constraint.list = &wm8741->rate_constraint_list[0];
- wm8741->rate_constraint.count =
- ARRAY_SIZE(wm8741->rate_constraint_list);
-
- memcpy(codec->reg_cache, wm8741_reg_defaults,
- sizeof(wm8741->reg_cache));
-
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8741->control_type);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
- }
-
- for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++)
- wm8741->supplies[i].supply = wm8741_supply_names[i];
-
- ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8741->supplies),
- wm8741->supplies);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
- goto err;
- }
-
- ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies),
- wm8741->supplies);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
- goto err_get;
+ return ret;
}
ret = wm8741_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
- goto err_enable;
+ return ret;
}
- wm8741_dai.dev = codec->dev;
-
/* Change some default settings - latch VU */
wm8741->reg_cache[WM8741_DACLLSB_ATTENUATION] |= WM8741_UPDATELL;
wm8741->reg_cache[WM8741_DACLMSB_ATTENUATION] |= WM8741_UPDATELM;
wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERL;
wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERM;
- wm8741_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- return ret;
- }
-
- ret = snd_soc_register_dai(&wm8741_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- snd_soc_unregister_codec(codec);
- return ret;
- }
+ snd_soc_add_controls(codec, wm8741_snd_controls,
+ ARRAY_SIZE(wm8741_snd_controls));
+ wm8741_add_widgets(codec);
dev_dbg(codec->dev, "Successful registration\n");
- return 0;
+ return ret;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8741 = {
+ .probe = wm8741_probe,
+ .resume = wm8741_resume,
+ .reg_cache_size = ARRAY_SIZE(wm8741_reg_defaults),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = &wm8741_reg_defaults,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static int wm8741_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8741_priv *wm8741;
+ int ret, i;
+
+ wm8741 = kzalloc(sizeof(struct wm8741_priv), GFP_KERNEL);
+ if (wm8741 == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++)
+ wm8741->supplies[i].supply = wm8741_supply_names[i];
+
+ ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8741->supplies),
+ wm8741->supplies);
+ if (ret != 0) {
+ dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+ goto err;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies),
+ wm8741->supplies);
+ if (ret != 0) {
+ dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+ goto err_get;
+ }
+
+ i2c_set_clientdata(i2c, wm8741);
+ wm8741->control_type = SND_SOC_I2C;
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8741, &wm8741_dai, 1);
+ if (ret < 0)
+ goto err_enable;
+ return ret;
err_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
err_get:
regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
-
err:
kfree(wm8741);
return ret;
}
-static void wm8741_unregister(struct wm8741_priv *wm8741)
-{
- regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
-
- snd_soc_unregister_dai(&wm8741_dai);
- snd_soc_unregister_codec(&wm8741->codec);
- kfree(wm8741);
- wm8741_codec = NULL;
-}
-
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-static __devinit int wm8741_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
-{
- struct wm8741_priv *wm8741;
- struct snd_soc_codec *codec;
-
- wm8741 = kzalloc(sizeof(struct wm8741_priv), GFP_KERNEL);
- if (wm8741 == NULL)
- return -ENOMEM;
-
- codec = &wm8741->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
-
- i2c_set_clientdata(i2c, wm8741);
- codec->control_data = i2c;
-
- codec->dev = &i2c->dev;
-
- return wm8741_register(wm8741, SND_SOC_I2C);
-}
-
-static __devexit int wm8741_i2c_remove(struct i2c_client *client)
+static int wm8741_i2c_remove(struct i2c_client *client)
{
struct wm8741_priv *wm8741 = i2c_get_clientdata(client);
- wm8741_unregister(wm8741);
+
+ snd_soc_unregister_codec(&client->dev);
+ regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -540,29 +521,28 @@
};
MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id);
-
static struct i2c_driver wm8741_i2c_driver = {
.driver = {
- .name = "WM8741",
+ .name = "wm8741-codec",
.owner = THIS_MODULE,
},
.probe = wm8741_i2c_probe,
- .remove = __devexit_p(wm8741_i2c_remove),
+ .remove = wm8741_i2c_remove,
.id_table = wm8741_i2c_id,
};
#endif
static int __init wm8741_modinit(void)
{
- int ret;
+ int ret = 0;
+
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8741_i2c_driver);
- if (ret != 0) {
- printk(KERN_ERR "Failed to register WM8741 I2C driver: %d\n",
- ret);
- }
+ if (ret != 0)
+ pr_err("Failed to register WM8741 I2C driver: %d\n", ret);
#endif
- return 0;
+
+ return ret;
}
module_init(wm8741_modinit);
diff --git a/sound/soc/codecs/wm8741.h b/sound/soc/codecs/wm8741.h
index fdef6ec..56c1b1d 100644
--- a/sound/soc/codecs/wm8741.h
+++ b/sound/soc/codecs/wm8741.h
@@ -208,7 +208,4 @@
#define WM8741_SYSCLK 0
-extern struct snd_soc_dai wm8741_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8741;
-
#endif
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index e2c05e3..6c924cd 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -52,7 +52,7 @@
/* codec private data */
struct wm8750_priv {
unsigned int sysclk;
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
u16 reg_cache[ARRAY_SIZE(wm8750_reg)];
};
@@ -560,8 +560,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec);
u16 iface = snd_soc_read(codec, WM8750_IFACE) & 0x1f3;
u16 srate = snd_soc_read(codec, WM8750_SRATE) & 0x1c0;
@@ -649,8 +648,8 @@
.set_sysclk = wm8750_set_dai_sysclk,
};
-struct snd_soc_dai wm8750_dai = {
- .name = "WM8750",
+static struct snd_soc_dai_driver wm8750_dai = {
+ .name = "wm8750-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -665,21 +664,15 @@
.formats = WM8750_FORMATS,},
.ops = &wm8750_dai_ops,
};
-EXPORT_SYMBOL_GPL(wm8750_dai);
-static int wm8750_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8750_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8750_resume(struct platform_device *pdev)
+static int wm8750_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -698,100 +691,21 @@
return 0;
}
-static struct snd_soc_codec *wm8750_codec;
-
-static int wm8750_probe(struct platform_device *pdev)
+static int wm8750_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
+ struct wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec);
+ int reg, ret;
- if (!wm8750_codec) {
- dev_err(&pdev->dev, "WM8750 codec not yet registered\n");
- return -EINVAL;
- }
-
- socdev->card->codec = wm8750_codec;
- codec = wm8750_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "wm8750: failed to create pcms\n");
- goto err;
- }
-
- snd_soc_add_controls(codec, wm8750_snd_controls,
- ARRAY_SIZE(wm8750_snd_controls));
- wm8750_add_widgets(codec);
-
- return 0;
-
-err:
- return ret;
-}
-
-/* power down chip */
-static int wm8750_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8750 = {
- .probe = wm8750_probe,
- .remove = wm8750_remove,
- .suspend = wm8750_suspend,
- .resume = wm8750_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8750);
-
-/*
- * initialise the WM8750 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int wm8750_register(struct wm8750_priv *wm8750,
- enum snd_soc_control_type control)
-{
- struct snd_soc_codec *codec = &wm8750->codec;
- int reg, ret = 0;
-
- if (wm8750_codec) {
- dev_err(codec->dev, "Multiple WM8750 devices not supported\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->name = "WM8750";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_STANDBY;
- codec->set_bias_level = wm8750_set_bias_level;
- codec->dai = &wm8750_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(wm8750->reg_cache) + 1;
- codec->reg_cache = &wm8750->reg_cache;
- snd_soc_codec_set_drvdata(codec, wm8750);
-
- memcpy(codec->reg_cache, wm8750_reg, sizeof(wm8750->reg_cache));
-
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8750->control_type);
if (ret < 0) {
printk(KERN_ERR "wm8750: failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
ret = wm8750_reset(codec);
if (ret < 0) {
printk(KERN_ERR "wm8750: failed to reset: %d\n", ret);
- goto err;
+ return ret;
}
/* charge output caps */
@@ -815,150 +729,130 @@
reg = snd_soc_read(codec, WM8750_RINVOL);
snd_soc_write(codec, WM8750_RINVOL, reg | 0x0100);
- wm8750_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dais(&wm8750_dai, 1);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
- goto err_codec;
- }
-
- return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- kfree(wm8750);
+ snd_soc_add_controls(codec, wm8750_snd_controls,
+ ARRAY_SIZE(wm8750_snd_controls));
+ wm8750_add_widgets(codec);
return ret;
}
-static void wm8750_unregister(struct wm8750_priv *wm8750)
+static int wm8750_remove(struct snd_soc_codec *codec)
{
- wm8750_set_bias_level(&wm8750->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dais(&wm8750_dai, 1);
- snd_soc_unregister_codec(&wm8750->codec);
- kfree(wm8750);
- wm8750_codec = NULL;
+ wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
}
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static struct snd_soc_codec_driver soc_codec_dev_wm8750 = {
+ .probe = wm8750_probe,
+ .remove = wm8750_remove,
+ .suspend = wm8750_suspend,
+ .resume = wm8750_resume,
+ .set_bias_level = wm8750_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8750_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8750_reg,
+};
-/*
- * WM8750 2 wire address is determined by GPIO5
- * state during powerup.
- * low = 0x1a
- * high = 0x1b
- */
-
-static int wm8750_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8750_spi_probe(struct spi_device *spi)
{
- struct snd_soc_codec *codec;
struct wm8750_priv *wm8750;
+ int ret;
wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL);
if (wm8750 == NULL)
return -ENOMEM;
- codec = &wm8750->codec;
- codec->control_data = i2c;
- i2c_set_clientdata(i2c, wm8750);
+ wm8750->control_type = SND_SOC_SPI;
+ spi_set_drvdata(spi, wm8750);
- codec->dev = &i2c->dev;
-
- return wm8750_register(wm8750, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_wm8750, &wm8750_dai, 1);
+ if (ret < 0)
+ kfree(wm8750);
+ return ret;
}
-static int wm8750_i2c_remove(struct i2c_client *client)
+static int __devexit wm8750_spi_remove(struct spi_device *spi)
{
- struct wm8750_priv *wm8750 = i2c_get_clientdata(client);
- wm8750_unregister(wm8750);
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
+ return 0;
+}
+
+static struct spi_driver wm8750_spi_driver = {
+ .driver = {
+ .name = "wm8750-codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8750_spi_probe,
+ .remove = __devexit_p(wm8750_spi_remove),
+};
+#endif /* CONFIG_SPI_MASTER */
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8750_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8750_priv *wm8750;
+ int ret;
+
+ wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL);
+ if (wm8750 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, wm8750);
+ wm8750->control_type = SND_SOC_I2C;
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8750, &wm8750_dai, 1);
+ if (ret < 0)
+ kfree(wm8750);
+ return ret;
+}
+
+static __devexit int wm8750_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
static const struct i2c_device_id wm8750_i2c_id[] = {
{ "wm8750", 0 },
- { "wm8987", 0 }, /* WM8987 is register compatible with WM8750 */
+ { "wm8987", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id);
static struct i2c_driver wm8750_i2c_driver = {
.driver = {
- .name = "WM8750 I2C Codec",
+ .name = "wm8750-codec",
.owner = THIS_MODULE,
},
.probe = wm8750_i2c_probe,
- .remove = wm8750_i2c_remove,
+ .remove = __devexit_p(wm8750_i2c_remove),
.id_table = wm8750_i2c_id,
};
#endif
-#if defined(CONFIG_SPI_MASTER)
-static int __devinit wm8750_spi_probe(struct spi_device *spi)
-{
- struct snd_soc_codec *codec;
- struct wm8750_priv *wm8750;
-
- wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL);
- if (wm8750 == NULL)
- return -ENOMEM;
-
- codec = &wm8750->codec;
- codec->control_data = spi;
- codec->dev = &spi->dev;
-
- dev_set_drvdata(&spi->dev, wm8750);
-
- return wm8750_register(wm8750, SND_SOC_SPI);
-}
-
-static int __devexit wm8750_spi_remove(struct spi_device *spi)
-{
- struct wm8750_priv *wm8750 = dev_get_drvdata(&spi->dev);
- wm8750_unregister(wm8750);
- return 0;
-}
-
-static const struct spi_device_id wm8750_spi_id[] = {
- { "wm8750", 0 },
- { "wm8987", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(spi, wm8750_spi_id);
-
-static struct spi_driver wm8750_spi_driver = {
- .driver = {
- .name = "WM8750 SPI Codec",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
- },
- .probe = wm8750_spi_probe,
- .remove = __devexit_p(wm8750_spi_remove),
- .id_table = wm8750_spi_id,
-};
-#endif
-
static int __init wm8750_modinit(void)
{
- int ret;
+ int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8750_i2c_driver);
- if (ret != 0)
- pr_err("Failed to register WM8750 I2C driver: %d\n", ret);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8750 I2C driver: %d\n",
+ ret);
+ }
#endif
#if defined(CONFIG_SPI_MASTER)
ret = spi_register_driver(&wm8750_spi_driver);
- if (ret != 0)
- pr_err("Failed to register WM8750 SPI driver: %d\n", ret);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8750 SPI driver: %d\n",
+ ret);
+ }
#endif
- return 0;
+ return ret;
}
module_init(wm8750_modinit);
diff --git a/sound/soc/codecs/wm8750.h b/sound/soc/codecs/wm8750.h
index 1dc100e..121427c 100644
--- a/sound/soc/codecs/wm8750.h
+++ b/sound/soc/codecs/wm8750.h
@@ -57,13 +57,4 @@
#define WM8750_SYSCLK 0
-struct wm8750_setup_data {
- int spi;
- int i2c_bus;
- unsigned short i2c_address;
-};
-
-extern struct snd_soc_dai wm8750_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8750;
-
#endif
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index b59f349..8f679a1 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -57,7 +57,7 @@
MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)");
static void wm8753_set_dai_mode(struct snd_soc_codec *codec,
- unsigned int mode);
+ struct snd_soc_dai *dai, unsigned int hifi);
/*
* wm8753 register cache
@@ -85,10 +85,11 @@
/* codec private data */
struct wm8753_priv {
+ enum snd_soc_control_type control_type;
unsigned int sysclk;
unsigned int pcmclk;
- struct snd_soc_codec codec;
u16 reg_cache[ARRAY_SIZE(wm8753_reg)];
+ int dai_func;
};
/*
@@ -228,6 +229,7 @@
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
int mode = wm8753_read_reg_cache(codec, WM8753_IOCTL);
+ struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
if (((mode & 0xc) >> 2) == ucontrol->value.integer.value[0])
return 0;
@@ -235,8 +237,7 @@
mode &= 0xfff3;
mode |= (ucontrol->value.integer.value[0] << 2);
- wm8753_write(codec, WM8753_IOCTL, mode);
- wm8753_set_dai_mode(codec, ucontrol->value.integer.value[0]);
+ wm8753->dai_func = ucontrol->value.integer.value[0];
return 1;
}
@@ -904,6 +905,13 @@
return 0;
}
+static int wm8753_pcm_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ wm8753_set_dai_mode(dai->codec, dai, 0);
+ return 0;
+}
+
/*
* Set PCM DAI bit size and sample rate.
*/
@@ -912,8 +920,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01f3;
u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x017f;
@@ -1138,6 +1145,13 @@
return 0;
}
+static int wm8753_i2s_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ wm8753_set_dai_mode(dai->codec, dai, 1);
+ return 0;
+}
+
/*
* Set PCM DAI bit size and sample rate.
*/
@@ -1146,8 +1160,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x01c0;
u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01f3;
@@ -1240,12 +1253,12 @@
{
struct snd_soc_codec *codec = dai->codec;
u16 mute_reg = wm8753_read_reg_cache(codec, WM8753_DAC) & 0xfff7;
+ struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
/* the digital mute covers the HiFi and Voice DAC's on the WM8753.
* make sure we check if they are not both active when we mute */
- if (mute && dai->id == 1) {
- if (!wm8753_dai[WM8753_DAI_VOICE].playback.active ||
- !wm8753_dai[WM8753_DAI_HIFI].playback.active)
+ if (mute && wm8753->dai_func == 1) {
+ if (!codec->active)
wm8753_write(codec, WM8753_DAC, mute_reg | 0x8);
} else {
if (mute)
@@ -1303,6 +1316,7 @@
* 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture
*/
static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode1 = {
+ .startup = wm8753_i2s_startup,
.hw_params = wm8753_i2s_hw_params,
.digital_mute = wm8753_mute,
.set_fmt = wm8753_mode1h_set_dai_fmt,
@@ -1312,6 +1326,7 @@
};
static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode1 = {
+ .startup = wm8753_pcm_startup,
.hw_params = wm8753_pcm_hw_params,
.digital_mute = wm8753_mute,
.set_fmt = wm8753_mode1v_set_dai_fmt,
@@ -1321,6 +1336,7 @@
};
static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode2 = {
+ .startup = wm8753_pcm_startup,
.hw_params = wm8753_pcm_hw_params,
.digital_mute = wm8753_mute,
.set_fmt = wm8753_mode2_set_dai_fmt,
@@ -1330,6 +1346,7 @@
};
static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode3 = {
+ .startup = wm8753_i2s_startup,
.hw_params = wm8753_i2s_hw_params,
.digital_mute = wm8753_mute,
.set_fmt = wm8753_mode3_4_set_dai_fmt,
@@ -1339,6 +1356,7 @@
};
static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode4 = {
+ .startup = wm8753_i2s_startup,
.hw_params = wm8753_i2s_hw_params,
.digital_mute = wm8753_mute,
.set_fmt = wm8753_mode3_4_set_dai_fmt,
@@ -1347,10 +1365,9 @@
.set_sysclk = wm8753_set_dai_sysclk,
};
-static const struct snd_soc_dai wm8753_all_dai[] = {
+static struct snd_soc_dai_driver wm8753_all_dai[] = {
/* DAI HiFi mode 1 */
-{ .name = "WM8753 HiFi",
- .id = 1,
+{ .name = "wm8753-hifi",
.playback = {
.stream_name = "HiFi Playback",
.channels_min = 1,
@@ -1366,8 +1383,7 @@
.ops = &wm8753_dai_ops_hifi_mode1,
},
/* DAI Voice mode 1 */
-{ .name = "WM8753 Voice",
- .id = 1,
+{ .name = "wm8753-voice",
.playback = {
.stream_name = "Voice Playback",
.channels_min = 1,
@@ -1383,12 +1399,10 @@
.ops = &wm8753_dai_ops_voice_mode1,
},
/* DAI HiFi mode 2 - dummy */
-{ .name = "WM8753 HiFi",
- .id = 2,
+{ .name = "wm8753-hifi",
},
/* DAI Voice mode 2 */
-{ .name = "WM8753 Voice",
- .id = 2,
+{ .name = "wm8753-voice",
.playback = {
.stream_name = "Voice Playback",
.channels_min = 1,
@@ -1404,8 +1418,7 @@
.ops = &wm8753_dai_ops_voice_mode2,
},
/* DAI HiFi mode 3 */
-{ .name = "WM8753 HiFi",
- .id = 3,
+{ .name = "wm8753-hifi",
.playback = {
.stream_name = "HiFi Playback",
.channels_min = 1,
@@ -1421,12 +1434,10 @@
.ops = &wm8753_dai_ops_hifi_mode3,
},
/* DAI Voice mode 3 - dummy */
-{ .name = "WM8753 Voice",
- .id = 3,
+{ .name = "wm8753-voice",
},
/* DAI HiFi mode 4 */
-{ .name = "WM8753 HiFi",
- .id = 4,
+{ .name = "wm8753-hifi",
.playback = {
.stream_name = "HiFi Playback",
.channels_min = 1,
@@ -1442,58 +1453,31 @@
.ops = &wm8753_dai_ops_hifi_mode4,
},
/* DAI Voice mode 4 - dummy */
-{ .name = "WM8753 Voice",
- .id = 4,
+{ .name = "wm8753-voice",
},
};
-struct snd_soc_dai wm8753_dai[] = {
+static struct snd_soc_dai_driver wm8753_dai[] = {
{
- .name = "WM8753 DAI 0",
+ .name = "wm8753-aif0",
},
{
- .name = "WM8753 DAI 1",
+ .name = "wm8753-aif1",
},
};
-EXPORT_SYMBOL_GPL(wm8753_dai);
-static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode)
+static void wm8753_set_dai_mode(struct snd_soc_codec *codec,
+ struct snd_soc_dai *dai, unsigned int hifi)
{
- if (mode < 4) {
- int playback_active, capture_active, codec_active, pop_wait;
- void *private_data;
- struct list_head list;
+ struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
- playback_active = wm8753_dai[0].playback.active;
- capture_active = wm8753_dai[0].capture.active;
- codec_active = wm8753_dai[0].active;
- private_data = wm8753_dai[0].private_data;
- pop_wait = wm8753_dai[0].pop_wait;
- list = wm8753_dai[0].list;
- wm8753_dai[0] = wm8753_all_dai[mode << 1];
- wm8753_dai[0].playback.active = playback_active;
- wm8753_dai[0].capture.active = capture_active;
- wm8753_dai[0].active = codec_active;
- wm8753_dai[0].private_data = private_data;
- wm8753_dai[0].pop_wait = pop_wait;
- wm8753_dai[0].list = list;
-
- playback_active = wm8753_dai[1].playback.active;
- capture_active = wm8753_dai[1].capture.active;
- codec_active = wm8753_dai[1].active;
- private_data = wm8753_dai[1].private_data;
- pop_wait = wm8753_dai[1].pop_wait;
- list = wm8753_dai[1].list;
- wm8753_dai[1] = wm8753_all_dai[(mode << 1) + 1];
- wm8753_dai[1].playback.active = playback_active;
- wm8753_dai[1].capture.active = capture_active;
- wm8753_dai[1].active = codec_active;
- wm8753_dai[1].private_data = private_data;
- wm8753_dai[1].pop_wait = pop_wait;
- wm8753_dai[1].list = list;
+ if (wm8753->dai_func < 4) {
+ if (hifi)
+ dai->driver = &wm8753_all_dai[wm8753->dai_func << 1];
+ else
+ dai->driver = &wm8753_all_dai[(wm8753->dai_func << 1) + 1];
}
- wm8753_dai[0].codec = codec;
- wm8753_dai[1].codec = codec;
+ wm8753_write(codec, WM8753_IOCTL, wm8753->dai_func);
}
static void wm8753_work(struct work_struct *work)
@@ -1503,19 +1487,14 @@
wm8753_set_bias_level(codec, codec->bias_level);
}
-static int wm8753_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8753_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8753_resume(struct platform_device *pdev)
+static int wm8753_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -1547,41 +1526,6 @@
return 0;
}
-static struct snd_soc_codec *wm8753_codec;
-
-static int wm8753_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- if (!wm8753_codec) {
- dev_err(&pdev->dev, "WM8753 codec not yet registered\n");
- return -EINVAL;
- }
-
- socdev->card->codec = wm8753_codec;
- codec = wm8753_codec;
-
- wm8753_set_dai_mode(codec, 0);
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "wm8753: failed to create pcms\n");
- goto pcm_err;
- }
-
- snd_soc_add_controls(codec, wm8753_snd_controls,
- ARRAY_SIZE(wm8753_snd_controls));
- wm8753_add_widgets(codec);
-
- return 0;
-
-pcm_err:
- return ret;
-}
-
/*
* This function forces any delayed work to be queued and run.
*/
@@ -1601,62 +1545,28 @@
return ret;
}
-/* power down chip */
-static int wm8753_remove(struct platform_device *pdev)
+static int wm8753_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0, reg;
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8753 = {
- .probe = wm8753_probe,
- .remove = wm8753_remove,
- .suspend = wm8753_suspend,
- .resume = wm8753_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753);
-
-static int wm8753_register(struct wm8753_priv *wm8753)
-{
- int ret, i;
- struct snd_soc_codec *codec = &wm8753->codec;
- u16 reg;
-
- if (wm8753_codec) {
- dev_err(codec->dev, "Multiple WM8753 devices not supported\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->name = "WM8753";
- codec->owner = THIS_MODULE;
- codec->read = wm8753_read_reg_cache;
- codec->write = wm8753_write;
- codec->bias_level = SND_SOC_BIAS_STANDBY;
- codec->set_bias_level = wm8753_set_bias_level;
- codec->dai = wm8753_dai;
- codec->num_dai = 2;
- codec->reg_cache_size = ARRAY_SIZE(wm8753->reg_cache) + 1;
- codec->reg_cache = &wm8753->reg_cache;
- snd_soc_codec_set_drvdata(codec, wm8753);
-
- memcpy(codec->reg_cache, wm8753_reg, sizeof(wm8753->reg_cache));
INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8753->control_type);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
+
ret = wm8753_reset(codec);
if (ret < 0) {
- dev_err(codec->dev, "Failed to issue reset\n");
- goto err;
+ dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+ return ret;
}
+ wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ wm8753->dai_func = 0;
+
/* charge output caps */
wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
schedule_delayed_work(&codec->delayed_work,
@@ -1684,70 +1594,96 @@
reg = wm8753_read_reg_cache(codec, WM8753_RINVOL);
wm8753_write(codec, WM8753_RINVOL, reg | 0x0100);
- wm8753_codec = codec;
-
- for (i = 0; i < ARRAY_SIZE(wm8753_dai); i++)
- wm8753_dai[i].dev = codec->dev;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dais(&wm8753_dai[0], ARRAY_SIZE(wm8753_dai));
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
- goto err_codec;
- }
+ snd_soc_add_controls(codec, wm8753_snd_controls,
+ ARRAY_SIZE(wm8753_snd_controls));
+ wm8753_add_widgets(codec);
return 0;
+}
-err_codec:
+/* power down chip */
+static int wm8753_remove(struct snd_soc_codec *codec)
+{
run_delayed_work(&codec->delayed_work);
- snd_soc_unregister_codec(codec);
-err:
- kfree(wm8753);
- return ret;
+ wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
}
-static void wm8753_unregister(struct wm8753_priv *wm8753)
-{
- wm8753_set_bias_level(&wm8753->codec, SND_SOC_BIAS_OFF);
- run_delayed_work(&wm8753->codec.delayed_work);
- snd_soc_unregister_dais(&wm8753_dai[0], ARRAY_SIZE(wm8753_dai));
- snd_soc_unregister_codec(&wm8753->codec);
- kfree(wm8753);
- wm8753_codec = NULL;
-}
+static struct snd_soc_codec_driver soc_codec_dev_wm8753 = {
+ .probe = wm8753_probe,
+ .remove = wm8753_remove,
+ .suspend = wm8753_suspend,
+ .resume = wm8753_resume,
+ .set_bias_level = wm8753_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8753_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8753_reg,
+};
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-
-static int wm8753_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8753_spi_probe(struct spi_device *spi)
{
- struct snd_soc_codec *codec;
struct wm8753_priv *wm8753;
+ int ret;
wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL);
if (wm8753 == NULL)
return -ENOMEM;
- codec = &wm8753->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
- codec->control_data = i2c;
- i2c_set_clientdata(i2c, wm8753);
+ wm8753->control_type = SND_SOC_SPI;
+ spi_set_drvdata(spi, wm8753);
- codec->dev = &i2c->dev;
-
- return wm8753_register(wm8753);
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai));
+ if (ret < 0)
+ kfree(wm8753);
+ return ret;
}
-static int wm8753_i2c_remove(struct i2c_client *client)
+static int __devexit wm8753_spi_remove(struct spi_device *spi)
{
- struct wm8753_priv *wm8753 = i2c_get_clientdata(client);
- wm8753_unregister(wm8753);
- return 0;
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
+ return 0;
+}
+
+static struct spi_driver wm8753_spi_driver = {
+ .driver = {
+ .name = "wm8753-codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8753_spi_probe,
+ .remove = __devexit_p(wm8753_spi_remove),
+};
+#endif /* CONFIG_SPI_MASTER */
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8753_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8753_priv *wm8753;
+ int ret;
+
+ wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL);
+ if (wm8753 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, wm8753);
+ wm8753->control_type = SND_SOC_I2C;
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai));
+ if (ret < 0)
+ kfree(wm8753);
+ return ret;
+}
+
+static __devexit int wm8753_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
+ return 0;
}
static const struct i2c_device_id wm8753_i2c_id[] = {
@@ -1758,91 +1694,33 @@
static struct i2c_driver wm8753_i2c_driver = {
.driver = {
- .name = "wm8753",
+ .name = "wm8753-codec",
.owner = THIS_MODULE,
},
.probe = wm8753_i2c_probe,
- .remove = wm8753_i2c_remove,
+ .remove = __devexit_p(wm8753_i2c_remove),
.id_table = wm8753_i2c_id,
};
#endif
-#if defined(CONFIG_SPI_MASTER)
-static int wm8753_spi_write(struct spi_device *spi, const char *data, int len)
-{
- struct spi_transfer t;
- struct spi_message m;
- u8 msg[2];
-
- if (len <= 0)
- return 0;
-
- msg[0] = data[0];
- msg[1] = data[1];
-
- spi_message_init(&m);
- memset(&t, 0, (sizeof t));
-
- t.tx_buf = &msg[0];
- t.len = len;
-
- spi_message_add_tail(&t, &m);
- spi_sync(spi, &m);
-
- return len;
-}
-
-static int __devinit wm8753_spi_probe(struct spi_device *spi)
-{
- struct snd_soc_codec *codec;
- struct wm8753_priv *wm8753;
-
- wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL);
- if (wm8753 == NULL)
- return -ENOMEM;
-
- codec = &wm8753->codec;
- codec->control_data = spi;
- codec->hw_write = (hw_write_t)wm8753_spi_write;
- codec->dev = &spi->dev;
-
- dev_set_drvdata(&spi->dev, wm8753);
-
- return wm8753_register(wm8753);
-}
-
-static int __devexit wm8753_spi_remove(struct spi_device *spi)
-{
- struct wm8753_priv *wm8753 = dev_get_drvdata(&spi->dev);
- wm8753_unregister(wm8753);
- return 0;
-}
-
-static struct spi_driver wm8753_spi_driver = {
- .driver = {
- .name = "wm8753",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
- },
- .probe = wm8753_spi_probe,
- .remove = __devexit_p(wm8753_spi_remove),
-};
-#endif
-
static int __init wm8753_modinit(void)
{
- int ret;
+ int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8753_i2c_driver);
- if (ret != 0)
- pr_err("Failed to register WM8753 I2C driver: %d\n", ret);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8753 I2C driver: %d\n",
+ ret);
+ }
#endif
#if defined(CONFIG_SPI_MASTER)
ret = spi_register_driver(&wm8753_spi_driver);
- if (ret != 0)
- pr_err("Failed to register WM8753 SPI driver: %d\n", ret);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8753 SPI driver: %d\n",
+ ret);
+ }
#endif
- return 0;
+ return ret;
}
module_init(wm8753_modinit);
diff --git a/sound/soc/codecs/wm8753.h b/sound/soc/codecs/wm8753.h
index 57b2ba2..94edac1 100644
--- a/sound/soc/codecs/wm8753.h
+++ b/sound/soc/codecs/wm8753.h
@@ -115,7 +115,4 @@
#define WM8753_DAI_HIFI 0
#define WM8753_DAI_VOICE 1
-extern struct snd_soc_dai wm8753_dai[2];
-extern struct snd_soc_codec_device soc_codec_dev_wm8753;
-
#endif
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c
index f8154e6..04182c4 100644
--- a/sound/soc/codecs/wm8776.c
+++ b/sound/soc/codecs/wm8776.c
@@ -31,20 +31,13 @@
#include "wm8776.h"
-static struct snd_soc_codec *wm8776_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8776;
-
/* codec private data */
struct wm8776_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
u16 reg_cache[WM8776_CACHEREGNUM];
int sysclk[2];
};
-#ifdef CONFIG_SPI_MASTER
-static int wm8776_spi_write(struct spi_device *spi, const char *data, int len);
-#endif
-
static const u16 wm8776_reg[WM8776_CACHEREGNUM] = {
0x79, 0x79, 0x79, 0xff, 0xff, /* 4 */
0xff, 0x00, 0x90, 0x00, 0x00, /* 9 */
@@ -144,7 +137,7 @@
struct snd_soc_codec *codec = dai->codec;
int reg, iface, master;
- switch (dai->id) {
+ switch (dai->driver->id) {
case WM8776_DAI_DAC:
reg = WM8776_DACIFCTRL;
master = 0x80;
@@ -226,7 +219,7 @@
iface = 0;
- switch (dai->id) {
+ switch (dai->driver->id) {
case WM8776_DAI_DAC:
iface_reg = WM8776_DACIFCTRL;
master = 0x80;
@@ -260,7 +253,7 @@
/* Only need to set MCLK/LRCLK ratio if we're master */
if (snd_soc_read(codec, WM8776_MSTRCTRL) & master) {
for (i = 0; i < ARRAY_SIZE(mclk_ratios); i++) {
- if (wm8776->sysclk[dai->id] / params_rate(params)
+ if (wm8776->sysclk[dai->driver->id] / params_rate(params)
== mclk_ratios[i])
break;
}
@@ -268,7 +261,7 @@
if (i == ARRAY_SIZE(mclk_ratios)) {
dev_err(codec->dev,
"Unable to configure MCLK ratio %d/%d\n",
- wm8776->sysclk[dai->id], params_rate(params));
+ wm8776->sysclk[dai->driver->id], params_rate(params));
return -EINVAL;
}
@@ -298,9 +291,9 @@
struct snd_soc_codec *codec = dai->codec;
struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);
- BUG_ON(dai->id >= ARRAY_SIZE(wm8776->sysclk));
+ BUG_ON(dai->driver->id >= ARRAY_SIZE(wm8776->sysclk));
- wm8776->sysclk[dai->id] = freq;
+ wm8776->sysclk[dai->driver->id] = freq;
return 0;
}
@@ -350,10 +343,10 @@
.set_sysclk = wm8776_set_sysclk,
};
-struct snd_soc_dai wm8776_dai[] = {
+static struct snd_soc_dai_driver wm8776_dai[] = {
{
- .name = "WM8776 Playback",
- .id = WM8776_DAI_DAC,
+ .name = "wm8776-hifi-playback",
+ .id = WM8776_DAI_DAC,
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -364,8 +357,8 @@
.ops = &wm8776_dac_ops,
},
{
- .name = "WM8776 Capture",
- .id = WM8776_DAI_ADC,
+ .name = "wm8776-hifi-capture",
+ .id = WM8776_DAI_ADC,
.capture = {
.stream_name = "Capture",
.channels_min = 2,
@@ -376,23 +369,17 @@
.ops = &wm8776_adc_ops,
},
};
-EXPORT_SYMBOL_GPL(wm8776_dai);
#ifdef CONFIG_PM
-static int wm8776_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8776_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8776_resume(struct platform_device *pdev)
+static int wm8776_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -415,99 +402,21 @@
#define wm8776_resume NULL
#endif
-static int wm8776_probe(struct platform_device *pdev)
+static int wm8776_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
+ struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
- if (wm8776_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8776_codec;
- codec = wm8776_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- snd_soc_add_controls(codec, wm8776_snd_controls,
- ARRAY_SIZE(wm8776_snd_controls));
- snd_soc_dapm_new_controls(codec, wm8776_dapm_widgets,
- ARRAY_SIZE(wm8776_dapm_widgets));
- snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes));
-
- return ret;
-
-pcm_err:
- return ret;
-}
-
-/* power down chip */
-static int wm8776_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8776 = {
- .probe = wm8776_probe,
- .remove = wm8776_remove,
- .suspend = wm8776_suspend,
- .resume = wm8776_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8776);
-
-static int wm8776_register(struct wm8776_priv *wm8776,
- enum snd_soc_control_type control)
-{
- int ret, i;
- struct snd_soc_codec *codec = &wm8776->codec;
-
- if (wm8776_codec) {
- dev_err(codec->dev, "Another WM8776 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8776);
- codec->name = "WM8776";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8776_set_bias_level;
- codec->dai = wm8776_dai;
- codec->num_dai = ARRAY_SIZE(wm8776_dai);
- codec->reg_cache_size = WM8776_CACHEREGNUM;
- codec->reg_cache = &wm8776->reg_cache;
-
- memcpy(codec->reg_cache, wm8776_reg, sizeof(wm8776_reg));
-
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8776->control_type);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
- for (i = 0; i < ARRAY_SIZE(wm8776_dai); i++)
- wm8776_dai[i].dev = codec->dev;
-
ret = wm8776_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
- goto err;
+ return ret;
}
wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -517,95 +426,63 @@
snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100);
snd_soc_update_bits(codec, WM8776_DACRVOL, 0x100, 0x100);
- wm8776_codec = codec;
+ snd_soc_add_controls(codec, wm8776_snd_controls,
+ ARRAY_SIZE(wm8776_snd_controls));
+ snd_soc_dapm_new_controls(codec, wm8776_dapm_widgets,
+ ARRAY_SIZE(wm8776_dapm_widgets));
+ snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes));
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dais(wm8776_dai, ARRAY_SIZE(wm8776_dai));
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
- goto err_codec;
- }
-
- return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- kfree(wm8776);
return ret;
}
-static void wm8776_unregister(struct wm8776_priv *wm8776)
+/* power down chip */
+static int wm8776_remove(struct snd_soc_codec *codec)
{
- wm8776_set_bias_level(&wm8776->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dais(wm8776_dai, ARRAY_SIZE(wm8776_dai));
- snd_soc_unregister_codec(&wm8776->codec);
- kfree(wm8776);
- wm8776_codec = NULL;
+ wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_wm8776 = {
+ .probe = wm8776_probe,
+ .remove = wm8776_remove,
+ .suspend = wm8776_suspend,
+ .resume = wm8776_resume,
+ .set_bias_level = wm8776_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8776_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8776_reg,
+};
+
#if defined(CONFIG_SPI_MASTER)
-static int wm8776_spi_write(struct spi_device *spi, const char *data, int len)
-{
- struct spi_transfer t;
- struct spi_message m;
- u8 msg[2];
-
- if (len <= 0)
- return 0;
-
- msg[0] = data[0];
- msg[1] = data[1];
-
- spi_message_init(&m);
- memset(&t, 0, (sizeof t));
-
- t.tx_buf = &msg[0];
- t.len = len;
-
- spi_message_add_tail(&t, &m);
- spi_sync(spi, &m);
-
- return len;
-}
-
static int __devinit wm8776_spi_probe(struct spi_device *spi)
{
- struct snd_soc_codec *codec;
struct wm8776_priv *wm8776;
+ int ret;
wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL);
if (wm8776 == NULL)
return -ENOMEM;
- codec = &wm8776->codec;
- codec->control_data = spi;
- codec->hw_write = (hw_write_t)wm8776_spi_write;
- codec->dev = &spi->dev;
+ wm8776->control_type = SND_SOC_SPI;
+ spi_set_drvdata(spi, wm8776);
- dev_set_drvdata(&spi->dev, wm8776);
-
- return wm8776_register(wm8776, SND_SOC_SPI);
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai));
+ if (ret < 0)
+ kfree(wm8776);
+ return ret;
}
static int __devexit wm8776_spi_remove(struct spi_device *spi)
{
- struct wm8776_priv *wm8776 = dev_get_drvdata(&spi->dev);
-
- wm8776_unregister(wm8776);
-
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
return 0;
}
static struct spi_driver wm8776_spi_driver = {
.driver = {
- .name = "wm8776",
- .bus = &spi_bus_type,
+ .name = "wm8776-codec",
.owner = THIS_MODULE,
},
.probe = wm8776_spi_probe,
@@ -618,27 +495,26 @@
const struct i2c_device_id *id)
{
struct wm8776_priv *wm8776;
- struct snd_soc_codec *codec;
+ int ret;
wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL);
if (wm8776 == NULL)
return -ENOMEM;
- codec = &wm8776->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
-
i2c_set_clientdata(i2c, wm8776);
- codec->control_data = i2c;
+ wm8776->control_type = SND_SOC_I2C;
- codec->dev = &i2c->dev;
-
- return wm8776_register(wm8776, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai));
+ if (ret < 0)
+ kfree(wm8776);
+ return ret;
}
static __devexit int wm8776_i2c_remove(struct i2c_client *client)
{
- struct wm8776_priv *wm8776 = i2c_get_clientdata(client);
- wm8776_unregister(wm8776);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -650,7 +526,7 @@
static struct i2c_driver wm8776_i2c_driver = {
.driver = {
- .name = "wm8776",
+ .name = "wm8776-codec",
.owner = THIS_MODULE,
},
.probe = wm8776_i2c_probe,
@@ -661,22 +537,22 @@
static int __init wm8776_modinit(void)
{
- int ret;
+ int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8776_i2c_driver);
if (ret != 0) {
- printk(KERN_ERR "Failed to register WM8776 I2C driver: %d\n",
+ printk(KERN_ERR "Failed to register wm8776 I2C driver: %d\n",
ret);
}
#endif
#if defined(CONFIG_SPI_MASTER)
ret = spi_register_driver(&wm8776_spi_driver);
if (ret != 0) {
- printk(KERN_ERR "Failed to register WM8776 SPI driver: %d\n",
+ printk(KERN_ERR "Failed to register wm8776 SPI driver: %d\n",
ret);
}
#endif
- return 0;
+ return ret;
}
module_init(wm8776_modinit);
diff --git a/sound/soc/codecs/wm8776.h b/sound/soc/codecs/wm8776.h
index 6606d25..4cf1c8e 100644
--- a/sound/soc/codecs/wm8776.h
+++ b/sound/soc/codecs/wm8776.h
@@ -45,7 +45,4 @@
#define WM8776_DAI_DAC 0
#define WM8776_DAI_ADC 1
-extern struct snd_soc_dai wm8776_dai[];
-extern struct snd_soc_codec_device soc_codec_dev_wm8776;
-
#endif
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
new file mode 100644
index 0000000..4599e8e
--- /dev/null
+++ b/sound/soc/codecs/wm8804.c
@@ -0,0 +1,833 @@
+/*
+ * wm8804.c -- WM8804 S/PDIF transceiver driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *
+ * 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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8804.h"
+
+#define WM8804_NUM_SUPPLIES 2
+static const char *wm8804_supply_names[WM8804_NUM_SUPPLIES] = {
+ "PVDD",
+ "DVDD"
+};
+
+static const u8 wm8804_reg_defs[] = {
+ 0x05, /* R0 - RST/DEVID1 */
+ 0x88, /* R1 - DEVID2 */
+ 0x04, /* R2 - DEVREV */
+ 0x21, /* R3 - PLL1 */
+ 0xFD, /* R4 - PLL2 */
+ 0x36, /* R5 - PLL3 */
+ 0x07, /* R6 - PLL4 */
+ 0x16, /* R7 - PLL5 */
+ 0x18, /* R8 - PLL6 */
+ 0xFF, /* R9 - SPDMODE */
+ 0x00, /* R10 - INTMASK */
+ 0x00, /* R11 - INTSTAT */
+ 0x00, /* R12 - SPDSTAT */
+ 0x00, /* R13 - RXCHAN1 */
+ 0x00, /* R14 - RXCHAN2 */
+ 0x00, /* R15 - RXCHAN3 */
+ 0x00, /* R16 - RXCHAN4 */
+ 0x00, /* R17 - RXCHAN5 */
+ 0x00, /* R18 - SPDTX1 */
+ 0x00, /* R19 - SPDTX2 */
+ 0x00, /* R20 - SPDTX3 */
+ 0x71, /* R21 - SPDTX4 */
+ 0x0B, /* R22 - SPDTX5 */
+ 0x70, /* R23 - GPO0 */
+ 0x57, /* R24 - GPO1 */
+ 0x00, /* R25 */
+ 0x42, /* R26 - GPO2 */
+ 0x06, /* R27 - AIFTX */
+ 0x06, /* R28 - AIFRX */
+ 0x80, /* R29 - SPDRX1 */
+ 0x07, /* R30 - PWRDN */
+};
+
+struct wm8804_priv {
+ enum snd_soc_control_type control_type;
+ struct regulator_bulk_data supplies[WM8804_NUM_SUPPLIES];
+ struct notifier_block disable_nb[WM8804_NUM_SUPPLIES];
+ struct snd_soc_codec *codec;
+};
+
+static int txsrc_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+
+static int txsrc_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+
+/*
+ * We can't use the same notifier block for more than one supply and
+ * there's no way I can see to get from a callback to the caller
+ * except container_of().
+ */
+#define WM8804_REGULATOR_EVENT(n) \
+static int wm8804_regulator_event_##n(struct notifier_block *nb, \
+ unsigned long event, void *data) \
+{ \
+ struct wm8804_priv *wm8804 = container_of(nb, struct wm8804_priv, \
+ disable_nb[n]); \
+ if (event & REGULATOR_EVENT_DISABLE) { \
+ wm8804->codec->cache_sync = 1; \
+ } \
+ return 0; \
+}
+
+WM8804_REGULATOR_EVENT(0)
+WM8804_REGULATOR_EVENT(1)
+
+static const char *txsrc_text[] = { "S/PDIF RX", "AIF" };
+static const SOC_ENUM_SINGLE_EXT_DECL(txsrc, txsrc_text);
+
+static const struct snd_kcontrol_new wm8804_snd_controls[] = {
+ SOC_ENUM_EXT("Input Source", txsrc, txsrc_get, txsrc_put),
+ SOC_SINGLE("TX Playback Switch", WM8804_PWRDN, 2, 1, 1),
+ SOC_SINGLE("AIF Playback Switch", WM8804_PWRDN, 4, 1, 1)
+};
+
+static int txsrc_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec;
+ unsigned int src;
+
+ codec = snd_kcontrol_chip(kcontrol);
+ src = snd_soc_read(codec, WM8804_SPDTX4);
+ if (src & 0x40)
+ ucontrol->value.integer.value[0] = 1;
+ else
+ ucontrol->value.integer.value[0] = 0;
+
+ return 0;
+}
+
+static int txsrc_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec;
+ unsigned int src, txpwr;
+
+ codec = snd_kcontrol_chip(kcontrol);
+
+ if (ucontrol->value.integer.value[0] != 0
+ && ucontrol->value.integer.value[0] != 1)
+ return -EINVAL;
+
+ src = snd_soc_read(codec, WM8804_SPDTX4);
+ switch ((src & 0x40) >> 6) {
+ case 0:
+ if (!ucontrol->value.integer.value[0])
+ return 0;
+ break;
+ case 1:
+ if (ucontrol->value.integer.value[1])
+ return 0;
+ break;
+ }
+
+ /* save the current power state of the transmitter */
+ txpwr = snd_soc_read(codec, WM8804_PWRDN) & 0x4;
+ /* power down the transmitter */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x4);
+ /* set the tx source */
+ snd_soc_update_bits(codec, WM8804_SPDTX4, 0x40,
+ ucontrol->value.integer.value[0] << 6);
+
+ if (ucontrol->value.integer.value[0]) {
+ /* power down the receiver */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x2, 0x2);
+ /* power up the AIF */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x10, 0);
+ } else {
+ /* don't power down the AIF -- may be used as an output */
+ /* power up the receiver */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x2, 0);
+ }
+
+ /* restore the transmitter's configuration */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, txpwr);
+
+ return 0;
+}
+
+static int wm8804_volatile(unsigned int reg)
+{
+ switch (reg) {
+ case WM8804_RST_DEVID1:
+ case WM8804_DEVID2:
+ case WM8804_DEVREV:
+ case WM8804_INTSTAT:
+ case WM8804_SPDSTAT:
+ case WM8804_RXCHAN1:
+ case WM8804_RXCHAN2:
+ case WM8804_RXCHAN3:
+ case WM8804_RXCHAN4:
+ case WM8804_RXCHAN5:
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int wm8804_reset(struct snd_soc_codec *codec)
+{
+ return snd_soc_write(codec, WM8804_RST_DEVID1, 0x0);
+}
+
+static int wm8804_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec;
+ u16 format, master, bcp, lrp;
+
+ codec = dai->codec;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ format = 0x2;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ format = 0x0;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ format = 0x1;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_DSP_B:
+ format = 0x3;
+ break;
+ default:
+ dev_err(dai->dev, "Unknown dai format\n");
+ return -EINVAL;
+ }
+
+ /* set data format */
+ snd_soc_update_bits(codec, WM8804_AIFTX, 0x3, format);
+ snd_soc_update_bits(codec, WM8804_AIFRX, 0x3, format);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ master = 1;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ master = 0;
+ break;
+ default:
+ dev_err(dai->dev, "Unknown master/slave configuration\n");
+ return -EINVAL;
+ }
+
+ /* set master/slave mode */
+ snd_soc_update_bits(codec, WM8804_AIFRX, 0x40, master << 6);
+
+ bcp = lrp = 0;
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ bcp = lrp = 1;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ bcp = 1;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ lrp = 1;
+ break;
+ default:
+ dev_err(dai->dev, "Unknown polarity configuration\n");
+ return -EINVAL;
+ }
+
+ /* set frame inversion */
+ snd_soc_update_bits(codec, WM8804_AIFTX, 0x10 | 0x20,
+ (bcp << 4) | (lrp << 5));
+ snd_soc_update_bits(codec, WM8804_AIFRX, 0x10 | 0x20,
+ (bcp << 4) | (lrp << 5));
+ return 0;
+}
+
+static int wm8804_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec;
+ u16 blen;
+
+ codec = dai->codec;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ blen = 0x0;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ blen = 0x1;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ blen = 0x2;
+ break;
+ default:
+ dev_err(dai->dev, "Unsupported word length: %u\n",
+ params_format(params));
+ return -EINVAL;
+ }
+
+ /* set word length */
+ snd_soc_update_bits(codec, WM8804_AIFTX, 0xc, blen << 2);
+ snd_soc_update_bits(codec, WM8804_AIFRX, 0xc, blen << 2);
+
+ return 0;
+}
+
+struct pll_div {
+ u32 prescale:1;
+ u32 mclkdiv:1;
+ u32 freqmode:2;
+ u32 n:4;
+ u32 k:22;
+};
+
+/* PLL rate to output rate divisions */
+static struct {
+ unsigned int div;
+ unsigned int freqmode;
+ unsigned int mclkdiv;
+} post_table[] = {
+ { 2, 0, 0 },
+ { 4, 0, 1 },
+ { 4, 1, 0 },
+ { 8, 1, 1 },
+ { 8, 2, 0 },
+ { 16, 2, 1 },
+ { 12, 3, 0 },
+ { 24, 3, 1 }
+};
+
+#define FIXED_PLL_SIZE ((1ULL << 22) * 10)
+static int pll_factors(struct pll_div *pll_div, unsigned int target,
+ unsigned int source)
+{
+ u64 Kpart;
+ unsigned long int K, Ndiv, Nmod, tmp;
+ int i;
+
+ /*
+ * Scale the output frequency up; the PLL should run in the
+ * region of 90-100MHz.
+ */
+ for (i = 0; i < ARRAY_SIZE(post_table); i++) {
+ tmp = target * post_table[i].div;
+ if (tmp >= 90000000 && tmp <= 100000000) {
+ pll_div->freqmode = post_table[i].freqmode;
+ pll_div->mclkdiv = post_table[i].mclkdiv;
+ target *= post_table[i].div;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(post_table)) {
+ pr_err("%s: Unable to scale output frequency: %uHz\n",
+ __func__, target);
+ return -EINVAL;
+ }
+
+ pll_div->prescale = 0;
+ Ndiv = target / source;
+ if (Ndiv < 5) {
+ source >>= 1;
+ pll_div->prescale = 1;
+ Ndiv = target / source;
+ }
+
+ if (Ndiv < 5 || Ndiv > 13) {
+ pr_err("%s: WM8804 N value is not within the recommended range: %lu\n",
+ __func__, Ndiv);
+ return -EINVAL;
+ }
+ pll_div->n = Ndiv;
+
+ Nmod = target % source;
+ Kpart = FIXED_PLL_SIZE * (u64)Nmod;
+
+ do_div(Kpart, source);
+
+ K = Kpart & 0xffffffff;
+ if ((K % 10) >= 5)
+ K += 5;
+ K /= 10;
+ pll_div->k = K;
+
+ return 0;
+}
+
+static int wm8804_set_pll(struct snd_soc_dai *dai, int pll_id,
+ int source, unsigned int freq_in,
+ unsigned int freq_out)
+{
+ struct snd_soc_codec *codec;
+
+ codec = dai->codec;
+ if (!freq_in || !freq_out) {
+ /* disable the PLL */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0x1);
+ return 0;
+ } else {
+ int ret;
+ struct pll_div pll_div;
+
+ ret = pll_factors(&pll_div, freq_out, freq_in);
+ if (ret)
+ return ret;
+
+ /* power down the PLL before reprogramming it */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0x1);
+
+ if (!freq_in || !freq_out)
+ return 0;
+
+ /* set PLLN and PRESCALE */
+ snd_soc_update_bits(codec, WM8804_PLL4, 0xf | 0x10,
+ pll_div.n | (pll_div.prescale << 4));
+ /* set mclkdiv and freqmode */
+ snd_soc_update_bits(codec, WM8804_PLL5, 0x3 | 0x8,
+ pll_div.freqmode | (pll_div.mclkdiv << 3));
+ /* set PLLK */
+ snd_soc_write(codec, WM8804_PLL1, pll_div.k & 0xff);
+ snd_soc_write(codec, WM8804_PLL2, (pll_div.k >> 8) & 0xff);
+ snd_soc_write(codec, WM8804_PLL3, pll_div.k >> 16);
+
+ /* power up the PLL */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0);
+ }
+
+ return 0;
+}
+
+static int wm8804_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec;
+
+ codec = dai->codec;
+
+ switch (clk_id) {
+ case WM8804_TX_CLKSRC_MCLK:
+ if ((freq >= 10000000 && freq <= 14400000)
+ || (freq >= 16280000 && freq <= 27000000))
+ snd_soc_update_bits(codec, WM8804_PLL6, 0x80, 0x80);
+ else {
+ dev_err(dai->dev, "OSCCLOCK is not within the "
+ "recommended range: %uHz\n", freq);
+ return -EINVAL;
+ }
+ break;
+ case WM8804_TX_CLKSRC_PLL:
+ snd_soc_update_bits(codec, WM8804_PLL6, 0x80, 0);
+ break;
+ case WM8804_CLKOUT_SRC_CLK1:
+ snd_soc_update_bits(codec, WM8804_PLL6, 0x8, 0);
+ break;
+ case WM8804_CLKOUT_SRC_OSCCLK:
+ snd_soc_update_bits(codec, WM8804_PLL6, 0x8, 0x8);
+ break;
+ default:
+ dev_err(dai->dev, "Unknown clock source: %d\n", clk_id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int wm8804_set_clkdiv(struct snd_soc_dai *dai,
+ int div_id, int div)
+{
+ struct snd_soc_codec *codec;
+
+ codec = dai->codec;
+ switch (div_id) {
+ case WM8804_CLKOUT_DIV:
+ snd_soc_update_bits(codec, WM8804_PLL5, 0x30,
+ (div & 0x3) << 4);
+ break;
+ default:
+ dev_err(dai->dev, "Unknown clock divider: %d\n", div_id);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void wm8804_sync_cache(struct snd_soc_codec *codec)
+{
+ short i;
+ u8 *cache;
+
+ if (!codec->cache_sync)
+ return;
+
+ codec->cache_only = 0;
+ cache = codec->reg_cache;
+ for (i = 0; i < codec->driver->reg_cache_size; i++) {
+ if (i == WM8804_RST_DEVID1 || cache[i] == wm8804_reg_defs[i])
+ continue;
+ snd_soc_write(codec, i, cache[i]);
+ }
+ codec->cache_sync = 0;
+}
+
+static int wm8804_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ int ret;
+ struct wm8804_priv *wm8804;
+
+ wm8804 = snd_soc_codec_get_drvdata(codec);
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ /* power up the OSC and the PLL */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0);
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->bias_level == SND_SOC_BIAS_OFF) {
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies),
+ wm8804->supplies);
+ if (ret) {
+ dev_err(codec->dev,
+ "Failed to enable supplies: %d\n",
+ ret);
+ return ret;
+ }
+ wm8804_sync_cache(codec);
+ }
+ /* power down the OSC and the PLL */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0x9);
+ break;
+ case SND_SOC_BIAS_OFF:
+ /* power down the OSC and the PLL */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0x9);
+ regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies),
+ wm8804->supplies);
+ break;
+ }
+
+ codec->bias_level = level;
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int wm8804_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+ wm8804_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static int wm8804_resume(struct snd_soc_codec *codec)
+{
+ wm8804_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ return 0;
+}
+#else
+#define wm8804_suspend NULL
+#define wm8804_resume NULL
+#endif
+
+static int wm8804_remove(struct snd_soc_codec *codec)
+{
+ struct wm8804_priv *wm8804;
+ int i;
+
+ wm8804 = snd_soc_codec_get_drvdata(codec);
+ wm8804_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i)
+ regulator_unregister_notifier(wm8804->supplies[i].consumer,
+ &wm8804->disable_nb[i]);
+ regulator_bulk_free(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
+ return 0;
+}
+
+static int wm8804_probe(struct snd_soc_codec *codec)
+{
+ struct wm8804_priv *wm8804;
+ int i, id1, id2, ret;
+
+ wm8804 = snd_soc_codec_get_drvdata(codec);
+ wm8804->codec = codec;
+
+ codec->idle_bias_off = 1;
+
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, wm8804->control_type);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++)
+ wm8804->supplies[i].supply = wm8804_supply_names[i];
+
+ ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8804->supplies),
+ wm8804->supplies);
+ if (ret) {
+ dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+ return ret;
+ }
+
+ wm8804->disable_nb[0].notifier_call = wm8804_regulator_event_0;
+ wm8804->disable_nb[1].notifier_call = wm8804_regulator_event_1;
+
+ /* This should really be moved into the regulator core */
+ for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) {
+ ret = regulator_register_notifier(wm8804->supplies[i].consumer,
+ &wm8804->disable_nb[i]);
+ if (ret != 0) {
+ dev_err(codec->dev,
+ "Failed to register regulator notifier: %d\n",
+ ret);
+ }
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies),
+ wm8804->supplies);
+ if (ret) {
+ dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+ goto err_reg_get;
+ }
+
+ id1 = snd_soc_read(codec, WM8804_RST_DEVID1);
+ if (id1 < 0) {
+ dev_err(codec->dev, "Failed to read device ID: %d\n", id1);
+ ret = id1;
+ goto err_reg_enable;
+ }
+
+ id2 = snd_soc_read(codec, WM8804_DEVID2);
+ if (id2 < 0) {
+ dev_err(codec->dev, "Failed to read device ID: %d\n", id2);
+ ret = id2;
+ goto err_reg_enable;
+ }
+
+ id2 = (id2 << 8) | id1;
+
+ if (id2 != ((wm8804_reg_defs[WM8804_DEVID2] << 8)
+ | wm8804_reg_defs[WM8804_RST_DEVID1])) {
+ dev_err(codec->dev, "Invalid device ID: %#x\n", id2);
+ ret = -EINVAL;
+ goto err_reg_enable;
+ }
+
+ ret = snd_soc_read(codec, WM8804_DEVREV);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to read device revision: %d\n",
+ ret);
+ goto err_reg_enable;
+ }
+ dev_info(codec->dev, "revision %c\n", ret + 'A');
+
+ ret = wm8804_reset(codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+ goto err_reg_enable;
+ }
+
+ wm8804_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ snd_soc_add_controls(codec, wm8804_snd_controls,
+ ARRAY_SIZE(wm8804_snd_controls));
+ return 0;
+
+err_reg_enable:
+ regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
+err_reg_get:
+ regulator_bulk_free(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
+ return ret;
+}
+
+static struct snd_soc_dai_ops wm8804_dai_ops = {
+ .hw_params = wm8804_hw_params,
+ .set_fmt = wm8804_set_fmt,
+ .set_sysclk = wm8804_set_sysclk,
+ .set_clkdiv = wm8804_set_clkdiv,
+ .set_pll = wm8804_set_pll
+};
+
+#define WM8804_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_driver wm8804_dai = {
+ .name = "wm8804-spdif",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = WM8804_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = WM8804_FORMATS,
+ },
+ .ops = &wm8804_dai_ops,
+ .symmetric_rates = 1
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
+ .probe = wm8804_probe,
+ .remove = wm8804_remove,
+ .suspend = wm8804_suspend,
+ .resume = wm8804_resume,
+ .set_bias_level = wm8804_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8804_reg_defs),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = wm8804_reg_defs,
+ .volatile_register = wm8804_volatile
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8804_spi_probe(struct spi_device *spi)
+{
+ struct wm8804_priv *wm8804;
+ int ret;
+
+ wm8804 = kzalloc(sizeof *wm8804, GFP_KERNEL);
+ if (!wm8804)
+ return -ENOMEM;
+
+ wm8804->control_type = SND_SOC_SPI;
+ spi_set_drvdata(spi, wm8804);
+
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_wm8804, &wm8804_dai, 1);
+ if (ret < 0)
+ kfree(wm8804);
+ return ret;
+}
+
+static int __devexit wm8804_spi_remove(struct spi_device *spi)
+{
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
+ return 0;
+}
+
+static struct spi_driver wm8804_spi_driver = {
+ .driver = {
+ .name = "wm8804",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8804_spi_probe,
+ .remove = __devexit_p(wm8804_spi_remove)
+};
+#endif
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8804_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8804_priv *wm8804;
+ int ret;
+
+ wm8804 = kzalloc(sizeof *wm8804, GFP_KERNEL);
+ if (!wm8804)
+ return -ENOMEM;
+
+ wm8804->control_type = SND_SOC_I2C;
+ i2c_set_clientdata(i2c, wm8804);
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8804, &wm8804_dai, 1);
+ if (ret < 0)
+ kfree(wm8804);
+ return ret;
+}
+
+static __devexit int wm8804_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+static const struct i2c_device_id wm8804_i2c_id[] = {
+ { "wm8804", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8804_i2c_id);
+
+static struct i2c_driver wm8804_i2c_driver = {
+ .driver = {
+ .name = "wm8804",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8804_i2c_probe,
+ .remove = __devexit_p(wm8804_i2c_remove),
+ .id_table = wm8804_i2c_id
+};
+#endif
+
+static int __init wm8804_modinit(void)
+{
+ int ret = 0;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8804_i2c_driver);
+ if (ret) {
+ printk(KERN_ERR "Failed to register wm8804 I2C driver: %d\n",
+ ret);
+ }
+#endif
+#if defined(CONFIG_SPI_MASTER)
+ ret = spi_register_driver(&wm8804_spi_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8804 SPI driver: %d\n",
+ ret);
+ }
+#endif
+ return ret;
+}
+module_init(wm8804_modinit);
+
+static void __exit wm8804_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&wm8804_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+ spi_unregister_driver(&wm8804_spi_driver);
+#endif
+}
+module_exit(wm8804_exit);
+
+MODULE_DESCRIPTION("ASoC WM8804 driver");
+MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8804.h b/sound/soc/codecs/wm8804.h
new file mode 100644
index 0000000..8ec14f5
--- /dev/null
+++ b/sound/soc/codecs/wm8804.h
@@ -0,0 +1,61 @@
+/*
+ * wm8804.h -- WM8804 S/PDIF transceiver driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *
+ * 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 _WM8804_H
+#define _WM8804_H
+
+/*
+ * Register values.
+ */
+#define WM8804_RST_DEVID1 0x00
+#define WM8804_DEVID2 0x01
+#define WM8804_DEVREV 0x02
+#define WM8804_PLL1 0x03
+#define WM8804_PLL2 0x04
+#define WM8804_PLL3 0x05
+#define WM8804_PLL4 0x06
+#define WM8804_PLL5 0x07
+#define WM8804_PLL6 0x08
+#define WM8804_SPDMODE 0x09
+#define WM8804_INTMASK 0x0A
+#define WM8804_INTSTAT 0x0B
+#define WM8804_SPDSTAT 0x0C
+#define WM8804_RXCHAN1 0x0D
+#define WM8804_RXCHAN2 0x0E
+#define WM8804_RXCHAN3 0x0F
+#define WM8804_RXCHAN4 0x10
+#define WM8804_RXCHAN5 0x11
+#define WM8804_SPDTX1 0x12
+#define WM8804_SPDTX2 0x13
+#define WM8804_SPDTX3 0x14
+#define WM8804_SPDTX4 0x15
+#define WM8804_SPDTX5 0x16
+#define WM8804_GPO0 0x17
+#define WM8804_GPO1 0x18
+#define WM8804_GPO2 0x1A
+#define WM8804_AIFTX 0x1B
+#define WM8804_AIFRX 0x1C
+#define WM8804_SPDRX1 0x1D
+#define WM8804_PWRDN 0x1E
+
+#define WM8804_REGISTER_COUNT 30
+#define WM8804_MAX_REGISTER 0x1E
+
+#define WM8804_TX_CLKSRC_MCLK 1
+#define WM8804_TX_CLKSRC_PLL 2
+
+#define WM8804_CLKOUT_SRC_CLK1 3
+#define WM8804_CLKOUT_SRC_OSCCLK 4
+
+#define WM8804_CLKOUT_DIV 1
+
+#endif /* _WM8804_H */
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index 5da17a7..b4f1172 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -23,6 +23,7 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
+#include <linux/spi/spi.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <sound/core.h>
@@ -137,11 +138,8 @@
#define WM8900_LRC_MASK 0xfc00
-struct snd_soc_codec_device soc_codec_dev_wm8900;
-
struct wm8900_priv {
- struct snd_soc_codec codec;
-
+ enum snd_soc_control_type control_type;
u16 reg_cache[WM8900_MAXREG];
u32 fll_in; /* FLL input frequency */
@@ -627,8 +625,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
u16 reg;
reg = snd_soc_read(codec, WM8900_REG_AUDIO1) & ~0x60;
@@ -1015,8 +1012,8 @@
.digital_mute = wm8900_digital_mute,
};
-struct snd_soc_dai wm8900_dai = {
- .name = "WM8900 HiFi",
+static struct snd_soc_dai_driver wm8900_dai = {
+ .name = "wm8900-hifi",
.playback = {
.stream_name = "HiFi Playback",
.channels_min = 1,
@@ -1033,7 +1030,6 @@
},
.ops = &wm8900_dai_ops,
};
-EXPORT_SYMBOL_GPL(wm8900_dai);
static int wm8900_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
@@ -1128,10 +1124,8 @@
return 0;
}
-static int wm8900_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8900_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
int fll_out = wm8900->fll_out;
int fll_in = wm8900->fll_in;
@@ -1140,7 +1134,7 @@
/* Stop the FLL in an orderly fashion */
ret = wm8900_set_fll(codec, 0, 0, 0);
if (ret != 0) {
- dev_err(&pdev->dev, "Failed to stop FLL\n");
+ dev_err(codec->dev, "Failed to stop FLL\n");
return ret;
}
@@ -1152,10 +1146,8 @@
return 0;
}
-static int wm8900_resume(struct platform_device *pdev)
+static int wm8900_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
u16 *cache;
int i, ret;
@@ -1176,7 +1168,7 @@
ret = wm8900_set_fll(codec, 0, fll_in, fll_out);
if (ret != 0) {
- dev_err(&pdev->dev, "Failed to restart FLL\n");
+ dev_err(codec->dev, "Failed to restart FLL\n");
return ret;
}
}
@@ -1186,60 +1178,32 @@
snd_soc_write(codec, i, cache[i]);
kfree(cache);
} else
- dev_err(&pdev->dev, "Unable to allocate register cache\n");
+ dev_err(codec->dev, "Unable to allocate register cache\n");
return 0;
}
-static struct snd_soc_codec *wm8900_codec;
-
-static __devinit int wm8900_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int wm8900_probe(struct snd_soc_codec *codec)
{
- struct wm8900_priv *wm8900;
- struct snd_soc_codec *codec;
- unsigned int reg;
- int ret;
+ struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0, reg;
- wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL);
- if (wm8900 == NULL)
- return -ENOMEM;
-
- codec = &wm8900->codec;
- snd_soc_codec_set_drvdata(codec, wm8900);
- codec->reg_cache = &wm8900->reg_cache[0];
- codec->reg_cache_size = WM8900_MAXREG;
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->name = "WM8900";
- codec->owner = THIS_MODULE;
- codec->dai = &wm8900_dai;
- codec->num_dai = 1;
- codec->control_data = i2c;
- codec->set_bias_level = wm8900_set_bias_level;
- codec->volatile_register = wm8900_volatile_register;
- codec->dev = &i2c->dev;
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+ ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8900->control_type);
if (ret != 0) {
- dev_err(&i2c->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
}
reg = snd_soc_read(codec, WM8900_REG_ID);
if (reg != 0x8900) {
- dev_err(&i2c->dev, "Device is not a WM8900 - ID %x\n", reg);
- ret = -ENODEV;
- goto err;
+ dev_err(codec->dev, "Device is not a WM8900 - ID %x\n", reg);
+ return -ENODEV;
}
/* Read back from the chip */
reg = snd_soc_read(codec, WM8900_REG_POWER1);
reg = (reg >> 12) & 0xf;
- dev_info(&i2c->dev, "WM8900 revision %d\n", reg);
+ dev_info(codec->dev, "WM8900 revision %d\n", reg);
wm8900_reset(codec);
@@ -1271,43 +1235,94 @@
/* Set the DAC and mixer output bias */
snd_soc_write(codec, WM8900_REG_OUTBIASCTL, 0x81);
- wm8900_dai.dev = &i2c->dev;
+ snd_soc_add_controls(codec, wm8900_snd_controls,
+ ARRAY_SIZE(wm8900_snd_controls));
+ wm8900_add_widgets(codec);
- wm8900_codec = codec;
+ return 0;
+}
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
+/* power down chip */
+static int wm8900_remove(struct snd_soc_codec *codec)
+{
+ wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
- ret = snd_soc_register_dai(&wm8900_dai);
- if (ret != 0) {
- dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
+static struct snd_soc_codec_driver soc_codec_dev_wm8900 = {
+ .probe = wm8900_probe,
+ .remove = wm8900_remove,
+ .suspend = wm8900_suspend,
+ .resume = wm8900_resume,
+ .set_bias_level = wm8900_set_bias_level,
+ .volatile_register = wm8900_volatile_register,
+ .reg_cache_size = ARRAY_SIZE(wm8900_reg_defaults),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8900_reg_defaults,
+};
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8900_spi_probe(struct spi_device *spi)
+{
+ struct wm8900_priv *wm8900;
+ int ret;
+
+ wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL);
+ if (wm8900 == NULL)
+ return -ENOMEM;
+
+ wm8900->control_type = SND_SOC_SPI;
+ spi_set_drvdata(spi, wm8900);
+
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_wm8900, &wm8900_dai, 1);
+ if (ret < 0)
+ kfree(wm8900);
return ret;
+}
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- kfree(wm8900);
- wm8900_codec = NULL;
+static int __devexit wm8900_spi_remove(struct spi_device *spi)
+{
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
+ return 0;
+}
+
+static struct spi_driver wm8900_spi_driver = {
+ .driver = {
+ .name = "wm8900-codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8900_spi_probe,
+ .remove = __devexit_p(wm8900_spi_remove),
+};
+#endif /* CONFIG_SPI_MASTER */
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8900_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8900_priv *wm8900;
+ int ret;
+
+ wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL);
+ if (wm8900 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, wm8900);
+ wm8900->control_type = SND_SOC_I2C;
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8900, &wm8900_dai, 1);
+ if (ret < 0)
+ kfree(wm8900);
return ret;
}
static __devexit int wm8900_i2c_remove(struct i2c_client *client)
{
- snd_soc_unregister_dai(&wm8900_dai);
- snd_soc_unregister_codec(wm8900_codec);
-
- wm8900_set_bias_level(wm8900_codec, SND_SOC_BIAS_OFF);
-
- wm8900_dai.dev = NULL;
- kfree(snd_soc_codec_get_drvdata(wm8900_codec));
- wm8900_codec = NULL;
-
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -1319,71 +1334,44 @@
static struct i2c_driver wm8900_i2c_driver = {
.driver = {
- .name = "WM8900",
+ .name = "wm8900-codec",
.owner = THIS_MODULE,
},
- .probe = wm8900_i2c_probe,
- .remove = __devexit_p(wm8900_i2c_remove),
+ .probe = wm8900_i2c_probe,
+ .remove = __devexit_p(wm8900_i2c_remove),
.id_table = wm8900_i2c_id,
};
-
-static int wm8900_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- if (!wm8900_codec) {
- dev_err(&pdev->dev, "I2C client not yet instantiated\n");
- return -ENODEV;
- }
-
- codec = wm8900_codec;
- socdev->card->codec = codec;
-
- /* Register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to register new PCMs\n");
- goto pcm_err;
- }
-
- snd_soc_add_controls(codec, wm8900_snd_controls,
- ARRAY_SIZE(wm8900_snd_controls));
- wm8900_add_widgets(codec);
-
-pcm_err:
- return ret;
-}
-
-/* power down chip */
-static int wm8900_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8900 = {
- .probe = wm8900_probe,
- .remove = wm8900_remove,
- .suspend = wm8900_suspend,
- .resume = wm8900_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8900);
+#endif
static int __init wm8900_modinit(void)
{
- return i2c_add_driver(&wm8900_i2c_driver);
+ int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8900_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8900 I2C driver: %d\n",
+ ret);
+ }
+#endif
+#if defined(CONFIG_SPI_MASTER)
+ ret = spi_register_driver(&wm8900_spi_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8900 SPI driver: %d\n",
+ ret);
+ }
+#endif
+ return ret;
}
module_init(wm8900_modinit);
static void __exit wm8900_exit(void)
{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&wm8900_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+ spi_unregister_driver(&wm8900_spi_driver);
+#endif
}
module_exit(wm8900_exit);
diff --git a/sound/soc/codecs/wm8900.h b/sound/soc/codecs/wm8900.h
index fd15007..583f257 100644
--- a/sound/soc/codecs/wm8900.h
+++ b/sound/soc/codecs/wm8900.h
@@ -52,7 +52,4 @@
#define WM8900_DAC_CLKDIV_5_5 0x14
#define WM8900_DAC_CLKDIV_6 0x18
-extern struct snd_soc_dai wm8900_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8900;
-
#endif
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index bf08282..622b602 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -213,10 +213,11 @@
};
struct wm8903_priv {
- struct snd_soc_codec codec;
+
u16 reg_cache[ARRAY_SIZE(wm8903_reg_defaults)];
int sysclk;
+ int irq;
/* Reference counts */
int class_w_users;
@@ -252,7 +253,6 @@
static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start)
{
u16 reg[5];
- struct i2c_client *i2c = codec->control_data;
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
BUG_ON(start > 48);
@@ -262,7 +262,7 @@
snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0,
reg[0] | WM8903_WSEQ_ENA);
- dev_dbg(&i2c->dev, "Starting sequence at %d\n", start);
+ dev_dbg(codec->dev, "Starting sequence at %d\n", start);
snd_soc_write(codec, WM8903_WRITE_SEQUENCER_3,
start | WM8903_WSEQ_START);
@@ -277,7 +277,7 @@
reg[4] = snd_soc_read(codec, WM8903_WRITE_SEQUENCER_4);
} while (reg[4] & WM8903_WSEQ_BUSY);
- dev_dbg(&i2c->dev, "Sequence complete\n");
+ dev_dbg(codec->dev, "Sequence complete\n");
/* Disable the sequencer again if we enabled it */
snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0, reg[0]);
@@ -422,7 +422,6 @@
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
struct snd_soc_codec *codec = widget->codec;
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
- struct i2c_client *i2c = codec->control_data;
u16 reg;
int ret;
@@ -431,7 +430,7 @@
/* Turn it off if we're about to enable bypass */
if (ucontrol->value.integer.value[0]) {
if (wm8903->class_w_users == 0) {
- dev_dbg(&i2c->dev, "Disabling Class W\n");
+ dev_dbg(codec->dev, "Disabling Class W\n");
snd_soc_write(codec, WM8903_CLASS_W_0, reg &
~(WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V));
}
@@ -444,14 +443,14 @@
/* If we've just disabled the last bypass path turn Class W on */
if (!ucontrol->value.integer.value[0]) {
if (wm8903->class_w_users == 1) {
- dev_dbg(&i2c->dev, "Enabling Class W\n");
+ dev_dbg(codec->dev, "Enabling Class W\n");
snd_soc_write(codec, WM8903_CLASS_W_0, reg |
WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V);
}
wm8903->class_w_users--;
}
- dev_dbg(&i2c->dev, "Bypass use count now %d\n",
+ dev_dbg(codec->dev, "Bypass use count now %d\n",
wm8903->class_w_users);
return ret;
@@ -935,7 +934,6 @@
static int wm8903_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- struct i2c_client *i2c = codec->control_data;
u16 reg, reg2;
switch (level) {
@@ -974,7 +972,7 @@
/* By default no bypass paths are enabled so
* enable Class W support.
*/
- dev_dbg(&i2c->dev, "Enabling Class W\n");
+ dev_dbg(codec->dev, "Enabling Class W\n");
snd_soc_write(codec, WM8903_CLASS_W_0, reg |
WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V);
}
@@ -1228,10 +1226,8 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
- struct i2c_client *i2c = codec->control_data;
struct snd_pcm_runtime *master_runtime;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -1245,7 +1241,7 @@
if (wm8903->master_substream) {
master_runtime = wm8903->master_substream->runtime;
- dev_dbg(&i2c->dev, "Constraining to %d bits\n",
+ dev_dbg(codec->dev, "Constraining to %d bits\n",
master_runtime->sample_bits);
snd_pcm_hw_constraint_minmax(substream->runtime,
@@ -1264,8 +1260,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -1284,10 +1279,8 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec =rtd->codec;
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
- struct i2c_client *i2c = codec->control_data;
int fs = params_rate(params);
int bclk;
int bclk_div;
@@ -1306,7 +1299,7 @@
u16 dac_digital1 = snd_soc_read(codec, WM8903_DAC_DIGITAL_1);
if (substream == wm8903->slave_substream) {
- dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n");
+ dev_dbg(codec->dev, "Ignoring hw_params for slave substream\n");
return 0;
}
@@ -1332,7 +1325,7 @@
switch (sample_rates[dsp_config].rate) {
case 88200:
case 96000:
- dev_err(&i2c->dev, "%dHz unsupported by ADC\n",
+ dev_err(codec->dev, "%dHz unsupported by ADC\n",
fs);
return -EINVAL;
@@ -1340,7 +1333,7 @@
break;
}
- dev_dbg(&i2c->dev, "DSP fs = %dHz\n", sample_rates[dsp_config].rate);
+ dev_dbg(codec->dev, "DSP fs = %dHz\n", sample_rates[dsp_config].rate);
clock1 &= ~WM8903_SAMPLE_RATE_MASK;
clock1 |= sample_rates[dsp_config].value;
@@ -1366,7 +1359,7 @@
return -EINVAL;
}
- dev_dbg(&i2c->dev, "MCLK = %dHz, target sample rate = %dHz\n",
+ dev_dbg(codec->dev, "MCLK = %dHz, target sample rate = %dHz\n",
wm8903->sysclk, fs);
/* We may not have an MCLK which allows us to generate exactly
@@ -1401,12 +1394,12 @@
clock1 |= clk_sys_ratios[clk_config].rate << WM8903_CLK_SYS_RATE_SHIFT;
clock1 |= clk_sys_ratios[clk_config].mode << WM8903_CLK_SYS_MODE_SHIFT;
- dev_dbg(&i2c->dev, "CLK_SYS_RATE=%x, CLK_SYS_MODE=%x div=%d\n",
+ dev_dbg(codec->dev, "CLK_SYS_RATE=%x, CLK_SYS_MODE=%x div=%d\n",
clk_sys_ratios[clk_config].rate,
clk_sys_ratios[clk_config].mode,
clk_sys_ratios[clk_config].div);
- dev_dbg(&i2c->dev, "Actual CLK_SYS = %dHz\n", clk_sys);
+ dev_dbg(codec->dev, "Actual CLK_SYS = %dHz\n", clk_sys);
/* We may not get quite the right frequency if using
* approximate clocks so look for the closest match that is
@@ -1428,7 +1421,7 @@
aif2 &= ~WM8903_BCLK_DIV_MASK;
aif3 &= ~WM8903_LRCLK_RATE_MASK;
- dev_dbg(&i2c->dev, "BCLK ratio %d for %dHz - actual BCLK = %dHz\n",
+ dev_dbg(codec->dev, "BCLK ratio %d for %dHz - actual BCLK = %dHz\n",
bclk_divs[bclk_div].ratio / 10, bclk,
(clk_sys * 10) / bclk_divs[bclk_div].ratio);
@@ -1504,8 +1497,8 @@
static irqreturn_t wm8903_irq(int irq, void *data)
{
- struct wm8903_priv *wm8903 = data;
- struct snd_soc_codec *codec = &wm8903->codec;
+ struct snd_soc_codec *codec = data;
+ struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
int mic_report;
int int_pol;
int int_val = 0;
@@ -1586,8 +1579,8 @@
.set_sysclk = wm8903_set_dai_sysclk,
};
-struct snd_soc_dai wm8903_dai = {
- .name = "WM8903",
+static struct snd_soc_dai_driver wm8903_dai = {
+ .name = "wm8903-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -1605,23 +1598,16 @@
.ops = &wm8903_dai_ops,
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(wm8903_dai);
-static int wm8903_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8903_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8903_resume(struct platform_device *pdev)
+static int wm8903_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
- struct i2c_client *i2c = codec->control_data;
int i;
u16 *reg_cache = codec->reg_cache;
u16 *tmp_cache = kmemdup(reg_cache, sizeof(wm8903_reg_defaults),
@@ -1637,65 +1623,37 @@
snd_soc_write(codec, i, tmp_cache[i]);
kfree(tmp_cache);
} else {
- dev_err(&i2c->dev, "Failed to allocate temporary cache\n");
+ dev_err(codec->dev, "Failed to allocate temporary cache\n");
}
return 0;
}
-static struct snd_soc_codec *wm8903_codec;
-
-static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int wm8903_probe(struct snd_soc_codec *codec)
{
- struct wm8903_platform_data *pdata = dev_get_platdata(&i2c->dev);
- struct wm8903_priv *wm8903;
- struct snd_soc_codec *codec;
+ struct wm8903_platform_data *pdata = dev_get_platdata(codec->dev);
+ struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
int ret, i;
int trigger, irq_pol;
u16 val;
- wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL);
- if (wm8903 == NULL)
- return -ENOMEM;
-
- codec = &wm8903->codec;
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->dev = &i2c->dev;
- codec->name = "WM8903";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8903_set_bias_level;
- codec->dai = &wm8903_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(wm8903->reg_cache);
- codec->reg_cache = &wm8903->reg_cache[0];
- snd_soc_codec_set_drvdata(codec, wm8903);
- codec->volatile_register = wm8903_volatile_register;
init_completion(&wm8903->wseq);
- i2c_set_clientdata(i2c, codec);
- codec->control_data = i2c;
-
ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
if (ret != 0) {
- dev_err(&i2c->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
}
val = snd_soc_read(codec, WM8903_SW_RESET_AND_ID);
if (val != wm8903_reg_defaults[WM8903_SW_RESET_AND_ID]) {
- dev_err(&i2c->dev,
+ dev_err(codec->dev,
"Device with ID register %x is not a WM8903\n", val);
return -ENODEV;
}
val = snd_soc_read(codec, WM8903_REVISION_NUMBER);
- dev_info(&i2c->dev, "WM8903 revision %d\n",
+ dev_info(codec->dev, "WM8903 revision %d\n",
val & WM8903_CHIP_REV_MASK);
wm8903_reset(codec);
@@ -1721,7 +1679,7 @@
wm8903->mic_delay = pdata->micdet_delay;
}
- if (i2c->irq) {
+ if (wm8903->irq) {
if (pdata && pdata->irq_active_low) {
trigger = IRQF_TRIGGER_LOW;
irq_pol = WM8903_IRQ_POL;
@@ -1733,13 +1691,13 @@
snd_soc_update_bits(codec, WM8903_INTERRUPT_CONTROL,
WM8903_IRQ_POL, irq_pol);
- ret = request_threaded_irq(i2c->irq, NULL, wm8903_irq,
+ ret = request_threaded_irq(wm8903->irq, NULL, wm8903_irq,
trigger | IRQF_ONESHOT,
- "wm8903", wm8903);
+ "wm8903", codec);
if (ret != 0) {
- dev_err(&i2c->dev, "Failed to request IRQ: %d\n",
+ dev_err(codec->dev, "Failed to request IRQ: %d\n",
ret);
- goto err;
+ return ret;
}
/* Enable write sequencer interrupts */
@@ -1781,133 +1739,96 @@
val |= WM8903_DAC_MUTEMODE;
snd_soc_write(codec, WM8903_DAC_DIGITAL_1, val);
- wm8903_dai.dev = &i2c->dev;
- wm8903_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
- goto err_irq;
- }
-
- ret = snd_soc_register_dai(&wm8903_dai);
- if (ret != 0) {
- dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
+ snd_soc_add_controls(codec, wm8903_snd_controls,
+ ARRAY_SIZE(wm8903_snd_controls));
+ wm8903_add_widgets(codec);
return ret;
+}
-err_codec:
- snd_soc_unregister_codec(codec);
-err_irq:
- if (i2c->irq)
- free_irq(i2c->irq, wm8903);
-err:
- wm8903_codec = NULL;
- kfree(wm8903);
+/* power down chip */
+static int wm8903_remove(struct snd_soc_codec *codec)
+{
+ wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8903 = {
+ .probe = wm8903_probe,
+ .remove = wm8903_remove,
+ .suspend = wm8903_suspend,
+ .resume = wm8903_resume,
+ .set_bias_level = wm8903_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8903_reg_defaults),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8903_reg_defaults,
+ .volatile_register = wm8903_volatile_register,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8903_priv *wm8903;
+ int ret;
+
+ wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL);
+ if (wm8903 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, wm8903);
+ wm8903->irq = i2c->irq;
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8903, &wm8903_dai, 1);
+ if (ret < 0)
+ kfree(wm8903);
return ret;
}
static __devexit int wm8903_i2c_remove(struct i2c_client *client)
{
- struct snd_soc_codec *codec = i2c_get_clientdata(client);
- struct wm8903_priv *priv = snd_soc_codec_get_drvdata(codec);
-
- snd_soc_unregister_dai(&wm8903_dai);
- snd_soc_unregister_codec(codec);
-
- wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- if (client->irq)
- free_irq(client->irq, priv);
-
- kfree(priv);
-
- wm8903_codec = NULL;
- wm8903_dai.dev = NULL;
-
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
-/* i2c codec control layer */
static const struct i2c_device_id wm8903_i2c_id[] = {
- { "wm8903", 0 },
- { }
+ { "wm8903", 0 },
+ { }
};
MODULE_DEVICE_TABLE(i2c, wm8903_i2c_id);
static struct i2c_driver wm8903_i2c_driver = {
.driver = {
- .name = "WM8903",
+ .name = "wm8903-codec",
.owner = THIS_MODULE,
},
- .probe = wm8903_i2c_probe,
- .remove = __devexit_p(wm8903_i2c_remove),
+ .probe = wm8903_i2c_probe,
+ .remove = __devexit_p(wm8903_i2c_remove),
.id_table = wm8903_i2c_id,
};
-
-static int wm8903_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- int ret = 0;
-
- if (!wm8903_codec) {
- dev_err(&pdev->dev, "I2C device not yet probed\n");
- goto err;
- }
-
- socdev->card->codec = wm8903_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to create pcms\n");
- goto err;
- }
-
- snd_soc_add_controls(socdev->card->codec, wm8903_snd_controls,
- ARRAY_SIZE(wm8903_snd_controls));
- wm8903_add_widgets(socdev->card->codec);
-
- return ret;
-
-err:
- return ret;
-}
-
-/* power down chip */
-static int wm8903_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec->control_data)
- wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8903 = {
- .probe = wm8903_probe,
- .remove = wm8903_remove,
- .suspend = wm8903_suspend,
- .resume = wm8903_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8903);
+#endif
static int __init wm8903_modinit(void)
{
- return i2c_add_driver(&wm8903_i2c_driver);
+ int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8903_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8903 I2C driver: %d\n",
+ ret);
+ }
+#endif
+ return ret;
}
module_init(wm8903_modinit);
static void __exit wm8903_exit(void)
{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&wm8903_i2c_driver);
+#endif
}
module_exit(wm8903_exit);
diff --git a/sound/soc/codecs/wm8903.h b/sound/soc/codecs/wm8903.h
index ce384a2..996435e 100644
--- a/sound/soc/codecs/wm8903.h
+++ b/sound/soc/codecs/wm8903.h
@@ -15,9 +15,6 @@
#include <linux/i2c.h>
-extern struct snd_soc_dai wm8903_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8903;
-
extern int wm8903_mic_detect(struct snd_soc_codec *codec,
struct snd_soc_jack *jack,
int det, int shrt);
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index f7dcabf..33be84e 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -31,9 +31,6 @@
#include "wm8904.h"
-static struct snd_soc_codec *wm8904_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8904;
-
enum wm8904_type {
WM8904,
WM8912,
@@ -52,10 +49,11 @@
/* codec private data */
struct wm8904_priv {
- struct snd_soc_codec codec;
+
u16 reg_cache[WM8904_MAX_REGISTER + 1];
enum wm8904_type devtype;
+ void *control_data;
struct regulator_bulk_data supplies[WM8904_NUM_SUPPLIES];
@@ -689,7 +687,7 @@
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+ struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
struct wm8904_pdata *pdata = wm8904->pdata;
int value = ucontrol->value.integer.value[0];
@@ -760,7 +758,7 @@
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+ struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
struct wm8904_pdata *pdata = wm8904->pdata;
int value = ucontrol->value.integer.value[0];
@@ -2218,8 +2216,8 @@
.digital_mute = wm8904_digital_mute,
};
-struct snd_soc_dai wm8904_dai = {
- .name = "WM8904",
+static struct snd_soc_dai_driver wm8904_dai = {
+ .name = "wm8904-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -2237,24 +2235,17 @@
.ops = &wm8904_dai_ops,
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(wm8904_dai);
#ifdef CONFIG_PM
-static int wm8904_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8904_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8904_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8904_resume(struct platform_device *pdev)
+static int wm8904_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
@@ -2264,9 +2255,9 @@
#define wm8904_resume NULL
#endif
-static void wm8904_handle_retune_mobile_pdata(struct wm8904_priv *wm8904)
+static void wm8904_handle_retune_mobile_pdata(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = &wm8904->codec;
+ struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
struct wm8904_pdata *pdata = wm8904->pdata;
struct snd_kcontrol_new control =
SOC_ENUM_EXT("EQ Mode",
@@ -2315,20 +2306,20 @@
wm8904->retune_mobile_enum.max = wm8904->num_retune_mobile_texts;
wm8904->retune_mobile_enum.texts = wm8904->retune_mobile_texts;
- ret = snd_soc_add_controls(&wm8904->codec, &control, 1);
+ ret = snd_soc_add_controls(codec, &control, 1);
if (ret != 0)
- dev_err(wm8904->codec.dev,
+ dev_err(codec->dev,
"Failed to add ReTune Mobile control: %d\n", ret);
}
-static void wm8904_handle_pdata(struct wm8904_priv *wm8904)
+static void wm8904_handle_pdata(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = &wm8904->codec;
+ struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
struct wm8904_pdata *pdata = wm8904->pdata;
int ret, i;
if (!pdata) {
- snd_soc_add_controls(&wm8904->codec, wm8904_eq_controls,
+ snd_soc_add_controls(codec, wm8904_eq_controls,
ARRAY_SIZE(wm8904_eq_controls));
return;
}
@@ -2344,7 +2335,7 @@
wm8904->drc_texts = kmalloc(sizeof(char *)
* pdata->num_drc_cfgs, GFP_KERNEL);
if (!wm8904->drc_texts) {
- dev_err(wm8904->codec.dev,
+ dev_err(codec->dev,
"Failed to allocate %d DRC config texts\n",
pdata->num_drc_cfgs);
return;
@@ -2356,9 +2347,9 @@
wm8904->drc_enum.max = pdata->num_drc_cfgs;
wm8904->drc_enum.texts = wm8904->drc_texts;
- ret = snd_soc_add_controls(&wm8904->codec, &control, 1);
+ ret = snd_soc_add_controls(codec, &control, 1);
if (ret != 0)
- dev_err(wm8904->codec.dev,
+ dev_err(codec->dev,
"Failed to add DRC mode control: %d\n", ret);
wm8904_set_drc(codec);
@@ -2368,89 +2359,19 @@
pdata->num_retune_mobile_cfgs);
if (pdata->num_retune_mobile_cfgs)
- wm8904_handle_retune_mobile_pdata(wm8904);
+ wm8904_handle_retune_mobile_pdata(codec);
else
- snd_soc_add_controls(&wm8904->codec, wm8904_eq_controls,
+ snd_soc_add_controls(codec, wm8904_eq_controls,
ARRAY_SIZE(wm8904_eq_controls));
}
-static int wm8904_probe(struct platform_device *pdev)
+
+static int wm8904_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- if (wm8904_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8904_codec;
- codec = wm8904_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- wm8904_handle_pdata(snd_soc_codec_get_drvdata(codec));
-
- wm8904_add_widgets(codec);
-
- return ret;
-
-pcm_err:
- return ret;
-}
-
-static int wm8904_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8904 = {
- .probe = wm8904_probe,
- .remove = wm8904_remove,
- .suspend = wm8904_suspend,
- .resume = wm8904_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8904);
-
-static int wm8904_register(struct wm8904_priv *wm8904,
- enum snd_soc_control_type control)
-{
+ struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
struct wm8904_pdata *pdata = wm8904->pdata;
- int ret;
- struct snd_soc_codec *codec = &wm8904->codec;
- int i;
+ int ret, i;
- if (wm8904_codec) {
- dev_err(codec->dev, "Another WM8904 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8904);
- codec->name = "WM8904";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8904_set_bias_level;
- codec->dai = &wm8904_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = WM8904_MAX_REGISTER;
- codec->reg_cache = &wm8904->reg_cache;
- codec->volatile_register = wm8904_volatile_register;
codec->cache_sync = 1;
codec->idle_bias_off = 1;
@@ -2463,16 +2384,13 @@
default:
dev_err(codec->dev, "Unknown device type %d\n",
wm8904->devtype);
- ret = -EINVAL;
- goto err;
+ return -EINVAL;
}
- memcpy(codec->reg_cache, wm8904_reg, sizeof(wm8904_reg));
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
+ ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
for (i = 0; i < ARRAY_SIZE(wm8904->supplies); i++)
@@ -2482,7 +2400,7 @@
wm8904->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
- goto err;
+ return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies),
@@ -2517,8 +2435,6 @@
goto err_enable;
}
- wm8904_dai.dev = codec->dev;
-
/* Change some default settings - latch VU and enable ZC */
wm8904->reg_cache[WM8904_ADC_DIGITAL_VOLUME_LEFT] |= WM8904_ADC_VU;
wm8904->reg_cache[WM8904_ADC_DIGITAL_VOLUME_RIGHT] |= WM8904_ADC_VU;
@@ -2563,72 +2479,68 @@
/* Bias level configuration will have done an extra enable */
regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
- wm8904_codec = codec;
+ wm8904_handle_pdata(codec);
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err_enable;
- }
-
- ret = snd_soc_register_dai(&wm8904_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
+ wm8904_add_widgets(codec);
return 0;
-err_codec:
- snd_soc_unregister_codec(codec);
err_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
err_get:
regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
-err:
- kfree(wm8904);
return ret;
}
-static void wm8904_unregister(struct wm8904_priv *wm8904)
+static int wm8904_remove(struct snd_soc_codec *codec)
{
- wm8904_set_bias_level(&wm8904->codec, SND_SOC_BIAS_OFF);
+ struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+
+ wm8904_set_bias_level(codec, SND_SOC_BIAS_OFF);
regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
- snd_soc_unregister_dai(&wm8904_dai);
- snd_soc_unregister_codec(&wm8904->codec);
- kfree(wm8904);
- wm8904_codec = NULL;
+
+ return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_wm8904 = {
+ .probe = wm8904_probe,
+ .remove = wm8904_remove,
+ .suspend = wm8904_suspend,
+ .resume = wm8904_resume,
+ .set_bias_level = wm8904_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8904_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8904_reg,
+ .volatile_register = wm8904_volatile_register,
+};
+
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static __devinit int wm8904_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm8904_priv *wm8904;
- struct snd_soc_codec *codec;
+ int ret;
wm8904 = kzalloc(sizeof(struct wm8904_priv), GFP_KERNEL);
if (wm8904 == NULL)
return -ENOMEM;
- codec = &wm8904->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
-
wm8904->devtype = id->driver_data;
-
i2c_set_clientdata(i2c, wm8904);
- codec->control_data = i2c;
+ wm8904->control_data = i2c;
wm8904->pdata = i2c->dev.platform_data;
- codec->dev = &i2c->dev;
-
- return wm8904_register(wm8904, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8904, &wm8904_dai, 1);
+ if (ret < 0)
+ kfree(wm8904);
+ return ret;
}
static __devexit int wm8904_i2c_remove(struct i2c_client *client)
{
- struct wm8904_priv *wm8904 = i2c_get_clientdata(client);
- wm8904_unregister(wm8904);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -2641,7 +2553,7 @@
static struct i2c_driver wm8904_i2c_driver = {
.driver = {
- .name = "WM8904",
+ .name = "wm8904-codec",
.owner = THIS_MODULE,
},
.probe = wm8904_i2c_probe,
@@ -2652,15 +2564,15 @@
static int __init wm8904_modinit(void)
{
- int ret;
+ int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8904_i2c_driver);
if (ret != 0) {
- printk(KERN_ERR "Failed to register WM8904 I2C driver: %d\n",
+ printk(KERN_ERR "Failed to register wm8904 I2C driver: %d\n",
ret);
}
#endif
- return 0;
+ return ret;
}
module_init(wm8904_modinit);
diff --git a/sound/soc/codecs/wm8904.h b/sound/soc/codecs/wm8904.h
index abe5059..9e8c841 100644
--- a/sound/soc/codecs/wm8904.h
+++ b/sound/soc/codecs/wm8904.h
@@ -21,9 +21,6 @@
#define WM8904_FLL_LRCLK 3
#define WM8904_FLL_FREE_RUNNING 4
-extern struct snd_soc_dai wm8904_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8904;
-
/*
* Register values.
*/
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index f0c1113..2cb16f8 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -44,7 +44,8 @@
struct wm8940_priv {
unsigned int sysclk;
u16 reg_cache[WM8940_CACHEREGNUM];
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
+ void *control_data;
};
static u16 wm8940_reg_defaults[] = {
@@ -365,8 +366,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFD9F;
u16 addcntrl = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFF1;
u16 companding = snd_soc_read(codec,
@@ -636,8 +636,8 @@
.set_pll = wm8940_set_dai_pll,
};
-struct snd_soc_dai wm8940_dai = {
- .name = "WM8940",
+static struct snd_soc_dai_driver wm8940_dai = {
+ .name = "wm8940-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -655,20 +655,14 @@
.ops = &wm8940_dai_ops,
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(wm8940_dai);
-static int wm8940_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8940_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
return wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF);
}
-static int wm8940_resume(struct platform_device *pdev)
+static int wm8940_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i;
int ret;
u8 data[3];
@@ -697,108 +691,26 @@
return ret;
}
-static struct snd_soc_codec *wm8940_codec;
-
-static int wm8940_probe(struct platform_device *pdev)
+static int wm8940_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
-
- int ret = 0;
-
- if (wm8940_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8940_codec;
- codec = wm8940_codec;
-
- mutex_init(&codec->mutex);
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- ret = snd_soc_add_controls(codec, wm8940_snd_controls,
- ARRAY_SIZE(wm8940_snd_controls));
- if (ret)
- goto error_free_pcms;
- ret = wm8940_add_widgets(codec);
- if (ret)
- goto error_free_pcms;
-
- return ret;
-
-error_free_pcms:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-pcm_err:
- return ret;
-}
-
-static int wm8940_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8940 = {
- .probe = wm8940_probe,
- .remove = wm8940_remove,
- .suspend = wm8940_suspend,
- .resume = wm8940_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8940);
-
-static int wm8940_register(struct wm8940_priv *wm8940,
- enum snd_soc_control_type control)
-{
- struct wm8940_setup_data *pdata = wm8940->codec.dev->platform_data;
- struct snd_soc_codec *codec = &wm8940->codec;
+ struct wm8940_priv *wm8940 = snd_soc_codec_get_drvdata(codec);
+ struct wm8940_setup_data *pdata = codec->dev->platform_data;
int ret;
u16 reg;
- if (wm8940_codec) {
- dev_err(codec->dev, "Another WM8940 is registered\n");
- return -EINVAL;
- }
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8940);
- codec->name = "WM8940";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8940_set_bias_level;
- codec->dai = &wm8940_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults);
- codec->reg_cache = &wm8940->reg_cache;
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
+ codec->control_data = wm8940->control_data;
+ ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8940->control_type);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
}
- memcpy(codec->reg_cache, wm8940_reg_defaults,
- sizeof(wm8940_reg_defaults));
-
ret = wm8940_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
return ret;
}
- wm8940_dai.dev = codec->dev;
-
wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
ret = snd_soc_write(codec, WM8940_POWER1, 0x180);
@@ -814,64 +726,60 @@
return ret;
}
-
- wm8940_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+ ret = snd_soc_add_controls(codec, wm8940_snd_controls,
+ ARRAY_SIZE(wm8940_snd_controls));
+ if (ret)
return ret;
- }
-
- ret = snd_soc_register_dai(&wm8940_dai);
- if (ret) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- snd_soc_unregister_codec(codec);
+ ret = wm8940_add_widgets(codec);
+ if (ret)
return ret;
- }
+ return ret;
+;
+}
+
+static int wm8940_remove(struct snd_soc_codec *codec)
+{
+ wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static void wm8940_unregister(struct wm8940_priv *wm8940)
-{
- wm8940_set_bias_level(&wm8940->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dai(&wm8940_dai);
- snd_soc_unregister_codec(&wm8940->codec);
- kfree(wm8940);
- wm8940_codec = NULL;
-}
+static struct snd_soc_codec_driver soc_codec_dev_wm8940 = {
+ .probe = wm8940_probe,
+ .remove = wm8940_remove,
+ .suspend = wm8940_suspend,
+ .resume = wm8940_resume,
+ .set_bias_level = wm8940_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8940_reg_defaults,
+};
-static int wm8940_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8940_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
{
- int ret;
struct wm8940_priv *wm8940;
- struct snd_soc_codec *codec;
+ int ret;
- wm8940 = kzalloc(sizeof *wm8940, GFP_KERNEL);
+ wm8940 = kzalloc(sizeof(struct wm8940_priv), GFP_KERNEL);
if (wm8940 == NULL)
return -ENOMEM;
- codec = &wm8940->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
i2c_set_clientdata(i2c, wm8940);
- codec->control_data = i2c;
- codec->dev = &i2c->dev;
+ wm8940->control_data = i2c;
- ret = wm8940_register(wm8940, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8940, &wm8940_dai, 1);
if (ret < 0)
kfree(wm8940);
-
return ret;
}
-static int __devexit wm8940_i2c_remove(struct i2c_client *client)
+static __devexit int wm8940_i2c_remove(struct i2c_client *client)
{
- struct wm8940_priv *wm8940 = i2c_get_clientdata(client);
-
- wm8940_unregister(wm8940);
-
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -883,29 +791,34 @@
static struct i2c_driver wm8940_i2c_driver = {
.driver = {
- .name = "WM8940 I2C Codec",
+ .name = "wm8940-codec",
.owner = THIS_MODULE,
},
- .probe = wm8940_i2c_probe,
- .remove = __devexit_p(wm8940_i2c_remove),
+ .probe = wm8940_i2c_probe,
+ .remove = __devexit_p(wm8940_i2c_remove),
.id_table = wm8940_i2c_id,
};
+#endif
static int __init wm8940_modinit(void)
{
- int ret;
-
+ int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8940_i2c_driver);
- if (ret)
- printk(KERN_ERR "Failed to register WM8940 I2C driver: %d\n",
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8940 I2C driver: %d\n",
ret);
+ }
+#endif
return ret;
}
module_init(wm8940_modinit);
static void __exit wm8940_exit(void)
{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&wm8940_i2c_driver);
+#endif
}
module_exit(wm8940_exit);
diff --git a/sound/soc/codecs/wm8940.h b/sound/soc/codecs/wm8940.h
index 8410eed..907fe19 100644
--- a/sound/soc/codecs/wm8940.h
+++ b/sound/soc/codecs/wm8940.h
@@ -15,8 +15,6 @@
#define WM8940_VROI_30K 1
unsigned int vroi:1;
};
-extern struct snd_soc_dai wm8940_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8940;
/* WM8940 register space */
#define WM8940_SOFTRESET 0x00
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
index 5f02559..f89ad6c 100644
--- a/sound/soc/codecs/wm8955.c
+++ b/sound/soc/codecs/wm8955.c
@@ -30,9 +30,6 @@
#include "wm8955.h"
-static struct snd_soc_codec *wm8955_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8955;
-
#define WM8955_NUM_SUPPLIES 4
static const char *wm8955_supply_names[WM8955_NUM_SUPPLIES] = {
"DCVDD",
@@ -43,7 +40,8 @@
/* codec private data */
struct wm8955_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
+
u16 reg_cache[WM8955_MAX_REGISTER + 1];
unsigned int mclk_rate;
@@ -52,8 +50,6 @@
int fs;
struct regulator_bulk_data supplies[WM8955_NUM_SUPPLIES];
-
- struct wm8955_pdata *pdata;
};
static const u16 wm8955_reg[WM8955_MAX_REGISTER + 1] = {
@@ -870,8 +866,8 @@
.digital_mute = wm8955_digital_mute,
};
-struct snd_soc_dai wm8955_dai = {
- .name = "WM8955",
+static struct snd_soc_dai_driver wm8955_dai = {
+ .name = "wm8955-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -881,24 +877,17 @@
},
.ops = &wm8955_dai_ops,
};
-EXPORT_SYMBOL_GPL(wm8955_dai);
#ifdef CONFIG_PM
-static int wm8955_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8955_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8955_resume(struct platform_device *pdev)
+static int wm8955_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
@@ -908,86 +897,16 @@
#define wm8955_resume NULL
#endif
-static int wm8955_probe(struct platform_device *pdev)
+static int wm8955_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
+ struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
+ struct wm8955_pdata *pdata = dev_get_platdata(codec->dev);
+ int ret, i;
- if (wm8955_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8955_codec;
- codec = wm8955_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- wm8955_add_widgets(codec);
-
- return ret;
-
-pcm_err:
- return ret;
-}
-
-static int wm8955_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8955 = {
- .probe = wm8955_probe,
- .remove = wm8955_remove,
- .suspend = wm8955_suspend,
- .resume = wm8955_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8955);
-
-static int wm8955_register(struct wm8955_priv *wm8955,
- enum snd_soc_control_type control)
-{
- int ret;
- struct snd_soc_codec *codec = &wm8955->codec;
- int i;
-
- if (wm8955_codec) {
- dev_err(codec->dev, "Another WM8955 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8955);
- codec->name = "WM8955";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8955_set_bias_level;
- codec->dai = &wm8955_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = WM8955_MAX_REGISTER;
- codec->reg_cache = &wm8955->reg_cache;
-
- memcpy(codec->reg_cache, wm8955_reg, sizeof(wm8955_reg));
-
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8955->control_type);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
for (i = 0; i < ARRAY_SIZE(wm8955->supplies); i++)
@@ -997,7 +916,7 @@
wm8955->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
- goto err;
+ return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies),
@@ -1013,8 +932,6 @@
goto err_enable;
}
- wm8955_dai.dev = codec->dev;
-
/* Change some default settings - latch VU and enable ZC */
wm8955->reg_cache[WM8955_LEFT_DAC_VOLUME] |= WM8955_LDVU;
wm8955->reg_cache[WM8955_RIGHT_DAC_VOLUME] |= WM8955_RDVU;
@@ -1028,12 +945,12 @@
wm8955->reg_cache[WM8955_BASS_CONTROL] |= WM8955_BB;
/* Set platform data values */
- if (wm8955->pdata) {
- if (wm8955->pdata->out2_speaker)
+ if (pdata) {
+ if (pdata->out2_speaker)
wm8955->reg_cache[WM8955_ADDITIONAL_CONTROL_2]
|= WM8955_ROUT2INV;
- if (wm8955->pdata->monoin_diff)
+ if (pdata->monoin_diff)
wm8955->reg_cache[WM8955_MONO_OUT_MIX_1]
|= WM8955_DMEN;
}
@@ -1043,70 +960,60 @@
/* Bias level configuration will have done an extra enable */
regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
- wm8955_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err_enable;
- }
-
- ret = snd_soc_register_dai(&wm8955_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
-
+ wm8955_add_widgets(codec);
return 0;
-err_codec:
- snd_soc_unregister_codec(codec);
err_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
err_get:
regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
-err:
- kfree(wm8955);
return ret;
}
-static void wm8955_unregister(struct wm8955_priv *wm8955)
+static int wm8955_remove(struct snd_soc_codec *codec)
{
- wm8955_set_bias_level(&wm8955->codec, SND_SOC_BIAS_OFF);
+ struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
+
+ wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF);
regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
- snd_soc_unregister_dai(&wm8955_dai);
- snd_soc_unregister_codec(&wm8955->codec);
- kfree(wm8955);
- wm8955_codec = NULL;
+ return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_wm8955 = {
+ .probe = wm8955_probe,
+ .remove = wm8955_remove,
+ .suspend = wm8955_suspend,
+ .resume = wm8955_resume,
+ .set_bias_level = wm8955_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8955_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8955_reg,
+};
+
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static __devinit int wm8955_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm8955_priv *wm8955;
- struct snd_soc_codec *codec;
+ int ret;
wm8955 = kzalloc(sizeof(struct wm8955_priv), GFP_KERNEL);
if (wm8955 == NULL)
return -ENOMEM;
- codec = &wm8955->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
-
i2c_set_clientdata(i2c, wm8955);
- codec->control_data = i2c;
- wm8955->pdata = i2c->dev.platform_data;
- codec->dev = &i2c->dev;
-
- return wm8955_register(wm8955, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8955, &wm8955_dai, 1);
+ if (ret < 0)
+ kfree(wm8955);
+ return ret;
}
static __devexit int wm8955_i2c_remove(struct i2c_client *client)
{
- struct wm8955_priv *wm8955 = i2c_get_clientdata(client);
- wm8955_unregister(wm8955);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -1118,7 +1025,7 @@
static struct i2c_driver wm8955_i2c_driver = {
.driver = {
- .name = "wm8955",
+ .name = "wm8955-codec",
.owner = THIS_MODULE,
},
.probe = wm8955_i2c_probe,
@@ -1129,7 +1036,7 @@
static int __init wm8955_modinit(void)
{
- int ret;
+ int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8955_i2c_driver);
if (ret != 0) {
@@ -1137,7 +1044,7 @@
ret);
}
#endif
- return 0;
+ return ret;
}
module_init(wm8955_modinit);
diff --git a/sound/soc/codecs/wm8955.h b/sound/soc/codecs/wm8955.h
index ae349c8..d13fd5c 100644
--- a/sound/soc/codecs/wm8955.h
+++ b/sound/soc/codecs/wm8955.h
@@ -15,9 +15,6 @@
#define WM8955_CLK_MCLK 1
-extern struct snd_soc_dai wm8955_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8955;
-
/*
* Register values.
*/
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 3c6ee61..8d5efb3 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -29,8 +29,6 @@
#define AUDIO_NAME "wm8960"
-struct snd_soc_codec_device soc_codec_dev_wm8960;
-
/* R25 - Power 1 */
#define WM8960_VMID_MASK 0x180
#define WM8960_VREF 0x40
@@ -75,7 +73,10 @@
struct wm8960_priv {
u16 reg_cache[WM8960_CACHEREGNUM];
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
+ void *control_data;
+ int (*set_bias_level)(struct snd_soc_codec *,
+ enum snd_soc_bias_level level);
struct snd_soc_dapm_widget *lout1;
struct snd_soc_dapm_widget *rout1;
struct snd_soc_dapm_widget *out3;
@@ -507,8 +508,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3;
int i;
@@ -849,6 +849,14 @@
return 0;
}
+static int wm8960_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+
+ return wm8960->set_bias_level(codec, level);
+}
+
#define WM8960_RATES SNDRV_PCM_RATE_8000_48000
#define WM8960_FORMATS \
@@ -863,8 +871,8 @@
.set_pll = wm8960_set_dai_pll,
};
-struct snd_soc_dai wm8960_dai = {
- .name = "WM8960",
+static struct snd_soc_dai_driver wm8960_dai = {
+ .name = "wm8960-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -880,21 +888,18 @@
.ops = &wm8960_dai_ops,
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(wm8960_dai);
-static int wm8960_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8960_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
- codec->set_bias_level(codec, SND_SOC_BIAS_OFF);
+ wm8960->set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8960_resume(struct platform_device *pdev)
+static int wm8960_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -906,78 +911,19 @@
codec->hw_write(codec->control_data, data, 2);
}
- codec->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
+ wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
-static struct snd_soc_codec *wm8960_codec;
-
-static int wm8960_probe(struct platform_device *pdev)
+static int wm8960_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- if (wm8960_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8960_codec;
- codec = wm8960_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- snd_soc_add_controls(codec, wm8960_snd_controls,
- ARRAY_SIZE(wm8960_snd_controls));
- wm8960_add_widgets(codec);
-
- return ret;
-
-pcm_err:
- return ret;
-}
-
-/* power down chip */
-static int wm8960_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8960 = {
- .probe = wm8960_probe,
- .remove = wm8960_remove,
- .suspend = wm8960_suspend,
- .resume = wm8960_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8960);
-
-static int wm8960_register(struct wm8960_priv *wm8960,
- enum snd_soc_control_type control)
-{
- struct wm8960_data *pdata = wm8960->codec.dev->platform_data;
- struct snd_soc_codec *codec = &wm8960->codec;
+ struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+ struct wm8960_data *pdata = dev_get_platdata(codec->dev);
int ret;
u16 reg;
- if (wm8960_codec) {
- dev_err(codec->dev, "Another WM8960 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- codec->set_bias_level = wm8960_set_bias_level_out3;
+ wm8960->set_bias_level = wm8960_set_bias_level_out3;
+ codec->control_data = wm8960->control_data;
if (!pdata) {
dev_warn(codec->dev, "No platform data supplied\n");
@@ -988,39 +934,22 @@
}
if (pdata->capless)
- codec->set_bias_level = wm8960_set_bias_level_capless;
+ wm8960->set_bias_level = wm8960_set_bias_level_capless;
}
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8960);
- codec->name = "WM8960";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->dai = &wm8960_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = WM8960_CACHEREGNUM;
- codec->reg_cache = &wm8960->reg_cache;
-
- memcpy(codec->reg_cache, wm8960_reg, sizeof(wm8960_reg));
-
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8960->control_type);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
ret = wm8960_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
- goto err;
+ return ret;
}
- wm8960_dai.dev = codec->dev;
-
- codec->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Latch the update bits */
reg = snd_soc_read(codec, WM8960_LINVOL);
@@ -1044,62 +973,58 @@
reg = snd_soc_read(codec, WM8960_ROUT2);
snd_soc_write(codec, WM8960_ROUT2, reg | 0x100);
- wm8960_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dai(&wm8960_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
+ snd_soc_add_controls(codec, wm8960_snd_controls,
+ ARRAY_SIZE(wm8960_snd_controls));
+ wm8960_add_widgets(codec);
return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- kfree(wm8960);
- return ret;
}
-static void wm8960_unregister(struct wm8960_priv *wm8960)
+/* power down chip */
+static int wm8960_remove(struct snd_soc_codec *codec)
{
- wm8960->codec.set_bias_level(&wm8960->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dai(&wm8960_dai);
- snd_soc_unregister_codec(&wm8960->codec);
- kfree(wm8960);
- wm8960_codec = NULL;
+ struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+
+ wm8960->set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_wm8960 = {
+ .probe = wm8960_probe,
+ .remove = wm8960_remove,
+ .suspend = wm8960_suspend,
+ .resume = wm8960_resume,
+ .set_bias_level = wm8960_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8960_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8960_reg,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static __devinit int wm8960_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm8960_priv *wm8960;
- struct snd_soc_codec *codec;
+ int ret;
wm8960 = kzalloc(sizeof(struct wm8960_priv), GFP_KERNEL);
if (wm8960 == NULL)
return -ENOMEM;
- codec = &wm8960->codec;
-
i2c_set_clientdata(i2c, wm8960);
- codec->control_data = i2c;
+ wm8960->control_data = i2c;
- codec->dev = &i2c->dev;
-
- return wm8960_register(wm8960, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8960, &wm8960_dai, 1);
+ if (ret < 0)
+ kfree(wm8960);
+ return ret;
}
static __devexit int wm8960_i2c_remove(struct i2c_client *client)
{
- struct wm8960_priv *wm8960 = i2c_get_clientdata(client);
- wm8960_unregister(wm8960);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -1111,35 +1036,37 @@
static struct i2c_driver wm8960_i2c_driver = {
.driver = {
- .name = "wm8960",
+ .name = "wm8960-codec",
.owner = THIS_MODULE,
},
.probe = wm8960_i2c_probe,
.remove = __devexit_p(wm8960_i2c_remove),
.id_table = wm8960_i2c_id,
};
+#endif
static int __init wm8960_modinit(void)
{
- int ret;
-
+ int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8960_i2c_driver);
if (ret != 0) {
printk(KERN_ERR "Failed to register WM8960 I2C driver: %d\n",
ret);
}
-
+#endif
return ret;
}
module_init(wm8960_modinit);
static void __exit wm8960_exit(void)
{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&wm8960_i2c_driver);
+#endif
}
module_exit(wm8960_exit);
-
MODULE_DESCRIPTION("ASoC WM8960 driver");
MODULE_AUTHOR("Liam Girdwood");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8960.h b/sound/soc/codecs/wm8960.h
index a5ef654..2d8163d 100644
--- a/sound/soc/codecs/wm8960.h
+++ b/sound/soc/codecs/wm8960.h
@@ -110,7 +110,4 @@
#define WM8960_OPCLK_DIV_5_5 (4 << 0)
#define WM8960_OPCLK_DIV_6 (5 << 0)
-extern struct snd_soc_dai wm8960_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8960;
-
#endif
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index 2549d3a..4f326f6 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -288,7 +288,7 @@
};
struct wm8961_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
int sysclk;
u16 reg_cache[WM8961_MAX_REGISTER];
};
@@ -940,8 +940,8 @@
.set_clkdiv = wm8961_set_clkdiv,
};
-struct snd_soc_dai wm8961_dai = {
- .name = "WM8961",
+static struct snd_soc_dai_driver wm8961_dai = {
+ .name = "wm8961-hifi",
.playback = {
.stream_name = "HiFi Playback",
.channels_min = 1,
@@ -956,140 +956,22 @@
.formats = WM8961_FORMATS,},
.ops = &wm8961_dai_ops,
};
-EXPORT_SYMBOL_GPL(wm8961_dai);
-
-static struct snd_soc_codec *wm8961_codec;
-
-static int wm8961_probe(struct platform_device *pdev)
+static int wm8961_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
int ret = 0;
-
- if (wm8961_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8961_codec;
- codec = wm8961_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- snd_soc_add_controls(codec, wm8961_snd_controls,
- ARRAY_SIZE(wm8961_snd_controls));
- snd_soc_dapm_new_controls(codec, wm8961_dapm_widgets,
- ARRAY_SIZE(wm8961_dapm_widgets));
- snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
-
- return ret;
-
-pcm_err:
- return ret;
-}
-
-static int wm8961_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int wm8961_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- return 0;
-}
-
-static int wm8961_resume(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
- u16 *reg_cache = codec->reg_cache;
- int i;
-
- for (i = 0; i < codec->reg_cache_size; i++) {
- if (reg_cache[i] == wm8961_reg_defaults[i])
- continue;
-
- if (i == WM8961_SOFTWARE_RESET)
- continue;
-
- snd_soc_write(codec, i, reg_cache[i]);
- }
-
- wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-#else
-#define wm8961_suspend NULL
-#define wm8961_resume NULL
-#endif
-
-struct snd_soc_codec_device soc_codec_dev_wm8961 = {
- .probe = wm8961_probe,
- .remove = wm8961_remove,
- .suspend = wm8961_suspend,
- .resume = wm8961_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8961);
-
-static int wm8961_register(struct wm8961_priv *wm8961)
-{
- struct snd_soc_codec *codec = &wm8961->codec;
- int ret;
u16 reg;
- if (wm8961_codec) {
- dev_err(codec->dev, "Another WM8961 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8961);
- codec->name = "WM8961";
- codec->owner = THIS_MODULE;
- codec->dai = &wm8961_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(wm8961->reg_cache);
- codec->reg_cache = &wm8961->reg_cache;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8961_set_bias_level;
- codec->volatile_register = wm8961_volatile_register;
-
- memcpy(codec->reg_cache, wm8961_reg_defaults,
- sizeof(wm8961_reg_defaults));
-
ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
reg = snd_soc_read(codec, WM8961_SOFTWARE_RESET);
if (reg != 0x1801) {
dev_err(codec->dev, "Device is not a WM8961: ID=0x%x\n", reg);
- ret = -EINVAL;
- goto err;
+ return -EINVAL;
}
/* This isn't volatile - readback doesn't correspond to write */
@@ -1102,7 +984,7 @@
ret = wm8961_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
- goto err;
+ return ret;
}
/* Enable class W */
@@ -1140,64 +1022,89 @@
wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- wm8961_dai.dev = codec->dev;
-
- wm8961_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dai(&wm8961_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
+ snd_soc_add_controls(codec, wm8961_snd_controls,
+ ARRAY_SIZE(wm8961_snd_controls));
+ snd_soc_dapm_new_controls(codec, wm8961_dapm_widgets,
+ ARRAY_SIZE(wm8961_dapm_widgets));
+ snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- kfree(wm8961);
- return ret;
}
-static void wm8961_unregister(struct wm8961_priv *wm8961)
+static int wm8961_remove(struct snd_soc_codec *codec)
{
- wm8961_set_bias_level(&wm8961->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dai(&wm8961_dai);
- snd_soc_unregister_codec(&wm8961->codec);
- kfree(wm8961);
- wm8961_codec = NULL;
+ wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
}
+#ifdef CONFIG_PM
+static int wm8961_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+ wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+static int wm8961_resume(struct snd_soc_codec *codec)
+{
+ u16 *reg_cache = codec->reg_cache;
+ int i;
+
+ for (i = 0; i < codec->driver->reg_cache_size; i++) {
+ if (reg_cache[i] == wm8961_reg_defaults[i])
+ continue;
+
+ if (i == WM8961_SOFTWARE_RESET)
+ continue;
+
+ snd_soc_write(codec, i, reg_cache[i]);
+ }
+
+ wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ return 0;
+}
+#else
+#define wm8961_suspend NULL
+#define wm8961_resume NULL
+#endif
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8961 = {
+ .probe = wm8961_probe,
+ .remove = wm8961_remove,
+ .suspend = wm8961_suspend,
+ .resume = wm8961_resume,
+ .set_bias_level = wm8961_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8961_reg_defaults),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8961_reg_defaults,
+ .volatile_register = wm8961_volatile_register,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static __devinit int wm8961_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm8961_priv *wm8961;
- struct snd_soc_codec *codec;
+ int ret;
wm8961 = kzalloc(sizeof(struct wm8961_priv), GFP_KERNEL);
if (wm8961 == NULL)
return -ENOMEM;
- codec = &wm8961->codec;
-
i2c_set_clientdata(i2c, wm8961);
- codec->control_data = i2c;
- codec->dev = &i2c->dev;
-
- return wm8961_register(wm8961);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8961, &wm8961_dai, 1);
+ if (ret < 0)
+ kfree(wm8961);
+ return ret;
}
static __devexit int wm8961_i2c_remove(struct i2c_client *client)
{
- struct wm8961_priv *wm8961 = i2c_get_clientdata(client);
- wm8961_unregister(wm8961);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -1209,35 +1116,37 @@
static struct i2c_driver wm8961_i2c_driver = {
.driver = {
- .name = "wm8961",
+ .name = "wm8961-codec",
.owner = THIS_MODULE,
},
.probe = wm8961_i2c_probe,
.remove = __devexit_p(wm8961_i2c_remove),
.id_table = wm8961_i2c_id,
};
+#endif
static int __init wm8961_modinit(void)
{
- int ret;
-
+ int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8961_i2c_driver);
if (ret != 0) {
- printk(KERN_ERR "Failed to register WM8961 I2C driver: %d\n",
+ printk(KERN_ERR "Failed to register wm8961 I2C driver: %d\n",
ret);
}
-
+#endif
return ret;
}
module_init(wm8961_modinit);
static void __exit wm8961_exit(void)
{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&wm8961_i2c_driver);
+#endif
}
module_exit(wm8961_exit);
-
MODULE_DESCRIPTION("ASoC WM8961 driver");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8961.h b/sound/soc/codecs/wm8961.h
index 5513bfd..1d736e5 100644
--- a/sound/soc/codecs/wm8961.h
+++ b/sound/soc/codecs/wm8961.h
@@ -11,9 +11,6 @@
#include <sound/soc.h>
-extern struct snd_soc_codec_device soc_codec_dev_wm8961;
-extern struct snd_soc_dai wm8961_dai;
-
#define WM8961_BCLK 1
#define WM8961_LRCLK 2
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
new file mode 100644
index 0000000..894d0cd
--- /dev/null
+++ b/sound/soc/codecs/wm8962.c
@@ -0,0 +1,3977 @@
+/*
+ * wm8962.c -- WM8962 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *
+ * 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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/gcd.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/wm8962.h>
+
+#include "wm8962.h"
+
+#define WM8962_NUM_SUPPLIES 8
+static const char *wm8962_supply_names[WM8962_NUM_SUPPLIES] = {
+ "DCVDD",
+ "DBVDD",
+ "AVDD",
+ "CPVDD",
+ "MICVDD",
+ "PLLVDD",
+ "SPKVDD1",
+ "SPKVDD2",
+};
+
+/* codec private data */
+struct wm8962_priv {
+ struct snd_soc_codec *codec;
+
+ u16 reg_cache[WM8962_MAX_REGISTER + 1];
+
+ int sysclk;
+ int sysclk_rate;
+
+ int bclk; /* Desired BCLK */
+ int lrclk;
+
+ int fll_src;
+ int fll_fref;
+ int fll_fout;
+
+ struct delayed_work mic_work;
+ struct snd_soc_jack *jack;
+
+ struct regulator_bulk_data supplies[WM8962_NUM_SUPPLIES];
+ struct notifier_block disable_nb[WM8962_NUM_SUPPLIES];
+
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+ struct input_dev *beep;
+ struct work_struct beep_work;
+ int beep_rate;
+#endif
+
+#ifdef CONFIG_GPIOLIB
+ struct gpio_chip gpio_chip;
+#endif
+};
+
+/* We can't use the same notifier block for more than one supply and
+ * there's no way I can see to get from a callback to the caller
+ * except container_of().
+ */
+#define WM8962_REGULATOR_EVENT(n) \
+static int wm8962_regulator_event_##n(struct notifier_block *nb, \
+ unsigned long event, void *data) \
+{ \
+ struct wm8962_priv *wm8962 = container_of(nb, struct wm8962_priv, \
+ disable_nb[n]); \
+ if (event & REGULATOR_EVENT_DISABLE) { \
+ wm8962->codec->cache_sync = 1; \
+ } \
+ return 0; \
+}
+
+WM8962_REGULATOR_EVENT(0)
+WM8962_REGULATOR_EVENT(1)
+WM8962_REGULATOR_EVENT(2)
+WM8962_REGULATOR_EVENT(3)
+WM8962_REGULATOR_EVENT(4)
+WM8962_REGULATOR_EVENT(5)
+WM8962_REGULATOR_EVENT(6)
+WM8962_REGULATOR_EVENT(7)
+
+static const u16 wm8962_reg[WM8962_MAX_REGISTER + 1] = {
+ [0] = 0x009F, /* R0 - Left Input volume */
+ [1] = 0x049F, /* R1 - Right Input volume */
+ [2] = 0x0000, /* R2 - HPOUTL volume */
+ [3] = 0x0000, /* R3 - HPOUTR volume */
+ [4] = 0x0020, /* R4 - Clocking1 */
+ [5] = 0x0018, /* R5 - ADC & DAC Control 1 */
+ [6] = 0x2008, /* R6 - ADC & DAC Control 2 */
+ [7] = 0x000A, /* R7 - Audio Interface 0 */
+ [8] = 0x01E4, /* R8 - Clocking2 */
+ [9] = 0x0300, /* R9 - Audio Interface 1 */
+ [10] = 0x00C0, /* R10 - Left DAC volume */
+ [11] = 0x00C0, /* R11 - Right DAC volume */
+
+ [14] = 0x0040, /* R14 - Audio Interface 2 */
+ [15] = 0x6243, /* R15 - Software Reset */
+
+ [17] = 0x007B, /* R17 - ALC1 */
+ [18] = 0x0000, /* R18 - ALC2 */
+ [19] = 0x1C32, /* R19 - ALC3 */
+ [20] = 0x3200, /* R20 - Noise Gate */
+ [21] = 0x00C0, /* R21 - Left ADC volume */
+ [22] = 0x00C0, /* R22 - Right ADC volume */
+ [23] = 0x0160, /* R23 - Additional control(1) */
+ [24] = 0x0000, /* R24 - Additional control(2) */
+ [25] = 0x0000, /* R25 - Pwr Mgmt (1) */
+ [26] = 0x0000, /* R26 - Pwr Mgmt (2) */
+ [27] = 0x0010, /* R27 - Additional Control (3) */
+ [28] = 0x0000, /* R28 - Anti-pop */
+
+ [30] = 0x005E, /* R30 - Clocking 3 */
+ [31] = 0x0000, /* R31 - Input mixer control (1) */
+ [32] = 0x0145, /* R32 - Left input mixer volume */
+ [33] = 0x0145, /* R33 - Right input mixer volume */
+ [34] = 0x0009, /* R34 - Input mixer control (2) */
+ [35] = 0x0003, /* R35 - Input bias control */
+ [37] = 0x0008, /* R37 - Left input PGA control */
+ [38] = 0x0008, /* R38 - Right input PGA control */
+
+ [40] = 0x0000, /* R40 - SPKOUTL volume */
+ [41] = 0x0000, /* R41 - SPKOUTR volume */
+
+ [47] = 0x0000, /* R47 - Thermal Shutdown Status */
+ [48] = 0x8027, /* R48 - Additional Control (4) */
+ [49] = 0x0010, /* R49 - Class D Control 1 */
+
+ [51] = 0x0003, /* R51 - Class D Control 2 */
+
+ [56] = 0x0506, /* R56 - Clocking 4 */
+ [57] = 0x0000, /* R57 - DAC DSP Mixing (1) */
+ [58] = 0x0000, /* R58 - DAC DSP Mixing (2) */
+
+ [60] = 0x0300, /* R60 - DC Servo 0 */
+ [61] = 0x0300, /* R61 - DC Servo 1 */
+
+ [64] = 0x0810, /* R64 - DC Servo 4 */
+
+ [66] = 0x0000, /* R66 - DC Servo 6 */
+
+ [68] = 0x001B, /* R68 - Analogue PGA Bias */
+ [69] = 0x0000, /* R69 - Analogue HP 0 */
+
+ [71] = 0x01FB, /* R71 - Analogue HP 2 */
+ [72] = 0x0000, /* R72 - Charge Pump 1 */
+
+ [82] = 0x0004, /* R82 - Charge Pump B */
+
+ [87] = 0x0000, /* R87 - Write Sequencer Control 1 */
+
+ [90] = 0x0000, /* R90 - Write Sequencer Control 2 */
+
+ [93] = 0x0000, /* R93 - Write Sequencer Control 3 */
+ [94] = 0x0000, /* R94 - Control Interface */
+
+ [99] = 0x0000, /* R99 - Mixer Enables */
+ [100] = 0x0000, /* R100 - Headphone Mixer (1) */
+ [101] = 0x0000, /* R101 - Headphone Mixer (2) */
+ [102] = 0x013F, /* R102 - Headphone Mixer (3) */
+ [103] = 0x013F, /* R103 - Headphone Mixer (4) */
+
+ [105] = 0x0000, /* R105 - Speaker Mixer (1) */
+ [106] = 0x0000, /* R106 - Speaker Mixer (2) */
+ [107] = 0x013F, /* R107 - Speaker Mixer (3) */
+ [108] = 0x013F, /* R108 - Speaker Mixer (4) */
+ [109] = 0x0003, /* R109 - Speaker Mixer (5) */
+ [110] = 0x0002, /* R110 - Beep Generator (1) */
+
+ [115] = 0x0006, /* R115 - Oscillator Trim (3) */
+ [116] = 0x0026, /* R116 - Oscillator Trim (4) */
+
+ [119] = 0x0000, /* R119 - Oscillator Trim (7) */
+
+ [124] = 0x0011, /* R124 - Analogue Clocking1 */
+ [125] = 0x004B, /* R125 - Analogue Clocking2 */
+ [126] = 0x000D, /* R126 - Analogue Clocking3 */
+ [127] = 0x0000, /* R127 - PLL Software Reset */
+
+ [129] = 0x0000, /* R129 - PLL2 */
+
+ [131] = 0x0000, /* R131 - PLL 4 */
+
+ [136] = 0x0067, /* R136 - PLL 9 */
+ [137] = 0x001C, /* R137 - PLL 10 */
+ [138] = 0x0071, /* R138 - PLL 11 */
+ [139] = 0x00C7, /* R139 - PLL 12 */
+ [140] = 0x0067, /* R140 - PLL 13 */
+ [141] = 0x0048, /* R141 - PLL 14 */
+ [142] = 0x0022, /* R142 - PLL 15 */
+ [143] = 0x0097, /* R143 - PLL 16 */
+
+ [155] = 0x000C, /* R155 - FLL Control (1) */
+ [156] = 0x0039, /* R156 - FLL Control (2) */
+ [157] = 0x0180, /* R157 - FLL Control (3) */
+
+ [159] = 0x0032, /* R159 - FLL Control (5) */
+ [160] = 0x0018, /* R160 - FLL Control (6) */
+ [161] = 0x007D, /* R161 - FLL Control (7) */
+ [162] = 0x0008, /* R162 - FLL Control (8) */
+
+ [252] = 0x0005, /* R252 - General test 1 */
+
+ [256] = 0x0000, /* R256 - DF1 */
+ [257] = 0x0000, /* R257 - DF2 */
+ [258] = 0x0000, /* R258 - DF3 */
+ [259] = 0x0000, /* R259 - DF4 */
+ [260] = 0x0000, /* R260 - DF5 */
+ [261] = 0x0000, /* R261 - DF6 */
+ [262] = 0x0000, /* R262 - DF7 */
+
+ [264] = 0x0000, /* R264 - LHPF1 */
+ [265] = 0x0000, /* R265 - LHPF2 */
+
+ [268] = 0x0000, /* R268 - THREED1 */
+ [269] = 0x0000, /* R269 - THREED2 */
+ [270] = 0x0000, /* R270 - THREED3 */
+ [271] = 0x0000, /* R271 - THREED4 */
+
+ [276] = 0x000C, /* R276 - DRC 1 */
+ [277] = 0x0925, /* R277 - DRC 2 */
+ [278] = 0x0000, /* R278 - DRC 3 */
+ [279] = 0x0000, /* R279 - DRC 4 */
+ [280] = 0x0000, /* R280 - DRC 5 */
+
+ [285] = 0x0000, /* R285 - Tloopback */
+
+ [335] = 0x0004, /* R335 - EQ1 */
+ [336] = 0x6318, /* R336 - EQ2 */
+ [337] = 0x6300, /* R337 - EQ3 */
+ [338] = 0x0FCA, /* R338 - EQ4 */
+ [339] = 0x0400, /* R339 - EQ5 */
+ [340] = 0x00D8, /* R340 - EQ6 */
+ [341] = 0x1EB5, /* R341 - EQ7 */
+ [342] = 0xF145, /* R342 - EQ8 */
+ [343] = 0x0B75, /* R343 - EQ9 */
+ [344] = 0x01C5, /* R344 - EQ10 */
+ [345] = 0x1C58, /* R345 - EQ11 */
+ [346] = 0xF373, /* R346 - EQ12 */
+ [347] = 0x0A54, /* R347 - EQ13 */
+ [348] = 0x0558, /* R348 - EQ14 */
+ [349] = 0x168E, /* R349 - EQ15 */
+ [350] = 0xF829, /* R350 - EQ16 */
+ [351] = 0x07AD, /* R351 - EQ17 */
+ [352] = 0x1103, /* R352 - EQ18 */
+ [353] = 0x0564, /* R353 - EQ19 */
+ [354] = 0x0559, /* R354 - EQ20 */
+ [355] = 0x4000, /* R355 - EQ21 */
+ [356] = 0x6318, /* R356 - EQ22 */
+ [357] = 0x6300, /* R357 - EQ23 */
+ [358] = 0x0FCA, /* R358 - EQ24 */
+ [359] = 0x0400, /* R359 - EQ25 */
+ [360] = 0x00D8, /* R360 - EQ26 */
+ [361] = 0x1EB5, /* R361 - EQ27 */
+ [362] = 0xF145, /* R362 - EQ28 */
+ [363] = 0x0B75, /* R363 - EQ29 */
+ [364] = 0x01C5, /* R364 - EQ30 */
+ [365] = 0x1C58, /* R365 - EQ31 */
+ [366] = 0xF373, /* R366 - EQ32 */
+ [367] = 0x0A54, /* R367 - EQ33 */
+ [368] = 0x0558, /* R368 - EQ34 */
+ [369] = 0x168E, /* R369 - EQ35 */
+ [370] = 0xF829, /* R370 - EQ36 */
+ [371] = 0x07AD, /* R371 - EQ37 */
+ [372] = 0x1103, /* R372 - EQ38 */
+ [373] = 0x0564, /* R373 - EQ39 */
+ [374] = 0x0559, /* R374 - EQ40 */
+ [375] = 0x4000, /* R375 - EQ41 */
+
+ [513] = 0x0000, /* R513 - GPIO 2 */
+ [514] = 0x0000, /* R514 - GPIO 3 */
+
+ [516] = 0x8100, /* R516 - GPIO 5 */
+ [517] = 0x8100, /* R517 - GPIO 6 */
+
+ [560] = 0x0000, /* R560 - Interrupt Status 1 */
+ [561] = 0x0000, /* R561 - Interrupt Status 2 */
+
+ [568] = 0x0030, /* R568 - Interrupt Status 1 Mask */
+ [569] = 0xFFED, /* R569 - Interrupt Status 2 Mask */
+
+ [576] = 0x0000, /* R576 - Interrupt Control */
+
+ [584] = 0x002D, /* R584 - IRQ Debounce */
+
+ [586] = 0x0000, /* R586 - MICINT Source Pol */
+
+ [768] = 0x1C00, /* R768 - DSP2 Power Management */
+
+ [1037] = 0x0000, /* R1037 - DSP2_ExecControl */
+
+ [8192] = 0x0000, /* R8192 - DSP2 Instruction RAM 0 */
+
+ [9216] = 0x0030, /* R9216 - DSP2 Address RAM 2 */
+ [9217] = 0x0000, /* R9217 - DSP2 Address RAM 1 */
+ [9218] = 0x0000, /* R9218 - DSP2 Address RAM 0 */
+
+ [12288] = 0x0000, /* R12288 - DSP2 Data1 RAM 1 */
+ [12289] = 0x0000, /* R12289 - DSP2 Data1 RAM 0 */
+
+ [13312] = 0x0000, /* R13312 - DSP2 Data2 RAM 1 */
+ [13313] = 0x0000, /* R13313 - DSP2 Data2 RAM 0 */
+
+ [14336] = 0x0000, /* R14336 - DSP2 Data3 RAM 1 */
+ [14337] = 0x0000, /* R14337 - DSP2 Data3 RAM 0 */
+
+ [15360] = 0x000A, /* R15360 - DSP2 Coeff RAM 0 */
+
+ [16384] = 0x0000, /* R16384 - RETUNEADC_SHARED_COEFF_1 */
+ [16385] = 0x0000, /* R16385 - RETUNEADC_SHARED_COEFF_0 */
+ [16386] = 0x0000, /* R16386 - RETUNEDAC_SHARED_COEFF_1 */
+ [16387] = 0x0000, /* R16387 - RETUNEDAC_SHARED_COEFF_0 */
+ [16388] = 0x0000, /* R16388 - SOUNDSTAGE_ENABLES_1 */
+ [16389] = 0x0000, /* R16389 - SOUNDSTAGE_ENABLES_0 */
+
+ [16896] = 0x0002, /* R16896 - HDBASS_AI_1 */
+ [16897] = 0xBD12, /* R16897 - HDBASS_AI_0 */
+ [16898] = 0x007C, /* R16898 - HDBASS_AR_1 */
+ [16899] = 0x586C, /* R16899 - HDBASS_AR_0 */
+ [16900] = 0x0053, /* R16900 - HDBASS_B_1 */
+ [16901] = 0x8121, /* R16901 - HDBASS_B_0 */
+ [16902] = 0x003F, /* R16902 - HDBASS_K_1 */
+ [16903] = 0x8BD8, /* R16903 - HDBASS_K_0 */
+ [16904] = 0x0032, /* R16904 - HDBASS_N1_1 */
+ [16905] = 0xF52D, /* R16905 - HDBASS_N1_0 */
+ [16906] = 0x0065, /* R16906 - HDBASS_N2_1 */
+ [16907] = 0xAC8C, /* R16907 - HDBASS_N2_0 */
+ [16908] = 0x006B, /* R16908 - HDBASS_N3_1 */
+ [16909] = 0xE087, /* R16909 - HDBASS_N3_0 */
+ [16910] = 0x0072, /* R16910 - HDBASS_N4_1 */
+ [16911] = 0x1483, /* R16911 - HDBASS_N4_0 */
+ [16912] = 0x0072, /* R16912 - HDBASS_N5_1 */
+ [16913] = 0x1483, /* R16913 - HDBASS_N5_0 */
+ [16914] = 0x0043, /* R16914 - HDBASS_X1_1 */
+ [16915] = 0x3525, /* R16915 - HDBASS_X1_0 */
+ [16916] = 0x0006, /* R16916 - HDBASS_X2_1 */
+ [16917] = 0x6A4A, /* R16917 - HDBASS_X2_0 */
+ [16918] = 0x0043, /* R16918 - HDBASS_X3_1 */
+ [16919] = 0x6079, /* R16919 - HDBASS_X3_0 */
+ [16920] = 0x0008, /* R16920 - HDBASS_ATK_1 */
+ [16921] = 0x0000, /* R16921 - HDBASS_ATK_0 */
+ [16922] = 0x0001, /* R16922 - HDBASS_DCY_1 */
+ [16923] = 0x0000, /* R16923 - HDBASS_DCY_0 */
+ [16924] = 0x0059, /* R16924 - HDBASS_PG_1 */
+ [16925] = 0x999A, /* R16925 - HDBASS_PG_0 */
+
+ [17048] = 0x0083, /* R17408 - HPF_C_1 */
+ [17049] = 0x98AD, /* R17409 - HPF_C_0 */
+
+ [17920] = 0x007F, /* R17920 - ADCL_RETUNE_C1_1 */
+ [17921] = 0xFFFF, /* R17921 - ADCL_RETUNE_C1_0 */
+ [17922] = 0x0000, /* R17922 - ADCL_RETUNE_C2_1 */
+ [17923] = 0x0000, /* R17923 - ADCL_RETUNE_C2_0 */
+ [17924] = 0x0000, /* R17924 - ADCL_RETUNE_C3_1 */
+ [17925] = 0x0000, /* R17925 - ADCL_RETUNE_C3_0 */
+ [17926] = 0x0000, /* R17926 - ADCL_RETUNE_C4_1 */
+ [17927] = 0x0000, /* R17927 - ADCL_RETUNE_C4_0 */
+ [17928] = 0x0000, /* R17928 - ADCL_RETUNE_C5_1 */
+ [17929] = 0x0000, /* R17929 - ADCL_RETUNE_C5_0 */
+ [17930] = 0x0000, /* R17930 - ADCL_RETUNE_C6_1 */
+ [17931] = 0x0000, /* R17931 - ADCL_RETUNE_C6_0 */
+ [17932] = 0x0000, /* R17932 - ADCL_RETUNE_C7_1 */
+ [17933] = 0x0000, /* R17933 - ADCL_RETUNE_C7_0 */
+ [17934] = 0x0000, /* R17934 - ADCL_RETUNE_C8_1 */
+ [17935] = 0x0000, /* R17935 - ADCL_RETUNE_C8_0 */
+ [17936] = 0x0000, /* R17936 - ADCL_RETUNE_C9_1 */
+ [17937] = 0x0000, /* R17937 - ADCL_RETUNE_C9_0 */
+ [17938] = 0x0000, /* R17938 - ADCL_RETUNE_C10_1 */
+ [17939] = 0x0000, /* R17939 - ADCL_RETUNE_C10_0 */
+ [17940] = 0x0000, /* R17940 - ADCL_RETUNE_C11_1 */
+ [17941] = 0x0000, /* R17941 - ADCL_RETUNE_C11_0 */
+ [17942] = 0x0000, /* R17942 - ADCL_RETUNE_C12_1 */
+ [17943] = 0x0000, /* R17943 - ADCL_RETUNE_C12_0 */
+ [17944] = 0x0000, /* R17944 - ADCL_RETUNE_C13_1 */
+ [17945] = 0x0000, /* R17945 - ADCL_RETUNE_C13_0 */
+ [17946] = 0x0000, /* R17946 - ADCL_RETUNE_C14_1 */
+ [17947] = 0x0000, /* R17947 - ADCL_RETUNE_C14_0 */
+ [17948] = 0x0000, /* R17948 - ADCL_RETUNE_C15_1 */
+ [17949] = 0x0000, /* R17949 - ADCL_RETUNE_C15_0 */
+ [17950] = 0x0000, /* R17950 - ADCL_RETUNE_C16_1 */
+ [17951] = 0x0000, /* R17951 - ADCL_RETUNE_C16_0 */
+ [17952] = 0x0000, /* R17952 - ADCL_RETUNE_C17_1 */
+ [17953] = 0x0000, /* R17953 - ADCL_RETUNE_C17_0 */
+ [17954] = 0x0000, /* R17954 - ADCL_RETUNE_C18_1 */
+ [17955] = 0x0000, /* R17955 - ADCL_RETUNE_C18_0 */
+ [17956] = 0x0000, /* R17956 - ADCL_RETUNE_C19_1 */
+ [17957] = 0x0000, /* R17957 - ADCL_RETUNE_C19_0 */
+ [17958] = 0x0000, /* R17958 - ADCL_RETUNE_C20_1 */
+ [17959] = 0x0000, /* R17959 - ADCL_RETUNE_C20_0 */
+ [17960] = 0x0000, /* R17960 - ADCL_RETUNE_C21_1 */
+ [17961] = 0x0000, /* R17961 - ADCL_RETUNE_C21_0 */
+ [17962] = 0x0000, /* R17962 - ADCL_RETUNE_C22_1 */
+ [17963] = 0x0000, /* R17963 - ADCL_RETUNE_C22_0 */
+ [17964] = 0x0000, /* R17964 - ADCL_RETUNE_C23_1 */
+ [17965] = 0x0000, /* R17965 - ADCL_RETUNE_C23_0 */
+ [17966] = 0x0000, /* R17966 - ADCL_RETUNE_C24_1 */
+ [17967] = 0x0000, /* R17967 - ADCL_RETUNE_C24_0 */
+ [17968] = 0x0000, /* R17968 - ADCL_RETUNE_C25_1 */
+ [17969] = 0x0000, /* R17969 - ADCL_RETUNE_C25_0 */
+ [17970] = 0x0000, /* R17970 - ADCL_RETUNE_C26_1 */
+ [17971] = 0x0000, /* R17971 - ADCL_RETUNE_C26_0 */
+ [17972] = 0x0000, /* R17972 - ADCL_RETUNE_C27_1 */
+ [17973] = 0x0000, /* R17973 - ADCL_RETUNE_C27_0 */
+ [17974] = 0x0000, /* R17974 - ADCL_RETUNE_C28_1 */
+ [17975] = 0x0000, /* R17975 - ADCL_RETUNE_C28_0 */
+ [17976] = 0x0000, /* R17976 - ADCL_RETUNE_C29_1 */
+ [17977] = 0x0000, /* R17977 - ADCL_RETUNE_C29_0 */
+ [17978] = 0x0000, /* R17978 - ADCL_RETUNE_C30_1 */
+ [17979] = 0x0000, /* R17979 - ADCL_RETUNE_C30_0 */
+ [17980] = 0x0000, /* R17980 - ADCL_RETUNE_C31_1 */
+ [17981] = 0x0000, /* R17981 - ADCL_RETUNE_C31_0 */
+ [17982] = 0x0000, /* R17982 - ADCL_RETUNE_C32_1 */
+ [17983] = 0x0000, /* R17983 - ADCL_RETUNE_C32_0 */
+
+ [18432] = 0x0020, /* R18432 - RETUNEADC_PG2_1 */
+ [18433] = 0x0000, /* R18433 - RETUNEADC_PG2_0 */
+ [18434] = 0x0040, /* R18434 - RETUNEADC_PG_1 */
+ [18435] = 0x0000, /* R18435 - RETUNEADC_PG_0 */
+
+ [18944] = 0x007F, /* R18944 - ADCR_RETUNE_C1_1 */
+ [18945] = 0xFFFF, /* R18945 - ADCR_RETUNE_C1_0 */
+ [18946] = 0x0000, /* R18946 - ADCR_RETUNE_C2_1 */
+ [18947] = 0x0000, /* R18947 - ADCR_RETUNE_C2_0 */
+ [18948] = 0x0000, /* R18948 - ADCR_RETUNE_C3_1 */
+ [18949] = 0x0000, /* R18949 - ADCR_RETUNE_C3_0 */
+ [18950] = 0x0000, /* R18950 - ADCR_RETUNE_C4_1 */
+ [18951] = 0x0000, /* R18951 - ADCR_RETUNE_C4_0 */
+ [18952] = 0x0000, /* R18952 - ADCR_RETUNE_C5_1 */
+ [18953] = 0x0000, /* R18953 - ADCR_RETUNE_C5_0 */
+ [18954] = 0x0000, /* R18954 - ADCR_RETUNE_C6_1 */
+ [18955] = 0x0000, /* R18955 - ADCR_RETUNE_C6_0 */
+ [18956] = 0x0000, /* R18956 - ADCR_RETUNE_C7_1 */
+ [18957] = 0x0000, /* R18957 - ADCR_RETUNE_C7_0 */
+ [18958] = 0x0000, /* R18958 - ADCR_RETUNE_C8_1 */
+ [18959] = 0x0000, /* R18959 - ADCR_RETUNE_C8_0 */
+ [18960] = 0x0000, /* R18960 - ADCR_RETUNE_C9_1 */
+ [18961] = 0x0000, /* R18961 - ADCR_RETUNE_C9_0 */
+ [18962] = 0x0000, /* R18962 - ADCR_RETUNE_C10_1 */
+ [18963] = 0x0000, /* R18963 - ADCR_RETUNE_C10_0 */
+ [18964] = 0x0000, /* R18964 - ADCR_RETUNE_C11_1 */
+ [18965] = 0x0000, /* R18965 - ADCR_RETUNE_C11_0 */
+ [18966] = 0x0000, /* R18966 - ADCR_RETUNE_C12_1 */
+ [18967] = 0x0000, /* R18967 - ADCR_RETUNE_C12_0 */
+ [18968] = 0x0000, /* R18968 - ADCR_RETUNE_C13_1 */
+ [18969] = 0x0000, /* R18969 - ADCR_RETUNE_C13_0 */
+ [18970] = 0x0000, /* R18970 - ADCR_RETUNE_C14_1 */
+ [18971] = 0x0000, /* R18971 - ADCR_RETUNE_C14_0 */
+ [18972] = 0x0000, /* R18972 - ADCR_RETUNE_C15_1 */
+ [18973] = 0x0000, /* R18973 - ADCR_RETUNE_C15_0 */
+ [18974] = 0x0000, /* R18974 - ADCR_RETUNE_C16_1 */
+ [18975] = 0x0000, /* R18975 - ADCR_RETUNE_C16_0 */
+ [18976] = 0x0000, /* R18976 - ADCR_RETUNE_C17_1 */
+ [18977] = 0x0000, /* R18977 - ADCR_RETUNE_C17_0 */
+ [18978] = 0x0000, /* R18978 - ADCR_RETUNE_C18_1 */
+ [18979] = 0x0000, /* R18979 - ADCR_RETUNE_C18_0 */
+ [18980] = 0x0000, /* R18980 - ADCR_RETUNE_C19_1 */
+ [18981] = 0x0000, /* R18981 - ADCR_RETUNE_C19_0 */
+ [18982] = 0x0000, /* R18982 - ADCR_RETUNE_C20_1 */
+ [18983] = 0x0000, /* R18983 - ADCR_RETUNE_C20_0 */
+ [18984] = 0x0000, /* R18984 - ADCR_RETUNE_C21_1 */
+ [18985] = 0x0000, /* R18985 - ADCR_RETUNE_C21_0 */
+ [18986] = 0x0000, /* R18986 - ADCR_RETUNE_C22_1 */
+ [18987] = 0x0000, /* R18987 - ADCR_RETUNE_C22_0 */
+ [18988] = 0x0000, /* R18988 - ADCR_RETUNE_C23_1 */
+ [18989] = 0x0000, /* R18989 - ADCR_RETUNE_C23_0 */
+ [18990] = 0x0000, /* R18990 - ADCR_RETUNE_C24_1 */
+ [18991] = 0x0000, /* R18991 - ADCR_RETUNE_C24_0 */
+ [18992] = 0x0000, /* R18992 - ADCR_RETUNE_C25_1 */
+ [18993] = 0x0000, /* R18993 - ADCR_RETUNE_C25_0 */
+ [18994] = 0x0000, /* R18994 - ADCR_RETUNE_C26_1 */
+ [18995] = 0x0000, /* R18995 - ADCR_RETUNE_C26_0 */
+ [18996] = 0x0000, /* R18996 - ADCR_RETUNE_C27_1 */
+ [18997] = 0x0000, /* R18997 - ADCR_RETUNE_C27_0 */
+ [18998] = 0x0000, /* R18998 - ADCR_RETUNE_C28_1 */
+ [18999] = 0x0000, /* R18999 - ADCR_RETUNE_C28_0 */
+ [19000] = 0x0000, /* R19000 - ADCR_RETUNE_C29_1 */
+ [19001] = 0x0000, /* R19001 - ADCR_RETUNE_C29_0 */
+ [19002] = 0x0000, /* R19002 - ADCR_RETUNE_C30_1 */
+ [19003] = 0x0000, /* R19003 - ADCR_RETUNE_C30_0 */
+ [19004] = 0x0000, /* R19004 - ADCR_RETUNE_C31_1 */
+ [19005] = 0x0000, /* R19005 - ADCR_RETUNE_C31_0 */
+ [19006] = 0x0000, /* R19006 - ADCR_RETUNE_C32_1 */
+ [19007] = 0x0000, /* R19007 - ADCR_RETUNE_C32_0 */
+
+ [19456] = 0x007F, /* R19456 - DACL_RETUNE_C1_1 */
+ [19457] = 0xFFFF, /* R19457 - DACL_RETUNE_C1_0 */
+ [19458] = 0x0000, /* R19458 - DACL_RETUNE_C2_1 */
+ [19459] = 0x0000, /* R19459 - DACL_RETUNE_C2_0 */
+ [19460] = 0x0000, /* R19460 - DACL_RETUNE_C3_1 */
+ [19461] = 0x0000, /* R19461 - DACL_RETUNE_C3_0 */
+ [19462] = 0x0000, /* R19462 - DACL_RETUNE_C4_1 */
+ [19463] = 0x0000, /* R19463 - DACL_RETUNE_C4_0 */
+ [19464] = 0x0000, /* R19464 - DACL_RETUNE_C5_1 */
+ [19465] = 0x0000, /* R19465 - DACL_RETUNE_C5_0 */
+ [19466] = 0x0000, /* R19466 - DACL_RETUNE_C6_1 */
+ [19467] = 0x0000, /* R19467 - DACL_RETUNE_C6_0 */
+ [19468] = 0x0000, /* R19468 - DACL_RETUNE_C7_1 */
+ [19469] = 0x0000, /* R19469 - DACL_RETUNE_C7_0 */
+ [19470] = 0x0000, /* R19470 - DACL_RETUNE_C8_1 */
+ [19471] = 0x0000, /* R19471 - DACL_RETUNE_C8_0 */
+ [19472] = 0x0000, /* R19472 - DACL_RETUNE_C9_1 */
+ [19473] = 0x0000, /* R19473 - DACL_RETUNE_C9_0 */
+ [19474] = 0x0000, /* R19474 - DACL_RETUNE_C10_1 */
+ [19475] = 0x0000, /* R19475 - DACL_RETUNE_C10_0 */
+ [19476] = 0x0000, /* R19476 - DACL_RETUNE_C11_1 */
+ [19477] = 0x0000, /* R19477 - DACL_RETUNE_C11_0 */
+ [19478] = 0x0000, /* R19478 - DACL_RETUNE_C12_1 */
+ [19479] = 0x0000, /* R19479 - DACL_RETUNE_C12_0 */
+ [19480] = 0x0000, /* R19480 - DACL_RETUNE_C13_1 */
+ [19481] = 0x0000, /* R19481 - DACL_RETUNE_C13_0 */
+ [19482] = 0x0000, /* R19482 - DACL_RETUNE_C14_1 */
+ [19483] = 0x0000, /* R19483 - DACL_RETUNE_C14_0 */
+ [19484] = 0x0000, /* R19484 - DACL_RETUNE_C15_1 */
+ [19485] = 0x0000, /* R19485 - DACL_RETUNE_C15_0 */
+ [19486] = 0x0000, /* R19486 - DACL_RETUNE_C16_1 */
+ [19487] = 0x0000, /* R19487 - DACL_RETUNE_C16_0 */
+ [19488] = 0x0000, /* R19488 - DACL_RETUNE_C17_1 */
+ [19489] = 0x0000, /* R19489 - DACL_RETUNE_C17_0 */
+ [19490] = 0x0000, /* R19490 - DACL_RETUNE_C18_1 */
+ [19491] = 0x0000, /* R19491 - DACL_RETUNE_C18_0 */
+ [19492] = 0x0000, /* R19492 - DACL_RETUNE_C19_1 */
+ [19493] = 0x0000, /* R19493 - DACL_RETUNE_C19_0 */
+ [19494] = 0x0000, /* R19494 - DACL_RETUNE_C20_1 */
+ [19495] = 0x0000, /* R19495 - DACL_RETUNE_C20_0 */
+ [19496] = 0x0000, /* R19496 - DACL_RETUNE_C21_1 */
+ [19497] = 0x0000, /* R19497 - DACL_RETUNE_C21_0 */
+ [19498] = 0x0000, /* R19498 - DACL_RETUNE_C22_1 */
+ [19499] = 0x0000, /* R19499 - DACL_RETUNE_C22_0 */
+ [19500] = 0x0000, /* R19500 - DACL_RETUNE_C23_1 */
+ [19501] = 0x0000, /* R19501 - DACL_RETUNE_C23_0 */
+ [19502] = 0x0000, /* R19502 - DACL_RETUNE_C24_1 */
+ [19503] = 0x0000, /* R19503 - DACL_RETUNE_C24_0 */
+ [19504] = 0x0000, /* R19504 - DACL_RETUNE_C25_1 */
+ [19505] = 0x0000, /* R19505 - DACL_RETUNE_C25_0 */
+ [19506] = 0x0000, /* R19506 - DACL_RETUNE_C26_1 */
+ [19507] = 0x0000, /* R19507 - DACL_RETUNE_C26_0 */
+ [19508] = 0x0000, /* R19508 - DACL_RETUNE_C27_1 */
+ [19509] = 0x0000, /* R19509 - DACL_RETUNE_C27_0 */
+ [19510] = 0x0000, /* R19510 - DACL_RETUNE_C28_1 */
+ [19511] = 0x0000, /* R19511 - DACL_RETUNE_C28_0 */
+ [19512] = 0x0000, /* R19512 - DACL_RETUNE_C29_1 */
+ [19513] = 0x0000, /* R19513 - DACL_RETUNE_C29_0 */
+ [19514] = 0x0000, /* R19514 - DACL_RETUNE_C30_1 */
+ [19515] = 0x0000, /* R19515 - DACL_RETUNE_C30_0 */
+ [19516] = 0x0000, /* R19516 - DACL_RETUNE_C31_1 */
+ [19517] = 0x0000, /* R19517 - DACL_RETUNE_C31_0 */
+ [19518] = 0x0000, /* R19518 - DACL_RETUNE_C32_1 */
+ [19519] = 0x0000, /* R19519 - DACL_RETUNE_C32_0 */
+
+ [19968] = 0x0020, /* R19968 - RETUNEDAC_PG2_1 */
+ [19969] = 0x0000, /* R19969 - RETUNEDAC_PG2_0 */
+ [19970] = 0x0040, /* R19970 - RETUNEDAC_PG_1 */
+ [19971] = 0x0000, /* R19971 - RETUNEDAC_PG_0 */
+
+ [20480] = 0x007F, /* R20480 - DACR_RETUNE_C1_1 */
+ [20481] = 0xFFFF, /* R20481 - DACR_RETUNE_C1_0 */
+ [20482] = 0x0000, /* R20482 - DACR_RETUNE_C2_1 */
+ [20483] = 0x0000, /* R20483 - DACR_RETUNE_C2_0 */
+ [20484] = 0x0000, /* R20484 - DACR_RETUNE_C3_1 */
+ [20485] = 0x0000, /* R20485 - DACR_RETUNE_C3_0 */
+ [20486] = 0x0000, /* R20486 - DACR_RETUNE_C4_1 */
+ [20487] = 0x0000, /* R20487 - DACR_RETUNE_C4_0 */
+ [20488] = 0x0000, /* R20488 - DACR_RETUNE_C5_1 */
+ [20489] = 0x0000, /* R20489 - DACR_RETUNE_C5_0 */
+ [20490] = 0x0000, /* R20490 - DACR_RETUNE_C6_1 */
+ [20491] = 0x0000, /* R20491 - DACR_RETUNE_C6_0 */
+ [20492] = 0x0000, /* R20492 - DACR_RETUNE_C7_1 */
+ [20493] = 0x0000, /* R20493 - DACR_RETUNE_C7_0 */
+ [20494] = 0x0000, /* R20494 - DACR_RETUNE_C8_1 */
+ [20495] = 0x0000, /* R20495 - DACR_RETUNE_C8_0 */
+ [20496] = 0x0000, /* R20496 - DACR_RETUNE_C9_1 */
+ [20497] = 0x0000, /* R20497 - DACR_RETUNE_C9_0 */
+ [20498] = 0x0000, /* R20498 - DACR_RETUNE_C10_1 */
+ [20499] = 0x0000, /* R20499 - DACR_RETUNE_C10_0 */
+ [20500] = 0x0000, /* R20500 - DACR_RETUNE_C11_1 */
+ [20501] = 0x0000, /* R20501 - DACR_RETUNE_C11_0 */
+ [20502] = 0x0000, /* R20502 - DACR_RETUNE_C12_1 */
+ [20503] = 0x0000, /* R20503 - DACR_RETUNE_C12_0 */
+ [20504] = 0x0000, /* R20504 - DACR_RETUNE_C13_1 */
+ [20505] = 0x0000, /* R20505 - DACR_RETUNE_C13_0 */
+ [20506] = 0x0000, /* R20506 - DACR_RETUNE_C14_1 */
+ [20507] = 0x0000, /* R20507 - DACR_RETUNE_C14_0 */
+ [20508] = 0x0000, /* R20508 - DACR_RETUNE_C15_1 */
+ [20509] = 0x0000, /* R20509 - DACR_RETUNE_C15_0 */
+ [20510] = 0x0000, /* R20510 - DACR_RETUNE_C16_1 */
+ [20511] = 0x0000, /* R20511 - DACR_RETUNE_C16_0 */
+ [20512] = 0x0000, /* R20512 - DACR_RETUNE_C17_1 */
+ [20513] = 0x0000, /* R20513 - DACR_RETUNE_C17_0 */
+ [20514] = 0x0000, /* R20514 - DACR_RETUNE_C18_1 */
+ [20515] = 0x0000, /* R20515 - DACR_RETUNE_C18_0 */
+ [20516] = 0x0000, /* R20516 - DACR_RETUNE_C19_1 */
+ [20517] = 0x0000, /* R20517 - DACR_RETUNE_C19_0 */
+ [20518] = 0x0000, /* R20518 - DACR_RETUNE_C20_1 */
+ [20519] = 0x0000, /* R20519 - DACR_RETUNE_C20_0 */
+ [20520] = 0x0000, /* R20520 - DACR_RETUNE_C21_1 */
+ [20521] = 0x0000, /* R20521 - DACR_RETUNE_C21_0 */
+ [20522] = 0x0000, /* R20522 - DACR_RETUNE_C22_1 */
+ [20523] = 0x0000, /* R20523 - DACR_RETUNE_C22_0 */
+ [20524] = 0x0000, /* R20524 - DACR_RETUNE_C23_1 */
+ [20525] = 0x0000, /* R20525 - DACR_RETUNE_C23_0 */
+ [20526] = 0x0000, /* R20526 - DACR_RETUNE_C24_1 */
+ [20527] = 0x0000, /* R20527 - DACR_RETUNE_C24_0 */
+ [20528] = 0x0000, /* R20528 - DACR_RETUNE_C25_1 */
+ [20529] = 0x0000, /* R20529 - DACR_RETUNE_C25_0 */
+ [20530] = 0x0000, /* R20530 - DACR_RETUNE_C26_1 */
+ [20531] = 0x0000, /* R20531 - DACR_RETUNE_C26_0 */
+ [20532] = 0x0000, /* R20532 - DACR_RETUNE_C27_1 */
+ [20533] = 0x0000, /* R20533 - DACR_RETUNE_C27_0 */
+ [20534] = 0x0000, /* R20534 - DACR_RETUNE_C28_1 */
+ [20535] = 0x0000, /* R20535 - DACR_RETUNE_C28_0 */
+ [20536] = 0x0000, /* R20536 - DACR_RETUNE_C29_1 */
+ [20537] = 0x0000, /* R20537 - DACR_RETUNE_C29_0 */
+ [20538] = 0x0000, /* R20538 - DACR_RETUNE_C30_1 */
+ [20539] = 0x0000, /* R20539 - DACR_RETUNE_C30_0 */
+ [20540] = 0x0000, /* R20540 - DACR_RETUNE_C31_1 */
+ [20541] = 0x0000, /* R20541 - DACR_RETUNE_C31_0 */
+ [20542] = 0x0000, /* R20542 - DACR_RETUNE_C32_1 */
+ [20543] = 0x0000, /* R20543 - DACR_RETUNE_C32_0 */
+
+ [20992] = 0x008C, /* R20992 - VSS_XHD2_1 */
+ [20993] = 0x0200, /* R20993 - VSS_XHD2_0 */
+ [20994] = 0x0035, /* R20994 - VSS_XHD3_1 */
+ [20995] = 0x0700, /* R20995 - VSS_XHD3_0 */
+ [20996] = 0x003A, /* R20996 - VSS_XHN1_1 */
+ [20997] = 0x4100, /* R20997 - VSS_XHN1_0 */
+ [20998] = 0x008B, /* R20998 - VSS_XHN2_1 */
+ [20999] = 0x7D00, /* R20999 - VSS_XHN2_0 */
+ [21000] = 0x003A, /* R21000 - VSS_XHN3_1 */
+ [21001] = 0x4100, /* R21001 - VSS_XHN3_0 */
+ [21002] = 0x008C, /* R21002 - VSS_XLA_1 */
+ [21003] = 0xFEE8, /* R21003 - VSS_XLA_0 */
+ [21004] = 0x0078, /* R21004 - VSS_XLB_1 */
+ [21005] = 0x0000, /* R21005 - VSS_XLB_0 */
+ [21006] = 0x003F, /* R21006 - VSS_XLG_1 */
+ [21007] = 0xB260, /* R21007 - VSS_XLG_0 */
+ [21008] = 0x002D, /* R21008 - VSS_PG2_1 */
+ [21009] = 0x1818, /* R21009 - VSS_PG2_0 */
+ [21010] = 0x0020, /* R21010 - VSS_PG_1 */
+ [21011] = 0x0000, /* R21011 - VSS_PG_0 */
+ [21012] = 0x00F1, /* R21012 - VSS_XTD1_1 */
+ [21013] = 0x8340, /* R21013 - VSS_XTD1_0 */
+ [21014] = 0x00FB, /* R21014 - VSS_XTD2_1 */
+ [21015] = 0x8300, /* R21015 - VSS_XTD2_0 */
+ [21016] = 0x00EE, /* R21016 - VSS_XTD3_1 */
+ [21017] = 0xAEC0, /* R21017 - VSS_XTD3_0 */
+ [21018] = 0x00FB, /* R21018 - VSS_XTD4_1 */
+ [21019] = 0xAC40, /* R21019 - VSS_XTD4_0 */
+ [21020] = 0x00F1, /* R21020 - VSS_XTD5_1 */
+ [21021] = 0x7F80, /* R21021 - VSS_XTD5_0 */
+ [21022] = 0x00F4, /* R21022 - VSS_XTD6_1 */
+ [21023] = 0x3B40, /* R21023 - VSS_XTD6_0 */
+ [21024] = 0x00F5, /* R21024 - VSS_XTD7_1 */
+ [21025] = 0xFB00, /* R21025 - VSS_XTD7_0 */
+ [21026] = 0x00EA, /* R21026 - VSS_XTD8_1 */
+ [21027] = 0x10C0, /* R21027 - VSS_XTD8_0 */
+ [21028] = 0x00FC, /* R21028 - VSS_XTD9_1 */
+ [21029] = 0xC580, /* R21029 - VSS_XTD9_0 */
+ [21030] = 0x00E2, /* R21030 - VSS_XTD10_1 */
+ [21031] = 0x75C0, /* R21031 - VSS_XTD10_0 */
+ [21032] = 0x0004, /* R21032 - VSS_XTD11_1 */
+ [21033] = 0xB480, /* R21033 - VSS_XTD11_0 */
+ [21034] = 0x00D4, /* R21034 - VSS_XTD12_1 */
+ [21035] = 0xF980, /* R21035 - VSS_XTD12_0 */
+ [21036] = 0x0004, /* R21036 - VSS_XTD13_1 */
+ [21037] = 0x9140, /* R21037 - VSS_XTD13_0 */
+ [21038] = 0x00D8, /* R21038 - VSS_XTD14_1 */
+ [21039] = 0xA480, /* R21039 - VSS_XTD14_0 */
+ [21040] = 0x0002, /* R21040 - VSS_XTD15_1 */
+ [21041] = 0x3DC0, /* R21041 - VSS_XTD15_0 */
+ [21042] = 0x00CF, /* R21042 - VSS_XTD16_1 */
+ [21043] = 0x7A80, /* R21043 - VSS_XTD16_0 */
+ [21044] = 0x00DC, /* R21044 - VSS_XTD17_1 */
+ [21045] = 0x0600, /* R21045 - VSS_XTD17_0 */
+ [21046] = 0x00F2, /* R21046 - VSS_XTD18_1 */
+ [21047] = 0xDAC0, /* R21047 - VSS_XTD18_0 */
+ [21048] = 0x00BA, /* R21048 - VSS_XTD19_1 */
+ [21049] = 0xF340, /* R21049 - VSS_XTD19_0 */
+ [21050] = 0x000A, /* R21050 - VSS_XTD20_1 */
+ [21051] = 0x7940, /* R21051 - VSS_XTD20_0 */
+ [21052] = 0x001C, /* R21052 - VSS_XTD21_1 */
+ [21053] = 0x0680, /* R21053 - VSS_XTD21_0 */
+ [21054] = 0x00FD, /* R21054 - VSS_XTD22_1 */
+ [21055] = 0x2D00, /* R21055 - VSS_XTD22_0 */
+ [21056] = 0x001C, /* R21056 - VSS_XTD23_1 */
+ [21057] = 0xE840, /* R21057 - VSS_XTD23_0 */
+ [21058] = 0x000D, /* R21058 - VSS_XTD24_1 */
+ [21059] = 0xDC40, /* R21059 - VSS_XTD24_0 */
+ [21060] = 0x00FC, /* R21060 - VSS_XTD25_1 */
+ [21061] = 0x9D00, /* R21061 - VSS_XTD25_0 */
+ [21062] = 0x0009, /* R21062 - VSS_XTD26_1 */
+ [21063] = 0x5580, /* R21063 - VSS_XTD26_0 */
+ [21064] = 0x00FE, /* R21064 - VSS_XTD27_1 */
+ [21065] = 0x7E80, /* R21065 - VSS_XTD27_0 */
+ [21066] = 0x000E, /* R21066 - VSS_XTD28_1 */
+ [21067] = 0xAB40, /* R21067 - VSS_XTD28_0 */
+ [21068] = 0x00F9, /* R21068 - VSS_XTD29_1 */
+ [21069] = 0x9880, /* R21069 - VSS_XTD29_0 */
+ [21070] = 0x0009, /* R21070 - VSS_XTD30_1 */
+ [21071] = 0x87C0, /* R21071 - VSS_XTD30_0 */
+ [21072] = 0x00FD, /* R21072 - VSS_XTD31_1 */
+ [21073] = 0x2C40, /* R21073 - VSS_XTD31_0 */
+ [21074] = 0x0009, /* R21074 - VSS_XTD32_1 */
+ [21075] = 0x4800, /* R21075 - VSS_XTD32_0 */
+ [21076] = 0x0003, /* R21076 - VSS_XTS1_1 */
+ [21077] = 0x5F40, /* R21077 - VSS_XTS1_0 */
+ [21078] = 0x0000, /* R21078 - VSS_XTS2_1 */
+ [21079] = 0x8700, /* R21079 - VSS_XTS2_0 */
+ [21080] = 0x00FA, /* R21080 - VSS_XTS3_1 */
+ [21081] = 0xE4C0, /* R21081 - VSS_XTS3_0 */
+ [21082] = 0x0000, /* R21082 - VSS_XTS4_1 */
+ [21083] = 0x0B40, /* R21083 - VSS_XTS4_0 */
+ [21084] = 0x0004, /* R21084 - VSS_XTS5_1 */
+ [21085] = 0xE180, /* R21085 - VSS_XTS5_0 */
+ [21086] = 0x0001, /* R21086 - VSS_XTS6_1 */
+ [21087] = 0x1F40, /* R21087 - VSS_XTS6_0 */
+ [21088] = 0x00F8, /* R21088 - VSS_XTS7_1 */
+ [21089] = 0xB000, /* R21089 - VSS_XTS7_0 */
+ [21090] = 0x00FB, /* R21090 - VSS_XTS8_1 */
+ [21091] = 0xCBC0, /* R21091 - VSS_XTS8_0 */
+ [21092] = 0x0004, /* R21092 - VSS_XTS9_1 */
+ [21093] = 0xF380, /* R21093 - VSS_XTS9_0 */
+ [21094] = 0x0007, /* R21094 - VSS_XTS10_1 */
+ [21095] = 0xDF40, /* R21095 - VSS_XTS10_0 */
+ [21096] = 0x00FF, /* R21096 - VSS_XTS11_1 */
+ [21097] = 0x0700, /* R21097 - VSS_XTS11_0 */
+ [21098] = 0x00EF, /* R21098 - VSS_XTS12_1 */
+ [21099] = 0xD700, /* R21099 - VSS_XTS12_0 */
+ [21100] = 0x00FB, /* R21100 - VSS_XTS13_1 */
+ [21101] = 0xAF40, /* R21101 - VSS_XTS13_0 */
+ [21102] = 0x0010, /* R21102 - VSS_XTS14_1 */
+ [21103] = 0x8A80, /* R21103 - VSS_XTS14_0 */
+ [21104] = 0x0011, /* R21104 - VSS_XTS15_1 */
+ [21105] = 0x07C0, /* R21105 - VSS_XTS15_0 */
+ [21106] = 0x00E0, /* R21106 - VSS_XTS16_1 */
+ [21107] = 0x0800, /* R21107 - VSS_XTS16_0 */
+ [21108] = 0x00D2, /* R21108 - VSS_XTS17_1 */
+ [21109] = 0x7600, /* R21109 - VSS_XTS17_0 */
+ [21110] = 0x0020, /* R21110 - VSS_XTS18_1 */
+ [21111] = 0xCF40, /* R21111 - VSS_XTS18_0 */
+ [21112] = 0x0030, /* R21112 - VSS_XTS19_1 */
+ [21113] = 0x2340, /* R21113 - VSS_XTS19_0 */
+ [21114] = 0x00FD, /* R21114 - VSS_XTS20_1 */
+ [21115] = 0x69C0, /* R21115 - VSS_XTS20_0 */
+ [21116] = 0x0028, /* R21116 - VSS_XTS21_1 */
+ [21117] = 0x3500, /* R21117 - VSS_XTS21_0 */
+ [21118] = 0x0006, /* R21118 - VSS_XTS22_1 */
+ [21119] = 0x3300, /* R21119 - VSS_XTS22_0 */
+ [21120] = 0x00D9, /* R21120 - VSS_XTS23_1 */
+ [21121] = 0xF6C0, /* R21121 - VSS_XTS23_0 */
+ [21122] = 0x00F3, /* R21122 - VSS_XTS24_1 */
+ [21123] = 0x3340, /* R21123 - VSS_XTS24_0 */
+ [21124] = 0x000F, /* R21124 - VSS_XTS25_1 */
+ [21125] = 0x4200, /* R21125 - VSS_XTS25_0 */
+ [21126] = 0x0004, /* R21126 - VSS_XTS26_1 */
+ [21127] = 0x0C80, /* R21127 - VSS_XTS26_0 */
+ [21128] = 0x00FB, /* R21128 - VSS_XTS27_1 */
+ [21129] = 0x3F80, /* R21129 - VSS_XTS27_0 */
+ [21130] = 0x00F7, /* R21130 - VSS_XTS28_1 */
+ [21131] = 0x57C0, /* R21131 - VSS_XTS28_0 */
+ [21132] = 0x0003, /* R21132 - VSS_XTS29_1 */
+ [21133] = 0x5400, /* R21133 - VSS_XTS29_0 */
+ [21134] = 0x0000, /* R21134 - VSS_XTS30_1 */
+ [21135] = 0xC6C0, /* R21135 - VSS_XTS30_0 */
+ [21136] = 0x0003, /* R21136 - VSS_XTS31_1 */
+ [21137] = 0x12C0, /* R21137 - VSS_XTS31_0 */
+ [21138] = 0x00FD, /* R21138 - VSS_XTS32_1 */
+ [21139] = 0x8580, /* R21139 - VSS_XTS32_0 */
+};
+
+static const struct wm8962_reg_access {
+ u16 read;
+ u16 write;
+ u16 vol;
+} wm8962_reg_access[WM8962_MAX_REGISTER + 1] = {
+ [0] = { 0x00FF, 0x01FF, 0x0000 }, /* R0 - Left Input volume */
+ [1] = { 0xFEFF, 0x01FF, 0xFFFF }, /* R1 - Right Input volume */
+ [2] = { 0x00FF, 0x01FF, 0x0000 }, /* R2 - HPOUTL volume */
+ [3] = { 0x00FF, 0x01FF, 0x0000 }, /* R3 - HPOUTR volume */
+ [4] = { 0x07FE, 0x07FE, 0xFFFF }, /* R4 - Clocking1 */
+ [5] = { 0x007F, 0x007F, 0x0000 }, /* R5 - ADC & DAC Control 1 */
+ [6] = { 0x37ED, 0x37ED, 0x0000 }, /* R6 - ADC & DAC Control 2 */
+ [7] = { 0x1FFF, 0x1FFF, 0x0000 }, /* R7 - Audio Interface 0 */
+ [8] = { 0x0FEF, 0x0FEF, 0xFFFF }, /* R8 - Clocking2 */
+ [9] = { 0x0B9F, 0x039F, 0x0000 }, /* R9 - Audio Interface 1 */
+ [10] = { 0x00FF, 0x01FF, 0x0000 }, /* R10 - Left DAC volume */
+ [11] = { 0x00FF, 0x01FF, 0x0000 }, /* R11 - Right DAC volume */
+ [14] = { 0x07FF, 0x07FF, 0x0000 }, /* R14 - Audio Interface 2 */
+ [15] = { 0xFFFF, 0xFFFF, 0xFFFF }, /* R15 - Software Reset */
+ [17] = { 0x07FF, 0x07FF, 0x0000 }, /* R17 - ALC1 */
+ [18] = { 0xF8FF, 0x00FF, 0xFFFF }, /* R18 - ALC2 */
+ [19] = { 0x1DFF, 0x1DFF, 0x0000 }, /* R19 - ALC3 */
+ [20] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20 - Noise Gate */
+ [21] = { 0x00FF, 0x01FF, 0x0000 }, /* R21 - Left ADC volume */
+ [22] = { 0x00FF, 0x01FF, 0x0000 }, /* R22 - Right ADC volume */
+ [23] = { 0x0161, 0x0161, 0x0000 }, /* R23 - Additional control(1) */
+ [24] = { 0x0008, 0x0008, 0x0000 }, /* R24 - Additional control(2) */
+ [25] = { 0x07FE, 0x07FE, 0x0000 }, /* R25 - Pwr Mgmt (1) */
+ [26] = { 0x01FB, 0x01FB, 0x0000 }, /* R26 - Pwr Mgmt (2) */
+ [27] = { 0x0017, 0x0017, 0x0000 }, /* R27 - Additional Control (3) */
+ [28] = { 0x001C, 0x001C, 0x0000 }, /* R28 - Anti-pop */
+
+ [30] = { 0xFFFE, 0xFFFE, 0x0000 }, /* R30 - Clocking 3 */
+ [31] = { 0x000F, 0x000F, 0x0000 }, /* R31 - Input mixer control (1) */
+ [32] = { 0x01FF, 0x01FF, 0x0000 }, /* R32 - Left input mixer volume */
+ [33] = { 0x01FF, 0x01FF, 0x0000 }, /* R33 - Right input mixer volume */
+ [34] = { 0x003F, 0x003F, 0x0000 }, /* R34 - Input mixer control (2) */
+ [35] = { 0x003F, 0x003F, 0x0000 }, /* R35 - Input bias control */
+ [37] = { 0x001F, 0x001F, 0x0000 }, /* R37 - Left input PGA control */
+ [38] = { 0x001F, 0x001F, 0x0000 }, /* R38 - Right input PGA control */
+ [40] = { 0x00FF, 0x01FF, 0x0000 }, /* R40 - SPKOUTL volume */
+ [41] = { 0x00FF, 0x01FF, 0x0000 }, /* R41 - SPKOUTR volume */
+
+ [47] = { 0x000F, 0x0000, 0x0000 }, /* R47 - Thermal Shutdown Status */
+ [48] = { 0x7EC7, 0x7E07, 0xFFFF }, /* R48 - Additional Control (4) */
+ [49] = { 0x00D3, 0x00D7, 0xFFFF }, /* R49 - Class D Control 1 */
+ [51] = { 0x0047, 0x0047, 0x0000 }, /* R51 - Class D Control 2 */
+ [56] = { 0x001E, 0x001E, 0x0000 }, /* R56 - Clocking 4 */
+ [57] = { 0x02FC, 0x02FC, 0x0000 }, /* R57 - DAC DSP Mixing (1) */
+ [58] = { 0x00FC, 0x00FC, 0x0000 }, /* R58 - DAC DSP Mixing (2) */
+ [60] = { 0x00CC, 0x00CC, 0x0000 }, /* R60 - DC Servo 0 */
+ [61] = { 0x00DD, 0x00DD, 0x0000 }, /* R61 - DC Servo 1 */
+ [64] = { 0x3F80, 0x3F80, 0x0000 }, /* R64 - DC Servo 4 */
+ [66] = { 0x0780, 0x0000, 0xFFFF }, /* R66 - DC Servo 6 */
+ [68] = { 0x0007, 0x0007, 0x0000 }, /* R68 - Analogue PGA Bias */
+ [69] = { 0x00FF, 0x00FF, 0x0000 }, /* R69 - Analogue HP 0 */
+ [71] = { 0x01FF, 0x01FF, 0x0000 }, /* R71 - Analogue HP 2 */
+ [72] = { 0x0001, 0x0001, 0x0000 }, /* R72 - Charge Pump 1 */
+ [82] = { 0x0001, 0x0001, 0x0000 }, /* R82 - Charge Pump B */
+ [87] = { 0x00A0, 0x00A0, 0x0000 }, /* R87 - Write Sequencer Control 1 */
+ [90] = { 0x007F, 0x01FF, 0x0000 }, /* R90 - Write Sequencer Control 2 */
+ [93] = { 0x03F9, 0x0000, 0x0000 }, /* R93 - Write Sequencer Control 3 */
+ [94] = { 0x0070, 0x0070, 0x0000 }, /* R94 - Control Interface */
+ [99] = { 0x000F, 0x000F, 0x0000 }, /* R99 - Mixer Enables */
+ [100] = { 0x00BF, 0x00BF, 0x0000 }, /* R100 - Headphone Mixer (1) */
+ [101] = { 0x00BF, 0x00BF, 0x0000 }, /* R101 - Headphone Mixer (2) */
+ [102] = { 0x01FF, 0x01FF, 0x0000 }, /* R102 - Headphone Mixer (3) */
+ [103] = { 0x01FF, 0x01FF, 0x0000 }, /* R103 - Headphone Mixer (4) */
+ [105] = { 0x00BF, 0x00BF, 0x0000 }, /* R105 - Speaker Mixer (1) */
+ [106] = { 0x00BF, 0x00BF, 0x0000 }, /* R106 - Speaker Mixer (2) */
+ [107] = { 0x01FF, 0x01FF, 0x0000 }, /* R107 - Speaker Mixer (3) */
+ [108] = { 0x01FF, 0x01FF, 0x0000 }, /* R108 - Speaker Mixer (4) */
+ [109] = { 0x00F0, 0x00F0, 0x0000 }, /* R109 - Speaker Mixer (5) */
+ [110] = { 0x00F7, 0x00F7, 0x0000 }, /* R110 - Beep Generator (1) */
+ [115] = { 0x001F, 0x001F, 0x0000 }, /* R115 - Oscillator Trim (3) */
+ [116] = { 0x001F, 0x001F, 0x0000 }, /* R116 - Oscillator Trim (4) */
+ [119] = { 0x00FF, 0x00FF, 0x0000 }, /* R119 - Oscillator Trim (7) */
+ [124] = { 0x0079, 0x0079, 0x0000 }, /* R124 - Analogue Clocking1 */
+ [125] = { 0x00DF, 0x00DF, 0x0000 }, /* R125 - Analogue Clocking2 */
+ [126] = { 0x000D, 0x000D, 0x0000 }, /* R126 - Analogue Clocking3 */
+ [127] = { 0x0000, 0xFFFF, 0x0000 }, /* R127 - PLL Software Reset */
+ [129] = { 0x00B0, 0x00B0, 0x0000 }, /* R129 - PLL2 */
+ [131] = { 0x0003, 0x0003, 0x0000 }, /* R131 - PLL 4 */
+ [136] = { 0x005F, 0x005F, 0x0000 }, /* R136 - PLL 9 */
+ [137] = { 0x00FF, 0x00FF, 0x0000 }, /* R137 - PLL 10 */
+ [138] = { 0x00FF, 0x00FF, 0x0000 }, /* R138 - PLL 11 */
+ [139] = { 0x00FF, 0x00FF, 0x0000 }, /* R139 - PLL 12 */
+ [140] = { 0x005F, 0x005F, 0x0000 }, /* R140 - PLL 13 */
+ [141] = { 0x00FF, 0x00FF, 0x0000 }, /* R141 - PLL 14 */
+ [142] = { 0x00FF, 0x00FF, 0x0000 }, /* R142 - PLL 15 */
+ [143] = { 0x00FF, 0x00FF, 0x0000 }, /* R143 - PLL 16 */
+ [155] = { 0x0067, 0x0067, 0x0000 }, /* R155 - FLL Control (1) */
+ [156] = { 0x01FB, 0x01FB, 0x0000 }, /* R156 - FLL Control (2) */
+ [157] = { 0x0007, 0x0007, 0x0000 }, /* R157 - FLL Control (3) */
+ [159] = { 0x007F, 0x007F, 0x0000 }, /* R159 - FLL Control (5) */
+ [160] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R160 - FLL Control (6) */
+ [161] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R161 - FLL Control (7) */
+ [162] = { 0x03FF, 0x03FF, 0x0000 }, /* R162 - FLL Control (8) */
+ [252] = { 0x0005, 0x0005, 0x0000 }, /* R252 - General test 1 */
+ [256] = { 0x000F, 0x000F, 0x0000 }, /* R256 - DF1 */
+ [257] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R257 - DF2 */
+ [258] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R258 - DF3 */
+ [259] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R259 - DF4 */
+ [260] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R260 - DF5 */
+ [261] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R261 - DF6 */
+ [262] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R262 - DF7 */
+ [264] = { 0x0003, 0x0003, 0x0000 }, /* R264 - LHPF1 */
+ [265] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R265 - LHPF2 */
+ [268] = { 0x0077, 0x0077, 0x0000 }, /* R268 - THREED1 */
+ [269] = { 0xFFFC, 0xFFFC, 0x0000 }, /* R269 - THREED2 */
+ [270] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R270 - THREED3 */
+ [271] = { 0xFFFC, 0xFFFC, 0x0000 }, /* R271 - THREED4 */
+ [276] = { 0x7FFF, 0x7FFF, 0x0000 }, /* R276 - DRC 1 */
+ [277] = { 0x1FFF, 0x1FFF, 0x0000 }, /* R277 - DRC 2 */
+ [278] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R278 - DRC 3 */
+ [279] = { 0x07FF, 0x07FF, 0x0000 }, /* R279 - DRC 4 */
+ [280] = { 0x03FF, 0x03FF, 0x0000 }, /* R280 - DRC 5 */
+ [285] = { 0x0003, 0x0003, 0x0000 }, /* R285 - Tloopback */
+ [335] = { 0x0007, 0x0007, 0x0000 }, /* R335 - EQ1 */
+ [336] = { 0xFFFE, 0xFFFE, 0x0000 }, /* R336 - EQ2 */
+ [337] = { 0xFFC0, 0xFFC0, 0x0000 }, /* R337 - EQ3 */
+ [338] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R338 - EQ4 */
+ [339] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R339 - EQ5 */
+ [340] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R340 - EQ6 */
+ [341] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R341 - EQ7 */
+ [342] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R342 - EQ8 */
+ [343] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R343 - EQ9 */
+ [344] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R344 - EQ10 */
+ [345] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R345 - EQ11 */
+ [346] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R346 - EQ12 */
+ [347] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R347 - EQ13 */
+ [348] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R348 - EQ14 */
+ [349] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R349 - EQ15 */
+ [350] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R350 - EQ16 */
+ [351] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R351 - EQ17 */
+ [352] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R352 - EQ18 */
+ [353] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R353 - EQ19 */
+ [354] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R354 - EQ20 */
+ [355] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R355 - EQ21 */
+ [356] = { 0xFFFE, 0xFFFE, 0x0000 }, /* R356 - EQ22 */
+ [357] = { 0xFFC0, 0xFFC0, 0x0000 }, /* R357 - EQ23 */
+ [358] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R358 - EQ24 */
+ [359] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R359 - EQ25 */
+ [360] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R360 - EQ26 */
+ [361] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R361 - EQ27 */
+ [362] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R362 - EQ28 */
+ [363] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R363 - EQ29 */
+ [364] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R364 - EQ30 */
+ [365] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R365 - EQ31 */
+ [366] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R366 - EQ32 */
+ [367] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R367 - EQ33 */
+ [368] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R368 - EQ34 */
+ [369] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R369 - EQ35 */
+ [370] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R370 - EQ36 */
+ [371] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R371 - EQ37 */
+ [372] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R372 - EQ38 */
+ [373] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R373 - EQ39 */
+ [374] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R374 - EQ40 */
+ [375] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R375 - EQ41 */
+ [513] = { 0x045F, 0x045F, 0x0000 }, /* R513 - GPIO 2 */
+ [514] = { 0x045F, 0x045F, 0x0000 }, /* R514 - GPIO 3 */
+ [516] = { 0xE75F, 0xE75F, 0x0000 }, /* R516 - GPIO 5 */
+ [517] = { 0xE75F, 0xE75F, 0x0000 }, /* R517 - GPIO 6 */
+ [560] = { 0x0030, 0x0030, 0xFFFF }, /* R560 - Interrupt Status 1 */
+ [561] = { 0xFFED, 0xFFED, 0xFFFF }, /* R561 - Interrupt Status 2 */
+ [568] = { 0x0030, 0x0030, 0x0000 }, /* R568 - Interrupt Status 1 Mask */
+ [569] = { 0xFFED, 0xFFED, 0x0000 }, /* R569 - Interrupt Status 2 Mask */
+ [576] = { 0x0001, 0x0001, 0x0000 }, /* R576 - Interrupt Control */
+ [584] = { 0x002D, 0x002D, 0x0000 }, /* R584 - IRQ Debounce */
+ [586] = { 0xC000, 0xC000, 0x0000 }, /* R586 - MICINT Source Pol */
+ [768] = { 0x0001, 0x0001, 0x0000 }, /* R768 - DSP2 Power Management */
+ [1037] = { 0x0000, 0x003F, 0x0000 }, /* R1037 - DSP2_ExecControl */
+ [4096] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4096 - Write Sequencer 0 */
+ [4097] = { 0x00FF, 0x00FF, 0x0000 }, /* R4097 - Write Sequencer 1 */
+ [4098] = { 0x070F, 0x070F, 0x0000 }, /* R4098 - Write Sequencer 2 */
+ [4099] = { 0x010F, 0x010F, 0x0000 }, /* R4099 - Write Sequencer 3 */
+ [4100] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4100 - Write Sequencer 4 */
+ [4101] = { 0x00FF, 0x00FF, 0x0000 }, /* R4101 - Write Sequencer 5 */
+ [4102] = { 0x070F, 0x070F, 0x0000 }, /* R4102 - Write Sequencer 6 */
+ [4103] = { 0x010F, 0x010F, 0x0000 }, /* R4103 - Write Sequencer 7 */
+ [4104] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4104 - Write Sequencer 8 */
+ [4105] = { 0x00FF, 0x00FF, 0x0000 }, /* R4105 - Write Sequencer 9 */
+ [4106] = { 0x070F, 0x070F, 0x0000 }, /* R4106 - Write Sequencer 10 */
+ [4107] = { 0x010F, 0x010F, 0x0000 }, /* R4107 - Write Sequencer 11 */
+ [4108] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4108 - Write Sequencer 12 */
+ [4109] = { 0x00FF, 0x00FF, 0x0000 }, /* R4109 - Write Sequencer 13 */
+ [4110] = { 0x070F, 0x070F, 0x0000 }, /* R4110 - Write Sequencer 14 */
+ [4111] = { 0x010F, 0x010F, 0x0000 }, /* R4111 - Write Sequencer 15 */
+ [4112] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4112 - Write Sequencer 16 */
+ [4113] = { 0x00FF, 0x00FF, 0x0000 }, /* R4113 - Write Sequencer 17 */
+ [4114] = { 0x070F, 0x070F, 0x0000 }, /* R4114 - Write Sequencer 18 */
+ [4115] = { 0x010F, 0x010F, 0x0000 }, /* R4115 - Write Sequencer 19 */
+ [4116] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4116 - Write Sequencer 20 */
+ [4117] = { 0x00FF, 0x00FF, 0x0000 }, /* R4117 - Write Sequencer 21 */
+ [4118] = { 0x070F, 0x070F, 0x0000 }, /* R4118 - Write Sequencer 22 */
+ [4119] = { 0x010F, 0x010F, 0x0000 }, /* R4119 - Write Sequencer 23 */
+ [4120] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4120 - Write Sequencer 24 */
+ [4121] = { 0x00FF, 0x00FF, 0x0000 }, /* R4121 - Write Sequencer 25 */
+ [4122] = { 0x070F, 0x070F, 0x0000 }, /* R4122 - Write Sequencer 26 */
+ [4123] = { 0x010F, 0x010F, 0x0000 }, /* R4123 - Write Sequencer 27 */
+ [4124] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4124 - Write Sequencer 28 */
+ [4125] = { 0x00FF, 0x00FF, 0x0000 }, /* R4125 - Write Sequencer 29 */
+ [4126] = { 0x070F, 0x070F, 0x0000 }, /* R4126 - Write Sequencer 30 */
+ [4127] = { 0x010F, 0x010F, 0x0000 }, /* R4127 - Write Sequencer 31 */
+ [4128] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4128 - Write Sequencer 32 */
+ [4129] = { 0x00FF, 0x00FF, 0x0000 }, /* R4129 - Write Sequencer 33 */
+ [4130] = { 0x070F, 0x070F, 0x0000 }, /* R4130 - Write Sequencer 34 */
+ [4131] = { 0x010F, 0x010F, 0x0000 }, /* R4131 - Write Sequencer 35 */
+ [4132] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4132 - Write Sequencer 36 */
+ [4133] = { 0x00FF, 0x00FF, 0x0000 }, /* R4133 - Write Sequencer 37 */
+ [4134] = { 0x070F, 0x070F, 0x0000 }, /* R4134 - Write Sequencer 38 */
+ [4135] = { 0x010F, 0x010F, 0x0000 }, /* R4135 - Write Sequencer 39 */
+ [4136] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4136 - Write Sequencer 40 */
+ [4137] = { 0x00FF, 0x00FF, 0x0000 }, /* R4137 - Write Sequencer 41 */
+ [4138] = { 0x070F, 0x070F, 0x0000 }, /* R4138 - Write Sequencer 42 */
+ [4139] = { 0x010F, 0x010F, 0x0000 }, /* R4139 - Write Sequencer 43 */
+ [4140] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4140 - Write Sequencer 44 */
+ [4141] = { 0x00FF, 0x00FF, 0x0000 }, /* R4141 - Write Sequencer 45 */
+ [4142] = { 0x070F, 0x070F, 0x0000 }, /* R4142 - Write Sequencer 46 */
+ [4143] = { 0x010F, 0x010F, 0x0000 }, /* R4143 - Write Sequencer 47 */
+ [4144] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4144 - Write Sequencer 48 */
+ [4145] = { 0x00FF, 0x00FF, 0x0000 }, /* R4145 - Write Sequencer 49 */
+ [4146] = { 0x070F, 0x070F, 0x0000 }, /* R4146 - Write Sequencer 50 */
+ [4147] = { 0x010F, 0x010F, 0x0000 }, /* R4147 - Write Sequencer 51 */
+ [4148] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4148 - Write Sequencer 52 */
+ [4149] = { 0x00FF, 0x00FF, 0x0000 }, /* R4149 - Write Sequencer 53 */
+ [4150] = { 0x070F, 0x070F, 0x0000 }, /* R4150 - Write Sequencer 54 */
+ [4151] = { 0x010F, 0x010F, 0x0000 }, /* R4151 - Write Sequencer 55 */
+ [4152] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4152 - Write Sequencer 56 */
+ [4153] = { 0x00FF, 0x00FF, 0x0000 }, /* R4153 - Write Sequencer 57 */
+ [4154] = { 0x070F, 0x070F, 0x0000 }, /* R4154 - Write Sequencer 58 */
+ [4155] = { 0x010F, 0x010F, 0x0000 }, /* R4155 - Write Sequencer 59 */
+ [4156] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4156 - Write Sequencer 60 */
+ [4157] = { 0x00FF, 0x00FF, 0x0000 }, /* R4157 - Write Sequencer 61 */
+ [4158] = { 0x070F, 0x070F, 0x0000 }, /* R4158 - Write Sequencer 62 */
+ [4159] = { 0x010F, 0x010F, 0x0000 }, /* R4159 - Write Sequencer 63 */
+ [4160] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4160 - Write Sequencer 64 */
+ [4161] = { 0x00FF, 0x00FF, 0x0000 }, /* R4161 - Write Sequencer 65 */
+ [4162] = { 0x070F, 0x070F, 0x0000 }, /* R4162 - Write Sequencer 66 */
+ [4163] = { 0x010F, 0x010F, 0x0000 }, /* R4163 - Write Sequencer 67 */
+ [4164] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4164 - Write Sequencer 68 */
+ [4165] = { 0x00FF, 0x00FF, 0x0000 }, /* R4165 - Write Sequencer 69 */
+ [4166] = { 0x070F, 0x070F, 0x0000 }, /* R4166 - Write Sequencer 70 */
+ [4167] = { 0x010F, 0x010F, 0x0000 }, /* R4167 - Write Sequencer 71 */
+ [4168] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4168 - Write Sequencer 72 */
+ [4169] = { 0x00FF, 0x00FF, 0x0000 }, /* R4169 - Write Sequencer 73 */
+ [4170] = { 0x070F, 0x070F, 0x0000 }, /* R4170 - Write Sequencer 74 */
+ [4171] = { 0x010F, 0x010F, 0x0000 }, /* R4171 - Write Sequencer 75 */
+ [4172] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4172 - Write Sequencer 76 */
+ [4173] = { 0x00FF, 0x00FF, 0x0000 }, /* R4173 - Write Sequencer 77 */
+ [4174] = { 0x070F, 0x070F, 0x0000 }, /* R4174 - Write Sequencer 78 */
+ [4175] = { 0x010F, 0x010F, 0x0000 }, /* R4175 - Write Sequencer 79 */
+ [4176] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4176 - Write Sequencer 80 */
+ [4177] = { 0x00FF, 0x00FF, 0x0000 }, /* R4177 - Write Sequencer 81 */
+ [4178] = { 0x070F, 0x070F, 0x0000 }, /* R4178 - Write Sequencer 82 */
+ [4179] = { 0x010F, 0x010F, 0x0000 }, /* R4179 - Write Sequencer 83 */
+ [4180] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4180 - Write Sequencer 84 */
+ [4181] = { 0x00FF, 0x00FF, 0x0000 }, /* R4181 - Write Sequencer 85 */
+ [4182] = { 0x070F, 0x070F, 0x0000 }, /* R4182 - Write Sequencer 86 */
+ [4183] = { 0x010F, 0x010F, 0x0000 }, /* R4183 - Write Sequencer 87 */
+ [4184] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4184 - Write Sequencer 88 */
+ [4185] = { 0x00FF, 0x00FF, 0x0000 }, /* R4185 - Write Sequencer 89 */
+ [4186] = { 0x070F, 0x070F, 0x0000 }, /* R4186 - Write Sequencer 90 */
+ [4187] = { 0x010F, 0x010F, 0x0000 }, /* R4187 - Write Sequencer 91 */
+ [4188] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4188 - Write Sequencer 92 */
+ [4189] = { 0x00FF, 0x00FF, 0x0000 }, /* R4189 - Write Sequencer 93 */
+ [4190] = { 0x070F, 0x070F, 0x0000 }, /* R4190 - Write Sequencer 94 */
+ [4191] = { 0x010F, 0x010F, 0x0000 }, /* R4191 - Write Sequencer 95 */
+ [4192] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4192 - Write Sequencer 96 */
+ [4193] = { 0x00FF, 0x00FF, 0x0000 }, /* R4193 - Write Sequencer 97 */
+ [4194] = { 0x070F, 0x070F, 0x0000 }, /* R4194 - Write Sequencer 98 */
+ [4195] = { 0x010F, 0x010F, 0x0000 }, /* R4195 - Write Sequencer 99 */
+ [4196] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4196 - Write Sequencer 100 */
+ [4197] = { 0x00FF, 0x00FF, 0x0000 }, /* R4197 - Write Sequencer 101 */
+ [4198] = { 0x070F, 0x070F, 0x0000 }, /* R4198 - Write Sequencer 102 */
+ [4199] = { 0x010F, 0x010F, 0x0000 }, /* R4199 - Write Sequencer 103 */
+ [4200] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4200 - Write Sequencer 104 */
+ [4201] = { 0x00FF, 0x00FF, 0x0000 }, /* R4201 - Write Sequencer 105 */
+ [4202] = { 0x070F, 0x070F, 0x0000 }, /* R4202 - Write Sequencer 106 */
+ [4203] = { 0x010F, 0x010F, 0x0000 }, /* R4203 - Write Sequencer 107 */
+ [4204] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4204 - Write Sequencer 108 */
+ [4205] = { 0x00FF, 0x00FF, 0x0000 }, /* R4205 - Write Sequencer 109 */
+ [4206] = { 0x070F, 0x070F, 0x0000 }, /* R4206 - Write Sequencer 110 */
+ [4207] = { 0x010F, 0x010F, 0x0000 }, /* R4207 - Write Sequencer 111 */
+ [4208] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4208 - Write Sequencer 112 */
+ [4209] = { 0x00FF, 0x00FF, 0x0000 }, /* R4209 - Write Sequencer 113 */
+ [4210] = { 0x070F, 0x070F, 0x0000 }, /* R4210 - Write Sequencer 114 */
+ [4211] = { 0x010F, 0x010F, 0x0000 }, /* R4211 - Write Sequencer 115 */
+ [4212] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4212 - Write Sequencer 116 */
+ [4213] = { 0x00FF, 0x00FF, 0x0000 }, /* R4213 - Write Sequencer 117 */
+ [4214] = { 0x070F, 0x070F, 0x0000 }, /* R4214 - Write Sequencer 118 */
+ [4215] = { 0x010F, 0x010F, 0x0000 }, /* R4215 - Write Sequencer 119 */
+ [4216] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4216 - Write Sequencer 120 */
+ [4217] = { 0x00FF, 0x00FF, 0x0000 }, /* R4217 - Write Sequencer 121 */
+ [4218] = { 0x070F, 0x070F, 0x0000 }, /* R4218 - Write Sequencer 122 */
+ [4219] = { 0x010F, 0x010F, 0x0000 }, /* R4219 - Write Sequencer 123 */
+ [4220] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4220 - Write Sequencer 124 */
+ [4221] = { 0x00FF, 0x00FF, 0x0000 }, /* R4221 - Write Sequencer 125 */
+ [4222] = { 0x070F, 0x070F, 0x0000 }, /* R4222 - Write Sequencer 126 */
+ [4223] = { 0x010F, 0x010F, 0x0000 }, /* R4223 - Write Sequencer 127 */
+ [4224] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4224 - Write Sequencer 128 */
+ [4225] = { 0x00FF, 0x00FF, 0x0000 }, /* R4225 - Write Sequencer 129 */
+ [4226] = { 0x070F, 0x070F, 0x0000 }, /* R4226 - Write Sequencer 130 */
+ [4227] = { 0x010F, 0x010F, 0x0000 }, /* R4227 - Write Sequencer 131 */
+ [4228] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4228 - Write Sequencer 132 */
+ [4229] = { 0x00FF, 0x00FF, 0x0000 }, /* R4229 - Write Sequencer 133 */
+ [4230] = { 0x070F, 0x070F, 0x0000 }, /* R4230 - Write Sequencer 134 */
+ [4231] = { 0x010F, 0x010F, 0x0000 }, /* R4231 - Write Sequencer 135 */
+ [4232] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4232 - Write Sequencer 136 */
+ [4233] = { 0x00FF, 0x00FF, 0x0000 }, /* R4233 - Write Sequencer 137 */
+ [4234] = { 0x070F, 0x070F, 0x0000 }, /* R4234 - Write Sequencer 138 */
+ [4235] = { 0x010F, 0x010F, 0x0000 }, /* R4235 - Write Sequencer 139 */
+ [4236] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4236 - Write Sequencer 140 */
+ [4237] = { 0x00FF, 0x00FF, 0x0000 }, /* R4237 - Write Sequencer 141 */
+ [4238] = { 0x070F, 0x070F, 0x0000 }, /* R4238 - Write Sequencer 142 */
+ [4239] = { 0x010F, 0x010F, 0x0000 }, /* R4239 - Write Sequencer 143 */
+ [4240] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4240 - Write Sequencer 144 */
+ [4241] = { 0x00FF, 0x00FF, 0x0000 }, /* R4241 - Write Sequencer 145 */
+ [4242] = { 0x070F, 0x070F, 0x0000 }, /* R4242 - Write Sequencer 146 */
+ [4243] = { 0x010F, 0x010F, 0x0000 }, /* R4243 - Write Sequencer 147 */
+ [4244] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4244 - Write Sequencer 148 */
+ [4245] = { 0x00FF, 0x00FF, 0x0000 }, /* R4245 - Write Sequencer 149 */
+ [4246] = { 0x070F, 0x070F, 0x0000 }, /* R4246 - Write Sequencer 150 */
+ [4247] = { 0x010F, 0x010F, 0x0000 }, /* R4247 - Write Sequencer 151 */
+ [4248] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4248 - Write Sequencer 152 */
+ [4249] = { 0x00FF, 0x00FF, 0x0000 }, /* R4249 - Write Sequencer 153 */
+ [4250] = { 0x070F, 0x070F, 0x0000 }, /* R4250 - Write Sequencer 154 */
+ [4251] = { 0x010F, 0x010F, 0x0000 }, /* R4251 - Write Sequencer 155 */
+ [4252] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4252 - Write Sequencer 156 */
+ [4253] = { 0x00FF, 0x00FF, 0x0000 }, /* R4253 - Write Sequencer 157 */
+ [4254] = { 0x070F, 0x070F, 0x0000 }, /* R4254 - Write Sequencer 158 */
+ [4255] = { 0x010F, 0x010F, 0x0000 }, /* R4255 - Write Sequencer 159 */
+ [4256] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4256 - Write Sequencer 160 */
+ [4257] = { 0x00FF, 0x00FF, 0x0000 }, /* R4257 - Write Sequencer 161 */
+ [4258] = { 0x070F, 0x070F, 0x0000 }, /* R4258 - Write Sequencer 162 */
+ [4259] = { 0x010F, 0x010F, 0x0000 }, /* R4259 - Write Sequencer 163 */
+ [4260] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4260 - Write Sequencer 164 */
+ [4261] = { 0x00FF, 0x00FF, 0x0000 }, /* R4261 - Write Sequencer 165 */
+ [4262] = { 0x070F, 0x070F, 0x0000 }, /* R4262 - Write Sequencer 166 */
+ [4263] = { 0x010F, 0x010F, 0x0000 }, /* R4263 - Write Sequencer 167 */
+ [4264] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4264 - Write Sequencer 168 */
+ [4265] = { 0x00FF, 0x00FF, 0x0000 }, /* R4265 - Write Sequencer 169 */
+ [4266] = { 0x070F, 0x070F, 0x0000 }, /* R4266 - Write Sequencer 170 */
+ [4267] = { 0x010F, 0x010F, 0x0000 }, /* R4267 - Write Sequencer 171 */
+ [4268] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4268 - Write Sequencer 172 */
+ [4269] = { 0x00FF, 0x00FF, 0x0000 }, /* R4269 - Write Sequencer 173 */
+ [4270] = { 0x070F, 0x070F, 0x0000 }, /* R4270 - Write Sequencer 174 */
+ [4271] = { 0x010F, 0x010F, 0x0000 }, /* R4271 - Write Sequencer 175 */
+ [4272] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4272 - Write Sequencer 176 */
+ [4273] = { 0x00FF, 0x00FF, 0x0000 }, /* R4273 - Write Sequencer 177 */
+ [4274] = { 0x070F, 0x070F, 0x0000 }, /* R4274 - Write Sequencer 178 */
+ [4275] = { 0x010F, 0x010F, 0x0000 }, /* R4275 - Write Sequencer 179 */
+ [4276] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4276 - Write Sequencer 180 */
+ [4277] = { 0x00FF, 0x00FF, 0x0000 }, /* R4277 - Write Sequencer 181 */
+ [4278] = { 0x070F, 0x070F, 0x0000 }, /* R4278 - Write Sequencer 182 */
+ [4279] = { 0x010F, 0x010F, 0x0000 }, /* R4279 - Write Sequencer 183 */
+ [4280] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4280 - Write Sequencer 184 */
+ [4281] = { 0x00FF, 0x00FF, 0x0000 }, /* R4281 - Write Sequencer 185 */
+ [4282] = { 0x070F, 0x070F, 0x0000 }, /* R4282 - Write Sequencer 186 */
+ [4283] = { 0x010F, 0x010F, 0x0000 }, /* R4283 - Write Sequencer 187 */
+ [4284] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4284 - Write Sequencer 188 */
+ [4285] = { 0x00FF, 0x00FF, 0x0000 }, /* R4285 - Write Sequencer 189 */
+ [4286] = { 0x070F, 0x070F, 0x0000 }, /* R4286 - Write Sequencer 190 */
+ [4287] = { 0x010F, 0x010F, 0x0000 }, /* R4287 - Write Sequencer 191 */
+ [4288] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4288 - Write Sequencer 192 */
+ [4289] = { 0x00FF, 0x00FF, 0x0000 }, /* R4289 - Write Sequencer 193 */
+ [4290] = { 0x070F, 0x070F, 0x0000 }, /* R4290 - Write Sequencer 194 */
+ [4291] = { 0x010F, 0x010F, 0x0000 }, /* R4291 - Write Sequencer 195 */
+ [4292] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4292 - Write Sequencer 196 */
+ [4293] = { 0x00FF, 0x00FF, 0x0000 }, /* R4293 - Write Sequencer 197 */
+ [4294] = { 0x070F, 0x070F, 0x0000 }, /* R4294 - Write Sequencer 198 */
+ [4295] = { 0x010F, 0x010F, 0x0000 }, /* R4295 - Write Sequencer 199 */
+ [4296] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4296 - Write Sequencer 200 */
+ [4297] = { 0x00FF, 0x00FF, 0x0000 }, /* R4297 - Write Sequencer 201 */
+ [4298] = { 0x070F, 0x070F, 0x0000 }, /* R4298 - Write Sequencer 202 */
+ [4299] = { 0x010F, 0x010F, 0x0000 }, /* R4299 - Write Sequencer 203 */
+ [4300] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4300 - Write Sequencer 204 */
+ [4301] = { 0x00FF, 0x00FF, 0x0000 }, /* R4301 - Write Sequencer 205 */
+ [4302] = { 0x070F, 0x070F, 0x0000 }, /* R4302 - Write Sequencer 206 */
+ [4303] = { 0x010F, 0x010F, 0x0000 }, /* R4303 - Write Sequencer 207 */
+ [4304] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4304 - Write Sequencer 208 */
+ [4305] = { 0x00FF, 0x00FF, 0x0000 }, /* R4305 - Write Sequencer 209 */
+ [4306] = { 0x070F, 0x070F, 0x0000 }, /* R4306 - Write Sequencer 210 */
+ [4307] = { 0x010F, 0x010F, 0x0000 }, /* R4307 - Write Sequencer 211 */
+ [4308] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4308 - Write Sequencer 212 */
+ [4309] = { 0x00FF, 0x00FF, 0x0000 }, /* R4309 - Write Sequencer 213 */
+ [4310] = { 0x070F, 0x070F, 0x0000 }, /* R4310 - Write Sequencer 214 */
+ [4311] = { 0x010F, 0x010F, 0x0000 }, /* R4311 - Write Sequencer 215 */
+ [4312] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4312 - Write Sequencer 216 */
+ [4313] = { 0x00FF, 0x00FF, 0x0000 }, /* R4313 - Write Sequencer 217 */
+ [4314] = { 0x070F, 0x070F, 0x0000 }, /* R4314 - Write Sequencer 218 */
+ [4315] = { 0x010F, 0x010F, 0x0000 }, /* R4315 - Write Sequencer 219 */
+ [4316] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4316 - Write Sequencer 220 */
+ [4317] = { 0x00FF, 0x00FF, 0x0000 }, /* R4317 - Write Sequencer 221 */
+ [4318] = { 0x070F, 0x070F, 0x0000 }, /* R4318 - Write Sequencer 222 */
+ [4319] = { 0x010F, 0x010F, 0x0000 }, /* R4319 - Write Sequencer 223 */
+ [4320] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4320 - Write Sequencer 224 */
+ [4321] = { 0x00FF, 0x00FF, 0x0000 }, /* R4321 - Write Sequencer 225 */
+ [4322] = { 0x070F, 0x070F, 0x0000 }, /* R4322 - Write Sequencer 226 */
+ [4323] = { 0x010F, 0x010F, 0x0000 }, /* R4323 - Write Sequencer 227 */
+ [4324] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4324 - Write Sequencer 228 */
+ [4325] = { 0x00FF, 0x00FF, 0x0000 }, /* R4325 - Write Sequencer 229 */
+ [4326] = { 0x070F, 0x070F, 0x0000 }, /* R4326 - Write Sequencer 230 */
+ [4327] = { 0x010F, 0x010F, 0x0000 }, /* R4327 - Write Sequencer 231 */
+ [4328] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4328 - Write Sequencer 232 */
+ [4329] = { 0x00FF, 0x00FF, 0x0000 }, /* R4329 - Write Sequencer 233 */
+ [4330] = { 0x070F, 0x070F, 0x0000 }, /* R4330 - Write Sequencer 234 */
+ [4331] = { 0x010F, 0x010F, 0x0000 }, /* R4331 - Write Sequencer 235 */
+ [4332] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4332 - Write Sequencer 236 */
+ [4333] = { 0x00FF, 0x00FF, 0x0000 }, /* R4333 - Write Sequencer 237 */
+ [4334] = { 0x070F, 0x070F, 0x0000 }, /* R4334 - Write Sequencer 238 */
+ [4335] = { 0x010F, 0x010F, 0x0000 }, /* R4335 - Write Sequencer 239 */
+ [4336] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4336 - Write Sequencer 240 */
+ [4337] = { 0x00FF, 0x00FF, 0x0000 }, /* R4337 - Write Sequencer 241 */
+ [4338] = { 0x070F, 0x070F, 0x0000 }, /* R4338 - Write Sequencer 242 */
+ [4339] = { 0x010F, 0x010F, 0x0000 }, /* R4339 - Write Sequencer 243 */
+ [4340] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4340 - Write Sequencer 244 */
+ [4341] = { 0x00FF, 0x00FF, 0x0000 }, /* R4341 - Write Sequencer 245 */
+ [4342] = { 0x070F, 0x070F, 0x0000 }, /* R4342 - Write Sequencer 246 */
+ [4343] = { 0x010F, 0x010F, 0x0000 }, /* R4343 - Write Sequencer 247 */
+ [4344] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4344 - Write Sequencer 248 */
+ [4345] = { 0x00FF, 0x00FF, 0x0000 }, /* R4345 - Write Sequencer 249 */
+ [4346] = { 0x070F, 0x070F, 0x0000 }, /* R4346 - Write Sequencer 250 */
+ [4347] = { 0x010F, 0x010F, 0x0000 }, /* R4347 - Write Sequencer 251 */
+ [4348] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4348 - Write Sequencer 252 */
+ [4349] = { 0x00FF, 0x00FF, 0x0000 }, /* R4349 - Write Sequencer 253 */
+ [4350] = { 0x070F, 0x070F, 0x0000 }, /* R4350 - Write Sequencer 254 */
+ [4351] = { 0x010F, 0x010F, 0x0000 }, /* R4351 - Write Sequencer 255 */
+ [4352] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4352 - Write Sequencer 256 */
+ [4353] = { 0x00FF, 0x00FF, 0x0000 }, /* R4353 - Write Sequencer 257 */
+ [4354] = { 0x070F, 0x070F, 0x0000 }, /* R4354 - Write Sequencer 258 */
+ [4355] = { 0x010F, 0x010F, 0x0000 }, /* R4355 - Write Sequencer 259 */
+ [4356] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4356 - Write Sequencer 260 */
+ [4357] = { 0x00FF, 0x00FF, 0x0000 }, /* R4357 - Write Sequencer 261 */
+ [4358] = { 0x070F, 0x070F, 0x0000 }, /* R4358 - Write Sequencer 262 */
+ [4359] = { 0x010F, 0x010F, 0x0000 }, /* R4359 - Write Sequencer 263 */
+ [4360] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4360 - Write Sequencer 264 */
+ [4361] = { 0x00FF, 0x00FF, 0x0000 }, /* R4361 - Write Sequencer 265 */
+ [4362] = { 0x070F, 0x070F, 0x0000 }, /* R4362 - Write Sequencer 266 */
+ [4363] = { 0x010F, 0x010F, 0x0000 }, /* R4363 - Write Sequencer 267 */
+ [4364] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4364 - Write Sequencer 268 */
+ [4365] = { 0x00FF, 0x00FF, 0x0000 }, /* R4365 - Write Sequencer 269 */
+ [4366] = { 0x070F, 0x070F, 0x0000 }, /* R4366 - Write Sequencer 270 */
+ [4367] = { 0x010F, 0x010F, 0x0000 }, /* R4367 - Write Sequencer 271 */
+ [4368] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4368 - Write Sequencer 272 */
+ [4369] = { 0x00FF, 0x00FF, 0x0000 }, /* R4369 - Write Sequencer 273 */
+ [4370] = { 0x070F, 0x070F, 0x0000 }, /* R4370 - Write Sequencer 274 */
+ [4371] = { 0x010F, 0x010F, 0x0000 }, /* R4371 - Write Sequencer 275 */
+ [4372] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4372 - Write Sequencer 276 */
+ [4373] = { 0x00FF, 0x00FF, 0x0000 }, /* R4373 - Write Sequencer 277 */
+ [4374] = { 0x070F, 0x070F, 0x0000 }, /* R4374 - Write Sequencer 278 */
+ [4375] = { 0x010F, 0x010F, 0x0000 }, /* R4375 - Write Sequencer 279 */
+ [4376] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4376 - Write Sequencer 280 */
+ [4377] = { 0x00FF, 0x00FF, 0x0000 }, /* R4377 - Write Sequencer 281 */
+ [4378] = { 0x070F, 0x070F, 0x0000 }, /* R4378 - Write Sequencer 282 */
+ [4379] = { 0x010F, 0x010F, 0x0000 }, /* R4379 - Write Sequencer 283 */
+ [4380] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4380 - Write Sequencer 284 */
+ [4381] = { 0x00FF, 0x00FF, 0x0000 }, /* R4381 - Write Sequencer 285 */
+ [4382] = { 0x070F, 0x070F, 0x0000 }, /* R4382 - Write Sequencer 286 */
+ [4383] = { 0x010F, 0x010F, 0x0000 }, /* R4383 - Write Sequencer 287 */
+ [4384] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4384 - Write Sequencer 288 */
+ [4385] = { 0x00FF, 0x00FF, 0x0000 }, /* R4385 - Write Sequencer 289 */
+ [4386] = { 0x070F, 0x070F, 0x0000 }, /* R4386 - Write Sequencer 290 */
+ [4387] = { 0x010F, 0x010F, 0x0000 }, /* R4387 - Write Sequencer 291 */
+ [4388] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4388 - Write Sequencer 292 */
+ [4389] = { 0x00FF, 0x00FF, 0x0000 }, /* R4389 - Write Sequencer 293 */
+ [4390] = { 0x070F, 0x070F, 0x0000 }, /* R4390 - Write Sequencer 294 */
+ [4391] = { 0x010F, 0x010F, 0x0000 }, /* R4391 - Write Sequencer 295 */
+ [4392] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4392 - Write Sequencer 296 */
+ [4393] = { 0x00FF, 0x00FF, 0x0000 }, /* R4393 - Write Sequencer 297 */
+ [4394] = { 0x070F, 0x070F, 0x0000 }, /* R4394 - Write Sequencer 298 */
+ [4395] = { 0x010F, 0x010F, 0x0000 }, /* R4395 - Write Sequencer 299 */
+ [4396] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4396 - Write Sequencer 300 */
+ [4397] = { 0x00FF, 0x00FF, 0x0000 }, /* R4397 - Write Sequencer 301 */
+ [4398] = { 0x070F, 0x070F, 0x0000 }, /* R4398 - Write Sequencer 302 */
+ [4399] = { 0x010F, 0x010F, 0x0000 }, /* R4399 - Write Sequencer 303 */
+ [4400] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4400 - Write Sequencer 304 */
+ [4401] = { 0x00FF, 0x00FF, 0x0000 }, /* R4401 - Write Sequencer 305 */
+ [4402] = { 0x070F, 0x070F, 0x0000 }, /* R4402 - Write Sequencer 306 */
+ [4403] = { 0x010F, 0x010F, 0x0000 }, /* R4403 - Write Sequencer 307 */
+ [4404] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4404 - Write Sequencer 308 */
+ [4405] = { 0x00FF, 0x00FF, 0x0000 }, /* R4405 - Write Sequencer 309 */
+ [4406] = { 0x070F, 0x070F, 0x0000 }, /* R4406 - Write Sequencer 310 */
+ [4407] = { 0x010F, 0x010F, 0x0000 }, /* R4407 - Write Sequencer 311 */
+ [4408] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4408 - Write Sequencer 312 */
+ [4409] = { 0x00FF, 0x00FF, 0x0000 }, /* R4409 - Write Sequencer 313 */
+ [4410] = { 0x070F, 0x070F, 0x0000 }, /* R4410 - Write Sequencer 314 */
+ [4411] = { 0x010F, 0x010F, 0x0000 }, /* R4411 - Write Sequencer 315 */
+ [4412] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4412 - Write Sequencer 316 */
+ [4413] = { 0x00FF, 0x00FF, 0x0000 }, /* R4413 - Write Sequencer 317 */
+ [4414] = { 0x070F, 0x070F, 0x0000 }, /* R4414 - Write Sequencer 318 */
+ [4415] = { 0x010F, 0x010F, 0x0000 }, /* R4415 - Write Sequencer 319 */
+ [4416] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4416 - Write Sequencer 320 */
+ [4417] = { 0x00FF, 0x00FF, 0x0000 }, /* R4417 - Write Sequencer 321 */
+ [4418] = { 0x070F, 0x070F, 0x0000 }, /* R4418 - Write Sequencer 322 */
+ [4419] = { 0x010F, 0x010F, 0x0000 }, /* R4419 - Write Sequencer 323 */
+ [4420] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4420 - Write Sequencer 324 */
+ [4421] = { 0x00FF, 0x00FF, 0x0000 }, /* R4421 - Write Sequencer 325 */
+ [4422] = { 0x070F, 0x070F, 0x0000 }, /* R4422 - Write Sequencer 326 */
+ [4423] = { 0x010F, 0x010F, 0x0000 }, /* R4423 - Write Sequencer 327 */
+ [4424] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4424 - Write Sequencer 328 */
+ [4425] = { 0x00FF, 0x00FF, 0x0000 }, /* R4425 - Write Sequencer 329 */
+ [4426] = { 0x070F, 0x070F, 0x0000 }, /* R4426 - Write Sequencer 330 */
+ [4427] = { 0x010F, 0x010F, 0x0000 }, /* R4427 - Write Sequencer 331 */
+ [4428] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4428 - Write Sequencer 332 */
+ [4429] = { 0x00FF, 0x00FF, 0x0000 }, /* R4429 - Write Sequencer 333 */
+ [4430] = { 0x070F, 0x070F, 0x0000 }, /* R4430 - Write Sequencer 334 */
+ [4431] = { 0x010F, 0x010F, 0x0000 }, /* R4431 - Write Sequencer 335 */
+ [4432] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4432 - Write Sequencer 336 */
+ [4433] = { 0x00FF, 0x00FF, 0x0000 }, /* R4433 - Write Sequencer 337 */
+ [4434] = { 0x070F, 0x070F, 0x0000 }, /* R4434 - Write Sequencer 338 */
+ [4435] = { 0x010F, 0x010F, 0x0000 }, /* R4435 - Write Sequencer 339 */
+ [4436] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4436 - Write Sequencer 340 */
+ [4437] = { 0x00FF, 0x00FF, 0x0000 }, /* R4437 - Write Sequencer 341 */
+ [4438] = { 0x070F, 0x070F, 0x0000 }, /* R4438 - Write Sequencer 342 */
+ [4439] = { 0x010F, 0x010F, 0x0000 }, /* R4439 - Write Sequencer 343 */
+ [4440] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4440 - Write Sequencer 344 */
+ [4441] = { 0x00FF, 0x00FF, 0x0000 }, /* R4441 - Write Sequencer 345 */
+ [4442] = { 0x070F, 0x070F, 0x0000 }, /* R4442 - Write Sequencer 346 */
+ [4443] = { 0x010F, 0x010F, 0x0000 }, /* R4443 - Write Sequencer 347 */
+ [4444] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4444 - Write Sequencer 348 */
+ [4445] = { 0x00FF, 0x00FF, 0x0000 }, /* R4445 - Write Sequencer 349 */
+ [4446] = { 0x070F, 0x070F, 0x0000 }, /* R4446 - Write Sequencer 350 */
+ [4447] = { 0x010F, 0x010F, 0x0000 }, /* R4447 - Write Sequencer 351 */
+ [4448] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4448 - Write Sequencer 352 */
+ [4449] = { 0x00FF, 0x00FF, 0x0000 }, /* R4449 - Write Sequencer 353 */
+ [4450] = { 0x070F, 0x070F, 0x0000 }, /* R4450 - Write Sequencer 354 */
+ [4451] = { 0x010F, 0x010F, 0x0000 }, /* R4451 - Write Sequencer 355 */
+ [4452] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4452 - Write Sequencer 356 */
+ [4453] = { 0x00FF, 0x00FF, 0x0000 }, /* R4453 - Write Sequencer 357 */
+ [4454] = { 0x070F, 0x070F, 0x0000 }, /* R4454 - Write Sequencer 358 */
+ [4455] = { 0x010F, 0x010F, 0x0000 }, /* R4455 - Write Sequencer 359 */
+ [4456] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4456 - Write Sequencer 360 */
+ [4457] = { 0x00FF, 0x00FF, 0x0000 }, /* R4457 - Write Sequencer 361 */
+ [4458] = { 0x070F, 0x070F, 0x0000 }, /* R4458 - Write Sequencer 362 */
+ [4459] = { 0x010F, 0x010F, 0x0000 }, /* R4459 - Write Sequencer 363 */
+ [4460] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4460 - Write Sequencer 364 */
+ [4461] = { 0x00FF, 0x00FF, 0x0000 }, /* R4461 - Write Sequencer 365 */
+ [4462] = { 0x070F, 0x070F, 0x0000 }, /* R4462 - Write Sequencer 366 */
+ [4463] = { 0x010F, 0x010F, 0x0000 }, /* R4463 - Write Sequencer 367 */
+ [4464] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4464 - Write Sequencer 368 */
+ [4465] = { 0x00FF, 0x00FF, 0x0000 }, /* R4465 - Write Sequencer 369 */
+ [4466] = { 0x070F, 0x070F, 0x0000 }, /* R4466 - Write Sequencer 370 */
+ [4467] = { 0x010F, 0x010F, 0x0000 }, /* R4467 - Write Sequencer 371 */
+ [4468] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4468 - Write Sequencer 372 */
+ [4469] = { 0x00FF, 0x00FF, 0x0000 }, /* R4469 - Write Sequencer 373 */
+ [4470] = { 0x070F, 0x070F, 0x0000 }, /* R4470 - Write Sequencer 374 */
+ [4471] = { 0x010F, 0x010F, 0x0000 }, /* R4471 - Write Sequencer 375 */
+ [4472] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4472 - Write Sequencer 376 */
+ [4473] = { 0x00FF, 0x00FF, 0x0000 }, /* R4473 - Write Sequencer 377 */
+ [4474] = { 0x070F, 0x070F, 0x0000 }, /* R4474 - Write Sequencer 378 */
+ [4475] = { 0x010F, 0x010F, 0x0000 }, /* R4475 - Write Sequencer 379 */
+ [4476] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4476 - Write Sequencer 380 */
+ [4477] = { 0x00FF, 0x00FF, 0x0000 }, /* R4477 - Write Sequencer 381 */
+ [4478] = { 0x070F, 0x070F, 0x0000 }, /* R4478 - Write Sequencer 382 */
+ [4479] = { 0x010F, 0x010F, 0x0000 }, /* R4479 - Write Sequencer 383 */
+ [4480] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4480 - Write Sequencer 384 */
+ [4481] = { 0x00FF, 0x00FF, 0x0000 }, /* R4481 - Write Sequencer 385 */
+ [4482] = { 0x070F, 0x070F, 0x0000 }, /* R4482 - Write Sequencer 386 */
+ [4483] = { 0x010F, 0x010F, 0x0000 }, /* R4483 - Write Sequencer 387 */
+ [4484] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4484 - Write Sequencer 388 */
+ [4485] = { 0x00FF, 0x00FF, 0x0000 }, /* R4485 - Write Sequencer 389 */
+ [4486] = { 0x070F, 0x070F, 0x0000 }, /* R4486 - Write Sequencer 390 */
+ [4487] = { 0x010F, 0x010F, 0x0000 }, /* R4487 - Write Sequencer 391 */
+ [4488] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4488 - Write Sequencer 392 */
+ [4489] = { 0x00FF, 0x00FF, 0x0000 }, /* R4489 - Write Sequencer 393 */
+ [4490] = { 0x070F, 0x070F, 0x0000 }, /* R4490 - Write Sequencer 394 */
+ [4491] = { 0x010F, 0x010F, 0x0000 }, /* R4491 - Write Sequencer 395 */
+ [4492] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4492 - Write Sequencer 396 */
+ [4493] = { 0x00FF, 0x00FF, 0x0000 }, /* R4493 - Write Sequencer 397 */
+ [4494] = { 0x070F, 0x070F, 0x0000 }, /* R4494 - Write Sequencer 398 */
+ [4495] = { 0x010F, 0x010F, 0x0000 }, /* R4495 - Write Sequencer 399 */
+ [4496] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4496 - Write Sequencer 400 */
+ [4497] = { 0x00FF, 0x00FF, 0x0000 }, /* R4497 - Write Sequencer 401 */
+ [4498] = { 0x070F, 0x070F, 0x0000 }, /* R4498 - Write Sequencer 402 */
+ [4499] = { 0x010F, 0x010F, 0x0000 }, /* R4499 - Write Sequencer 403 */
+ [4500] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4500 - Write Sequencer 404 */
+ [4501] = { 0x00FF, 0x00FF, 0x0000 }, /* R4501 - Write Sequencer 405 */
+ [4502] = { 0x070F, 0x070F, 0x0000 }, /* R4502 - Write Sequencer 406 */
+ [4503] = { 0x010F, 0x010F, 0x0000 }, /* R4503 - Write Sequencer 407 */
+ [4504] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4504 - Write Sequencer 408 */
+ [4505] = { 0x00FF, 0x00FF, 0x0000 }, /* R4505 - Write Sequencer 409 */
+ [4506] = { 0x070F, 0x070F, 0x0000 }, /* R4506 - Write Sequencer 410 */
+ [4507] = { 0x010F, 0x010F, 0x0000 }, /* R4507 - Write Sequencer 411 */
+ [4508] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4508 - Write Sequencer 412 */
+ [4509] = { 0x00FF, 0x00FF, 0x0000 }, /* R4509 - Write Sequencer 413 */
+ [4510] = { 0x070F, 0x070F, 0x0000 }, /* R4510 - Write Sequencer 414 */
+ [4511] = { 0x010F, 0x010F, 0x0000 }, /* R4511 - Write Sequencer 415 */
+ [4512] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4512 - Write Sequencer 416 */
+ [4513] = { 0x00FF, 0x00FF, 0x0000 }, /* R4513 - Write Sequencer 417 */
+ [4514] = { 0x070F, 0x070F, 0x0000 }, /* R4514 - Write Sequencer 418 */
+ [4515] = { 0x010F, 0x010F, 0x0000 }, /* R4515 - Write Sequencer 419 */
+ [4516] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4516 - Write Sequencer 420 */
+ [4517] = { 0x00FF, 0x00FF, 0x0000 }, /* R4517 - Write Sequencer 421 */
+ [4518] = { 0x070F, 0x070F, 0x0000 }, /* R4518 - Write Sequencer 422 */
+ [4519] = { 0x010F, 0x010F, 0x0000 }, /* R4519 - Write Sequencer 423 */
+ [4520] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4520 - Write Sequencer 424 */
+ [4521] = { 0x00FF, 0x00FF, 0x0000 }, /* R4521 - Write Sequencer 425 */
+ [4522] = { 0x070F, 0x070F, 0x0000 }, /* R4522 - Write Sequencer 426 */
+ [4523] = { 0x010F, 0x010F, 0x0000 }, /* R4523 - Write Sequencer 427 */
+ [4524] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4524 - Write Sequencer 428 */
+ [4525] = { 0x00FF, 0x00FF, 0x0000 }, /* R4525 - Write Sequencer 429 */
+ [4526] = { 0x070F, 0x070F, 0x0000 }, /* R4526 - Write Sequencer 430 */
+ [4527] = { 0x010F, 0x010F, 0x0000 }, /* R4527 - Write Sequencer 431 */
+ [4528] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4528 - Write Sequencer 432 */
+ [4529] = { 0x00FF, 0x00FF, 0x0000 }, /* R4529 - Write Sequencer 433 */
+ [4530] = { 0x070F, 0x070F, 0x0000 }, /* R4530 - Write Sequencer 434 */
+ [4531] = { 0x010F, 0x010F, 0x0000 }, /* R4531 - Write Sequencer 435 */
+ [4532] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4532 - Write Sequencer 436 */
+ [4533] = { 0x00FF, 0x00FF, 0x0000 }, /* R4533 - Write Sequencer 437 */
+ [4534] = { 0x070F, 0x070F, 0x0000 }, /* R4534 - Write Sequencer 438 */
+ [4535] = { 0x010F, 0x010F, 0x0000 }, /* R4535 - Write Sequencer 439 */
+ [4536] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4536 - Write Sequencer 440 */
+ [4537] = { 0x00FF, 0x00FF, 0x0000 }, /* R4537 - Write Sequencer 441 */
+ [4538] = { 0x070F, 0x070F, 0x0000 }, /* R4538 - Write Sequencer 442 */
+ [4539] = { 0x010F, 0x010F, 0x0000 }, /* R4539 - Write Sequencer 443 */
+ [4540] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4540 - Write Sequencer 444 */
+ [4541] = { 0x00FF, 0x00FF, 0x0000 }, /* R4541 - Write Sequencer 445 */
+ [4542] = { 0x070F, 0x070F, 0x0000 }, /* R4542 - Write Sequencer 446 */
+ [4543] = { 0x010F, 0x010F, 0x0000 }, /* R4543 - Write Sequencer 447 */
+ [4544] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4544 - Write Sequencer 448 */
+ [4545] = { 0x00FF, 0x00FF, 0x0000 }, /* R4545 - Write Sequencer 449 */
+ [4546] = { 0x070F, 0x070F, 0x0000 }, /* R4546 - Write Sequencer 450 */
+ [4547] = { 0x010F, 0x010F, 0x0000 }, /* R4547 - Write Sequencer 451 */
+ [4548] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4548 - Write Sequencer 452 */
+ [4549] = { 0x00FF, 0x00FF, 0x0000 }, /* R4549 - Write Sequencer 453 */
+ [4550] = { 0x070F, 0x070F, 0x0000 }, /* R4550 - Write Sequencer 454 */
+ [4551] = { 0x010F, 0x010F, 0x0000 }, /* R4551 - Write Sequencer 455 */
+ [4552] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4552 - Write Sequencer 456 */
+ [4553] = { 0x00FF, 0x00FF, 0x0000 }, /* R4553 - Write Sequencer 457 */
+ [4554] = { 0x070F, 0x070F, 0x0000 }, /* R4554 - Write Sequencer 458 */
+ [4555] = { 0x010F, 0x010F, 0x0000 }, /* R4555 - Write Sequencer 459 */
+ [4556] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4556 - Write Sequencer 460 */
+ [4557] = { 0x00FF, 0x00FF, 0x0000 }, /* R4557 - Write Sequencer 461 */
+ [4558] = { 0x070F, 0x070F, 0x0000 }, /* R4558 - Write Sequencer 462 */
+ [4559] = { 0x010F, 0x010F, 0x0000 }, /* R4559 - Write Sequencer 463 */
+ [4560] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4560 - Write Sequencer 464 */
+ [4561] = { 0x00FF, 0x00FF, 0x0000 }, /* R4561 - Write Sequencer 465 */
+ [4562] = { 0x070F, 0x070F, 0x0000 }, /* R4562 - Write Sequencer 466 */
+ [4563] = { 0x010F, 0x010F, 0x0000 }, /* R4563 - Write Sequencer 467 */
+ [4564] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4564 - Write Sequencer 468 */
+ [4565] = { 0x00FF, 0x00FF, 0x0000 }, /* R4565 - Write Sequencer 469 */
+ [4566] = { 0x070F, 0x070F, 0x0000 }, /* R4566 - Write Sequencer 470 */
+ [4567] = { 0x010F, 0x010F, 0x0000 }, /* R4567 - Write Sequencer 471 */
+ [4568] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4568 - Write Sequencer 472 */
+ [4569] = { 0x00FF, 0x00FF, 0x0000 }, /* R4569 - Write Sequencer 473 */
+ [4570] = { 0x070F, 0x070F, 0x0000 }, /* R4570 - Write Sequencer 474 */
+ [4571] = { 0x010F, 0x010F, 0x0000 }, /* R4571 - Write Sequencer 475 */
+ [4572] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4572 - Write Sequencer 476 */
+ [4573] = { 0x00FF, 0x00FF, 0x0000 }, /* R4573 - Write Sequencer 477 */
+ [4574] = { 0x070F, 0x070F, 0x0000 }, /* R4574 - Write Sequencer 478 */
+ [4575] = { 0x010F, 0x010F, 0x0000 }, /* R4575 - Write Sequencer 479 */
+ [4576] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4576 - Write Sequencer 480 */
+ [4577] = { 0x00FF, 0x00FF, 0x0000 }, /* R4577 - Write Sequencer 481 */
+ [4578] = { 0x070F, 0x070F, 0x0000 }, /* R4578 - Write Sequencer 482 */
+ [4579] = { 0x010F, 0x010F, 0x0000 }, /* R4579 - Write Sequencer 483 */
+ [4580] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4580 - Write Sequencer 484 */
+ [4581] = { 0x00FF, 0x00FF, 0x0000 }, /* R4581 - Write Sequencer 485 */
+ [4582] = { 0x070F, 0x070F, 0x0000 }, /* R4582 - Write Sequencer 486 */
+ [4583] = { 0x010F, 0x010F, 0x0000 }, /* R4583 - Write Sequencer 487 */
+ [4584] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4584 - Write Sequencer 488 */
+ [4585] = { 0x00FF, 0x00FF, 0x0000 }, /* R4585 - Write Sequencer 489 */
+ [4586] = { 0x070F, 0x070F, 0x0000 }, /* R4586 - Write Sequencer 490 */
+ [4587] = { 0x010F, 0x010F, 0x0000 }, /* R4587 - Write Sequencer 491 */
+ [4588] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4588 - Write Sequencer 492 */
+ [4589] = { 0x00FF, 0x00FF, 0x0000 }, /* R4589 - Write Sequencer 493 */
+ [4590] = { 0x070F, 0x070F, 0x0000 }, /* R4590 - Write Sequencer 494 */
+ [4591] = { 0x010F, 0x010F, 0x0000 }, /* R4591 - Write Sequencer 495 */
+ [4592] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4592 - Write Sequencer 496 */
+ [4593] = { 0x00FF, 0x00FF, 0x0000 }, /* R4593 - Write Sequencer 497 */
+ [4594] = { 0x070F, 0x070F, 0x0000 }, /* R4594 - Write Sequencer 498 */
+ [4595] = { 0x010F, 0x010F, 0x0000 }, /* R4595 - Write Sequencer 499 */
+ [4596] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4596 - Write Sequencer 500 */
+ [4597] = { 0x00FF, 0x00FF, 0x0000 }, /* R4597 - Write Sequencer 501 */
+ [4598] = { 0x070F, 0x070F, 0x0000 }, /* R4598 - Write Sequencer 502 */
+ [4599] = { 0x010F, 0x010F, 0x0000 }, /* R4599 - Write Sequencer 503 */
+ [4600] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4600 - Write Sequencer 504 */
+ [4601] = { 0x00FF, 0x00FF, 0x0000 }, /* R4601 - Write Sequencer 505 */
+ [4602] = { 0x070F, 0x070F, 0x0000 }, /* R4602 - Write Sequencer 506 */
+ [4603] = { 0x010F, 0x010F, 0x0000 }, /* R4603 - Write Sequencer 507 */
+ [4604] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4604 - Write Sequencer 508 */
+ [4605] = { 0x00FF, 0x00FF, 0x0000 }, /* R4605 - Write Sequencer 509 */
+ [4606] = { 0x070F, 0x070F, 0x0000 }, /* R4606 - Write Sequencer 510 */
+ [4607] = { 0x010F, 0x010F, 0x0000 }, /* R4607 - Write Sequencer 511 */
+ [8192] = { 0x03FF, 0x03FF, 0x0000 }, /* R8192 - DSP2 Instruction RAM 0 */
+ [9216] = { 0x003F, 0x003F, 0x0000 }, /* R9216 - DSP2 Address RAM 2 */
+ [9217] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R9217 - DSP2 Address RAM 1 */
+ [9218] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R9218 - DSP2 Address RAM 0 */
+ [12288] = { 0x00FF, 0x00FF, 0x0000 }, /* R12288 - DSP2 Data1 RAM 1 */
+ [12289] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R12289 - DSP2 Data1 RAM 0 */
+ [13312] = { 0x00FF, 0x00FF, 0x0000 }, /* R13312 - DSP2 Data2 RAM 1 */
+ [13313] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R13313 - DSP2 Data2 RAM 0 */
+ [14336] = { 0x00FF, 0x00FF, 0x0000 }, /* R14336 - DSP2 Data3 RAM 1 */
+ [14337] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R14337 - DSP2 Data3 RAM 0 */
+ [15360] = { 0x07FF, 0x07FF, 0x0000 }, /* R15360 - DSP2 Coeff RAM 0 */
+ [16384] = { 0x00FF, 0x00FF, 0x0000 }, /* R16384 - RETUNEADC_SHARED_COEFF_1 */
+ [16385] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16385 - RETUNEADC_SHARED_COEFF_0 */
+ [16386] = { 0x00FF, 0x00FF, 0x0000 }, /* R16386 - RETUNEDAC_SHARED_COEFF_1 */
+ [16387] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16387 - RETUNEDAC_SHARED_COEFF_0 */
+ [16388] = { 0x00FF, 0x00FF, 0x0000 }, /* R16388 - SOUNDSTAGE_ENABLES_1 */
+ [16389] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16389 - SOUNDSTAGE_ENABLES_0 */
+ [16896] = { 0x00FF, 0x00FF, 0x0000 }, /* R16896 - HDBASS_AI_1 */
+ [16897] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16897 - HDBASS_AI_0 */
+ [16898] = { 0x00FF, 0x00FF, 0x0000 }, /* R16898 - HDBASS_AR_1 */
+ [16899] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16899 - HDBASS_AR_0 */
+ [16900] = { 0x00FF, 0x00FF, 0x0000 }, /* R16900 - HDBASS_B_1 */
+ [16901] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16901 - HDBASS_B_0 */
+ [16902] = { 0x00FF, 0x00FF, 0x0000 }, /* R16902 - HDBASS_K_1 */
+ [16903] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16903 - HDBASS_K_0 */
+ [16904] = { 0x00FF, 0x00FF, 0x0000 }, /* R16904 - HDBASS_N1_1 */
+ [16905] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16905 - HDBASS_N1_0 */
+ [16906] = { 0x00FF, 0x00FF, 0x0000 }, /* R16906 - HDBASS_N2_1 */
+ [16907] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16907 - HDBASS_N2_0 */
+ [16908] = { 0x00FF, 0x00FF, 0x0000 }, /* R16908 - HDBASS_N3_1 */
+ [16909] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16909 - HDBASS_N3_0 */
+ [16910] = { 0x00FF, 0x00FF, 0x0000 }, /* R16910 - HDBASS_N4_1 */
+ [16911] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16911 - HDBASS_N4_0 */
+ [16912] = { 0x00FF, 0x00FF, 0x0000 }, /* R16912 - HDBASS_N5_1 */
+ [16913] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16913 - HDBASS_N5_0 */
+ [16914] = { 0x00FF, 0x00FF, 0x0000 }, /* R16914 - HDBASS_X1_1 */
+ [16915] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16915 - HDBASS_X1_0 */
+ [16916] = { 0x00FF, 0x00FF, 0x0000 }, /* R16916 - HDBASS_X2_1 */
+ [16917] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16917 - HDBASS_X2_0 */
+ [16918] = { 0x00FF, 0x00FF, 0x0000 }, /* R16918 - HDBASS_X3_1 */
+ [16919] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16919 - HDBASS_X3_0 */
+ [16920] = { 0x00FF, 0x00FF, 0x0000 }, /* R16920 - HDBASS_ATK_1 */
+ [16921] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16921 - HDBASS_ATK_0 */
+ [16922] = { 0x00FF, 0x00FF, 0x0000 }, /* R16922 - HDBASS_DCY_1 */
+ [16923] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16923 - HDBASS_DCY_0 */
+ [16924] = { 0x00FF, 0x00FF, 0x0000 }, /* R16924 - HDBASS_PG_1 */
+ [16925] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16925 - HDBASS_PG_0 */
+ [17408] = { 0x00FF, 0x00FF, 0x0000 }, /* R17408 - HPF_C_1 */
+ [17409] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17409 - HPF_C_0 */
+ [17920] = { 0x00FF, 0x00FF, 0x0000 }, /* R17920 - ADCL_RETUNE_C1_1 */
+ [17921] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17921 - ADCL_RETUNE_C1_0 */
+ [17922] = { 0x00FF, 0x00FF, 0x0000 }, /* R17922 - ADCL_RETUNE_C2_1 */
+ [17923] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17923 - ADCL_RETUNE_C2_0 */
+ [17924] = { 0x00FF, 0x00FF, 0x0000 }, /* R17924 - ADCL_RETUNE_C3_1 */
+ [17925] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17925 - ADCL_RETUNE_C3_0 */
+ [17926] = { 0x00FF, 0x00FF, 0x0000 }, /* R17926 - ADCL_RETUNE_C4_1 */
+ [17927] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17927 - ADCL_RETUNE_C4_0 */
+ [17928] = { 0x00FF, 0x00FF, 0x0000 }, /* R17928 - ADCL_RETUNE_C5_1 */
+ [17929] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17929 - ADCL_RETUNE_C5_0 */
+ [17930] = { 0x00FF, 0x00FF, 0x0000 }, /* R17930 - ADCL_RETUNE_C6_1 */
+ [17931] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17931 - ADCL_RETUNE_C6_0 */
+ [17932] = { 0x00FF, 0x00FF, 0x0000 }, /* R17932 - ADCL_RETUNE_C7_1 */
+ [17933] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17933 - ADCL_RETUNE_C7_0 */
+ [17934] = { 0x00FF, 0x00FF, 0x0000 }, /* R17934 - ADCL_RETUNE_C8_1 */
+ [17935] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17935 - ADCL_RETUNE_C8_0 */
+ [17936] = { 0x00FF, 0x00FF, 0x0000 }, /* R17936 - ADCL_RETUNE_C9_1 */
+ [17937] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17937 - ADCL_RETUNE_C9_0 */
+ [17938] = { 0x00FF, 0x00FF, 0x0000 }, /* R17938 - ADCL_RETUNE_C10_1 */
+ [17939] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17939 - ADCL_RETUNE_C10_0 */
+ [17940] = { 0x00FF, 0x00FF, 0x0000 }, /* R17940 - ADCL_RETUNE_C11_1 */
+ [17941] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17941 - ADCL_RETUNE_C11_0 */
+ [17942] = { 0x00FF, 0x00FF, 0x0000 }, /* R17942 - ADCL_RETUNE_C12_1 */
+ [17943] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17943 - ADCL_RETUNE_C12_0 */
+ [17944] = { 0x00FF, 0x00FF, 0x0000 }, /* R17944 - ADCL_RETUNE_C13_1 */
+ [17945] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17945 - ADCL_RETUNE_C13_0 */
+ [17946] = { 0x00FF, 0x00FF, 0x0000 }, /* R17946 - ADCL_RETUNE_C14_1 */
+ [17947] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17947 - ADCL_RETUNE_C14_0 */
+ [17948] = { 0x00FF, 0x00FF, 0x0000 }, /* R17948 - ADCL_RETUNE_C15_1 */
+ [17949] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17949 - ADCL_RETUNE_C15_0 */
+ [17950] = { 0x00FF, 0x00FF, 0x0000 }, /* R17950 - ADCL_RETUNE_C16_1 */
+ [17951] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17951 - ADCL_RETUNE_C16_0 */
+ [17952] = { 0x00FF, 0x00FF, 0x0000 }, /* R17952 - ADCL_RETUNE_C17_1 */
+ [17953] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17953 - ADCL_RETUNE_C17_0 */
+ [17954] = { 0x00FF, 0x00FF, 0x0000 }, /* R17954 - ADCL_RETUNE_C18_1 */
+ [17955] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17955 - ADCL_RETUNE_C18_0 */
+ [17956] = { 0x00FF, 0x00FF, 0x0000 }, /* R17956 - ADCL_RETUNE_C19_1 */
+ [17957] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17957 - ADCL_RETUNE_C19_0 */
+ [17958] = { 0x00FF, 0x00FF, 0x0000 }, /* R17958 - ADCL_RETUNE_C20_1 */
+ [17959] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17959 - ADCL_RETUNE_C20_0 */
+ [17960] = { 0x00FF, 0x00FF, 0x0000 }, /* R17960 - ADCL_RETUNE_C21_1 */
+ [17961] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17961 - ADCL_RETUNE_C21_0 */
+ [17962] = { 0x00FF, 0x00FF, 0x0000 }, /* R17962 - ADCL_RETUNE_C22_1 */
+ [17963] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17963 - ADCL_RETUNE_C22_0 */
+ [17964] = { 0x00FF, 0x00FF, 0x0000 }, /* R17964 - ADCL_RETUNE_C23_1 */
+ [17965] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17965 - ADCL_RETUNE_C23_0 */
+ [17966] = { 0x00FF, 0x00FF, 0x0000 }, /* R17966 - ADCL_RETUNE_C24_1 */
+ [17967] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17967 - ADCL_RETUNE_C24_0 */
+ [17968] = { 0x00FF, 0x00FF, 0x0000 }, /* R17968 - ADCL_RETUNE_C25_1 */
+ [17969] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17969 - ADCL_RETUNE_C25_0 */
+ [17970] = { 0x00FF, 0x00FF, 0x0000 }, /* R17970 - ADCL_RETUNE_C26_1 */
+ [17971] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17971 - ADCL_RETUNE_C26_0 */
+ [17972] = { 0x00FF, 0x00FF, 0x0000 }, /* R17972 - ADCL_RETUNE_C27_1 */
+ [17973] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17973 - ADCL_RETUNE_C27_0 */
+ [17974] = { 0x00FF, 0x00FF, 0x0000 }, /* R17974 - ADCL_RETUNE_C28_1 */
+ [17975] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17975 - ADCL_RETUNE_C28_0 */
+ [17976] = { 0x00FF, 0x00FF, 0x0000 }, /* R17976 - ADCL_RETUNE_C29_1 */
+ [17977] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17977 - ADCL_RETUNE_C29_0 */
+ [17978] = { 0x00FF, 0x00FF, 0x0000 }, /* R17978 - ADCL_RETUNE_C30_1 */
+ [17979] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17979 - ADCL_RETUNE_C30_0 */
+ [17980] = { 0x00FF, 0x00FF, 0x0000 }, /* R17980 - ADCL_RETUNE_C31_1 */
+ [17981] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17981 - ADCL_RETUNE_C31_0 */
+ [17982] = { 0x00FF, 0x00FF, 0x0000 }, /* R17982 - ADCL_RETUNE_C32_1 */
+ [17983] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17983 - ADCL_RETUNE_C32_0 */
+ [18432] = { 0x00FF, 0x00FF, 0x0000 }, /* R18432 - RETUNEADC_PG2_1 */
+ [18433] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18433 - RETUNEADC_PG2_0 */
+ [18434] = { 0x00FF, 0x00FF, 0x0000 }, /* R18434 - RETUNEADC_PG_1 */
+ [18435] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18435 - RETUNEADC_PG_0 */
+ [18944] = { 0x00FF, 0x00FF, 0x0000 }, /* R18944 - ADCR_RETUNE_C1_1 */
+ [18945] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18945 - ADCR_RETUNE_C1_0 */
+ [18946] = { 0x00FF, 0x00FF, 0x0000 }, /* R18946 - ADCR_RETUNE_C2_1 */
+ [18947] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18947 - ADCR_RETUNE_C2_0 */
+ [18948] = { 0x00FF, 0x00FF, 0x0000 }, /* R18948 - ADCR_RETUNE_C3_1 */
+ [18949] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18949 - ADCR_RETUNE_C3_0 */
+ [18950] = { 0x00FF, 0x00FF, 0x0000 }, /* R18950 - ADCR_RETUNE_C4_1 */
+ [18951] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18951 - ADCR_RETUNE_C4_0 */
+ [18952] = { 0x00FF, 0x00FF, 0x0000 }, /* R18952 - ADCR_RETUNE_C5_1 */
+ [18953] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18953 - ADCR_RETUNE_C5_0 */
+ [18954] = { 0x00FF, 0x00FF, 0x0000 }, /* R18954 - ADCR_RETUNE_C6_1 */
+ [18955] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18955 - ADCR_RETUNE_C6_0 */
+ [18956] = { 0x00FF, 0x00FF, 0x0000 }, /* R18956 - ADCR_RETUNE_C7_1 */
+ [18957] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18957 - ADCR_RETUNE_C7_0 */
+ [18958] = { 0x00FF, 0x00FF, 0x0000 }, /* R18958 - ADCR_RETUNE_C8_1 */
+ [18959] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18959 - ADCR_RETUNE_C8_0 */
+ [18960] = { 0x00FF, 0x00FF, 0x0000 }, /* R18960 - ADCR_RETUNE_C9_1 */
+ [18961] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18961 - ADCR_RETUNE_C9_0 */
+ [18962] = { 0x00FF, 0x00FF, 0x0000 }, /* R18962 - ADCR_RETUNE_C10_1 */
+ [18963] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18963 - ADCR_RETUNE_C10_0 */
+ [18964] = { 0x00FF, 0x00FF, 0x0000 }, /* R18964 - ADCR_RETUNE_C11_1 */
+ [18965] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18965 - ADCR_RETUNE_C11_0 */
+ [18966] = { 0x00FF, 0x00FF, 0x0000 }, /* R18966 - ADCR_RETUNE_C12_1 */
+ [18967] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18967 - ADCR_RETUNE_C12_0 */
+ [18968] = { 0x00FF, 0x00FF, 0x0000 }, /* R18968 - ADCR_RETUNE_C13_1 */
+ [18969] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18969 - ADCR_RETUNE_C13_0 */
+ [18970] = { 0x00FF, 0x00FF, 0x0000 }, /* R18970 - ADCR_RETUNE_C14_1 */
+ [18971] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18971 - ADCR_RETUNE_C14_0 */
+ [18972] = { 0x00FF, 0x00FF, 0x0000 }, /* R18972 - ADCR_RETUNE_C15_1 */
+ [18973] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18973 - ADCR_RETUNE_C15_0 */
+ [18974] = { 0x00FF, 0x00FF, 0x0000 }, /* R18974 - ADCR_RETUNE_C16_1 */
+ [18975] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18975 - ADCR_RETUNE_C16_0 */
+ [18976] = { 0x00FF, 0x00FF, 0x0000 }, /* R18976 - ADCR_RETUNE_C17_1 */
+ [18977] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18977 - ADCR_RETUNE_C17_0 */
+ [18978] = { 0x00FF, 0x00FF, 0x0000 }, /* R18978 - ADCR_RETUNE_C18_1 */
+ [18979] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18979 - ADCR_RETUNE_C18_0 */
+ [18980] = { 0x00FF, 0x00FF, 0x0000 }, /* R18980 - ADCR_RETUNE_C19_1 */
+ [18981] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18981 - ADCR_RETUNE_C19_0 */
+ [18982] = { 0x00FF, 0x00FF, 0x0000 }, /* R18982 - ADCR_RETUNE_C20_1 */
+ [18983] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18983 - ADCR_RETUNE_C20_0 */
+ [18984] = { 0x00FF, 0x00FF, 0x0000 }, /* R18984 - ADCR_RETUNE_C21_1 */
+ [18985] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18985 - ADCR_RETUNE_C21_0 */
+ [18986] = { 0x00FF, 0x00FF, 0x0000 }, /* R18986 - ADCR_RETUNE_C22_1 */
+ [18987] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18987 - ADCR_RETUNE_C22_0 */
+ [18988] = { 0x00FF, 0x00FF, 0x0000 }, /* R18988 - ADCR_RETUNE_C23_1 */
+ [18989] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18989 - ADCR_RETUNE_C23_0 */
+ [18990] = { 0x00FF, 0x00FF, 0x0000 }, /* R18990 - ADCR_RETUNE_C24_1 */
+ [18991] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18991 - ADCR_RETUNE_C24_0 */
+ [18992] = { 0x00FF, 0x00FF, 0x0000 }, /* R18992 - ADCR_RETUNE_C25_1 */
+ [18993] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18993 - ADCR_RETUNE_C25_0 */
+ [18994] = { 0x00FF, 0x00FF, 0x0000 }, /* R18994 - ADCR_RETUNE_C26_1 */
+ [18995] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18995 - ADCR_RETUNE_C26_0 */
+ [18996] = { 0x00FF, 0x00FF, 0x0000 }, /* R18996 - ADCR_RETUNE_C27_1 */
+ [18997] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18997 - ADCR_RETUNE_C27_0 */
+ [18998] = { 0x00FF, 0x00FF, 0x0000 }, /* R18998 - ADCR_RETUNE_C28_1 */
+ [18999] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18999 - ADCR_RETUNE_C28_0 */
+ [19000] = { 0x00FF, 0x00FF, 0x0000 }, /* R19000 - ADCR_RETUNE_C29_1 */
+ [19001] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19001 - ADCR_RETUNE_C29_0 */
+ [19002] = { 0x00FF, 0x00FF, 0x0000 }, /* R19002 - ADCR_RETUNE_C30_1 */
+ [19003] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19003 - ADCR_RETUNE_C30_0 */
+ [19004] = { 0x00FF, 0x00FF, 0x0000 }, /* R19004 - ADCR_RETUNE_C31_1 */
+ [19005] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19005 - ADCR_RETUNE_C31_0 */
+ [19006] = { 0x00FF, 0x00FF, 0x0000 }, /* R19006 - ADCR_RETUNE_C32_1 */
+ [19007] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19007 - ADCR_RETUNE_C32_0 */
+ [19456] = { 0x00FF, 0x00FF, 0x0000 }, /* R19456 - DACL_RETUNE_C1_1 */
+ [19457] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19457 - DACL_RETUNE_C1_0 */
+ [19458] = { 0x00FF, 0x00FF, 0x0000 }, /* R19458 - DACL_RETUNE_C2_1 */
+ [19459] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19459 - DACL_RETUNE_C2_0 */
+ [19460] = { 0x00FF, 0x00FF, 0x0000 }, /* R19460 - DACL_RETUNE_C3_1 */
+ [19461] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19461 - DACL_RETUNE_C3_0 */
+ [19462] = { 0x00FF, 0x00FF, 0x0000 }, /* R19462 - DACL_RETUNE_C4_1 */
+ [19463] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19463 - DACL_RETUNE_C4_0 */
+ [19464] = { 0x00FF, 0x00FF, 0x0000 }, /* R19464 - DACL_RETUNE_C5_1 */
+ [19465] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19465 - DACL_RETUNE_C5_0 */
+ [19466] = { 0x00FF, 0x00FF, 0x0000 }, /* R19466 - DACL_RETUNE_C6_1 */
+ [19467] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19467 - DACL_RETUNE_C6_0 */
+ [19468] = { 0x00FF, 0x00FF, 0x0000 }, /* R19468 - DACL_RETUNE_C7_1 */
+ [19469] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19469 - DACL_RETUNE_C7_0 */
+ [19470] = { 0x00FF, 0x00FF, 0x0000 }, /* R19470 - DACL_RETUNE_C8_1 */
+ [19471] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19471 - DACL_RETUNE_C8_0 */
+ [19472] = { 0x00FF, 0x00FF, 0x0000 }, /* R19472 - DACL_RETUNE_C9_1 */
+ [19473] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19473 - DACL_RETUNE_C9_0 */
+ [19474] = { 0x00FF, 0x00FF, 0x0000 }, /* R19474 - DACL_RETUNE_C10_1 */
+ [19475] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19475 - DACL_RETUNE_C10_0 */
+ [19476] = { 0x00FF, 0x00FF, 0x0000 }, /* R19476 - DACL_RETUNE_C11_1 */
+ [19477] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19477 - DACL_RETUNE_C11_0 */
+ [19478] = { 0x00FF, 0x00FF, 0x0000 }, /* R19478 - DACL_RETUNE_C12_1 */
+ [19479] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19479 - DACL_RETUNE_C12_0 */
+ [19480] = { 0x00FF, 0x00FF, 0x0000 }, /* R19480 - DACL_RETUNE_C13_1 */
+ [19481] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19481 - DACL_RETUNE_C13_0 */
+ [19482] = { 0x00FF, 0x00FF, 0x0000 }, /* R19482 - DACL_RETUNE_C14_1 */
+ [19483] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19483 - DACL_RETUNE_C14_0 */
+ [19484] = { 0x00FF, 0x00FF, 0x0000 }, /* R19484 - DACL_RETUNE_C15_1 */
+ [19485] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19485 - DACL_RETUNE_C15_0 */
+ [19486] = { 0x00FF, 0x00FF, 0x0000 }, /* R19486 - DACL_RETUNE_C16_1 */
+ [19487] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19487 - DACL_RETUNE_C16_0 */
+ [19488] = { 0x00FF, 0x00FF, 0x0000 }, /* R19488 - DACL_RETUNE_C17_1 */
+ [19489] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19489 - DACL_RETUNE_C17_0 */
+ [19490] = { 0x00FF, 0x00FF, 0x0000 }, /* R19490 - DACL_RETUNE_C18_1 */
+ [19491] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19491 - DACL_RETUNE_C18_0 */
+ [19492] = { 0x00FF, 0x00FF, 0x0000 }, /* R19492 - DACL_RETUNE_C19_1 */
+ [19493] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19493 - DACL_RETUNE_C19_0 */
+ [19494] = { 0x00FF, 0x00FF, 0x0000 }, /* R19494 - DACL_RETUNE_C20_1 */
+ [19495] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19495 - DACL_RETUNE_C20_0 */
+ [19496] = { 0x00FF, 0x00FF, 0x0000 }, /* R19496 - DACL_RETUNE_C21_1 */
+ [19497] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19497 - DACL_RETUNE_C21_0 */
+ [19498] = { 0x00FF, 0x00FF, 0x0000 }, /* R19498 - DACL_RETUNE_C22_1 */
+ [19499] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19499 - DACL_RETUNE_C22_0 */
+ [19500] = { 0x00FF, 0x00FF, 0x0000 }, /* R19500 - DACL_RETUNE_C23_1 */
+ [19501] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19501 - DACL_RETUNE_C23_0 */
+ [19502] = { 0x00FF, 0x00FF, 0x0000 }, /* R19502 - DACL_RETUNE_C24_1 */
+ [19503] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19503 - DACL_RETUNE_C24_0 */
+ [19504] = { 0x00FF, 0x00FF, 0x0000 }, /* R19504 - DACL_RETUNE_C25_1 */
+ [19505] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19505 - DACL_RETUNE_C25_0 */
+ [19506] = { 0x00FF, 0x00FF, 0x0000 }, /* R19506 - DACL_RETUNE_C26_1 */
+ [19507] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19507 - DACL_RETUNE_C26_0 */
+ [19508] = { 0x00FF, 0x00FF, 0x0000 }, /* R19508 - DACL_RETUNE_C27_1 */
+ [19509] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19509 - DACL_RETUNE_C27_0 */
+ [19510] = { 0x00FF, 0x00FF, 0x0000 }, /* R19510 - DACL_RETUNE_C28_1 */
+ [19511] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19511 - DACL_RETUNE_C28_0 */
+ [19512] = { 0x00FF, 0x00FF, 0x0000 }, /* R19512 - DACL_RETUNE_C29_1 */
+ [19513] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19513 - DACL_RETUNE_C29_0 */
+ [19514] = { 0x00FF, 0x00FF, 0x0000 }, /* R19514 - DACL_RETUNE_C30_1 */
+ [19515] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19515 - DACL_RETUNE_C30_0 */
+ [19516] = { 0x00FF, 0x00FF, 0x0000 }, /* R19516 - DACL_RETUNE_C31_1 */
+ [19517] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19517 - DACL_RETUNE_C31_0 */
+ [19518] = { 0x00FF, 0x00FF, 0x0000 }, /* R19518 - DACL_RETUNE_C32_1 */
+ [19519] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19519 - DACL_RETUNE_C32_0 */
+ [19968] = { 0x00FF, 0x00FF, 0x0000 }, /* R19968 - RETUNEDAC_PG2_1 */
+ [19969] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19969 - RETUNEDAC_PG2_0 */
+ [19970] = { 0x00FF, 0x00FF, 0x0000 }, /* R19970 - RETUNEDAC_PG_1 */
+ [19971] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19971 - RETUNEDAC_PG_0 */
+ [20480] = { 0x00FF, 0x00FF, 0x0000 }, /* R20480 - DACR_RETUNE_C1_1 */
+ [20481] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20481 - DACR_RETUNE_C1_0 */
+ [20482] = { 0x00FF, 0x00FF, 0x0000 }, /* R20482 - DACR_RETUNE_C2_1 */
+ [20483] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20483 - DACR_RETUNE_C2_0 */
+ [20484] = { 0x00FF, 0x00FF, 0x0000 }, /* R20484 - DACR_RETUNE_C3_1 */
+ [20485] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20485 - DACR_RETUNE_C3_0 */
+ [20486] = { 0x00FF, 0x00FF, 0x0000 }, /* R20486 - DACR_RETUNE_C4_1 */
+ [20487] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20487 - DACR_RETUNE_C4_0 */
+ [20488] = { 0x00FF, 0x00FF, 0x0000 }, /* R20488 - DACR_RETUNE_C5_1 */
+ [20489] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20489 - DACR_RETUNE_C5_0 */
+ [20490] = { 0x00FF, 0x00FF, 0x0000 }, /* R20490 - DACR_RETUNE_C6_1 */
+ [20491] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20491 - DACR_RETUNE_C6_0 */
+ [20492] = { 0x00FF, 0x00FF, 0x0000 }, /* R20492 - DACR_RETUNE_C7_1 */
+ [20493] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20493 - DACR_RETUNE_C7_0 */
+ [20494] = { 0x00FF, 0x00FF, 0x0000 }, /* R20494 - DACR_RETUNE_C8_1 */
+ [20495] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20495 - DACR_RETUNE_C8_0 */
+ [20496] = { 0x00FF, 0x00FF, 0x0000 }, /* R20496 - DACR_RETUNE_C9_1 */
+ [20497] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20497 - DACR_RETUNE_C9_0 */
+ [20498] = { 0x00FF, 0x00FF, 0x0000 }, /* R20498 - DACR_RETUNE_C10_1 */
+ [20499] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20499 - DACR_RETUNE_C10_0 */
+ [20500] = { 0x00FF, 0x00FF, 0x0000 }, /* R20500 - DACR_RETUNE_C11_1 */
+ [20501] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20501 - DACR_RETUNE_C11_0 */
+ [20502] = { 0x00FF, 0x00FF, 0x0000 }, /* R20502 - DACR_RETUNE_C12_1 */
+ [20503] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20503 - DACR_RETUNE_C12_0 */
+ [20504] = { 0x00FF, 0x00FF, 0x0000 }, /* R20504 - DACR_RETUNE_C13_1 */
+ [20505] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20505 - DACR_RETUNE_C13_0 */
+ [20506] = { 0x00FF, 0x00FF, 0x0000 }, /* R20506 - DACR_RETUNE_C14_1 */
+ [20507] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20507 - DACR_RETUNE_C14_0 */
+ [20508] = { 0x00FF, 0x00FF, 0x0000 }, /* R20508 - DACR_RETUNE_C15_1 */
+ [20509] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20509 - DACR_RETUNE_C15_0 */
+ [20510] = { 0x00FF, 0x00FF, 0x0000 }, /* R20510 - DACR_RETUNE_C16_1 */
+ [20511] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20511 - DACR_RETUNE_C16_0 */
+ [20512] = { 0x00FF, 0x00FF, 0x0000 }, /* R20512 - DACR_RETUNE_C17_1 */
+ [20513] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20513 - DACR_RETUNE_C17_0 */
+ [20514] = { 0x00FF, 0x00FF, 0x0000 }, /* R20514 - DACR_RETUNE_C18_1 */
+ [20515] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20515 - DACR_RETUNE_C18_0 */
+ [20516] = { 0x00FF, 0x00FF, 0x0000 }, /* R20516 - DACR_RETUNE_C19_1 */
+ [20517] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20517 - DACR_RETUNE_C19_0 */
+ [20518] = { 0x00FF, 0x00FF, 0x0000 }, /* R20518 - DACR_RETUNE_C20_1 */
+ [20519] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20519 - DACR_RETUNE_C20_0 */
+ [20520] = { 0x00FF, 0x00FF, 0x0000 }, /* R20520 - DACR_RETUNE_C21_1 */
+ [20521] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20521 - DACR_RETUNE_C21_0 */
+ [20522] = { 0x00FF, 0x00FF, 0x0000 }, /* R20522 - DACR_RETUNE_C22_1 */
+ [20523] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20523 - DACR_RETUNE_C22_0 */
+ [20524] = { 0x00FF, 0x00FF, 0x0000 }, /* R20524 - DACR_RETUNE_C23_1 */
+ [20525] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20525 - DACR_RETUNE_C23_0 */
+ [20526] = { 0x00FF, 0x00FF, 0x0000 }, /* R20526 - DACR_RETUNE_C24_1 */
+ [20527] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20527 - DACR_RETUNE_C24_0 */
+ [20528] = { 0x00FF, 0x00FF, 0x0000 }, /* R20528 - DACR_RETUNE_C25_1 */
+ [20529] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20529 - DACR_RETUNE_C25_0 */
+ [20530] = { 0x00FF, 0x00FF, 0x0000 }, /* R20530 - DACR_RETUNE_C26_1 */
+ [20531] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20531 - DACR_RETUNE_C26_0 */
+ [20532] = { 0x00FF, 0x00FF, 0x0000 }, /* R20532 - DACR_RETUNE_C27_1 */
+ [20533] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20533 - DACR_RETUNE_C27_0 */
+ [20534] = { 0x00FF, 0x00FF, 0x0000 }, /* R20534 - DACR_RETUNE_C28_1 */
+ [20535] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20535 - DACR_RETUNE_C28_0 */
+ [20536] = { 0x00FF, 0x00FF, 0x0000 }, /* R20536 - DACR_RETUNE_C29_1 */
+ [20537] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20537 - DACR_RETUNE_C29_0 */
+ [20538] = { 0x00FF, 0x00FF, 0x0000 }, /* R20538 - DACR_RETUNE_C30_1 */
+ [20539] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20539 - DACR_RETUNE_C30_0 */
+ [20540] = { 0x00FF, 0x00FF, 0x0000 }, /* R20540 - DACR_RETUNE_C31_1 */
+ [20541] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20541 - DACR_RETUNE_C31_0 */
+ [20542] = { 0x00FF, 0x00FF, 0x0000 }, /* R20542 - DACR_RETUNE_C32_1 */
+ [20543] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20543 - DACR_RETUNE_C32_0 */
+ [20992] = { 0x00FF, 0x00FF, 0x0000 }, /* R20992 - VSS_XHD2_1 */
+ [20993] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20993 - VSS_XHD2_0 */
+ [20994] = { 0x00FF, 0x00FF, 0x0000 }, /* R20994 - VSS_XHD3_1 */
+ [20995] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20995 - VSS_XHD3_0 */
+ [20996] = { 0x00FF, 0x00FF, 0x0000 }, /* R20996 - VSS_XHN1_1 */
+ [20997] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20997 - VSS_XHN1_0 */
+ [20998] = { 0x00FF, 0x00FF, 0x0000 }, /* R20998 - VSS_XHN2_1 */
+ [20999] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20999 - VSS_XHN2_0 */
+ [21000] = { 0x00FF, 0x00FF, 0x0000 }, /* R21000 - VSS_XHN3_1 */
+ [21001] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21001 - VSS_XHN3_0 */
+ [21002] = { 0x00FF, 0x00FF, 0x0000 }, /* R21002 - VSS_XLA_1 */
+ [21003] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21003 - VSS_XLA_0 */
+ [21004] = { 0x00FF, 0x00FF, 0x0000 }, /* R21004 - VSS_XLB_1 */
+ [21005] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21005 - VSS_XLB_0 */
+ [21006] = { 0x00FF, 0x00FF, 0x0000 }, /* R21006 - VSS_XLG_1 */
+ [21007] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21007 - VSS_XLG_0 */
+ [21008] = { 0x00FF, 0x00FF, 0x0000 }, /* R21008 - VSS_PG2_1 */
+ [21009] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21009 - VSS_PG2_0 */
+ [21010] = { 0x00FF, 0x00FF, 0x0000 }, /* R21010 - VSS_PG_1 */
+ [21011] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21011 - VSS_PG_0 */
+ [21012] = { 0x00FF, 0x00FF, 0x0000 }, /* R21012 - VSS_XTD1_1 */
+ [21013] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21013 - VSS_XTD1_0 */
+ [21014] = { 0x00FF, 0x00FF, 0x0000 }, /* R21014 - VSS_XTD2_1 */
+ [21015] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21015 - VSS_XTD2_0 */
+ [21016] = { 0x00FF, 0x00FF, 0x0000 }, /* R21016 - VSS_XTD3_1 */
+ [21017] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21017 - VSS_XTD3_0 */
+ [21018] = { 0x00FF, 0x00FF, 0x0000 }, /* R21018 - VSS_XTD4_1 */
+ [21019] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21019 - VSS_XTD4_0 */
+ [21020] = { 0x00FF, 0x00FF, 0x0000 }, /* R21020 - VSS_XTD5_1 */
+ [21021] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21021 - VSS_XTD5_0 */
+ [21022] = { 0x00FF, 0x00FF, 0x0000 }, /* R21022 - VSS_XTD6_1 */
+ [21023] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21023 - VSS_XTD6_0 */
+ [21024] = { 0x00FF, 0x00FF, 0x0000 }, /* R21024 - VSS_XTD7_1 */
+ [21025] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21025 - VSS_XTD7_0 */
+ [21026] = { 0x00FF, 0x00FF, 0x0000 }, /* R21026 - VSS_XTD8_1 */
+ [21027] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21027 - VSS_XTD8_0 */
+ [21028] = { 0x00FF, 0x00FF, 0x0000 }, /* R21028 - VSS_XTD9_1 */
+ [21029] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21029 - VSS_XTD9_0 */
+ [21030] = { 0x00FF, 0x00FF, 0x0000 }, /* R21030 - VSS_XTD10_1 */
+ [21031] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21031 - VSS_XTD10_0 */
+ [21032] = { 0x00FF, 0x00FF, 0x0000 }, /* R21032 - VSS_XTD11_1 */
+ [21033] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21033 - VSS_XTD11_0 */
+ [21034] = { 0x00FF, 0x00FF, 0x0000 }, /* R21034 - VSS_XTD12_1 */
+ [21035] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21035 - VSS_XTD12_0 */
+ [21036] = { 0x00FF, 0x00FF, 0x0000 }, /* R21036 - VSS_XTD13_1 */
+ [21037] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21037 - VSS_XTD13_0 */
+ [21038] = { 0x00FF, 0x00FF, 0x0000 }, /* R21038 - VSS_XTD14_1 */
+ [21039] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21039 - VSS_XTD14_0 */
+ [21040] = { 0x00FF, 0x00FF, 0x0000 }, /* R21040 - VSS_XTD15_1 */
+ [21041] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21041 - VSS_XTD15_0 */
+ [21042] = { 0x00FF, 0x00FF, 0x0000 }, /* R21042 - VSS_XTD16_1 */
+ [21043] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21043 - VSS_XTD16_0 */
+ [21044] = { 0x00FF, 0x00FF, 0x0000 }, /* R21044 - VSS_XTD17_1 */
+ [21045] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21045 - VSS_XTD17_0 */
+ [21046] = { 0x00FF, 0x00FF, 0x0000 }, /* R21046 - VSS_XTD18_1 */
+ [21047] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21047 - VSS_XTD18_0 */
+ [21048] = { 0x00FF, 0x00FF, 0x0000 }, /* R21048 - VSS_XTD19_1 */
+ [21049] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21049 - VSS_XTD19_0 */
+ [21050] = { 0x00FF, 0x00FF, 0x0000 }, /* R21050 - VSS_XTD20_1 */
+ [21051] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21051 - VSS_XTD20_0 */
+ [21052] = { 0x00FF, 0x00FF, 0x0000 }, /* R21052 - VSS_XTD21_1 */
+ [21053] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21053 - VSS_XTD21_0 */
+ [21054] = { 0x00FF, 0x00FF, 0x0000 }, /* R21054 - VSS_XTD22_1 */
+ [21055] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21055 - VSS_XTD22_0 */
+ [21056] = { 0x00FF, 0x00FF, 0x0000 }, /* R21056 - VSS_XTD23_1 */
+ [21057] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21057 - VSS_XTD23_0 */
+ [21058] = { 0x00FF, 0x00FF, 0x0000 }, /* R21058 - VSS_XTD24_1 */
+ [21059] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21059 - VSS_XTD24_0 */
+ [21060] = { 0x00FF, 0x00FF, 0x0000 }, /* R21060 - VSS_XTD25_1 */
+ [21061] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21061 - VSS_XTD25_0 */
+ [21062] = { 0x00FF, 0x00FF, 0x0000 }, /* R21062 - VSS_XTD26_1 */
+ [21063] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21063 - VSS_XTD26_0 */
+ [21064] = { 0x00FF, 0x00FF, 0x0000 }, /* R21064 - VSS_XTD27_1 */
+ [21065] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21065 - VSS_XTD27_0 */
+ [21066] = { 0x00FF, 0x00FF, 0x0000 }, /* R21066 - VSS_XTD28_1 */
+ [21067] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21067 - VSS_XTD28_0 */
+ [21068] = { 0x00FF, 0x00FF, 0x0000 }, /* R21068 - VSS_XTD29_1 */
+ [21069] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21069 - VSS_XTD29_0 */
+ [21070] = { 0x00FF, 0x00FF, 0x0000 }, /* R21070 - VSS_XTD30_1 */
+ [21071] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21071 - VSS_XTD30_0 */
+ [21072] = { 0x00FF, 0x00FF, 0x0000 }, /* R21072 - VSS_XTD31_1 */
+ [21073] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21073 - VSS_XTD31_0 */
+ [21074] = { 0x00FF, 0x00FF, 0x0000 }, /* R21074 - VSS_XTD32_1 */
+ [21075] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21075 - VSS_XTD32_0 */
+ [21076] = { 0x00FF, 0x00FF, 0x0000 }, /* R21076 - VSS_XTS1_1 */
+ [21077] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21077 - VSS_XTS1_0 */
+ [21078] = { 0x00FF, 0x00FF, 0x0000 }, /* R21078 - VSS_XTS2_1 */
+ [21079] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21079 - VSS_XTS2_0 */
+ [21080] = { 0x00FF, 0x00FF, 0x0000 }, /* R21080 - VSS_XTS3_1 */
+ [21081] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21081 - VSS_XTS3_0 */
+ [21082] = { 0x00FF, 0x00FF, 0x0000 }, /* R21082 - VSS_XTS4_1 */
+ [21083] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21083 - VSS_XTS4_0 */
+ [21084] = { 0x00FF, 0x00FF, 0x0000 }, /* R21084 - VSS_XTS5_1 */
+ [21085] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21085 - VSS_XTS5_0 */
+ [21086] = { 0x00FF, 0x00FF, 0x0000 }, /* R21086 - VSS_XTS6_1 */
+ [21087] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21087 - VSS_XTS6_0 */
+ [21088] = { 0x00FF, 0x00FF, 0x0000 }, /* R21088 - VSS_XTS7_1 */
+ [21089] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21089 - VSS_XTS7_0 */
+ [21090] = { 0x00FF, 0x00FF, 0x0000 }, /* R21090 - VSS_XTS8_1 */
+ [21091] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21091 - VSS_XTS8_0 */
+ [21092] = { 0x00FF, 0x00FF, 0x0000 }, /* R21092 - VSS_XTS9_1 */
+ [21093] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21093 - VSS_XTS9_0 */
+ [21094] = { 0x00FF, 0x00FF, 0x0000 }, /* R21094 - VSS_XTS10_1 */
+ [21095] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21095 - VSS_XTS10_0 */
+ [21096] = { 0x00FF, 0x00FF, 0x0000 }, /* R21096 - VSS_XTS11_1 */
+ [21097] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21097 - VSS_XTS11_0 */
+ [21098] = { 0x00FF, 0x00FF, 0x0000 }, /* R21098 - VSS_XTS12_1 */
+ [21099] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21099 - VSS_XTS12_0 */
+ [21100] = { 0x00FF, 0x00FF, 0x0000 }, /* R21100 - VSS_XTS13_1 */
+ [21101] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21101 - VSS_XTS13_0 */
+ [21102] = { 0x00FF, 0x00FF, 0x0000 }, /* R21102 - VSS_XTS14_1 */
+ [21103] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21103 - VSS_XTS14_0 */
+ [21104] = { 0x00FF, 0x00FF, 0x0000 }, /* R21104 - VSS_XTS15_1 */
+ [21105] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21105 - VSS_XTS15_0 */
+ [21106] = { 0x00FF, 0x00FF, 0x0000 }, /* R21106 - VSS_XTS16_1 */
+ [21107] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21107 - VSS_XTS16_0 */
+ [21108] = { 0x00FF, 0x00FF, 0x0000 }, /* R21108 - VSS_XTS17_1 */
+ [21109] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21109 - VSS_XTS17_0 */
+ [21110] = { 0x00FF, 0x00FF, 0x0000 }, /* R21110 - VSS_XTS18_1 */
+ [21111] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21111 - VSS_XTS18_0 */
+ [21112] = { 0x00FF, 0x00FF, 0x0000 }, /* R21112 - VSS_XTS19_1 */
+ [21113] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21113 - VSS_XTS19_0 */
+ [21114] = { 0x00FF, 0x00FF, 0x0000 }, /* R21114 - VSS_XTS20_1 */
+ [21115] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21115 - VSS_XTS20_0 */
+ [21116] = { 0x00FF, 0x00FF, 0x0000 }, /* R21116 - VSS_XTS21_1 */
+ [21117] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21117 - VSS_XTS21_0 */
+ [21118] = { 0x00FF, 0x00FF, 0x0000 }, /* R21118 - VSS_XTS22_1 */
+ [21119] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21119 - VSS_XTS22_0 */
+ [21120] = { 0x00FF, 0x00FF, 0x0000 }, /* R21120 - VSS_XTS23_1 */
+ [21121] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21121 - VSS_XTS23_0 */
+ [21122] = { 0x00FF, 0x00FF, 0x0000 }, /* R21122 - VSS_XTS24_1 */
+ [21123] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21123 - VSS_XTS24_0 */
+ [21124] = { 0x00FF, 0x00FF, 0x0000 }, /* R21124 - VSS_XTS25_1 */
+ [21125] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21125 - VSS_XTS25_0 */
+ [21126] = { 0x00FF, 0x00FF, 0x0000 }, /* R21126 - VSS_XTS26_1 */
+ [21127] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21127 - VSS_XTS26_0 */
+ [21128] = { 0x00FF, 0x00FF, 0x0000 }, /* R21128 - VSS_XTS27_1 */
+ [21129] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21129 - VSS_XTS27_0 */
+ [21130] = { 0x00FF, 0x00FF, 0x0000 }, /* R21130 - VSS_XTS28_1 */
+ [21131] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21131 - VSS_XTS28_0 */
+ [21132] = { 0x00FF, 0x00FF, 0x0000 }, /* R21132 - VSS_XTS29_1 */
+ [21133] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21133 - VSS_XTS29_0 */
+ [21134] = { 0x00FF, 0x00FF, 0x0000 }, /* R21134 - VSS_XTS30_1 */
+ [21135] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21135 - VSS_XTS30_0 */
+ [21136] = { 0x00FF, 0x00FF, 0x0000 }, /* R21136 - VSS_XTS31_1 */
+ [21137] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21137 - VSS_XTS31_0 */
+ [21138] = { 0x00FF, 0x00FF, 0x0000 }, /* R21138 - VSS_XTS32_1 */
+ [21139] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21139 - VSS_XTS32_0 */
+};
+
+static int wm8962_volatile_register(unsigned int reg)
+{
+ if (wm8962_reg_access[reg].vol)
+ return 1;
+ else
+ return 0;
+}
+
+static int wm8962_readable_register(unsigned int reg)
+{
+ if (wm8962_reg_access[reg].read)
+ return 1;
+ else
+ return 0;
+}
+
+static int wm8962_reset(struct snd_soc_codec *codec)
+{
+ return snd_soc_write(codec, WM8962_SOFTWARE_RESET, 0);
+}
+
+static const DECLARE_TLV_DB_SCALE(inpga_tlv, -2325, 75, 0);
+static const DECLARE_TLV_DB_SCALE(mixin_tlv, -1500, 300, 0);
+static const unsigned int mixinpga_tlv[] = {
+ TLV_DB_RANGE_HEAD(7),
+ 0, 1, TLV_DB_SCALE_ITEM(0, 600, 0),
+ 2, 2, TLV_DB_SCALE_ITEM(1300, 1300, 0),
+ 3, 4, TLV_DB_SCALE_ITEM(1800, 200, 0),
+ 5, 5, TLV_DB_SCALE_ITEM(2400, 0, 0),
+ 6, 7, TLV_DB_SCALE_ITEM(2700, 300, 0),
+};
+static const DECLARE_TLV_DB_SCALE(beep_tlv, -9600, 600, 1);
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(st_tlv, -3600, 300, 0);
+static const DECLARE_TLV_DB_SCALE(inmix_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+static const DECLARE_TLV_DB_SCALE(hp_tlv, -700, 100, 0);
+static const unsigned int classd_tlv[] = {
+ TLV_DB_RANGE_HEAD(7),
+ 0, 6, TLV_DB_SCALE_ITEM(0, 150, 0),
+ 7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0),
+};
+
+/* The VU bits for the headphones are in a different register to the mute
+ * bits and only take effect on the PGA if it is actually powered.
+ */
+static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ u16 *reg_cache = wm8962->reg_cache;
+ int ret;
+
+ /* Apply the update (if any) */
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
+ if (ret == 0)
+ return 0;
+
+ /* If the left PGA is enabled hit that VU bit... */
+ if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_HPOUTL_PGA_ENA)
+ return snd_soc_write(codec, WM8962_HPOUTL_VOLUME,
+ reg_cache[WM8962_HPOUTL_VOLUME]);
+
+ /* ...otherwise the right. The VU is stereo. */
+ if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_HPOUTR_PGA_ENA)
+ return snd_soc_write(codec, WM8962_HPOUTR_VOLUME,
+ reg_cache[WM8962_HPOUTR_VOLUME]);
+
+ return 0;
+}
+
+/* The VU bits for the speakers are in a different register to the mute
+ * bits and only take effect on the PGA if it is actually powered.
+ */
+static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ u16 *reg_cache = wm8962->reg_cache;
+ int ret;
+
+ /* Apply the update (if any) */
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
+ if (ret == 0)
+ return 0;
+
+ /* If the left PGA is enabled hit that VU bit... */
+ if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_SPKOUTL_PGA_ENA)
+ return snd_soc_write(codec, WM8962_SPKOUTL_VOLUME,
+ reg_cache[WM8962_SPKOUTL_VOLUME]);
+
+ /* ...otherwise the right. The VU is stereo. */
+ if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_SPKOUTR_PGA_ENA)
+ return snd_soc_write(codec, WM8962_SPKOUTR_VOLUME,
+ reg_cache[WM8962_SPKOUTR_VOLUME]);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new wm8962_snd_controls[] = {
+SOC_DOUBLE("Input Mixer Switch", WM8962_INPUT_MIXER_CONTROL_1, 3, 2, 1, 1),
+
+SOC_SINGLE_TLV("MIXINL IN2L Volume", WM8962_LEFT_INPUT_MIXER_VOLUME, 6, 7, 0,
+ mixin_tlv),
+SOC_SINGLE_TLV("MIXINL PGA Volume", WM8962_LEFT_INPUT_MIXER_VOLUME, 3, 7, 0,
+ mixinpga_tlv),
+SOC_SINGLE_TLV("MIXINL IN3L Volume", WM8962_LEFT_INPUT_MIXER_VOLUME, 0, 7, 0,
+ mixin_tlv),
+
+SOC_SINGLE_TLV("MIXINR IN2R Volume", WM8962_RIGHT_INPUT_MIXER_VOLUME, 6, 7, 0,
+ mixin_tlv),
+SOC_SINGLE_TLV("MIXINR PGA Volume", WM8962_RIGHT_INPUT_MIXER_VOLUME, 3, 7, 0,
+ mixinpga_tlv),
+SOC_SINGLE_TLV("MIXINR IN3R Volume", WM8962_RIGHT_INPUT_MIXER_VOLUME, 0, 7, 0,
+ mixin_tlv),
+
+SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8962_LEFT_ADC_VOLUME,
+ WM8962_RIGHT_ADC_VOLUME, 1, 127, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("Capture Volume", WM8962_LEFT_INPUT_VOLUME,
+ WM8962_RIGHT_INPUT_VOLUME, 0, 63, 0, inpga_tlv),
+SOC_DOUBLE_R("Capture Switch", WM8962_LEFT_INPUT_VOLUME,
+ WM8962_RIGHT_INPUT_VOLUME, 7, 1, 1),
+SOC_DOUBLE_R("Capture ZC Switch", WM8962_LEFT_INPUT_VOLUME,
+ WM8962_RIGHT_INPUT_VOLUME, 6, 1, 1),
+
+SOC_DOUBLE_R_TLV("Sidetone Volume", WM8962_DAC_DSP_MIXING_1,
+ WM8962_DAC_DSP_MIXING_2, 4, 12, 0, st_tlv),
+
+SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8962_LEFT_DAC_VOLUME,
+ WM8962_RIGHT_DAC_VOLUME, 1, 127, 0, digital_tlv),
+SOC_SINGLE("DAC High Performance Switch", WM8962_ADC_DAC_CONTROL_2, 0, 1, 0),
+
+SOC_SINGLE("ADC High Performance Switch", WM8962_ADDITIONAL_CONTROL_1,
+ 5, 1, 0),
+
+SOC_SINGLE_TLV("Beep Volume", WM8962_BEEP_GENERATOR_1, 4, 15, 0, beep_tlv),
+
+SOC_DOUBLE_R_TLV("Headphone Volume", WM8962_HPOUTL_VOLUME,
+ WM8962_HPOUTR_VOLUME, 0, 127, 0, out_tlv),
+SOC_DOUBLE_EXT("Headphone Switch", WM8962_PWR_MGMT_2, 1, 0, 1, 1,
+ snd_soc_get_volsw, wm8962_put_hp_sw),
+SOC_DOUBLE_R("Headphone ZC Switch", WM8962_HPOUTL_VOLUME, WM8962_HPOUTR_VOLUME,
+ 7, 1, 0),
+SOC_DOUBLE_TLV("Headphone Aux Volume", WM8962_ANALOGUE_HP_2, 3, 6, 7, 0,
+ hp_tlv),
+
+SOC_DOUBLE_R("Headphone Mixer Switch", WM8962_HEADPHONE_MIXER_3,
+ WM8962_HEADPHONE_MIXER_4, 8, 1, 1),
+
+SOC_SINGLE_TLV("HPMIXL IN4L Volume", WM8962_HEADPHONE_MIXER_3,
+ 3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("HPMIXL IN4R Volume", WM8962_HEADPHONE_MIXER_3,
+ 0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("HPMIXL MIXINL Volume", WM8962_HEADPHONE_MIXER_3,
+ 7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("HPMIXL MIXINR Volume", WM8962_HEADPHONE_MIXER_3,
+ 6, 1, 1, inmix_tlv),
+
+SOC_SINGLE_TLV("HPMIXR IN4L Volume", WM8962_HEADPHONE_MIXER_4,
+ 3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("HPMIXR IN4R Volume", WM8962_HEADPHONE_MIXER_4,
+ 0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("HPMIXR MIXINL Volume", WM8962_HEADPHONE_MIXER_4,
+ 7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("HPMIXR MIXINR Volume", WM8962_HEADPHONE_MIXER_4,
+ 6, 1, 1, inmix_tlv),
+
+SOC_SINGLE_TLV("Speaker Boost Volume", WM8962_CLASS_D_CONTROL_2, 0, 7, 0,
+ classd_tlv),
+};
+
+static const struct snd_kcontrol_new wm8962_spk_mono_controls[] = {
+SOC_SINGLE_TLV("Speaker Volume", WM8962_SPKOUTL_VOLUME, 0, 127, 0, out_tlv),
+SOC_SINGLE_EXT("Speaker Switch", WM8962_CLASS_D_CONTROL_1, 1, 1, 1,
+ snd_soc_get_volsw, wm8962_put_spk_sw),
+SOC_SINGLE("Speaker ZC Switch", WM8962_SPKOUTL_VOLUME, 7, 1, 0),
+
+SOC_SINGLE("Speaker Mixer Switch", WM8962_SPEAKER_MIXER_3, 8, 1, 1),
+SOC_SINGLE_TLV("Speaker Mixer IN4L Volume", WM8962_SPEAKER_MIXER_3,
+ 3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("Speaker Mixer IN4R Volume", WM8962_SPEAKER_MIXER_3,
+ 0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("Speaker Mixer MIXINL Volume", WM8962_SPEAKER_MIXER_3,
+ 7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("Speaker Mixer MIXINR Volume", WM8962_SPEAKER_MIXER_3,
+ 6, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("Speaker Mixer DACL Volume", WM8962_SPEAKER_MIXER_5,
+ 7, 1, 0, inmix_tlv),
+SOC_SINGLE_TLV("Speaker Mixer DACR Volume", WM8962_SPEAKER_MIXER_5,
+ 6, 1, 0, inmix_tlv),
+};
+
+static const struct snd_kcontrol_new wm8962_spk_stereo_controls[] = {
+SOC_DOUBLE_R_TLV("Speaker Volume", WM8962_SPKOUTL_VOLUME,
+ WM8962_SPKOUTR_VOLUME, 0, 127, 0, out_tlv),
+SOC_DOUBLE_EXT("Speaker Switch", WM8962_CLASS_D_CONTROL_1, 1, 0, 1, 1,
+ snd_soc_get_volsw, wm8962_put_spk_sw),
+SOC_DOUBLE_R("Speaker ZC Switch", WM8962_SPKOUTL_VOLUME, WM8962_SPKOUTR_VOLUME,
+ 7, 1, 0),
+
+SOC_DOUBLE_R("Speaker Mixer Switch", WM8962_SPEAKER_MIXER_3,
+ WM8962_SPEAKER_MIXER_4, 8, 1, 1),
+
+SOC_SINGLE_TLV("SPKOUTL Mixer IN4L Volume", WM8962_SPEAKER_MIXER_3,
+ 3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer IN4R Volume", WM8962_SPEAKER_MIXER_3,
+ 0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer MIXINL Volume", WM8962_SPEAKER_MIXER_3,
+ 7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer MIXINR Volume", WM8962_SPEAKER_MIXER_3,
+ 6, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer DACL Volume", WM8962_SPEAKER_MIXER_5,
+ 7, 1, 0, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer DACR Volume", WM8962_SPEAKER_MIXER_5,
+ 6, 1, 0, inmix_tlv),
+
+SOC_SINGLE_TLV("SPKOUTR Mixer IN4L Volume", WM8962_SPEAKER_MIXER_4,
+ 3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer IN4R Volume", WM8962_SPEAKER_MIXER_4,
+ 0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer MIXINL Volume", WM8962_SPEAKER_MIXER_4,
+ 7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer MIXINR Volume", WM8962_SPEAKER_MIXER_4,
+ 6, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer DACL Volume", WM8962_SPEAKER_MIXER_5,
+ 5, 1, 0, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer DACR Volume", WM8962_SPEAKER_MIXER_5,
+ 4, 1, 0, inmix_tlv),
+};
+
+static int sysclk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ int src;
+ int fll;
+
+ src = snd_soc_read(codec, WM8962_CLOCKING2) & WM8962_SYSCLK_SRC_MASK;
+
+ switch (src) {
+ case 0: /* MCLK */
+ fll = 0;
+ break;
+ case 0x200: /* FLL */
+ fll = 1;
+ break;
+ default:
+ dev_err(codec->dev, "Unknown SYSCLK source %x\n", src);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (fll)
+ snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+ WM8962_FLL_ENA, WM8962_FLL_ENA);
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ if (fll)
+ snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+ WM8962_FLL_ENA, 0);
+ break;
+
+ default:
+ BUG();
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ msleep(5);
+ break;
+
+ default:
+ BUG();
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int hp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ int timeout;
+ int reg;
+ int expected = (WM8962_DCS_STARTUP_DONE_HP1L |
+ WM8962_DCS_STARTUP_DONE_HP1R);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+ WM8962_HP1L_ENA | WM8962_HP1R_ENA,
+ WM8962_HP1L_ENA | WM8962_HP1R_ENA);
+ udelay(20);
+
+ snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+ WM8962_HP1L_ENA_DLY | WM8962_HP1R_ENA_DLY,
+ WM8962_HP1L_ENA_DLY | WM8962_HP1R_ENA_DLY);
+
+ /* Start the DC servo */
+ snd_soc_update_bits(codec, WM8962_DC_SERVO_1,
+ WM8962_HP1L_DCS_ENA | WM8962_HP1R_DCS_ENA |
+ WM8962_HP1L_DCS_STARTUP |
+ WM8962_HP1R_DCS_STARTUP,
+ WM8962_HP1L_DCS_ENA | WM8962_HP1R_DCS_ENA |
+ WM8962_HP1L_DCS_STARTUP |
+ WM8962_HP1R_DCS_STARTUP);
+
+ /* Wait for it to complete, should be well under 100ms */
+ timeout = 0;
+ do {
+ msleep(1);
+ reg = snd_soc_read(codec, WM8962_DC_SERVO_6);
+ if (reg < 0) {
+ dev_err(codec->dev,
+ "Failed to read DCS status: %d\n",
+ reg);
+ continue;
+ }
+ dev_dbg(codec->dev, "DCS status: %x\n", reg);
+ } while (++timeout < 200 && (reg & expected) != expected);
+
+ if ((reg & expected) != expected)
+ dev_err(codec->dev, "DC servo timed out\n");
+ else
+ dev_dbg(codec->dev, "DC servo complete after %dms\n",
+ timeout);
+
+ snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+ WM8962_HP1L_ENA_OUTP |
+ WM8962_HP1R_ENA_OUTP,
+ WM8962_HP1L_ENA_OUTP |
+ WM8962_HP1R_ENA_OUTP);
+ udelay(20);
+
+ snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+ WM8962_HP1L_RMV_SHORT |
+ WM8962_HP1R_RMV_SHORT,
+ WM8962_HP1L_RMV_SHORT |
+ WM8962_HP1R_RMV_SHORT);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+ WM8962_HP1L_RMV_SHORT |
+ WM8962_HP1R_RMV_SHORT, 0);
+
+ udelay(20);
+
+ snd_soc_update_bits(codec, WM8962_DC_SERVO_1,
+ WM8962_HP1L_DCS_ENA | WM8962_HP1R_DCS_ENA |
+ WM8962_HP1L_DCS_STARTUP |
+ WM8962_HP1R_DCS_STARTUP,
+ 0);
+
+ snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+ WM8962_HP1L_ENA | WM8962_HP1R_ENA |
+ WM8962_HP1L_ENA_DLY | WM8962_HP1R_ENA_DLY |
+ WM8962_HP1L_ENA_OUTP |
+ WM8962_HP1R_ENA_OUTP, 0);
+
+ break;
+
+ default:
+ BUG();
+ return -EINVAL;
+
+ }
+
+ return 0;
+}
+
+/* VU bits for the output PGAs only take effect while the PGA is powered */
+static int out_pga_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ u16 *reg_cache = wm8962->reg_cache;
+ int reg;
+
+ switch (w->shift) {
+ case WM8962_HPOUTR_PGA_ENA_SHIFT:
+ reg = WM8962_HPOUTR_VOLUME;
+ break;
+ case WM8962_HPOUTL_PGA_ENA_SHIFT:
+ reg = WM8962_HPOUTL_VOLUME;
+ break;
+ case WM8962_SPKOUTR_PGA_ENA_SHIFT:
+ reg = WM8962_SPKOUTR_VOLUME;
+ break;
+ case WM8962_SPKOUTL_PGA_ENA_SHIFT:
+ reg = WM8962_SPKOUTL_VOLUME;
+ break;
+ default:
+ BUG();
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ return snd_soc_write(codec, reg, reg_cache[reg]);
+ default:
+ BUG();
+ return -EINVAL;
+ }
+}
+
+static const char *st_text[] = { "None", "Right", "Left" };
+
+static const struct soc_enum str_enum =
+ SOC_ENUM_SINGLE(WM8962_DAC_DSP_MIXING_1, 2, 3, st_text);
+
+static const struct snd_kcontrol_new str_mux =
+ SOC_DAPM_ENUM("Right Sidetone", str_enum);
+
+static const struct soc_enum stl_enum =
+ SOC_ENUM_SINGLE(WM8962_DAC_DSP_MIXING_2, 2, 3, st_text);
+
+static const struct snd_kcontrol_new stl_mux =
+ SOC_DAPM_ENUM("Left Sidetone", stl_enum);
+
+static const char *outmux_text[] = { "DAC", "Mixer" };
+
+static const struct soc_enum spkoutr_enum =
+ SOC_ENUM_SINGLE(WM8962_SPEAKER_MIXER_2, 7, 2, outmux_text);
+
+static const struct snd_kcontrol_new spkoutr_mux =
+ SOC_DAPM_ENUM("SPKOUTR Mux", spkoutr_enum);
+
+static const struct soc_enum spkoutl_enum =
+ SOC_ENUM_SINGLE(WM8962_SPEAKER_MIXER_1, 7, 2, outmux_text);
+
+static const struct snd_kcontrol_new spkoutl_mux =
+ SOC_DAPM_ENUM("SPKOUTL Mux", spkoutl_enum);
+
+static const struct soc_enum hpoutr_enum =
+ SOC_ENUM_SINGLE(WM8962_HEADPHONE_MIXER_2, 7, 2, outmux_text);
+
+static const struct snd_kcontrol_new hpoutr_mux =
+ SOC_DAPM_ENUM("HPOUTR Mux", hpoutr_enum);
+
+static const struct soc_enum hpoutl_enum =
+ SOC_ENUM_SINGLE(WM8962_HEADPHONE_MIXER_1, 7, 2, outmux_text);
+
+static const struct snd_kcontrol_new hpoutl_mux =
+ SOC_DAPM_ENUM("HPOUTL Mux", hpoutl_enum);
+
+static const struct snd_kcontrol_new inpgal[] = {
+SOC_DAPM_SINGLE("IN1L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 3, 1, 0),
+SOC_DAPM_SINGLE("IN2L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 2, 1, 0),
+SOC_DAPM_SINGLE("IN3L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new inpgar[] = {
+SOC_DAPM_SINGLE("IN1R Switch", WM8962_RIGHT_INPUT_PGA_CONTROL, 3, 1, 0),
+SOC_DAPM_SINGLE("IN2R Switch", WM8962_RIGHT_INPUT_PGA_CONTROL, 2, 1, 0),
+SOC_DAPM_SINGLE("IN3R Switch", WM8962_RIGHT_INPUT_PGA_CONTROL, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_RIGHT_INPUT_PGA_CONTROL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new mixinl[] = {
+SOC_DAPM_SINGLE("IN2L Switch", WM8962_INPUT_MIXER_CONTROL_2, 5, 1, 0),
+SOC_DAPM_SINGLE("IN3L Switch", WM8962_INPUT_MIXER_CONTROL_2, 4, 1, 0),
+SOC_DAPM_SINGLE("PGA Switch", WM8962_INPUT_MIXER_CONTROL_2, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new mixinr[] = {
+SOC_DAPM_SINGLE("IN2R Switch", WM8962_INPUT_MIXER_CONTROL_2, 2, 1, 0),
+SOC_DAPM_SINGLE("IN3R Switch", WM8962_INPUT_MIXER_CONTROL_2, 1, 1, 0),
+SOC_DAPM_SINGLE("PGA Switch", WM8962_INPUT_MIXER_CONTROL_2, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new hpmixl[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8962_HEADPHONE_MIXER_1, 5, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8962_HEADPHONE_MIXER_1, 4, 1, 0),
+SOC_DAPM_SINGLE("MIXINL Switch", WM8962_HEADPHONE_MIXER_1, 3, 1, 0),
+SOC_DAPM_SINGLE("MIXINR Switch", WM8962_HEADPHONE_MIXER_1, 2, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_HEADPHONE_MIXER_1, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_HEADPHONE_MIXER_1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new hpmixr[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8962_HEADPHONE_MIXER_2, 5, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8962_HEADPHONE_MIXER_2, 4, 1, 0),
+SOC_DAPM_SINGLE("MIXINL Switch", WM8962_HEADPHONE_MIXER_2, 3, 1, 0),
+SOC_DAPM_SINGLE("MIXINR Switch", WM8962_HEADPHONE_MIXER_2, 2, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_HEADPHONE_MIXER_2, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_HEADPHONE_MIXER_2, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new spkmixl[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8962_SPEAKER_MIXER_1, 5, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8962_SPEAKER_MIXER_1, 4, 1, 0),
+SOC_DAPM_SINGLE("MIXINL Switch", WM8962_SPEAKER_MIXER_1, 3, 1, 0),
+SOC_DAPM_SINGLE("MIXINR Switch", WM8962_SPEAKER_MIXER_1, 2, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_SPEAKER_MIXER_1, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_SPEAKER_MIXER_1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new spkmixr[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8962_SPEAKER_MIXER_2, 5, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8962_SPEAKER_MIXER_2, 4, 1, 0),
+SOC_DAPM_SINGLE("MIXINL Switch", WM8962_SPEAKER_MIXER_2, 3, 1, 0),
+SOC_DAPM_SINGLE("MIXINR Switch", WM8962_SPEAKER_MIXER_2, 2, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_SPEAKER_MIXER_2, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_SPEAKER_MIXER_2, 0, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8962_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+SND_SOC_DAPM_INPUT("IN3L"),
+SND_SOC_DAPM_INPUT("IN3R"),
+SND_SOC_DAPM_INPUT("IN4L"),
+SND_SOC_DAPM_INPUT("IN4R"),
+SND_SOC_DAPM_INPUT("Beep"),
+
+SND_SOC_DAPM_MICBIAS("MICBIAS", WM8962_PWR_MGMT_1, 1, 0),
+
+SND_SOC_DAPM_SUPPLY("Class G", WM8962_CHARGE_PUMP_B, 0, 1, NULL, 0),
+SND_SOC_DAPM_SUPPLY("SYSCLK", WM8962_CLOCKING2, 5, 0, sysclk_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("Charge Pump", WM8962_CHARGE_PUMP_1, 0, 0, cp_event,
+ SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_SUPPLY("TOCLK", WM8962_ADDITIONAL_CONTROL_1, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("INPGAL", WM8962_LEFT_INPUT_PGA_CONTROL, 4, 0,
+ inpgal, ARRAY_SIZE(inpgal)),
+SND_SOC_DAPM_MIXER("INPGAR", WM8962_RIGHT_INPUT_PGA_CONTROL, 4, 0,
+ inpgar, ARRAY_SIZE(inpgar)),
+SND_SOC_DAPM_MIXER("MIXINL", WM8962_PWR_MGMT_1, 5, 0,
+ mixinl, ARRAY_SIZE(mixinl)),
+SND_SOC_DAPM_MIXER("MIXINR", WM8962_PWR_MGMT_1, 4, 0,
+ mixinr, ARRAY_SIZE(mixinr)),
+
+SND_SOC_DAPM_ADC("ADCL", "Capture", WM8962_PWR_MGMT_1, 3, 0),
+SND_SOC_DAPM_ADC("ADCR", "Capture", WM8962_PWR_MGMT_1, 2, 0),
+
+SND_SOC_DAPM_MUX("STL", SND_SOC_NOPM, 0, 0, &stl_mux),
+SND_SOC_DAPM_MUX("STR", SND_SOC_NOPM, 0, 0, &str_mux),
+
+SND_SOC_DAPM_DAC("DACL", "Playback", WM8962_PWR_MGMT_2, 8, 0),
+SND_SOC_DAPM_DAC("DACR", "Playback", WM8962_PWR_MGMT_2, 7, 0),
+
+SND_SOC_DAPM_PGA("Left Bypass", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Bypass", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("HPMIXL", WM8962_MIXER_ENABLES, 3, 0,
+ hpmixl, ARRAY_SIZE(hpmixl)),
+SND_SOC_DAPM_MIXER("HPMIXR", WM8962_MIXER_ENABLES, 2, 0,
+ hpmixr, ARRAY_SIZE(hpmixr)),
+
+SND_SOC_DAPM_MUX_E("HPOUTL PGA", WM8962_PWR_MGMT_2, 6, 0, &hpoutl_mux,
+ out_pga_event, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_MUX_E("HPOUTR PGA", WM8962_PWR_MGMT_2, 5, 0, &hpoutr_mux,
+ out_pga_event, SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_PGA_E("HPOUT", SND_SOC_NOPM, 0, 0, NULL, 0, hp_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_OUTPUT("HPOUTL"),
+SND_SOC_DAPM_OUTPUT("HPOUTR"),
+};
+
+static const struct snd_soc_dapm_widget wm8962_dapm_spk_mono_widgets[] = {
+SND_SOC_DAPM_MIXER("Speaker Mixer", WM8962_MIXER_ENABLES, 1, 0,
+ spkmixl, ARRAY_SIZE(spkmixl)),
+SND_SOC_DAPM_MUX_E("Speaker PGA", WM8962_PWR_MGMT_2, 4, 0, &spkoutl_mux,
+ out_pga_event, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA("Speaker Output", WM8962_CLASS_D_CONTROL_1, 7, 0, NULL, 0),
+SND_SOC_DAPM_OUTPUT("SPKOUT"),
+};
+
+static const struct snd_soc_dapm_widget wm8962_dapm_spk_stereo_widgets[] = {
+SND_SOC_DAPM_MIXER("SPKOUTL Mixer", WM8962_MIXER_ENABLES, 1, 0,
+ spkmixl, ARRAY_SIZE(spkmixl)),
+SND_SOC_DAPM_MIXER("SPKOUTR Mixer", WM8962_MIXER_ENABLES, 0, 0,
+ spkmixr, ARRAY_SIZE(spkmixr)),
+
+SND_SOC_DAPM_MUX_E("SPKOUTL PGA", WM8962_PWR_MGMT_2, 4, 0, &spkoutl_mux,
+ out_pga_event, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_MUX_E("SPKOUTR PGA", WM8962_PWR_MGMT_2, 3, 0, &spkoutr_mux,
+ out_pga_event, SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_PGA("SPKOUTR Output", WM8962_CLASS_D_CONTROL_1, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA("SPKOUTL Output", WM8962_CLASS_D_CONTROL_1, 6, 0, NULL, 0),
+
+SND_SOC_DAPM_OUTPUT("SPKOUTL"),
+SND_SOC_DAPM_OUTPUT("SPKOUTR"),
+};
+
+static const struct snd_soc_dapm_route wm8962_intercon[] = {
+ { "INPGAL", "IN1L Switch", "IN1L" },
+ { "INPGAL", "IN2L Switch", "IN2L" },
+ { "INPGAL", "IN3L Switch", "IN3L" },
+ { "INPGAL", "IN4L Switch", "IN4L" },
+
+ { "INPGAR", "IN1R Switch", "IN1R" },
+ { "INPGAR", "IN2R Switch", "IN2R" },
+ { "INPGAR", "IN3R Switch", "IN3R" },
+ { "INPGAR", "IN4R Switch", "IN4R" },
+
+ { "MIXINL", "IN2L Switch", "IN2L" },
+ { "MIXINL", "IN3L Switch", "IN3L" },
+ { "MIXINL", "PGA Switch", "INPGAL" },
+
+ { "MIXINR", "IN2R Switch", "IN2R" },
+ { "MIXINR", "IN3R Switch", "IN3R" },
+ { "MIXINR", "PGA Switch", "INPGAR" },
+
+ { "MICBIAS", NULL, "SYSCLK" },
+
+ { "ADCL", NULL, "SYSCLK" },
+ { "ADCL", NULL, "TOCLK" },
+ { "ADCL", NULL, "MIXINL" },
+
+ { "ADCR", NULL, "SYSCLK" },
+ { "ADCR", NULL, "TOCLK" },
+ { "ADCR", NULL, "MIXINR" },
+
+ { "STL", "Left", "ADCL" },
+ { "STL", "Right", "ADCR" },
+
+ { "STR", "Left", "ADCL" },
+ { "STR", "Right", "ADCR" },
+
+ { "DACL", NULL, "SYSCLK" },
+ { "DACL", NULL, "TOCLK" },
+ { "DACL", NULL, "Beep" },
+ { "DACL", NULL, "STL" },
+
+ { "DACR", NULL, "SYSCLK" },
+ { "DACR", NULL, "TOCLK" },
+ { "DACR", NULL, "Beep" },
+ { "DACR", NULL, "STR" },
+
+ { "HPMIXL", "IN4L Switch", "IN4L" },
+ { "HPMIXL", "IN4R Switch", "IN4R" },
+ { "HPMIXL", "DACL Switch", "DACL" },
+ { "HPMIXL", "DACR Switch", "DACR" },
+ { "HPMIXL", "MIXINL Switch", "MIXINL" },
+ { "HPMIXL", "MIXINR Switch", "MIXINR" },
+
+ { "HPMIXR", "IN4L Switch", "IN4L" },
+ { "HPMIXR", "IN4R Switch", "IN4R" },
+ { "HPMIXR", "DACL Switch", "DACL" },
+ { "HPMIXR", "DACR Switch", "DACR" },
+ { "HPMIXR", "MIXINL Switch", "MIXINL" },
+ { "HPMIXR", "MIXINR Switch", "MIXINR" },
+
+ { "Left Bypass", NULL, "HPMIXL" },
+ { "Left Bypass", NULL, "Class G" },
+
+ { "Right Bypass", NULL, "HPMIXR" },
+ { "Right Bypass", NULL, "Class G" },
+
+ { "HPOUTL PGA", "Mixer", "Left Bypass" },
+ { "HPOUTL PGA", "DAC", "DACL" },
+
+ { "HPOUTR PGA", "Mixer", "Right Bypass" },
+ { "HPOUTR PGA", "DAC", "DACR" },
+
+ { "HPOUT", NULL, "HPOUTL PGA" },
+ { "HPOUT", NULL, "HPOUTR PGA" },
+ { "HPOUT", NULL, "Charge Pump" },
+ { "HPOUT", NULL, "SYSCLK" },
+ { "HPOUT", NULL, "TOCLK" },
+
+ { "HPOUTL", NULL, "HPOUT" },
+ { "HPOUTR", NULL, "HPOUT" },
+};
+
+static const struct snd_soc_dapm_route wm8962_spk_mono_intercon[] = {
+ { "Speaker Mixer", "IN4L Switch", "IN4L" },
+ { "Speaker Mixer", "IN4R Switch", "IN4R" },
+ { "Speaker Mixer", "DACL Switch", "DACL" },
+ { "Speaker Mixer", "DACR Switch", "DACR" },
+ { "Speaker Mixer", "MIXINL Switch", "MIXINL" },
+ { "Speaker Mixer", "MIXINR Switch", "MIXINR" },
+
+ { "Speaker PGA", "Mixer", "Speaker Mixer" },
+ { "Speaker PGA", "DAC", "DACL" },
+
+ { "Speaker Output", NULL, "Speaker PGA" },
+ { "Speaker Output", NULL, "SYSCLK" },
+ { "Speaker Output", NULL, "TOCLK" },
+
+ { "SPKOUT", NULL, "Speaker Output" },
+};
+
+static const struct snd_soc_dapm_route wm8962_spk_stereo_intercon[] = {
+ { "SPKOUTL Mixer", "IN4L Switch", "IN4L" },
+ { "SPKOUTL Mixer", "IN4R Switch", "IN4R" },
+ { "SPKOUTL Mixer", "DACL Switch", "DACL" },
+ { "SPKOUTL Mixer", "DACR Switch", "DACR" },
+ { "SPKOUTL Mixer", "MIXINL Switch", "MIXINL" },
+ { "SPKOUTL Mixer", "MIXINR Switch", "MIXINR" },
+
+ { "SPKOUTR Mixer", "IN4L Switch", "IN4L" },
+ { "SPKOUTR Mixer", "IN4R Switch", "IN4R" },
+ { "SPKOUTR Mixer", "DACL Switch", "DACL" },
+ { "SPKOUTR Mixer", "DACR Switch", "DACR" },
+ { "SPKOUTR Mixer", "MIXINL Switch", "MIXINL" },
+ { "SPKOUTR Mixer", "MIXINR Switch", "MIXINR" },
+
+ { "SPKOUTL PGA", "Mixer", "SPKOUTL Mixer" },
+ { "SPKOUTL PGA", "DAC", "DACL" },
+
+ { "SPKOUTR PGA", "Mixer", "SPKOUTR Mixer" },
+ { "SPKOUTR PGA", "DAC", "DACR" },
+
+ { "SPKOUTL Output", NULL, "SPKOUTL PGA" },
+ { "SPKOUTL Output", NULL, "SYSCLK" },
+ { "SPKOUTL Output", NULL, "TOCLK" },
+
+ { "SPKOUTR Output", NULL, "SPKOUTR PGA" },
+ { "SPKOUTR Output", NULL, "SYSCLK" },
+ { "SPKOUTR Output", NULL, "TOCLK" },
+
+ { "SPKOUTL", NULL, "SPKOUTL Output" },
+ { "SPKOUTR", NULL, "SPKOUTR Output" },
+};
+
+static int wm8962_add_widgets(struct snd_soc_codec *codec)
+{
+ struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
+
+ snd_soc_add_controls(codec, wm8962_snd_controls,
+ ARRAY_SIZE(wm8962_snd_controls));
+ if (pdata && pdata->spk_mono)
+ snd_soc_add_controls(codec, wm8962_spk_mono_controls,
+ ARRAY_SIZE(wm8962_spk_mono_controls));
+ else
+ snd_soc_add_controls(codec, wm8962_spk_stereo_controls,
+ ARRAY_SIZE(wm8962_spk_stereo_controls));
+
+
+ snd_soc_dapm_new_controls(codec, wm8962_dapm_widgets,
+ ARRAY_SIZE(wm8962_dapm_widgets));
+ if (pdata && pdata->spk_mono)
+ snd_soc_dapm_new_controls(codec, wm8962_dapm_spk_mono_widgets,
+ ARRAY_SIZE(wm8962_dapm_spk_mono_widgets));
+ else
+ snd_soc_dapm_new_controls(codec, wm8962_dapm_spk_stereo_widgets,
+ ARRAY_SIZE(wm8962_dapm_spk_stereo_widgets));
+
+ snd_soc_dapm_add_routes(codec, wm8962_intercon,
+ ARRAY_SIZE(wm8962_intercon));
+ if (pdata && pdata->spk_mono)
+ snd_soc_dapm_add_routes(codec, wm8962_spk_mono_intercon,
+ ARRAY_SIZE(wm8962_spk_mono_intercon));
+ else
+ snd_soc_dapm_add_routes(codec, wm8962_spk_stereo_intercon,
+ ARRAY_SIZE(wm8962_spk_stereo_intercon));
+
+
+ snd_soc_dapm_disable_pin(codec, "Beep");
+
+ return 0;
+}
+
+static void wm8962_sync_cache(struct snd_soc_codec *codec)
+{
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ int i;
+
+ if (!codec->cache_sync)
+ return;
+
+ dev_dbg(codec->dev, "Syncing cache\n");
+
+ codec->cache_only = 0;
+
+ /* Sync back cached values if they're different from the
+ * hardware default.
+ */
+ for (i = 1; i < ARRAY_SIZE(wm8962->reg_cache); i++) {
+ if (i == WM8962_SOFTWARE_RESET)
+ continue;
+ if (wm8962->reg_cache[i] == wm8962_reg[i])
+ continue;
+
+ snd_soc_write(codec, i, wm8962->reg_cache[i]);
+ }
+
+ codec->cache_sync = 0;
+}
+
+/* -1 for reserved values */
+static const int bclk_divs[] = {
+ 1, -1, 2, 3, 4, -1, 6, 8, -1, 12, 16, 24, -1, 32, 32, 32
+};
+
+static void wm8962_configure_bclk(struct snd_soc_codec *codec)
+{
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ int dspclk, i;
+ int clocking2 = 0;
+ int aif2 = 0;
+
+ if (!wm8962->bclk) {
+ dev_dbg(codec->dev, "No BCLK rate configured\n");
+ return;
+ }
+
+ dspclk = snd_soc_read(codec, WM8962_CLOCKING1);
+ if (dspclk < 0) {
+ dev_err(codec->dev, "Failed to read DSPCLK: %d\n", dspclk);
+ return;
+ }
+
+ dspclk = (dspclk & WM8962_DSPCLK_DIV_MASK) >> WM8962_DSPCLK_DIV_SHIFT;
+ switch (dspclk) {
+ case 0:
+ dspclk = wm8962->sysclk_rate;
+ break;
+ case 1:
+ dspclk = wm8962->sysclk_rate / 2;
+ break;
+ case 2:
+ dspclk = wm8962->sysclk_rate / 4;
+ break;
+ default:
+ dev_warn(codec->dev, "Unknown DSPCLK divisor read back\n");
+ dspclk = wm8962->sysclk;
+ }
+
+ dev_dbg(codec->dev, "DSPCLK is %dHz, BCLK %d\n", dspclk, wm8962->bclk);
+
+ /* We're expecting an exact match */
+ for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+ if (bclk_divs[i] < 0)
+ continue;
+
+ if (dspclk / bclk_divs[i] == wm8962->bclk) {
+ dev_dbg(codec->dev, "Selected BCLK_DIV %d for %dHz\n",
+ bclk_divs[i], wm8962->bclk);
+ clocking2 |= i;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(bclk_divs)) {
+ dev_err(codec->dev, "Unsupported BCLK ratio %d\n",
+ dspclk / wm8962->bclk);
+ return;
+ }
+
+ aif2 |= wm8962->bclk / wm8962->lrclk;
+ dev_dbg(codec->dev, "Selected LRCLK divisor %d for %dHz\n",
+ wm8962->bclk / wm8962->lrclk, wm8962->lrclk);
+
+ snd_soc_update_bits(codec, WM8962_CLOCKING2,
+ WM8962_BCLK_DIV_MASK, clocking2);
+ snd_soc_update_bits(codec, WM8962_AUDIO_INTERFACE_2,
+ WM8962_AIF_RATE_MASK, aif2);
+}
+
+static int wm8962_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ if (level == codec->bias_level)
+ return 0;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+
+ case SND_SOC_BIAS_PREPARE:
+ /* VMID 2*50k */
+ snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
+ WM8962_VMID_SEL_MASK, 0x80);
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->bias_level == SND_SOC_BIAS_OFF) {
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8962->supplies),
+ wm8962->supplies);
+ if (ret != 0) {
+ dev_err(codec->dev,
+ "Failed to enable supplies: %d\n",
+ ret);
+ return ret;
+ }
+
+ wm8962_sync_cache(codec);
+
+ snd_soc_update_bits(codec, WM8962_ANTI_POP,
+ WM8962_STARTUP_BIAS_ENA |
+ WM8962_VMID_BUF_ENA,
+ WM8962_STARTUP_BIAS_ENA |
+ WM8962_VMID_BUF_ENA);
+
+ /* Bias enable at 2*50k for ramp */
+ snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
+ WM8962_VMID_SEL_MASK |
+ WM8962_BIAS_ENA,
+ WM8962_BIAS_ENA | 0x180);
+
+ msleep(5);
+
+ snd_soc_update_bits(codec, WM8962_CLOCKING2,
+ WM8962_CLKREG_OVD,
+ WM8962_CLKREG_OVD);
+
+ wm8962_configure_bclk(codec);
+ }
+
+ /* VMID 2*250k */
+ snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
+ WM8962_VMID_SEL_MASK, 0x100);
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
+ WM8962_VMID_SEL_MASK | WM8962_BIAS_ENA, 0);
+
+ snd_soc_update_bits(codec, WM8962_ANTI_POP,
+ WM8962_STARTUP_BIAS_ENA |
+ WM8962_VMID_BUF_ENA, 0);
+
+ regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies),
+ wm8962->supplies);
+ break;
+ }
+ codec->bias_level = level;
+ return 0;
+}
+
+static const struct {
+ int rate;
+ int reg;
+} sr_vals[] = {
+ { 48000, 0 },
+ { 44100, 0 },
+ { 32000, 1 },
+ { 22050, 2 },
+ { 24000, 2 },
+ { 16000, 3 },
+ { 11025, 4 },
+ { 12000, 4 },
+ { 8000, 5 },
+ { 88200, 6 },
+ { 96000, 6 },
+};
+
+static const int sysclk_rates[] = {
+ 64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536,
+};
+
+static int wm8962_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ int rate = params_rate(params);
+ int i;
+ int aif0 = 0;
+ int adctl3 = 0;
+ int clocking4 = 0;
+
+ wm8962->bclk = snd_soc_params_to_bclk(params);
+ wm8962->lrclk = params_rate(params);
+
+ for (i = 0; i < ARRAY_SIZE(sr_vals); i++) {
+ if (sr_vals[i].rate == rate) {
+ adctl3 |= sr_vals[i].reg;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(sr_vals)) {
+ dev_err(codec->dev, "Unsupported rate %dHz\n", rate);
+ return -EINVAL;
+ }
+
+ if (rate % 8000 == 0)
+ adctl3 |= WM8962_SAMPLE_RATE_INT_MODE;
+
+ for (i = 0; i < ARRAY_SIZE(sysclk_rates); i++) {
+ if (sysclk_rates[i] == wm8962->sysclk_rate / rate) {
+ clocking4 |= i << WM8962_SYSCLK_RATE_SHIFT;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(sysclk_rates)) {
+ dev_err(codec->dev, "Unsupported sysclk ratio %d\n",
+ wm8962->sysclk_rate / rate);
+ return -EINVAL;
+ }
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ aif0 |= 0x40;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ aif0 |= 0x80;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ aif0 |= 0xc0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, WM8962_AUDIO_INTERFACE_0,
+ WM8962_WL_MASK, aif0);
+ snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_3,
+ WM8962_SAMPLE_RATE_INT_MODE |
+ WM8962_SAMPLE_RATE_MASK, adctl3);
+ snd_soc_update_bits(codec, WM8962_CLOCKING_4,
+ WM8962_SYSCLK_RATE_MASK, clocking4);
+
+ wm8962_configure_bclk(codec);
+
+ return 0;
+}
+
+static int wm8962_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ int src;
+
+ switch (clk_id) {
+ case WM8962_SYSCLK_MCLK:
+ wm8962->sysclk = WM8962_SYSCLK_MCLK;
+ src = 0;
+ break;
+ case WM8962_SYSCLK_FLL:
+ wm8962->sysclk = WM8962_SYSCLK_FLL;
+ src = 1 << WM8962_SYSCLK_SRC_SHIFT;
+ WARN_ON(freq != wm8962->fll_fout);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, WM8962_CLOCKING2, WM8962_SYSCLK_SRC_MASK,
+ src);
+
+ wm8962->sysclk_rate = freq;
+
+ return 0;
+}
+
+static int wm8962_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ int aif0 = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ aif0 |= WM8962_LRCLK_INV;
+ case SND_SOC_DAIFMT_DSP_B:
+ aif0 |= 3;
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ case SND_SOC_DAIFMT_IB_NF:
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ case SND_SOC_DAIFMT_RIGHT_J:
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ aif0 |= 1;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ aif0 |= 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ aif0 |= WM8962_BCLK_INV;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ aif0 |= WM8962_LRCLK_INV;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ aif0 |= WM8962_BCLK_INV | WM8962_LRCLK_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ aif0 |= WM8962_MSTR;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, WM8962_AUDIO_INTERFACE_0,
+ WM8962_FMT_MASK | WM8962_BCLK_INV | WM8962_MSTR |
+ WM8962_LRCLK_INV, aif0);
+
+ return 0;
+}
+
+struct _fll_div {
+ u16 fll_fratio;
+ u16 fll_outdiv;
+ u16 fll_refclk_div;
+ u16 n;
+ u16 theta;
+ u16 lambda;
+};
+
+/* The size in bits of the FLL divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_FLL_SIZE ((1 << 16) * 10)
+
+static struct {
+ unsigned int min;
+ unsigned int max;
+ u16 fll_fratio;
+ int ratio;
+} fll_fratios[] = {
+ { 0, 64000, 4, 16 },
+ { 64000, 128000, 3, 8 },
+ { 128000, 256000, 2, 4 },
+ { 256000, 1000000, 1, 2 },
+ { 1000000, 13500000, 0, 1 },
+};
+
+static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
+ unsigned int Fout)
+{
+ unsigned int target;
+ unsigned int div;
+ unsigned int fratio, gcd_fll;
+ int i;
+
+ /* Fref must be <=13.5MHz */
+ div = 1;
+ fll_div->fll_refclk_div = 0;
+ while ((Fref / div) > 13500000) {
+ div *= 2;
+ fll_div->fll_refclk_div++;
+
+ if (div > 4) {
+ pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
+ Fref);
+ return -EINVAL;
+ }
+ }
+
+ pr_debug("FLL Fref=%u Fout=%u\n", Fref, Fout);
+
+ /* Apply the division for our remaining calculations */
+ Fref /= div;
+
+ /* Fvco should be 90-100MHz; don't check the upper bound */
+ div = 2;
+ while (Fout * div < 90000000) {
+ div++;
+ if (div > 64) {
+ pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
+ Fout);
+ return -EINVAL;
+ }
+ }
+ target = Fout * div;
+ fll_div->fll_outdiv = div - 1;
+
+ pr_debug("FLL Fvco=%dHz\n", target);
+
+ /* Find an appropraite FLL_FRATIO and factor it out of the target */
+ for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+ if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+ fll_div->fll_fratio = fll_fratios[i].fll_fratio;
+ fratio = fll_fratios[i].ratio;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(fll_fratios)) {
+ pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
+ return -EINVAL;
+ }
+
+ fll_div->n = target / (fratio * Fref);
+
+ if (target % Fref == 0) {
+ fll_div->theta = 0;
+ fll_div->lambda = 0;
+ } else {
+ gcd_fll = gcd(target, fratio * Fref);
+
+ fll_div->theta = (target - (fll_div->n * fratio * Fref))
+ / gcd_fll;
+ fll_div->lambda = (fratio * Fref) / gcd_fll;
+ }
+
+ pr_debug("FLL N=%x THETA=%x LAMBDA=%x\n",
+ fll_div->n, fll_div->theta, fll_div->lambda);
+ pr_debug("FLL_FRATIO=%x FLL_OUTDIV=%x FLL_REFCLK_DIV=%x\n",
+ fll_div->fll_fratio, fll_div->fll_outdiv,
+ fll_div->fll_refclk_div);
+
+ return 0;
+}
+
+static int wm8962_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
+ unsigned int Fref, unsigned int Fout)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct _fll_div fll_div;
+ int ret;
+ int fll1 = snd_soc_read(codec, WM8962_FLL_CONTROL_1) & WM8962_FLL_ENA;
+
+ /* Any change? */
+ if (source == wm8962->fll_src && Fref == wm8962->fll_fref &&
+ Fout == wm8962->fll_fout)
+ return 0;
+
+ if (Fout == 0) {
+ dev_dbg(codec->dev, "FLL disabled\n");
+
+ wm8962->fll_fref = 0;
+ wm8962->fll_fout = 0;
+
+ snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+ WM8962_FLL_ENA, 0);
+
+ return 0;
+ }
+
+ ret = fll_factors(&fll_div, Fref, Fout);
+ if (ret != 0)
+ return ret;
+
+ switch (fll_id) {
+ case WM8962_FLL_MCLK:
+ case WM8962_FLL_BCLK:
+ case WM8962_FLL_OSC:
+ fll1 |= (fll_id - 1) << WM8962_FLL_REFCLK_SRC_SHIFT;
+ break;
+ case WM8962_FLL_INT:
+ snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+ WM8962_FLL_OSC_ENA, WM8962_FLL_OSC_ENA);
+ snd_soc_update_bits(codec, WM8962_FLL_CONTROL_5,
+ WM8962_FLL_FRC_NCO, WM8962_FLL_FRC_NCO);
+ break;
+ default:
+ dev_err(codec->dev, "Unknown FLL source %d\n", ret);
+ return -EINVAL;
+ }
+
+ if (fll_div.theta || fll_div.lambda)
+ fll1 |= WM8962_FLL_FRAC;
+
+ /* Stop the FLL while we reconfigure */
+ snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, 0);
+
+ snd_soc_update_bits(codec, WM8962_FLL_CONTROL_2,
+ WM8962_FLL_OUTDIV_MASK |
+ WM8962_FLL_REFCLK_DIV_MASK,
+ (fll_div.fll_outdiv << WM8962_FLL_OUTDIV_SHIFT) |
+ (fll_div.fll_refclk_div));
+
+ snd_soc_update_bits(codec, WM8962_FLL_CONTROL_3,
+ WM8962_FLL_FRATIO_MASK, fll_div.fll_fratio);
+
+ snd_soc_write(codec, WM8962_FLL_CONTROL_6, fll_div.theta);
+ snd_soc_write(codec, WM8962_FLL_CONTROL_7, fll_div.lambda);
+ snd_soc_write(codec, WM8962_FLL_CONTROL_8, fll_div.n);
+
+ snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+ WM8962_FLL_FRAC | WM8962_FLL_REFCLK_SRC_MASK |
+ WM8962_FLL_ENA, fll1);
+
+ dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
+
+ wm8962->fll_fref = Fref;
+ wm8962->fll_fout = Fout;
+ wm8962->fll_src = source;
+
+ return 0;
+}
+
+static int wm8962_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ int val;
+
+ if (mute)
+ val = WM8962_DAC_MUTE;
+ else
+ val = 0;
+
+ return snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1,
+ WM8962_DAC_MUTE, val);
+}
+
+#define WM8962_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM8962_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops wm8962_dai_ops = {
+ .hw_params = wm8962_hw_params,
+ .set_sysclk = wm8962_set_dai_sysclk,
+ .set_fmt = wm8962_set_dai_fmt,
+ .set_pll = wm8962_set_fll,
+ .digital_mute = wm8962_mute,
+};
+
+static struct snd_soc_dai_driver wm8962_dai = {
+ .name = "wm8962",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = WM8962_RATES,
+ .formats = WM8962_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = WM8962_RATES,
+ .formats = WM8962_FORMATS,
+ },
+ .ops = &wm8962_dai_ops,
+ .symmetric_rates = 1,
+};
+
+static void wm8962_mic_work(struct work_struct *work)
+{
+ struct wm8962_priv *wm8962 = container_of(work,
+ struct wm8962_priv,
+ mic_work.work);
+ struct snd_soc_codec *codec = wm8962->codec;
+ int status = 0;
+ int irq_pol = 0;
+ int reg;
+
+ reg = snd_soc_read(codec, WM8962_ADDITIONAL_CONTROL_4);
+
+ if (reg & WM8962_MICDET_STS) {
+ status |= SND_JACK_MICROPHONE;
+ irq_pol |= WM8962_MICD_IRQ_POL;
+ }
+
+ if (reg & WM8962_MICSHORT_STS) {
+ status |= SND_JACK_BTN_0;
+ irq_pol |= WM8962_MICSCD_IRQ_POL;
+ }
+
+ snd_soc_jack_report(wm8962->jack, status,
+ SND_JACK_MICROPHONE | SND_JACK_BTN_0);
+
+ snd_soc_update_bits(codec, WM8962_MICINT_SOURCE_POL,
+ WM8962_MICSCD_IRQ_POL |
+ WM8962_MICD_IRQ_POL, irq_pol);
+}
+
+static irqreturn_t wm8962_irq(int irq, void *data)
+{
+ struct snd_soc_codec *codec = data;
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ int mask;
+ int active;
+
+ mask = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2);
+
+ active = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2);
+ active &= ~mask;
+
+ if (active & WM8962_FIFOS_ERR_EINT)
+ dev_err(codec->dev, "FIFO error\n");
+
+ if (active & WM8962_TEMP_SHUT_EINT)
+ dev_crit(codec->dev, "Thermal shutdown\n");
+
+ if (active & (WM8962_MICSCD_EINT | WM8962_MICD_EINT)) {
+ dev_dbg(codec->dev, "Microphone event detected\n");
+
+ schedule_delayed_work(&wm8962->mic_work,
+ msecs_to_jiffies(250));
+ }
+
+ /* Acknowledge the interrupts */
+ snd_soc_write(codec, WM8962_INTERRUPT_STATUS_2, active);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * wm8962_mic_detect - Enable microphone detection via the WM8962 IRQ
+ *
+ * @codec: WM8962 codec
+ * @jack: jack to report detection events on
+ *
+ * Enable microphone detection via IRQ on the WM8962. If GPIOs are
+ * being used to bring out signals to the processor then only platform
+ * data configuration is needed for WM8962 and processor GPIOs should
+ * be configured using snd_soc_jack_add_gpios() instead.
+ *
+ * If no jack is supplied detection will be disabled.
+ */
+int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
+{
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ int irq_mask, enable;
+
+ wm8962->jack = jack;
+ if (jack) {
+ irq_mask = 0;
+ enable = WM8962_MICDET_ENA;
+ } else {
+ irq_mask = WM8962_MICD_EINT | WM8962_MICSCD_EINT;
+ enable = 0;
+ }
+
+ snd_soc_update_bits(codec, WM8962_INTERRUPT_STATUS_2_MASK,
+ WM8962_MICD_EINT | WM8962_MICSCD_EINT, irq_mask);
+ snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_4,
+ WM8962_MICDET_ENA, enable);
+
+ /* Send an initial empty report */
+ snd_soc_jack_report(wm8962->jack, 0,
+ SND_JACK_MICROPHONE | SND_JACK_BTN_0);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm8962_mic_detect);
+
+#ifdef CONFIG_PM
+static int wm8962_resume(struct snd_soc_codec *codec)
+{
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ u16 *reg_cache = codec->reg_cache;
+ int i;
+
+ /* Restore the registers */
+ for (i = 1; i < ARRAY_SIZE(wm8962->reg_cache); i++) {
+ switch (i) {
+ case WM8962_SOFTWARE_RESET:
+ continue;
+ default:
+ break;
+ }
+
+ if (reg_cache[i] != wm8962_reg[i])
+ snd_soc_write(codec, i, reg_cache[i]);
+ }
+
+ return 0;
+}
+#else
+#define wm8962_resume NULL
+#endif
+
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+static int beep_rates[] = {
+ 500, 1000, 2000, 4000,
+};
+
+static void wm8962_beep_work(struct work_struct *work)
+{
+ struct wm8962_priv *wm8962 =
+ container_of(work, struct wm8962_priv, beep_work);
+ struct snd_soc_codec *codec = wm8962->codec;
+ int i;
+ int reg = 0;
+ int best = 0;
+
+ if (wm8962->beep_rate) {
+ for (i = 0; i < ARRAY_SIZE(beep_rates); i++) {
+ if (abs(wm8962->beep_rate - beep_rates[i]) <
+ abs(wm8962->beep_rate - beep_rates[best]))
+ best = i;
+ }
+
+ dev_dbg(codec->dev, "Set beep rate %dHz for requested %dHz\n",
+ beep_rates[best], wm8962->beep_rate);
+
+ reg = WM8962_BEEP_ENA | (best << WM8962_BEEP_RATE_SHIFT);
+
+ snd_soc_dapm_enable_pin(codec, "Beep");
+ } else {
+ dev_dbg(codec->dev, "Disabling beep\n");
+ snd_soc_dapm_disable_pin(codec, "Beep");
+ }
+
+ snd_soc_update_bits(codec, WM8962_BEEP_GENERATOR_1,
+ WM8962_BEEP_ENA | WM8962_BEEP_RATE_MASK, reg);
+
+ snd_soc_dapm_sync(codec);
+}
+
+/* For usability define a way of injecting beep events for the device -
+ * many systems will not have a keyboard.
+ */
+static int wm8962_beep_event(struct input_dev *dev, unsigned int type,
+ unsigned int code, int hz)
+{
+ struct snd_soc_codec *codec = input_get_drvdata(dev);
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "Beep event %x %x\n", code, hz);
+
+ switch (code) {
+ case SND_BELL:
+ if (hz)
+ hz = 1000;
+ case SND_TONE:
+ break;
+ default:
+ return -1;
+ }
+
+ /* Kick the beep from a workqueue */
+ wm8962->beep_rate = hz;
+ schedule_work(&wm8962->beep_work);
+ return 0;
+}
+
+static ssize_t wm8962_beep_set(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct wm8962_priv *wm8962 = dev_get_drvdata(dev);
+ long int time;
+
+ strict_strtol(buf, 10, &time);
+
+ input_event(wm8962->beep, EV_SND, SND_TONE, time);
+
+ return count;
+}
+
+static DEVICE_ATTR(beep, 0200, NULL, wm8962_beep_set);
+
+static void wm8962_init_beep(struct snd_soc_codec *codec)
+{
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ wm8962->beep = input_allocate_device();
+ if (!wm8962->beep) {
+ dev_err(codec->dev, "Failed to allocate beep device\n");
+ return;
+ }
+
+ INIT_WORK(&wm8962->beep_work, wm8962_beep_work);
+ wm8962->beep_rate = 0;
+
+ wm8962->beep->name = "WM8962 Beep Generator";
+ wm8962->beep->phys = dev_name(codec->dev);
+ wm8962->beep->id.bustype = BUS_I2C;
+
+ wm8962->beep->evbit[0] = BIT_MASK(EV_SND);
+ wm8962->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
+ wm8962->beep->event = wm8962_beep_event;
+ wm8962->beep->dev.parent = codec->dev;
+ input_set_drvdata(wm8962->beep, codec);
+
+ ret = input_register_device(wm8962->beep);
+ if (ret != 0) {
+ input_free_device(wm8962->beep);
+ wm8962->beep = NULL;
+ dev_err(codec->dev, "Failed to register beep device\n");
+ }
+
+ ret = device_create_file(codec->dev, &dev_attr_beep);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to create keyclick file: %d\n",
+ ret);
+ }
+}
+
+static void wm8962_free_beep(struct snd_soc_codec *codec)
+{
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+
+ device_remove_file(codec->dev, &dev_attr_beep);
+ input_unregister_device(wm8962->beep);
+ cancel_work_sync(&wm8962->beep_work);
+ wm8962->beep = NULL;
+
+ snd_soc_update_bits(codec, WM8962_BEEP_GENERATOR_1, WM8962_BEEP_ENA,0);
+}
+#else
+static void wm8962_init_beep(struct snd_soc_codec *codec)
+{
+}
+
+static void wm8962_free_beep(struct snd_soc_codec *codec)
+{
+}
+#endif
+
+static void wm8962_set_gpio_mode(struct snd_soc_codec *codec, int gpio)
+{
+ int mask = 0;
+ int val = 0;
+
+ /* Some of the GPIOs are behind MFP configuration and need to
+ * be put into GPIO mode. */
+ switch (gpio) {
+ case 2:
+ mask = WM8962_CLKOUT2_SEL_MASK;
+ val = 1 << WM8962_CLKOUT2_SEL_SHIFT;
+ break;
+ case 3:
+ mask = WM8962_CLKOUT3_SEL_MASK;
+ val = 1 << WM8962_CLKOUT3_SEL_SHIFT;
+ break;
+ default:
+ break;
+ }
+
+ if (mask)
+ snd_soc_update_bits(codec, WM8962_ANALOGUE_CLOCKING1,
+ mask, val);
+}
+
+#ifdef CONFIG_GPIOLIB
+static inline struct wm8962_priv *gpio_to_wm8962(struct gpio_chip *chip)
+{
+ return container_of(chip, struct wm8962_priv, gpio_chip);
+}
+
+static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ struct wm8962_priv *wm8962 = gpio_to_wm8962(chip);
+ struct snd_soc_codec *codec = wm8962->codec;
+
+ /* The WM8962 GPIOs aren't linearly numbered. For simplicity
+ * we export linear numbers and error out if the unsupported
+ * ones are requsted.
+ */
+ switch (offset + 1) {
+ case 2:
+ case 3:
+ case 5:
+ case 6:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ wm8962_set_gpio_mode(codec, offset + 1);
+
+ return 0;
+}
+
+static void wm8962_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct wm8962_priv *wm8962 = gpio_to_wm8962(chip);
+ struct snd_soc_codec *codec = wm8962->codec;
+
+ snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset,
+ WM8962_GP2_LVL, value << WM8962_GP2_LVL_SHIFT);
+}
+
+static int wm8962_gpio_direction_out(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct wm8962_priv *wm8962 = gpio_to_wm8962(chip);
+ struct snd_soc_codec *codec = wm8962->codec;
+ int val;
+
+ /* Force function 1 (logic output) */
+ val = (1 << WM8962_GP2_FN_SHIFT) | (value << WM8962_GP2_LVL_SHIFT);
+
+ return snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset,
+ WM8962_GP2_FN_MASK | WM8962_GP2_LVL, val);
+}
+
+static struct gpio_chip wm8962_template_chip = {
+ .label = "wm8962",
+ .owner = THIS_MODULE,
+ .request = wm8962_gpio_request,
+ .direction_output = wm8962_gpio_direction_out,
+ .set = wm8962_gpio_set,
+ .can_sleep = 1,
+};
+
+static void wm8962_init_gpio(struct snd_soc_codec *codec)
+{
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
+ int ret;
+
+ wm8962->gpio_chip = wm8962_template_chip;
+ wm8962->gpio_chip.ngpio = WM8962_MAX_GPIO;
+ wm8962->gpio_chip.dev = codec->dev;
+
+ if (pdata && pdata->gpio_base)
+ wm8962->gpio_chip.base = pdata->gpio_base;
+ else
+ wm8962->gpio_chip.base = -1;
+
+ ret = gpiochip_add(&wm8962->gpio_chip);
+ if (ret != 0)
+ dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
+}
+
+static void wm8962_free_gpio(struct snd_soc_codec *codec)
+{
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ ret = gpiochip_remove(&wm8962->gpio_chip);
+ if (ret != 0)
+ dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
+}
+#else
+static void wm8962_init_gpio(struct snd_soc_codec *codec)
+{
+}
+
+static void wm8962_free_gpio(struct snd_soc_codec *codec)
+{
+}
+#endif
+
+static int wm8962_probe(struct snd_soc_codec *codec)
+{
+ int ret;
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
+ struct i2c_client *i2c = container_of(codec->dev, struct i2c_client,
+ dev);
+ int i, trigger, irq_pol;
+
+ wm8962->codec = codec;
+ INIT_DELAYED_WORK(&wm8962->mic_work, wm8962_mic_work);
+
+ codec->cache_sync = 1;
+ codec->idle_bias_off = 1;
+
+ ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ goto err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++)
+ wm8962->supplies[i].supply = wm8962_supply_names[i];
+
+ ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8962->supplies),
+ wm8962->supplies);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+ goto err;
+ }
+
+ wm8962->disable_nb[0].notifier_call = wm8962_regulator_event_0;
+ wm8962->disable_nb[1].notifier_call = wm8962_regulator_event_1;
+ wm8962->disable_nb[2].notifier_call = wm8962_regulator_event_2;
+ wm8962->disable_nb[3].notifier_call = wm8962_regulator_event_3;
+ wm8962->disable_nb[4].notifier_call = wm8962_regulator_event_4;
+ wm8962->disable_nb[5].notifier_call = wm8962_regulator_event_5;
+ wm8962->disable_nb[6].notifier_call = wm8962_regulator_event_6;
+ wm8962->disable_nb[7].notifier_call = wm8962_regulator_event_7;
+
+ /* This should really be moved into the regulator core */
+ for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) {
+ ret = regulator_register_notifier(wm8962->supplies[i].consumer,
+ &wm8962->disable_nb[i]);
+ if (ret != 0) {
+ dev_err(codec->dev,
+ "Failed to register regulator notifier: %d\n",
+ ret);
+ }
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8962->supplies),
+ wm8962->supplies);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+ goto err_get;
+ }
+
+ ret = snd_soc_read(codec, WM8962_SOFTWARE_RESET);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to read ID register\n");
+ goto err_enable;
+ }
+ if (ret != wm8962_reg[WM8962_SOFTWARE_RESET]) {
+ dev_err(codec->dev, "Device is not a WM8962, ID %x != %x\n",
+ ret, wm8962_reg[WM8962_SOFTWARE_RESET]);
+ ret = -EINVAL;
+ goto err_enable;
+ }
+
+ ret = snd_soc_read(codec, WM8962_RIGHT_INPUT_VOLUME);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to read device revision: %d\n",
+ ret);
+ goto err_enable;
+ }
+
+ dev_info(codec->dev, "customer id %x revision %c\n",
+ (ret & WM8962_CUST_ID_MASK) >> WM8962_CUST_ID_SHIFT,
+ ((ret & WM8962_CHIP_REV_MASK) >> WM8962_CHIP_REV_SHIFT)
+ + 'A');
+
+ ret = wm8962_reset(codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to issue reset\n");
+ goto err_enable;
+ }
+
+ /* SYSCLK defaults to on; make sure it is off so we can safely
+ * write to registers if the device is declocked.
+ */
+ snd_soc_update_bits(codec, WM8962_CLOCKING2, WM8962_SYSCLK_ENA, 0);
+
+ regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
+
+ if (pdata) {
+ /* Apply static configuration for GPIOs */
+ for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++)
+ if (pdata->gpio_init[i]) {
+ wm8962_set_gpio_mode(codec, i + 1);
+ snd_soc_write(codec, 0x200 + i,
+ pdata->gpio_init[i] & 0xffff);
+ }
+
+ /* Put the speakers into mono mode? */
+ if (pdata->spk_mono)
+ wm8962->reg_cache[WM8962_CLASS_D_CONTROL_2]
+ |= WM8962_SPK_MONO;
+
+ /* Micbias setup, detection enable and detection
+ * threasholds. */
+ if (pdata->mic_cfg)
+ snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_4,
+ WM8962_MICDET_ENA |
+ WM8962_MICDET_THR_MASK |
+ WM8962_MICSHORT_THR_MASK |
+ WM8962_MICBIAS_LVL,
+ pdata->mic_cfg);
+ }
+
+ /* Latch volume update bits */
+ wm8962->reg_cache[WM8962_LEFT_INPUT_VOLUME] |= WM8962_IN_VU;
+ wm8962->reg_cache[WM8962_RIGHT_INPUT_VOLUME] |= WM8962_IN_VU;
+ wm8962->reg_cache[WM8962_LEFT_ADC_VOLUME] |= WM8962_ADC_VU;
+ wm8962->reg_cache[WM8962_RIGHT_ADC_VOLUME] |= WM8962_ADC_VU;
+ wm8962->reg_cache[WM8962_LEFT_DAC_VOLUME] |= WM8962_DAC_VU;
+ wm8962->reg_cache[WM8962_RIGHT_DAC_VOLUME] |= WM8962_DAC_VU;
+ wm8962->reg_cache[WM8962_SPKOUTL_VOLUME] |= WM8962_SPKOUT_VU;
+ wm8962->reg_cache[WM8962_SPKOUTR_VOLUME] |= WM8962_SPKOUT_VU;
+ wm8962->reg_cache[WM8962_HPOUTL_VOLUME] |= WM8962_HPOUT_VU;
+ wm8962->reg_cache[WM8962_HPOUTR_VOLUME] |= WM8962_HPOUT_VU;
+
+ wm8962_add_widgets(codec);
+
+ wm8962_init_beep(codec);
+ wm8962_init_gpio(codec);
+
+ if (i2c->irq) {
+ if (pdata && pdata->irq_active_low) {
+ trigger = IRQF_TRIGGER_LOW;
+ irq_pol = WM8962_IRQ_POL;
+ } else {
+ trigger = IRQF_TRIGGER_HIGH;
+ irq_pol = 0;
+ }
+
+ snd_soc_update_bits(codec, WM8962_INTERRUPT_CONTROL,
+ WM8962_IRQ_POL, irq_pol);
+
+ ret = request_threaded_irq(i2c->irq, NULL, wm8962_irq,
+ trigger | IRQF_ONESHOT,
+ "wm8962", codec);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to request IRQ %d: %d\n",
+ i2c->irq, ret);
+ /* Non-fatal */
+ } else {
+ /* Enable error reporting IRQs by default */
+ snd_soc_update_bits(codec,
+ WM8962_INTERRUPT_STATUS_2_MASK,
+ WM8962_TEMP_SHUT_EINT |
+ WM8962_FIFOS_ERR_EINT, 0);
+ }
+ }
+
+ return 0;
+
+err_enable:
+ regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
+err_get:
+ regulator_bulk_free(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
+err:
+ kfree(wm8962);
+ return ret;
+}
+
+static int wm8962_remove(struct snd_soc_codec *codec)
+{
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct i2c_client *i2c = container_of(codec->dev, struct i2c_client,
+ dev);
+ int i;
+
+ if (i2c->irq)
+ free_irq(i2c->irq, codec);
+
+ cancel_delayed_work_sync(&wm8962->mic_work);
+
+ wm8962_free_gpio(codec);
+ wm8962_free_beep(codec);
+ for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++)
+ regulator_unregister_notifier(wm8962->supplies[i].consumer,
+ &wm8962->disable_nb[i]);
+ regulator_bulk_free(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8962 = {
+ .probe = wm8962_probe,
+ .remove = wm8962_remove,
+ .resume = wm8962_resume,
+ .set_bias_level = wm8962_set_bias_level,
+ .reg_cache_size = WM8962_MAX_REGISTER + 1,
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8962_reg,
+ .volatile_register = wm8962_volatile_register,
+ .readable_register = wm8962_readable_register,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8962_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8962_priv *wm8962;
+ int ret;
+
+ wm8962 = kzalloc(sizeof(struct wm8962_priv), GFP_KERNEL);
+ if (wm8962 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, wm8962);
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8962, &wm8962_dai, 1);
+ if (ret < 0)
+ kfree(wm8962);
+
+ return ret;
+}
+
+static __devexit int wm8962_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+static const struct i2c_device_id wm8962_i2c_id[] = {
+ { "wm8962", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8962_i2c_id);
+
+static struct i2c_driver wm8962_i2c_driver = {
+ .driver = {
+ .name = "wm8962",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8962_i2c_probe,
+ .remove = __devexit_p(wm8962_i2c_remove),
+ .id_table = wm8962_i2c_id,
+};
+#endif
+
+static int __init wm8962_modinit(void)
+{
+ int ret;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8962_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register WM8962 I2C driver: %d\n",
+ ret);
+ }
+#endif
+ return 0;
+}
+module_init(wm8962_modinit);
+
+static void __exit wm8962_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&wm8962_i2c_driver);
+#endif
+}
+module_exit(wm8962_exit);
+
+MODULE_DESCRIPTION("ASoC WM8962 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8962.h b/sound/soc/codecs/wm8962.h
new file mode 100644
index 0000000..a1a5d52
--- /dev/null
+++ b/sound/soc/codecs/wm8962.h
@@ -0,0 +1,3780 @@
+/*
+ * wm8962.h -- WM8962 ASoC driver
+ *
+ * Copyright 2010 Wolfson Microelectronics, plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * 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 _WM8962_H
+#define _WM8962_H
+
+#include <asm/types.h>
+#include <sound/soc.h>
+
+#define WM8962_SYSCLK_MCLK 1
+#define WM8962_SYSCLK_FLL 2
+#define WM8962_SYSCLK_PLL3 3
+
+#define WM8962_FLL 1
+
+#define WM8962_FLL_MCLK 1
+#define WM8962_FLL_BCLK 2
+#define WM8962_FLL_OSC 3
+#define WM8962_FLL_INT 4
+
+/*
+ * Register values.
+ */
+#define WM8962_LEFT_INPUT_VOLUME 0x00
+#define WM8962_RIGHT_INPUT_VOLUME 0x01
+#define WM8962_HPOUTL_VOLUME 0x02
+#define WM8962_HPOUTR_VOLUME 0x03
+#define WM8962_CLOCKING1 0x04
+#define WM8962_ADC_DAC_CONTROL_1 0x05
+#define WM8962_ADC_DAC_CONTROL_2 0x06
+#define WM8962_AUDIO_INTERFACE_0 0x07
+#define WM8962_CLOCKING2 0x08
+#define WM8962_AUDIO_INTERFACE_1 0x09
+#define WM8962_LEFT_DAC_VOLUME 0x0A
+#define WM8962_RIGHT_DAC_VOLUME 0x0B
+#define WM8962_AUDIO_INTERFACE_2 0x0E
+#define WM8962_SOFTWARE_RESET 0x0F
+#define WM8962_ALC1 0x11
+#define WM8962_ALC2 0x12
+#define WM8962_ALC3 0x13
+#define WM8962_NOISE_GATE 0x14
+#define WM8962_LEFT_ADC_VOLUME 0x15
+#define WM8962_RIGHT_ADC_VOLUME 0x16
+#define WM8962_ADDITIONAL_CONTROL_1 0x17
+#define WM8962_ADDITIONAL_CONTROL_2 0x18
+#define WM8962_PWR_MGMT_1 0x19
+#define WM8962_PWR_MGMT_2 0x1A
+#define WM8962_ADDITIONAL_CONTROL_3 0x1B
+#define WM8962_ANTI_POP 0x1C
+#define WM8962_CLOCKING_3 0x1E
+#define WM8962_INPUT_MIXER_CONTROL_1 0x1F
+#define WM8962_LEFT_INPUT_MIXER_VOLUME 0x20
+#define WM8962_RIGHT_INPUT_MIXER_VOLUME 0x21
+#define WM8962_INPUT_MIXER_CONTROL_2 0x22
+#define WM8962_INPUT_BIAS_CONTROL 0x23
+#define WM8962_LEFT_INPUT_PGA_CONTROL 0x25
+#define WM8962_RIGHT_INPUT_PGA_CONTROL 0x26
+#define WM8962_SPKOUTL_VOLUME 0x28
+#define WM8962_SPKOUTR_VOLUME 0x29
+#define WM8962_THERMAL_SHUTDOWN_STATUS 0x2F
+#define WM8962_ADDITIONAL_CONTROL_4 0x30
+#define WM8962_CLASS_D_CONTROL_1 0x31
+#define WM8962_CLASS_D_CONTROL_2 0x33
+#define WM8962_CLOCKING_4 0x38
+#define WM8962_DAC_DSP_MIXING_1 0x39
+#define WM8962_DAC_DSP_MIXING_2 0x3A
+#define WM8962_DC_SERVO_0 0x3C
+#define WM8962_DC_SERVO_1 0x3D
+#define WM8962_DC_SERVO_4 0x40
+#define WM8962_DC_SERVO_6 0x42
+#define WM8962_ANALOGUE_PGA_BIAS 0x44
+#define WM8962_ANALOGUE_HP_0 0x45
+#define WM8962_ANALOGUE_HP_2 0x47
+#define WM8962_CHARGE_PUMP_1 0x48
+#define WM8962_CHARGE_PUMP_B 0x52
+#define WM8962_WRITE_SEQUENCER_CONTROL_1 0x57
+#define WM8962_WRITE_SEQUENCER_CONTROL_2 0x5A
+#define WM8962_WRITE_SEQUENCER_CONTROL_3 0x5D
+#define WM8962_CONTROL_INTERFACE 0x5E
+#define WM8962_MIXER_ENABLES 0x63
+#define WM8962_HEADPHONE_MIXER_1 0x64
+#define WM8962_HEADPHONE_MIXER_2 0x65
+#define WM8962_HEADPHONE_MIXER_3 0x66
+#define WM8962_HEADPHONE_MIXER_4 0x67
+#define WM8962_SPEAKER_MIXER_1 0x69
+#define WM8962_SPEAKER_MIXER_2 0x6A
+#define WM8962_SPEAKER_MIXER_3 0x6B
+#define WM8962_SPEAKER_MIXER_4 0x6C
+#define WM8962_SPEAKER_MIXER_5 0x6D
+#define WM8962_BEEP_GENERATOR_1 0x6E
+#define WM8962_OSCILLATOR_TRIM_3 0x73
+#define WM8962_OSCILLATOR_TRIM_4 0x74
+#define WM8962_OSCILLATOR_TRIM_7 0x77
+#define WM8962_ANALOGUE_CLOCKING1 0x7C
+#define WM8962_ANALOGUE_CLOCKING2 0x7D
+#define WM8962_ANALOGUE_CLOCKING3 0x7E
+#define WM8962_PLL_SOFTWARE_RESET 0x7F
+#define WM8962_PLL2 0x81
+#define WM8962_PLL_4 0x83
+#define WM8962_PLL_9 0x88
+#define WM8962_PLL_10 0x89
+#define WM8962_PLL_11 0x8A
+#define WM8962_PLL_12 0x8B
+#define WM8962_PLL_13 0x8C
+#define WM8962_PLL_14 0x8D
+#define WM8962_PLL_15 0x8E
+#define WM8962_PLL_16 0x8F
+#define WM8962_FLL_CONTROL_1 0x9B
+#define WM8962_FLL_CONTROL_2 0x9C
+#define WM8962_FLL_CONTROL_3 0x9D
+#define WM8962_FLL_CONTROL_5 0x9F
+#define WM8962_FLL_CONTROL_6 0xA0
+#define WM8962_FLL_CONTROL_7 0xA1
+#define WM8962_FLL_CONTROL_8 0xA2
+#define WM8962_GENERAL_TEST_1 0xFC
+#define WM8962_DF1 0x100
+#define WM8962_DF2 0x101
+#define WM8962_DF3 0x102
+#define WM8962_DF4 0x103
+#define WM8962_DF5 0x104
+#define WM8962_DF6 0x105
+#define WM8962_DF7 0x106
+#define WM8962_LHPF1 0x108
+#define WM8962_LHPF2 0x109
+#define WM8962_THREED1 0x10C
+#define WM8962_THREED2 0x10D
+#define WM8962_THREED3 0x10E
+#define WM8962_THREED4 0x10F
+#define WM8962_DRC_1 0x114
+#define WM8962_DRC_2 0x115
+#define WM8962_DRC_3 0x116
+#define WM8962_DRC_4 0x117
+#define WM8962_DRC_5 0x118
+#define WM8962_TLOOPBACK 0x11D
+#define WM8962_EQ1 0x14F
+#define WM8962_EQ2 0x150
+#define WM8962_EQ3 0x151
+#define WM8962_EQ4 0x152
+#define WM8962_EQ5 0x153
+#define WM8962_EQ6 0x154
+#define WM8962_EQ7 0x155
+#define WM8962_EQ8 0x156
+#define WM8962_EQ9 0x157
+#define WM8962_EQ10 0x158
+#define WM8962_EQ11 0x159
+#define WM8962_EQ12 0x15A
+#define WM8962_EQ13 0x15B
+#define WM8962_EQ14 0x15C
+#define WM8962_EQ15 0x15D
+#define WM8962_EQ16 0x15E
+#define WM8962_EQ17 0x15F
+#define WM8962_EQ18 0x160
+#define WM8962_EQ19 0x161
+#define WM8962_EQ20 0x162
+#define WM8962_EQ21 0x163
+#define WM8962_EQ22 0x164
+#define WM8962_EQ23 0x165
+#define WM8962_EQ24 0x166
+#define WM8962_EQ25 0x167
+#define WM8962_EQ26 0x168
+#define WM8962_EQ27 0x169
+#define WM8962_EQ28 0x16A
+#define WM8962_EQ29 0x16B
+#define WM8962_EQ30 0x16C
+#define WM8962_EQ31 0x16D
+#define WM8962_EQ32 0x16E
+#define WM8962_EQ33 0x16F
+#define WM8962_EQ34 0x170
+#define WM8962_EQ35 0x171
+#define WM8962_EQ36 0x172
+#define WM8962_EQ37 0x173
+#define WM8962_EQ38 0x174
+#define WM8962_EQ39 0x175
+#define WM8962_EQ40 0x176
+#define WM8962_EQ41 0x177
+#define WM8962_GPIO_BASE 0x200
+#define WM8962_GPIO_2 0x201
+#define WM8962_GPIO_3 0x202
+#define WM8962_GPIO_5 0x204
+#define WM8962_GPIO_6 0x205
+#define WM8962_INTERRUPT_STATUS_1 0x230
+#define WM8962_INTERRUPT_STATUS_2 0x231
+#define WM8962_INTERRUPT_STATUS_1_MASK 0x238
+#define WM8962_INTERRUPT_STATUS_2_MASK 0x239
+#define WM8962_INTERRUPT_CONTROL 0x240
+#define WM8962_IRQ_DEBOUNCE 0x248
+#define WM8962_MICINT_SOURCE_POL 0x24A
+#define WM8962_DSP2_POWER_MANAGEMENT 0x300
+#define WM8962_DSP2_EXECCONTROL 0x40D
+#define WM8962_WRITE_SEQUENCER_0 0x1000
+#define WM8962_WRITE_SEQUENCER_1 0x1001
+#define WM8962_WRITE_SEQUENCER_2 0x1002
+#define WM8962_WRITE_SEQUENCER_3 0x1003
+#define WM8962_WRITE_SEQUENCER_4 0x1004
+#define WM8962_WRITE_SEQUENCER_5 0x1005
+#define WM8962_WRITE_SEQUENCER_6 0x1006
+#define WM8962_WRITE_SEQUENCER_7 0x1007
+#define WM8962_WRITE_SEQUENCER_8 0x1008
+#define WM8962_WRITE_SEQUENCER_9 0x1009
+#define WM8962_WRITE_SEQUENCER_10 0x100A
+#define WM8962_WRITE_SEQUENCER_11 0x100B
+#define WM8962_WRITE_SEQUENCER_12 0x100C
+#define WM8962_WRITE_SEQUENCER_13 0x100D
+#define WM8962_WRITE_SEQUENCER_14 0x100E
+#define WM8962_WRITE_SEQUENCER_15 0x100F
+#define WM8962_WRITE_SEQUENCER_16 0x1010
+#define WM8962_WRITE_SEQUENCER_17 0x1011
+#define WM8962_WRITE_SEQUENCER_18 0x1012
+#define WM8962_WRITE_SEQUENCER_19 0x1013
+#define WM8962_WRITE_SEQUENCER_20 0x1014
+#define WM8962_WRITE_SEQUENCER_21 0x1015
+#define WM8962_WRITE_SEQUENCER_22 0x1016
+#define WM8962_WRITE_SEQUENCER_23 0x1017
+#define WM8962_WRITE_SEQUENCER_24 0x1018
+#define WM8962_WRITE_SEQUENCER_25 0x1019
+#define WM8962_WRITE_SEQUENCER_26 0x101A
+#define WM8962_WRITE_SEQUENCER_27 0x101B
+#define WM8962_WRITE_SEQUENCER_28 0x101C
+#define WM8962_WRITE_SEQUENCER_29 0x101D
+#define WM8962_WRITE_SEQUENCER_30 0x101E
+#define WM8962_WRITE_SEQUENCER_31 0x101F
+#define WM8962_WRITE_SEQUENCER_32 0x1020
+#define WM8962_WRITE_SEQUENCER_33 0x1021
+#define WM8962_WRITE_SEQUENCER_34 0x1022
+#define WM8962_WRITE_SEQUENCER_35 0x1023
+#define WM8962_WRITE_SEQUENCER_36 0x1024
+#define WM8962_WRITE_SEQUENCER_37 0x1025
+#define WM8962_WRITE_SEQUENCER_38 0x1026
+#define WM8962_WRITE_SEQUENCER_39 0x1027
+#define WM8962_WRITE_SEQUENCER_40 0x1028
+#define WM8962_WRITE_SEQUENCER_41 0x1029
+#define WM8962_WRITE_SEQUENCER_42 0x102A
+#define WM8962_WRITE_SEQUENCER_43 0x102B
+#define WM8962_WRITE_SEQUENCER_44 0x102C
+#define WM8962_WRITE_SEQUENCER_45 0x102D
+#define WM8962_WRITE_SEQUENCER_46 0x102E
+#define WM8962_WRITE_SEQUENCER_47 0x102F
+#define WM8962_WRITE_SEQUENCER_48 0x1030
+#define WM8962_WRITE_SEQUENCER_49 0x1031
+#define WM8962_WRITE_SEQUENCER_50 0x1032
+#define WM8962_WRITE_SEQUENCER_51 0x1033
+#define WM8962_WRITE_SEQUENCER_52 0x1034
+#define WM8962_WRITE_SEQUENCER_53 0x1035
+#define WM8962_WRITE_SEQUENCER_54 0x1036
+#define WM8962_WRITE_SEQUENCER_55 0x1037
+#define WM8962_WRITE_SEQUENCER_56 0x1038
+#define WM8962_WRITE_SEQUENCER_57 0x1039
+#define WM8962_WRITE_SEQUENCER_58 0x103A
+#define WM8962_WRITE_SEQUENCER_59 0x103B
+#define WM8962_WRITE_SEQUENCER_60 0x103C
+#define WM8962_WRITE_SEQUENCER_61 0x103D
+#define WM8962_WRITE_SEQUENCER_62 0x103E
+#define WM8962_WRITE_SEQUENCER_63 0x103F
+#define WM8962_WRITE_SEQUENCER_64 0x1040
+#define WM8962_WRITE_SEQUENCER_65 0x1041
+#define WM8962_WRITE_SEQUENCER_66 0x1042
+#define WM8962_WRITE_SEQUENCER_67 0x1043
+#define WM8962_WRITE_SEQUENCER_68 0x1044
+#define WM8962_WRITE_SEQUENCER_69 0x1045
+#define WM8962_WRITE_SEQUENCER_70 0x1046
+#define WM8962_WRITE_SEQUENCER_71 0x1047
+#define WM8962_WRITE_SEQUENCER_72 0x1048
+#define WM8962_WRITE_SEQUENCER_73 0x1049
+#define WM8962_WRITE_SEQUENCER_74 0x104A
+#define WM8962_WRITE_SEQUENCER_75 0x104B
+#define WM8962_WRITE_SEQUENCER_76 0x104C
+#define WM8962_WRITE_SEQUENCER_77 0x104D
+#define WM8962_WRITE_SEQUENCER_78 0x104E
+#define WM8962_WRITE_SEQUENCER_79 0x104F
+#define WM8962_WRITE_SEQUENCER_80 0x1050
+#define WM8962_WRITE_SEQUENCER_81 0x1051
+#define WM8962_WRITE_SEQUENCER_82 0x1052
+#define WM8962_WRITE_SEQUENCER_83 0x1053
+#define WM8962_WRITE_SEQUENCER_84 0x1054
+#define WM8962_WRITE_SEQUENCER_85 0x1055
+#define WM8962_WRITE_SEQUENCER_86 0x1056
+#define WM8962_WRITE_SEQUENCER_87 0x1057
+#define WM8962_WRITE_SEQUENCER_88 0x1058
+#define WM8962_WRITE_SEQUENCER_89 0x1059
+#define WM8962_WRITE_SEQUENCER_90 0x105A
+#define WM8962_WRITE_SEQUENCER_91 0x105B
+#define WM8962_WRITE_SEQUENCER_92 0x105C
+#define WM8962_WRITE_SEQUENCER_93 0x105D
+#define WM8962_WRITE_SEQUENCER_94 0x105E
+#define WM8962_WRITE_SEQUENCER_95 0x105F
+#define WM8962_WRITE_SEQUENCER_96 0x1060
+#define WM8962_WRITE_SEQUENCER_97 0x1061
+#define WM8962_WRITE_SEQUENCER_98 0x1062
+#define WM8962_WRITE_SEQUENCER_99 0x1063
+#define WM8962_WRITE_SEQUENCER_100 0x1064
+#define WM8962_WRITE_SEQUENCER_101 0x1065
+#define WM8962_WRITE_SEQUENCER_102 0x1066
+#define WM8962_WRITE_SEQUENCER_103 0x1067
+#define WM8962_WRITE_SEQUENCER_104 0x1068
+#define WM8962_WRITE_SEQUENCER_105 0x1069
+#define WM8962_WRITE_SEQUENCER_106 0x106A
+#define WM8962_WRITE_SEQUENCER_107 0x106B
+#define WM8962_WRITE_SEQUENCER_108 0x106C
+#define WM8962_WRITE_SEQUENCER_109 0x106D
+#define WM8962_WRITE_SEQUENCER_110 0x106E
+#define WM8962_WRITE_SEQUENCER_111 0x106F
+#define WM8962_WRITE_SEQUENCER_112 0x1070
+#define WM8962_WRITE_SEQUENCER_113 0x1071
+#define WM8962_WRITE_SEQUENCER_114 0x1072
+#define WM8962_WRITE_SEQUENCER_115 0x1073
+#define WM8962_WRITE_SEQUENCER_116 0x1074
+#define WM8962_WRITE_SEQUENCER_117 0x1075
+#define WM8962_WRITE_SEQUENCER_118 0x1076
+#define WM8962_WRITE_SEQUENCER_119 0x1077
+#define WM8962_WRITE_SEQUENCER_120 0x1078
+#define WM8962_WRITE_SEQUENCER_121 0x1079
+#define WM8962_WRITE_SEQUENCER_122 0x107A
+#define WM8962_WRITE_SEQUENCER_123 0x107B
+#define WM8962_WRITE_SEQUENCER_124 0x107C
+#define WM8962_WRITE_SEQUENCER_125 0x107D
+#define WM8962_WRITE_SEQUENCER_126 0x107E
+#define WM8962_WRITE_SEQUENCER_127 0x107F
+#define WM8962_WRITE_SEQUENCER_128 0x1080
+#define WM8962_WRITE_SEQUENCER_129 0x1081
+#define WM8962_WRITE_SEQUENCER_130 0x1082
+#define WM8962_WRITE_SEQUENCER_131 0x1083
+#define WM8962_WRITE_SEQUENCER_132 0x1084
+#define WM8962_WRITE_SEQUENCER_133 0x1085
+#define WM8962_WRITE_SEQUENCER_134 0x1086
+#define WM8962_WRITE_SEQUENCER_135 0x1087
+#define WM8962_WRITE_SEQUENCER_136 0x1088
+#define WM8962_WRITE_SEQUENCER_137 0x1089
+#define WM8962_WRITE_SEQUENCER_138 0x108A
+#define WM8962_WRITE_SEQUENCER_139 0x108B
+#define WM8962_WRITE_SEQUENCER_140 0x108C
+#define WM8962_WRITE_SEQUENCER_141 0x108D
+#define WM8962_WRITE_SEQUENCER_142 0x108E
+#define WM8962_WRITE_SEQUENCER_143 0x108F
+#define WM8962_WRITE_SEQUENCER_144 0x1090
+#define WM8962_WRITE_SEQUENCER_145 0x1091
+#define WM8962_WRITE_SEQUENCER_146 0x1092
+#define WM8962_WRITE_SEQUENCER_147 0x1093
+#define WM8962_WRITE_SEQUENCER_148 0x1094
+#define WM8962_WRITE_SEQUENCER_149 0x1095
+#define WM8962_WRITE_SEQUENCER_150 0x1096
+#define WM8962_WRITE_SEQUENCER_151 0x1097
+#define WM8962_WRITE_SEQUENCER_152 0x1098
+#define WM8962_WRITE_SEQUENCER_153 0x1099
+#define WM8962_WRITE_SEQUENCER_154 0x109A
+#define WM8962_WRITE_SEQUENCER_155 0x109B
+#define WM8962_WRITE_SEQUENCER_156 0x109C
+#define WM8962_WRITE_SEQUENCER_157 0x109D
+#define WM8962_WRITE_SEQUENCER_158 0x109E
+#define WM8962_WRITE_SEQUENCER_159 0x109F
+#define WM8962_WRITE_SEQUENCER_160 0x10A0
+#define WM8962_WRITE_SEQUENCER_161 0x10A1
+#define WM8962_WRITE_SEQUENCER_162 0x10A2
+#define WM8962_WRITE_SEQUENCER_163 0x10A3
+#define WM8962_WRITE_SEQUENCER_164 0x10A4
+#define WM8962_WRITE_SEQUENCER_165 0x10A5
+#define WM8962_WRITE_SEQUENCER_166 0x10A6
+#define WM8962_WRITE_SEQUENCER_167 0x10A7
+#define WM8962_WRITE_SEQUENCER_168 0x10A8
+#define WM8962_WRITE_SEQUENCER_169 0x10A9
+#define WM8962_WRITE_SEQUENCER_170 0x10AA
+#define WM8962_WRITE_SEQUENCER_171 0x10AB
+#define WM8962_WRITE_SEQUENCER_172 0x10AC
+#define WM8962_WRITE_SEQUENCER_173 0x10AD
+#define WM8962_WRITE_SEQUENCER_174 0x10AE
+#define WM8962_WRITE_SEQUENCER_175 0x10AF
+#define WM8962_WRITE_SEQUENCER_176 0x10B0
+#define WM8962_WRITE_SEQUENCER_177 0x10B1
+#define WM8962_WRITE_SEQUENCER_178 0x10B2
+#define WM8962_WRITE_SEQUENCER_179 0x10B3
+#define WM8962_WRITE_SEQUENCER_180 0x10B4
+#define WM8962_WRITE_SEQUENCER_181 0x10B5
+#define WM8962_WRITE_SEQUENCER_182 0x10B6
+#define WM8962_WRITE_SEQUENCER_183 0x10B7
+#define WM8962_WRITE_SEQUENCER_184 0x10B8
+#define WM8962_WRITE_SEQUENCER_185 0x10B9
+#define WM8962_WRITE_SEQUENCER_186 0x10BA
+#define WM8962_WRITE_SEQUENCER_187 0x10BB
+#define WM8962_WRITE_SEQUENCER_188 0x10BC
+#define WM8962_WRITE_SEQUENCER_189 0x10BD
+#define WM8962_WRITE_SEQUENCER_190 0x10BE
+#define WM8962_WRITE_SEQUENCER_191 0x10BF
+#define WM8962_WRITE_SEQUENCER_192 0x10C0
+#define WM8962_WRITE_SEQUENCER_193 0x10C1
+#define WM8962_WRITE_SEQUENCER_194 0x10C2
+#define WM8962_WRITE_SEQUENCER_195 0x10C3
+#define WM8962_WRITE_SEQUENCER_196 0x10C4
+#define WM8962_WRITE_SEQUENCER_197 0x10C5
+#define WM8962_WRITE_SEQUENCER_198 0x10C6
+#define WM8962_WRITE_SEQUENCER_199 0x10C7
+#define WM8962_WRITE_SEQUENCER_200 0x10C8
+#define WM8962_WRITE_SEQUENCER_201 0x10C9
+#define WM8962_WRITE_SEQUENCER_202 0x10CA
+#define WM8962_WRITE_SEQUENCER_203 0x10CB
+#define WM8962_WRITE_SEQUENCER_204 0x10CC
+#define WM8962_WRITE_SEQUENCER_205 0x10CD
+#define WM8962_WRITE_SEQUENCER_206 0x10CE
+#define WM8962_WRITE_SEQUENCER_207 0x10CF
+#define WM8962_WRITE_SEQUENCER_208 0x10D0
+#define WM8962_WRITE_SEQUENCER_209 0x10D1
+#define WM8962_WRITE_SEQUENCER_210 0x10D2
+#define WM8962_WRITE_SEQUENCER_211 0x10D3
+#define WM8962_WRITE_SEQUENCER_212 0x10D4
+#define WM8962_WRITE_SEQUENCER_213 0x10D5
+#define WM8962_WRITE_SEQUENCER_214 0x10D6
+#define WM8962_WRITE_SEQUENCER_215 0x10D7
+#define WM8962_WRITE_SEQUENCER_216 0x10D8
+#define WM8962_WRITE_SEQUENCER_217 0x10D9
+#define WM8962_WRITE_SEQUENCER_218 0x10DA
+#define WM8962_WRITE_SEQUENCER_219 0x10DB
+#define WM8962_WRITE_SEQUENCER_220 0x10DC
+#define WM8962_WRITE_SEQUENCER_221 0x10DD
+#define WM8962_WRITE_SEQUENCER_222 0x10DE
+#define WM8962_WRITE_SEQUENCER_223 0x10DF
+#define WM8962_WRITE_SEQUENCER_224 0x10E0
+#define WM8962_WRITE_SEQUENCER_225 0x10E1
+#define WM8962_WRITE_SEQUENCER_226 0x10E2
+#define WM8962_WRITE_SEQUENCER_227 0x10E3
+#define WM8962_WRITE_SEQUENCER_228 0x10E4
+#define WM8962_WRITE_SEQUENCER_229 0x10E5
+#define WM8962_WRITE_SEQUENCER_230 0x10E6
+#define WM8962_WRITE_SEQUENCER_231 0x10E7
+#define WM8962_WRITE_SEQUENCER_232 0x10E8
+#define WM8962_WRITE_SEQUENCER_233 0x10E9
+#define WM8962_WRITE_SEQUENCER_234 0x10EA
+#define WM8962_WRITE_SEQUENCER_235 0x10EB
+#define WM8962_WRITE_SEQUENCER_236 0x10EC
+#define WM8962_WRITE_SEQUENCER_237 0x10ED
+#define WM8962_WRITE_SEQUENCER_238 0x10EE
+#define WM8962_WRITE_SEQUENCER_239 0x10EF
+#define WM8962_WRITE_SEQUENCER_240 0x10F0
+#define WM8962_WRITE_SEQUENCER_241 0x10F1
+#define WM8962_WRITE_SEQUENCER_242 0x10F2
+#define WM8962_WRITE_SEQUENCER_243 0x10F3
+#define WM8962_WRITE_SEQUENCER_244 0x10F4
+#define WM8962_WRITE_SEQUENCER_245 0x10F5
+#define WM8962_WRITE_SEQUENCER_246 0x10F6
+#define WM8962_WRITE_SEQUENCER_247 0x10F7
+#define WM8962_WRITE_SEQUENCER_248 0x10F8
+#define WM8962_WRITE_SEQUENCER_249 0x10F9
+#define WM8962_WRITE_SEQUENCER_250 0x10FA
+#define WM8962_WRITE_SEQUENCER_251 0x10FB
+#define WM8962_WRITE_SEQUENCER_252 0x10FC
+#define WM8962_WRITE_SEQUENCER_253 0x10FD
+#define WM8962_WRITE_SEQUENCER_254 0x10FE
+#define WM8962_WRITE_SEQUENCER_255 0x10FF
+#define WM8962_WRITE_SEQUENCER_256 0x1100
+#define WM8962_WRITE_SEQUENCER_257 0x1101
+#define WM8962_WRITE_SEQUENCER_258 0x1102
+#define WM8962_WRITE_SEQUENCER_259 0x1103
+#define WM8962_WRITE_SEQUENCER_260 0x1104
+#define WM8962_WRITE_SEQUENCER_261 0x1105
+#define WM8962_WRITE_SEQUENCER_262 0x1106
+#define WM8962_WRITE_SEQUENCER_263 0x1107
+#define WM8962_WRITE_SEQUENCER_264 0x1108
+#define WM8962_WRITE_SEQUENCER_265 0x1109
+#define WM8962_WRITE_SEQUENCER_266 0x110A
+#define WM8962_WRITE_SEQUENCER_267 0x110B
+#define WM8962_WRITE_SEQUENCER_268 0x110C
+#define WM8962_WRITE_SEQUENCER_269 0x110D
+#define WM8962_WRITE_SEQUENCER_270 0x110E
+#define WM8962_WRITE_SEQUENCER_271 0x110F
+#define WM8962_WRITE_SEQUENCER_272 0x1110
+#define WM8962_WRITE_SEQUENCER_273 0x1111
+#define WM8962_WRITE_SEQUENCER_274 0x1112
+#define WM8962_WRITE_SEQUENCER_275 0x1113
+#define WM8962_WRITE_SEQUENCER_276 0x1114
+#define WM8962_WRITE_SEQUENCER_277 0x1115
+#define WM8962_WRITE_SEQUENCER_278 0x1116
+#define WM8962_WRITE_SEQUENCER_279 0x1117
+#define WM8962_WRITE_SEQUENCER_280 0x1118
+#define WM8962_WRITE_SEQUENCER_281 0x1119
+#define WM8962_WRITE_SEQUENCER_282 0x111A
+#define WM8962_WRITE_SEQUENCER_283 0x111B
+#define WM8962_WRITE_SEQUENCER_284 0x111C
+#define WM8962_WRITE_SEQUENCER_285 0x111D
+#define WM8962_WRITE_SEQUENCER_286 0x111E
+#define WM8962_WRITE_SEQUENCER_287 0x111F
+#define WM8962_WRITE_SEQUENCER_288 0x1120
+#define WM8962_WRITE_SEQUENCER_289 0x1121
+#define WM8962_WRITE_SEQUENCER_290 0x1122
+#define WM8962_WRITE_SEQUENCER_291 0x1123
+#define WM8962_WRITE_SEQUENCER_292 0x1124
+#define WM8962_WRITE_SEQUENCER_293 0x1125
+#define WM8962_WRITE_SEQUENCER_294 0x1126
+#define WM8962_WRITE_SEQUENCER_295 0x1127
+#define WM8962_WRITE_SEQUENCER_296 0x1128
+#define WM8962_WRITE_SEQUENCER_297 0x1129
+#define WM8962_WRITE_SEQUENCER_298 0x112A
+#define WM8962_WRITE_SEQUENCER_299 0x112B
+#define WM8962_WRITE_SEQUENCER_300 0x112C
+#define WM8962_WRITE_SEQUENCER_301 0x112D
+#define WM8962_WRITE_SEQUENCER_302 0x112E
+#define WM8962_WRITE_SEQUENCER_303 0x112F
+#define WM8962_WRITE_SEQUENCER_304 0x1130
+#define WM8962_WRITE_SEQUENCER_305 0x1131
+#define WM8962_WRITE_SEQUENCER_306 0x1132
+#define WM8962_WRITE_SEQUENCER_307 0x1133
+#define WM8962_WRITE_SEQUENCER_308 0x1134
+#define WM8962_WRITE_SEQUENCER_309 0x1135
+#define WM8962_WRITE_SEQUENCER_310 0x1136
+#define WM8962_WRITE_SEQUENCER_311 0x1137
+#define WM8962_WRITE_SEQUENCER_312 0x1138
+#define WM8962_WRITE_SEQUENCER_313 0x1139
+#define WM8962_WRITE_SEQUENCER_314 0x113A
+#define WM8962_WRITE_SEQUENCER_315 0x113B
+#define WM8962_WRITE_SEQUENCER_316 0x113C
+#define WM8962_WRITE_SEQUENCER_317 0x113D
+#define WM8962_WRITE_SEQUENCER_318 0x113E
+#define WM8962_WRITE_SEQUENCER_319 0x113F
+#define WM8962_WRITE_SEQUENCER_320 0x1140
+#define WM8962_WRITE_SEQUENCER_321 0x1141
+#define WM8962_WRITE_SEQUENCER_322 0x1142
+#define WM8962_WRITE_SEQUENCER_323 0x1143
+#define WM8962_WRITE_SEQUENCER_324 0x1144
+#define WM8962_WRITE_SEQUENCER_325 0x1145
+#define WM8962_WRITE_SEQUENCER_326 0x1146
+#define WM8962_WRITE_SEQUENCER_327 0x1147
+#define WM8962_WRITE_SEQUENCER_328 0x1148
+#define WM8962_WRITE_SEQUENCER_329 0x1149
+#define WM8962_WRITE_SEQUENCER_330 0x114A
+#define WM8962_WRITE_SEQUENCER_331 0x114B
+#define WM8962_WRITE_SEQUENCER_332 0x114C
+#define WM8962_WRITE_SEQUENCER_333 0x114D
+#define WM8962_WRITE_SEQUENCER_334 0x114E
+#define WM8962_WRITE_SEQUENCER_335 0x114F
+#define WM8962_WRITE_SEQUENCER_336 0x1150
+#define WM8962_WRITE_SEQUENCER_337 0x1151
+#define WM8962_WRITE_SEQUENCER_338 0x1152
+#define WM8962_WRITE_SEQUENCER_339 0x1153
+#define WM8962_WRITE_SEQUENCER_340 0x1154
+#define WM8962_WRITE_SEQUENCER_341 0x1155
+#define WM8962_WRITE_SEQUENCER_342 0x1156
+#define WM8962_WRITE_SEQUENCER_343 0x1157
+#define WM8962_WRITE_SEQUENCER_344 0x1158
+#define WM8962_WRITE_SEQUENCER_345 0x1159
+#define WM8962_WRITE_SEQUENCER_346 0x115A
+#define WM8962_WRITE_SEQUENCER_347 0x115B
+#define WM8962_WRITE_SEQUENCER_348 0x115C
+#define WM8962_WRITE_SEQUENCER_349 0x115D
+#define WM8962_WRITE_SEQUENCER_350 0x115E
+#define WM8962_WRITE_SEQUENCER_351 0x115F
+#define WM8962_WRITE_SEQUENCER_352 0x1160
+#define WM8962_WRITE_SEQUENCER_353 0x1161
+#define WM8962_WRITE_SEQUENCER_354 0x1162
+#define WM8962_WRITE_SEQUENCER_355 0x1163
+#define WM8962_WRITE_SEQUENCER_356 0x1164
+#define WM8962_WRITE_SEQUENCER_357 0x1165
+#define WM8962_WRITE_SEQUENCER_358 0x1166
+#define WM8962_WRITE_SEQUENCER_359 0x1167
+#define WM8962_WRITE_SEQUENCER_360 0x1168
+#define WM8962_WRITE_SEQUENCER_361 0x1169
+#define WM8962_WRITE_SEQUENCER_362 0x116A
+#define WM8962_WRITE_SEQUENCER_363 0x116B
+#define WM8962_WRITE_SEQUENCER_364 0x116C
+#define WM8962_WRITE_SEQUENCER_365 0x116D
+#define WM8962_WRITE_SEQUENCER_366 0x116E
+#define WM8962_WRITE_SEQUENCER_367 0x116F
+#define WM8962_WRITE_SEQUENCER_368 0x1170
+#define WM8962_WRITE_SEQUENCER_369 0x1171
+#define WM8962_WRITE_SEQUENCER_370 0x1172
+#define WM8962_WRITE_SEQUENCER_371 0x1173
+#define WM8962_WRITE_SEQUENCER_372 0x1174
+#define WM8962_WRITE_SEQUENCER_373 0x1175
+#define WM8962_WRITE_SEQUENCER_374 0x1176
+#define WM8962_WRITE_SEQUENCER_375 0x1177
+#define WM8962_WRITE_SEQUENCER_376 0x1178
+#define WM8962_WRITE_SEQUENCER_377 0x1179
+#define WM8962_WRITE_SEQUENCER_378 0x117A
+#define WM8962_WRITE_SEQUENCER_379 0x117B
+#define WM8962_WRITE_SEQUENCER_380 0x117C
+#define WM8962_WRITE_SEQUENCER_381 0x117D
+#define WM8962_WRITE_SEQUENCER_382 0x117E
+#define WM8962_WRITE_SEQUENCER_383 0x117F
+#define WM8962_WRITE_SEQUENCER_384 0x1180
+#define WM8962_WRITE_SEQUENCER_385 0x1181
+#define WM8962_WRITE_SEQUENCER_386 0x1182
+#define WM8962_WRITE_SEQUENCER_387 0x1183
+#define WM8962_WRITE_SEQUENCER_388 0x1184
+#define WM8962_WRITE_SEQUENCER_389 0x1185
+#define WM8962_WRITE_SEQUENCER_390 0x1186
+#define WM8962_WRITE_SEQUENCER_391 0x1187
+#define WM8962_WRITE_SEQUENCER_392 0x1188
+#define WM8962_WRITE_SEQUENCER_393 0x1189
+#define WM8962_WRITE_SEQUENCER_394 0x118A
+#define WM8962_WRITE_SEQUENCER_395 0x118B
+#define WM8962_WRITE_SEQUENCER_396 0x118C
+#define WM8962_WRITE_SEQUENCER_397 0x118D
+#define WM8962_WRITE_SEQUENCER_398 0x118E
+#define WM8962_WRITE_SEQUENCER_399 0x118F
+#define WM8962_WRITE_SEQUENCER_400 0x1190
+#define WM8962_WRITE_SEQUENCER_401 0x1191
+#define WM8962_WRITE_SEQUENCER_402 0x1192
+#define WM8962_WRITE_SEQUENCER_403 0x1193
+#define WM8962_WRITE_SEQUENCER_404 0x1194
+#define WM8962_WRITE_SEQUENCER_405 0x1195
+#define WM8962_WRITE_SEQUENCER_406 0x1196
+#define WM8962_WRITE_SEQUENCER_407 0x1197
+#define WM8962_WRITE_SEQUENCER_408 0x1198
+#define WM8962_WRITE_SEQUENCER_409 0x1199
+#define WM8962_WRITE_SEQUENCER_410 0x119A
+#define WM8962_WRITE_SEQUENCER_411 0x119B
+#define WM8962_WRITE_SEQUENCER_412 0x119C
+#define WM8962_WRITE_SEQUENCER_413 0x119D
+#define WM8962_WRITE_SEQUENCER_414 0x119E
+#define WM8962_WRITE_SEQUENCER_415 0x119F
+#define WM8962_WRITE_SEQUENCER_416 0x11A0
+#define WM8962_WRITE_SEQUENCER_417 0x11A1
+#define WM8962_WRITE_SEQUENCER_418 0x11A2
+#define WM8962_WRITE_SEQUENCER_419 0x11A3
+#define WM8962_WRITE_SEQUENCER_420 0x11A4
+#define WM8962_WRITE_SEQUENCER_421 0x11A5
+#define WM8962_WRITE_SEQUENCER_422 0x11A6
+#define WM8962_WRITE_SEQUENCER_423 0x11A7
+#define WM8962_WRITE_SEQUENCER_424 0x11A8
+#define WM8962_WRITE_SEQUENCER_425 0x11A9
+#define WM8962_WRITE_SEQUENCER_426 0x11AA
+#define WM8962_WRITE_SEQUENCER_427 0x11AB
+#define WM8962_WRITE_SEQUENCER_428 0x11AC
+#define WM8962_WRITE_SEQUENCER_429 0x11AD
+#define WM8962_WRITE_SEQUENCER_430 0x11AE
+#define WM8962_WRITE_SEQUENCER_431 0x11AF
+#define WM8962_WRITE_SEQUENCER_432 0x11B0
+#define WM8962_WRITE_SEQUENCER_433 0x11B1
+#define WM8962_WRITE_SEQUENCER_434 0x11B2
+#define WM8962_WRITE_SEQUENCER_435 0x11B3
+#define WM8962_WRITE_SEQUENCER_436 0x11B4
+#define WM8962_WRITE_SEQUENCER_437 0x11B5
+#define WM8962_WRITE_SEQUENCER_438 0x11B6
+#define WM8962_WRITE_SEQUENCER_439 0x11B7
+#define WM8962_WRITE_SEQUENCER_440 0x11B8
+#define WM8962_WRITE_SEQUENCER_441 0x11B9
+#define WM8962_WRITE_SEQUENCER_442 0x11BA
+#define WM8962_WRITE_SEQUENCER_443 0x11BB
+#define WM8962_WRITE_SEQUENCER_444 0x11BC
+#define WM8962_WRITE_SEQUENCER_445 0x11BD
+#define WM8962_WRITE_SEQUENCER_446 0x11BE
+#define WM8962_WRITE_SEQUENCER_447 0x11BF
+#define WM8962_WRITE_SEQUENCER_448 0x11C0
+#define WM8962_WRITE_SEQUENCER_449 0x11C1
+#define WM8962_WRITE_SEQUENCER_450 0x11C2
+#define WM8962_WRITE_SEQUENCER_451 0x11C3
+#define WM8962_WRITE_SEQUENCER_452 0x11C4
+#define WM8962_WRITE_SEQUENCER_453 0x11C5
+#define WM8962_WRITE_SEQUENCER_454 0x11C6
+#define WM8962_WRITE_SEQUENCER_455 0x11C7
+#define WM8962_WRITE_SEQUENCER_456 0x11C8
+#define WM8962_WRITE_SEQUENCER_457 0x11C9
+#define WM8962_WRITE_SEQUENCER_458 0x11CA
+#define WM8962_WRITE_SEQUENCER_459 0x11CB
+#define WM8962_WRITE_SEQUENCER_460 0x11CC
+#define WM8962_WRITE_SEQUENCER_461 0x11CD
+#define WM8962_WRITE_SEQUENCER_462 0x11CE
+#define WM8962_WRITE_SEQUENCER_463 0x11CF
+#define WM8962_WRITE_SEQUENCER_464 0x11D0
+#define WM8962_WRITE_SEQUENCER_465 0x11D1
+#define WM8962_WRITE_SEQUENCER_466 0x11D2
+#define WM8962_WRITE_SEQUENCER_467 0x11D3
+#define WM8962_WRITE_SEQUENCER_468 0x11D4
+#define WM8962_WRITE_SEQUENCER_469 0x11D5
+#define WM8962_WRITE_SEQUENCER_470 0x11D6
+#define WM8962_WRITE_SEQUENCER_471 0x11D7
+#define WM8962_WRITE_SEQUENCER_472 0x11D8
+#define WM8962_WRITE_SEQUENCER_473 0x11D9
+#define WM8962_WRITE_SEQUENCER_474 0x11DA
+#define WM8962_WRITE_SEQUENCER_475 0x11DB
+#define WM8962_WRITE_SEQUENCER_476 0x11DC
+#define WM8962_WRITE_SEQUENCER_477 0x11DD
+#define WM8962_WRITE_SEQUENCER_478 0x11DE
+#define WM8962_WRITE_SEQUENCER_479 0x11DF
+#define WM8962_WRITE_SEQUENCER_480 0x11E0
+#define WM8962_WRITE_SEQUENCER_481 0x11E1
+#define WM8962_WRITE_SEQUENCER_482 0x11E2
+#define WM8962_WRITE_SEQUENCER_483 0x11E3
+#define WM8962_WRITE_SEQUENCER_484 0x11E4
+#define WM8962_WRITE_SEQUENCER_485 0x11E5
+#define WM8962_WRITE_SEQUENCER_486 0x11E6
+#define WM8962_WRITE_SEQUENCER_487 0x11E7
+#define WM8962_WRITE_SEQUENCER_488 0x11E8
+#define WM8962_WRITE_SEQUENCER_489 0x11E9
+#define WM8962_WRITE_SEQUENCER_490 0x11EA
+#define WM8962_WRITE_SEQUENCER_491 0x11EB
+#define WM8962_WRITE_SEQUENCER_492 0x11EC
+#define WM8962_WRITE_SEQUENCER_493 0x11ED
+#define WM8962_WRITE_SEQUENCER_494 0x11EE
+#define WM8962_WRITE_SEQUENCER_495 0x11EF
+#define WM8962_WRITE_SEQUENCER_496 0x11F0
+#define WM8962_WRITE_SEQUENCER_497 0x11F1
+#define WM8962_WRITE_SEQUENCER_498 0x11F2
+#define WM8962_WRITE_SEQUENCER_499 0x11F3
+#define WM8962_WRITE_SEQUENCER_500 0x11F4
+#define WM8962_WRITE_SEQUENCER_501 0x11F5
+#define WM8962_WRITE_SEQUENCER_502 0x11F6
+#define WM8962_WRITE_SEQUENCER_503 0x11F7
+#define WM8962_WRITE_SEQUENCER_504 0x11F8
+#define WM8962_WRITE_SEQUENCER_505 0x11F9
+#define WM8962_WRITE_SEQUENCER_506 0x11FA
+#define WM8962_WRITE_SEQUENCER_507 0x11FB
+#define WM8962_WRITE_SEQUENCER_508 0x11FC
+#define WM8962_WRITE_SEQUENCER_509 0x11FD
+#define WM8962_WRITE_SEQUENCER_510 0x11FE
+#define WM8962_WRITE_SEQUENCER_511 0x11FF
+#define WM8962_DSP2_INSTRUCTION_RAM_0 0x2000
+#define WM8962_DSP2_ADDRESS_RAM_2 0x2400
+#define WM8962_DSP2_ADDRESS_RAM_1 0x2401
+#define WM8962_DSP2_ADDRESS_RAM_0 0x2402
+#define WM8962_DSP2_DATA1_RAM_1 0x3000
+#define WM8962_DSP2_DATA1_RAM_0 0x3001
+#define WM8962_DSP2_DATA2_RAM_1 0x3400
+#define WM8962_DSP2_DATA2_RAM_0 0x3401
+#define WM8962_DSP2_DATA3_RAM_1 0x3800
+#define WM8962_DSP2_DATA3_RAM_0 0x3801
+#define WM8962_DSP2_COEFF_RAM_0 0x3C00
+#define WM8962_RETUNEADC_SHARED_COEFF_1 0x4000
+#define WM8962_RETUNEADC_SHARED_COEFF_0 0x4001
+#define WM8962_RETUNEDAC_SHARED_COEFF_1 0x4002
+#define WM8962_RETUNEDAC_SHARED_COEFF_0 0x4003
+#define WM8962_SOUNDSTAGE_ENABLES_1 0x4004
+#define WM8962_SOUNDSTAGE_ENABLES_0 0x4005
+#define WM8962_HDBASS_AI_1 0x4200
+#define WM8962_HDBASS_AI_0 0x4201
+#define WM8962_HDBASS_AR_1 0x4202
+#define WM8962_HDBASS_AR_0 0x4203
+#define WM8962_HDBASS_B_1 0x4204
+#define WM8962_HDBASS_B_0 0x4205
+#define WM8962_HDBASS_K_1 0x4206
+#define WM8962_HDBASS_K_0 0x4207
+#define WM8962_HDBASS_N1_1 0x4208
+#define WM8962_HDBASS_N1_0 0x4209
+#define WM8962_HDBASS_N2_1 0x420A
+#define WM8962_HDBASS_N2_0 0x420B
+#define WM8962_HDBASS_N3_1 0x420C
+#define WM8962_HDBASS_N3_0 0x420D
+#define WM8962_HDBASS_N4_1 0x420E
+#define WM8962_HDBASS_N4_0 0x420F
+#define WM8962_HDBASS_N5_1 0x4210
+#define WM8962_HDBASS_N5_0 0x4211
+#define WM8962_HDBASS_X1_1 0x4212
+#define WM8962_HDBASS_X1_0 0x4213
+#define WM8962_HDBASS_X2_1 0x4214
+#define WM8962_HDBASS_X2_0 0x4215
+#define WM8962_HDBASS_X3_1 0x4216
+#define WM8962_HDBASS_X3_0 0x4217
+#define WM8962_HDBASS_ATK_1 0x4218
+#define WM8962_HDBASS_ATK_0 0x4219
+#define WM8962_HDBASS_DCY_1 0x421A
+#define WM8962_HDBASS_DCY_0 0x421B
+#define WM8962_HDBASS_PG_1 0x421C
+#define WM8962_HDBASS_PG_0 0x421D
+#define WM8962_HPF_C_1 0x4400
+#define WM8962_HPF_C_0 0x4401
+#define WM8962_ADCL_RETUNE_C1_1 0x4600
+#define WM8962_ADCL_RETUNE_C1_0 0x4601
+#define WM8962_ADCL_RETUNE_C2_1 0x4602
+#define WM8962_ADCL_RETUNE_C2_0 0x4603
+#define WM8962_ADCL_RETUNE_C3_1 0x4604
+#define WM8962_ADCL_RETUNE_C3_0 0x4605
+#define WM8962_ADCL_RETUNE_C4_1 0x4606
+#define WM8962_ADCL_RETUNE_C4_0 0x4607
+#define WM8962_ADCL_RETUNE_C5_1 0x4608
+#define WM8962_ADCL_RETUNE_C5_0 0x4609
+#define WM8962_ADCL_RETUNE_C6_1 0x460A
+#define WM8962_ADCL_RETUNE_C6_0 0x460B
+#define WM8962_ADCL_RETUNE_C7_1 0x460C
+#define WM8962_ADCL_RETUNE_C7_0 0x460D
+#define WM8962_ADCL_RETUNE_C8_1 0x460E
+#define WM8962_ADCL_RETUNE_C8_0 0x460F
+#define WM8962_ADCL_RETUNE_C9_1 0x4610
+#define WM8962_ADCL_RETUNE_C9_0 0x4611
+#define WM8962_ADCL_RETUNE_C10_1 0x4612
+#define WM8962_ADCL_RETUNE_C10_0 0x4613
+#define WM8962_ADCL_RETUNE_C11_1 0x4614
+#define WM8962_ADCL_RETUNE_C11_0 0x4615
+#define WM8962_ADCL_RETUNE_C12_1 0x4616
+#define WM8962_ADCL_RETUNE_C12_0 0x4617
+#define WM8962_ADCL_RETUNE_C13_1 0x4618
+#define WM8962_ADCL_RETUNE_C13_0 0x4619
+#define WM8962_ADCL_RETUNE_C14_1 0x461A
+#define WM8962_ADCL_RETUNE_C14_0 0x461B
+#define WM8962_ADCL_RETUNE_C15_1 0x461C
+#define WM8962_ADCL_RETUNE_C15_0 0x461D
+#define WM8962_ADCL_RETUNE_C16_1 0x461E
+#define WM8962_ADCL_RETUNE_C16_0 0x461F
+#define WM8962_ADCL_RETUNE_C17_1 0x4620
+#define WM8962_ADCL_RETUNE_C17_0 0x4621
+#define WM8962_ADCL_RETUNE_C18_1 0x4622
+#define WM8962_ADCL_RETUNE_C18_0 0x4623
+#define WM8962_ADCL_RETUNE_C19_1 0x4624
+#define WM8962_ADCL_RETUNE_C19_0 0x4625
+#define WM8962_ADCL_RETUNE_C20_1 0x4626
+#define WM8962_ADCL_RETUNE_C20_0 0x4627
+#define WM8962_ADCL_RETUNE_C21_1 0x4628
+#define WM8962_ADCL_RETUNE_C21_0 0x4629
+#define WM8962_ADCL_RETUNE_C22_1 0x462A
+#define WM8962_ADCL_RETUNE_C22_0 0x462B
+#define WM8962_ADCL_RETUNE_C23_1 0x462C
+#define WM8962_ADCL_RETUNE_C23_0 0x462D
+#define WM8962_ADCL_RETUNE_C24_1 0x462E
+#define WM8962_ADCL_RETUNE_C24_0 0x462F
+#define WM8962_ADCL_RETUNE_C25_1 0x4630
+#define WM8962_ADCL_RETUNE_C25_0 0x4631
+#define WM8962_ADCL_RETUNE_C26_1 0x4632
+#define WM8962_ADCL_RETUNE_C26_0 0x4633
+#define WM8962_ADCL_RETUNE_C27_1 0x4634
+#define WM8962_ADCL_RETUNE_C27_0 0x4635
+#define WM8962_ADCL_RETUNE_C28_1 0x4636
+#define WM8962_ADCL_RETUNE_C28_0 0x4637
+#define WM8962_ADCL_RETUNE_C29_1 0x4638
+#define WM8962_ADCL_RETUNE_C29_0 0x4639
+#define WM8962_ADCL_RETUNE_C30_1 0x463A
+#define WM8962_ADCL_RETUNE_C30_0 0x463B
+#define WM8962_ADCL_RETUNE_C31_1 0x463C
+#define WM8962_ADCL_RETUNE_C31_0 0x463D
+#define WM8962_ADCL_RETUNE_C32_1 0x463E
+#define WM8962_ADCL_RETUNE_C32_0 0x463F
+#define WM8962_RETUNEADC_PG2_1 0x4800
+#define WM8962_RETUNEADC_PG2_0 0x4801
+#define WM8962_RETUNEADC_PG_1 0x4802
+#define WM8962_RETUNEADC_PG_0 0x4803
+#define WM8962_ADCR_RETUNE_C1_1 0x4A00
+#define WM8962_ADCR_RETUNE_C1_0 0x4A01
+#define WM8962_ADCR_RETUNE_C2_1 0x4A02
+#define WM8962_ADCR_RETUNE_C2_0 0x4A03
+#define WM8962_ADCR_RETUNE_C3_1 0x4A04
+#define WM8962_ADCR_RETUNE_C3_0 0x4A05
+#define WM8962_ADCR_RETUNE_C4_1 0x4A06
+#define WM8962_ADCR_RETUNE_C4_0 0x4A07
+#define WM8962_ADCR_RETUNE_C5_1 0x4A08
+#define WM8962_ADCR_RETUNE_C5_0 0x4A09
+#define WM8962_ADCR_RETUNE_C6_1 0x4A0A
+#define WM8962_ADCR_RETUNE_C6_0 0x4A0B
+#define WM8962_ADCR_RETUNE_C7_1 0x4A0C
+#define WM8962_ADCR_RETUNE_C7_0 0x4A0D
+#define WM8962_ADCR_RETUNE_C8_1 0x4A0E
+#define WM8962_ADCR_RETUNE_C8_0 0x4A0F
+#define WM8962_ADCR_RETUNE_C9_1 0x4A10
+#define WM8962_ADCR_RETUNE_C9_0 0x4A11
+#define WM8962_ADCR_RETUNE_C10_1 0x4A12
+#define WM8962_ADCR_RETUNE_C10_0 0x4A13
+#define WM8962_ADCR_RETUNE_C11_1 0x4A14
+#define WM8962_ADCR_RETUNE_C11_0 0x4A15
+#define WM8962_ADCR_RETUNE_C12_1 0x4A16
+#define WM8962_ADCR_RETUNE_C12_0 0x4A17
+#define WM8962_ADCR_RETUNE_C13_1 0x4A18
+#define WM8962_ADCR_RETUNE_C13_0 0x4A19
+#define WM8962_ADCR_RETUNE_C14_1 0x4A1A
+#define WM8962_ADCR_RETUNE_C14_0 0x4A1B
+#define WM8962_ADCR_RETUNE_C15_1 0x4A1C
+#define WM8962_ADCR_RETUNE_C15_0 0x4A1D
+#define WM8962_ADCR_RETUNE_C16_1 0x4A1E
+#define WM8962_ADCR_RETUNE_C16_0 0x4A1F
+#define WM8962_ADCR_RETUNE_C17_1 0x4A20
+#define WM8962_ADCR_RETUNE_C17_0 0x4A21
+#define WM8962_ADCR_RETUNE_C18_1 0x4A22
+#define WM8962_ADCR_RETUNE_C18_0 0x4A23
+#define WM8962_ADCR_RETUNE_C19_1 0x4A24
+#define WM8962_ADCR_RETUNE_C19_0 0x4A25
+#define WM8962_ADCR_RETUNE_C20_1 0x4A26
+#define WM8962_ADCR_RETUNE_C20_0 0x4A27
+#define WM8962_ADCR_RETUNE_C21_1 0x4A28
+#define WM8962_ADCR_RETUNE_C21_0 0x4A29
+#define WM8962_ADCR_RETUNE_C22_1 0x4A2A
+#define WM8962_ADCR_RETUNE_C22_0 0x4A2B
+#define WM8962_ADCR_RETUNE_C23_1 0x4A2C
+#define WM8962_ADCR_RETUNE_C23_0 0x4A2D
+#define WM8962_ADCR_RETUNE_C24_1 0x4A2E
+#define WM8962_ADCR_RETUNE_C24_0 0x4A2F
+#define WM8962_ADCR_RETUNE_C25_1 0x4A30
+#define WM8962_ADCR_RETUNE_C25_0 0x4A31
+#define WM8962_ADCR_RETUNE_C26_1 0x4A32
+#define WM8962_ADCR_RETUNE_C26_0 0x4A33
+#define WM8962_ADCR_RETUNE_C27_1 0x4A34
+#define WM8962_ADCR_RETUNE_C27_0 0x4A35
+#define WM8962_ADCR_RETUNE_C28_1 0x4A36
+#define WM8962_ADCR_RETUNE_C28_0 0x4A37
+#define WM8962_ADCR_RETUNE_C29_1 0x4A38
+#define WM8962_ADCR_RETUNE_C29_0 0x4A39
+#define WM8962_ADCR_RETUNE_C30_1 0x4A3A
+#define WM8962_ADCR_RETUNE_C30_0 0x4A3B
+#define WM8962_ADCR_RETUNE_C31_1 0x4A3C
+#define WM8962_ADCR_RETUNE_C31_0 0x4A3D
+#define WM8962_ADCR_RETUNE_C32_1 0x4A3E
+#define WM8962_ADCR_RETUNE_C32_0 0x4A3F
+#define WM8962_DACL_RETUNE_C1_1 0x4C00
+#define WM8962_DACL_RETUNE_C1_0 0x4C01
+#define WM8962_DACL_RETUNE_C2_1 0x4C02
+#define WM8962_DACL_RETUNE_C2_0 0x4C03
+#define WM8962_DACL_RETUNE_C3_1 0x4C04
+#define WM8962_DACL_RETUNE_C3_0 0x4C05
+#define WM8962_DACL_RETUNE_C4_1 0x4C06
+#define WM8962_DACL_RETUNE_C4_0 0x4C07
+#define WM8962_DACL_RETUNE_C5_1 0x4C08
+#define WM8962_DACL_RETUNE_C5_0 0x4C09
+#define WM8962_DACL_RETUNE_C6_1 0x4C0A
+#define WM8962_DACL_RETUNE_C6_0 0x4C0B
+#define WM8962_DACL_RETUNE_C7_1 0x4C0C
+#define WM8962_DACL_RETUNE_C7_0 0x4C0D
+#define WM8962_DACL_RETUNE_C8_1 0x4C0E
+#define WM8962_DACL_RETUNE_C8_0 0x4C0F
+#define WM8962_DACL_RETUNE_C9_1 0x4C10
+#define WM8962_DACL_RETUNE_C9_0 0x4C11
+#define WM8962_DACL_RETUNE_C10_1 0x4C12
+#define WM8962_DACL_RETUNE_C10_0 0x4C13
+#define WM8962_DACL_RETUNE_C11_1 0x4C14
+#define WM8962_DACL_RETUNE_C11_0 0x4C15
+#define WM8962_DACL_RETUNE_C12_1 0x4C16
+#define WM8962_DACL_RETUNE_C12_0 0x4C17
+#define WM8962_DACL_RETUNE_C13_1 0x4C18
+#define WM8962_DACL_RETUNE_C13_0 0x4C19
+#define WM8962_DACL_RETUNE_C14_1 0x4C1A
+#define WM8962_DACL_RETUNE_C14_0 0x4C1B
+#define WM8962_DACL_RETUNE_C15_1 0x4C1C
+#define WM8962_DACL_RETUNE_C15_0 0x4C1D
+#define WM8962_DACL_RETUNE_C16_1 0x4C1E
+#define WM8962_DACL_RETUNE_C16_0 0x4C1F
+#define WM8962_DACL_RETUNE_C17_1 0x4C20
+#define WM8962_DACL_RETUNE_C17_0 0x4C21
+#define WM8962_DACL_RETUNE_C18_1 0x4C22
+#define WM8962_DACL_RETUNE_C18_0 0x4C23
+#define WM8962_DACL_RETUNE_C19_1 0x4C24
+#define WM8962_DACL_RETUNE_C19_0 0x4C25
+#define WM8962_DACL_RETUNE_C20_1 0x4C26
+#define WM8962_DACL_RETUNE_C20_0 0x4C27
+#define WM8962_DACL_RETUNE_C21_1 0x4C28
+#define WM8962_DACL_RETUNE_C21_0 0x4C29
+#define WM8962_DACL_RETUNE_C22_1 0x4C2A
+#define WM8962_DACL_RETUNE_C22_0 0x4C2B
+#define WM8962_DACL_RETUNE_C23_1 0x4C2C
+#define WM8962_DACL_RETUNE_C23_0 0x4C2D
+#define WM8962_DACL_RETUNE_C24_1 0x4C2E
+#define WM8962_DACL_RETUNE_C24_0 0x4C2F
+#define WM8962_DACL_RETUNE_C25_1 0x4C30
+#define WM8962_DACL_RETUNE_C25_0 0x4C31
+#define WM8962_DACL_RETUNE_C26_1 0x4C32
+#define WM8962_DACL_RETUNE_C26_0 0x4C33
+#define WM8962_DACL_RETUNE_C27_1 0x4C34
+#define WM8962_DACL_RETUNE_C27_0 0x4C35
+#define WM8962_DACL_RETUNE_C28_1 0x4C36
+#define WM8962_DACL_RETUNE_C28_0 0x4C37
+#define WM8962_DACL_RETUNE_C29_1 0x4C38
+#define WM8962_DACL_RETUNE_C29_0 0x4C39
+#define WM8962_DACL_RETUNE_C30_1 0x4C3A
+#define WM8962_DACL_RETUNE_C30_0 0x4C3B
+#define WM8962_DACL_RETUNE_C31_1 0x4C3C
+#define WM8962_DACL_RETUNE_C31_0 0x4C3D
+#define WM8962_DACL_RETUNE_C32_1 0x4C3E
+#define WM8962_DACL_RETUNE_C32_0 0x4C3F
+#define WM8962_RETUNEDAC_PG2_1 0x4E00
+#define WM8962_RETUNEDAC_PG2_0 0x4E01
+#define WM8962_RETUNEDAC_PG_1 0x4E02
+#define WM8962_RETUNEDAC_PG_0 0x4E03
+#define WM8962_DACR_RETUNE_C1_1 0x5000
+#define WM8962_DACR_RETUNE_C1_0 0x5001
+#define WM8962_DACR_RETUNE_C2_1 0x5002
+#define WM8962_DACR_RETUNE_C2_0 0x5003
+#define WM8962_DACR_RETUNE_C3_1 0x5004
+#define WM8962_DACR_RETUNE_C3_0 0x5005
+#define WM8962_DACR_RETUNE_C4_1 0x5006
+#define WM8962_DACR_RETUNE_C4_0 0x5007
+#define WM8962_DACR_RETUNE_C5_1 0x5008
+#define WM8962_DACR_RETUNE_C5_0 0x5009
+#define WM8962_DACR_RETUNE_C6_1 0x500A
+#define WM8962_DACR_RETUNE_C6_0 0x500B
+#define WM8962_DACR_RETUNE_C7_1 0x500C
+#define WM8962_DACR_RETUNE_C7_0 0x500D
+#define WM8962_DACR_RETUNE_C8_1 0x500E
+#define WM8962_DACR_RETUNE_C8_0 0x500F
+#define WM8962_DACR_RETUNE_C9_1 0x5010
+#define WM8962_DACR_RETUNE_C9_0 0x5011
+#define WM8962_DACR_RETUNE_C10_1 0x5012
+#define WM8962_DACR_RETUNE_C10_0 0x5013
+#define WM8962_DACR_RETUNE_C11_1 0x5014
+#define WM8962_DACR_RETUNE_C11_0 0x5015
+#define WM8962_DACR_RETUNE_C12_1 0x5016
+#define WM8962_DACR_RETUNE_C12_0 0x5017
+#define WM8962_DACR_RETUNE_C13_1 0x5018
+#define WM8962_DACR_RETUNE_C13_0 0x5019
+#define WM8962_DACR_RETUNE_C14_1 0x501A
+#define WM8962_DACR_RETUNE_C14_0 0x501B
+#define WM8962_DACR_RETUNE_C15_1 0x501C
+#define WM8962_DACR_RETUNE_C15_0 0x501D
+#define WM8962_DACR_RETUNE_C16_1 0x501E
+#define WM8962_DACR_RETUNE_C16_0 0x501F
+#define WM8962_DACR_RETUNE_C17_1 0x5020
+#define WM8962_DACR_RETUNE_C17_0 0x5021
+#define WM8962_DACR_RETUNE_C18_1 0x5022
+#define WM8962_DACR_RETUNE_C18_0 0x5023
+#define WM8962_DACR_RETUNE_C19_1 0x5024
+#define WM8962_DACR_RETUNE_C19_0 0x5025
+#define WM8962_DACR_RETUNE_C20_1 0x5026
+#define WM8962_DACR_RETUNE_C20_0 0x5027
+#define WM8962_DACR_RETUNE_C21_1 0x5028
+#define WM8962_DACR_RETUNE_C21_0 0x5029
+#define WM8962_DACR_RETUNE_C22_1 0x502A
+#define WM8962_DACR_RETUNE_C22_0 0x502B
+#define WM8962_DACR_RETUNE_C23_1 0x502C
+#define WM8962_DACR_RETUNE_C23_0 0x502D
+#define WM8962_DACR_RETUNE_C24_1 0x502E
+#define WM8962_DACR_RETUNE_C24_0 0x502F
+#define WM8962_DACR_RETUNE_C25_1 0x5030
+#define WM8962_DACR_RETUNE_C25_0 0x5031
+#define WM8962_DACR_RETUNE_C26_1 0x5032
+#define WM8962_DACR_RETUNE_C26_0 0x5033
+#define WM8962_DACR_RETUNE_C27_1 0x5034
+#define WM8962_DACR_RETUNE_C27_0 0x5035
+#define WM8962_DACR_RETUNE_C28_1 0x5036
+#define WM8962_DACR_RETUNE_C28_0 0x5037
+#define WM8962_DACR_RETUNE_C29_1 0x5038
+#define WM8962_DACR_RETUNE_C29_0 0x5039
+#define WM8962_DACR_RETUNE_C30_1 0x503A
+#define WM8962_DACR_RETUNE_C30_0 0x503B
+#define WM8962_DACR_RETUNE_C31_1 0x503C
+#define WM8962_DACR_RETUNE_C31_0 0x503D
+#define WM8962_DACR_RETUNE_C32_1 0x503E
+#define WM8962_DACR_RETUNE_C32_0 0x503F
+#define WM8962_VSS_XHD2_1 0x5200
+#define WM8962_VSS_XHD2_0 0x5201
+#define WM8962_VSS_XHD3_1 0x5202
+#define WM8962_VSS_XHD3_0 0x5203
+#define WM8962_VSS_XHN1_1 0x5204
+#define WM8962_VSS_XHN1_0 0x5205
+#define WM8962_VSS_XHN2_1 0x5206
+#define WM8962_VSS_XHN2_0 0x5207
+#define WM8962_VSS_XHN3_1 0x5208
+#define WM8962_VSS_XHN3_0 0x5209
+#define WM8962_VSS_XLA_1 0x520A
+#define WM8962_VSS_XLA_0 0x520B
+#define WM8962_VSS_XLB_1 0x520C
+#define WM8962_VSS_XLB_0 0x520D
+#define WM8962_VSS_XLG_1 0x520E
+#define WM8962_VSS_XLG_0 0x520F
+#define WM8962_VSS_PG2_1 0x5210
+#define WM8962_VSS_PG2_0 0x5211
+#define WM8962_VSS_PG_1 0x5212
+#define WM8962_VSS_PG_0 0x5213
+#define WM8962_VSS_XTD1_1 0x5214
+#define WM8962_VSS_XTD1_0 0x5215
+#define WM8962_VSS_XTD2_1 0x5216
+#define WM8962_VSS_XTD2_0 0x5217
+#define WM8962_VSS_XTD3_1 0x5218
+#define WM8962_VSS_XTD3_0 0x5219
+#define WM8962_VSS_XTD4_1 0x521A
+#define WM8962_VSS_XTD4_0 0x521B
+#define WM8962_VSS_XTD5_1 0x521C
+#define WM8962_VSS_XTD5_0 0x521D
+#define WM8962_VSS_XTD6_1 0x521E
+#define WM8962_VSS_XTD6_0 0x521F
+#define WM8962_VSS_XTD7_1 0x5220
+#define WM8962_VSS_XTD7_0 0x5221
+#define WM8962_VSS_XTD8_1 0x5222
+#define WM8962_VSS_XTD8_0 0x5223
+#define WM8962_VSS_XTD9_1 0x5224
+#define WM8962_VSS_XTD9_0 0x5225
+#define WM8962_VSS_XTD10_1 0x5226
+#define WM8962_VSS_XTD10_0 0x5227
+#define WM8962_VSS_XTD11_1 0x5228
+#define WM8962_VSS_XTD11_0 0x5229
+#define WM8962_VSS_XTD12_1 0x522A
+#define WM8962_VSS_XTD12_0 0x522B
+#define WM8962_VSS_XTD13_1 0x522C
+#define WM8962_VSS_XTD13_0 0x522D
+#define WM8962_VSS_XTD14_1 0x522E
+#define WM8962_VSS_XTD14_0 0x522F
+#define WM8962_VSS_XTD15_1 0x5230
+#define WM8962_VSS_XTD15_0 0x5231
+#define WM8962_VSS_XTD16_1 0x5232
+#define WM8962_VSS_XTD16_0 0x5233
+#define WM8962_VSS_XTD17_1 0x5234
+#define WM8962_VSS_XTD17_0 0x5235
+#define WM8962_VSS_XTD18_1 0x5236
+#define WM8962_VSS_XTD18_0 0x5237
+#define WM8962_VSS_XTD19_1 0x5238
+#define WM8962_VSS_XTD19_0 0x5239
+#define WM8962_VSS_XTD20_1 0x523A
+#define WM8962_VSS_XTD20_0 0x523B
+#define WM8962_VSS_XTD21_1 0x523C
+#define WM8962_VSS_XTD21_0 0x523D
+#define WM8962_VSS_XTD22_1 0x523E
+#define WM8962_VSS_XTD22_0 0x523F
+#define WM8962_VSS_XTD23_1 0x5240
+#define WM8962_VSS_XTD23_0 0x5241
+#define WM8962_VSS_XTD24_1 0x5242
+#define WM8962_VSS_XTD24_0 0x5243
+#define WM8962_VSS_XTD25_1 0x5244
+#define WM8962_VSS_XTD25_0 0x5245
+#define WM8962_VSS_XTD26_1 0x5246
+#define WM8962_VSS_XTD26_0 0x5247
+#define WM8962_VSS_XTD27_1 0x5248
+#define WM8962_VSS_XTD27_0 0x5249
+#define WM8962_VSS_XTD28_1 0x524A
+#define WM8962_VSS_XTD28_0 0x524B
+#define WM8962_VSS_XTD29_1 0x524C
+#define WM8962_VSS_XTD29_0 0x524D
+#define WM8962_VSS_XTD30_1 0x524E
+#define WM8962_VSS_XTD30_0 0x524F
+#define WM8962_VSS_XTD31_1 0x5250
+#define WM8962_VSS_XTD31_0 0x5251
+#define WM8962_VSS_XTD32_1 0x5252
+#define WM8962_VSS_XTD32_0 0x5253
+#define WM8962_VSS_XTS1_1 0x5254
+#define WM8962_VSS_XTS1_0 0x5255
+#define WM8962_VSS_XTS2_1 0x5256
+#define WM8962_VSS_XTS2_0 0x5257
+#define WM8962_VSS_XTS3_1 0x5258
+#define WM8962_VSS_XTS3_0 0x5259
+#define WM8962_VSS_XTS4_1 0x525A
+#define WM8962_VSS_XTS4_0 0x525B
+#define WM8962_VSS_XTS5_1 0x525C
+#define WM8962_VSS_XTS5_0 0x525D
+#define WM8962_VSS_XTS6_1 0x525E
+#define WM8962_VSS_XTS6_0 0x525F
+#define WM8962_VSS_XTS7_1 0x5260
+#define WM8962_VSS_XTS7_0 0x5261
+#define WM8962_VSS_XTS8_1 0x5262
+#define WM8962_VSS_XTS8_0 0x5263
+#define WM8962_VSS_XTS9_1 0x5264
+#define WM8962_VSS_XTS9_0 0x5265
+#define WM8962_VSS_XTS10_1 0x5266
+#define WM8962_VSS_XTS10_0 0x5267
+#define WM8962_VSS_XTS11_1 0x5268
+#define WM8962_VSS_XTS11_0 0x5269
+#define WM8962_VSS_XTS12_1 0x526A
+#define WM8962_VSS_XTS12_0 0x526B
+#define WM8962_VSS_XTS13_1 0x526C
+#define WM8962_VSS_XTS13_0 0x526D
+#define WM8962_VSS_XTS14_1 0x526E
+#define WM8962_VSS_XTS14_0 0x526F
+#define WM8962_VSS_XTS15_1 0x5270
+#define WM8962_VSS_XTS15_0 0x5271
+#define WM8962_VSS_XTS16_1 0x5272
+#define WM8962_VSS_XTS16_0 0x5273
+#define WM8962_VSS_XTS17_1 0x5274
+#define WM8962_VSS_XTS17_0 0x5275
+#define WM8962_VSS_XTS18_1 0x5276
+#define WM8962_VSS_XTS18_0 0x5277
+#define WM8962_VSS_XTS19_1 0x5278
+#define WM8962_VSS_XTS19_0 0x5279
+#define WM8962_VSS_XTS20_1 0x527A
+#define WM8962_VSS_XTS20_0 0x527B
+#define WM8962_VSS_XTS21_1 0x527C
+#define WM8962_VSS_XTS21_0 0x527D
+#define WM8962_VSS_XTS22_1 0x527E
+#define WM8962_VSS_XTS22_0 0x527F
+#define WM8962_VSS_XTS23_1 0x5280
+#define WM8962_VSS_XTS23_0 0x5281
+#define WM8962_VSS_XTS24_1 0x5282
+#define WM8962_VSS_XTS24_0 0x5283
+#define WM8962_VSS_XTS25_1 0x5284
+#define WM8962_VSS_XTS25_0 0x5285
+#define WM8962_VSS_XTS26_1 0x5286
+#define WM8962_VSS_XTS26_0 0x5287
+#define WM8962_VSS_XTS27_1 0x5288
+#define WM8962_VSS_XTS27_0 0x5289
+#define WM8962_VSS_XTS28_1 0x528A
+#define WM8962_VSS_XTS28_0 0x528B
+#define WM8962_VSS_XTS29_1 0x528C
+#define WM8962_VSS_XTS29_0 0x528D
+#define WM8962_VSS_XTS30_1 0x528E
+#define WM8962_VSS_XTS30_0 0x528F
+#define WM8962_VSS_XTS31_1 0x5290
+#define WM8962_VSS_XTS31_0 0x5291
+#define WM8962_VSS_XTS32_1 0x5292
+#define WM8962_VSS_XTS32_0 0x5293
+
+#define WM8962_REGISTER_COUNT 1138
+#define WM8962_MAX_REGISTER 0x5293
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Left Input volume
+ */
+#define WM8962_IN_VU 0x0100 /* IN_VU */
+#define WM8962_IN_VU_MASK 0x0100 /* IN_VU */
+#define WM8962_IN_VU_SHIFT 8 /* IN_VU */
+#define WM8962_IN_VU_WIDTH 1 /* IN_VU */
+#define WM8962_INPGAL_MUTE 0x0080 /* INPGAL_MUTE */
+#define WM8962_INPGAL_MUTE_MASK 0x0080 /* INPGAL_MUTE */
+#define WM8962_INPGAL_MUTE_SHIFT 7 /* INPGAL_MUTE */
+#define WM8962_INPGAL_MUTE_WIDTH 1 /* INPGAL_MUTE */
+#define WM8962_INL_ZC 0x0040 /* INL_ZC */
+#define WM8962_INL_ZC_MASK 0x0040 /* INL_ZC */
+#define WM8962_INL_ZC_SHIFT 6 /* INL_ZC */
+#define WM8962_INL_ZC_WIDTH 1 /* INL_ZC */
+#define WM8962_INL_VOL_MASK 0x003F /* INL_VOL - [5:0] */
+#define WM8962_INL_VOL_SHIFT 0 /* INL_VOL - [5:0] */
+#define WM8962_INL_VOL_WIDTH 6 /* INL_VOL - [5:0] */
+
+/*
+ * R1 (0x01) - Right Input volume
+ */
+#define WM8962_CUST_ID_MASK 0xF000 /* CUST_ID - [15:12] */
+#define WM8962_CUST_ID_SHIFT 12 /* CUST_ID - [15:12] */
+#define WM8962_CUST_ID_WIDTH 4 /* CUST_ID - [15:12] */
+#define WM8962_CHIP_REV_MASK 0x0E00 /* CHIP_REV - [11:9] */
+#define WM8962_CHIP_REV_SHIFT 9 /* CHIP_REV - [11:9] */
+#define WM8962_CHIP_REV_WIDTH 3 /* CHIP_REV - [11:9] */
+#define WM8962_IN_VU 0x0100 /* IN_VU */
+#define WM8962_IN_VU_MASK 0x0100 /* IN_VU */
+#define WM8962_IN_VU_SHIFT 8 /* IN_VU */
+#define WM8962_IN_VU_WIDTH 1 /* IN_VU */
+#define WM8962_INPGAR_MUTE 0x0080 /* INPGAR_MUTE */
+#define WM8962_INPGAR_MUTE_MASK 0x0080 /* INPGAR_MUTE */
+#define WM8962_INPGAR_MUTE_SHIFT 7 /* INPGAR_MUTE */
+#define WM8962_INPGAR_MUTE_WIDTH 1 /* INPGAR_MUTE */
+#define WM8962_INR_ZC 0x0040 /* INR_ZC */
+#define WM8962_INR_ZC_MASK 0x0040 /* INR_ZC */
+#define WM8962_INR_ZC_SHIFT 6 /* INR_ZC */
+#define WM8962_INR_ZC_WIDTH 1 /* INR_ZC */
+#define WM8962_INR_VOL_MASK 0x003F /* INR_VOL - [5:0] */
+#define WM8962_INR_VOL_SHIFT 0 /* INR_VOL - [5:0] */
+#define WM8962_INR_VOL_WIDTH 6 /* INR_VOL - [5:0] */
+
+/*
+ * R2 (0x02) - HPOUTL volume
+ */
+#define WM8962_HPOUT_VU 0x0100 /* HPOUT_VU */
+#define WM8962_HPOUT_VU_MASK 0x0100 /* HPOUT_VU */
+#define WM8962_HPOUT_VU_SHIFT 8 /* HPOUT_VU */
+#define WM8962_HPOUT_VU_WIDTH 1 /* HPOUT_VU */
+#define WM8962_HPOUTL_ZC 0x0080 /* HPOUTL_ZC */
+#define WM8962_HPOUTL_ZC_MASK 0x0080 /* HPOUTL_ZC */
+#define WM8962_HPOUTL_ZC_SHIFT 7 /* HPOUTL_ZC */
+#define WM8962_HPOUTL_ZC_WIDTH 1 /* HPOUTL_ZC */
+#define WM8962_HPOUTL_VOL_MASK 0x007F /* HPOUTL_VOL - [6:0] */
+#define WM8962_HPOUTL_VOL_SHIFT 0 /* HPOUTL_VOL - [6:0] */
+#define WM8962_HPOUTL_VOL_WIDTH 7 /* HPOUTL_VOL - [6:0] */
+
+/*
+ * R3 (0x03) - HPOUTR volume
+ */
+#define WM8962_HPOUT_VU 0x0100 /* HPOUT_VU */
+#define WM8962_HPOUT_VU_MASK 0x0100 /* HPOUT_VU */
+#define WM8962_HPOUT_VU_SHIFT 8 /* HPOUT_VU */
+#define WM8962_HPOUT_VU_WIDTH 1 /* HPOUT_VU */
+#define WM8962_HPOUTR_ZC 0x0080 /* HPOUTR_ZC */
+#define WM8962_HPOUTR_ZC_MASK 0x0080 /* HPOUTR_ZC */
+#define WM8962_HPOUTR_ZC_SHIFT 7 /* HPOUTR_ZC */
+#define WM8962_HPOUTR_ZC_WIDTH 1 /* HPOUTR_ZC */
+#define WM8962_HPOUTR_VOL_MASK 0x007F /* HPOUTR_VOL - [6:0] */
+#define WM8962_HPOUTR_VOL_SHIFT 0 /* HPOUTR_VOL - [6:0] */
+#define WM8962_HPOUTR_VOL_WIDTH 7 /* HPOUTR_VOL - [6:0] */
+
+/*
+ * R4 (0x04) - Clocking1
+ */
+#define WM8962_DSPCLK_DIV_MASK 0x0600 /* DSPCLK_DIV - [10:9] */
+#define WM8962_DSPCLK_DIV_SHIFT 9 /* DSPCLK_DIV - [10:9] */
+#define WM8962_DSPCLK_DIV_WIDTH 2 /* DSPCLK_DIV - [10:9] */
+#define WM8962_ADCSYS_CLK_DIV_MASK 0x01C0 /* ADCSYS_CLK_DIV - [8:6] */
+#define WM8962_ADCSYS_CLK_DIV_SHIFT 6 /* ADCSYS_CLK_DIV - [8:6] */
+#define WM8962_ADCSYS_CLK_DIV_WIDTH 3 /* ADCSYS_CLK_DIV - [8:6] */
+#define WM8962_DACSYS_CLK_DIV_MASK 0x0038 /* DACSYS_CLK_DIV - [5:3] */
+#define WM8962_DACSYS_CLK_DIV_SHIFT 3 /* DACSYS_CLK_DIV - [5:3] */
+#define WM8962_DACSYS_CLK_DIV_WIDTH 3 /* DACSYS_CLK_DIV - [5:3] */
+#define WM8962_MCLKDIV_MASK 0x0006 /* MCLKDIV - [2:1] */
+#define WM8962_MCLKDIV_SHIFT 1 /* MCLKDIV - [2:1] */
+#define WM8962_MCLKDIV_WIDTH 2 /* MCLKDIV - [2:1] */
+
+/*
+ * R5 (0x05) - ADC & DAC Control 1
+ */
+#define WM8962_ADCR_DAT_INV 0x0040 /* ADCR_DAT_INV */
+#define WM8962_ADCR_DAT_INV_MASK 0x0040 /* ADCR_DAT_INV */
+#define WM8962_ADCR_DAT_INV_SHIFT 6 /* ADCR_DAT_INV */
+#define WM8962_ADCR_DAT_INV_WIDTH 1 /* ADCR_DAT_INV */
+#define WM8962_ADCL_DAT_INV 0x0020 /* ADCL_DAT_INV */
+#define WM8962_ADCL_DAT_INV_MASK 0x0020 /* ADCL_DAT_INV */
+#define WM8962_ADCL_DAT_INV_SHIFT 5 /* ADCL_DAT_INV */
+#define WM8962_ADCL_DAT_INV_WIDTH 1 /* ADCL_DAT_INV */
+#define WM8962_DAC_MUTE_RAMP 0x0010 /* DAC_MUTE_RAMP */
+#define WM8962_DAC_MUTE_RAMP_MASK 0x0010 /* DAC_MUTE_RAMP */
+#define WM8962_DAC_MUTE_RAMP_SHIFT 4 /* DAC_MUTE_RAMP */
+#define WM8962_DAC_MUTE_RAMP_WIDTH 1 /* DAC_MUTE_RAMP */
+#define WM8962_DAC_MUTE 0x0008 /* DAC_MUTE */
+#define WM8962_DAC_MUTE_MASK 0x0008 /* DAC_MUTE */
+#define WM8962_DAC_MUTE_SHIFT 3 /* DAC_MUTE */
+#define WM8962_DAC_MUTE_WIDTH 1 /* DAC_MUTE */
+#define WM8962_DAC_DEEMP_MASK 0x0006 /* DAC_DEEMP - [2:1] */
+#define WM8962_DAC_DEEMP_SHIFT 1 /* DAC_DEEMP - [2:1] */
+#define WM8962_DAC_DEEMP_WIDTH 2 /* DAC_DEEMP - [2:1] */
+#define WM8962_ADC_HPF_DIS 0x0001 /* ADC_HPF_DIS */
+#define WM8962_ADC_HPF_DIS_MASK 0x0001 /* ADC_HPF_DIS */
+#define WM8962_ADC_HPF_DIS_SHIFT 0 /* ADC_HPF_DIS */
+#define WM8962_ADC_HPF_DIS_WIDTH 1 /* ADC_HPF_DIS */
+
+/*
+ * R6 (0x06) - ADC & DAC Control 2
+ */
+#define WM8962_ADC_HPF_SR_MASK 0x3000 /* ADC_HPF_SR - [13:12] */
+#define WM8962_ADC_HPF_SR_SHIFT 12 /* ADC_HPF_SR - [13:12] */
+#define WM8962_ADC_HPF_SR_WIDTH 2 /* ADC_HPF_SR - [13:12] */
+#define WM8962_ADC_HPF_MODE 0x0400 /* ADC_HPF_MODE */
+#define WM8962_ADC_HPF_MODE_MASK 0x0400 /* ADC_HPF_MODE */
+#define WM8962_ADC_HPF_MODE_SHIFT 10 /* ADC_HPF_MODE */
+#define WM8962_ADC_HPF_MODE_WIDTH 1 /* ADC_HPF_MODE */
+#define WM8962_ADC_HPF_CUT_MASK 0x0380 /* ADC_HPF_CUT - [9:7] */
+#define WM8962_ADC_HPF_CUT_SHIFT 7 /* ADC_HPF_CUT - [9:7] */
+#define WM8962_ADC_HPF_CUT_WIDTH 3 /* ADC_HPF_CUT - [9:7] */
+#define WM8962_DACR_DAT_INV 0x0040 /* DACR_DAT_INV */
+#define WM8962_DACR_DAT_INV_MASK 0x0040 /* DACR_DAT_INV */
+#define WM8962_DACR_DAT_INV_SHIFT 6 /* DACR_DAT_INV */
+#define WM8962_DACR_DAT_INV_WIDTH 1 /* DACR_DAT_INV */
+#define WM8962_DACL_DAT_INV 0x0020 /* DACL_DAT_INV */
+#define WM8962_DACL_DAT_INV_MASK 0x0020 /* DACL_DAT_INV */
+#define WM8962_DACL_DAT_INV_SHIFT 5 /* DACL_DAT_INV */
+#define WM8962_DACL_DAT_INV_WIDTH 1 /* DACL_DAT_INV */
+#define WM8962_DAC_UNMUTE_RAMP 0x0008 /* DAC_UNMUTE_RAMP */
+#define WM8962_DAC_UNMUTE_RAMP_MASK 0x0008 /* DAC_UNMUTE_RAMP */
+#define WM8962_DAC_UNMUTE_RAMP_SHIFT 3 /* DAC_UNMUTE_RAMP */
+#define WM8962_DAC_UNMUTE_RAMP_WIDTH 1 /* DAC_UNMUTE_RAMP */
+#define WM8962_DAC_MUTERATE 0x0004 /* DAC_MUTERATE */
+#define WM8962_DAC_MUTERATE_MASK 0x0004 /* DAC_MUTERATE */
+#define WM8962_DAC_MUTERATE_SHIFT 2 /* DAC_MUTERATE */
+#define WM8962_DAC_MUTERATE_WIDTH 1 /* DAC_MUTERATE */
+#define WM8962_DAC_HP 0x0001 /* DAC_HP */
+#define WM8962_DAC_HP_MASK 0x0001 /* DAC_HP */
+#define WM8962_DAC_HP_SHIFT 0 /* DAC_HP */
+#define WM8962_DAC_HP_WIDTH 1 /* DAC_HP */
+
+/*
+ * R7 (0x07) - Audio Interface 0
+ */
+#define WM8962_AIFDAC_TDM_MODE 0x1000 /* AIFDAC_TDM_MODE */
+#define WM8962_AIFDAC_TDM_MODE_MASK 0x1000 /* AIFDAC_TDM_MODE */
+#define WM8962_AIFDAC_TDM_MODE_SHIFT 12 /* AIFDAC_TDM_MODE */
+#define WM8962_AIFDAC_TDM_MODE_WIDTH 1 /* AIFDAC_TDM_MODE */
+#define WM8962_AIFDAC_TDM_SLOT 0x0800 /* AIFDAC_TDM_SLOT */
+#define WM8962_AIFDAC_TDM_SLOT_MASK 0x0800 /* AIFDAC_TDM_SLOT */
+#define WM8962_AIFDAC_TDM_SLOT_SHIFT 11 /* AIFDAC_TDM_SLOT */
+#define WM8962_AIFDAC_TDM_SLOT_WIDTH 1 /* AIFDAC_TDM_SLOT */
+#define WM8962_AIFADC_TDM_MODE 0x0400 /* AIFADC_TDM_MODE */
+#define WM8962_AIFADC_TDM_MODE_MASK 0x0400 /* AIFADC_TDM_MODE */
+#define WM8962_AIFADC_TDM_MODE_SHIFT 10 /* AIFADC_TDM_MODE */
+#define WM8962_AIFADC_TDM_MODE_WIDTH 1 /* AIFADC_TDM_MODE */
+#define WM8962_AIFADC_TDM_SLOT 0x0200 /* AIFADC_TDM_SLOT */
+#define WM8962_AIFADC_TDM_SLOT_MASK 0x0200 /* AIFADC_TDM_SLOT */
+#define WM8962_AIFADC_TDM_SLOT_SHIFT 9 /* AIFADC_TDM_SLOT */
+#define WM8962_AIFADC_TDM_SLOT_WIDTH 1 /* AIFADC_TDM_SLOT */
+#define WM8962_ADC_LRSWAP 0x0100 /* ADC_LRSWAP */
+#define WM8962_ADC_LRSWAP_MASK 0x0100 /* ADC_LRSWAP */
+#define WM8962_ADC_LRSWAP_SHIFT 8 /* ADC_LRSWAP */
+#define WM8962_ADC_LRSWAP_WIDTH 1 /* ADC_LRSWAP */
+#define WM8962_BCLK_INV 0x0080 /* BCLK_INV */
+#define WM8962_BCLK_INV_MASK 0x0080 /* BCLK_INV */
+#define WM8962_BCLK_INV_SHIFT 7 /* BCLK_INV */
+#define WM8962_BCLK_INV_WIDTH 1 /* BCLK_INV */
+#define WM8962_MSTR 0x0040 /* MSTR */
+#define WM8962_MSTR_MASK 0x0040 /* MSTR */
+#define WM8962_MSTR_SHIFT 6 /* MSTR */
+#define WM8962_MSTR_WIDTH 1 /* MSTR */
+#define WM8962_DAC_LRSWAP 0x0020 /* DAC_LRSWAP */
+#define WM8962_DAC_LRSWAP_MASK 0x0020 /* DAC_LRSWAP */
+#define WM8962_DAC_LRSWAP_SHIFT 5 /* DAC_LRSWAP */
+#define WM8962_DAC_LRSWAP_WIDTH 1 /* DAC_LRSWAP */
+#define WM8962_LRCLK_INV 0x0010 /* LRCLK_INV */
+#define WM8962_LRCLK_INV_MASK 0x0010 /* LRCLK_INV */
+#define WM8962_LRCLK_INV_SHIFT 4 /* LRCLK_INV */
+#define WM8962_LRCLK_INV_WIDTH 1 /* LRCLK_INV */
+#define WM8962_WL_MASK 0x000C /* WL - [3:2] */
+#define WM8962_WL_SHIFT 2 /* WL - [3:2] */
+#define WM8962_WL_WIDTH 2 /* WL - [3:2] */
+#define WM8962_FMT_MASK 0x0003 /* FMT - [1:0] */
+#define WM8962_FMT_SHIFT 0 /* FMT - [1:0] */
+#define WM8962_FMT_WIDTH 2 /* FMT - [1:0] */
+
+/*
+ * R8 (0x08) - Clocking2
+ */
+#define WM8962_CLKREG_OVD 0x0800 /* CLKREG_OVD */
+#define WM8962_CLKREG_OVD_MASK 0x0800 /* CLKREG_OVD */
+#define WM8962_CLKREG_OVD_SHIFT 11 /* CLKREG_OVD */
+#define WM8962_CLKREG_OVD_WIDTH 1 /* CLKREG_OVD */
+#define WM8962_SYSCLK_SRC_MASK 0x0600 /* SYSCLK_SRC - [10:9] */
+#define WM8962_SYSCLK_SRC_SHIFT 9 /* SYSCLK_SRC - [10:9] */
+#define WM8962_SYSCLK_SRC_WIDTH 2 /* SYSCLK_SRC - [10:9] */
+#define WM8962_CLASSD_CLK_DIV_MASK 0x01C0 /* CLASSD_CLK_DIV - [8:6] */
+#define WM8962_CLASSD_CLK_DIV_SHIFT 6 /* CLASSD_CLK_DIV - [8:6] */
+#define WM8962_CLASSD_CLK_DIV_WIDTH 3 /* CLASSD_CLK_DIV - [8:6] */
+#define WM8962_SYSCLK_ENA 0x0020 /* SYSCLK_ENA */
+#define WM8962_SYSCLK_ENA_MASK 0x0020 /* SYSCLK_ENA */
+#define WM8962_SYSCLK_ENA_SHIFT 5 /* SYSCLK_ENA */
+#define WM8962_SYSCLK_ENA_WIDTH 1 /* SYSCLK_ENA */
+#define WM8962_BCLK_DIV_MASK 0x000F /* BCLK_DIV - [3:0] */
+#define WM8962_BCLK_DIV_SHIFT 0 /* BCLK_DIV - [3:0] */
+#define WM8962_BCLK_DIV_WIDTH 4 /* BCLK_DIV - [3:0] */
+
+/*
+ * R9 (0x09) - Audio Interface 1
+ */
+#define WM8962_AUTOMUTE_STS 0x0800 /* AUTOMUTE_STS */
+#define WM8962_AUTOMUTE_STS_MASK 0x0800 /* AUTOMUTE_STS */
+#define WM8962_AUTOMUTE_STS_SHIFT 11 /* AUTOMUTE_STS */
+#define WM8962_AUTOMUTE_STS_WIDTH 1 /* AUTOMUTE_STS */
+#define WM8962_DAC_AUTOMUTE_SAMPLES_MASK 0x0300 /* DAC_AUTOMUTE_SAMPLES - [9:8] */
+#define WM8962_DAC_AUTOMUTE_SAMPLES_SHIFT 8 /* DAC_AUTOMUTE_SAMPLES - [9:8] */
+#define WM8962_DAC_AUTOMUTE_SAMPLES_WIDTH 2 /* DAC_AUTOMUTE_SAMPLES - [9:8] */
+#define WM8962_DAC_AUTOMUTE 0x0080 /* DAC_AUTOMUTE */
+#define WM8962_DAC_AUTOMUTE_MASK 0x0080 /* DAC_AUTOMUTE */
+#define WM8962_DAC_AUTOMUTE_SHIFT 7 /* DAC_AUTOMUTE */
+#define WM8962_DAC_AUTOMUTE_WIDTH 1 /* DAC_AUTOMUTE */
+#define WM8962_DAC_COMP 0x0010 /* DAC_COMP */
+#define WM8962_DAC_COMP_MASK 0x0010 /* DAC_COMP */
+#define WM8962_DAC_COMP_SHIFT 4 /* DAC_COMP */
+#define WM8962_DAC_COMP_WIDTH 1 /* DAC_COMP */
+#define WM8962_DAC_COMPMODE 0x0008 /* DAC_COMPMODE */
+#define WM8962_DAC_COMPMODE_MASK 0x0008 /* DAC_COMPMODE */
+#define WM8962_DAC_COMPMODE_SHIFT 3 /* DAC_COMPMODE */
+#define WM8962_DAC_COMPMODE_WIDTH 1 /* DAC_COMPMODE */
+#define WM8962_ADC_COMP 0x0004 /* ADC_COMP */
+#define WM8962_ADC_COMP_MASK 0x0004 /* ADC_COMP */
+#define WM8962_ADC_COMP_SHIFT 2 /* ADC_COMP */
+#define WM8962_ADC_COMP_WIDTH 1 /* ADC_COMP */
+#define WM8962_ADC_COMPMODE 0x0002 /* ADC_COMPMODE */
+#define WM8962_ADC_COMPMODE_MASK 0x0002 /* ADC_COMPMODE */
+#define WM8962_ADC_COMPMODE_SHIFT 1 /* ADC_COMPMODE */
+#define WM8962_ADC_COMPMODE_WIDTH 1 /* ADC_COMPMODE */
+#define WM8962_LOOPBACK 0x0001 /* LOOPBACK */
+#define WM8962_LOOPBACK_MASK 0x0001 /* LOOPBACK */
+#define WM8962_LOOPBACK_SHIFT 0 /* LOOPBACK */
+#define WM8962_LOOPBACK_WIDTH 1 /* LOOPBACK */
+
+/*
+ * R10 (0x0A) - Left DAC volume
+ */
+#define WM8962_DAC_VU 0x0100 /* DAC_VU */
+#define WM8962_DAC_VU_MASK 0x0100 /* DAC_VU */
+#define WM8962_DAC_VU_SHIFT 8 /* DAC_VU */
+#define WM8962_DAC_VU_WIDTH 1 /* DAC_VU */
+#define WM8962_DACL_VOL_MASK 0x00FF /* DACL_VOL - [7:0] */
+#define WM8962_DACL_VOL_SHIFT 0 /* DACL_VOL - [7:0] */
+#define WM8962_DACL_VOL_WIDTH 8 /* DACL_VOL - [7:0] */
+
+/*
+ * R11 (0x0B) - Right DAC volume
+ */
+#define WM8962_DAC_VU 0x0100 /* DAC_VU */
+#define WM8962_DAC_VU_MASK 0x0100 /* DAC_VU */
+#define WM8962_DAC_VU_SHIFT 8 /* DAC_VU */
+#define WM8962_DAC_VU_WIDTH 1 /* DAC_VU */
+#define WM8962_DACR_VOL_MASK 0x00FF /* DACR_VOL - [7:0] */
+#define WM8962_DACR_VOL_SHIFT 0 /* DACR_VOL - [7:0] */
+#define WM8962_DACR_VOL_WIDTH 8 /* DACR_VOL - [7:0] */
+
+/*
+ * R14 (0x0E) - Audio Interface 2
+ */
+#define WM8962_AIF_RATE_MASK 0x07FF /* AIF_RATE - [10:0] */
+#define WM8962_AIF_RATE_SHIFT 0 /* AIF_RATE - [10:0] */
+#define WM8962_AIF_RATE_WIDTH 11 /* AIF_RATE - [10:0] */
+
+/*
+ * R15 (0x0F) - Software Reset
+ */
+#define WM8962_SW_RESET_MASK 0xFFFF /* SW_RESET - [15:0] */
+#define WM8962_SW_RESET_SHIFT 0 /* SW_RESET - [15:0] */
+#define WM8962_SW_RESET_WIDTH 16 /* SW_RESET - [15:0] */
+
+/*
+ * R17 (0x11) - ALC1
+ */
+#define WM8962_ALC_INACTIVE_ENA 0x0400 /* ALC_INACTIVE_ENA */
+#define WM8962_ALC_INACTIVE_ENA_MASK 0x0400 /* ALC_INACTIVE_ENA */
+#define WM8962_ALC_INACTIVE_ENA_SHIFT 10 /* ALC_INACTIVE_ENA */
+#define WM8962_ALC_INACTIVE_ENA_WIDTH 1 /* ALC_INACTIVE_ENA */
+#define WM8962_ALC_LVL_MODE 0x0200 /* ALC_LVL_MODE */
+#define WM8962_ALC_LVL_MODE_MASK 0x0200 /* ALC_LVL_MODE */
+#define WM8962_ALC_LVL_MODE_SHIFT 9 /* ALC_LVL_MODE */
+#define WM8962_ALC_LVL_MODE_WIDTH 1 /* ALC_LVL_MODE */
+#define WM8962_ALCL_ENA 0x0100 /* ALCL_ENA */
+#define WM8962_ALCL_ENA_MASK 0x0100 /* ALCL_ENA */
+#define WM8962_ALCL_ENA_SHIFT 8 /* ALCL_ENA */
+#define WM8962_ALCL_ENA_WIDTH 1 /* ALCL_ENA */
+#define WM8962_ALCR_ENA 0x0080 /* ALCR_ENA */
+#define WM8962_ALCR_ENA_MASK 0x0080 /* ALCR_ENA */
+#define WM8962_ALCR_ENA_SHIFT 7 /* ALCR_ENA */
+#define WM8962_ALCR_ENA_WIDTH 1 /* ALCR_ENA */
+#define WM8962_ALC_MAXGAIN_MASK 0x0070 /* ALC_MAXGAIN - [6:4] */
+#define WM8962_ALC_MAXGAIN_SHIFT 4 /* ALC_MAXGAIN - [6:4] */
+#define WM8962_ALC_MAXGAIN_WIDTH 3 /* ALC_MAXGAIN - [6:4] */
+#define WM8962_ALC_LVL_MASK 0x000F /* ALC_LVL - [3:0] */
+#define WM8962_ALC_LVL_SHIFT 0 /* ALC_LVL - [3:0] */
+#define WM8962_ALC_LVL_WIDTH 4 /* ALC_LVL - [3:0] */
+
+/*
+ * R18 (0x12) - ALC2
+ */
+#define WM8962_ALC_LOCK_STS 0x8000 /* ALC_LOCK_STS */
+#define WM8962_ALC_LOCK_STS_MASK 0x8000 /* ALC_LOCK_STS */
+#define WM8962_ALC_LOCK_STS_SHIFT 15 /* ALC_LOCK_STS */
+#define WM8962_ALC_LOCK_STS_WIDTH 1 /* ALC_LOCK_STS */
+#define WM8962_ALC_THRESH_STS 0x4000 /* ALC_THRESH_STS */
+#define WM8962_ALC_THRESH_STS_MASK 0x4000 /* ALC_THRESH_STS */
+#define WM8962_ALC_THRESH_STS_SHIFT 14 /* ALC_THRESH_STS */
+#define WM8962_ALC_THRESH_STS_WIDTH 1 /* ALC_THRESH_STS */
+#define WM8962_ALC_SAT_STS 0x2000 /* ALC_SAT_STS */
+#define WM8962_ALC_SAT_STS_MASK 0x2000 /* ALC_SAT_STS */
+#define WM8962_ALC_SAT_STS_SHIFT 13 /* ALC_SAT_STS */
+#define WM8962_ALC_SAT_STS_WIDTH 1 /* ALC_SAT_STS */
+#define WM8962_ALC_PKOVR_STS 0x1000 /* ALC_PKOVR_STS */
+#define WM8962_ALC_PKOVR_STS_MASK 0x1000 /* ALC_PKOVR_STS */
+#define WM8962_ALC_PKOVR_STS_SHIFT 12 /* ALC_PKOVR_STS */
+#define WM8962_ALC_PKOVR_STS_WIDTH 1 /* ALC_PKOVR_STS */
+#define WM8962_ALC_NGATE_STS 0x0800 /* ALC_NGATE_STS */
+#define WM8962_ALC_NGATE_STS_MASK 0x0800 /* ALC_NGATE_STS */
+#define WM8962_ALC_NGATE_STS_SHIFT 11 /* ALC_NGATE_STS */
+#define WM8962_ALC_NGATE_STS_WIDTH 1 /* ALC_NGATE_STS */
+#define WM8962_ALC_ZC 0x0080 /* ALC_ZC */
+#define WM8962_ALC_ZC_MASK 0x0080 /* ALC_ZC */
+#define WM8962_ALC_ZC_SHIFT 7 /* ALC_ZC */
+#define WM8962_ALC_ZC_WIDTH 1 /* ALC_ZC */
+#define WM8962_ALC_MINGAIN_MASK 0x0070 /* ALC_MINGAIN - [6:4] */
+#define WM8962_ALC_MINGAIN_SHIFT 4 /* ALC_MINGAIN - [6:4] */
+#define WM8962_ALC_MINGAIN_WIDTH 3 /* ALC_MINGAIN - [6:4] */
+#define WM8962_ALC_HLD_MASK 0x000F /* ALC_HLD - [3:0] */
+#define WM8962_ALC_HLD_SHIFT 0 /* ALC_HLD - [3:0] */
+#define WM8962_ALC_HLD_WIDTH 4 /* ALC_HLD - [3:0] */
+
+/*
+ * R19 (0x13) - ALC3
+ */
+#define WM8962_ALC_NGATE_GAIN_MASK 0x1C00 /* ALC_NGATE_GAIN - [12:10] */
+#define WM8962_ALC_NGATE_GAIN_SHIFT 10 /* ALC_NGATE_GAIN - [12:10] */
+#define WM8962_ALC_NGATE_GAIN_WIDTH 3 /* ALC_NGATE_GAIN - [12:10] */
+#define WM8962_ALC_MODE 0x0100 /* ALC_MODE */
+#define WM8962_ALC_MODE_MASK 0x0100 /* ALC_MODE */
+#define WM8962_ALC_MODE_SHIFT 8 /* ALC_MODE */
+#define WM8962_ALC_MODE_WIDTH 1 /* ALC_MODE */
+#define WM8962_ALC_DCY_MASK 0x00F0 /* ALC_DCY - [7:4] */
+#define WM8962_ALC_DCY_SHIFT 4 /* ALC_DCY - [7:4] */
+#define WM8962_ALC_DCY_WIDTH 4 /* ALC_DCY - [7:4] */
+#define WM8962_ALC_ATK_MASK 0x000F /* ALC_ATK - [3:0] */
+#define WM8962_ALC_ATK_SHIFT 0 /* ALC_ATK - [3:0] */
+#define WM8962_ALC_ATK_WIDTH 4 /* ALC_ATK - [3:0] */
+
+/*
+ * R20 (0x14) - Noise Gate
+ */
+#define WM8962_ALC_NGATE_DCY_MASK 0xF000 /* ALC_NGATE_DCY - [15:12] */
+#define WM8962_ALC_NGATE_DCY_SHIFT 12 /* ALC_NGATE_DCY - [15:12] */
+#define WM8962_ALC_NGATE_DCY_WIDTH 4 /* ALC_NGATE_DCY - [15:12] */
+#define WM8962_ALC_NGATE_ATK_MASK 0x0F00 /* ALC_NGATE_ATK - [11:8] */
+#define WM8962_ALC_NGATE_ATK_SHIFT 8 /* ALC_NGATE_ATK - [11:8] */
+#define WM8962_ALC_NGATE_ATK_WIDTH 4 /* ALC_NGATE_ATK - [11:8] */
+#define WM8962_ALC_NGATE_THR_MASK 0x00F8 /* ALC_NGATE_THR - [7:3] */
+#define WM8962_ALC_NGATE_THR_SHIFT 3 /* ALC_NGATE_THR - [7:3] */
+#define WM8962_ALC_NGATE_THR_WIDTH 5 /* ALC_NGATE_THR - [7:3] */
+#define WM8962_ALC_NGATE_MODE_MASK 0x0006 /* ALC_NGATE_MODE - [2:1] */
+#define WM8962_ALC_NGATE_MODE_SHIFT 1 /* ALC_NGATE_MODE - [2:1] */
+#define WM8962_ALC_NGATE_MODE_WIDTH 2 /* ALC_NGATE_MODE - [2:1] */
+#define WM8962_ALC_NGATE_ENA 0x0001 /* ALC_NGATE_ENA */
+#define WM8962_ALC_NGATE_ENA_MASK 0x0001 /* ALC_NGATE_ENA */
+#define WM8962_ALC_NGATE_ENA_SHIFT 0 /* ALC_NGATE_ENA */
+#define WM8962_ALC_NGATE_ENA_WIDTH 1 /* ALC_NGATE_ENA */
+
+/*
+ * R21 (0x15) - Left ADC volume
+ */
+#define WM8962_ADC_VU 0x0100 /* ADC_VU */
+#define WM8962_ADC_VU_MASK 0x0100 /* ADC_VU */
+#define WM8962_ADC_VU_SHIFT 8 /* ADC_VU */
+#define WM8962_ADC_VU_WIDTH 1 /* ADC_VU */
+#define WM8962_ADCL_VOL_MASK 0x00FF /* ADCL_VOL - [7:0] */
+#define WM8962_ADCL_VOL_SHIFT 0 /* ADCL_VOL - [7:0] */
+#define WM8962_ADCL_VOL_WIDTH 8 /* ADCL_VOL - [7:0] */
+
+/*
+ * R22 (0x16) - Right ADC volume
+ */
+#define WM8962_ADC_VU 0x0100 /* ADC_VU */
+#define WM8962_ADC_VU_MASK 0x0100 /* ADC_VU */
+#define WM8962_ADC_VU_SHIFT 8 /* ADC_VU */
+#define WM8962_ADC_VU_WIDTH 1 /* ADC_VU */
+#define WM8962_ADCR_VOL_MASK 0x00FF /* ADCR_VOL - [7:0] */
+#define WM8962_ADCR_VOL_SHIFT 0 /* ADCR_VOL - [7:0] */
+#define WM8962_ADCR_VOL_WIDTH 8 /* ADCR_VOL - [7:0] */
+
+/*
+ * R23 (0x17) - Additional control(1)
+ */
+#define WM8962_THERR_ACT 0x0100 /* THERR_ACT */
+#define WM8962_THERR_ACT_MASK 0x0100 /* THERR_ACT */
+#define WM8962_THERR_ACT_SHIFT 8 /* THERR_ACT */
+#define WM8962_THERR_ACT_WIDTH 1 /* THERR_ACT */
+#define WM8962_ADC_BIAS 0x0040 /* ADC_BIAS */
+#define WM8962_ADC_BIAS_MASK 0x0040 /* ADC_BIAS */
+#define WM8962_ADC_BIAS_SHIFT 6 /* ADC_BIAS */
+#define WM8962_ADC_BIAS_WIDTH 1 /* ADC_BIAS */
+#define WM8962_ADC_HP 0x0020 /* ADC_HP */
+#define WM8962_ADC_HP_MASK 0x0020 /* ADC_HP */
+#define WM8962_ADC_HP_SHIFT 5 /* ADC_HP */
+#define WM8962_ADC_HP_WIDTH 1 /* ADC_HP */
+#define WM8962_TOCLK_ENA 0x0001 /* TOCLK_ENA */
+#define WM8962_TOCLK_ENA_MASK 0x0001 /* TOCLK_ENA */
+#define WM8962_TOCLK_ENA_SHIFT 0 /* TOCLK_ENA */
+#define WM8962_TOCLK_ENA_WIDTH 1 /* TOCLK_ENA */
+
+/*
+ * R24 (0x18) - Additional control(2)
+ */
+#define WM8962_AIF_TRI 0x0008 /* AIF_TRI */
+#define WM8962_AIF_TRI_MASK 0x0008 /* AIF_TRI */
+#define WM8962_AIF_TRI_SHIFT 3 /* AIF_TRI */
+#define WM8962_AIF_TRI_WIDTH 1 /* AIF_TRI */
+
+/*
+ * R25 (0x19) - Pwr Mgmt (1)
+ */
+#define WM8962_DMIC_ENA 0x0400 /* DMIC_ENA */
+#define WM8962_DMIC_ENA_MASK 0x0400 /* DMIC_ENA */
+#define WM8962_DMIC_ENA_SHIFT 10 /* DMIC_ENA */
+#define WM8962_DMIC_ENA_WIDTH 1 /* DMIC_ENA */
+#define WM8962_OPCLK_ENA 0x0200 /* OPCLK_ENA */
+#define WM8962_OPCLK_ENA_MASK 0x0200 /* OPCLK_ENA */
+#define WM8962_OPCLK_ENA_SHIFT 9 /* OPCLK_ENA */
+#define WM8962_OPCLK_ENA_WIDTH 1 /* OPCLK_ENA */
+#define WM8962_VMID_SEL_MASK 0x0180 /* VMID_SEL - [8:7] */
+#define WM8962_VMID_SEL_SHIFT 7 /* VMID_SEL - [8:7] */
+#define WM8962_VMID_SEL_WIDTH 2 /* VMID_SEL - [8:7] */
+#define WM8962_BIAS_ENA 0x0040 /* BIAS_ENA */
+#define WM8962_BIAS_ENA_MASK 0x0040 /* BIAS_ENA */
+#define WM8962_BIAS_ENA_SHIFT 6 /* BIAS_ENA */
+#define WM8962_BIAS_ENA_WIDTH 1 /* BIAS_ENA */
+#define WM8962_INL_ENA 0x0020 /* INL_ENA */
+#define WM8962_INL_ENA_MASK 0x0020 /* INL_ENA */
+#define WM8962_INL_ENA_SHIFT 5 /* INL_ENA */
+#define WM8962_INL_ENA_WIDTH 1 /* INL_ENA */
+#define WM8962_INR_ENA 0x0010 /* INR_ENA */
+#define WM8962_INR_ENA_MASK 0x0010 /* INR_ENA */
+#define WM8962_INR_ENA_SHIFT 4 /* INR_ENA */
+#define WM8962_INR_ENA_WIDTH 1 /* INR_ENA */
+#define WM8962_ADCL_ENA 0x0008 /* ADCL_ENA */
+#define WM8962_ADCL_ENA_MASK 0x0008 /* ADCL_ENA */
+#define WM8962_ADCL_ENA_SHIFT 3 /* ADCL_ENA */
+#define WM8962_ADCL_ENA_WIDTH 1 /* ADCL_ENA */
+#define WM8962_ADCR_ENA 0x0004 /* ADCR_ENA */
+#define WM8962_ADCR_ENA_MASK 0x0004 /* ADCR_ENA */
+#define WM8962_ADCR_ENA_SHIFT 2 /* ADCR_ENA */
+#define WM8962_ADCR_ENA_WIDTH 1 /* ADCR_ENA */
+#define WM8962_MICBIAS_ENA 0x0002 /* MICBIAS_ENA */
+#define WM8962_MICBIAS_ENA_MASK 0x0002 /* MICBIAS_ENA */
+#define WM8962_MICBIAS_ENA_SHIFT 1 /* MICBIAS_ENA */
+#define WM8962_MICBIAS_ENA_WIDTH 1 /* MICBIAS_ENA */
+
+/*
+ * R26 (0x1A) - Pwr Mgmt (2)
+ */
+#define WM8962_DACL_ENA 0x0100 /* DACL_ENA */
+#define WM8962_DACL_ENA_MASK 0x0100 /* DACL_ENA */
+#define WM8962_DACL_ENA_SHIFT 8 /* DACL_ENA */
+#define WM8962_DACL_ENA_WIDTH 1 /* DACL_ENA */
+#define WM8962_DACR_ENA 0x0080 /* DACR_ENA */
+#define WM8962_DACR_ENA_MASK 0x0080 /* DACR_ENA */
+#define WM8962_DACR_ENA_SHIFT 7 /* DACR_ENA */
+#define WM8962_DACR_ENA_WIDTH 1 /* DACR_ENA */
+#define WM8962_HPOUTL_PGA_ENA 0x0040 /* HPOUTL_PGA_ENA */
+#define WM8962_HPOUTL_PGA_ENA_MASK 0x0040 /* HPOUTL_PGA_ENA */
+#define WM8962_HPOUTL_PGA_ENA_SHIFT 6 /* HPOUTL_PGA_ENA */
+#define WM8962_HPOUTL_PGA_ENA_WIDTH 1 /* HPOUTL_PGA_ENA */
+#define WM8962_HPOUTR_PGA_ENA 0x0020 /* HPOUTR_PGA_ENA */
+#define WM8962_HPOUTR_PGA_ENA_MASK 0x0020 /* HPOUTR_PGA_ENA */
+#define WM8962_HPOUTR_PGA_ENA_SHIFT 5 /* HPOUTR_PGA_ENA */
+#define WM8962_HPOUTR_PGA_ENA_WIDTH 1 /* HPOUTR_PGA_ENA */
+#define WM8962_SPKOUTL_PGA_ENA 0x0010 /* SPKOUTL_PGA_ENA */
+#define WM8962_SPKOUTL_PGA_ENA_MASK 0x0010 /* SPKOUTL_PGA_ENA */
+#define WM8962_SPKOUTL_PGA_ENA_SHIFT 4 /* SPKOUTL_PGA_ENA */
+#define WM8962_SPKOUTL_PGA_ENA_WIDTH 1 /* SPKOUTL_PGA_ENA */
+#define WM8962_SPKOUTR_PGA_ENA 0x0008 /* SPKOUTR_PGA_ENA */
+#define WM8962_SPKOUTR_PGA_ENA_MASK 0x0008 /* SPKOUTR_PGA_ENA */
+#define WM8962_SPKOUTR_PGA_ENA_SHIFT 3 /* SPKOUTR_PGA_ENA */
+#define WM8962_SPKOUTR_PGA_ENA_WIDTH 1 /* SPKOUTR_PGA_ENA */
+#define WM8962_HPOUTL_PGA_MUTE 0x0002 /* HPOUTL_PGA_MUTE */
+#define WM8962_HPOUTL_PGA_MUTE_MASK 0x0002 /* HPOUTL_PGA_MUTE */
+#define WM8962_HPOUTL_PGA_MUTE_SHIFT 1 /* HPOUTL_PGA_MUTE */
+#define WM8962_HPOUTL_PGA_MUTE_WIDTH 1 /* HPOUTL_PGA_MUTE */
+#define WM8962_HPOUTR_PGA_MUTE 0x0001 /* HPOUTR_PGA_MUTE */
+#define WM8962_HPOUTR_PGA_MUTE_MASK 0x0001 /* HPOUTR_PGA_MUTE */
+#define WM8962_HPOUTR_PGA_MUTE_SHIFT 0 /* HPOUTR_PGA_MUTE */
+#define WM8962_HPOUTR_PGA_MUTE_WIDTH 1 /* HPOUTR_PGA_MUTE */
+
+/*
+ * R27 (0x1B) - Additional Control (3)
+ */
+#define WM8962_SAMPLE_RATE_INT_MODE 0x0010 /* SAMPLE_RATE_INT_MODE */
+#define WM8962_SAMPLE_RATE_INT_MODE_MASK 0x0010 /* SAMPLE_RATE_INT_MODE */
+#define WM8962_SAMPLE_RATE_INT_MODE_SHIFT 4 /* SAMPLE_RATE_INT_MODE */
+#define WM8962_SAMPLE_RATE_INT_MODE_WIDTH 1 /* SAMPLE_RATE_INT_MODE */
+#define WM8962_SAMPLE_RATE_MASK 0x0007 /* SAMPLE_RATE - [2:0] */
+#define WM8962_SAMPLE_RATE_SHIFT 0 /* SAMPLE_RATE - [2:0] */
+#define WM8962_SAMPLE_RATE_WIDTH 3 /* SAMPLE_RATE - [2:0] */
+
+/*
+ * R28 (0x1C) - Anti-pop
+ */
+#define WM8962_STARTUP_BIAS_ENA 0x0010 /* STARTUP_BIAS_ENA */
+#define WM8962_STARTUP_BIAS_ENA_MASK 0x0010 /* STARTUP_BIAS_ENA */
+#define WM8962_STARTUP_BIAS_ENA_SHIFT 4 /* STARTUP_BIAS_ENA */
+#define WM8962_STARTUP_BIAS_ENA_WIDTH 1 /* STARTUP_BIAS_ENA */
+#define WM8962_VMID_BUF_ENA 0x0008 /* VMID_BUF_ENA */
+#define WM8962_VMID_BUF_ENA_MASK 0x0008 /* VMID_BUF_ENA */
+#define WM8962_VMID_BUF_ENA_SHIFT 3 /* VMID_BUF_ENA */
+#define WM8962_VMID_BUF_ENA_WIDTH 1 /* VMID_BUF_ENA */
+#define WM8962_VMID_RAMP 0x0004 /* VMID_RAMP */
+#define WM8962_VMID_RAMP_MASK 0x0004 /* VMID_RAMP */
+#define WM8962_VMID_RAMP_SHIFT 2 /* VMID_RAMP */
+#define WM8962_VMID_RAMP_WIDTH 1 /* VMID_RAMP */
+
+/*
+ * R30 (0x1E) - Clocking 3
+ */
+#define WM8962_DBCLK_DIV_MASK 0xE000 /* DBCLK_DIV - [15:13] */
+#define WM8962_DBCLK_DIV_SHIFT 13 /* DBCLK_DIV - [15:13] */
+#define WM8962_DBCLK_DIV_WIDTH 3 /* DBCLK_DIV - [15:13] */
+#define WM8962_OPCLK_DIV_MASK 0x1C00 /* OPCLK_DIV - [12:10] */
+#define WM8962_OPCLK_DIV_SHIFT 10 /* OPCLK_DIV - [12:10] */
+#define WM8962_OPCLK_DIV_WIDTH 3 /* OPCLK_DIV - [12:10] */
+#define WM8962_TOCLK_DIV_MASK 0x0380 /* TOCLK_DIV - [9:7] */
+#define WM8962_TOCLK_DIV_SHIFT 7 /* TOCLK_DIV - [9:7] */
+#define WM8962_TOCLK_DIV_WIDTH 3 /* TOCLK_DIV - [9:7] */
+#define WM8962_F256KCLK_DIV_MASK 0x007E /* F256KCLK_DIV - [6:1] */
+#define WM8962_F256KCLK_DIV_SHIFT 1 /* F256KCLK_DIV - [6:1] */
+#define WM8962_F256KCLK_DIV_WIDTH 6 /* F256KCLK_DIV - [6:1] */
+
+/*
+ * R31 (0x1F) - Input mixer control (1)
+ */
+#define WM8962_MIXINL_MUTE 0x0008 /* MIXINL_MUTE */
+#define WM8962_MIXINL_MUTE_MASK 0x0008 /* MIXINL_MUTE */
+#define WM8962_MIXINL_MUTE_SHIFT 3 /* MIXINL_MUTE */
+#define WM8962_MIXINL_MUTE_WIDTH 1 /* MIXINL_MUTE */
+#define WM8962_MIXINR_MUTE 0x0004 /* MIXINR_MUTE */
+#define WM8962_MIXINR_MUTE_MASK 0x0004 /* MIXINR_MUTE */
+#define WM8962_MIXINR_MUTE_SHIFT 2 /* MIXINR_MUTE */
+#define WM8962_MIXINR_MUTE_WIDTH 1 /* MIXINR_MUTE */
+#define WM8962_MIXINL_ENA 0x0002 /* MIXINL_ENA */
+#define WM8962_MIXINL_ENA_MASK 0x0002 /* MIXINL_ENA */
+#define WM8962_MIXINL_ENA_SHIFT 1 /* MIXINL_ENA */
+#define WM8962_MIXINL_ENA_WIDTH 1 /* MIXINL_ENA */
+#define WM8962_MIXINR_ENA 0x0001 /* MIXINR_ENA */
+#define WM8962_MIXINR_ENA_MASK 0x0001 /* MIXINR_ENA */
+#define WM8962_MIXINR_ENA_SHIFT 0 /* MIXINR_ENA */
+#define WM8962_MIXINR_ENA_WIDTH 1 /* MIXINR_ENA */
+
+/*
+ * R32 (0x20) - Left input mixer volume
+ */
+#define WM8962_IN2L_MIXINL_VOL_MASK 0x01C0 /* IN2L_MIXINL_VOL - [8:6] */
+#define WM8962_IN2L_MIXINL_VOL_SHIFT 6 /* IN2L_MIXINL_VOL - [8:6] */
+#define WM8962_IN2L_MIXINL_VOL_WIDTH 3 /* IN2L_MIXINL_VOL - [8:6] */
+#define WM8962_INPGAL_MIXINL_VOL_MASK 0x0038 /* INPGAL_MIXINL_VOL - [5:3] */
+#define WM8962_INPGAL_MIXINL_VOL_SHIFT 3 /* INPGAL_MIXINL_VOL - [5:3] */
+#define WM8962_INPGAL_MIXINL_VOL_WIDTH 3 /* INPGAL_MIXINL_VOL - [5:3] */
+#define WM8962_IN3L_MIXINL_VOL_MASK 0x0007 /* IN3L_MIXINL_VOL - [2:0] */
+#define WM8962_IN3L_MIXINL_VOL_SHIFT 0 /* IN3L_MIXINL_VOL - [2:0] */
+#define WM8962_IN3L_MIXINL_VOL_WIDTH 3 /* IN3L_MIXINL_VOL - [2:0] */
+
+/*
+ * R33 (0x21) - Right input mixer volume
+ */
+#define WM8962_IN2R_MIXINR_VOL_MASK 0x01C0 /* IN2R_MIXINR_VOL - [8:6] */
+#define WM8962_IN2R_MIXINR_VOL_SHIFT 6 /* IN2R_MIXINR_VOL - [8:6] */
+#define WM8962_IN2R_MIXINR_VOL_WIDTH 3 /* IN2R_MIXINR_VOL - [8:6] */
+#define WM8962_INPGAR_MIXINR_VOL_MASK 0x0038 /* INPGAR_MIXINR_VOL - [5:3] */
+#define WM8962_INPGAR_MIXINR_VOL_SHIFT 3 /* INPGAR_MIXINR_VOL - [5:3] */
+#define WM8962_INPGAR_MIXINR_VOL_WIDTH 3 /* INPGAR_MIXINR_VOL - [5:3] */
+#define WM8962_IN3R_MIXINR_VOL_MASK 0x0007 /* IN3R_MIXINR_VOL - [2:0] */
+#define WM8962_IN3R_MIXINR_VOL_SHIFT 0 /* IN3R_MIXINR_VOL - [2:0] */
+#define WM8962_IN3R_MIXINR_VOL_WIDTH 3 /* IN3R_MIXINR_VOL - [2:0] */
+
+/*
+ * R34 (0x22) - Input mixer control (2)
+ */
+#define WM8962_IN2L_TO_MIXINL 0x0020 /* IN2L_TO_MIXINL */
+#define WM8962_IN2L_TO_MIXINL_MASK 0x0020 /* IN2L_TO_MIXINL */
+#define WM8962_IN2L_TO_MIXINL_SHIFT 5 /* IN2L_TO_MIXINL */
+#define WM8962_IN2L_TO_MIXINL_WIDTH 1 /* IN2L_TO_MIXINL */
+#define WM8962_IN3L_TO_MIXINL 0x0010 /* IN3L_TO_MIXINL */
+#define WM8962_IN3L_TO_MIXINL_MASK 0x0010 /* IN3L_TO_MIXINL */
+#define WM8962_IN3L_TO_MIXINL_SHIFT 4 /* IN3L_TO_MIXINL */
+#define WM8962_IN3L_TO_MIXINL_WIDTH 1 /* IN3L_TO_MIXINL */
+#define WM8962_INPGAL_TO_MIXINL 0x0008 /* INPGAL_TO_MIXINL */
+#define WM8962_INPGAL_TO_MIXINL_MASK 0x0008 /* INPGAL_TO_MIXINL */
+#define WM8962_INPGAL_TO_MIXINL_SHIFT 3 /* INPGAL_TO_MIXINL */
+#define WM8962_INPGAL_TO_MIXINL_WIDTH 1 /* INPGAL_TO_MIXINL */
+#define WM8962_IN2R_TO_MIXINR 0x0004 /* IN2R_TO_MIXINR */
+#define WM8962_IN2R_TO_MIXINR_MASK 0x0004 /* IN2R_TO_MIXINR */
+#define WM8962_IN2R_TO_MIXINR_SHIFT 2 /* IN2R_TO_MIXINR */
+#define WM8962_IN2R_TO_MIXINR_WIDTH 1 /* IN2R_TO_MIXINR */
+#define WM8962_IN3R_TO_MIXINR 0x0002 /* IN3R_TO_MIXINR */
+#define WM8962_IN3R_TO_MIXINR_MASK 0x0002 /* IN3R_TO_MIXINR */
+#define WM8962_IN3R_TO_MIXINR_SHIFT 1 /* IN3R_TO_MIXINR */
+#define WM8962_IN3R_TO_MIXINR_WIDTH 1 /* IN3R_TO_MIXINR */
+#define WM8962_INPGAR_TO_MIXINR 0x0001 /* INPGAR_TO_MIXINR */
+#define WM8962_INPGAR_TO_MIXINR_MASK 0x0001 /* INPGAR_TO_MIXINR */
+#define WM8962_INPGAR_TO_MIXINR_SHIFT 0 /* INPGAR_TO_MIXINR */
+#define WM8962_INPGAR_TO_MIXINR_WIDTH 1 /* INPGAR_TO_MIXINR */
+
+/*
+ * R35 (0x23) - Input bias control
+ */
+#define WM8962_MIXIN_BIAS_MASK 0x0038 /* MIXIN_BIAS - [5:3] */
+#define WM8962_MIXIN_BIAS_SHIFT 3 /* MIXIN_BIAS - [5:3] */
+#define WM8962_MIXIN_BIAS_WIDTH 3 /* MIXIN_BIAS - [5:3] */
+#define WM8962_INPGA_BIAS_MASK 0x0007 /* INPGA_BIAS - [2:0] */
+#define WM8962_INPGA_BIAS_SHIFT 0 /* INPGA_BIAS - [2:0] */
+#define WM8962_INPGA_BIAS_WIDTH 3 /* INPGA_BIAS - [2:0] */
+
+/*
+ * R37 (0x25) - Left input PGA control
+ */
+#define WM8962_INPGAL_ENA 0x0010 /* INPGAL_ENA */
+#define WM8962_INPGAL_ENA_MASK 0x0010 /* INPGAL_ENA */
+#define WM8962_INPGAL_ENA_SHIFT 4 /* INPGAL_ENA */
+#define WM8962_INPGAL_ENA_WIDTH 1 /* INPGAL_ENA */
+#define WM8962_IN1L_TO_INPGAL 0x0008 /* IN1L_TO_INPGAL */
+#define WM8962_IN1L_TO_INPGAL_MASK 0x0008 /* IN1L_TO_INPGAL */
+#define WM8962_IN1L_TO_INPGAL_SHIFT 3 /* IN1L_TO_INPGAL */
+#define WM8962_IN1L_TO_INPGAL_WIDTH 1 /* IN1L_TO_INPGAL */
+#define WM8962_IN2L_TO_INPGAL 0x0004 /* IN2L_TO_INPGAL */
+#define WM8962_IN2L_TO_INPGAL_MASK 0x0004 /* IN2L_TO_INPGAL */
+#define WM8962_IN2L_TO_INPGAL_SHIFT 2 /* IN2L_TO_INPGAL */
+#define WM8962_IN2L_TO_INPGAL_WIDTH 1 /* IN2L_TO_INPGAL */
+#define WM8962_IN3L_TO_INPGAL 0x0002 /* IN3L_TO_INPGAL */
+#define WM8962_IN3L_TO_INPGAL_MASK 0x0002 /* IN3L_TO_INPGAL */
+#define WM8962_IN3L_TO_INPGAL_SHIFT 1 /* IN3L_TO_INPGAL */
+#define WM8962_IN3L_TO_INPGAL_WIDTH 1 /* IN3L_TO_INPGAL */
+#define WM8962_IN4L_TO_INPGAL 0x0001 /* IN4L_TO_INPGAL */
+#define WM8962_IN4L_TO_INPGAL_MASK 0x0001 /* IN4L_TO_INPGAL */
+#define WM8962_IN4L_TO_INPGAL_SHIFT 0 /* IN4L_TO_INPGAL */
+#define WM8962_IN4L_TO_INPGAL_WIDTH 1 /* IN4L_TO_INPGAL */
+
+/*
+ * R38 (0x26) - Right input PGA control
+ */
+#define WM8962_INPGAR_ENA 0x0010 /* INPGAR_ENA */
+#define WM8962_INPGAR_ENA_MASK 0x0010 /* INPGAR_ENA */
+#define WM8962_INPGAR_ENA_SHIFT 4 /* INPGAR_ENA */
+#define WM8962_INPGAR_ENA_WIDTH 1 /* INPGAR_ENA */
+#define WM8962_IN1R_TO_INPGAR 0x0008 /* IN1R_TO_INPGAR */
+#define WM8962_IN1R_TO_INPGAR_MASK 0x0008 /* IN1R_TO_INPGAR */
+#define WM8962_IN1R_TO_INPGAR_SHIFT 3 /* IN1R_TO_INPGAR */
+#define WM8962_IN1R_TO_INPGAR_WIDTH 1 /* IN1R_TO_INPGAR */
+#define WM8962_IN2R_TO_INPGAR 0x0004 /* IN2R_TO_INPGAR */
+#define WM8962_IN2R_TO_INPGAR_MASK 0x0004 /* IN2R_TO_INPGAR */
+#define WM8962_IN2R_TO_INPGAR_SHIFT 2 /* IN2R_TO_INPGAR */
+#define WM8962_IN2R_TO_INPGAR_WIDTH 1 /* IN2R_TO_INPGAR */
+#define WM8962_IN3R_TO_INPGAR 0x0002 /* IN3R_TO_INPGAR */
+#define WM8962_IN3R_TO_INPGAR_MASK 0x0002 /* IN3R_TO_INPGAR */
+#define WM8962_IN3R_TO_INPGAR_SHIFT 1 /* IN3R_TO_INPGAR */
+#define WM8962_IN3R_TO_INPGAR_WIDTH 1 /* IN3R_TO_INPGAR */
+#define WM8962_IN4R_TO_INPGAR 0x0001 /* IN4R_TO_INPGAR */
+#define WM8962_IN4R_TO_INPGAR_MASK 0x0001 /* IN4R_TO_INPGAR */
+#define WM8962_IN4R_TO_INPGAR_SHIFT 0 /* IN4R_TO_INPGAR */
+#define WM8962_IN4R_TO_INPGAR_WIDTH 1 /* IN4R_TO_INPGAR */
+
+/*
+ * R40 (0x28) - SPKOUTL volume
+ */
+#define WM8962_SPKOUT_VU 0x0100 /* SPKOUT_VU */
+#define WM8962_SPKOUT_VU_MASK 0x0100 /* SPKOUT_VU */
+#define WM8962_SPKOUT_VU_SHIFT 8 /* SPKOUT_VU */
+#define WM8962_SPKOUT_VU_WIDTH 1 /* SPKOUT_VU */
+#define WM8962_SPKOUTL_ZC 0x0080 /* SPKOUTL_ZC */
+#define WM8962_SPKOUTL_ZC_MASK 0x0080 /* SPKOUTL_ZC */
+#define WM8962_SPKOUTL_ZC_SHIFT 7 /* SPKOUTL_ZC */
+#define WM8962_SPKOUTL_ZC_WIDTH 1 /* SPKOUTL_ZC */
+#define WM8962_SPKOUTL_VOL_MASK 0x007F /* SPKOUTL_VOL - [6:0] */
+#define WM8962_SPKOUTL_VOL_SHIFT 0 /* SPKOUTL_VOL - [6:0] */
+#define WM8962_SPKOUTL_VOL_WIDTH 7 /* SPKOUTL_VOL - [6:0] */
+
+/*
+ * R41 (0x29) - SPKOUTR volume
+ */
+#define WM8962_SPKOUTR_ZC 0x0080 /* SPKOUTR_ZC */
+#define WM8962_SPKOUTR_ZC_MASK 0x0080 /* SPKOUTR_ZC */
+#define WM8962_SPKOUTR_ZC_SHIFT 7 /* SPKOUTR_ZC */
+#define WM8962_SPKOUTR_ZC_WIDTH 1 /* SPKOUTR_ZC */
+#define WM8962_SPKOUTR_VOL_MASK 0x007F /* SPKOUTR_VOL - [6:0] */
+#define WM8962_SPKOUTR_VOL_SHIFT 0 /* SPKOUTR_VOL - [6:0] */
+#define WM8962_SPKOUTR_VOL_WIDTH 7 /* SPKOUTR_VOL - [6:0] */
+
+/*
+ * R47 (0x2F) - Thermal Shutdown Status
+ */
+#define WM8962_TEMP_ERR_HP 0x0008 /* TEMP_ERR_HP */
+#define WM8962_TEMP_ERR_HP_MASK 0x0008 /* TEMP_ERR_HP */
+#define WM8962_TEMP_ERR_HP_SHIFT 3 /* TEMP_ERR_HP */
+#define WM8962_TEMP_ERR_HP_WIDTH 1 /* TEMP_ERR_HP */
+#define WM8962_TEMP_WARN_HP 0x0004 /* TEMP_WARN_HP */
+#define WM8962_TEMP_WARN_HP_MASK 0x0004 /* TEMP_WARN_HP */
+#define WM8962_TEMP_WARN_HP_SHIFT 2 /* TEMP_WARN_HP */
+#define WM8962_TEMP_WARN_HP_WIDTH 1 /* TEMP_WARN_HP */
+#define WM8962_TEMP_ERR_SPK 0x0002 /* TEMP_ERR_SPK */
+#define WM8962_TEMP_ERR_SPK_MASK 0x0002 /* TEMP_ERR_SPK */
+#define WM8962_TEMP_ERR_SPK_SHIFT 1 /* TEMP_ERR_SPK */
+#define WM8962_TEMP_ERR_SPK_WIDTH 1 /* TEMP_ERR_SPK */
+#define WM8962_TEMP_WARN_SPK 0x0001 /* TEMP_WARN_SPK */
+#define WM8962_TEMP_WARN_SPK_MASK 0x0001 /* TEMP_WARN_SPK */
+#define WM8962_TEMP_WARN_SPK_SHIFT 0 /* TEMP_WARN_SPK */
+#define WM8962_TEMP_WARN_SPK_WIDTH 1 /* TEMP_WARN_SPK */
+
+/*
+ * R48 (0x30) - Additional Control (4)
+ */
+#define WM8962_MICDET_THR_MASK 0x7000 /* MICDET_THR - [14:12] */
+#define WM8962_MICDET_THR_SHIFT 12 /* MICDET_THR - [14:12] */
+#define WM8962_MICDET_THR_WIDTH 3 /* MICDET_THR - [14:12] */
+#define WM8962_MICSHORT_THR_MASK 0x0C00 /* MICSHORT_THR - [11:10] */
+#define WM8962_MICSHORT_THR_SHIFT 10 /* MICSHORT_THR - [11:10] */
+#define WM8962_MICSHORT_THR_WIDTH 2 /* MICSHORT_THR - [11:10] */
+#define WM8962_MICDET_ENA 0x0200 /* MICDET_ENA */
+#define WM8962_MICDET_ENA_MASK 0x0200 /* MICDET_ENA */
+#define WM8962_MICDET_ENA_SHIFT 9 /* MICDET_ENA */
+#define WM8962_MICDET_ENA_WIDTH 1 /* MICDET_ENA */
+#define WM8962_MICDET_STS 0x0080 /* MICDET_STS */
+#define WM8962_MICDET_STS_MASK 0x0080 /* MICDET_STS */
+#define WM8962_MICDET_STS_SHIFT 7 /* MICDET_STS */
+#define WM8962_MICDET_STS_WIDTH 1 /* MICDET_STS */
+#define WM8962_MICSHORT_STS 0x0040 /* MICSHORT_STS */
+#define WM8962_MICSHORT_STS_MASK 0x0040 /* MICSHORT_STS */
+#define WM8962_MICSHORT_STS_SHIFT 6 /* MICSHORT_STS */
+#define WM8962_MICSHORT_STS_WIDTH 1 /* MICSHORT_STS */
+#define WM8962_TEMP_ENA_HP 0x0004 /* TEMP_ENA_HP */
+#define WM8962_TEMP_ENA_HP_MASK 0x0004 /* TEMP_ENA_HP */
+#define WM8962_TEMP_ENA_HP_SHIFT 2 /* TEMP_ENA_HP */
+#define WM8962_TEMP_ENA_HP_WIDTH 1 /* TEMP_ENA_HP */
+#define WM8962_TEMP_ENA_SPK 0x0002 /* TEMP_ENA_SPK */
+#define WM8962_TEMP_ENA_SPK_MASK 0x0002 /* TEMP_ENA_SPK */
+#define WM8962_TEMP_ENA_SPK_SHIFT 1 /* TEMP_ENA_SPK */
+#define WM8962_TEMP_ENA_SPK_WIDTH 1 /* TEMP_ENA_SPK */
+#define WM8962_MICBIAS_LVL 0x0001 /* MICBIAS_LVL */
+#define WM8962_MICBIAS_LVL_MASK 0x0001 /* MICBIAS_LVL */
+#define WM8962_MICBIAS_LVL_SHIFT 0 /* MICBIAS_LVL */
+#define WM8962_MICBIAS_LVL_WIDTH 1 /* MICBIAS_LVL */
+
+/*
+ * R49 (0x31) - Class D Control 1
+ */
+#define WM8962_SPKOUTR_ENA 0x0080 /* SPKOUTR_ENA */
+#define WM8962_SPKOUTR_ENA_MASK 0x0080 /* SPKOUTR_ENA */
+#define WM8962_SPKOUTR_ENA_SHIFT 7 /* SPKOUTR_ENA */
+#define WM8962_SPKOUTR_ENA_WIDTH 1 /* SPKOUTR_ENA */
+#define WM8962_SPKOUTL_ENA 0x0040 /* SPKOUTL_ENA */
+#define WM8962_SPKOUTL_ENA_MASK 0x0040 /* SPKOUTL_ENA */
+#define WM8962_SPKOUTL_ENA_SHIFT 6 /* SPKOUTL_ENA */
+#define WM8962_SPKOUTL_ENA_WIDTH 1 /* SPKOUTL_ENA */
+#define WM8962_SPKOUTL_PGA_MUTE 0x0002 /* SPKOUTL_PGA_MUTE */
+#define WM8962_SPKOUTL_PGA_MUTE_MASK 0x0002 /* SPKOUTL_PGA_MUTE */
+#define WM8962_SPKOUTL_PGA_MUTE_SHIFT 1 /* SPKOUTL_PGA_MUTE */
+#define WM8962_SPKOUTL_PGA_MUTE_WIDTH 1 /* SPKOUTL_PGA_MUTE */
+#define WM8962_SPKOUTR_PGA_MUTE 0x0001 /* SPKOUTR_PGA_MUTE */
+#define WM8962_SPKOUTR_PGA_MUTE_MASK 0x0001 /* SPKOUTR_PGA_MUTE */
+#define WM8962_SPKOUTR_PGA_MUTE_SHIFT 0 /* SPKOUTR_PGA_MUTE */
+#define WM8962_SPKOUTR_PGA_MUTE_WIDTH 1 /* SPKOUTR_PGA_MUTE */
+
+/*
+ * R51 (0x33) - Class D Control 2
+ */
+#define WM8962_SPK_MONO 0x0040 /* SPK_MONO */
+#define WM8962_SPK_MONO_MASK 0x0040 /* SPK_MONO */
+#define WM8962_SPK_MONO_SHIFT 6 /* SPK_MONO */
+#define WM8962_SPK_MONO_WIDTH 1 /* SPK_MONO */
+#define WM8962_CLASSD_VOL_MASK 0x0007 /* CLASSD_VOL - [2:0] */
+#define WM8962_CLASSD_VOL_SHIFT 0 /* CLASSD_VOL - [2:0] */
+#define WM8962_CLASSD_VOL_WIDTH 3 /* CLASSD_VOL - [2:0] */
+
+/*
+ * R56 (0x38) - Clocking 4
+ */
+#define WM8962_SYSCLK_RATE_MASK 0x001E /* SYSCLK_RATE - [4:1] */
+#define WM8962_SYSCLK_RATE_SHIFT 1 /* SYSCLK_RATE - [4:1] */
+#define WM8962_SYSCLK_RATE_WIDTH 4 /* SYSCLK_RATE - [4:1] */
+
+/*
+ * R57 (0x39) - DAC DSP Mixing (1)
+ */
+#define WM8962_DAC_MONOMIX 0x0200 /* DAC_MONOMIX */
+#define WM8962_DAC_MONOMIX_MASK 0x0200 /* DAC_MONOMIX */
+#define WM8962_DAC_MONOMIX_SHIFT 9 /* DAC_MONOMIX */
+#define WM8962_DAC_MONOMIX_WIDTH 1 /* DAC_MONOMIX */
+#define WM8962_ADCR_DAC_SVOL_MASK 0x00F0 /* ADCR_DAC_SVOL - [7:4] */
+#define WM8962_ADCR_DAC_SVOL_SHIFT 4 /* ADCR_DAC_SVOL - [7:4] */
+#define WM8962_ADCR_DAC_SVOL_WIDTH 4 /* ADCR_DAC_SVOL - [7:4] */
+#define WM8962_ADC_TO_DACR_MASK 0x000C /* ADC_TO_DACR - [3:2] */
+#define WM8962_ADC_TO_DACR_SHIFT 2 /* ADC_TO_DACR - [3:2] */
+#define WM8962_ADC_TO_DACR_WIDTH 2 /* ADC_TO_DACR - [3:2] */
+
+/*
+ * R58 (0x3A) - DAC DSP Mixing (2)
+ */
+#define WM8962_ADCL_DAC_SVOL_MASK 0x00F0 /* ADCL_DAC_SVOL - [7:4] */
+#define WM8962_ADCL_DAC_SVOL_SHIFT 4 /* ADCL_DAC_SVOL - [7:4] */
+#define WM8962_ADCL_DAC_SVOL_WIDTH 4 /* ADCL_DAC_SVOL - [7:4] */
+#define WM8962_ADC_TO_DACL_MASK 0x000C /* ADC_TO_DACL - [3:2] */
+#define WM8962_ADC_TO_DACL_SHIFT 2 /* ADC_TO_DACL - [3:2] */
+#define WM8962_ADC_TO_DACL_WIDTH 2 /* ADC_TO_DACL - [3:2] */
+
+/*
+ * R60 (0x3C) - DC Servo 0
+ */
+#define WM8962_INL_DCS_ENA 0x0080 /* INL_DCS_ENA */
+#define WM8962_INL_DCS_ENA_MASK 0x0080 /* INL_DCS_ENA */
+#define WM8962_INL_DCS_ENA_SHIFT 7 /* INL_DCS_ENA */
+#define WM8962_INL_DCS_ENA_WIDTH 1 /* INL_DCS_ENA */
+#define WM8962_INL_DCS_STARTUP 0x0040 /* INL_DCS_STARTUP */
+#define WM8962_INL_DCS_STARTUP_MASK 0x0040 /* INL_DCS_STARTUP */
+#define WM8962_INL_DCS_STARTUP_SHIFT 6 /* INL_DCS_STARTUP */
+#define WM8962_INL_DCS_STARTUP_WIDTH 1 /* INL_DCS_STARTUP */
+#define WM8962_INR_DCS_ENA 0x0008 /* INR_DCS_ENA */
+#define WM8962_INR_DCS_ENA_MASK 0x0008 /* INR_DCS_ENA */
+#define WM8962_INR_DCS_ENA_SHIFT 3 /* INR_DCS_ENA */
+#define WM8962_INR_DCS_ENA_WIDTH 1 /* INR_DCS_ENA */
+#define WM8962_INR_DCS_STARTUP 0x0004 /* INR_DCS_STARTUP */
+#define WM8962_INR_DCS_STARTUP_MASK 0x0004 /* INR_DCS_STARTUP */
+#define WM8962_INR_DCS_STARTUP_SHIFT 2 /* INR_DCS_STARTUP */
+#define WM8962_INR_DCS_STARTUP_WIDTH 1 /* INR_DCS_STARTUP */
+
+/*
+ * R61 (0x3D) - DC Servo 1
+ */
+#define WM8962_HP1L_DCS_ENA 0x0080 /* HP1L_DCS_ENA */
+#define WM8962_HP1L_DCS_ENA_MASK 0x0080 /* HP1L_DCS_ENA */
+#define WM8962_HP1L_DCS_ENA_SHIFT 7 /* HP1L_DCS_ENA */
+#define WM8962_HP1L_DCS_ENA_WIDTH 1 /* HP1L_DCS_ENA */
+#define WM8962_HP1L_DCS_STARTUP 0x0040 /* HP1L_DCS_STARTUP */
+#define WM8962_HP1L_DCS_STARTUP_MASK 0x0040 /* HP1L_DCS_STARTUP */
+#define WM8962_HP1L_DCS_STARTUP_SHIFT 6 /* HP1L_DCS_STARTUP */
+#define WM8962_HP1L_DCS_STARTUP_WIDTH 1 /* HP1L_DCS_STARTUP */
+#define WM8962_HP1L_DCS_SYNC 0x0010 /* HP1L_DCS_SYNC */
+#define WM8962_HP1L_DCS_SYNC_MASK 0x0010 /* HP1L_DCS_SYNC */
+#define WM8962_HP1L_DCS_SYNC_SHIFT 4 /* HP1L_DCS_SYNC */
+#define WM8962_HP1L_DCS_SYNC_WIDTH 1 /* HP1L_DCS_SYNC */
+#define WM8962_HP1R_DCS_ENA 0x0008 /* HP1R_DCS_ENA */
+#define WM8962_HP1R_DCS_ENA_MASK 0x0008 /* HP1R_DCS_ENA */
+#define WM8962_HP1R_DCS_ENA_SHIFT 3 /* HP1R_DCS_ENA */
+#define WM8962_HP1R_DCS_ENA_WIDTH 1 /* HP1R_DCS_ENA */
+#define WM8962_HP1R_DCS_STARTUP 0x0004 /* HP1R_DCS_STARTUP */
+#define WM8962_HP1R_DCS_STARTUP_MASK 0x0004 /* HP1R_DCS_STARTUP */
+#define WM8962_HP1R_DCS_STARTUP_SHIFT 2 /* HP1R_DCS_STARTUP */
+#define WM8962_HP1R_DCS_STARTUP_WIDTH 1 /* HP1R_DCS_STARTUP */
+#define WM8962_HP1R_DCS_SYNC 0x0001 /* HP1R_DCS_SYNC */
+#define WM8962_HP1R_DCS_SYNC_MASK 0x0001 /* HP1R_DCS_SYNC */
+#define WM8962_HP1R_DCS_SYNC_SHIFT 0 /* HP1R_DCS_SYNC */
+#define WM8962_HP1R_DCS_SYNC_WIDTH 1 /* HP1R_DCS_SYNC */
+
+/*
+ * R64 (0x40) - DC Servo 4
+ */
+#define WM8962_HP1_DCS_SYNC_STEPS_MASK 0x3F80 /* HP1_DCS_SYNC_STEPS - [13:7] */
+#define WM8962_HP1_DCS_SYNC_STEPS_SHIFT 7 /* HP1_DCS_SYNC_STEPS - [13:7] */
+#define WM8962_HP1_DCS_SYNC_STEPS_WIDTH 7 /* HP1_DCS_SYNC_STEPS - [13:7] */
+
+/*
+ * R66 (0x42) - DC Servo 6
+ */
+#define WM8962_DCS_STARTUP_DONE_INL 0x0400 /* DCS_STARTUP_DONE_INL */
+#define WM8962_DCS_STARTUP_DONE_INL_MASK 0x0400 /* DCS_STARTUP_DONE_INL */
+#define WM8962_DCS_STARTUP_DONE_INL_SHIFT 10 /* DCS_STARTUP_DONE_INL */
+#define WM8962_DCS_STARTUP_DONE_INL_WIDTH 1 /* DCS_STARTUP_DONE_INL */
+#define WM8962_DCS_STARTUP_DONE_INR 0x0200 /* DCS_STARTUP_DONE_INR */
+#define WM8962_DCS_STARTUP_DONE_INR_MASK 0x0200 /* DCS_STARTUP_DONE_INR */
+#define WM8962_DCS_STARTUP_DONE_INR_SHIFT 9 /* DCS_STARTUP_DONE_INR */
+#define WM8962_DCS_STARTUP_DONE_INR_WIDTH 1 /* DCS_STARTUP_DONE_INR */
+#define WM8962_DCS_STARTUP_DONE_HP1L 0x0100 /* DCS_STARTUP_DONE_HP1L */
+#define WM8962_DCS_STARTUP_DONE_HP1L_MASK 0x0100 /* DCS_STARTUP_DONE_HP1L */
+#define WM8962_DCS_STARTUP_DONE_HP1L_SHIFT 8 /* DCS_STARTUP_DONE_HP1L */
+#define WM8962_DCS_STARTUP_DONE_HP1L_WIDTH 1 /* DCS_STARTUP_DONE_HP1L */
+#define WM8962_DCS_STARTUP_DONE_HP1R 0x0080 /* DCS_STARTUP_DONE_HP1R */
+#define WM8962_DCS_STARTUP_DONE_HP1R_MASK 0x0080 /* DCS_STARTUP_DONE_HP1R */
+#define WM8962_DCS_STARTUP_DONE_HP1R_SHIFT 7 /* DCS_STARTUP_DONE_HP1R */
+#define WM8962_DCS_STARTUP_DONE_HP1R_WIDTH 1 /* DCS_STARTUP_DONE_HP1R */
+
+/*
+ * R68 (0x44) - Analogue PGA Bias
+ */
+#define WM8962_HP_PGAS_BIAS_MASK 0x0007 /* HP_PGAS_BIAS - [2:0] */
+#define WM8962_HP_PGAS_BIAS_SHIFT 0 /* HP_PGAS_BIAS - [2:0] */
+#define WM8962_HP_PGAS_BIAS_WIDTH 3 /* HP_PGAS_BIAS - [2:0] */
+
+/*
+ * R69 (0x45) - Analogue HP 0
+ */
+#define WM8962_HP1L_RMV_SHORT 0x0080 /* HP1L_RMV_SHORT */
+#define WM8962_HP1L_RMV_SHORT_MASK 0x0080 /* HP1L_RMV_SHORT */
+#define WM8962_HP1L_RMV_SHORT_SHIFT 7 /* HP1L_RMV_SHORT */
+#define WM8962_HP1L_RMV_SHORT_WIDTH 1 /* HP1L_RMV_SHORT */
+#define WM8962_HP1L_ENA_OUTP 0x0040 /* HP1L_ENA_OUTP */
+#define WM8962_HP1L_ENA_OUTP_MASK 0x0040 /* HP1L_ENA_OUTP */
+#define WM8962_HP1L_ENA_OUTP_SHIFT 6 /* HP1L_ENA_OUTP */
+#define WM8962_HP1L_ENA_OUTP_WIDTH 1 /* HP1L_ENA_OUTP */
+#define WM8962_HP1L_ENA_DLY 0x0020 /* HP1L_ENA_DLY */
+#define WM8962_HP1L_ENA_DLY_MASK 0x0020 /* HP1L_ENA_DLY */
+#define WM8962_HP1L_ENA_DLY_SHIFT 5 /* HP1L_ENA_DLY */
+#define WM8962_HP1L_ENA_DLY_WIDTH 1 /* HP1L_ENA_DLY */
+#define WM8962_HP1L_ENA 0x0010 /* HP1L_ENA */
+#define WM8962_HP1L_ENA_MASK 0x0010 /* HP1L_ENA */
+#define WM8962_HP1L_ENA_SHIFT 4 /* HP1L_ENA */
+#define WM8962_HP1L_ENA_WIDTH 1 /* HP1L_ENA */
+#define WM8962_HP1R_RMV_SHORT 0x0008 /* HP1R_RMV_SHORT */
+#define WM8962_HP1R_RMV_SHORT_MASK 0x0008 /* HP1R_RMV_SHORT */
+#define WM8962_HP1R_RMV_SHORT_SHIFT 3 /* HP1R_RMV_SHORT */
+#define WM8962_HP1R_RMV_SHORT_WIDTH 1 /* HP1R_RMV_SHORT */
+#define WM8962_HP1R_ENA_OUTP 0x0004 /* HP1R_ENA_OUTP */
+#define WM8962_HP1R_ENA_OUTP_MASK 0x0004 /* HP1R_ENA_OUTP */
+#define WM8962_HP1R_ENA_OUTP_SHIFT 2 /* HP1R_ENA_OUTP */
+#define WM8962_HP1R_ENA_OUTP_WIDTH 1 /* HP1R_ENA_OUTP */
+#define WM8962_HP1R_ENA_DLY 0x0002 /* HP1R_ENA_DLY */
+#define WM8962_HP1R_ENA_DLY_MASK 0x0002 /* HP1R_ENA_DLY */
+#define WM8962_HP1R_ENA_DLY_SHIFT 1 /* HP1R_ENA_DLY */
+#define WM8962_HP1R_ENA_DLY_WIDTH 1 /* HP1R_ENA_DLY */
+#define WM8962_HP1R_ENA 0x0001 /* HP1R_ENA */
+#define WM8962_HP1R_ENA_MASK 0x0001 /* HP1R_ENA */
+#define WM8962_HP1R_ENA_SHIFT 0 /* HP1R_ENA */
+#define WM8962_HP1R_ENA_WIDTH 1 /* HP1R_ENA */
+
+/*
+ * R71 (0x47) - Analogue HP 2
+ */
+#define WM8962_HP1L_VOL_MASK 0x01C0 /* HP1L_VOL - [8:6] */
+#define WM8962_HP1L_VOL_SHIFT 6 /* HP1L_VOL - [8:6] */
+#define WM8962_HP1L_VOL_WIDTH 3 /* HP1L_VOL - [8:6] */
+#define WM8962_HP1R_VOL_MASK 0x0038 /* HP1R_VOL - [5:3] */
+#define WM8962_HP1R_VOL_SHIFT 3 /* HP1R_VOL - [5:3] */
+#define WM8962_HP1R_VOL_WIDTH 3 /* HP1R_VOL - [5:3] */
+#define WM8962_HP_BIAS_BOOST_MASK 0x0007 /* HP_BIAS_BOOST - [2:0] */
+#define WM8962_HP_BIAS_BOOST_SHIFT 0 /* HP_BIAS_BOOST - [2:0] */
+#define WM8962_HP_BIAS_BOOST_WIDTH 3 /* HP_BIAS_BOOST - [2:0] */
+
+/*
+ * R72 (0x48) - Charge Pump 1
+ */
+#define WM8962_CP_ENA 0x0001 /* CP_ENA */
+#define WM8962_CP_ENA_MASK 0x0001 /* CP_ENA */
+#define WM8962_CP_ENA_SHIFT 0 /* CP_ENA */
+#define WM8962_CP_ENA_WIDTH 1 /* CP_ENA */
+
+/*
+ * R82 (0x52) - Charge Pump B
+ */
+#define WM8962_CP_DYN_PWR 0x0001 /* CP_DYN_PWR */
+#define WM8962_CP_DYN_PWR_MASK 0x0001 /* CP_DYN_PWR */
+#define WM8962_CP_DYN_PWR_SHIFT 0 /* CP_DYN_PWR */
+#define WM8962_CP_DYN_PWR_WIDTH 1 /* CP_DYN_PWR */
+
+/*
+ * R87 (0x57) - Write Sequencer Control 1
+ */
+#define WM8962_WSEQ_AUTOSEQ_ENA 0x0080 /* WSEQ_AUTOSEQ_ENA */
+#define WM8962_WSEQ_AUTOSEQ_ENA_MASK 0x0080 /* WSEQ_AUTOSEQ_ENA */
+#define WM8962_WSEQ_AUTOSEQ_ENA_SHIFT 7 /* WSEQ_AUTOSEQ_ENA */
+#define WM8962_WSEQ_AUTOSEQ_ENA_WIDTH 1 /* WSEQ_AUTOSEQ_ENA */
+#define WM8962_WSEQ_ENA 0x0020 /* WSEQ_ENA */
+#define WM8962_WSEQ_ENA_MASK 0x0020 /* WSEQ_ENA */
+#define WM8962_WSEQ_ENA_SHIFT 5 /* WSEQ_ENA */
+#define WM8962_WSEQ_ENA_WIDTH 1 /* WSEQ_ENA */
+
+/*
+ * R90 (0x5A) - Write Sequencer Control 2
+ */
+#define WM8962_WSEQ_ABORT 0x0100 /* WSEQ_ABORT */
+#define WM8962_WSEQ_ABORT_MASK 0x0100 /* WSEQ_ABORT */
+#define WM8962_WSEQ_ABORT_SHIFT 8 /* WSEQ_ABORT */
+#define WM8962_WSEQ_ABORT_WIDTH 1 /* WSEQ_ABORT */
+#define WM8962_WSEQ_START 0x0080 /* WSEQ_START */
+#define WM8962_WSEQ_START_MASK 0x0080 /* WSEQ_START */
+#define WM8962_WSEQ_START_SHIFT 7 /* WSEQ_START */
+#define WM8962_WSEQ_START_WIDTH 1 /* WSEQ_START */
+#define WM8962_WSEQ_START_INDEX_MASK 0x007F /* WSEQ_START_INDEX - [6:0] */
+#define WM8962_WSEQ_START_INDEX_SHIFT 0 /* WSEQ_START_INDEX - [6:0] */
+#define WM8962_WSEQ_START_INDEX_WIDTH 7 /* WSEQ_START_INDEX - [6:0] */
+
+/*
+ * R93 (0x5D) - Write Sequencer Control 3
+ */
+#define WM8962_WSEQ_CURRENT_INDEX_MASK 0x03F8 /* WSEQ_CURRENT_INDEX - [9:3] */
+#define WM8962_WSEQ_CURRENT_INDEX_SHIFT 3 /* WSEQ_CURRENT_INDEX - [9:3] */
+#define WM8962_WSEQ_CURRENT_INDEX_WIDTH 7 /* WSEQ_CURRENT_INDEX - [9:3] */
+#define WM8962_WSEQ_BUSY 0x0001 /* WSEQ_BUSY */
+#define WM8962_WSEQ_BUSY_MASK 0x0001 /* WSEQ_BUSY */
+#define WM8962_WSEQ_BUSY_SHIFT 0 /* WSEQ_BUSY */
+#define WM8962_WSEQ_BUSY_WIDTH 1 /* WSEQ_BUSY */
+
+/*
+ * R94 (0x5E) - Control Interface
+ */
+#define WM8962_SPI_CONTRD 0x0040 /* SPI_CONTRD */
+#define WM8962_SPI_CONTRD_MASK 0x0040 /* SPI_CONTRD */
+#define WM8962_SPI_CONTRD_SHIFT 6 /* SPI_CONTRD */
+#define WM8962_SPI_CONTRD_WIDTH 1 /* SPI_CONTRD */
+#define WM8962_SPI_4WIRE 0x0020 /* SPI_4WIRE */
+#define WM8962_SPI_4WIRE_MASK 0x0020 /* SPI_4WIRE */
+#define WM8962_SPI_4WIRE_SHIFT 5 /* SPI_4WIRE */
+#define WM8962_SPI_4WIRE_WIDTH 1 /* SPI_4WIRE */
+#define WM8962_SPI_CFG 0x0010 /* SPI_CFG */
+#define WM8962_SPI_CFG_MASK 0x0010 /* SPI_CFG */
+#define WM8962_SPI_CFG_SHIFT 4 /* SPI_CFG */
+#define WM8962_SPI_CFG_WIDTH 1 /* SPI_CFG */
+
+/*
+ * R99 (0x63) - Mixer Enables
+ */
+#define WM8962_HPMIXL_ENA 0x0008 /* HPMIXL_ENA */
+#define WM8962_HPMIXL_ENA_MASK 0x0008 /* HPMIXL_ENA */
+#define WM8962_HPMIXL_ENA_SHIFT 3 /* HPMIXL_ENA */
+#define WM8962_HPMIXL_ENA_WIDTH 1 /* HPMIXL_ENA */
+#define WM8962_HPMIXR_ENA 0x0004 /* HPMIXR_ENA */
+#define WM8962_HPMIXR_ENA_MASK 0x0004 /* HPMIXR_ENA */
+#define WM8962_HPMIXR_ENA_SHIFT 2 /* HPMIXR_ENA */
+#define WM8962_HPMIXR_ENA_WIDTH 1 /* HPMIXR_ENA */
+#define WM8962_SPKMIXL_ENA 0x0002 /* SPKMIXL_ENA */
+#define WM8962_SPKMIXL_ENA_MASK 0x0002 /* SPKMIXL_ENA */
+#define WM8962_SPKMIXL_ENA_SHIFT 1 /* SPKMIXL_ENA */
+#define WM8962_SPKMIXL_ENA_WIDTH 1 /* SPKMIXL_ENA */
+#define WM8962_SPKMIXR_ENA 0x0001 /* SPKMIXR_ENA */
+#define WM8962_SPKMIXR_ENA_MASK 0x0001 /* SPKMIXR_ENA */
+#define WM8962_SPKMIXR_ENA_SHIFT 0 /* SPKMIXR_ENA */
+#define WM8962_SPKMIXR_ENA_WIDTH 1 /* SPKMIXR_ENA */
+
+/*
+ * R100 (0x64) - Headphone Mixer (1)
+ */
+#define WM8962_HPMIXL_TO_HPOUTL_PGA 0x0080 /* HPMIXL_TO_HPOUTL_PGA */
+#define WM8962_HPMIXL_TO_HPOUTL_PGA_MASK 0x0080 /* HPMIXL_TO_HPOUTL_PGA */
+#define WM8962_HPMIXL_TO_HPOUTL_PGA_SHIFT 7 /* HPMIXL_TO_HPOUTL_PGA */
+#define WM8962_HPMIXL_TO_HPOUTL_PGA_WIDTH 1 /* HPMIXL_TO_HPOUTL_PGA */
+#define WM8962_DACL_TO_HPMIXL 0x0020 /* DACL_TO_HPMIXL */
+#define WM8962_DACL_TO_HPMIXL_MASK 0x0020 /* DACL_TO_HPMIXL */
+#define WM8962_DACL_TO_HPMIXL_SHIFT 5 /* DACL_TO_HPMIXL */
+#define WM8962_DACL_TO_HPMIXL_WIDTH 1 /* DACL_TO_HPMIXL */
+#define WM8962_DACR_TO_HPMIXL 0x0010 /* DACR_TO_HPMIXL */
+#define WM8962_DACR_TO_HPMIXL_MASK 0x0010 /* DACR_TO_HPMIXL */
+#define WM8962_DACR_TO_HPMIXL_SHIFT 4 /* DACR_TO_HPMIXL */
+#define WM8962_DACR_TO_HPMIXL_WIDTH 1 /* DACR_TO_HPMIXL */
+#define WM8962_MIXINL_TO_HPMIXL 0x0008 /* MIXINL_TO_HPMIXL */
+#define WM8962_MIXINL_TO_HPMIXL_MASK 0x0008 /* MIXINL_TO_HPMIXL */
+#define WM8962_MIXINL_TO_HPMIXL_SHIFT 3 /* MIXINL_TO_HPMIXL */
+#define WM8962_MIXINL_TO_HPMIXL_WIDTH 1 /* MIXINL_TO_HPMIXL */
+#define WM8962_MIXINR_TO_HPMIXL 0x0004 /* MIXINR_TO_HPMIXL */
+#define WM8962_MIXINR_TO_HPMIXL_MASK 0x0004 /* MIXINR_TO_HPMIXL */
+#define WM8962_MIXINR_TO_HPMIXL_SHIFT 2 /* MIXINR_TO_HPMIXL */
+#define WM8962_MIXINR_TO_HPMIXL_WIDTH 1 /* MIXINR_TO_HPMIXL */
+#define WM8962_IN4L_TO_HPMIXL 0x0002 /* IN4L_TO_HPMIXL */
+#define WM8962_IN4L_TO_HPMIXL_MASK 0x0002 /* IN4L_TO_HPMIXL */
+#define WM8962_IN4L_TO_HPMIXL_SHIFT 1 /* IN4L_TO_HPMIXL */
+#define WM8962_IN4L_TO_HPMIXL_WIDTH 1 /* IN4L_TO_HPMIXL */
+#define WM8962_IN4R_TO_HPMIXL 0x0001 /* IN4R_TO_HPMIXL */
+#define WM8962_IN4R_TO_HPMIXL_MASK 0x0001 /* IN4R_TO_HPMIXL */
+#define WM8962_IN4R_TO_HPMIXL_SHIFT 0 /* IN4R_TO_HPMIXL */
+#define WM8962_IN4R_TO_HPMIXL_WIDTH 1 /* IN4R_TO_HPMIXL */
+
+/*
+ * R101 (0x65) - Headphone Mixer (2)
+ */
+#define WM8962_HPMIXR_TO_HPOUTR_PGA 0x0080 /* HPMIXR_TO_HPOUTR_PGA */
+#define WM8962_HPMIXR_TO_HPOUTR_PGA_MASK 0x0080 /* HPMIXR_TO_HPOUTR_PGA */
+#define WM8962_HPMIXR_TO_HPOUTR_PGA_SHIFT 7 /* HPMIXR_TO_HPOUTR_PGA */
+#define WM8962_HPMIXR_TO_HPOUTR_PGA_WIDTH 1 /* HPMIXR_TO_HPOUTR_PGA */
+#define WM8962_DACL_TO_HPMIXR 0x0020 /* DACL_TO_HPMIXR */
+#define WM8962_DACL_TO_HPMIXR_MASK 0x0020 /* DACL_TO_HPMIXR */
+#define WM8962_DACL_TO_HPMIXR_SHIFT 5 /* DACL_TO_HPMIXR */
+#define WM8962_DACL_TO_HPMIXR_WIDTH 1 /* DACL_TO_HPMIXR */
+#define WM8962_DACR_TO_HPMIXR 0x0010 /* DACR_TO_HPMIXR */
+#define WM8962_DACR_TO_HPMIXR_MASK 0x0010 /* DACR_TO_HPMIXR */
+#define WM8962_DACR_TO_HPMIXR_SHIFT 4 /* DACR_TO_HPMIXR */
+#define WM8962_DACR_TO_HPMIXR_WIDTH 1 /* DACR_TO_HPMIXR */
+#define WM8962_MIXINL_TO_HPMIXR 0x0008 /* MIXINL_TO_HPMIXR */
+#define WM8962_MIXINL_TO_HPMIXR_MASK 0x0008 /* MIXINL_TO_HPMIXR */
+#define WM8962_MIXINL_TO_HPMIXR_SHIFT 3 /* MIXINL_TO_HPMIXR */
+#define WM8962_MIXINL_TO_HPMIXR_WIDTH 1 /* MIXINL_TO_HPMIXR */
+#define WM8962_MIXINR_TO_HPMIXR 0x0004 /* MIXINR_TO_HPMIXR */
+#define WM8962_MIXINR_TO_HPMIXR_MASK 0x0004 /* MIXINR_TO_HPMIXR */
+#define WM8962_MIXINR_TO_HPMIXR_SHIFT 2 /* MIXINR_TO_HPMIXR */
+#define WM8962_MIXINR_TO_HPMIXR_WIDTH 1 /* MIXINR_TO_HPMIXR */
+#define WM8962_IN4L_TO_HPMIXR 0x0002 /* IN4L_TO_HPMIXR */
+#define WM8962_IN4L_TO_HPMIXR_MASK 0x0002 /* IN4L_TO_HPMIXR */
+#define WM8962_IN4L_TO_HPMIXR_SHIFT 1 /* IN4L_TO_HPMIXR */
+#define WM8962_IN4L_TO_HPMIXR_WIDTH 1 /* IN4L_TO_HPMIXR */
+#define WM8962_IN4R_TO_HPMIXR 0x0001 /* IN4R_TO_HPMIXR */
+#define WM8962_IN4R_TO_HPMIXR_MASK 0x0001 /* IN4R_TO_HPMIXR */
+#define WM8962_IN4R_TO_HPMIXR_SHIFT 0 /* IN4R_TO_HPMIXR */
+#define WM8962_IN4R_TO_HPMIXR_WIDTH 1 /* IN4R_TO_HPMIXR */
+
+/*
+ * R102 (0x66) - Headphone Mixer (3)
+ */
+#define WM8962_HPMIXL_MUTE 0x0100 /* HPMIXL_MUTE */
+#define WM8962_HPMIXL_MUTE_MASK 0x0100 /* HPMIXL_MUTE */
+#define WM8962_HPMIXL_MUTE_SHIFT 8 /* HPMIXL_MUTE */
+#define WM8962_HPMIXL_MUTE_WIDTH 1 /* HPMIXL_MUTE */
+#define WM8962_MIXINL_HPMIXL_VOL 0x0080 /* MIXINL_HPMIXL_VOL */
+#define WM8962_MIXINL_HPMIXL_VOL_MASK 0x0080 /* MIXINL_HPMIXL_VOL */
+#define WM8962_MIXINL_HPMIXL_VOL_SHIFT 7 /* MIXINL_HPMIXL_VOL */
+#define WM8962_MIXINL_HPMIXL_VOL_WIDTH 1 /* MIXINL_HPMIXL_VOL */
+#define WM8962_MIXINR_HPMIXL_VOL 0x0040 /* MIXINR_HPMIXL_VOL */
+#define WM8962_MIXINR_HPMIXL_VOL_MASK 0x0040 /* MIXINR_HPMIXL_VOL */
+#define WM8962_MIXINR_HPMIXL_VOL_SHIFT 6 /* MIXINR_HPMIXL_VOL */
+#define WM8962_MIXINR_HPMIXL_VOL_WIDTH 1 /* MIXINR_HPMIXL_VOL */
+#define WM8962_IN4L_HPMIXL_VOL_MASK 0x0038 /* IN4L_HPMIXL_VOL - [5:3] */
+#define WM8962_IN4L_HPMIXL_VOL_SHIFT 3 /* IN4L_HPMIXL_VOL - [5:3] */
+#define WM8962_IN4L_HPMIXL_VOL_WIDTH 3 /* IN4L_HPMIXL_VOL - [5:3] */
+#define WM8962_IN4R_HPMIXL_VOL_MASK 0x0007 /* IN4R_HPMIXL_VOL - [2:0] */
+#define WM8962_IN4R_HPMIXL_VOL_SHIFT 0 /* IN4R_HPMIXL_VOL - [2:0] */
+#define WM8962_IN4R_HPMIXL_VOL_WIDTH 3 /* IN4R_HPMIXL_VOL - [2:0] */
+
+/*
+ * R103 (0x67) - Headphone Mixer (4)
+ */
+#define WM8962_HPMIXR_MUTE 0x0100 /* HPMIXR_MUTE */
+#define WM8962_HPMIXR_MUTE_MASK 0x0100 /* HPMIXR_MUTE */
+#define WM8962_HPMIXR_MUTE_SHIFT 8 /* HPMIXR_MUTE */
+#define WM8962_HPMIXR_MUTE_WIDTH 1 /* HPMIXR_MUTE */
+#define WM8962_MIXINL_HPMIXR_VOL 0x0080 /* MIXINL_HPMIXR_VOL */
+#define WM8962_MIXINL_HPMIXR_VOL_MASK 0x0080 /* MIXINL_HPMIXR_VOL */
+#define WM8962_MIXINL_HPMIXR_VOL_SHIFT 7 /* MIXINL_HPMIXR_VOL */
+#define WM8962_MIXINL_HPMIXR_VOL_WIDTH 1 /* MIXINL_HPMIXR_VOL */
+#define WM8962_MIXINR_HPMIXR_VOL 0x0040 /* MIXINR_HPMIXR_VOL */
+#define WM8962_MIXINR_HPMIXR_VOL_MASK 0x0040 /* MIXINR_HPMIXR_VOL */
+#define WM8962_MIXINR_HPMIXR_VOL_SHIFT 6 /* MIXINR_HPMIXR_VOL */
+#define WM8962_MIXINR_HPMIXR_VOL_WIDTH 1 /* MIXINR_HPMIXR_VOL */
+#define WM8962_IN4L_HPMIXR_VOL_MASK 0x0038 /* IN4L_HPMIXR_VOL - [5:3] */
+#define WM8962_IN4L_HPMIXR_VOL_SHIFT 3 /* IN4L_HPMIXR_VOL - [5:3] */
+#define WM8962_IN4L_HPMIXR_VOL_WIDTH 3 /* IN4L_HPMIXR_VOL - [5:3] */
+#define WM8962_IN4R_HPMIXR_VOL_MASK 0x0007 /* IN4R_HPMIXR_VOL - [2:0] */
+#define WM8962_IN4R_HPMIXR_VOL_SHIFT 0 /* IN4R_HPMIXR_VOL - [2:0] */
+#define WM8962_IN4R_HPMIXR_VOL_WIDTH 3 /* IN4R_HPMIXR_VOL - [2:0] */
+
+/*
+ * R105 (0x69) - Speaker Mixer (1)
+ */
+#define WM8962_SPKMIXL_TO_SPKOUTL_PGA 0x0080 /* SPKMIXL_TO_SPKOUTL_PGA */
+#define WM8962_SPKMIXL_TO_SPKOUTL_PGA_MASK 0x0080 /* SPKMIXL_TO_SPKOUTL_PGA */
+#define WM8962_SPKMIXL_TO_SPKOUTL_PGA_SHIFT 7 /* SPKMIXL_TO_SPKOUTL_PGA */
+#define WM8962_SPKMIXL_TO_SPKOUTL_PGA_WIDTH 1 /* SPKMIXL_TO_SPKOUTL_PGA */
+#define WM8962_DACL_TO_SPKMIXL 0x0020 /* DACL_TO_SPKMIXL */
+#define WM8962_DACL_TO_SPKMIXL_MASK 0x0020 /* DACL_TO_SPKMIXL */
+#define WM8962_DACL_TO_SPKMIXL_SHIFT 5 /* DACL_TO_SPKMIXL */
+#define WM8962_DACL_TO_SPKMIXL_WIDTH 1 /* DACL_TO_SPKMIXL */
+#define WM8962_DACR_TO_SPKMIXL 0x0010 /* DACR_TO_SPKMIXL */
+#define WM8962_DACR_TO_SPKMIXL_MASK 0x0010 /* DACR_TO_SPKMIXL */
+#define WM8962_DACR_TO_SPKMIXL_SHIFT 4 /* DACR_TO_SPKMIXL */
+#define WM8962_DACR_TO_SPKMIXL_WIDTH 1 /* DACR_TO_SPKMIXL */
+#define WM8962_MIXINL_TO_SPKMIXL 0x0008 /* MIXINL_TO_SPKMIXL */
+#define WM8962_MIXINL_TO_SPKMIXL_MASK 0x0008 /* MIXINL_TO_SPKMIXL */
+#define WM8962_MIXINL_TO_SPKMIXL_SHIFT 3 /* MIXINL_TO_SPKMIXL */
+#define WM8962_MIXINL_TO_SPKMIXL_WIDTH 1 /* MIXINL_TO_SPKMIXL */
+#define WM8962_MIXINR_TO_SPKMIXL 0x0004 /* MIXINR_TO_SPKMIXL */
+#define WM8962_MIXINR_TO_SPKMIXL_MASK 0x0004 /* MIXINR_TO_SPKMIXL */
+#define WM8962_MIXINR_TO_SPKMIXL_SHIFT 2 /* MIXINR_TO_SPKMIXL */
+#define WM8962_MIXINR_TO_SPKMIXL_WIDTH 1 /* MIXINR_TO_SPKMIXL */
+#define WM8962_IN4L_TO_SPKMIXL 0x0002 /* IN4L_TO_SPKMIXL */
+#define WM8962_IN4L_TO_SPKMIXL_MASK 0x0002 /* IN4L_TO_SPKMIXL */
+#define WM8962_IN4L_TO_SPKMIXL_SHIFT 1 /* IN4L_TO_SPKMIXL */
+#define WM8962_IN4L_TO_SPKMIXL_WIDTH 1 /* IN4L_TO_SPKMIXL */
+#define WM8962_IN4R_TO_SPKMIXL 0x0001 /* IN4R_TO_SPKMIXL */
+#define WM8962_IN4R_TO_SPKMIXL_MASK 0x0001 /* IN4R_TO_SPKMIXL */
+#define WM8962_IN4R_TO_SPKMIXL_SHIFT 0 /* IN4R_TO_SPKMIXL */
+#define WM8962_IN4R_TO_SPKMIXL_WIDTH 1 /* IN4R_TO_SPKMIXL */
+
+/*
+ * R106 (0x6A) - Speaker Mixer (2)
+ */
+#define WM8962_SPKMIXR_TO_SPKOUTR_PGA 0x0080 /* SPKMIXR_TO_SPKOUTR_PGA */
+#define WM8962_SPKMIXR_TO_SPKOUTR_PGA_MASK 0x0080 /* SPKMIXR_TO_SPKOUTR_PGA */
+#define WM8962_SPKMIXR_TO_SPKOUTR_PGA_SHIFT 7 /* SPKMIXR_TO_SPKOUTR_PGA */
+#define WM8962_SPKMIXR_TO_SPKOUTR_PGA_WIDTH 1 /* SPKMIXR_TO_SPKOUTR_PGA */
+#define WM8962_DACL_TO_SPKMIXR 0x0020 /* DACL_TO_SPKMIXR */
+#define WM8962_DACL_TO_SPKMIXR_MASK 0x0020 /* DACL_TO_SPKMIXR */
+#define WM8962_DACL_TO_SPKMIXR_SHIFT 5 /* DACL_TO_SPKMIXR */
+#define WM8962_DACL_TO_SPKMIXR_WIDTH 1 /* DACL_TO_SPKMIXR */
+#define WM8962_DACR_TO_SPKMIXR 0x0010 /* DACR_TO_SPKMIXR */
+#define WM8962_DACR_TO_SPKMIXR_MASK 0x0010 /* DACR_TO_SPKMIXR */
+#define WM8962_DACR_TO_SPKMIXR_SHIFT 4 /* DACR_TO_SPKMIXR */
+#define WM8962_DACR_TO_SPKMIXR_WIDTH 1 /* DACR_TO_SPKMIXR */
+#define WM8962_MIXINL_TO_SPKMIXR 0x0008 /* MIXINL_TO_SPKMIXR */
+#define WM8962_MIXINL_TO_SPKMIXR_MASK 0x0008 /* MIXINL_TO_SPKMIXR */
+#define WM8962_MIXINL_TO_SPKMIXR_SHIFT 3 /* MIXINL_TO_SPKMIXR */
+#define WM8962_MIXINL_TO_SPKMIXR_WIDTH 1 /* MIXINL_TO_SPKMIXR */
+#define WM8962_MIXINR_TO_SPKMIXR 0x0004 /* MIXINR_TO_SPKMIXR */
+#define WM8962_MIXINR_TO_SPKMIXR_MASK 0x0004 /* MIXINR_TO_SPKMIXR */
+#define WM8962_MIXINR_TO_SPKMIXR_SHIFT 2 /* MIXINR_TO_SPKMIXR */
+#define WM8962_MIXINR_TO_SPKMIXR_WIDTH 1 /* MIXINR_TO_SPKMIXR */
+#define WM8962_IN4L_TO_SPKMIXR 0x0002 /* IN4L_TO_SPKMIXR */
+#define WM8962_IN4L_TO_SPKMIXR_MASK 0x0002 /* IN4L_TO_SPKMIXR */
+#define WM8962_IN4L_TO_SPKMIXR_SHIFT 1 /* IN4L_TO_SPKMIXR */
+#define WM8962_IN4L_TO_SPKMIXR_WIDTH 1 /* IN4L_TO_SPKMIXR */
+#define WM8962_IN4R_TO_SPKMIXR 0x0001 /* IN4R_TO_SPKMIXR */
+#define WM8962_IN4R_TO_SPKMIXR_MASK 0x0001 /* IN4R_TO_SPKMIXR */
+#define WM8962_IN4R_TO_SPKMIXR_SHIFT 0 /* IN4R_TO_SPKMIXR */
+#define WM8962_IN4R_TO_SPKMIXR_WIDTH 1 /* IN4R_TO_SPKMIXR */
+
+/*
+ * R107 (0x6B) - Speaker Mixer (3)
+ */
+#define WM8962_SPKMIXL_MUTE 0x0100 /* SPKMIXL_MUTE */
+#define WM8962_SPKMIXL_MUTE_MASK 0x0100 /* SPKMIXL_MUTE */
+#define WM8962_SPKMIXL_MUTE_SHIFT 8 /* SPKMIXL_MUTE */
+#define WM8962_SPKMIXL_MUTE_WIDTH 1 /* SPKMIXL_MUTE */
+#define WM8962_MIXINL_SPKMIXL_VOL 0x0080 /* MIXINL_SPKMIXL_VOL */
+#define WM8962_MIXINL_SPKMIXL_VOL_MASK 0x0080 /* MIXINL_SPKMIXL_VOL */
+#define WM8962_MIXINL_SPKMIXL_VOL_SHIFT 7 /* MIXINL_SPKMIXL_VOL */
+#define WM8962_MIXINL_SPKMIXL_VOL_WIDTH 1 /* MIXINL_SPKMIXL_VOL */
+#define WM8962_MIXINR_SPKMIXL_VOL 0x0040 /* MIXINR_SPKMIXL_VOL */
+#define WM8962_MIXINR_SPKMIXL_VOL_MASK 0x0040 /* MIXINR_SPKMIXL_VOL */
+#define WM8962_MIXINR_SPKMIXL_VOL_SHIFT 6 /* MIXINR_SPKMIXL_VOL */
+#define WM8962_MIXINR_SPKMIXL_VOL_WIDTH 1 /* MIXINR_SPKMIXL_VOL */
+#define WM8962_IN4L_SPKMIXL_VOL_MASK 0x0038 /* IN4L_SPKMIXL_VOL - [5:3] */
+#define WM8962_IN4L_SPKMIXL_VOL_SHIFT 3 /* IN4L_SPKMIXL_VOL - [5:3] */
+#define WM8962_IN4L_SPKMIXL_VOL_WIDTH 3 /* IN4L_SPKMIXL_VOL - [5:3] */
+#define WM8962_IN4R_SPKMIXL_VOL_MASK 0x0007 /* IN4R_SPKMIXL_VOL - [2:0] */
+#define WM8962_IN4R_SPKMIXL_VOL_SHIFT 0 /* IN4R_SPKMIXL_VOL - [2:0] */
+#define WM8962_IN4R_SPKMIXL_VOL_WIDTH 3 /* IN4R_SPKMIXL_VOL - [2:0] */
+
+/*
+ * R108 (0x6C) - Speaker Mixer (4)
+ */
+#define WM8962_SPKMIXR_MUTE 0x0100 /* SPKMIXR_MUTE */
+#define WM8962_SPKMIXR_MUTE_MASK 0x0100 /* SPKMIXR_MUTE */
+#define WM8962_SPKMIXR_MUTE_SHIFT 8 /* SPKMIXR_MUTE */
+#define WM8962_SPKMIXR_MUTE_WIDTH 1 /* SPKMIXR_MUTE */
+#define WM8962_MIXINL_SPKMIXR_VOL 0x0080 /* MIXINL_SPKMIXR_VOL */
+#define WM8962_MIXINL_SPKMIXR_VOL_MASK 0x0080 /* MIXINL_SPKMIXR_VOL */
+#define WM8962_MIXINL_SPKMIXR_VOL_SHIFT 7 /* MIXINL_SPKMIXR_VOL */
+#define WM8962_MIXINL_SPKMIXR_VOL_WIDTH 1 /* MIXINL_SPKMIXR_VOL */
+#define WM8962_MIXINR_SPKMIXR_VOL 0x0040 /* MIXINR_SPKMIXR_VOL */
+#define WM8962_MIXINR_SPKMIXR_VOL_MASK 0x0040 /* MIXINR_SPKMIXR_VOL */
+#define WM8962_MIXINR_SPKMIXR_VOL_SHIFT 6 /* MIXINR_SPKMIXR_VOL */
+#define WM8962_MIXINR_SPKMIXR_VOL_WIDTH 1 /* MIXINR_SPKMIXR_VOL */
+#define WM8962_IN4L_SPKMIXR_VOL_MASK 0x0038 /* IN4L_SPKMIXR_VOL - [5:3] */
+#define WM8962_IN4L_SPKMIXR_VOL_SHIFT 3 /* IN4L_SPKMIXR_VOL - [5:3] */
+#define WM8962_IN4L_SPKMIXR_VOL_WIDTH 3 /* IN4L_SPKMIXR_VOL - [5:3] */
+#define WM8962_IN4R_SPKMIXR_VOL_MASK 0x0007 /* IN4R_SPKMIXR_VOL - [2:0] */
+#define WM8962_IN4R_SPKMIXR_VOL_SHIFT 0 /* IN4R_SPKMIXR_VOL - [2:0] */
+#define WM8962_IN4R_SPKMIXR_VOL_WIDTH 3 /* IN4R_SPKMIXR_VOL - [2:0] */
+
+/*
+ * R109 (0x6D) - Speaker Mixer (5)
+ */
+#define WM8962_DACL_SPKMIXL_VOL 0x0080 /* DACL_SPKMIXL_VOL */
+#define WM8962_DACL_SPKMIXL_VOL_MASK 0x0080 /* DACL_SPKMIXL_VOL */
+#define WM8962_DACL_SPKMIXL_VOL_SHIFT 7 /* DACL_SPKMIXL_VOL */
+#define WM8962_DACL_SPKMIXL_VOL_WIDTH 1 /* DACL_SPKMIXL_VOL */
+#define WM8962_DACR_SPKMIXL_VOL 0x0040 /* DACR_SPKMIXL_VOL */
+#define WM8962_DACR_SPKMIXL_VOL_MASK 0x0040 /* DACR_SPKMIXL_VOL */
+#define WM8962_DACR_SPKMIXL_VOL_SHIFT 6 /* DACR_SPKMIXL_VOL */
+#define WM8962_DACR_SPKMIXL_VOL_WIDTH 1 /* DACR_SPKMIXL_VOL */
+#define WM8962_DACL_SPKMIXR_VOL 0x0020 /* DACL_SPKMIXR_VOL */
+#define WM8962_DACL_SPKMIXR_VOL_MASK 0x0020 /* DACL_SPKMIXR_VOL */
+#define WM8962_DACL_SPKMIXR_VOL_SHIFT 5 /* DACL_SPKMIXR_VOL */
+#define WM8962_DACL_SPKMIXR_VOL_WIDTH 1 /* DACL_SPKMIXR_VOL */
+#define WM8962_DACR_SPKMIXR_VOL 0x0010 /* DACR_SPKMIXR_VOL */
+#define WM8962_DACR_SPKMIXR_VOL_MASK 0x0010 /* DACR_SPKMIXR_VOL */
+#define WM8962_DACR_SPKMIXR_VOL_SHIFT 4 /* DACR_SPKMIXR_VOL */
+#define WM8962_DACR_SPKMIXR_VOL_WIDTH 1 /* DACR_SPKMIXR_VOL */
+
+/*
+ * R110 (0x6E) - Beep Generator (1)
+ */
+#define WM8962_BEEP_GAIN_MASK 0x00F0 /* BEEP_GAIN - [7:4] */
+#define WM8962_BEEP_GAIN_SHIFT 4 /* BEEP_GAIN - [7:4] */
+#define WM8962_BEEP_GAIN_WIDTH 4 /* BEEP_GAIN - [7:4] */
+#define WM8962_BEEP_RATE_MASK 0x0006 /* BEEP_RATE - [2:1] */
+#define WM8962_BEEP_RATE_SHIFT 1 /* BEEP_RATE - [2:1] */
+#define WM8962_BEEP_RATE_WIDTH 2 /* BEEP_RATE - [2:1] */
+#define WM8962_BEEP_ENA 0x0001 /* BEEP_ENA */
+#define WM8962_BEEP_ENA_MASK 0x0001 /* BEEP_ENA */
+#define WM8962_BEEP_ENA_SHIFT 0 /* BEEP_ENA */
+#define WM8962_BEEP_ENA_WIDTH 1 /* BEEP_ENA */
+
+/*
+ * R115 (0x73) - Oscillator Trim (3)
+ */
+#define WM8962_OSC_TRIM_XTI_MASK 0x001F /* OSC_TRIM_XTI - [4:0] */
+#define WM8962_OSC_TRIM_XTI_SHIFT 0 /* OSC_TRIM_XTI - [4:0] */
+#define WM8962_OSC_TRIM_XTI_WIDTH 5 /* OSC_TRIM_XTI - [4:0] */
+
+/*
+ * R116 (0x74) - Oscillator Trim (4)
+ */
+#define WM8962_OSC_TRIM_XTO_MASK 0x001F /* OSC_TRIM_XTO - [4:0] */
+#define WM8962_OSC_TRIM_XTO_SHIFT 0 /* OSC_TRIM_XTO - [4:0] */
+#define WM8962_OSC_TRIM_XTO_WIDTH 5 /* OSC_TRIM_XTO - [4:0] */
+
+/*
+ * R119 (0x77) - Oscillator Trim (7)
+ */
+#define WM8962_XTO_CAP_SEL_MASK 0x00F0 /* XTO_CAP_SEL - [7:4] */
+#define WM8962_XTO_CAP_SEL_SHIFT 4 /* XTO_CAP_SEL - [7:4] */
+#define WM8962_XTO_CAP_SEL_WIDTH 4 /* XTO_CAP_SEL - [7:4] */
+#define WM8962_XTI_CAP_SEL_MASK 0x000F /* XTI_CAP_SEL - [3:0] */
+#define WM8962_XTI_CAP_SEL_SHIFT 0 /* XTI_CAP_SEL - [3:0] */
+#define WM8962_XTI_CAP_SEL_WIDTH 4 /* XTI_CAP_SEL - [3:0] */
+
+/*
+ * R124 (0x7C) - Analogue Clocking1
+ */
+#define WM8962_CLKOUT2_SEL_MASK 0x0060 /* CLKOUT2_SEL - [6:5] */
+#define WM8962_CLKOUT2_SEL_SHIFT 5 /* CLKOUT2_SEL - [6:5] */
+#define WM8962_CLKOUT2_SEL_WIDTH 2 /* CLKOUT2_SEL - [6:5] */
+#define WM8962_CLKOUT3_SEL_MASK 0x0018 /* CLKOUT3_SEL - [4:3] */
+#define WM8962_CLKOUT3_SEL_SHIFT 3 /* CLKOUT3_SEL - [4:3] */
+#define WM8962_CLKOUT3_SEL_WIDTH 2 /* CLKOUT3_SEL - [4:3] */
+#define WM8962_CLKOUT5_SEL 0x0001 /* CLKOUT5_SEL */
+#define WM8962_CLKOUT5_SEL_MASK 0x0001 /* CLKOUT5_SEL */
+#define WM8962_CLKOUT5_SEL_SHIFT 0 /* CLKOUT5_SEL */
+#define WM8962_CLKOUT5_SEL_WIDTH 1 /* CLKOUT5_SEL */
+
+/*
+ * R125 (0x7D) - Analogue Clocking2
+ */
+#define WM8962_PLL2_OUTDIV 0x0080 /* PLL2_OUTDIV */
+#define WM8962_PLL2_OUTDIV_MASK 0x0080 /* PLL2_OUTDIV */
+#define WM8962_PLL2_OUTDIV_SHIFT 7 /* PLL2_OUTDIV */
+#define WM8962_PLL2_OUTDIV_WIDTH 1 /* PLL2_OUTDIV */
+#define WM8962_PLL3_OUTDIV 0x0040 /* PLL3_OUTDIV */
+#define WM8962_PLL3_OUTDIV_MASK 0x0040 /* PLL3_OUTDIV */
+#define WM8962_PLL3_OUTDIV_SHIFT 6 /* PLL3_OUTDIV */
+#define WM8962_PLL3_OUTDIV_WIDTH 1 /* PLL3_OUTDIV */
+#define WM8962_PLL_SYSCLK_DIV_MASK 0x0018 /* PLL_SYSCLK_DIV - [4:3] */
+#define WM8962_PLL_SYSCLK_DIV_SHIFT 3 /* PLL_SYSCLK_DIV - [4:3] */
+#define WM8962_PLL_SYSCLK_DIV_WIDTH 2 /* PLL_SYSCLK_DIV - [4:3] */
+#define WM8962_CLKOUT3_DIV 0x0004 /* CLKOUT3_DIV */
+#define WM8962_CLKOUT3_DIV_MASK 0x0004 /* CLKOUT3_DIV */
+#define WM8962_CLKOUT3_DIV_SHIFT 2 /* CLKOUT3_DIV */
+#define WM8962_CLKOUT3_DIV_WIDTH 1 /* CLKOUT3_DIV */
+#define WM8962_CLKOUT2_DIV 0x0002 /* CLKOUT2_DIV */
+#define WM8962_CLKOUT2_DIV_MASK 0x0002 /* CLKOUT2_DIV */
+#define WM8962_CLKOUT2_DIV_SHIFT 1 /* CLKOUT2_DIV */
+#define WM8962_CLKOUT2_DIV_WIDTH 1 /* CLKOUT2_DIV */
+#define WM8962_CLKOUT5_DIV 0x0001 /* CLKOUT5_DIV */
+#define WM8962_CLKOUT5_DIV_MASK 0x0001 /* CLKOUT5_DIV */
+#define WM8962_CLKOUT5_DIV_SHIFT 0 /* CLKOUT5_DIV */
+#define WM8962_CLKOUT5_DIV_WIDTH 1 /* CLKOUT5_DIV */
+
+/*
+ * R126 (0x7E) - Analogue Clocking3
+ */
+#define WM8962_CLKOUT2_OE 0x0008 /* CLKOUT2_OE */
+#define WM8962_CLKOUT2_OE_MASK 0x0008 /* CLKOUT2_OE */
+#define WM8962_CLKOUT2_OE_SHIFT 3 /* CLKOUT2_OE */
+#define WM8962_CLKOUT2_OE_WIDTH 1 /* CLKOUT2_OE */
+#define WM8962_CLKOUT3_OE 0x0004 /* CLKOUT3_OE */
+#define WM8962_CLKOUT3_OE_MASK 0x0004 /* CLKOUT3_OE */
+#define WM8962_CLKOUT3_OE_SHIFT 2 /* CLKOUT3_OE */
+#define WM8962_CLKOUT3_OE_WIDTH 1 /* CLKOUT3_OE */
+#define WM8962_CLKOUT5_OE 0x0001 /* CLKOUT5_OE */
+#define WM8962_CLKOUT5_OE_MASK 0x0001 /* CLKOUT5_OE */
+#define WM8962_CLKOUT5_OE_SHIFT 0 /* CLKOUT5_OE */
+#define WM8962_CLKOUT5_OE_WIDTH 1 /* CLKOUT5_OE */
+
+/*
+ * R127 (0x7F) - PLL Software Reset
+ */
+#define WM8962_SW_RESET_PLL_MASK 0xFFFF /* SW_RESET_PLL - [15:0] */
+#define WM8962_SW_RESET_PLL_SHIFT 0 /* SW_RESET_PLL - [15:0] */
+#define WM8962_SW_RESET_PLL_WIDTH 16 /* SW_RESET_PLL - [15:0] */
+
+/*
+ * R129 (0x81) - PLL2
+ */
+#define WM8962_OSC_ENA 0x0080 /* OSC_ENA */
+#define WM8962_OSC_ENA_MASK 0x0080 /* OSC_ENA */
+#define WM8962_OSC_ENA_SHIFT 7 /* OSC_ENA */
+#define WM8962_OSC_ENA_WIDTH 1 /* OSC_ENA */
+#define WM8962_PLL2_ENA 0x0020 /* PLL2_ENA */
+#define WM8962_PLL2_ENA_MASK 0x0020 /* PLL2_ENA */
+#define WM8962_PLL2_ENA_SHIFT 5 /* PLL2_ENA */
+#define WM8962_PLL2_ENA_WIDTH 1 /* PLL2_ENA */
+#define WM8962_PLL3_ENA 0x0010 /* PLL3_ENA */
+#define WM8962_PLL3_ENA_MASK 0x0010 /* PLL3_ENA */
+#define WM8962_PLL3_ENA_SHIFT 4 /* PLL3_ENA */
+#define WM8962_PLL3_ENA_WIDTH 1 /* PLL3_ENA */
+
+/*
+ * R131 (0x83) - PLL 4
+ */
+#define WM8962_PLL_CLK_SRC 0x0002 /* PLL_CLK_SRC */
+#define WM8962_PLL_CLK_SRC_MASK 0x0002 /* PLL_CLK_SRC */
+#define WM8962_PLL_CLK_SRC_SHIFT 1 /* PLL_CLK_SRC */
+#define WM8962_PLL_CLK_SRC_WIDTH 1 /* PLL_CLK_SRC */
+#define WM8962_FLL_TO_PLL3 0x0001 /* FLL_TO_PLL3 */
+#define WM8962_FLL_TO_PLL3_MASK 0x0001 /* FLL_TO_PLL3 */
+#define WM8962_FLL_TO_PLL3_SHIFT 0 /* FLL_TO_PLL3 */
+#define WM8962_FLL_TO_PLL3_WIDTH 1 /* FLL_TO_PLL3 */
+
+/*
+ * R136 (0x88) - PLL 9
+ */
+#define WM8962_PLL2_FRAC 0x0040 /* PLL2_FRAC */
+#define WM8962_PLL2_FRAC_MASK 0x0040 /* PLL2_FRAC */
+#define WM8962_PLL2_FRAC_SHIFT 6 /* PLL2_FRAC */
+#define WM8962_PLL2_FRAC_WIDTH 1 /* PLL2_FRAC */
+#define WM8962_PLL2_N_MASK 0x001F /* PLL2_N - [4:0] */
+#define WM8962_PLL2_N_SHIFT 0 /* PLL2_N - [4:0] */
+#define WM8962_PLL2_N_WIDTH 5 /* PLL2_N - [4:0] */
+
+/*
+ * R137 (0x89) - PLL 10
+ */
+#define WM8962_PLL2_K_MASK 0x00FF /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_SHIFT 0 /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_WIDTH 8 /* PLL2_K - [7:0] */
+
+/*
+ * R138 (0x8A) - PLL 11
+ */
+#define WM8962_PLL2_K_MASK 0x00FF /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_SHIFT 0 /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_WIDTH 8 /* PLL2_K - [7:0] */
+
+/*
+ * R139 (0x8B) - PLL 12
+ */
+#define WM8962_PLL2_K_MASK 0x00FF /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_SHIFT 0 /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_WIDTH 8 /* PLL2_K - [7:0] */
+
+/*
+ * R140 (0x8C) - PLL 13
+ */
+#define WM8962_PLL3_FRAC 0x0040 /* PLL3_FRAC */
+#define WM8962_PLL3_FRAC_MASK 0x0040 /* PLL3_FRAC */
+#define WM8962_PLL3_FRAC_SHIFT 6 /* PLL3_FRAC */
+#define WM8962_PLL3_FRAC_WIDTH 1 /* PLL3_FRAC */
+#define WM8962_PLL3_N_MASK 0x001F /* PLL3_N - [4:0] */
+#define WM8962_PLL3_N_SHIFT 0 /* PLL3_N - [4:0] */
+#define WM8962_PLL3_N_WIDTH 5 /* PLL3_N - [4:0] */
+
+/*
+ * R141 (0x8D) - PLL 14
+ */
+#define WM8962_PLL3_K_MASK 0x00FF /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_SHIFT 0 /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_WIDTH 8 /* PLL3_K - [7:0] */
+
+/*
+ * R142 (0x8E) - PLL 15
+ */
+#define WM8962_PLL3_K_MASK 0x00FF /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_SHIFT 0 /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_WIDTH 8 /* PLL3_K - [7:0] */
+
+/*
+ * R143 (0x8F) - PLL 16
+ */
+#define WM8962_PLL3_K_MASK 0x00FF /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_SHIFT 0 /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_WIDTH 8 /* PLL3_K - [7:0] */
+
+/*
+ * R155 (0x9B) - FLL Control (1)
+ */
+#define WM8962_FLL_REFCLK_SRC_MASK 0x0060 /* FLL_REFCLK_SRC - [6:5] */
+#define WM8962_FLL_REFCLK_SRC_SHIFT 5 /* FLL_REFCLK_SRC - [6:5] */
+#define WM8962_FLL_REFCLK_SRC_WIDTH 2 /* FLL_REFCLK_SRC - [6:5] */
+#define WM8962_FLL_FRAC 0x0004 /* FLL_FRAC */
+#define WM8962_FLL_FRAC_MASK 0x0004 /* FLL_FRAC */
+#define WM8962_FLL_FRAC_SHIFT 2 /* FLL_FRAC */
+#define WM8962_FLL_FRAC_WIDTH 1 /* FLL_FRAC */
+#define WM8962_FLL_OSC_ENA 0x0002 /* FLL_OSC_ENA */
+#define WM8962_FLL_OSC_ENA_MASK 0x0002 /* FLL_OSC_ENA */
+#define WM8962_FLL_OSC_ENA_SHIFT 1 /* FLL_OSC_ENA */
+#define WM8962_FLL_OSC_ENA_WIDTH 1 /* FLL_OSC_ENA */
+#define WM8962_FLL_ENA 0x0001 /* FLL_ENA */
+#define WM8962_FLL_ENA_MASK 0x0001 /* FLL_ENA */
+#define WM8962_FLL_ENA_SHIFT 0 /* FLL_ENA */
+#define WM8962_FLL_ENA_WIDTH 1 /* FLL_ENA */
+
+/*
+ * R156 (0x9C) - FLL Control (2)
+ */
+#define WM8962_FLL_OUTDIV_MASK 0x01F8 /* FLL_OUTDIV - [8:3] */
+#define WM8962_FLL_OUTDIV_SHIFT 3 /* FLL_OUTDIV - [8:3] */
+#define WM8962_FLL_OUTDIV_WIDTH 6 /* FLL_OUTDIV - [8:3] */
+#define WM8962_FLL_REFCLK_DIV_MASK 0x0003 /* FLL_REFCLK_DIV - [1:0] */
+#define WM8962_FLL_REFCLK_DIV_SHIFT 0 /* FLL_REFCLK_DIV - [1:0] */
+#define WM8962_FLL_REFCLK_DIV_WIDTH 2 /* FLL_REFCLK_DIV - [1:0] */
+
+/*
+ * R157 (0x9D) - FLL Control (3)
+ */
+#define WM8962_FLL_FRATIO_MASK 0x0007 /* FLL_FRATIO - [2:0] */
+#define WM8962_FLL_FRATIO_SHIFT 0 /* FLL_FRATIO - [2:0] */
+#define WM8962_FLL_FRATIO_WIDTH 3 /* FLL_FRATIO - [2:0] */
+
+/*
+ * R159 (0x9F) - FLL Control (5)
+ */
+#define WM8962_FLL_FRC_NCO_VAL_MASK 0x007E /* FLL_FRC_NCO_VAL - [6:1] */
+#define WM8962_FLL_FRC_NCO_VAL_SHIFT 1 /* FLL_FRC_NCO_VAL - [6:1] */
+#define WM8962_FLL_FRC_NCO_VAL_WIDTH 6 /* FLL_FRC_NCO_VAL - [6:1] */
+#define WM8962_FLL_FRC_NCO 0x0001 /* FLL_FRC_NCO */
+#define WM8962_FLL_FRC_NCO_MASK 0x0001 /* FLL_FRC_NCO */
+#define WM8962_FLL_FRC_NCO_SHIFT 0 /* FLL_FRC_NCO */
+#define WM8962_FLL_FRC_NCO_WIDTH 1 /* FLL_FRC_NCO */
+
+/*
+ * R160 (0xA0) - FLL Control (6)
+ */
+#define WM8962_FLL_THETA_MASK 0xFFFF /* FLL_THETA - [15:0] */
+#define WM8962_FLL_THETA_SHIFT 0 /* FLL_THETA - [15:0] */
+#define WM8962_FLL_THETA_WIDTH 16 /* FLL_THETA - [15:0] */
+
+/*
+ * R161 (0xA1) - FLL Control (7)
+ */
+#define WM8962_FLL_LAMBDA_MASK 0xFFFF /* FLL_LAMBDA - [15:0] */
+#define WM8962_FLL_LAMBDA_SHIFT 0 /* FLL_LAMBDA - [15:0] */
+#define WM8962_FLL_LAMBDA_WIDTH 16 /* FLL_LAMBDA - [15:0] */
+
+/*
+ * R162 (0xA2) - FLL Control (8)
+ */
+#define WM8962_FLL_N_MASK 0x03FF /* FLL_N - [9:0] */
+#define WM8962_FLL_N_SHIFT 0 /* FLL_N - [9:0] */
+#define WM8962_FLL_N_WIDTH 10 /* FLL_N - [9:0] */
+
+/*
+ * R252 (0xFC) - General test 1
+ */
+#define WM8962_REG_SYNC 0x0004 /* REG_SYNC */
+#define WM8962_REG_SYNC_MASK 0x0004 /* REG_SYNC */
+#define WM8962_REG_SYNC_SHIFT 2 /* REG_SYNC */
+#define WM8962_REG_SYNC_WIDTH 1 /* REG_SYNC */
+#define WM8962_AUTO_INC 0x0001 /* AUTO_INC */
+#define WM8962_AUTO_INC_MASK 0x0001 /* AUTO_INC */
+#define WM8962_AUTO_INC_SHIFT 0 /* AUTO_INC */
+#define WM8962_AUTO_INC_WIDTH 1 /* AUTO_INC */
+
+/*
+ * R256 (0x100) - DF1
+ */
+#define WM8962_DRC_DF1_ENA 0x0008 /* DRC_DF1_ENA */
+#define WM8962_DRC_DF1_ENA_MASK 0x0008 /* DRC_DF1_ENA */
+#define WM8962_DRC_DF1_ENA_SHIFT 3 /* DRC_DF1_ENA */
+#define WM8962_DRC_DF1_ENA_WIDTH 1 /* DRC_DF1_ENA */
+#define WM8962_DF1_SHARED_COEFF 0x0004 /* DF1_SHARED_COEFF */
+#define WM8962_DF1_SHARED_COEFF_MASK 0x0004 /* DF1_SHARED_COEFF */
+#define WM8962_DF1_SHARED_COEFF_SHIFT 2 /* DF1_SHARED_COEFF */
+#define WM8962_DF1_SHARED_COEFF_WIDTH 1 /* DF1_SHARED_COEFF */
+#define WM8962_DF1_SHARED_COEFF_SEL 0x0002 /* DF1_SHARED_COEFF_SEL */
+#define WM8962_DF1_SHARED_COEFF_SEL_MASK 0x0002 /* DF1_SHARED_COEFF_SEL */
+#define WM8962_DF1_SHARED_COEFF_SEL_SHIFT 1 /* DF1_SHARED_COEFF_SEL */
+#define WM8962_DF1_SHARED_COEFF_SEL_WIDTH 1 /* DF1_SHARED_COEFF_SEL */
+#define WM8962_DF1_ENA 0x0001 /* DF1_ENA */
+#define WM8962_DF1_ENA_MASK 0x0001 /* DF1_ENA */
+#define WM8962_DF1_ENA_SHIFT 0 /* DF1_ENA */
+#define WM8962_DF1_ENA_WIDTH 1 /* DF1_ENA */
+
+/*
+ * R257 (0x101) - DF2
+ */
+#define WM8962_DF1_COEFF_L0_MASK 0xFFFF /* DF1_COEFF_L0 - [15:0] */
+#define WM8962_DF1_COEFF_L0_SHIFT 0 /* DF1_COEFF_L0 - [15:0] */
+#define WM8962_DF1_COEFF_L0_WIDTH 16 /* DF1_COEFF_L0 - [15:0] */
+
+/*
+ * R258 (0x102) - DF3
+ */
+#define WM8962_DF1_COEFF_L1_MASK 0xFFFF /* DF1_COEFF_L1 - [15:0] */
+#define WM8962_DF1_COEFF_L1_SHIFT 0 /* DF1_COEFF_L1 - [15:0] */
+#define WM8962_DF1_COEFF_L1_WIDTH 16 /* DF1_COEFF_L1 - [15:0] */
+
+/*
+ * R259 (0x103) - DF4
+ */
+#define WM8962_DF1_COEFF_L2_MASK 0xFFFF /* DF1_COEFF_L2 - [15:0] */
+#define WM8962_DF1_COEFF_L2_SHIFT 0 /* DF1_COEFF_L2 - [15:0] */
+#define WM8962_DF1_COEFF_L2_WIDTH 16 /* DF1_COEFF_L2 - [15:0] */
+
+/*
+ * R260 (0x104) - DF5
+ */
+#define WM8962_DF1_COEFF_R0_MASK 0xFFFF /* DF1_COEFF_R0 - [15:0] */
+#define WM8962_DF1_COEFF_R0_SHIFT 0 /* DF1_COEFF_R0 - [15:0] */
+#define WM8962_DF1_COEFF_R0_WIDTH 16 /* DF1_COEFF_R0 - [15:0] */
+
+/*
+ * R261 (0x105) - DF6
+ */
+#define WM8962_DF1_COEFF_R1_MASK 0xFFFF /* DF1_COEFF_R1 - [15:0] */
+#define WM8962_DF1_COEFF_R1_SHIFT 0 /* DF1_COEFF_R1 - [15:0] */
+#define WM8962_DF1_COEFF_R1_WIDTH 16 /* DF1_COEFF_R1 - [15:0] */
+
+/*
+ * R262 (0x106) - DF7
+ */
+#define WM8962_DF1_COEFF_R2_MASK 0xFFFF /* DF1_COEFF_R2 - [15:0] */
+#define WM8962_DF1_COEFF_R2_SHIFT 0 /* DF1_COEFF_R2 - [15:0] */
+#define WM8962_DF1_COEFF_R2_WIDTH 16 /* DF1_COEFF_R2 - [15:0] */
+
+/*
+ * R264 (0x108) - LHPF1
+ */
+#define WM8962_LHPF_MODE 0x0002 /* LHPF_MODE */
+#define WM8962_LHPF_MODE_MASK 0x0002 /* LHPF_MODE */
+#define WM8962_LHPF_MODE_SHIFT 1 /* LHPF_MODE */
+#define WM8962_LHPF_MODE_WIDTH 1 /* LHPF_MODE */
+#define WM8962_LHPF_ENA 0x0001 /* LHPF_ENA */
+#define WM8962_LHPF_ENA_MASK 0x0001 /* LHPF_ENA */
+#define WM8962_LHPF_ENA_SHIFT 0 /* LHPF_ENA */
+#define WM8962_LHPF_ENA_WIDTH 1 /* LHPF_ENA */
+
+/*
+ * R265 (0x109) - LHPF2
+ */
+#define WM8962_LHPF_COEFF_MASK 0xFFFF /* LHPF_COEFF - [15:0] */
+#define WM8962_LHPF_COEFF_SHIFT 0 /* LHPF_COEFF - [15:0] */
+#define WM8962_LHPF_COEFF_WIDTH 16 /* LHPF_COEFF - [15:0] */
+
+/*
+ * R268 (0x10C) - THREED1
+ */
+#define WM8962_ADC_MONOMIX 0x0040 /* ADC_MONOMIX */
+#define WM8962_ADC_MONOMIX_MASK 0x0040 /* ADC_MONOMIX */
+#define WM8962_ADC_MONOMIX_SHIFT 6 /* ADC_MONOMIX */
+#define WM8962_ADC_MONOMIX_WIDTH 1 /* ADC_MONOMIX */
+#define WM8962_THREED_SIGN_L 0x0020 /* THREED_SIGN_L */
+#define WM8962_THREED_SIGN_L_MASK 0x0020 /* THREED_SIGN_L */
+#define WM8962_THREED_SIGN_L_SHIFT 5 /* THREED_SIGN_L */
+#define WM8962_THREED_SIGN_L_WIDTH 1 /* THREED_SIGN_L */
+#define WM8962_THREED_SIGN_R 0x0010 /* THREED_SIGN_R */
+#define WM8962_THREED_SIGN_R_MASK 0x0010 /* THREED_SIGN_R */
+#define WM8962_THREED_SIGN_R_SHIFT 4 /* THREED_SIGN_R */
+#define WM8962_THREED_SIGN_R_WIDTH 1 /* THREED_SIGN_R */
+#define WM8962_THREED_LHPF_MODE 0x0004 /* THREED_LHPF_MODE */
+#define WM8962_THREED_LHPF_MODE_MASK 0x0004 /* THREED_LHPF_MODE */
+#define WM8962_THREED_LHPF_MODE_SHIFT 2 /* THREED_LHPF_MODE */
+#define WM8962_THREED_LHPF_MODE_WIDTH 1 /* THREED_LHPF_MODE */
+#define WM8962_THREED_LHPF_ENA 0x0002 /* THREED_LHPF_ENA */
+#define WM8962_THREED_LHPF_ENA_MASK 0x0002 /* THREED_LHPF_ENA */
+#define WM8962_THREED_LHPF_ENA_SHIFT 1 /* THREED_LHPF_ENA */
+#define WM8962_THREED_LHPF_ENA_WIDTH 1 /* THREED_LHPF_ENA */
+#define WM8962_THREED_ENA 0x0001 /* THREED_ENA */
+#define WM8962_THREED_ENA_MASK 0x0001 /* THREED_ENA */
+#define WM8962_THREED_ENA_SHIFT 0 /* THREED_ENA */
+#define WM8962_THREED_ENA_WIDTH 1 /* THREED_ENA */
+
+/*
+ * R269 (0x10D) - THREED2
+ */
+#define WM8962_THREED_FGAINL_MASK 0xF800 /* THREED_FGAINL - [15:11] */
+#define WM8962_THREED_FGAINL_SHIFT 11 /* THREED_FGAINL - [15:11] */
+#define WM8962_THREED_FGAINL_WIDTH 5 /* THREED_FGAINL - [15:11] */
+#define WM8962_THREED_CGAINL_MASK 0x07C0 /* THREED_CGAINL - [10:6] */
+#define WM8962_THREED_CGAINL_SHIFT 6 /* THREED_CGAINL - [10:6] */
+#define WM8962_THREED_CGAINL_WIDTH 5 /* THREED_CGAINL - [10:6] */
+#define WM8962_THREED_DELAYL_MASK 0x003C /* THREED_DELAYL - [5:2] */
+#define WM8962_THREED_DELAYL_SHIFT 2 /* THREED_DELAYL - [5:2] */
+#define WM8962_THREED_DELAYL_WIDTH 4 /* THREED_DELAYL - [5:2] */
+
+/*
+ * R270 (0x10E) - THREED3
+ */
+#define WM8962_THREED_LHPF_COEFF_MASK 0xFFFF /* THREED_LHPF_COEFF - [15:0] */
+#define WM8962_THREED_LHPF_COEFF_SHIFT 0 /* THREED_LHPF_COEFF - [15:0] */
+#define WM8962_THREED_LHPF_COEFF_WIDTH 16 /* THREED_LHPF_COEFF - [15:0] */
+
+/*
+ * R271 (0x10F) - THREED4
+ */
+#define WM8962_THREED_FGAINR_MASK 0xF800 /* THREED_FGAINR - [15:11] */
+#define WM8962_THREED_FGAINR_SHIFT 11 /* THREED_FGAINR - [15:11] */
+#define WM8962_THREED_FGAINR_WIDTH 5 /* THREED_FGAINR - [15:11] */
+#define WM8962_THREED_CGAINR_MASK 0x07C0 /* THREED_CGAINR - [10:6] */
+#define WM8962_THREED_CGAINR_SHIFT 6 /* THREED_CGAINR - [10:6] */
+#define WM8962_THREED_CGAINR_WIDTH 5 /* THREED_CGAINR - [10:6] */
+#define WM8962_THREED_DELAYR_MASK 0x003C /* THREED_DELAYR - [5:2] */
+#define WM8962_THREED_DELAYR_SHIFT 2 /* THREED_DELAYR - [5:2] */
+#define WM8962_THREED_DELAYR_WIDTH 4 /* THREED_DELAYR - [5:2] */
+
+/*
+ * R276 (0x114) - DRC 1
+ */
+#define WM8962_DRC_SIG_DET_RMS_MASK 0x7C00 /* DRC_SIG_DET_RMS - [14:10] */
+#define WM8962_DRC_SIG_DET_RMS_SHIFT 10 /* DRC_SIG_DET_RMS - [14:10] */
+#define WM8962_DRC_SIG_DET_RMS_WIDTH 5 /* DRC_SIG_DET_RMS - [14:10] */
+#define WM8962_DRC_SIG_DET_PK_MASK 0x0300 /* DRC_SIG_DET_PK - [9:8] */
+#define WM8962_DRC_SIG_DET_PK_SHIFT 8 /* DRC_SIG_DET_PK - [9:8] */
+#define WM8962_DRC_SIG_DET_PK_WIDTH 2 /* DRC_SIG_DET_PK - [9:8] */
+#define WM8962_DRC_NG_ENA 0x0080 /* DRC_NG_ENA */
+#define WM8962_DRC_NG_ENA_MASK 0x0080 /* DRC_NG_ENA */
+#define WM8962_DRC_NG_ENA_SHIFT 7 /* DRC_NG_ENA */
+#define WM8962_DRC_NG_ENA_WIDTH 1 /* DRC_NG_ENA */
+#define WM8962_DRC_SIG_DET_MODE 0x0040 /* DRC_SIG_DET_MODE */
+#define WM8962_DRC_SIG_DET_MODE_MASK 0x0040 /* DRC_SIG_DET_MODE */
+#define WM8962_DRC_SIG_DET_MODE_SHIFT 6 /* DRC_SIG_DET_MODE */
+#define WM8962_DRC_SIG_DET_MODE_WIDTH 1 /* DRC_SIG_DET_MODE */
+#define WM8962_DRC_SIG_DET 0x0020 /* DRC_SIG_DET */
+#define WM8962_DRC_SIG_DET_MASK 0x0020 /* DRC_SIG_DET */
+#define WM8962_DRC_SIG_DET_SHIFT 5 /* DRC_SIG_DET */
+#define WM8962_DRC_SIG_DET_WIDTH 1 /* DRC_SIG_DET */
+#define WM8962_DRC_KNEE2_OP_ENA 0x0010 /* DRC_KNEE2_OP_ENA */
+#define WM8962_DRC_KNEE2_OP_ENA_MASK 0x0010 /* DRC_KNEE2_OP_ENA */
+#define WM8962_DRC_KNEE2_OP_ENA_SHIFT 4 /* DRC_KNEE2_OP_ENA */
+#define WM8962_DRC_KNEE2_OP_ENA_WIDTH 1 /* DRC_KNEE2_OP_ENA */
+#define WM8962_DRC_QR 0x0008 /* DRC_QR */
+#define WM8962_DRC_QR_MASK 0x0008 /* DRC_QR */
+#define WM8962_DRC_QR_SHIFT 3 /* DRC_QR */
+#define WM8962_DRC_QR_WIDTH 1 /* DRC_QR */
+#define WM8962_DRC_ANTICLIP 0x0004 /* DRC_ANTICLIP */
+#define WM8962_DRC_ANTICLIP_MASK 0x0004 /* DRC_ANTICLIP */
+#define WM8962_DRC_ANTICLIP_SHIFT 2 /* DRC_ANTICLIP */
+#define WM8962_DRC_ANTICLIP_WIDTH 1 /* DRC_ANTICLIP */
+#define WM8962_DRC_MODE 0x0002 /* DRC_MODE */
+#define WM8962_DRC_MODE_MASK 0x0002 /* DRC_MODE */
+#define WM8962_DRC_MODE_SHIFT 1 /* DRC_MODE */
+#define WM8962_DRC_MODE_WIDTH 1 /* DRC_MODE */
+#define WM8962_DRC_ENA 0x0001 /* DRC_ENA */
+#define WM8962_DRC_ENA_MASK 0x0001 /* DRC_ENA */
+#define WM8962_DRC_ENA_SHIFT 0 /* DRC_ENA */
+#define WM8962_DRC_ENA_WIDTH 1 /* DRC_ENA */
+
+/*
+ * R277 (0x115) - DRC 2
+ */
+#define WM8962_DRC_ATK_MASK 0x1E00 /* DRC_ATK - [12:9] */
+#define WM8962_DRC_ATK_SHIFT 9 /* DRC_ATK - [12:9] */
+#define WM8962_DRC_ATK_WIDTH 4 /* DRC_ATK - [12:9] */
+#define WM8962_DRC_DCY_MASK 0x01E0 /* DRC_DCY - [8:5] */
+#define WM8962_DRC_DCY_SHIFT 5 /* DRC_DCY - [8:5] */
+#define WM8962_DRC_DCY_WIDTH 4 /* DRC_DCY - [8:5] */
+#define WM8962_DRC_MINGAIN_MASK 0x001C /* DRC_MINGAIN - [4:2] */
+#define WM8962_DRC_MINGAIN_SHIFT 2 /* DRC_MINGAIN - [4:2] */
+#define WM8962_DRC_MINGAIN_WIDTH 3 /* DRC_MINGAIN - [4:2] */
+#define WM8962_DRC_MAXGAIN_MASK 0x0003 /* DRC_MAXGAIN - [1:0] */
+#define WM8962_DRC_MAXGAIN_SHIFT 0 /* DRC_MAXGAIN - [1:0] */
+#define WM8962_DRC_MAXGAIN_WIDTH 2 /* DRC_MAXGAIN - [1:0] */
+
+/*
+ * R278 (0x116) - DRC 3
+ */
+#define WM8962_DRC_NG_MINGAIN_MASK 0xF000 /* DRC_NG_MINGAIN - [15:12] */
+#define WM8962_DRC_NG_MINGAIN_SHIFT 12 /* DRC_NG_MINGAIN - [15:12] */
+#define WM8962_DRC_NG_MINGAIN_WIDTH 4 /* DRC_NG_MINGAIN - [15:12] */
+#define WM8962_DRC_QR_THR_MASK 0x0C00 /* DRC_QR_THR - [11:10] */
+#define WM8962_DRC_QR_THR_SHIFT 10 /* DRC_QR_THR - [11:10] */
+#define WM8962_DRC_QR_THR_WIDTH 2 /* DRC_QR_THR - [11:10] */
+#define WM8962_DRC_QR_DCY_MASK 0x0300 /* DRC_QR_DCY - [9:8] */
+#define WM8962_DRC_QR_DCY_SHIFT 8 /* DRC_QR_DCY - [9:8] */
+#define WM8962_DRC_QR_DCY_WIDTH 2 /* DRC_QR_DCY - [9:8] */
+#define WM8962_DRC_NG_EXP_MASK 0x00C0 /* DRC_NG_EXP - [7:6] */
+#define WM8962_DRC_NG_EXP_SHIFT 6 /* DRC_NG_EXP - [7:6] */
+#define WM8962_DRC_NG_EXP_WIDTH 2 /* DRC_NG_EXP - [7:6] */
+#define WM8962_DRC_HI_COMP_MASK 0x0038 /* DRC_HI_COMP - [5:3] */
+#define WM8962_DRC_HI_COMP_SHIFT 3 /* DRC_HI_COMP - [5:3] */
+#define WM8962_DRC_HI_COMP_WIDTH 3 /* DRC_HI_COMP - [5:3] */
+#define WM8962_DRC_LO_COMP_MASK 0x0007 /* DRC_LO_COMP - [2:0] */
+#define WM8962_DRC_LO_COMP_SHIFT 0 /* DRC_LO_COMP - [2:0] */
+#define WM8962_DRC_LO_COMP_WIDTH 3 /* DRC_LO_COMP - [2:0] */
+
+/*
+ * R279 (0x117) - DRC 4
+ */
+#define WM8962_DRC_KNEE_IP_MASK 0x07E0 /* DRC_KNEE_IP - [10:5] */
+#define WM8962_DRC_KNEE_IP_SHIFT 5 /* DRC_KNEE_IP - [10:5] */
+#define WM8962_DRC_KNEE_IP_WIDTH 6 /* DRC_KNEE_IP - [10:5] */
+#define WM8962_DRC_KNEE_OP_MASK 0x001F /* DRC_KNEE_OP - [4:0] */
+#define WM8962_DRC_KNEE_OP_SHIFT 0 /* DRC_KNEE_OP - [4:0] */
+#define WM8962_DRC_KNEE_OP_WIDTH 5 /* DRC_KNEE_OP - [4:0] */
+
+/*
+ * R280 (0x118) - DRC 5
+ */
+#define WM8962_DRC_KNEE2_IP_MASK 0x03E0 /* DRC_KNEE2_IP - [9:5] */
+#define WM8962_DRC_KNEE2_IP_SHIFT 5 /* DRC_KNEE2_IP - [9:5] */
+#define WM8962_DRC_KNEE2_IP_WIDTH 5 /* DRC_KNEE2_IP - [9:5] */
+#define WM8962_DRC_KNEE2_OP_MASK 0x001F /* DRC_KNEE2_OP - [4:0] */
+#define WM8962_DRC_KNEE2_OP_SHIFT 0 /* DRC_KNEE2_OP - [4:0] */
+#define WM8962_DRC_KNEE2_OP_WIDTH 5 /* DRC_KNEE2_OP - [4:0] */
+
+/*
+ * R285 (0x11D) - Tloopback
+ */
+#define WM8962_TLB_ENA 0x0002 /* TLB_ENA */
+#define WM8962_TLB_ENA_MASK 0x0002 /* TLB_ENA */
+#define WM8962_TLB_ENA_SHIFT 1 /* TLB_ENA */
+#define WM8962_TLB_ENA_WIDTH 1 /* TLB_ENA */
+#define WM8962_TLB_MODE 0x0001 /* TLB_MODE */
+#define WM8962_TLB_MODE_MASK 0x0001 /* TLB_MODE */
+#define WM8962_TLB_MODE_SHIFT 0 /* TLB_MODE */
+#define WM8962_TLB_MODE_WIDTH 1 /* TLB_MODE */
+
+/*
+ * R335 (0x14F) - EQ1
+ */
+#define WM8962_EQ_SHARED_COEFF 0x0004 /* EQ_SHARED_COEFF */
+#define WM8962_EQ_SHARED_COEFF_MASK 0x0004 /* EQ_SHARED_COEFF */
+#define WM8962_EQ_SHARED_COEFF_SHIFT 2 /* EQ_SHARED_COEFF */
+#define WM8962_EQ_SHARED_COEFF_WIDTH 1 /* EQ_SHARED_COEFF */
+#define WM8962_EQ_SHARED_COEFF_SEL 0x0002 /* EQ_SHARED_COEFF_SEL */
+#define WM8962_EQ_SHARED_COEFF_SEL_MASK 0x0002 /* EQ_SHARED_COEFF_SEL */
+#define WM8962_EQ_SHARED_COEFF_SEL_SHIFT 1 /* EQ_SHARED_COEFF_SEL */
+#define WM8962_EQ_SHARED_COEFF_SEL_WIDTH 1 /* EQ_SHARED_COEFF_SEL */
+#define WM8962_EQ_ENA 0x0001 /* EQ_ENA */
+#define WM8962_EQ_ENA_MASK 0x0001 /* EQ_ENA */
+#define WM8962_EQ_ENA_SHIFT 0 /* EQ_ENA */
+#define WM8962_EQ_ENA_WIDTH 1 /* EQ_ENA */
+
+/*
+ * R336 (0x150) - EQ2
+ */
+#define WM8962_EQL_B1_GAIN_MASK 0xF800 /* EQL_B1_GAIN - [15:11] */
+#define WM8962_EQL_B1_GAIN_SHIFT 11 /* EQL_B1_GAIN - [15:11] */
+#define WM8962_EQL_B1_GAIN_WIDTH 5 /* EQL_B1_GAIN - [15:11] */
+#define WM8962_EQL_B2_GAIN_MASK 0x07C0 /* EQL_B2_GAIN - [10:6] */
+#define WM8962_EQL_B2_GAIN_SHIFT 6 /* EQL_B2_GAIN - [10:6] */
+#define WM8962_EQL_B2_GAIN_WIDTH 5 /* EQL_B2_GAIN - [10:6] */
+#define WM8962_EQL_B3_GAIN_MASK 0x003E /* EQL_B3_GAIN - [5:1] */
+#define WM8962_EQL_B3_GAIN_SHIFT 1 /* EQL_B3_GAIN - [5:1] */
+#define WM8962_EQL_B3_GAIN_WIDTH 5 /* EQL_B3_GAIN - [5:1] */
+
+/*
+ * R337 (0x151) - EQ3
+ */
+#define WM8962_EQL_B4_GAIN_MASK 0xF800 /* EQL_B4_GAIN - [15:11] */
+#define WM8962_EQL_B4_GAIN_SHIFT 11 /* EQL_B4_GAIN - [15:11] */
+#define WM8962_EQL_B4_GAIN_WIDTH 5 /* EQL_B4_GAIN - [15:11] */
+#define WM8962_EQL_B5_GAIN_MASK 0x07C0 /* EQL_B5_GAIN - [10:6] */
+#define WM8962_EQL_B5_GAIN_SHIFT 6 /* EQL_B5_GAIN - [10:6] */
+#define WM8962_EQL_B5_GAIN_WIDTH 5 /* EQL_B5_GAIN - [10:6] */
+
+/*
+ * R338 (0x152) - EQ4
+ */
+#define WM8962_EQL_B1_A_MASK 0xFFFF /* EQL_B1_A - [15:0] */
+#define WM8962_EQL_B1_A_SHIFT 0 /* EQL_B1_A - [15:0] */
+#define WM8962_EQL_B1_A_WIDTH 16 /* EQL_B1_A - [15:0] */
+
+/*
+ * R339 (0x153) - EQ5
+ */
+#define WM8962_EQL_B1_B_MASK 0xFFFF /* EQL_B1_B - [15:0] */
+#define WM8962_EQL_B1_B_SHIFT 0 /* EQL_B1_B - [15:0] */
+#define WM8962_EQL_B1_B_WIDTH 16 /* EQL_B1_B - [15:0] */
+
+/*
+ * R340 (0x154) - EQ6
+ */
+#define WM8962_EQL_B1_PG_MASK 0xFFFF /* EQL_B1_PG - [15:0] */
+#define WM8962_EQL_B1_PG_SHIFT 0 /* EQL_B1_PG - [15:0] */
+#define WM8962_EQL_B1_PG_WIDTH 16 /* EQL_B1_PG - [15:0] */
+
+/*
+ * R341 (0x155) - EQ7
+ */
+#define WM8962_EQL_B2_A_MASK 0xFFFF /* EQL_B2_A - [15:0] */
+#define WM8962_EQL_B2_A_SHIFT 0 /* EQL_B2_A - [15:0] */
+#define WM8962_EQL_B2_A_WIDTH 16 /* EQL_B2_A - [15:0] */
+
+/*
+ * R342 (0x156) - EQ8
+ */
+#define WM8962_EQL_B2_B_MASK 0xFFFF /* EQL_B2_B - [15:0] */
+#define WM8962_EQL_B2_B_SHIFT 0 /* EQL_B2_B - [15:0] */
+#define WM8962_EQL_B2_B_WIDTH 16 /* EQL_B2_B - [15:0] */
+
+/*
+ * R343 (0x157) - EQ9
+ */
+#define WM8962_EQL_B2_C_MASK 0xFFFF /* EQL_B2_C - [15:0] */
+#define WM8962_EQL_B2_C_SHIFT 0 /* EQL_B2_C - [15:0] */
+#define WM8962_EQL_B2_C_WIDTH 16 /* EQL_B2_C - [15:0] */
+
+/*
+ * R344 (0x158) - EQ10
+ */
+#define WM8962_EQL_B2_PG_MASK 0xFFFF /* EQL_B2_PG - [15:0] */
+#define WM8962_EQL_B2_PG_SHIFT 0 /* EQL_B2_PG - [15:0] */
+#define WM8962_EQL_B2_PG_WIDTH 16 /* EQL_B2_PG - [15:0] */
+
+/*
+ * R345 (0x159) - EQ11
+ */
+#define WM8962_EQL_B3_A_MASK 0xFFFF /* EQL_B3_A - [15:0] */
+#define WM8962_EQL_B3_A_SHIFT 0 /* EQL_B3_A - [15:0] */
+#define WM8962_EQL_B3_A_WIDTH 16 /* EQL_B3_A - [15:0] */
+
+/*
+ * R346 (0x15A) - EQ12
+ */
+#define WM8962_EQL_B3_B_MASK 0xFFFF /* EQL_B3_B - [15:0] */
+#define WM8962_EQL_B3_B_SHIFT 0 /* EQL_B3_B - [15:0] */
+#define WM8962_EQL_B3_B_WIDTH 16 /* EQL_B3_B - [15:0] */
+
+/*
+ * R347 (0x15B) - EQ13
+ */
+#define WM8962_EQL_B3_C_MASK 0xFFFF /* EQL_B3_C - [15:0] */
+#define WM8962_EQL_B3_C_SHIFT 0 /* EQL_B3_C - [15:0] */
+#define WM8962_EQL_B3_C_WIDTH 16 /* EQL_B3_C - [15:0] */
+
+/*
+ * R348 (0x15C) - EQ14
+ */
+#define WM8962_EQL_B3_PG_MASK 0xFFFF /* EQL_B3_PG - [15:0] */
+#define WM8962_EQL_B3_PG_SHIFT 0 /* EQL_B3_PG - [15:0] */
+#define WM8962_EQL_B3_PG_WIDTH 16 /* EQL_B3_PG - [15:0] */
+
+/*
+ * R349 (0x15D) - EQ15
+ */
+#define WM8962_EQL_B4_A_MASK 0xFFFF /* EQL_B4_A - [15:0] */
+#define WM8962_EQL_B4_A_SHIFT 0 /* EQL_B4_A - [15:0] */
+#define WM8962_EQL_B4_A_WIDTH 16 /* EQL_B4_A - [15:0] */
+
+/*
+ * R350 (0x15E) - EQ16
+ */
+#define WM8962_EQL_B4_B_MASK 0xFFFF /* EQL_B4_B - [15:0] */
+#define WM8962_EQL_B4_B_SHIFT 0 /* EQL_B4_B - [15:0] */
+#define WM8962_EQL_B4_B_WIDTH 16 /* EQL_B4_B - [15:0] */
+
+/*
+ * R351 (0x15F) - EQ17
+ */
+#define WM8962_EQL_B4_C_MASK 0xFFFF /* EQL_B4_C - [15:0] */
+#define WM8962_EQL_B4_C_SHIFT 0 /* EQL_B4_C - [15:0] */
+#define WM8962_EQL_B4_C_WIDTH 16 /* EQL_B4_C - [15:0] */
+
+/*
+ * R352 (0x160) - EQ18
+ */
+#define WM8962_EQL_B4_PG_MASK 0xFFFF /* EQL_B4_PG - [15:0] */
+#define WM8962_EQL_B4_PG_SHIFT 0 /* EQL_B4_PG - [15:0] */
+#define WM8962_EQL_B4_PG_WIDTH 16 /* EQL_B4_PG - [15:0] */
+
+/*
+ * R353 (0x161) - EQ19
+ */
+#define WM8962_EQL_B5_A_MASK 0xFFFF /* EQL_B5_A - [15:0] */
+#define WM8962_EQL_B5_A_SHIFT 0 /* EQL_B5_A - [15:0] */
+#define WM8962_EQL_B5_A_WIDTH 16 /* EQL_B5_A - [15:0] */
+
+/*
+ * R354 (0x162) - EQ20
+ */
+#define WM8962_EQL_B5_B_MASK 0xFFFF /* EQL_B5_B - [15:0] */
+#define WM8962_EQL_B5_B_SHIFT 0 /* EQL_B5_B - [15:0] */
+#define WM8962_EQL_B5_B_WIDTH 16 /* EQL_B5_B - [15:0] */
+
+/*
+ * R355 (0x163) - EQ21
+ */
+#define WM8962_EQL_B5_PG_MASK 0xFFFF /* EQL_B5_PG - [15:0] */
+#define WM8962_EQL_B5_PG_SHIFT 0 /* EQL_B5_PG - [15:0] */
+#define WM8962_EQL_B5_PG_WIDTH 16 /* EQL_B5_PG - [15:0] */
+
+/*
+ * R356 (0x164) - EQ22
+ */
+#define WM8962_EQR_B1_GAIN_MASK 0xF800 /* EQR_B1_GAIN - [15:11] */
+#define WM8962_EQR_B1_GAIN_SHIFT 11 /* EQR_B1_GAIN - [15:11] */
+#define WM8962_EQR_B1_GAIN_WIDTH 5 /* EQR_B1_GAIN - [15:11] */
+#define WM8962_EQR_B2_GAIN_MASK 0x07C0 /* EQR_B2_GAIN - [10:6] */
+#define WM8962_EQR_B2_GAIN_SHIFT 6 /* EQR_B2_GAIN - [10:6] */
+#define WM8962_EQR_B2_GAIN_WIDTH 5 /* EQR_B2_GAIN - [10:6] */
+#define WM8962_EQR_B3_GAIN_MASK 0x003E /* EQR_B3_GAIN - [5:1] */
+#define WM8962_EQR_B3_GAIN_SHIFT 1 /* EQR_B3_GAIN - [5:1] */
+#define WM8962_EQR_B3_GAIN_WIDTH 5 /* EQR_B3_GAIN - [5:1] */
+
+/*
+ * R357 (0x165) - EQ23
+ */
+#define WM8962_EQR_B4_GAIN_MASK 0xF800 /* EQR_B4_GAIN - [15:11] */
+#define WM8962_EQR_B4_GAIN_SHIFT 11 /* EQR_B4_GAIN - [15:11] */
+#define WM8962_EQR_B4_GAIN_WIDTH 5 /* EQR_B4_GAIN - [15:11] */
+#define WM8962_EQR_B5_GAIN_MASK 0x07C0 /* EQR_B5_GAIN - [10:6] */
+#define WM8962_EQR_B5_GAIN_SHIFT 6 /* EQR_B5_GAIN - [10:6] */
+#define WM8962_EQR_B5_GAIN_WIDTH 5 /* EQR_B5_GAIN - [10:6] */
+
+/*
+ * R358 (0x166) - EQ24
+ */
+#define WM8962_EQR_B1_A_MASK 0xFFFF /* EQR_B1_A - [15:0] */
+#define WM8962_EQR_B1_A_SHIFT 0 /* EQR_B1_A - [15:0] */
+#define WM8962_EQR_B1_A_WIDTH 16 /* EQR_B1_A - [15:0] */
+
+/*
+ * R359 (0x167) - EQ25
+ */
+#define WM8962_EQR_B1_B_MASK 0xFFFF /* EQR_B1_B - [15:0] */
+#define WM8962_EQR_B1_B_SHIFT 0 /* EQR_B1_B - [15:0] */
+#define WM8962_EQR_B1_B_WIDTH 16 /* EQR_B1_B - [15:0] */
+
+/*
+ * R360 (0x168) - EQ26
+ */
+#define WM8962_EQR_B1_PG_MASK 0xFFFF /* EQR_B1_PG - [15:0] */
+#define WM8962_EQR_B1_PG_SHIFT 0 /* EQR_B1_PG - [15:0] */
+#define WM8962_EQR_B1_PG_WIDTH 16 /* EQR_B1_PG - [15:0] */
+
+/*
+ * R361 (0x169) - EQ27
+ */
+#define WM8962_EQR_B2_A_MASK 0xFFFF /* EQR_B2_A - [15:0] */
+#define WM8962_EQR_B2_A_SHIFT 0 /* EQR_B2_A - [15:0] */
+#define WM8962_EQR_B2_A_WIDTH 16 /* EQR_B2_A - [15:0] */
+
+/*
+ * R362 (0x16A) - EQ28
+ */
+#define WM8962_EQR_B2_B_MASK 0xFFFF /* EQR_B2_B - [15:0] */
+#define WM8962_EQR_B2_B_SHIFT 0 /* EQR_B2_B - [15:0] */
+#define WM8962_EQR_B2_B_WIDTH 16 /* EQR_B2_B - [15:0] */
+
+/*
+ * R363 (0x16B) - EQ29
+ */
+#define WM8962_EQR_B2_C_MASK 0xFFFF /* EQR_B2_C - [15:0] */
+#define WM8962_EQR_B2_C_SHIFT 0 /* EQR_B2_C - [15:0] */
+#define WM8962_EQR_B2_C_WIDTH 16 /* EQR_B2_C - [15:0] */
+
+/*
+ * R364 (0x16C) - EQ30
+ */
+#define WM8962_EQR_B2_PG_MASK 0xFFFF /* EQR_B2_PG - [15:0] */
+#define WM8962_EQR_B2_PG_SHIFT 0 /* EQR_B2_PG - [15:0] */
+#define WM8962_EQR_B2_PG_WIDTH 16 /* EQR_B2_PG - [15:0] */
+
+/*
+ * R365 (0x16D) - EQ31
+ */
+#define WM8962_EQR_B3_A_MASK 0xFFFF /* EQR_B3_A - [15:0] */
+#define WM8962_EQR_B3_A_SHIFT 0 /* EQR_B3_A - [15:0] */
+#define WM8962_EQR_B3_A_WIDTH 16 /* EQR_B3_A - [15:0] */
+
+/*
+ * R366 (0x16E) - EQ32
+ */
+#define WM8962_EQR_B3_B_MASK 0xFFFF /* EQR_B3_B - [15:0] */
+#define WM8962_EQR_B3_B_SHIFT 0 /* EQR_B3_B - [15:0] */
+#define WM8962_EQR_B3_B_WIDTH 16 /* EQR_B3_B - [15:0] */
+
+/*
+ * R367 (0x16F) - EQ33
+ */
+#define WM8962_EQR_B3_C_MASK 0xFFFF /* EQR_B3_C - [15:0] */
+#define WM8962_EQR_B3_C_SHIFT 0 /* EQR_B3_C - [15:0] */
+#define WM8962_EQR_B3_C_WIDTH 16 /* EQR_B3_C - [15:0] */
+
+/*
+ * R368 (0x170) - EQ34
+ */
+#define WM8962_EQR_B3_PG_MASK 0xFFFF /* EQR_B3_PG - [15:0] */
+#define WM8962_EQR_B3_PG_SHIFT 0 /* EQR_B3_PG - [15:0] */
+#define WM8962_EQR_B3_PG_WIDTH 16 /* EQR_B3_PG - [15:0] */
+
+/*
+ * R369 (0x171) - EQ35
+ */
+#define WM8962_EQR_B4_A_MASK 0xFFFF /* EQR_B4_A - [15:0] */
+#define WM8962_EQR_B4_A_SHIFT 0 /* EQR_B4_A - [15:0] */
+#define WM8962_EQR_B4_A_WIDTH 16 /* EQR_B4_A - [15:0] */
+
+/*
+ * R370 (0x172) - EQ36
+ */
+#define WM8962_EQR_B4_B_MASK 0xFFFF /* EQR_B4_B - [15:0] */
+#define WM8962_EQR_B4_B_SHIFT 0 /* EQR_B4_B - [15:0] */
+#define WM8962_EQR_B4_B_WIDTH 16 /* EQR_B4_B - [15:0] */
+
+/*
+ * R371 (0x173) - EQ37
+ */
+#define WM8962_EQR_B4_C_MASK 0xFFFF /* EQR_B4_C - [15:0] */
+#define WM8962_EQR_B4_C_SHIFT 0 /* EQR_B4_C - [15:0] */
+#define WM8962_EQR_B4_C_WIDTH 16 /* EQR_B4_C - [15:0] */
+
+/*
+ * R372 (0x174) - EQ38
+ */
+#define WM8962_EQR_B4_PG_MASK 0xFFFF /* EQR_B4_PG - [15:0] */
+#define WM8962_EQR_B4_PG_SHIFT 0 /* EQR_B4_PG - [15:0] */
+#define WM8962_EQR_B4_PG_WIDTH 16 /* EQR_B4_PG - [15:0] */
+
+/*
+ * R373 (0x175) - EQ39
+ */
+#define WM8962_EQR_B5_A_MASK 0xFFFF /* EQR_B5_A - [15:0] */
+#define WM8962_EQR_B5_A_SHIFT 0 /* EQR_B5_A - [15:0] */
+#define WM8962_EQR_B5_A_WIDTH 16 /* EQR_B5_A - [15:0] */
+
+/*
+ * R374 (0x176) - EQ40
+ */
+#define WM8962_EQR_B5_B_MASK 0xFFFF /* EQR_B5_B - [15:0] */
+#define WM8962_EQR_B5_B_SHIFT 0 /* EQR_B5_B - [15:0] */
+#define WM8962_EQR_B5_B_WIDTH 16 /* EQR_B5_B - [15:0] */
+
+/*
+ * R375 (0x177) - EQ41
+ */
+#define WM8962_EQR_B5_PG_MASK 0xFFFF /* EQR_B5_PG - [15:0] */
+#define WM8962_EQR_B5_PG_SHIFT 0 /* EQR_B5_PG - [15:0] */
+#define WM8962_EQR_B5_PG_WIDTH 16 /* EQR_B5_PG - [15:0] */
+
+/*
+ * R513 (0x201) - GPIO 2
+ */
+#define WM8962_GP2_POL 0x0400 /* GP2_POL */
+#define WM8962_GP2_POL_MASK 0x0400 /* GP2_POL */
+#define WM8962_GP2_POL_SHIFT 10 /* GP2_POL */
+#define WM8962_GP2_POL_WIDTH 1 /* GP2_POL */
+#define WM8962_GP2_LVL 0x0040 /* GP2_LVL */
+#define WM8962_GP2_LVL_MASK 0x0040 /* GP2_LVL */
+#define WM8962_GP2_LVL_SHIFT 6 /* GP2_LVL */
+#define WM8962_GP2_LVL_WIDTH 1 /* GP2_LVL */
+#define WM8962_GP2_FN_MASK 0x001F /* GP2_FN - [4:0] */
+#define WM8962_GP2_FN_SHIFT 0 /* GP2_FN - [4:0] */
+#define WM8962_GP2_FN_WIDTH 5 /* GP2_FN - [4:0] */
+
+/*
+ * R514 (0x202) - GPIO 3
+ */
+#define WM8962_GP3_POL 0x0400 /* GP3_POL */
+#define WM8962_GP3_POL_MASK 0x0400 /* GP3_POL */
+#define WM8962_GP3_POL_SHIFT 10 /* GP3_POL */
+#define WM8962_GP3_POL_WIDTH 1 /* GP3_POL */
+#define WM8962_GP3_LVL 0x0040 /* GP3_LVL */
+#define WM8962_GP3_LVL_MASK 0x0040 /* GP3_LVL */
+#define WM8962_GP3_LVL_SHIFT 6 /* GP3_LVL */
+#define WM8962_GP3_LVL_WIDTH 1 /* GP3_LVL */
+#define WM8962_GP3_FN_MASK 0x001F /* GP3_FN - [4:0] */
+#define WM8962_GP3_FN_SHIFT 0 /* GP3_FN - [4:0] */
+#define WM8962_GP3_FN_WIDTH 5 /* GP3_FN - [4:0] */
+
+/*
+ * R516 (0x204) - GPIO 5
+ */
+#define WM8962_GP5_DIR 0x8000 /* GP5_DIR */
+#define WM8962_GP5_DIR_MASK 0x8000 /* GP5_DIR */
+#define WM8962_GP5_DIR_SHIFT 15 /* GP5_DIR */
+#define WM8962_GP5_DIR_WIDTH 1 /* GP5_DIR */
+#define WM8962_GP5_PU 0x4000 /* GP5_PU */
+#define WM8962_GP5_PU_MASK 0x4000 /* GP5_PU */
+#define WM8962_GP5_PU_SHIFT 14 /* GP5_PU */
+#define WM8962_GP5_PU_WIDTH 1 /* GP5_PU */
+#define WM8962_GP5_PD 0x2000 /* GP5_PD */
+#define WM8962_GP5_PD_MASK 0x2000 /* GP5_PD */
+#define WM8962_GP5_PD_SHIFT 13 /* GP5_PD */
+#define WM8962_GP5_PD_WIDTH 1 /* GP5_PD */
+#define WM8962_GP5_POL 0x0400 /* GP5_POL */
+#define WM8962_GP5_POL_MASK 0x0400 /* GP5_POL */
+#define WM8962_GP5_POL_SHIFT 10 /* GP5_POL */
+#define WM8962_GP5_POL_WIDTH 1 /* GP5_POL */
+#define WM8962_GP5_OP_CFG 0x0200 /* GP5_OP_CFG */
+#define WM8962_GP5_OP_CFG_MASK 0x0200 /* GP5_OP_CFG */
+#define WM8962_GP5_OP_CFG_SHIFT 9 /* GP5_OP_CFG */
+#define WM8962_GP5_OP_CFG_WIDTH 1 /* GP5_OP_CFG */
+#define WM8962_GP5_DB 0x0100 /* GP5_DB */
+#define WM8962_GP5_DB_MASK 0x0100 /* GP5_DB */
+#define WM8962_GP5_DB_SHIFT 8 /* GP5_DB */
+#define WM8962_GP5_DB_WIDTH 1 /* GP5_DB */
+#define WM8962_GP5_LVL 0x0040 /* GP5_LVL */
+#define WM8962_GP5_LVL_MASK 0x0040 /* GP5_LVL */
+#define WM8962_GP5_LVL_SHIFT 6 /* GP5_LVL */
+#define WM8962_GP5_LVL_WIDTH 1 /* GP5_LVL */
+#define WM8962_GP5_FN_MASK 0x001F /* GP5_FN - [4:0] */
+#define WM8962_GP5_FN_SHIFT 0 /* GP5_FN - [4:0] */
+#define WM8962_GP5_FN_WIDTH 5 /* GP5_FN - [4:0] */
+
+/*
+ * R517 (0x205) - GPIO 6
+ */
+#define WM8962_GP6_DIR 0x8000 /* GP6_DIR */
+#define WM8962_GP6_DIR_MASK 0x8000 /* GP6_DIR */
+#define WM8962_GP6_DIR_SHIFT 15 /* GP6_DIR */
+#define WM8962_GP6_DIR_WIDTH 1 /* GP6_DIR */
+#define WM8962_GP6_PU 0x4000 /* GP6_PU */
+#define WM8962_GP6_PU_MASK 0x4000 /* GP6_PU */
+#define WM8962_GP6_PU_SHIFT 14 /* GP6_PU */
+#define WM8962_GP6_PU_WIDTH 1 /* GP6_PU */
+#define WM8962_GP6_PD 0x2000 /* GP6_PD */
+#define WM8962_GP6_PD_MASK 0x2000 /* GP6_PD */
+#define WM8962_GP6_PD_SHIFT 13 /* GP6_PD */
+#define WM8962_GP6_PD_WIDTH 1 /* GP6_PD */
+#define WM8962_GP6_POL 0x0400 /* GP6_POL */
+#define WM8962_GP6_POL_MASK 0x0400 /* GP6_POL */
+#define WM8962_GP6_POL_SHIFT 10 /* GP6_POL */
+#define WM8962_GP6_POL_WIDTH 1 /* GP6_POL */
+#define WM8962_GP6_OP_CFG 0x0200 /* GP6_OP_CFG */
+#define WM8962_GP6_OP_CFG_MASK 0x0200 /* GP6_OP_CFG */
+#define WM8962_GP6_OP_CFG_SHIFT 9 /* GP6_OP_CFG */
+#define WM8962_GP6_OP_CFG_WIDTH 1 /* GP6_OP_CFG */
+#define WM8962_GP6_DB 0x0100 /* GP6_DB */
+#define WM8962_GP6_DB_MASK 0x0100 /* GP6_DB */
+#define WM8962_GP6_DB_SHIFT 8 /* GP6_DB */
+#define WM8962_GP6_DB_WIDTH 1 /* GP6_DB */
+#define WM8962_GP6_LVL 0x0040 /* GP6_LVL */
+#define WM8962_GP6_LVL_MASK 0x0040 /* GP6_LVL */
+#define WM8962_GP6_LVL_SHIFT 6 /* GP6_LVL */
+#define WM8962_GP6_LVL_WIDTH 1 /* GP6_LVL */
+#define WM8962_GP6_FN_MASK 0x001F /* GP6_FN - [4:0] */
+#define WM8962_GP6_FN_SHIFT 0 /* GP6_FN - [4:0] */
+#define WM8962_GP6_FN_WIDTH 5 /* GP6_FN - [4:0] */
+
+/*
+ * R560 (0x230) - Interrupt Status 1
+ */
+#define WM8962_GP6_EINT 0x0020 /* GP6_EINT */
+#define WM8962_GP6_EINT_MASK 0x0020 /* GP6_EINT */
+#define WM8962_GP6_EINT_SHIFT 5 /* GP6_EINT */
+#define WM8962_GP6_EINT_WIDTH 1 /* GP6_EINT */
+#define WM8962_GP5_EINT 0x0010 /* GP5_EINT */
+#define WM8962_GP5_EINT_MASK 0x0010 /* GP5_EINT */
+#define WM8962_GP5_EINT_SHIFT 4 /* GP5_EINT */
+#define WM8962_GP5_EINT_WIDTH 1 /* GP5_EINT */
+
+/*
+ * R561 (0x231) - Interrupt Status 2
+ */
+#define WM8962_MICSCD_EINT 0x8000 /* MICSCD_EINT */
+#define WM8962_MICSCD_EINT_MASK 0x8000 /* MICSCD_EINT */
+#define WM8962_MICSCD_EINT_SHIFT 15 /* MICSCD_EINT */
+#define WM8962_MICSCD_EINT_WIDTH 1 /* MICSCD_EINT */
+#define WM8962_MICD_EINT 0x4000 /* MICD_EINT */
+#define WM8962_MICD_EINT_MASK 0x4000 /* MICD_EINT */
+#define WM8962_MICD_EINT_SHIFT 14 /* MICD_EINT */
+#define WM8962_MICD_EINT_WIDTH 1 /* MICD_EINT */
+#define WM8962_FIFOS_ERR_EINT 0x2000 /* FIFOS_ERR_EINT */
+#define WM8962_FIFOS_ERR_EINT_MASK 0x2000 /* FIFOS_ERR_EINT */
+#define WM8962_FIFOS_ERR_EINT_SHIFT 13 /* FIFOS_ERR_EINT */
+#define WM8962_FIFOS_ERR_EINT_WIDTH 1 /* FIFOS_ERR_EINT */
+#define WM8962_ALC_LOCK_EINT 0x1000 /* ALC_LOCK_EINT */
+#define WM8962_ALC_LOCK_EINT_MASK 0x1000 /* ALC_LOCK_EINT */
+#define WM8962_ALC_LOCK_EINT_SHIFT 12 /* ALC_LOCK_EINT */
+#define WM8962_ALC_LOCK_EINT_WIDTH 1 /* ALC_LOCK_EINT */
+#define WM8962_ALC_THRESH_EINT 0x0800 /* ALC_THRESH_EINT */
+#define WM8962_ALC_THRESH_EINT_MASK 0x0800 /* ALC_THRESH_EINT */
+#define WM8962_ALC_THRESH_EINT_SHIFT 11 /* ALC_THRESH_EINT */
+#define WM8962_ALC_THRESH_EINT_WIDTH 1 /* ALC_THRESH_EINT */
+#define WM8962_ALC_SAT_EINT 0x0400 /* ALC_SAT_EINT */
+#define WM8962_ALC_SAT_EINT_MASK 0x0400 /* ALC_SAT_EINT */
+#define WM8962_ALC_SAT_EINT_SHIFT 10 /* ALC_SAT_EINT */
+#define WM8962_ALC_SAT_EINT_WIDTH 1 /* ALC_SAT_EINT */
+#define WM8962_ALC_PKOVR_EINT 0x0200 /* ALC_PKOVR_EINT */
+#define WM8962_ALC_PKOVR_EINT_MASK 0x0200 /* ALC_PKOVR_EINT */
+#define WM8962_ALC_PKOVR_EINT_SHIFT 9 /* ALC_PKOVR_EINT */
+#define WM8962_ALC_PKOVR_EINT_WIDTH 1 /* ALC_PKOVR_EINT */
+#define WM8962_ALC_NGATE_EINT 0x0100 /* ALC_NGATE_EINT */
+#define WM8962_ALC_NGATE_EINT_MASK 0x0100 /* ALC_NGATE_EINT */
+#define WM8962_ALC_NGATE_EINT_SHIFT 8 /* ALC_NGATE_EINT */
+#define WM8962_ALC_NGATE_EINT_WIDTH 1 /* ALC_NGATE_EINT */
+#define WM8962_WSEQ_DONE_EINT 0x0080 /* WSEQ_DONE_EINT */
+#define WM8962_WSEQ_DONE_EINT_MASK 0x0080 /* WSEQ_DONE_EINT */
+#define WM8962_WSEQ_DONE_EINT_SHIFT 7 /* WSEQ_DONE_EINT */
+#define WM8962_WSEQ_DONE_EINT_WIDTH 1 /* WSEQ_DONE_EINT */
+#define WM8962_DRC_ACTDET_EINT 0x0040 /* DRC_ACTDET_EINT */
+#define WM8962_DRC_ACTDET_EINT_MASK 0x0040 /* DRC_ACTDET_EINT */
+#define WM8962_DRC_ACTDET_EINT_SHIFT 6 /* DRC_ACTDET_EINT */
+#define WM8962_DRC_ACTDET_EINT_WIDTH 1 /* DRC_ACTDET_EINT */
+#define WM8962_FLL_LOCK_EINT 0x0020 /* FLL_LOCK_EINT */
+#define WM8962_FLL_LOCK_EINT_MASK 0x0020 /* FLL_LOCK_EINT */
+#define WM8962_FLL_LOCK_EINT_SHIFT 5 /* FLL_LOCK_EINT */
+#define WM8962_FLL_LOCK_EINT_WIDTH 1 /* FLL_LOCK_EINT */
+#define WM8962_PLL3_LOCK_EINT 0x0008 /* PLL3_LOCK_EINT */
+#define WM8962_PLL3_LOCK_EINT_MASK 0x0008 /* PLL3_LOCK_EINT */
+#define WM8962_PLL3_LOCK_EINT_SHIFT 3 /* PLL3_LOCK_EINT */
+#define WM8962_PLL3_LOCK_EINT_WIDTH 1 /* PLL3_LOCK_EINT */
+#define WM8962_PLL2_LOCK_EINT 0x0004 /* PLL2_LOCK_EINT */
+#define WM8962_PLL2_LOCK_EINT_MASK 0x0004 /* PLL2_LOCK_EINT */
+#define WM8962_PLL2_LOCK_EINT_SHIFT 2 /* PLL2_LOCK_EINT */
+#define WM8962_PLL2_LOCK_EINT_WIDTH 1 /* PLL2_LOCK_EINT */
+#define WM8962_TEMP_SHUT_EINT 0x0001 /* TEMP_SHUT_EINT */
+#define WM8962_TEMP_SHUT_EINT_MASK 0x0001 /* TEMP_SHUT_EINT */
+#define WM8962_TEMP_SHUT_EINT_SHIFT 0 /* TEMP_SHUT_EINT */
+#define WM8962_TEMP_SHUT_EINT_WIDTH 1 /* TEMP_SHUT_EINT */
+
+/*
+ * R568 (0x238) - Interrupt Status 1 Mask
+ */
+#define WM8962_IM_GP6_EINT 0x0020 /* IM_GP6_EINT */
+#define WM8962_IM_GP6_EINT_MASK 0x0020 /* IM_GP6_EINT */
+#define WM8962_IM_GP6_EINT_SHIFT 5 /* IM_GP6_EINT */
+#define WM8962_IM_GP6_EINT_WIDTH 1 /* IM_GP6_EINT */
+#define WM8962_IM_GP5_EINT 0x0010 /* IM_GP5_EINT */
+#define WM8962_IM_GP5_EINT_MASK 0x0010 /* IM_GP5_EINT */
+#define WM8962_IM_GP5_EINT_SHIFT 4 /* IM_GP5_EINT */
+#define WM8962_IM_GP5_EINT_WIDTH 1 /* IM_GP5_EINT */
+
+/*
+ * R569 (0x239) - Interrupt Status 2 Mask
+ */
+#define WM8962_IM_MICSCD_EINT 0x8000 /* IM_MICSCD_EINT */
+#define WM8962_IM_MICSCD_EINT_MASK 0x8000 /* IM_MICSCD_EINT */
+#define WM8962_IM_MICSCD_EINT_SHIFT 15 /* IM_MICSCD_EINT */
+#define WM8962_IM_MICSCD_EINT_WIDTH 1 /* IM_MICSCD_EINT */
+#define WM8962_IM_MICD_EINT 0x4000 /* IM_MICD_EINT */
+#define WM8962_IM_MICD_EINT_MASK 0x4000 /* IM_MICD_EINT */
+#define WM8962_IM_MICD_EINT_SHIFT 14 /* IM_MICD_EINT */
+#define WM8962_IM_MICD_EINT_WIDTH 1 /* IM_MICD_EINT */
+#define WM8962_IM_FIFOS_ERR_EINT 0x2000 /* IM_FIFOS_ERR_EINT */
+#define WM8962_IM_FIFOS_ERR_EINT_MASK 0x2000 /* IM_FIFOS_ERR_EINT */
+#define WM8962_IM_FIFOS_ERR_EINT_SHIFT 13 /* IM_FIFOS_ERR_EINT */
+#define WM8962_IM_FIFOS_ERR_EINT_WIDTH 1 /* IM_FIFOS_ERR_EINT */
+#define WM8962_IM_ALC_LOCK_EINT 0x1000 /* IM_ALC_LOCK_EINT */
+#define WM8962_IM_ALC_LOCK_EINT_MASK 0x1000 /* IM_ALC_LOCK_EINT */
+#define WM8962_IM_ALC_LOCK_EINT_SHIFT 12 /* IM_ALC_LOCK_EINT */
+#define WM8962_IM_ALC_LOCK_EINT_WIDTH 1 /* IM_ALC_LOCK_EINT */
+#define WM8962_IM_ALC_THRESH_EINT 0x0800 /* IM_ALC_THRESH_EINT */
+#define WM8962_IM_ALC_THRESH_EINT_MASK 0x0800 /* IM_ALC_THRESH_EINT */
+#define WM8962_IM_ALC_THRESH_EINT_SHIFT 11 /* IM_ALC_THRESH_EINT */
+#define WM8962_IM_ALC_THRESH_EINT_WIDTH 1 /* IM_ALC_THRESH_EINT */
+#define WM8962_IM_ALC_SAT_EINT 0x0400 /* IM_ALC_SAT_EINT */
+#define WM8962_IM_ALC_SAT_EINT_MASK 0x0400 /* IM_ALC_SAT_EINT */
+#define WM8962_IM_ALC_SAT_EINT_SHIFT 10 /* IM_ALC_SAT_EINT */
+#define WM8962_IM_ALC_SAT_EINT_WIDTH 1 /* IM_ALC_SAT_EINT */
+#define WM8962_IM_ALC_PKOVR_EINT 0x0200 /* IM_ALC_PKOVR_EINT */
+#define WM8962_IM_ALC_PKOVR_EINT_MASK 0x0200 /* IM_ALC_PKOVR_EINT */
+#define WM8962_IM_ALC_PKOVR_EINT_SHIFT 9 /* IM_ALC_PKOVR_EINT */
+#define WM8962_IM_ALC_PKOVR_EINT_WIDTH 1 /* IM_ALC_PKOVR_EINT */
+#define WM8962_IM_ALC_NGATE_EINT 0x0100 /* IM_ALC_NGATE_EINT */
+#define WM8962_IM_ALC_NGATE_EINT_MASK 0x0100 /* IM_ALC_NGATE_EINT */
+#define WM8962_IM_ALC_NGATE_EINT_SHIFT 8 /* IM_ALC_NGATE_EINT */
+#define WM8962_IM_ALC_NGATE_EINT_WIDTH 1 /* IM_ALC_NGATE_EINT */
+#define WM8962_IM_WSEQ_DONE_EINT 0x0080 /* IM_WSEQ_DONE_EINT */
+#define WM8962_IM_WSEQ_DONE_EINT_MASK 0x0080 /* IM_WSEQ_DONE_EINT */
+#define WM8962_IM_WSEQ_DONE_EINT_SHIFT 7 /* IM_WSEQ_DONE_EINT */
+#define WM8962_IM_WSEQ_DONE_EINT_WIDTH 1 /* IM_WSEQ_DONE_EINT */
+#define WM8962_IM_DRC_ACTDET_EINT 0x0040 /* IM_DRC_ACTDET_EINT */
+#define WM8962_IM_DRC_ACTDET_EINT_MASK 0x0040 /* IM_DRC_ACTDET_EINT */
+#define WM8962_IM_DRC_ACTDET_EINT_SHIFT 6 /* IM_DRC_ACTDET_EINT */
+#define WM8962_IM_DRC_ACTDET_EINT_WIDTH 1 /* IM_DRC_ACTDET_EINT */
+#define WM8962_IM_FLL_LOCK_EINT 0x0020 /* IM_FLL_LOCK_EINT */
+#define WM8962_IM_FLL_LOCK_EINT_MASK 0x0020 /* IM_FLL_LOCK_EINT */
+#define WM8962_IM_FLL_LOCK_EINT_SHIFT 5 /* IM_FLL_LOCK_EINT */
+#define WM8962_IM_FLL_LOCK_EINT_WIDTH 1 /* IM_FLL_LOCK_EINT */
+#define WM8962_IM_PLL3_LOCK_EINT 0x0008 /* IM_PLL3_LOCK_EINT */
+#define WM8962_IM_PLL3_LOCK_EINT_MASK 0x0008 /* IM_PLL3_LOCK_EINT */
+#define WM8962_IM_PLL3_LOCK_EINT_SHIFT 3 /* IM_PLL3_LOCK_EINT */
+#define WM8962_IM_PLL3_LOCK_EINT_WIDTH 1 /* IM_PLL3_LOCK_EINT */
+#define WM8962_IM_PLL2_LOCK_EINT 0x0004 /* IM_PLL2_LOCK_EINT */
+#define WM8962_IM_PLL2_LOCK_EINT_MASK 0x0004 /* IM_PLL2_LOCK_EINT */
+#define WM8962_IM_PLL2_LOCK_EINT_SHIFT 2 /* IM_PLL2_LOCK_EINT */
+#define WM8962_IM_PLL2_LOCK_EINT_WIDTH 1 /* IM_PLL2_LOCK_EINT */
+#define WM8962_IM_TEMP_SHUT_EINT 0x0001 /* IM_TEMP_SHUT_EINT */
+#define WM8962_IM_TEMP_SHUT_EINT_MASK 0x0001 /* IM_TEMP_SHUT_EINT */
+#define WM8962_IM_TEMP_SHUT_EINT_SHIFT 0 /* IM_TEMP_SHUT_EINT */
+#define WM8962_IM_TEMP_SHUT_EINT_WIDTH 1 /* IM_TEMP_SHUT_EINT */
+
+/*
+ * R576 (0x240) - Interrupt Control
+ */
+#define WM8962_IRQ_POL 0x0001 /* IRQ_POL */
+#define WM8962_IRQ_POL_MASK 0x0001 /* IRQ_POL */
+#define WM8962_IRQ_POL_SHIFT 0 /* IRQ_POL */
+#define WM8962_IRQ_POL_WIDTH 1 /* IRQ_POL */
+
+/*
+ * R584 (0x248) - IRQ Debounce
+ */
+#define WM8962_FLL_LOCK_DB 0x0020 /* FLL_LOCK_DB */
+#define WM8962_FLL_LOCK_DB_MASK 0x0020 /* FLL_LOCK_DB */
+#define WM8962_FLL_LOCK_DB_SHIFT 5 /* FLL_LOCK_DB */
+#define WM8962_FLL_LOCK_DB_WIDTH 1 /* FLL_LOCK_DB */
+#define WM8962_PLL3_LOCK_DB 0x0008 /* PLL3_LOCK_DB */
+#define WM8962_PLL3_LOCK_DB_MASK 0x0008 /* PLL3_LOCK_DB */
+#define WM8962_PLL3_LOCK_DB_SHIFT 3 /* PLL3_LOCK_DB */
+#define WM8962_PLL3_LOCK_DB_WIDTH 1 /* PLL3_LOCK_DB */
+#define WM8962_PLL2_LOCK_DB 0x0004 /* PLL2_LOCK_DB */
+#define WM8962_PLL2_LOCK_DB_MASK 0x0004 /* PLL2_LOCK_DB */
+#define WM8962_PLL2_LOCK_DB_SHIFT 2 /* PLL2_LOCK_DB */
+#define WM8962_PLL2_LOCK_DB_WIDTH 1 /* PLL2_LOCK_DB */
+#define WM8962_TEMP_SHUT_DB 0x0001 /* TEMP_SHUT_DB */
+#define WM8962_TEMP_SHUT_DB_MASK 0x0001 /* TEMP_SHUT_DB */
+#define WM8962_TEMP_SHUT_DB_SHIFT 0 /* TEMP_SHUT_DB */
+#define WM8962_TEMP_SHUT_DB_WIDTH 1 /* TEMP_SHUT_DB */
+
+/*
+ * R586 (0x24A) - MICINT Source Pol
+ */
+#define WM8962_MICSCD_IRQ_POL 0x8000 /* MICSCD_IRQ_POL */
+#define WM8962_MICSCD_IRQ_POL_MASK 0x8000 /* MICSCD_IRQ_POL */
+#define WM8962_MICSCD_IRQ_POL_SHIFT 15 /* MICSCD_IRQ_POL */
+#define WM8962_MICSCD_IRQ_POL_WIDTH 1 /* MICSCD_IRQ_POL */
+#define WM8962_MICD_IRQ_POL 0x4000 /* MICD_IRQ_POL */
+#define WM8962_MICD_IRQ_POL_MASK 0x4000 /* MICD_IRQ_POL */
+#define WM8962_MICD_IRQ_POL_SHIFT 14 /* MICD_IRQ_POL */
+#define WM8962_MICD_IRQ_POL_WIDTH 1 /* MICD_IRQ_POL */
+
+/*
+ * R768 (0x300) - DSP2 Power Management
+ */
+#define WM8962_DSP2_ENA 0x0001 /* DSP2_ENA */
+#define WM8962_DSP2_ENA_MASK 0x0001 /* DSP2_ENA */
+#define WM8962_DSP2_ENA_SHIFT 0 /* DSP2_ENA */
+#define WM8962_DSP2_ENA_WIDTH 1 /* DSP2_ENA */
+
+/*
+ * R1037 (0x40D) - DSP2_ExecControl
+ */
+#define WM8962_DSP2_STOPC 0x0020 /* DSP2_STOPC */
+#define WM8962_DSP2_STOPC_MASK 0x0020 /* DSP2_STOPC */
+#define WM8962_DSP2_STOPC_SHIFT 5 /* DSP2_STOPC */
+#define WM8962_DSP2_STOPC_WIDTH 1 /* DSP2_STOPC */
+#define WM8962_DSP2_STOPS 0x0010 /* DSP2_STOPS */
+#define WM8962_DSP2_STOPS_MASK 0x0010 /* DSP2_STOPS */
+#define WM8962_DSP2_STOPS_SHIFT 4 /* DSP2_STOPS */
+#define WM8962_DSP2_STOPS_WIDTH 1 /* DSP2_STOPS */
+#define WM8962_DSP2_STOPI 0x0008 /* DSP2_STOPI */
+#define WM8962_DSP2_STOPI_MASK 0x0008 /* DSP2_STOPI */
+#define WM8962_DSP2_STOPI_SHIFT 3 /* DSP2_STOPI */
+#define WM8962_DSP2_STOPI_WIDTH 1 /* DSP2_STOPI */
+#define WM8962_DSP2_STOP 0x0004 /* DSP2_STOP */
+#define WM8962_DSP2_STOP_MASK 0x0004 /* DSP2_STOP */
+#define WM8962_DSP2_STOP_SHIFT 2 /* DSP2_STOP */
+#define WM8962_DSP2_STOP_WIDTH 1 /* DSP2_STOP */
+#define WM8962_DSP2_RUNR 0x0002 /* DSP2_RUNR */
+#define WM8962_DSP2_RUNR_MASK 0x0002 /* DSP2_RUNR */
+#define WM8962_DSP2_RUNR_SHIFT 1 /* DSP2_RUNR */
+#define WM8962_DSP2_RUNR_WIDTH 1 /* DSP2_RUNR */
+#define WM8962_DSP2_RUN 0x0001 /* DSP2_RUN */
+#define WM8962_DSP2_RUN_MASK 0x0001 /* DSP2_RUN */
+#define WM8962_DSP2_RUN_SHIFT 0 /* DSP2_RUN */
+#define WM8962_DSP2_RUN_WIDTH 1 /* DSP2_RUN */
+
+/*
+ * R8192 (0x2000) - DSP2 Instruction RAM 0
+ */
+#define WM8962_DSP2_INSTR_RAM_1024_10_9_0_MASK 0x03FF /* DSP2_INSTR_RAM_1024_10_9_0 - [9:0] */
+#define WM8962_DSP2_INSTR_RAM_1024_10_9_0_SHIFT 0 /* DSP2_INSTR_RAM_1024_10_9_0 - [9:0] */
+#define WM8962_DSP2_INSTR_RAM_1024_10_9_0_WIDTH 10 /* DSP2_INSTR_RAM_1024_10_9_0 - [9:0] */
+
+/*
+ * R9216 (0x2400) - DSP2 Address RAM 2
+ */
+#define WM8962_DSP2_ADDR_RAM_1024_38_37_32_MASK 0x003F /* DSP2_ADDR_RAM_1024_38_37_32 - [5:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_37_32_SHIFT 0 /* DSP2_ADDR_RAM_1024_38_37_32 - [5:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_37_32_WIDTH 6 /* DSP2_ADDR_RAM_1024_38_37_32 - [5:0] */
+
+/*
+ * R9217 (0x2401) - DSP2 Address RAM 1
+ */
+#define WM8962_DSP2_ADDR_RAM_1024_38_31_16_MASK 0xFFFF /* DSP2_ADDR_RAM_1024_38_31_16 - [15:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_31_16_SHIFT 0 /* DSP2_ADDR_RAM_1024_38_31_16 - [15:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_31_16_WIDTH 16 /* DSP2_ADDR_RAM_1024_38_31_16 - [15:0] */
+
+/*
+ * R9218 (0x2402) - DSP2 Address RAM 0
+ */
+#define WM8962_DSP2_ADDR_RAM_1024_38_15_0_MASK 0xFFFF /* DSP2_ADDR_RAM_1024_38_15_0 - [15:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_15_0_SHIFT 0 /* DSP2_ADDR_RAM_1024_38_15_0 - [15:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_15_0_WIDTH 16 /* DSP2_ADDR_RAM_1024_38_15_0 - [15:0] */
+
+/*
+ * R12288 (0x3000) - DSP2 Data1 RAM 1
+ */
+#define WM8962_DSP2_DATA1_RAM_384_24_23_16_MASK 0x00FF /* DSP2_DATA1_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA1_RAM_384_24_23_16_SHIFT 0 /* DSP2_DATA1_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA1_RAM_384_24_23_16_WIDTH 8 /* DSP2_DATA1_RAM_384_24_23_16 - [7:0] */
+
+/*
+ * R12289 (0x3001) - DSP2 Data1 RAM 0
+ */
+#define WM8962_DSP2_DATA1_RAM_384_24_15_0_MASK 0xFFFF /* DSP2_DATA1_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA1_RAM_384_24_15_0_SHIFT 0 /* DSP2_DATA1_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA1_RAM_384_24_15_0_WIDTH 16 /* DSP2_DATA1_RAM_384_24_15_0 - [15:0] */
+
+/*
+ * R13312 (0x3400) - DSP2 Data2 RAM 1
+ */
+#define WM8962_DSP2_DATA2_RAM_384_24_23_16_MASK 0x00FF /* DSP2_DATA2_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA2_RAM_384_24_23_16_SHIFT 0 /* DSP2_DATA2_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA2_RAM_384_24_23_16_WIDTH 8 /* DSP2_DATA2_RAM_384_24_23_16 - [7:0] */
+
+/*
+ * R13313 (0x3401) - DSP2 Data2 RAM 0
+ */
+#define WM8962_DSP2_DATA2_RAM_384_24_15_0_MASK 0xFFFF /* DSP2_DATA2_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA2_RAM_384_24_15_0_SHIFT 0 /* DSP2_DATA2_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA2_RAM_384_24_15_0_WIDTH 16 /* DSP2_DATA2_RAM_384_24_15_0 - [15:0] */
+
+/*
+ * R14336 (0x3800) - DSP2 Data3 RAM 1
+ */
+#define WM8962_DSP2_DATA3_RAM_384_24_23_16_MASK 0x00FF /* DSP2_DATA3_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA3_RAM_384_24_23_16_SHIFT 0 /* DSP2_DATA3_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA3_RAM_384_24_23_16_WIDTH 8 /* DSP2_DATA3_RAM_384_24_23_16 - [7:0] */
+
+/*
+ * R14337 (0x3801) - DSP2 Data3 RAM 0
+ */
+#define WM8962_DSP2_DATA3_RAM_384_24_15_0_MASK 0xFFFF /* DSP2_DATA3_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA3_RAM_384_24_15_0_SHIFT 0 /* DSP2_DATA3_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA3_RAM_384_24_15_0_WIDTH 16 /* DSP2_DATA3_RAM_384_24_15_0 - [15:0] */
+
+/*
+ * R15360 (0x3C00) - DSP2 Coeff RAM 0
+ */
+#define WM8962_DSP2_CMAP_RAM_384_11_10_0_MASK 0x07FF /* DSP2_CMAP_RAM_384_11_10_0 - [10:0] */
+#define WM8962_DSP2_CMAP_RAM_384_11_10_0_SHIFT 0 /* DSP2_CMAP_RAM_384_11_10_0 - [10:0] */
+#define WM8962_DSP2_CMAP_RAM_384_11_10_0_WIDTH 11 /* DSP2_CMAP_RAM_384_11_10_0 - [10:0] */
+
+/*
+ * R16384 (0x4000) - RETUNEADC_SHARED_COEFF_1
+ */
+#define WM8962_ADC_RETUNE_SCV 0x0080 /* ADC_RETUNE_SCV */
+#define WM8962_ADC_RETUNE_SCV_MASK 0x0080 /* ADC_RETUNE_SCV */
+#define WM8962_ADC_RETUNE_SCV_SHIFT 7 /* ADC_RETUNE_SCV */
+#define WM8962_ADC_RETUNE_SCV_WIDTH 1 /* ADC_RETUNE_SCV */
+#define WM8962_RETUNEADC_SHARED_COEFF_22_16_MASK 0x007F /* RETUNEADC_SHARED_COEFF_22_16 - [6:0] */
+#define WM8962_RETUNEADC_SHARED_COEFF_22_16_SHIFT 0 /* RETUNEADC_SHARED_COEFF_22_16 - [6:0] */
+#define WM8962_RETUNEADC_SHARED_COEFF_22_16_WIDTH 7 /* RETUNEADC_SHARED_COEFF_22_16 - [6:0] */
+
+/*
+ * R16385 (0x4001) - RETUNEADC_SHARED_COEFF_0
+ */
+#define WM8962_RETUNEADC_SHARED_COEFF_15_00_MASK 0xFFFF /* RETUNEADC_SHARED_COEFF_15_00 - [15:0] */
+#define WM8962_RETUNEADC_SHARED_COEFF_15_00_SHIFT 0 /* RETUNEADC_SHARED_COEFF_15_00 - [15:0] */
+#define WM8962_RETUNEADC_SHARED_COEFF_15_00_WIDTH 16 /* RETUNEADC_SHARED_COEFF_15_00 - [15:0] */
+
+/*
+ * R16386 (0x4002) - RETUNEDAC_SHARED_COEFF_1
+ */
+#define WM8962_DAC_RETUNE_SCV 0x0080 /* DAC_RETUNE_SCV */
+#define WM8962_DAC_RETUNE_SCV_MASK 0x0080 /* DAC_RETUNE_SCV */
+#define WM8962_DAC_RETUNE_SCV_SHIFT 7 /* DAC_RETUNE_SCV */
+#define WM8962_DAC_RETUNE_SCV_WIDTH 1 /* DAC_RETUNE_SCV */
+#define WM8962_RETUNEDAC_SHARED_COEFF_23_16_MASK 0x007F /* RETUNEDAC_SHARED_COEFF_23_16 - [6:0] */
+#define WM8962_RETUNEDAC_SHARED_COEFF_23_16_SHIFT 0 /* RETUNEDAC_SHARED_COEFF_23_16 - [6:0] */
+#define WM8962_RETUNEDAC_SHARED_COEFF_23_16_WIDTH 7 /* RETUNEDAC_SHARED_COEFF_23_16 - [6:0] */
+
+/*
+ * R16387 (0x4003) - RETUNEDAC_SHARED_COEFF_0
+ */
+#define WM8962_RETUNEDAC_SHARED_COEFF_15_00_MASK 0xFFFF /* RETUNEDAC_SHARED_COEFF_15_00 - [15:0] */
+#define WM8962_RETUNEDAC_SHARED_COEFF_15_00_SHIFT 0 /* RETUNEDAC_SHARED_COEFF_15_00 - [15:0] */
+#define WM8962_RETUNEDAC_SHARED_COEFF_15_00_WIDTH 16 /* RETUNEDAC_SHARED_COEFF_15_00 - [15:0] */
+
+/*
+ * R16388 (0x4004) - SOUNDSTAGE_ENABLES_1
+ */
+#define WM8962_SOUNDSTAGE_ENABLES_23_16_MASK 0x00FF /* SOUNDSTAGE_ENABLES_23_16 - [7:0] */
+#define WM8962_SOUNDSTAGE_ENABLES_23_16_SHIFT 0 /* SOUNDSTAGE_ENABLES_23_16 - [7:0] */
+#define WM8962_SOUNDSTAGE_ENABLES_23_16_WIDTH 8 /* SOUNDSTAGE_ENABLES_23_16 - [7:0] */
+
+/*
+ * R16389 (0x4005) - SOUNDSTAGE_ENABLES_0
+ */
+#define WM8962_SOUNDSTAGE_ENABLES_15_06_MASK 0xFFC0 /* SOUNDSTAGE_ENABLES_15_06 - [15:6] */
+#define WM8962_SOUNDSTAGE_ENABLES_15_06_SHIFT 6 /* SOUNDSTAGE_ENABLES_15_06 - [15:6] */
+#define WM8962_SOUNDSTAGE_ENABLES_15_06_WIDTH 10 /* SOUNDSTAGE_ENABLES_15_06 - [15:6] */
+#define WM8962_RTN_ADC_ENA 0x0020 /* RTN_ADC_ENA */
+#define WM8962_RTN_ADC_ENA_MASK 0x0020 /* RTN_ADC_ENA */
+#define WM8962_RTN_ADC_ENA_SHIFT 5 /* RTN_ADC_ENA */
+#define WM8962_RTN_ADC_ENA_WIDTH 1 /* RTN_ADC_ENA */
+#define WM8962_RTN_DAC_ENA 0x0010 /* RTN_DAC_ENA */
+#define WM8962_RTN_DAC_ENA_MASK 0x0010 /* RTN_DAC_ENA */
+#define WM8962_RTN_DAC_ENA_SHIFT 4 /* RTN_DAC_ENA */
+#define WM8962_RTN_DAC_ENA_WIDTH 1 /* RTN_DAC_ENA */
+#define WM8962_HDBASS_ENA 0x0008 /* HDBASS_ENA */
+#define WM8962_HDBASS_ENA_MASK 0x0008 /* HDBASS_ENA */
+#define WM8962_HDBASS_ENA_SHIFT 3 /* HDBASS_ENA */
+#define WM8962_HDBASS_ENA_WIDTH 1 /* HDBASS_ENA */
+#define WM8962_HPF2_ENA 0x0004 /* HPF2_ENA */
+#define WM8962_HPF2_ENA_MASK 0x0004 /* HPF2_ENA */
+#define WM8962_HPF2_ENA_SHIFT 2 /* HPF2_ENA */
+#define WM8962_HPF2_ENA_WIDTH 1 /* HPF2_ENA */
+#define WM8962_HPF1_ENA 0x0002 /* HPF1_ENA */
+#define WM8962_HPF1_ENA_MASK 0x0002 /* HPF1_ENA */
+#define WM8962_HPF1_ENA_SHIFT 1 /* HPF1_ENA */
+#define WM8962_HPF1_ENA_WIDTH 1 /* HPF1_ENA */
+#define WM8962_VSS_ENA 0x0001 /* VSS_ENA */
+#define WM8962_VSS_ENA_MASK 0x0001 /* VSS_ENA */
+#define WM8962_VSS_ENA_SHIFT 0 /* VSS_ENA */
+#define WM8962_VSS_ENA_WIDTH 1 /* VSS_ENA */
+
+int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
+
+#endif
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index a99620f..63f6dbf 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -30,14 +30,13 @@
#include "wm8971.h"
-#define WM8971_VERSION "0.9"
-
#define WM8971_REG_COUNT 43
static struct workqueue_struct *wm8971_workq = NULL;
/* codec private data */
struct wm8971_priv {
+ enum snd_soc_control_type control_type;
unsigned int sysclk;
};
@@ -492,8 +491,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
u16 iface = snd_soc_read(codec, WM8971_IFACE) & 0x1f3;
u16 srate = snd_soc_read(codec, WM8971_SRATE) & 0x1c0;
@@ -573,8 +571,8 @@
.set_sysclk = wm8971_set_dai_sysclk,
};
-struct snd_soc_dai wm8971_dai = {
- .name = "WM8971",
+static struct snd_soc_dai_driver wm8971_dai = {
+ .name = "wm8971-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -589,7 +587,6 @@
.formats = WM8971_FORMATS,},
.ops = &wm8971_dai_ops,
};
-EXPORT_SYMBOL_GPL(wm8971_dai);
static void wm8971_work(struct work_struct *work)
{
@@ -598,19 +595,14 @@
wm8971_set_bias_level(codec, codec->bias_level);
}
-static int wm8971_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8971_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8971_resume(struct platform_device *pdev)
+static int wm8971_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -639,38 +631,25 @@
return 0;
}
-static int wm8971_init(struct snd_soc_device *socdev,
- enum snd_soc_control_type control)
+static int wm8971_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = socdev->card->codec;
- int reg, ret = 0;
+ struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+ u16 reg;
- codec->name = "WM8971";
- codec->owner = THIS_MODULE;
- codec->set_bias_level = wm8971_set_bias_level;
- codec->dai = &wm8971_dai;
- codec->reg_cache_size = ARRAY_SIZE(wm8971_reg);
- codec->num_dai = 1;
- codec->reg_cache = kmemdup(wm8971_reg, sizeof(wm8971_reg), GFP_KERNEL);
-
- if (codec->reg_cache == NULL)
- return -ENOMEM;
-
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8971->control_type);
if (ret < 0) {
printk(KERN_ERR "wm8971: failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
+ INIT_DELAYED_WORK(&codec->delayed_work, wm8971_work);
+ wm8971_workq = create_workqueue("wm8971");
+ if (wm8971_workq == NULL)
+ return -ENOMEM;
+
wm8971_reset(codec);
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "wm8971: failed to create pcms\n");
- goto err;
- }
-
/* charge output caps - set vmid to 5k for quick power up */
reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e;
snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0);
@@ -704,40 +683,54 @@
wm8971_add_widgets(codec);
return ret;
-
-err:
- kfree(codec->reg_cache);
- return ret;
}
-/* If the i2c layer weren't so broken, we could pass this kind of data
- around */
-static struct snd_soc_device *wm8971_socdev;
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
-
-static int wm8971_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+/* power down chip */
+static int wm8971_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = wm8971_socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ if (wm8971_workq)
+ destroy_workqueue(wm8971_workq);
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8971 = {
+ .probe = wm8971_probe,
+ .remove = wm8971_remove,
+ .suspend = wm8971_suspend,
+ .resume = wm8971_resume,
+ .set_bias_level = wm8971_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8971_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8971_reg,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8971_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8971_priv *wm8971;
int ret;
- i2c_set_clientdata(i2c, codec);
+ wm8971 = kzalloc(sizeof(struct wm8971_priv), GFP_KERNEL);
+ if (wm8971 == NULL)
+ return -ENOMEM;
- codec->control_data = i2c;
+ i2c_set_clientdata(i2c, wm8971);
- ret = wm8971_init(socdev, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8971, &wm8971_dai, 1);
if (ret < 0)
- pr_err("failed to initialise WM8971\n");
-
+ kfree(wm8971);
return ret;
}
-static int wm8971_i2c_remove(struct i2c_client *client)
+static __devexit int wm8971_i2c_remove(struct i2c_client *client)
{
- struct snd_soc_codec *codec = i2c_get_clientdata(client);
- kfree(codec->reg_cache);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -749,148 +742,34 @@
static struct i2c_driver wm8971_i2c_driver = {
.driver = {
- .name = "WM8971 I2C Codec",
+ .name = "wm8971-codec",
.owner = THIS_MODULE,
},
- .probe = wm8971_i2c_probe,
- .remove = wm8971_i2c_remove,
+ .probe = wm8971_i2c_probe,
+ .remove = __devexit_p(wm8971_i2c_remove),
.id_table = wm8971_i2c_id,
};
-
-static int wm8971_add_i2c_device(struct platform_device *pdev,
- const struct wm8971_setup_data *setup)
-{
- struct i2c_board_info info;
- struct i2c_adapter *adapter;
- struct i2c_client *client;
- int ret;
-
- ret = i2c_add_driver(&wm8971_i2c_driver);
- if (ret != 0) {
- dev_err(&pdev->dev, "can't add i2c driver\n");
- return ret;
- }
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = setup->i2c_address;
- strlcpy(info.type, "wm8971", I2C_NAME_SIZE);
-
- adapter = i2c_get_adapter(setup->i2c_bus);
- if (!adapter) {
- dev_err(&pdev->dev, "can't get i2c adapter %d\n",
- setup->i2c_bus);
- goto err_driver;
- }
-
- client = i2c_new_device(adapter, &info);
- i2c_put_adapter(adapter);
- if (!client) {
- dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
- (unsigned int)info.addr);
- goto err_driver;
- }
-
- return 0;
-
-err_driver:
- i2c_del_driver(&wm8971_i2c_driver);
- return -ENODEV;
-}
-
#endif
-static int wm8971_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct wm8971_setup_data *setup;
- struct snd_soc_codec *codec;
- struct wm8971_priv *wm8971;
- int ret = 0;
-
- pr_info("WM8971 Audio Codec %s", WM8971_VERSION);
-
- setup = socdev->codec_data;
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
-
- wm8971 = kzalloc(sizeof(struct wm8971_priv), GFP_KERNEL);
- if (wm8971 == NULL) {
- kfree(codec);
- return -ENOMEM;
- }
-
- snd_soc_codec_set_drvdata(codec, wm8971);
- socdev->card->codec = codec;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
- wm8971_socdev = socdev;
-
- INIT_DELAYED_WORK(&codec->delayed_work, wm8971_work);
- wm8971_workq = create_workqueue("wm8971");
- if (wm8971_workq == NULL) {
- kfree(snd_soc_codec_get_drvdata(codec));
- kfree(codec);
- return -ENOMEM;
- }
-
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
- if (setup->i2c_address) {
- ret = wm8971_add_i2c_device(pdev, setup);
- }
-#endif
- /* Add other interfaces here */
-
- if (ret != 0) {
- destroy_workqueue(wm8971_workq);
- kfree(snd_soc_codec_get_drvdata(codec));
- kfree(codec);
- }
-
- return ret;
-}
-
-/* power down chip */
-static int wm8971_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec->control_data)
- wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
- if (wm8971_workq)
- destroy_workqueue(wm8971_workq);
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
- i2c_unregister_device(codec->control_data);
- i2c_del_driver(&wm8971_i2c_driver);
-#endif
- kfree(snd_soc_codec_get_drvdata(codec));
- kfree(codec);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8971 = {
- .probe = wm8971_probe,
- .remove = wm8971_remove,
- .suspend = wm8971_suspend,
- .resume = wm8971_resume,
-};
-
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8971);
-
static int __init wm8971_modinit(void)
{
- return snd_soc_register_dai(&wm8971_dai);
+ int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8971_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register WM8971 I2C driver: %d\n",
+ ret);
+ }
+#endif
+ return ret;
}
module_init(wm8971_modinit);
static void __exit wm8971_exit(void)
{
- snd_soc_unregister_dai(&wm8971_dai);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&wm8971_i2c_driver);
+#endif
}
module_exit(wm8971_exit);
diff --git a/sound/soc/codecs/wm8971.h b/sound/soc/codecs/wm8971.h
index ef4f08f..f31c38f 100644
--- a/sound/soc/codecs/wm8971.h
+++ b/sound/soc/codecs/wm8971.h
@@ -53,12 +53,4 @@
#define WM8971_SYSCLK 0
-struct wm8971_setup_data {
- int i2c_bus;
- unsigned short i2c_address;
-};
-
-extern struct snd_soc_dai wm8971_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8971;
-
#endif
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index 1468fe1..b4363f6 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -51,12 +51,10 @@
#define WM8974_POWER1_BUFIOEN 0x04
struct wm8974_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
u16 reg_cache[WM8974_CACHEREGNUM];
};
-static struct snd_soc_codec *wm8974_codec;
-
#define wm8974_reset(c) snd_soc_write(c, WM8974_RESET, 0)
static const char *wm8974_companding[] = {"Off", "NC", "u-law", "A-law" };
@@ -566,8 +564,8 @@
.set_pll = wm8974_set_dai_pll,
};
-struct snd_soc_dai wm8974_dai = {
- .name = "WM8974 HiFi",
+static struct snd_soc_dai_driver wm8974_dai = {
+ .name = "wm8974-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -583,21 +581,15 @@
.ops = &wm8974_ops,
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(wm8974_dai);
-static int wm8974_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8974_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8974_resume(struct platform_device *pdev)
+static int wm8974_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -613,156 +605,72 @@
return 0;
}
-static int wm8974_probe(struct platform_device *pdev)
+static int wm8974_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
int ret = 0;
- if (wm8974_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8974_codec;
- codec = wm8974_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C);
if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
}
+ ret = wm8974_reset(codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to issue reset\n");
+ return ret;
+ }
+
+ wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
snd_soc_add_controls(codec, wm8974_snd_controls,
ARRAY_SIZE(wm8974_snd_controls));
wm8974_add_widgets(codec);
return ret;
-
-pcm_err:
- return ret;
}
/* power down chip */
-static int wm8974_remove(struct platform_device *pdev)
+static int wm8974_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
+ wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_wm8974 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm8974 = {
.probe = wm8974_probe,
.remove = wm8974_remove,
.suspend = wm8974_suspend,
.resume = wm8974_resume,
+ .set_bias_level = wm8974_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8974_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8974_reg,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8974);
-static __devinit int wm8974_register(struct wm8974_priv *wm8974)
-{
- int ret;
- struct snd_soc_codec *codec = &wm8974->codec;
-
- if (wm8974_codec) {
- dev_err(codec->dev, "Another WM8974 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8974);
- codec->name = "WM8974";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8974_set_bias_level;
- codec->dai = &wm8974_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = WM8974_CACHEREGNUM;
- codec->reg_cache = &wm8974->reg_cache;
-
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
- }
-
- memcpy(codec->reg_cache, wm8974_reg, sizeof(wm8974_reg));
-
- ret = wm8974_reset(codec);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to issue reset\n");
- goto err;
- }
-
- wm8974_dai.dev = codec->dev;
-
- wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- wm8974_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dai(&wm8974_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
-
- return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- kfree(wm8974);
- return ret;
-}
-
-static __devexit void wm8974_unregister(struct wm8974_priv *wm8974)
-{
- wm8974_set_bias_level(&wm8974->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dai(&wm8974_dai);
- snd_soc_unregister_codec(&wm8974->codec);
- kfree(wm8974);
- wm8974_codec = NULL;
-}
-
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static __devinit int wm8974_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm8974_priv *wm8974;
- struct snd_soc_codec *codec;
+ int ret;
wm8974 = kzalloc(sizeof(struct wm8974_priv), GFP_KERNEL);
if (wm8974 == NULL)
return -ENOMEM;
- codec = &wm8974->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
-
i2c_set_clientdata(i2c, wm8974);
- codec->control_data = i2c;
- codec->dev = &i2c->dev;
-
- return wm8974_register(wm8974);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8974, &wm8974_dai, 1);
+ if (ret < 0)
+ kfree(wm8974);
+ return ret;
}
static __devexit int wm8974_i2c_remove(struct i2c_client *client)
{
- struct wm8974_priv *wm8974 = i2c_get_clientdata(client);
- wm8974_unregister(wm8974);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -774,23 +682,34 @@
static struct i2c_driver wm8974_i2c_driver = {
.driver = {
- .name = "WM8974",
+ .name = "wm8974-codec",
.owner = THIS_MODULE,
},
.probe = wm8974_i2c_probe,
.remove = __devexit_p(wm8974_i2c_remove),
.id_table = wm8974_i2c_id,
};
+#endif
static int __init wm8974_modinit(void)
{
- return i2c_add_driver(&wm8974_i2c_driver);
+ int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8974_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8974 I2C driver: %d\n",
+ ret);
+ }
+#endif
+ return ret;
}
module_init(wm8974_modinit);
static void __exit wm8974_exit(void)
{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&wm8974_i2c_driver);
+#endif
}
module_exit(wm8974_exit);
diff --git a/sound/soc/codecs/wm8974.h b/sound/soc/codecs/wm8974.h
index 896a7f0..3c94e7b 100644
--- a/sound/soc/codecs/wm8974.h
+++ b/sound/soc/codecs/wm8974.h
@@ -83,7 +83,4 @@
#define WM8974_MCLKDIV_8 (6 << 5)
#define WM8974_MCLKDIV_12 (7 << 5)
-extern struct snd_soc_dai wm8974_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8974;
-
#endif
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index 8a1ad77..13b979a 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -31,8 +31,6 @@
#include "wm8978.h"
-static struct snd_soc_codec *wm8978_codec;
-
/* wm8978 register cache. Note that register 0 is not included in the cache. */
static const u16 wm8978_reg[WM8978_CACHEREGNUM] = {
0x0000, 0x0000, 0x0000, 0x0000, /* 0x00...0x03 */
@@ -54,7 +52,8 @@
/* codec private data */
struct wm8978_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
+ void *control_data;
unsigned int f_pllout;
unsigned int f_mclk;
unsigned int f_256fs;
@@ -374,8 +373,8 @@
#define FIXED_PLL_SIZE (1 << 24)
-static void pll_factors(struct wm8978_pll_div *pll_div, unsigned int target,
- unsigned int source)
+static void pll_factors(struct snd_soc_codec *codec,
+ struct wm8978_pll_div *pll_div, unsigned int target, unsigned int source)
{
u64 k_part;
unsigned int k, n_div, n_mod;
@@ -390,7 +389,7 @@
}
if (n_div < 6 || n_div > 12)
- dev_warn(wm8978_codec->dev,
+ dev_warn(codec->dev,
"WM8978 N value exceeds recommended range! N = %u\n",
n_div);
@@ -505,7 +504,7 @@
dev_dbg(codec->dev, "%s: f_MCLK=%uHz, f_PLLOUT=%uHz\n", __func__,
wm8978->f_mclk, wm8978->f_pllout);
- pll_factors(&pll_div, f2, wm8978->f_mclk);
+ pll_factors(codec, &pll_div, f2, wm8978->f_mclk);
dev_dbg(codec->dev, "%s: calculated PLL N=0x%x, K=0x%x, div2=%d\n",
__func__, pll_div.n, pll_div.k, pll_div.div2);
@@ -690,8 +689,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
/* Word length mask = 0x60 */
u16 iface_ctl = snd_soc_read(codec, WM8978_AUDIO_INTERFACE) & ~0x60;
@@ -875,9 +873,8 @@
};
/* Also supports 12kHz */
-struct snd_soc_dai wm8978_dai = {
- .name = "WM8978 HiFi",
- .id = 1,
+static struct snd_soc_dai_driver wm8978_dai = {
+ .name = "wm8978-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -894,13 +891,9 @@
},
.ops = &wm8978_dai_ops,
};
-EXPORT_SYMBOL_GPL(wm8978_dai);
-static int wm8978_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8978_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF);
/* Also switch PLL off */
snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, 0);
@@ -908,10 +901,8 @@
return 0;
}
-static int wm8978_resume(struct platform_device *pdev)
+static int wm8978_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
int i;
u16 *cache = codec->reg_cache;
@@ -933,54 +924,6 @@
return 0;
}
-static int wm8978_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- if (wm8978_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8978_codec;
- codec = wm8978_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- snd_soc_add_controls(codec, wm8978_snd_controls,
- ARRAY_SIZE(wm8978_snd_controls));
- wm8978_add_widgets(codec);
-
-pcm_err:
- return ret;
-}
-
-/* power down chip */
-static int wm8978_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8978 = {
- .probe = wm8978_probe,
- .remove = wm8978_remove,
- .suspend = wm8978_suspend,
- .resume = wm8978_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8978);
-
/*
* These registers contain an "update" bit - bit 8. This means, for example,
* that one can write new DAC digital volume for both channels, but only when
@@ -1000,44 +943,23 @@
WM8978_ROUT2_SPK_CONTROL,
};
-static __devinit int wm8978_register(struct wm8978_priv *wm8978)
+static int wm8978_probe(struct snd_soc_codec *codec)
{
- int ret, i;
- struct snd_soc_codec *codec = &wm8978->codec;
-
- if (wm8978_codec) {
- dev_err(codec->dev, "Another WM8978 is registered\n");
- return -EINVAL;
- }
+ struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0, i;
/*
* Set default system clock to PLL, it is more precise, this is also the
* default hardware setting
*/
wm8978->sysclk = WM8978_PLL;
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8978);
- codec->name = "WM8978";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8978_set_bias_level;
- codec->dai = &wm8978_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = WM8978_CACHEREGNUM;
- codec->reg_cache = &wm8978->reg_cache;
-
+ codec->control_data = wm8978->control_data;
ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
- memcpy(codec->reg_cache, wm8978_reg, sizeof(wm8978_reg));
-
/*
* Set the update bit in all registers, that have one. This way all
* writes to those registers will also cause the update bit to be
@@ -1050,74 +972,61 @@
ret = snd_soc_write(codec, WM8978_RESET, 0);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
- goto err;
+ return ret;
}
- wm8978_dai.dev = codec->dev;
-
wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- wm8978_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dai(&wm8978_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
+ snd_soc_add_controls(codec, wm8978_snd_controls,
+ ARRAY_SIZE(wm8978_snd_controls));
+ wm8978_add_widgets(codec);
return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- return ret;
}
-static __devexit void wm8978_unregister(struct wm8978_priv *wm8978)
+/* power down chip */
+static int wm8978_remove(struct snd_soc_codec *codec)
{
- wm8978_set_bias_level(&wm8978->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dai(&wm8978_dai);
- snd_soc_unregister_codec(&wm8978->codec);
- wm8978_codec = NULL;
+ wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_wm8978 = {
+ .probe = wm8978_probe,
+ .remove = wm8978_remove,
+ .suspend = wm8978_suspend,
+ .resume = wm8978_resume,
+ .set_bias_level = wm8978_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8978_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8978_reg,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static __devinit int wm8978_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
- int ret;
struct wm8978_priv *wm8978;
- struct snd_soc_codec *codec;
+ int ret;
wm8978 = kzalloc(sizeof(struct wm8978_priv), GFP_KERNEL);
if (wm8978 == NULL)
return -ENOMEM;
- codec = &wm8978->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
-
i2c_set_clientdata(i2c, wm8978);
- codec->control_data = i2c;
+ wm8978->control_data = i2c;
- codec->dev = &i2c->dev;
-
- ret = wm8978_register(wm8978);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8978, &wm8978_dai, 1);
if (ret < 0)
kfree(wm8978);
-
return ret;
}
static __devexit int wm8978_i2c_remove(struct i2c_client *client)
{
- struct wm8978_priv *wm8978 = i2c_get_clientdata(client);
- wm8978_unregister(wm8978);
- kfree(wm8978);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -1129,23 +1038,34 @@
static struct i2c_driver wm8978_i2c_driver = {
.driver = {
- .name = "WM8978",
+ .name = "wm8978",
.owner = THIS_MODULE,
},
.probe = wm8978_i2c_probe,
.remove = __devexit_p(wm8978_i2c_remove),
.id_table = wm8978_i2c_id,
};
+#endif
static int __init wm8978_modinit(void)
{
- return i2c_add_driver(&wm8978_i2c_driver);
+ int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8978_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register WM8978 I2C driver: %d\n",
+ ret);
+ }
+#endif
+ return ret;
}
module_init(wm8978_modinit);
static void __exit wm8978_exit(void)
{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&wm8978_i2c_driver);
+#endif
}
module_exit(wm8978_exit);
diff --git a/sound/soc/codecs/wm8978.h b/sound/soc/codecs/wm8978.h
index 56ec832..c75525b 100644
--- a/sound/soc/codecs/wm8978.h
+++ b/sound/soc/codecs/wm8978.h
@@ -80,7 +80,4 @@
WM8978_MCLK
};
-extern struct snd_soc_dai wm8978_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8978;
-
#endif /* __WM8978_H__ */
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c
new file mode 100644
index 0000000..fd2e7cc
--- /dev/null
+++ b/sound/soc/codecs/wm8985.c
@@ -0,0 +1,1192 @@
+/*
+ * wm8985.c -- WM8985 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *
+ * 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.
+ *
+ * TODO:
+ * o Add OUT3/OUT4 mixer controls.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8985.h"
+
+#define WM8985_NUM_SUPPLIES 4
+static const char *wm8985_supply_names[WM8985_NUM_SUPPLIES] = {
+ "DCVDD",
+ "DBVDD",
+ "AVDD1",
+ "AVDD2"
+};
+
+static const u16 wm8985_reg_defs[] = {
+ 0x0000, /* R0 - Software Reset */
+ 0x0000, /* R1 - Power management 1 */
+ 0x0000, /* R2 - Power management 2 */
+ 0x0000, /* R3 - Power management 3 */
+ 0x0050, /* R4 - Audio Interface */
+ 0x0000, /* R5 - Companding control */
+ 0x0140, /* R6 - Clock Gen control */
+ 0x0000, /* R7 - Additional control */
+ 0x0000, /* R8 - GPIO Control */
+ 0x0000, /* R9 - Jack Detect Control 1 */
+ 0x0000, /* R10 - DAC Control */
+ 0x00FF, /* R11 - Left DAC digital Vol */
+ 0x00FF, /* R12 - Right DAC digital vol */
+ 0x0000, /* R13 - Jack Detect Control 2 */
+ 0x0100, /* R14 - ADC Control */
+ 0x00FF, /* R15 - Left ADC Digital Vol */
+ 0x00FF, /* R16 - Right ADC Digital Vol */
+ 0x0000, /* R17 */
+ 0x012C, /* R18 - EQ1 - low shelf */
+ 0x002C, /* R19 - EQ2 - peak 1 */
+ 0x002C, /* R20 - EQ3 - peak 2 */
+ 0x002C, /* R21 - EQ4 - peak 3 */
+ 0x002C, /* R22 - EQ5 - high shelf */
+ 0x0000, /* R23 */
+ 0x0032, /* R24 - DAC Limiter 1 */
+ 0x0000, /* R25 - DAC Limiter 2 */
+ 0x0000, /* R26 */
+ 0x0000, /* R27 - Notch Filter 1 */
+ 0x0000, /* R28 - Notch Filter 2 */
+ 0x0000, /* R29 - Notch Filter 3 */
+ 0x0000, /* R30 - Notch Filter 4 */
+ 0x0000, /* R31 */
+ 0x0038, /* R32 - ALC control 1 */
+ 0x000B, /* R33 - ALC control 2 */
+ 0x0032, /* R34 - ALC control 3 */
+ 0x0000, /* R35 - Noise Gate */
+ 0x0008, /* R36 - PLL N */
+ 0x000C, /* R37 - PLL K 1 */
+ 0x0093, /* R38 - PLL K 2 */
+ 0x00E9, /* R39 - PLL K 3 */
+ 0x0000, /* R40 */
+ 0x0000, /* R41 - 3D control */
+ 0x0000, /* R42 - OUT4 to ADC */
+ 0x0000, /* R43 - Beep control */
+ 0x0033, /* R44 - Input ctrl */
+ 0x0010, /* R45 - Left INP PGA gain ctrl */
+ 0x0010, /* R46 - Right INP PGA gain ctrl */
+ 0x0100, /* R47 - Left ADC BOOST ctrl */
+ 0x0100, /* R48 - Right ADC BOOST ctrl */
+ 0x0002, /* R49 - Output ctrl */
+ 0x0001, /* R50 - Left mixer ctrl */
+ 0x0001, /* R51 - Right mixer ctrl */
+ 0x0039, /* R52 - LOUT1 (HP) volume ctrl */
+ 0x0039, /* R53 - ROUT1 (HP) volume ctrl */
+ 0x0039, /* R54 - LOUT2 (SPK) volume ctrl */
+ 0x0039, /* R55 - ROUT2 (SPK) volume ctrl */
+ 0x0001, /* R56 - OUT3 mixer ctrl */
+ 0x0001, /* R57 - OUT4 (MONO) mix ctrl */
+ 0x0001, /* R58 */
+ 0x0000, /* R59 */
+ 0x0004, /* R60 - OUTPUT ctrl */
+ 0x0000, /* R61 - BIAS CTRL */
+ 0x0180, /* R62 */
+ 0x0000 /* R63 */
+};
+
+/*
+ * latch bit 8 of these registers to ensure instant
+ * volume updates
+ */
+static const int volume_update_regs[] = {
+ WM8985_LEFT_DAC_DIGITAL_VOL,
+ WM8985_RIGHT_DAC_DIGITAL_VOL,
+ WM8985_LEFT_ADC_DIGITAL_VOL,
+ WM8985_RIGHT_ADC_DIGITAL_VOL,
+ WM8985_LOUT2_SPK_VOLUME_CTRL,
+ WM8985_ROUT2_SPK_VOLUME_CTRL,
+ WM8985_LOUT1_HP_VOLUME_CTRL,
+ WM8985_ROUT1_HP_VOLUME_CTRL,
+ WM8985_LEFT_INP_PGA_GAIN_CTRL,
+ WM8985_RIGHT_INP_PGA_GAIN_CTRL
+};
+
+struct wm8985_priv {
+ enum snd_soc_control_type control_type;
+ struct regulator_bulk_data supplies[WM8985_NUM_SUPPLIES];
+ unsigned int sysclk;
+ unsigned int bclk;
+};
+
+static const struct {
+ int div;
+ int ratio;
+} fs_ratios[] = {
+ { 10, 128 },
+ { 15, 192 },
+ { 20, 256 },
+ { 30, 384 },
+ { 40, 512 },
+ { 60, 768 },
+ { 80, 1024 },
+ { 120, 1536 }
+};
+
+static const int srates[] = { 48000, 32000, 24000, 16000, 12000, 8000 };
+
+static const int bclk_divs[] = {
+ 1, 2, 4, 8, 16, 32
+};
+
+static int eqmode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+static int eqmode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1);
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -12700, 50, 1);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
+static const DECLARE_TLV_DB_SCALE(lim_thresh_tlv, -600, 100, 0);
+static const DECLARE_TLV_DB_SCALE(lim_boost_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(alc_min_tlv, -1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(alc_max_tlv, -675, 600, 0);
+static const DECLARE_TLV_DB_SCALE(alc_tar_tlv, -2250, 150, 0);
+static const DECLARE_TLV_DB_SCALE(pga_vol_tlv, -1200, 75, 0);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, -1200, 300, 1);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(aux_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0);
+
+static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" };
+static const SOC_ENUM_SINGLE_DECL(alc_sel, WM8985_ALC_CONTROL_1, 7,
+ alc_sel_text);
+
+static const char *alc_mode_text[] = { "ALC", "Limiter" };
+static const SOC_ENUM_SINGLE_DECL(alc_mode, WM8985_ALC_CONTROL_3, 8,
+ alc_mode_text);
+
+static const char *filter_mode_text[] = { "Audio", "Application" };
+static const SOC_ENUM_SINGLE_DECL(filter_mode, WM8985_ADC_CONTROL, 7,
+ filter_mode_text);
+
+static const char *eq_bw_text[] = { "Narrow", "Wide" };
+static const char *eqmode_text[] = { "Capture", "Playback" };
+static const SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text);
+
+static const char *eq1_cutoff_text[] = {
+ "80Hz", "105Hz", "135Hz", "175Hz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8985_EQ1_LOW_SHELF, 5,
+ eq1_cutoff_text);
+static const char *eq2_cutoff_text[] = {
+ "230Hz", "300Hz", "385Hz", "500Hz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq2_bw, WM8985_EQ2_PEAK_1, 8, eq_bw_text);
+static const SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8985_EQ2_PEAK_1, 5,
+ eq2_cutoff_text);
+static const char *eq3_cutoff_text[] = {
+ "650Hz", "850Hz", "1.1kHz", "1.4kHz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq3_bw, WM8985_EQ3_PEAK_2, 8, eq_bw_text);
+static const SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8985_EQ3_PEAK_2, 5,
+ eq3_cutoff_text);
+static const char *eq4_cutoff_text[] = {
+ "1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq4_bw, WM8985_EQ4_PEAK_3, 8, eq_bw_text);
+static const SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8985_EQ4_PEAK_3, 5,
+ eq4_cutoff_text);
+static const char *eq5_cutoff_text[] = {
+ "5.3kHz", "6.9kHz", "9kHz", "11.7kHz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8985_EQ5_HIGH_SHELF, 5,
+ eq5_cutoff_text);
+
+static const char *speaker_mode_text[] = { "Class A/B", "Class D" };
+static const SOC_ENUM_SINGLE_DECL(speaker_mode, 0x17, 8, speaker_mode_text);
+
+static const char *depth_3d_text[] = {
+ "Off",
+ "6.67%",
+ "13.3%",
+ "20%",
+ "26.7%",
+ "33.3%",
+ "40%",
+ "46.6%",
+ "53.3%",
+ "60%",
+ "66.7%",
+ "73.3%",
+ "80%",
+ "86.7%",
+ "93.3%",
+ "100%"
+};
+static const SOC_ENUM_SINGLE_DECL(depth_3d, WM8985_3D_CONTROL, 0,
+ depth_3d_text);
+
+static const struct snd_kcontrol_new wm8985_snd_controls[] = {
+ SOC_SINGLE("Digital Loopback Switch", WM8985_COMPANDING_CONTROL,
+ 0, 1, 0),
+
+ SOC_ENUM("ALC Capture Function", alc_sel),
+ SOC_SINGLE_TLV("ALC Capture Max Volume", WM8985_ALC_CONTROL_1,
+ 3, 7, 0, alc_max_tlv),
+ SOC_SINGLE_TLV("ALC Capture Min Volume", WM8985_ALC_CONTROL_1,
+ 0, 7, 0, alc_min_tlv),
+ SOC_SINGLE_TLV("ALC Capture Target Volume", WM8985_ALC_CONTROL_2,
+ 0, 15, 0, alc_tar_tlv),
+ SOC_SINGLE("ALC Capture Attack", WM8985_ALC_CONTROL_3, 0, 10, 0),
+ SOC_SINGLE("ALC Capture Hold", WM8985_ALC_CONTROL_2, 4, 10, 0),
+ SOC_SINGLE("ALC Capture Decay", WM8985_ALC_CONTROL_3, 4, 10, 0),
+ SOC_ENUM("ALC Mode", alc_mode),
+ SOC_SINGLE("ALC Capture NG Switch", WM8985_NOISE_GATE,
+ 3, 1, 0),
+ SOC_SINGLE("ALC Capture NG Threshold", WM8985_NOISE_GATE,
+ 0, 7, 1),
+
+ SOC_DOUBLE_R_TLV("Capture Volume", WM8985_LEFT_ADC_DIGITAL_VOL,
+ WM8985_RIGHT_ADC_DIGITAL_VOL, 0, 255, 0, adc_tlv),
+ SOC_DOUBLE_R("Capture PGA ZC Switch", WM8985_LEFT_INP_PGA_GAIN_CTRL,
+ WM8985_RIGHT_INP_PGA_GAIN_CTRL, 7, 1, 0),
+ SOC_DOUBLE_R_TLV("Capture PGA Volume", WM8985_LEFT_INP_PGA_GAIN_CTRL,
+ WM8985_RIGHT_INP_PGA_GAIN_CTRL, 0, 63, 0, pga_vol_tlv),
+
+ SOC_DOUBLE_R_TLV("Capture PGA Boost Volume",
+ WM8985_LEFT_ADC_BOOST_CTRL, WM8985_RIGHT_ADC_BOOST_CTRL,
+ 8, 1, 0, pga_boost_tlv),
+
+ SOC_DOUBLE("ADC Inversion Switch", WM8985_ADC_CONTROL, 0, 1, 1, 0),
+ SOC_SINGLE("ADC 128x Oversampling Switch", WM8985_ADC_CONTROL, 8, 1, 0),
+
+ SOC_DOUBLE_R_TLV("Playback Volume", WM8985_LEFT_DAC_DIGITAL_VOL,
+ WM8985_RIGHT_DAC_DIGITAL_VOL, 0, 255, 0, dac_tlv),
+
+ SOC_SINGLE("DAC Playback Limiter Switch", WM8985_DAC_LIMITER_1, 8, 1, 0),
+ SOC_SINGLE("DAC Playback Limiter Decay", WM8985_DAC_LIMITER_1, 4, 10, 0),
+ SOC_SINGLE("DAC Playback Limiter Attack", WM8985_DAC_LIMITER_1, 0, 11, 0),
+ SOC_SINGLE_TLV("DAC Playback Limiter Threshold", WM8985_DAC_LIMITER_2,
+ 4, 7, 1, lim_thresh_tlv),
+ SOC_SINGLE_TLV("DAC Playback Limiter Boost Volume", WM8985_DAC_LIMITER_2,
+ 0, 12, 0, lim_boost_tlv),
+ SOC_DOUBLE("DAC Inversion Switch", WM8985_DAC_CONTROL, 0, 1, 1, 0),
+ SOC_SINGLE("DAC Auto Mute Switch", WM8985_DAC_CONTROL, 2, 1, 0),
+ SOC_SINGLE("DAC 128x Oversampling Switch", WM8985_DAC_CONTROL, 3, 1, 0),
+
+ SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8985_LOUT1_HP_VOLUME_CTRL,
+ WM8985_ROUT1_HP_VOLUME_CTRL, 0, 63, 0, out_tlv),
+ SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8985_LOUT1_HP_VOLUME_CTRL,
+ WM8985_ROUT1_HP_VOLUME_CTRL, 7, 1, 0),
+ SOC_DOUBLE_R("Headphone Switch", WM8985_LOUT1_HP_VOLUME_CTRL,
+ WM8985_ROUT1_HP_VOLUME_CTRL, 6, 1, 1),
+
+ SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8985_LOUT2_SPK_VOLUME_CTRL,
+ WM8985_ROUT2_SPK_VOLUME_CTRL, 0, 63, 0, out_tlv),
+ SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8985_LOUT2_SPK_VOLUME_CTRL,
+ WM8985_ROUT2_SPK_VOLUME_CTRL, 7, 1, 0),
+ SOC_DOUBLE_R("Speaker Switch", WM8985_LOUT2_SPK_VOLUME_CTRL,
+ WM8985_ROUT2_SPK_VOLUME_CTRL, 6, 1, 1),
+
+ SOC_SINGLE("High Pass Filter Switch", WM8985_ADC_CONTROL, 8, 1, 0),
+ SOC_ENUM("High Pass Filter Mode", filter_mode),
+ SOC_SINGLE("High Pass Filter Cutoff", WM8985_ADC_CONTROL, 4, 7, 0),
+
+ SOC_DOUBLE_R_TLV("Aux Bypass Volume",
+ WM8985_LEFT_MIXER_CTRL, WM8985_RIGHT_MIXER_CTRL, 6, 7, 0,
+ aux_tlv),
+
+ SOC_DOUBLE_R_TLV("Input PGA Bypass Volume",
+ WM8985_LEFT_MIXER_CTRL, WM8985_RIGHT_MIXER_CTRL, 2, 7, 0,
+ bypass_tlv),
+
+ SOC_ENUM_EXT("Equalizer Function", eqmode, eqmode_get, eqmode_put),
+ SOC_ENUM("EQ1 Cutoff", eq1_cutoff),
+ SOC_SINGLE_TLV("EQ1 Volume", WM8985_EQ1_LOW_SHELF, 0, 24, 1, eq_tlv),
+ SOC_ENUM("EQ2 Bandwith", eq2_bw),
+ SOC_ENUM("EQ2 Cutoff", eq2_cutoff),
+ SOC_SINGLE_TLV("EQ2 Volume", WM8985_EQ2_PEAK_1, 0, 24, 1, eq_tlv),
+ SOC_ENUM("EQ3 Bandwith", eq3_bw),
+ SOC_ENUM("EQ3 Cutoff", eq3_cutoff),
+ SOC_SINGLE_TLV("EQ3 Volume", WM8985_EQ3_PEAK_2, 0, 24, 1, eq_tlv),
+ SOC_ENUM("EQ4 Bandwith", eq4_bw),
+ SOC_ENUM("EQ4 Cutoff", eq4_cutoff),
+ SOC_SINGLE_TLV("EQ4 Volume", WM8985_EQ4_PEAK_3, 0, 24, 1, eq_tlv),
+ SOC_ENUM("EQ5 Cutoff", eq5_cutoff),
+ SOC_SINGLE_TLV("EQ5 Volume", WM8985_EQ5_HIGH_SHELF, 0, 24, 1, eq_tlv),
+
+ SOC_ENUM("3D Depth", depth_3d),
+
+ SOC_ENUM("Speaker Mode", speaker_mode)
+};
+
+static const struct snd_kcontrol_new left_out_mixer[] = {
+ SOC_DAPM_SINGLE("Line Switch", WM8985_LEFT_MIXER_CTRL, 1, 1, 0),
+ SOC_DAPM_SINGLE("Aux Switch", WM8985_LEFT_MIXER_CTRL, 5, 1, 0),
+ SOC_DAPM_SINGLE("PCM Switch", WM8985_LEFT_MIXER_CTRL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_out_mixer[] = {
+ SOC_DAPM_SINGLE("Line Switch", WM8985_RIGHT_MIXER_CTRL, 1, 1, 0),
+ SOC_DAPM_SINGLE("Aux Switch", WM8985_RIGHT_MIXER_CTRL, 5, 1, 0),
+ SOC_DAPM_SINGLE("PCM Switch", WM8985_RIGHT_MIXER_CTRL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_input_mixer[] = {
+ SOC_DAPM_SINGLE("L2 Switch", WM8985_INPUT_CTRL, 2, 1, 0),
+ SOC_DAPM_SINGLE("MicN Switch", WM8985_INPUT_CTRL, 1, 1, 0),
+ SOC_DAPM_SINGLE("MicP Switch", WM8985_INPUT_CTRL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_input_mixer[] = {
+ SOC_DAPM_SINGLE("R2 Switch", WM8985_INPUT_CTRL, 6, 1, 0),
+ SOC_DAPM_SINGLE("MicN Switch", WM8985_INPUT_CTRL, 5, 1, 0),
+ SOC_DAPM_SINGLE("MicP Switch", WM8985_INPUT_CTRL, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_boost_mixer[] = {
+ SOC_DAPM_SINGLE_TLV("L2 Volume", WM8985_LEFT_ADC_BOOST_CTRL,
+ 4, 7, 0, boost_tlv),
+ SOC_DAPM_SINGLE_TLV("AUXL Volume", WM8985_LEFT_ADC_BOOST_CTRL,
+ 0, 7, 0, boost_tlv)
+};
+
+static const struct snd_kcontrol_new right_boost_mixer[] = {
+ SOC_DAPM_SINGLE_TLV("R2 Volume", WM8985_RIGHT_ADC_BOOST_CTRL,
+ 4, 7, 0, boost_tlv),
+ SOC_DAPM_SINGLE_TLV("AUXR Volume", WM8985_RIGHT_ADC_BOOST_CTRL,
+ 0, 7, 0, boost_tlv)
+};
+
+static const struct snd_soc_dapm_widget wm8985_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8985_POWER_MANAGEMENT_3,
+ 0, 0),
+ SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8985_POWER_MANAGEMENT_3,
+ 1, 0),
+ SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8985_POWER_MANAGEMENT_2,
+ 0, 0),
+ SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8985_POWER_MANAGEMENT_2,
+ 1, 0),
+
+ SND_SOC_DAPM_MIXER("Left Output Mixer", WM8985_POWER_MANAGEMENT_3,
+ 2, 0, left_out_mixer, ARRAY_SIZE(left_out_mixer)),
+ SND_SOC_DAPM_MIXER("Right Output Mixer", WM8985_POWER_MANAGEMENT_3,
+ 3, 0, right_out_mixer, ARRAY_SIZE(right_out_mixer)),
+
+ SND_SOC_DAPM_MIXER("Left Input Mixer", WM8985_POWER_MANAGEMENT_2,
+ 2, 0, left_input_mixer, ARRAY_SIZE(left_input_mixer)),
+ SND_SOC_DAPM_MIXER("Right Input Mixer", WM8985_POWER_MANAGEMENT_2,
+ 3, 0, right_input_mixer, ARRAY_SIZE(right_input_mixer)),
+
+ SND_SOC_DAPM_MIXER("Left Boost Mixer", WM8985_POWER_MANAGEMENT_2,
+ 4, 0, left_boost_mixer, ARRAY_SIZE(left_boost_mixer)),
+ SND_SOC_DAPM_MIXER("Right Boost Mixer", WM8985_POWER_MANAGEMENT_2,
+ 5, 0, right_boost_mixer, ARRAY_SIZE(right_boost_mixer)),
+
+ SND_SOC_DAPM_PGA("Left Capture PGA", WM8985_LEFT_INP_PGA_GAIN_CTRL,
+ 6, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("Right Capture PGA", WM8985_RIGHT_INP_PGA_GAIN_CTRL,
+ 6, 1, NULL, 0),
+
+ SND_SOC_DAPM_PGA("Left Headphone Out", WM8985_POWER_MANAGEMENT_2,
+ 7, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Right Headphone Out", WM8985_POWER_MANAGEMENT_2,
+ 8, 0, NULL, 0),
+
+ SND_SOC_DAPM_PGA("Left Speaker Out", WM8985_POWER_MANAGEMENT_3,
+ 5, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Right Speaker Out", WM8985_POWER_MANAGEMENT_3,
+ 6, 0, NULL, 0),
+
+ SND_SOC_DAPM_MICBIAS("Mic Bias", WM8985_POWER_MANAGEMENT_1, 4, 0),
+
+ SND_SOC_DAPM_INPUT("LIN"),
+ SND_SOC_DAPM_INPUT("LIP"),
+ SND_SOC_DAPM_INPUT("RIN"),
+ SND_SOC_DAPM_INPUT("RIP"),
+ SND_SOC_DAPM_INPUT("AUXL"),
+ SND_SOC_DAPM_INPUT("AUXR"),
+ SND_SOC_DAPM_INPUT("L2"),
+ SND_SOC_DAPM_INPUT("R2"),
+ SND_SOC_DAPM_OUTPUT("HPL"),
+ SND_SOC_DAPM_OUTPUT("HPR"),
+ SND_SOC_DAPM_OUTPUT("SPKL"),
+ SND_SOC_DAPM_OUTPUT("SPKR")
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ { "Right Output Mixer", "PCM Switch", "Right DAC" },
+ { "Right Output Mixer", "Aux Switch", "AUXR" },
+ { "Right Output Mixer", "Line Switch", "Right Boost Mixer" },
+
+ { "Left Output Mixer", "PCM Switch", "Left DAC" },
+ { "Left Output Mixer", "Aux Switch", "AUXL" },
+ { "Left Output Mixer", "Line Switch", "Left Boost Mixer" },
+
+ { "Right Headphone Out", NULL, "Right Output Mixer" },
+ { "HPR", NULL, "Right Headphone Out" },
+
+ { "Left Headphone Out", NULL, "Left Output Mixer" },
+ { "HPL", NULL, "Left Headphone Out" },
+
+ { "Right Speaker Out", NULL, "Right Output Mixer" },
+ { "SPKR", NULL, "Right Speaker Out" },
+
+ { "Left Speaker Out", NULL, "Left Output Mixer" },
+ { "SPKL", NULL, "Left Speaker Out" },
+
+ { "Right ADC", NULL, "Right Boost Mixer" },
+
+ { "Right Boost Mixer", "AUXR Volume", "AUXR" },
+ { "Right Boost Mixer", NULL, "Right Capture PGA" },
+ { "Right Boost Mixer", "R2 Volume", "R2" },
+
+ { "Left ADC", NULL, "Left Boost Mixer" },
+
+ { "Left Boost Mixer", "AUXL Volume", "AUXL" },
+ { "Left Boost Mixer", NULL, "Left Capture PGA" },
+ { "Left Boost Mixer", "L2 Volume", "L2" },
+
+ { "Right Capture PGA", NULL, "Right Input Mixer" },
+ { "Left Capture PGA", NULL, "Left Input Mixer" },
+
+ { "Right Input Mixer", "R2 Switch", "R2" },
+ { "Right Input Mixer", "MicN Switch", "RIN" },
+ { "Right Input Mixer", "MicP Switch", "RIP" },
+
+ { "Left Input Mixer", "L2 Switch", "L2" },
+ { "Left Input Mixer", "MicN Switch", "LIN" },
+ { "Left Input Mixer", "MicP Switch", "LIP" },
+};
+
+static int eqmode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned int reg;
+
+ reg = snd_soc_read(codec, WM8985_EQ1_LOW_SHELF);
+ if (reg & WM8985_EQ3DMODE)
+ ucontrol->value.integer.value[0] = 1;
+ else
+ ucontrol->value.integer.value[0] = 0;
+
+ return 0;
+}
+
+static int eqmode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned int regpwr2, regpwr3;
+ unsigned int reg_eq;
+
+ if (ucontrol->value.integer.value[0] != 0
+ && ucontrol->value.integer.value[0] != 1)
+ return -EINVAL;
+
+ reg_eq = snd_soc_read(codec, WM8985_EQ1_LOW_SHELF);
+ switch ((reg_eq & WM8985_EQ3DMODE) >> WM8985_EQ3DMODE_SHIFT) {
+ case 0:
+ if (!ucontrol->value.integer.value[0])
+ return 0;
+ break;
+ case 1:
+ if (ucontrol->value.integer.value[0])
+ return 0;
+ break;
+ }
+
+ regpwr2 = snd_soc_read(codec, WM8985_POWER_MANAGEMENT_2);
+ regpwr3 = snd_soc_read(codec, WM8985_POWER_MANAGEMENT_3);
+ /* disable the DACs and ADCs */
+ snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_2,
+ WM8985_ADCENR_MASK | WM8985_ADCENL_MASK, 0);
+ snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_3,
+ WM8985_DACENR_MASK | WM8985_DACENL_MASK, 0);
+ snd_soc_update_bits(codec, WM8985_ADDITIONAL_CONTROL,
+ WM8985_M128ENB_MASK, WM8985_M128ENB);
+ /* set the desired eqmode */
+ snd_soc_update_bits(codec, WM8985_EQ1_LOW_SHELF,
+ WM8985_EQ3DMODE_MASK,
+ ucontrol->value.integer.value[0]
+ << WM8985_EQ3DMODE_SHIFT);
+ /* restore DAC/ADC configuration */
+ snd_soc_write(codec, WM8985_POWER_MANAGEMENT_2, regpwr2);
+ snd_soc_write(codec, WM8985_POWER_MANAGEMENT_3, regpwr3);
+ return 0;
+}
+
+static int wm8985_add_widgets(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_new_controls(codec, wm8985_dapm_widgets,
+ ARRAY_SIZE(wm8985_dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, audio_map,
+ ARRAY_SIZE(audio_map));
+ return 0;
+}
+
+static int wm8985_reset(struct snd_soc_codec *codec)
+{
+ return snd_soc_write(codec, WM8985_SOFTWARE_RESET, 0x0);
+}
+
+static int wm8985_dac_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+
+ return snd_soc_update_bits(codec, WM8985_DAC_CONTROL,
+ WM8985_SOFTMUTE_MASK,
+ !!mute << WM8985_SOFTMUTE_SHIFT);
+}
+
+static int wm8985_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec;
+ u16 format, master, bcp, lrp;
+
+ codec = dai->codec;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ format = 0x2;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ format = 0x0;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ format = 0x1;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_DSP_B:
+ format = 0x3;
+ break;
+ default:
+ dev_err(dai->dev, "Unknown dai format\n");
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, WM8985_AUDIO_INTERFACE,
+ WM8985_FMT_MASK, format << WM8985_FMT_SHIFT);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ master = 1;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ master = 0;
+ break;
+ default:
+ dev_err(dai->dev, "Unknown master/slave configuration\n");
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+ WM8985_MS_MASK, master << WM8985_MS_SHIFT);
+
+ /* frame inversion is not valid for dsp modes */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_DSP_B:
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_IB_IF:
+ case SND_SOC_DAIFMT_NB_IF:
+ return -EINVAL;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ bcp = lrp = 0;
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ bcp = lrp = 1;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ bcp = 1;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ lrp = 1;
+ break;
+ default:
+ dev_err(dai->dev, "Unknown polarity configuration\n");
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, WM8985_AUDIO_INTERFACE,
+ WM8985_LRP_MASK, lrp << WM8985_LRP_SHIFT);
+ snd_soc_update_bits(codec, WM8985_AUDIO_INTERFACE,
+ WM8985_BCP_MASK, bcp << WM8985_BCP_SHIFT);
+ return 0;
+}
+
+static int wm8985_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ int i;
+ struct snd_soc_codec *codec;
+ struct wm8985_priv *wm8985;
+ u16 blen, srate_idx;
+ unsigned int tmp;
+ int srate_best;
+
+ codec = dai->codec;
+ wm8985 = snd_soc_codec_get_drvdata(codec);
+
+ wm8985->bclk = snd_soc_params_to_bclk(params);
+ if ((int)wm8985->bclk < 0)
+ return wm8985->bclk;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ blen = 0x0;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ blen = 0x1;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ blen = 0x2;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ blen = 0x3;
+ break;
+ default:
+ dev_err(dai->dev, "Unsupported word length %u\n",
+ params_format(params));
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, WM8985_AUDIO_INTERFACE,
+ WM8985_WL_MASK, blen << WM8985_WL_SHIFT);
+
+ /*
+ * match to the nearest possible sample rate and rely
+ * on the array index to configure the SR register
+ */
+ srate_idx = 0;
+ srate_best = abs(srates[0] - params_rate(params));
+ for (i = 1; i < ARRAY_SIZE(srates); ++i) {
+ if (abs(srates[i] - params_rate(params)) >= srate_best)
+ continue;
+ srate_idx = i;
+ srate_best = abs(srates[i] - params_rate(params));
+ }
+
+ dev_dbg(dai->dev, "Selected SRATE = %d\n", srates[srate_idx]);
+ snd_soc_update_bits(codec, WM8985_ADDITIONAL_CONTROL,
+ WM8985_SR_MASK, srate_idx << WM8985_SR_SHIFT);
+
+ dev_dbg(dai->dev, "Target BCLK = %uHz\n", wm8985->bclk);
+ dev_dbg(dai->dev, "SYSCLK = %uHz\n", wm8985->sysclk);
+
+ for (i = 0; i < ARRAY_SIZE(fs_ratios); ++i) {
+ if (wm8985->sysclk / params_rate(params)
+ == fs_ratios[i].ratio)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(fs_ratios)) {
+ dev_err(dai->dev, "Unable to configure MCLK ratio %u/%u\n",
+ wm8985->sysclk, params_rate(params));
+ return -EINVAL;
+ }
+
+ dev_dbg(dai->dev, "MCLK ratio = %dfs\n", fs_ratios[i].ratio);
+ snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+ WM8985_MCLKDIV_MASK, i << WM8985_MCLKDIV_SHIFT);
+
+ /* select the appropriate bclk divider */
+ tmp = (wm8985->sysclk / fs_ratios[i].div) * 10;
+ for (i = 0; i < ARRAY_SIZE(bclk_divs); ++i) {
+ if (wm8985->bclk == tmp / bclk_divs[i])
+ break;
+ }
+
+ if (i == ARRAY_SIZE(bclk_divs)) {
+ dev_err(dai->dev, "No matching BCLK divider found\n");
+ return -EINVAL;
+ }
+
+ dev_dbg(dai->dev, "BCLK div = %d\n", i);
+ snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+ WM8985_BCLKDIV_MASK, i << WM8985_BCLKDIV_SHIFT);
+ return 0;
+}
+
+struct pll_div {
+ u32 div2:1;
+ u32 n:4;
+ u32 k:24;
+};
+
+#define FIXED_PLL_SIZE ((1ULL << 24) * 10)
+static int pll_factors(struct pll_div *pll_div, unsigned int target,
+ unsigned int source)
+{
+ u64 Kpart;
+ unsigned long int K, Ndiv, Nmod;
+
+ pll_div->div2 = 0;
+ Ndiv = target / source;
+ if (Ndiv < 6) {
+ source >>= 1;
+ pll_div->div2 = 1;
+ Ndiv = target / source;
+ }
+
+ if (Ndiv < 6 || Ndiv > 12) {
+ printk(KERN_ERR "%s: WM8985 N value is not within"
+ " the recommended range: %lu\n", __func__, Ndiv);
+ return -EINVAL;
+ }
+ pll_div->n = Ndiv;
+
+ Nmod = target % source;
+ Kpart = FIXED_PLL_SIZE * (u64)Nmod;
+
+ do_div(Kpart, source);
+
+ K = Kpart & 0xffffffff;
+ if ((K % 10) >= 5)
+ K += 5;
+ K /= 10;
+ pll_div->k = K;
+
+ return 0;
+}
+
+static int wm8985_set_pll(struct snd_soc_dai *dai, int pll_id,
+ int source, unsigned int freq_in,
+ unsigned int freq_out)
+{
+ int ret;
+ struct snd_soc_codec *codec;
+ struct pll_div pll_div;
+
+ codec = dai->codec;
+ if (freq_in && freq_out) {
+ ret = pll_factors(&pll_div, freq_out * 4 * 2, freq_in);
+ if (ret)
+ return ret;
+ }
+
+ /* disable the PLL before reprogramming it */
+ snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+ WM8985_PLLEN_MASK, 0);
+
+ if (!freq_in || !freq_out)
+ return 0;
+
+ /* set PLLN and PRESCALE */
+ snd_soc_write(codec, WM8985_PLL_N,
+ (pll_div.div2 << WM8985_PLL_PRESCALE_SHIFT)
+ | pll_div.n);
+ /* set PLLK */
+ snd_soc_write(codec, WM8985_PLL_K_3, pll_div.k & 0x1ff);
+ snd_soc_write(codec, WM8985_PLL_K_2, (pll_div.k >> 9) & 0x1ff);
+ snd_soc_write(codec, WM8985_PLL_K_1, (pll_div.k >> 18));
+ /* set the source of the clock to be the PLL */
+ snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+ WM8985_CLKSEL_MASK, WM8985_CLKSEL);
+ /* enable the PLL */
+ snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+ WM8985_PLLEN_MASK, WM8985_PLLEN);
+ return 0;
+}
+
+static int wm8985_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec;
+ struct wm8985_priv *wm8985;
+
+ codec = dai->codec;
+ wm8985 = snd_soc_codec_get_drvdata(codec);
+
+ switch (clk_id) {
+ case WM8985_CLKSRC_MCLK:
+ snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+ WM8985_CLKSEL_MASK, 0);
+ snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+ WM8985_PLLEN_MASK, 0);
+ break;
+ case WM8985_CLKSRC_PLL:
+ snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+ WM8985_CLKSEL_MASK, WM8985_CLKSEL);
+ break;
+ default:
+ dev_err(dai->dev, "Unknown clock source %d\n", clk_id);
+ return -EINVAL;
+ }
+
+ wm8985->sysclk = freq;
+ return 0;
+}
+
+static void wm8985_sync_cache(struct snd_soc_codec *codec)
+{
+ short i;
+ u16 *cache;
+
+ if (!codec->cache_sync)
+ return;
+ codec->cache_only = 0;
+ /* restore cache */
+ cache = codec->reg_cache;
+ for (i = 0; i < codec->driver->reg_cache_size; i++) {
+ if (i == WM8985_SOFTWARE_RESET
+ || cache[i] == wm8985_reg_defs[i])
+ continue;
+ snd_soc_write(codec, i, cache[i]);
+ }
+ codec->cache_sync = 0;
+}
+
+static int wm8985_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ int ret;
+ struct wm8985_priv *wm8985;
+
+ wm8985 = snd_soc_codec_get_drvdata(codec);
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ case SND_SOC_BIAS_PREPARE:
+ /* VMID at 75k */
+ snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+ WM8985_VMIDSEL_MASK,
+ 1 << WM8985_VMIDSEL_SHIFT);
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->bias_level == SND_SOC_BIAS_OFF) {
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8985->supplies),
+ wm8985->supplies);
+ if (ret) {
+ dev_err(codec->dev,
+ "Failed to enable supplies: %d\n",
+ ret);
+ return ret;
+ }
+
+ wm8985_sync_cache(codec);
+
+ /* enable anti-pop features */
+ snd_soc_update_bits(codec, WM8985_OUT4_TO_ADC,
+ WM8985_POBCTRL_MASK,
+ WM8985_POBCTRL);
+ /* enable thermal shutdown */
+ snd_soc_update_bits(codec, WM8985_OUTPUT_CTRL0,
+ WM8985_TSDEN_MASK, WM8985_TSDEN);
+ snd_soc_update_bits(codec, WM8985_OUTPUT_CTRL0,
+ WM8985_TSOPCTRL_MASK,
+ WM8985_TSOPCTRL);
+ /* enable BIASEN */
+ snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+ WM8985_BIASEN_MASK, WM8985_BIASEN);
+ /* VMID at 75k */
+ snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+ WM8985_VMIDSEL_MASK,
+ 1 << WM8985_VMIDSEL_SHIFT);
+ msleep(500);
+ /* disable anti-pop features */
+ snd_soc_update_bits(codec, WM8985_OUT4_TO_ADC,
+ WM8985_POBCTRL_MASK, 0);
+ }
+ /* VMID at 300k */
+ snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+ WM8985_VMIDSEL_MASK,
+ 2 << WM8985_VMIDSEL_SHIFT);
+ break;
+ case SND_SOC_BIAS_OFF:
+ /* disable thermal shutdown */
+ snd_soc_update_bits(codec, WM8985_OUTPUT_CTRL0,
+ WM8985_TSOPCTRL_MASK, 0);
+ snd_soc_update_bits(codec, WM8985_OUTPUT_CTRL0,
+ WM8985_TSDEN_MASK, 0);
+ /* disable VMIDSEL and BIASEN */
+ snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+ WM8985_VMIDSEL_MASK | WM8985_BIASEN_MASK,
+ 0);
+ snd_soc_write(codec, WM8985_POWER_MANAGEMENT_1, 0);
+ snd_soc_write(codec, WM8985_POWER_MANAGEMENT_2, 0);
+ snd_soc_write(codec, WM8985_POWER_MANAGEMENT_3, 0);
+
+ codec->cache_sync = 1;
+
+ regulator_bulk_disable(ARRAY_SIZE(wm8985->supplies),
+ wm8985->supplies);
+ break;
+ }
+
+ codec->bias_level = level;
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int wm8985_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+ wm8985_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static int wm8985_resume(struct snd_soc_codec *codec)
+{
+ wm8985_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ return 0;
+}
+#else
+#define wm8985_suspend NULL
+#define wm8985_resume NULL
+#endif
+
+static int wm8985_remove(struct snd_soc_codec *codec)
+{
+ struct wm8985_priv *wm8985;
+
+ wm8985 = snd_soc_codec_get_drvdata(codec);
+ wm8985_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ regulator_bulk_free(ARRAY_SIZE(wm8985->supplies), wm8985->supplies);
+ return 0;
+}
+
+static int wm8985_probe(struct snd_soc_codec *codec)
+{
+ size_t i;
+ struct wm8985_priv *wm8985;
+ int ret;
+ u16 *cache;
+
+ wm8985 = snd_soc_codec_get_drvdata(codec);
+
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8985->control_type);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(wm8985->supplies); i++)
+ wm8985->supplies[i].supply = wm8985_supply_names[i];
+
+ ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8985->supplies),
+ wm8985->supplies);
+ if (ret) {
+ dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8985->supplies),
+ wm8985->supplies);
+ if (ret) {
+ dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+ goto err_reg_get;
+ }
+
+ ret = wm8985_reset(codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+ goto err_reg_enable;
+ }
+
+ cache = codec->reg_cache;
+ /* latch volume update bits */
+ for (i = 0; i < ARRAY_SIZE(volume_update_regs); ++i)
+ cache[volume_update_regs[i]] |= 0x100;
+ /* enable BIASCUT */
+ cache[WM8985_BIAS_CTRL] |= WM8985_BIASCUT;
+ codec->cache_sync = 1;
+
+ snd_soc_add_controls(codec, wm8985_snd_controls,
+ ARRAY_SIZE(wm8985_snd_controls));
+ wm8985_add_widgets(codec);
+
+ wm8985_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ return 0;
+
+err_reg_enable:
+ regulator_bulk_disable(ARRAY_SIZE(wm8985->supplies), wm8985->supplies);
+err_reg_get:
+ regulator_bulk_free(ARRAY_SIZE(wm8985->supplies), wm8985->supplies);
+ return ret;
+}
+
+static struct snd_soc_dai_ops wm8985_dai_ops = {
+ .digital_mute = wm8985_dac_mute,
+ .hw_params = wm8985_hw_params,
+ .set_fmt = wm8985_set_fmt,
+ .set_sysclk = wm8985_set_sysclk,
+ .set_pll = wm8985_set_pll
+};
+
+#define WM8985_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver wm8985_dai = {
+ .name = "wm8985-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = WM8985_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = WM8985_FORMATS,
+ },
+ .ops = &wm8985_dai_ops,
+ .symmetric_rates = 1
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8985 = {
+ .probe = wm8985_probe,
+ .remove = wm8985_remove,
+ .suspend = wm8985_suspend,
+ .resume = wm8985_resume,
+ .set_bias_level = wm8985_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8985_reg_defs),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8985_reg_defs
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8985_spi_probe(struct spi_device *spi)
+{
+ struct wm8985_priv *wm8985;
+ int ret;
+
+ wm8985 = kzalloc(sizeof *wm8985, GFP_KERNEL);
+ if (!wm8985)
+ return -ENOMEM;
+
+ wm8985->control_type = SND_SOC_SPI;
+ spi_set_drvdata(spi, wm8985);
+
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_wm8985, &wm8985_dai, 1);
+ if (ret < 0)
+ kfree(wm8985);
+ return ret;
+}
+
+static int __devexit wm8985_spi_remove(struct spi_device *spi)
+{
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
+ return 0;
+}
+
+static struct spi_driver wm8985_spi_driver = {
+ .driver = {
+ .name = "wm8985",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8985_spi_probe,
+ .remove = __devexit_p(wm8985_spi_remove)
+};
+#endif
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8985_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8985_priv *wm8985;
+ int ret;
+
+ wm8985 = kzalloc(sizeof *wm8985, GFP_KERNEL);
+ if (!wm8985)
+ return -ENOMEM;
+
+ wm8985->control_type = SND_SOC_I2C;
+ i2c_set_clientdata(i2c, wm8985);
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8985, &wm8985_dai, 1);
+ if (ret < 0)
+ kfree(wm8985);
+ return ret;
+}
+
+static __devexit int wm8985_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+static const struct i2c_device_id wm8985_i2c_id[] = {
+ { "wm8985", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8985_i2c_id);
+
+static struct i2c_driver wm8985_i2c_driver = {
+ .driver = {
+ .name = "wm8985",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8985_i2c_probe,
+ .remove = __devexit_p(wm8985_i2c_remove),
+ .id_table = wm8985_i2c_id
+};
+#endif
+
+static int __init wm8985_modinit(void)
+{
+ int ret = 0;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8985_i2c_driver);
+ if (ret) {
+ printk(KERN_ERR "Failed to register wm8985 I2C driver: %d\n",
+ ret);
+ }
+#endif
+#if defined(CONFIG_SPI_MASTER)
+ ret = spi_register_driver(&wm8985_spi_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8985 SPI driver: %d\n",
+ ret);
+ }
+#endif
+ return ret;
+}
+module_init(wm8985_modinit);
+
+static void __exit wm8985_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&wm8985_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+ spi_unregister_driver(&wm8985_spi_driver);
+#endif
+}
+module_exit(wm8985_exit);
+
+MODULE_DESCRIPTION("ASoC WM8985 driver");
+MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8985.h b/sound/soc/codecs/wm8985.h
new file mode 100644
index 0000000..2e71ff5
--- /dev/null
+++ b/sound/soc/codecs/wm8985.h
@@ -0,0 +1,1045 @@
+/*
+ * wm8985.h -- WM8985 ASoC driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *
+ * 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 _WM8985_H
+#define _WM8985_H
+
+#define WM8985_SOFTWARE_RESET 0x00
+#define WM8985_POWER_MANAGEMENT_1 0x01
+#define WM8985_POWER_MANAGEMENT_2 0x02
+#define WM8985_POWER_MANAGEMENT_3 0x03
+#define WM8985_AUDIO_INTERFACE 0x04
+#define WM8985_COMPANDING_CONTROL 0x05
+#define WM8985_CLOCK_GEN_CONTROL 0x06
+#define WM8985_ADDITIONAL_CONTROL 0x07
+#define WM8985_GPIO_CONTROL 0x08
+#define WM8985_JACK_DETECT_CONTROL_1 0x09
+#define WM8985_DAC_CONTROL 0x0A
+#define WM8985_LEFT_DAC_DIGITAL_VOL 0x0B
+#define WM8985_RIGHT_DAC_DIGITAL_VOL 0x0C
+#define WM8985_JACK_DETECT_CONTROL_2 0x0D
+#define WM8985_ADC_CONTROL 0x0E
+#define WM8985_LEFT_ADC_DIGITAL_VOL 0x0F
+#define WM8985_RIGHT_ADC_DIGITAL_VOL 0x10
+#define WM8985_EQ1_LOW_SHELF 0x12
+#define WM8985_EQ2_PEAK_1 0x13
+#define WM8985_EQ3_PEAK_2 0x14
+#define WM8985_EQ4_PEAK_3 0x15
+#define WM8985_EQ5_HIGH_SHELF 0x16
+#define WM8985_DAC_LIMITER_1 0x18
+#define WM8985_DAC_LIMITER_2 0x19
+#define WM8985_NOTCH_FILTER_1 0x1B
+#define WM8985_NOTCH_FILTER_2 0x1C
+#define WM8985_NOTCH_FILTER_3 0x1D
+#define WM8985_NOTCH_FILTER_4 0x1E
+#define WM8985_ALC_CONTROL_1 0x20
+#define WM8985_ALC_CONTROL_2 0x21
+#define WM8985_ALC_CONTROL_3 0x22
+#define WM8985_NOISE_GATE 0x23
+#define WM8985_PLL_N 0x24
+#define WM8985_PLL_K_1 0x25
+#define WM8985_PLL_K_2 0x26
+#define WM8985_PLL_K_3 0x27
+#define WM8985_3D_CONTROL 0x29
+#define WM8985_OUT4_TO_ADC 0x2A
+#define WM8985_BEEP_CONTROL 0x2B
+#define WM8985_INPUT_CTRL 0x2C
+#define WM8985_LEFT_INP_PGA_GAIN_CTRL 0x2D
+#define WM8985_RIGHT_INP_PGA_GAIN_CTRL 0x2E
+#define WM8985_LEFT_ADC_BOOST_CTRL 0x2F
+#define WM8985_RIGHT_ADC_BOOST_CTRL 0x30
+#define WM8985_OUTPUT_CTRL0 0x31
+#define WM8985_LEFT_MIXER_CTRL 0x32
+#define WM8985_RIGHT_MIXER_CTRL 0x33
+#define WM8985_LOUT1_HP_VOLUME_CTRL 0x34
+#define WM8985_ROUT1_HP_VOLUME_CTRL 0x35
+#define WM8985_LOUT2_SPK_VOLUME_CTRL 0x36
+#define WM8985_ROUT2_SPK_VOLUME_CTRL 0x37
+#define WM8985_OUT3_MIXER_CTRL 0x38
+#define WM8985_OUT4_MONO_MIX_CTRL 0x39
+#define WM8985_OUTPUT_CTRL1 0x3C
+#define WM8985_BIAS_CTRL 0x3D
+
+#define WM8985_REGISTER_COUNT 59
+#define WM8985_MAX_REGISTER 0x3F
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Software Reset
+ */
+#define WM8985_SOFTWARE_RESET_MASK 0x01FF /* SOFTWARE_RESET - [8:0] */
+#define WM8985_SOFTWARE_RESET_SHIFT 0 /* SOFTWARE_RESET - [8:0] */
+#define WM8985_SOFTWARE_RESET_WIDTH 9 /* SOFTWARE_RESET - [8:0] */
+
+/*
+ * R1 (0x01) - Power management 1
+ */
+#define WM8985_OUT4MIXEN 0x0080 /* OUT4MIXEN */
+#define WM8985_OUT4MIXEN_MASK 0x0080 /* OUT4MIXEN */
+#define WM8985_OUT4MIXEN_SHIFT 7 /* OUT4MIXEN */
+#define WM8985_OUT4MIXEN_WIDTH 1 /* OUT4MIXEN */
+#define WM8985_OUT3MIXEN 0x0040 /* OUT3MIXEN */
+#define WM8985_OUT3MIXEN_MASK 0x0040 /* OUT3MIXEN */
+#define WM8985_OUT3MIXEN_SHIFT 6 /* OUT3MIXEN */
+#define WM8985_OUT3MIXEN_WIDTH 1 /* OUT3MIXEN */
+#define WM8985_PLLEN 0x0020 /* PLLEN */
+#define WM8985_PLLEN_MASK 0x0020 /* PLLEN */
+#define WM8985_PLLEN_SHIFT 5 /* PLLEN */
+#define WM8985_PLLEN_WIDTH 1 /* PLLEN */
+#define WM8985_MICBEN 0x0010 /* MICBEN */
+#define WM8985_MICBEN_MASK 0x0010 /* MICBEN */
+#define WM8985_MICBEN_SHIFT 4 /* MICBEN */
+#define WM8985_MICBEN_WIDTH 1 /* MICBEN */
+#define WM8985_BIASEN 0x0008 /* BIASEN */
+#define WM8985_BIASEN_MASK 0x0008 /* BIASEN */
+#define WM8985_BIASEN_SHIFT 3 /* BIASEN */
+#define WM8985_BIASEN_WIDTH 1 /* BIASEN */
+#define WM8985_BUFIOEN 0x0004 /* BUFIOEN */
+#define WM8985_BUFIOEN_MASK 0x0004 /* BUFIOEN */
+#define WM8985_BUFIOEN_SHIFT 2 /* BUFIOEN */
+#define WM8985_BUFIOEN_WIDTH 1 /* BUFIOEN */
+#define WM8985_VMIDSEL 0x0003 /* VMIDSEL */
+#define WM8985_VMIDSEL_MASK 0x0003 /* VMIDSEL - [1:0] */
+#define WM8985_VMIDSEL_SHIFT 0 /* VMIDSEL - [1:0] */
+#define WM8985_VMIDSEL_WIDTH 2 /* VMIDSEL - [1:0] */
+
+/*
+ * R2 (0x02) - Power management 2
+ */
+#define WM8985_ROUT1EN 0x0100 /* ROUT1EN */
+#define WM8985_ROUT1EN_MASK 0x0100 /* ROUT1EN */
+#define WM8985_ROUT1EN_SHIFT 8 /* ROUT1EN */
+#define WM8985_ROUT1EN_WIDTH 1 /* ROUT1EN */
+#define WM8985_LOUT1EN 0x0080 /* LOUT1EN */
+#define WM8985_LOUT1EN_MASK 0x0080 /* LOUT1EN */
+#define WM8985_LOUT1EN_SHIFT 7 /* LOUT1EN */
+#define WM8985_LOUT1EN_WIDTH 1 /* LOUT1EN */
+#define WM8985_SLEEP 0x0040 /* SLEEP */
+#define WM8985_SLEEP_MASK 0x0040 /* SLEEP */
+#define WM8985_SLEEP_SHIFT 6 /* SLEEP */
+#define WM8985_SLEEP_WIDTH 1 /* SLEEP */
+#define WM8985_BOOSTENR 0x0020 /* BOOSTENR */
+#define WM8985_BOOSTENR_MASK 0x0020 /* BOOSTENR */
+#define WM8985_BOOSTENR_SHIFT 5 /* BOOSTENR */
+#define WM8985_BOOSTENR_WIDTH 1 /* BOOSTENR */
+#define WM8985_BOOSTENL 0x0010 /* BOOSTENL */
+#define WM8985_BOOSTENL_MASK 0x0010 /* BOOSTENL */
+#define WM8985_BOOSTENL_SHIFT 4 /* BOOSTENL */
+#define WM8985_BOOSTENL_WIDTH 1 /* BOOSTENL */
+#define WM8985_INPGAENR 0x0008 /* INPGAENR */
+#define WM8985_INPGAENR_MASK 0x0008 /* INPGAENR */
+#define WM8985_INPGAENR_SHIFT 3 /* INPGAENR */
+#define WM8985_INPGAENR_WIDTH 1 /* INPGAENR */
+#define WM8985_INPPGAENL 0x0004 /* INPPGAENL */
+#define WM8985_INPPGAENL_MASK 0x0004 /* INPPGAENL */
+#define WM8985_INPPGAENL_SHIFT 2 /* INPPGAENL */
+#define WM8985_INPPGAENL_WIDTH 1 /* INPPGAENL */
+#define WM8985_ADCENR 0x0002 /* ADCENR */
+#define WM8985_ADCENR_MASK 0x0002 /* ADCENR */
+#define WM8985_ADCENR_SHIFT 1 /* ADCENR */
+#define WM8985_ADCENR_WIDTH 1 /* ADCENR */
+#define WM8985_ADCENL 0x0001 /* ADCENL */
+#define WM8985_ADCENL_MASK 0x0001 /* ADCENL */
+#define WM8985_ADCENL_SHIFT 0 /* ADCENL */
+#define WM8985_ADCENL_WIDTH 1 /* ADCENL */
+
+/*
+ * R3 (0x03) - Power management 3
+ */
+#define WM8985_OUT4EN 0x0100 /* OUT4EN */
+#define WM8985_OUT4EN_MASK 0x0100 /* OUT4EN */
+#define WM8985_OUT4EN_SHIFT 8 /* OUT4EN */
+#define WM8985_OUT4EN_WIDTH 1 /* OUT4EN */
+#define WM8985_OUT3EN 0x0080 /* OUT3EN */
+#define WM8985_OUT3EN_MASK 0x0080 /* OUT3EN */
+#define WM8985_OUT3EN_SHIFT 7 /* OUT3EN */
+#define WM8985_OUT3EN_WIDTH 1 /* OUT3EN */
+#define WM8985_ROUT2EN 0x0040 /* ROUT2EN */
+#define WM8985_ROUT2EN_MASK 0x0040 /* ROUT2EN */
+#define WM8985_ROUT2EN_SHIFT 6 /* ROUT2EN */
+#define WM8985_ROUT2EN_WIDTH 1 /* ROUT2EN */
+#define WM8985_LOUT2EN 0x0020 /* LOUT2EN */
+#define WM8985_LOUT2EN_MASK 0x0020 /* LOUT2EN */
+#define WM8985_LOUT2EN_SHIFT 5 /* LOUT2EN */
+#define WM8985_LOUT2EN_WIDTH 1 /* LOUT2EN */
+#define WM8985_RMIXEN 0x0008 /* RMIXEN */
+#define WM8985_RMIXEN_MASK 0x0008 /* RMIXEN */
+#define WM8985_RMIXEN_SHIFT 3 /* RMIXEN */
+#define WM8985_RMIXEN_WIDTH 1 /* RMIXEN */
+#define WM8985_LMIXEN 0x0004 /* LMIXEN */
+#define WM8985_LMIXEN_MASK 0x0004 /* LMIXEN */
+#define WM8985_LMIXEN_SHIFT 2 /* LMIXEN */
+#define WM8985_LMIXEN_WIDTH 1 /* LMIXEN */
+#define WM8985_DACENR 0x0002 /* DACENR */
+#define WM8985_DACENR_MASK 0x0002 /* DACENR */
+#define WM8985_DACENR_SHIFT 1 /* DACENR */
+#define WM8985_DACENR_WIDTH 1 /* DACENR */
+#define WM8985_DACENL 0x0001 /* DACENL */
+#define WM8985_DACENL_MASK 0x0001 /* DACENL */
+#define WM8985_DACENL_SHIFT 0 /* DACENL */
+#define WM8985_DACENL_WIDTH 1 /* DACENL */
+
+/*
+ * R4 (0x04) - Audio Interface
+ */
+#define WM8985_BCP 0x0100 /* BCP */
+#define WM8985_BCP_MASK 0x0100 /* BCP */
+#define WM8985_BCP_SHIFT 8 /* BCP */
+#define WM8985_BCP_WIDTH 1 /* BCP */
+#define WM8985_LRP 0x0080 /* LRP */
+#define WM8985_LRP_MASK 0x0080 /* LRP */
+#define WM8985_LRP_SHIFT 7 /* LRP */
+#define WM8985_LRP_WIDTH 1 /* LRP */
+#define WM8985_WL_MASK 0x0060 /* WL - [6:5] */
+#define WM8985_WL_SHIFT 5 /* WL - [6:5] */
+#define WM8985_WL_WIDTH 2 /* WL - [6:5] */
+#define WM8985_FMT_MASK 0x0018 /* FMT - [4:3] */
+#define WM8985_FMT_SHIFT 3 /* FMT - [4:3] */
+#define WM8985_FMT_WIDTH 2 /* FMT - [4:3] */
+#define WM8985_DLRSWAP 0x0004 /* DLRSWAP */
+#define WM8985_DLRSWAP_MASK 0x0004 /* DLRSWAP */
+#define WM8985_DLRSWAP_SHIFT 2 /* DLRSWAP */
+#define WM8985_DLRSWAP_WIDTH 1 /* DLRSWAP */
+#define WM8985_ALRSWAP 0x0002 /* ALRSWAP */
+#define WM8985_ALRSWAP_MASK 0x0002 /* ALRSWAP */
+#define WM8985_ALRSWAP_SHIFT 1 /* ALRSWAP */
+#define WM8985_ALRSWAP_WIDTH 1 /* ALRSWAP */
+#define WM8985_MONO 0x0001 /* MONO */
+#define WM8985_MONO_MASK 0x0001 /* MONO */
+#define WM8985_MONO_SHIFT 0 /* MONO */
+#define WM8985_MONO_WIDTH 1 /* MONO */
+
+/*
+ * R5 (0x05) - Companding control
+ */
+#define WM8985_WL8 0x0020 /* WL8 */
+#define WM8985_WL8_MASK 0x0020 /* WL8 */
+#define WM8985_WL8_SHIFT 5 /* WL8 */
+#define WM8985_WL8_WIDTH 1 /* WL8 */
+#define WM8985_DAC_COMP_MASK 0x0018 /* DAC_COMP - [4:3] */
+#define WM8985_DAC_COMP_SHIFT 3 /* DAC_COMP - [4:3] */
+#define WM8985_DAC_COMP_WIDTH 2 /* DAC_COMP - [4:3] */
+#define WM8985_ADC_COMP_MASK 0x0006 /* ADC_COMP - [2:1] */
+#define WM8985_ADC_COMP_SHIFT 1 /* ADC_COMP - [2:1] */
+#define WM8985_ADC_COMP_WIDTH 2 /* ADC_COMP - [2:1] */
+#define WM8985_LOOPBACK 0x0001 /* LOOPBACK */
+#define WM8985_LOOPBACK_MASK 0x0001 /* LOOPBACK */
+#define WM8985_LOOPBACK_SHIFT 0 /* LOOPBACK */
+#define WM8985_LOOPBACK_WIDTH 1 /* LOOPBACK */
+
+/*
+ * R6 (0x06) - Clock Gen control
+ */
+#define WM8985_CLKSEL 0x0100 /* CLKSEL */
+#define WM8985_CLKSEL_MASK 0x0100 /* CLKSEL */
+#define WM8985_CLKSEL_SHIFT 8 /* CLKSEL */
+#define WM8985_CLKSEL_WIDTH 1 /* CLKSEL */
+#define WM8985_MCLKDIV_MASK 0x00E0 /* MCLKDIV - [7:5] */
+#define WM8985_MCLKDIV_SHIFT 5 /* MCLKDIV - [7:5] */
+#define WM8985_MCLKDIV_WIDTH 3 /* MCLKDIV - [7:5] */
+#define WM8985_BCLKDIV_MASK 0x001C /* BCLKDIV - [4:2] */
+#define WM8985_BCLKDIV_SHIFT 2 /* BCLKDIV - [4:2] */
+#define WM8985_BCLKDIV_WIDTH 3 /* BCLKDIV - [4:2] */
+#define WM8985_MS 0x0001 /* MS */
+#define WM8985_MS_MASK 0x0001 /* MS */
+#define WM8985_MS_SHIFT 0 /* MS */
+#define WM8985_MS_WIDTH 1 /* MS */
+
+/*
+ * R7 (0x07) - Additional control
+ */
+#define WM8985_M128ENB 0x0100 /* M128ENB */
+#define WM8985_M128ENB_MASK 0x0100 /* M128ENB */
+#define WM8985_M128ENB_SHIFT 8 /* M128ENB */
+#define WM8985_M128ENB_WIDTH 1 /* M128ENB */
+#define WM8985_DCLKDIV_MASK 0x00F0 /* DCLKDIV - [7:4] */
+#define WM8985_DCLKDIV_SHIFT 4 /* DCLKDIV - [7:4] */
+#define WM8985_DCLKDIV_WIDTH 4 /* DCLKDIV - [7:4] */
+#define WM8985_SR_MASK 0x000E /* SR - [3:1] */
+#define WM8985_SR_SHIFT 1 /* SR - [3:1] */
+#define WM8985_SR_WIDTH 3 /* SR - [3:1] */
+#define WM8985_SLOWCLKEN 0x0001 /* SLOWCLKEN */
+#define WM8985_SLOWCLKEN_MASK 0x0001 /* SLOWCLKEN */
+#define WM8985_SLOWCLKEN_SHIFT 0 /* SLOWCLKEN */
+#define WM8985_SLOWCLKEN_WIDTH 1 /* SLOWCLKEN */
+
+/*
+ * R8 (0x08) - GPIO Control
+ */
+#define WM8985_GPIO1GP 0x0100 /* GPIO1GP */
+#define WM8985_GPIO1GP_MASK 0x0100 /* GPIO1GP */
+#define WM8985_GPIO1GP_SHIFT 8 /* GPIO1GP */
+#define WM8985_GPIO1GP_WIDTH 1 /* GPIO1GP */
+#define WM8985_GPIO1GPU 0x0080 /* GPIO1GPU */
+#define WM8985_GPIO1GPU_MASK 0x0080 /* GPIO1GPU */
+#define WM8985_GPIO1GPU_SHIFT 7 /* GPIO1GPU */
+#define WM8985_GPIO1GPU_WIDTH 1 /* GPIO1GPU */
+#define WM8985_GPIO1GPD 0x0040 /* GPIO1GPD */
+#define WM8985_GPIO1GPD_MASK 0x0040 /* GPIO1GPD */
+#define WM8985_GPIO1GPD_SHIFT 6 /* GPIO1GPD */
+#define WM8985_GPIO1GPD_WIDTH 1 /* GPIO1GPD */
+#define WM8985_GPIO1POL 0x0008 /* GPIO1POL */
+#define WM8985_GPIO1POL_MASK 0x0008 /* GPIO1POL */
+#define WM8985_GPIO1POL_SHIFT 3 /* GPIO1POL */
+#define WM8985_GPIO1POL_WIDTH 1 /* GPIO1POL */
+#define WM8985_GPIO1SEL_MASK 0x0007 /* GPIO1SEL - [2:0] */
+#define WM8985_GPIO1SEL_SHIFT 0 /* GPIO1SEL - [2:0] */
+#define WM8985_GPIO1SEL_WIDTH 3 /* GPIO1SEL - [2:0] */
+
+/*
+ * R9 (0x09) - Jack Detect Control 1
+ */
+#define WM8985_JD_EN 0x0040 /* JD_EN */
+#define WM8985_JD_EN_MASK 0x0040 /* JD_EN */
+#define WM8985_JD_EN_SHIFT 6 /* JD_EN */
+#define WM8985_JD_EN_WIDTH 1 /* JD_EN */
+#define WM8985_JD_SEL_MASK 0x0030 /* JD_SEL - [5:4] */
+#define WM8985_JD_SEL_SHIFT 4 /* JD_SEL - [5:4] */
+#define WM8985_JD_SEL_WIDTH 2 /* JD_SEL - [5:4] */
+
+/*
+ * R10 (0x0A) - DAC Control
+ */
+#define WM8985_SOFTMUTE 0x0040 /* SOFTMUTE */
+#define WM8985_SOFTMUTE_MASK 0x0040 /* SOFTMUTE */
+#define WM8985_SOFTMUTE_SHIFT 6 /* SOFTMUTE */
+#define WM8985_SOFTMUTE_WIDTH 1 /* SOFTMUTE */
+#define WM8985_DACOSR128 0x0008 /* DACOSR128 */
+#define WM8985_DACOSR128_MASK 0x0008 /* DACOSR128 */
+#define WM8985_DACOSR128_SHIFT 3 /* DACOSR128 */
+#define WM8985_DACOSR128_WIDTH 1 /* DACOSR128 */
+#define WM8985_AMUTE 0x0004 /* AMUTE */
+#define WM8985_AMUTE_MASK 0x0004 /* AMUTE */
+#define WM8985_AMUTE_SHIFT 2 /* AMUTE */
+#define WM8985_AMUTE_WIDTH 1 /* AMUTE */
+#define WM8985_DACPOLR 0x0002 /* DACPOLR */
+#define WM8985_DACPOLR_MASK 0x0002 /* DACPOLR */
+#define WM8985_DACPOLR_SHIFT 1 /* DACPOLR */
+#define WM8985_DACPOLR_WIDTH 1 /* DACPOLR */
+#define WM8985_DACPOLL 0x0001 /* DACPOLL */
+#define WM8985_DACPOLL_MASK 0x0001 /* DACPOLL */
+#define WM8985_DACPOLL_SHIFT 0 /* DACPOLL */
+#define WM8985_DACPOLL_WIDTH 1 /* DACPOLL */
+
+/*
+ * R11 (0x0B) - Left DAC digital Vol
+ */
+#define WM8985_DACVU 0x0100 /* DACVU */
+#define WM8985_DACVU_MASK 0x0100 /* DACVU */
+#define WM8985_DACVU_SHIFT 8 /* DACVU */
+#define WM8985_DACVU_WIDTH 1 /* DACVU */
+#define WM8985_DACVOLL_MASK 0x00FF /* DACVOLL - [7:0] */
+#define WM8985_DACVOLL_SHIFT 0 /* DACVOLL - [7:0] */
+#define WM8985_DACVOLL_WIDTH 8 /* DACVOLL - [7:0] */
+
+/*
+ * R12 (0x0C) - Right DAC digital vol
+ */
+#define WM8985_DACVU 0x0100 /* DACVU */
+#define WM8985_DACVU_MASK 0x0100 /* DACVU */
+#define WM8985_DACVU_SHIFT 8 /* DACVU */
+#define WM8985_DACVU_WIDTH 1 /* DACVU */
+#define WM8985_DACVOLR_MASK 0x00FF /* DACVOLR - [7:0] */
+#define WM8985_DACVOLR_SHIFT 0 /* DACVOLR - [7:0] */
+#define WM8985_DACVOLR_WIDTH 8 /* DACVOLR - [7:0] */
+
+/*
+ * R13 (0x0D) - Jack Detect Control 2
+ */
+#define WM8985_JD_EN1_MASK 0x00F0 /* JD_EN1 - [7:4] */
+#define WM8985_JD_EN1_SHIFT 4 /* JD_EN1 - [7:4] */
+#define WM8985_JD_EN1_WIDTH 4 /* JD_EN1 - [7:4] */
+#define WM8985_JD_EN0_MASK 0x000F /* JD_EN0 - [3:0] */
+#define WM8985_JD_EN0_SHIFT 0 /* JD_EN0 - [3:0] */
+#define WM8985_JD_EN0_WIDTH 4 /* JD_EN0 - [3:0] */
+
+/*
+ * R14 (0x0E) - ADC Control
+ */
+#define WM8985_HPFEN 0x0100 /* HPFEN */
+#define WM8985_HPFEN_MASK 0x0100 /* HPFEN */
+#define WM8985_HPFEN_SHIFT 8 /* HPFEN */
+#define WM8985_HPFEN_WIDTH 1 /* HPFEN */
+#define WM8985_HPFAPP 0x0080 /* HPFAPP */
+#define WM8985_HPFAPP_MASK 0x0080 /* HPFAPP */
+#define WM8985_HPFAPP_SHIFT 7 /* HPFAPP */
+#define WM8985_HPFAPP_WIDTH 1 /* HPFAPP */
+#define WM8985_HPFCUT_MASK 0x0070 /* HPFCUT - [6:4] */
+#define WM8985_HPFCUT_SHIFT 4 /* HPFCUT - [6:4] */
+#define WM8985_HPFCUT_WIDTH 3 /* HPFCUT - [6:4] */
+#define WM8985_ADCOSR128 0x0008 /* ADCOSR128 */
+#define WM8985_ADCOSR128_MASK 0x0008 /* ADCOSR128 */
+#define WM8985_ADCOSR128_SHIFT 3 /* ADCOSR128 */
+#define WM8985_ADCOSR128_WIDTH 1 /* ADCOSR128 */
+#define WM8985_ADCRPOL 0x0002 /* ADCRPOL */
+#define WM8985_ADCRPOL_MASK 0x0002 /* ADCRPOL */
+#define WM8985_ADCRPOL_SHIFT 1 /* ADCRPOL */
+#define WM8985_ADCRPOL_WIDTH 1 /* ADCRPOL */
+#define WM8985_ADCLPOL 0x0001 /* ADCLPOL */
+#define WM8985_ADCLPOL_MASK 0x0001 /* ADCLPOL */
+#define WM8985_ADCLPOL_SHIFT 0 /* ADCLPOL */
+#define WM8985_ADCLPOL_WIDTH 1 /* ADCLPOL */
+
+/*
+ * R15 (0x0F) - Left ADC Digital Vol
+ */
+#define WM8985_ADCVU 0x0100 /* ADCVU */
+#define WM8985_ADCVU_MASK 0x0100 /* ADCVU */
+#define WM8985_ADCVU_SHIFT 8 /* ADCVU */
+#define WM8985_ADCVU_WIDTH 1 /* ADCVU */
+#define WM8985_ADCVOLL_MASK 0x00FF /* ADCVOLL - [7:0] */
+#define WM8985_ADCVOLL_SHIFT 0 /* ADCVOLL - [7:0] */
+#define WM8985_ADCVOLL_WIDTH 8 /* ADCVOLL - [7:0] */
+
+/*
+ * R16 (0x10) - Right ADC Digital Vol
+ */
+#define WM8985_ADCVU 0x0100 /* ADCVU */
+#define WM8985_ADCVU_MASK 0x0100 /* ADCVU */
+#define WM8985_ADCVU_SHIFT 8 /* ADCVU */
+#define WM8985_ADCVU_WIDTH 1 /* ADCVU */
+#define WM8985_ADCVOLR_MASK 0x00FF /* ADCVOLR - [7:0] */
+#define WM8985_ADCVOLR_SHIFT 0 /* ADCVOLR - [7:0] */
+#define WM8985_ADCVOLR_WIDTH 8 /* ADCVOLR - [7:0] */
+
+/*
+ * R18 (0x12) - EQ1 - low shelf
+ */
+#define WM8985_EQ3DMODE 0x0100 /* EQ3DMODE */
+#define WM8985_EQ3DMODE_MASK 0x0100 /* EQ3DMODE */
+#define WM8985_EQ3DMODE_SHIFT 8 /* EQ3DMODE */
+#define WM8985_EQ3DMODE_WIDTH 1 /* EQ3DMODE */
+#define WM8985_EQ1C_MASK 0x0060 /* EQ1C - [6:5] */
+#define WM8985_EQ1C_SHIFT 5 /* EQ1C - [6:5] */
+#define WM8985_EQ1C_WIDTH 2 /* EQ1C - [6:5] */
+#define WM8985_EQ1G_MASK 0x001F /* EQ1G - [4:0] */
+#define WM8985_EQ1G_SHIFT 0 /* EQ1G - [4:0] */
+#define WM8985_EQ1G_WIDTH 5 /* EQ1G - [4:0] */
+
+/*
+ * R19 (0x13) - EQ2 - peak 1
+ */
+#define WM8985_EQ2BW 0x0100 /* EQ2BW */
+#define WM8985_EQ2BW_MASK 0x0100 /* EQ2BW */
+#define WM8985_EQ2BW_SHIFT 8 /* EQ2BW */
+#define WM8985_EQ2BW_WIDTH 1 /* EQ2BW */
+#define WM8985_EQ2C_MASK 0x0060 /* EQ2C - [6:5] */
+#define WM8985_EQ2C_SHIFT 5 /* EQ2C - [6:5] */
+#define WM8985_EQ2C_WIDTH 2 /* EQ2C - [6:5] */
+#define WM8985_EQ2G_MASK 0x001F /* EQ2G - [4:0] */
+#define WM8985_EQ2G_SHIFT 0 /* EQ2G - [4:0] */
+#define WM8985_EQ2G_WIDTH 5 /* EQ2G - [4:0] */
+
+/*
+ * R20 (0x14) - EQ3 - peak 2
+ */
+#define WM8985_EQ3BW 0x0100 /* EQ3BW */
+#define WM8985_EQ3BW_MASK 0x0100 /* EQ3BW */
+#define WM8985_EQ3BW_SHIFT 8 /* EQ3BW */
+#define WM8985_EQ3BW_WIDTH 1 /* EQ3BW */
+#define WM8985_EQ3C_MASK 0x0060 /* EQ3C - [6:5] */
+#define WM8985_EQ3C_SHIFT 5 /* EQ3C - [6:5] */
+#define WM8985_EQ3C_WIDTH 2 /* EQ3C - [6:5] */
+#define WM8985_EQ3G_MASK 0x001F /* EQ3G - [4:0] */
+#define WM8985_EQ3G_SHIFT 0 /* EQ3G - [4:0] */
+#define WM8985_EQ3G_WIDTH 5 /* EQ3G - [4:0] */
+
+/*
+ * R21 (0x15) - EQ4 - peak 3
+ */
+#define WM8985_EQ4BW 0x0100 /* EQ4BW */
+#define WM8985_EQ4BW_MASK 0x0100 /* EQ4BW */
+#define WM8985_EQ4BW_SHIFT 8 /* EQ4BW */
+#define WM8985_EQ4BW_WIDTH 1 /* EQ4BW */
+#define WM8985_EQ4C_MASK 0x0060 /* EQ4C - [6:5] */
+#define WM8985_EQ4C_SHIFT 5 /* EQ4C - [6:5] */
+#define WM8985_EQ4C_WIDTH 2 /* EQ4C - [6:5] */
+#define WM8985_EQ4G_MASK 0x001F /* EQ4G - [4:0] */
+#define WM8985_EQ4G_SHIFT 0 /* EQ4G - [4:0] */
+#define WM8985_EQ4G_WIDTH 5 /* EQ4G - [4:0] */
+
+/*
+ * R22 (0x16) - EQ5 - high shelf
+ */
+#define WM8985_EQ5C_MASK 0x0060 /* EQ5C - [6:5] */
+#define WM8985_EQ5C_SHIFT 5 /* EQ5C - [6:5] */
+#define WM8985_EQ5C_WIDTH 2 /* EQ5C - [6:5] */
+#define WM8985_EQ5G_MASK 0x001F /* EQ5G - [4:0] */
+#define WM8985_EQ5G_SHIFT 0 /* EQ5G - [4:0] */
+#define WM8985_EQ5G_WIDTH 5 /* EQ5G - [4:0] */
+
+/*
+ * R24 (0x18) - DAC Limiter 1
+ */
+#define WM8985_LIMEN 0x0100 /* LIMEN */
+#define WM8985_LIMEN_MASK 0x0100 /* LIMEN */
+#define WM8985_LIMEN_SHIFT 8 /* LIMEN */
+#define WM8985_LIMEN_WIDTH 1 /* LIMEN */
+#define WM8985_LIMDCY_MASK 0x00F0 /* LIMDCY - [7:4] */
+#define WM8985_LIMDCY_SHIFT 4 /* LIMDCY - [7:4] */
+#define WM8985_LIMDCY_WIDTH 4 /* LIMDCY - [7:4] */
+#define WM8985_LIMATK_MASK 0x000F /* LIMATK - [3:0] */
+#define WM8985_LIMATK_SHIFT 0 /* LIMATK - [3:0] */
+#define WM8985_LIMATK_WIDTH 4 /* LIMATK - [3:0] */
+
+/*
+ * R25 (0x19) - DAC Limiter 2
+ */
+#define WM8985_LIMLVL_MASK 0x0070 /* LIMLVL - [6:4] */
+#define WM8985_LIMLVL_SHIFT 4 /* LIMLVL - [6:4] */
+#define WM8985_LIMLVL_WIDTH 3 /* LIMLVL - [6:4] */
+#define WM8985_LIMBOOST_MASK 0x000F /* LIMBOOST - [3:0] */
+#define WM8985_LIMBOOST_SHIFT 0 /* LIMBOOST - [3:0] */
+#define WM8985_LIMBOOST_WIDTH 4 /* LIMBOOST - [3:0] */
+
+/*
+ * R27 (0x1B) - Notch Filter 1
+ */
+#define WM8985_NFU 0x0100 /* NFU */
+#define WM8985_NFU_MASK 0x0100 /* NFU */
+#define WM8985_NFU_SHIFT 8 /* NFU */
+#define WM8985_NFU_WIDTH 1 /* NFU */
+#define WM8985_NFEN 0x0080 /* NFEN */
+#define WM8985_NFEN_MASK 0x0080 /* NFEN */
+#define WM8985_NFEN_SHIFT 7 /* NFEN */
+#define WM8985_NFEN_WIDTH 1 /* NFEN */
+#define WM8985_NFA0_13_7_MASK 0x007F /* NFA0(13:7) - [6:0] */
+#define WM8985_NFA0_13_7_SHIFT 0 /* NFA0(13:7) - [6:0] */
+#define WM8985_NFA0_13_7_WIDTH 7 /* NFA0(13:7) - [6:0] */
+
+/*
+ * R28 (0x1C) - Notch Filter 2
+ */
+#define WM8985_NFU 0x0100 /* NFU */
+#define WM8985_NFU_MASK 0x0100 /* NFU */
+#define WM8985_NFU_SHIFT 8 /* NFU */
+#define WM8985_NFU_WIDTH 1 /* NFU */
+#define WM8985_NFA0_6_0_MASK 0x007F /* NFA0(6:0) - [6:0] */
+#define WM8985_NFA0_6_0_SHIFT 0 /* NFA0(6:0) - [6:0] */
+#define WM8985_NFA0_6_0_WIDTH 7 /* NFA0(6:0) - [6:0] */
+
+/*
+ * R29 (0x1D) - Notch Filter 3
+ */
+#define WM8985_NFU 0x0100 /* NFU */
+#define WM8985_NFU_MASK 0x0100 /* NFU */
+#define WM8985_NFU_SHIFT 8 /* NFU */
+#define WM8985_NFU_WIDTH 1 /* NFU */
+#define WM8985_NFA1_13_7_MASK 0x007F /* NFA1(13:7) - [6:0] */
+#define WM8985_NFA1_13_7_SHIFT 0 /* NFA1(13:7) - [6:0] */
+#define WM8985_NFA1_13_7_WIDTH 7 /* NFA1(13:7) - [6:0] */
+
+/*
+ * R30 (0x1E) - Notch Filter 4
+ */
+#define WM8985_NFU 0x0100 /* NFU */
+#define WM8985_NFU_MASK 0x0100 /* NFU */
+#define WM8985_NFU_SHIFT 8 /* NFU */
+#define WM8985_NFU_WIDTH 1 /* NFU */
+#define WM8985_NFA1_6_0_MASK 0x007F /* NFA1(6:0) - [6:0] */
+#define WM8985_NFA1_6_0_SHIFT 0 /* NFA1(6:0) - [6:0] */
+#define WM8985_NFA1_6_0_WIDTH 7 /* NFA1(6:0) - [6:0] */
+
+/*
+ * R32 (0x20) - ALC control 1
+ */
+#define WM8985_ALCSEL_MASK 0x0180 /* ALCSEL - [8:7] */
+#define WM8985_ALCSEL_SHIFT 7 /* ALCSEL - [8:7] */
+#define WM8985_ALCSEL_WIDTH 2 /* ALCSEL - [8:7] */
+#define WM8985_ALCMAX_MASK 0x0038 /* ALCMAX - [5:3] */
+#define WM8985_ALCMAX_SHIFT 3 /* ALCMAX - [5:3] */
+#define WM8985_ALCMAX_WIDTH 3 /* ALCMAX - [5:3] */
+#define WM8985_ALCMIN_MASK 0x0007 /* ALCMIN - [2:0] */
+#define WM8985_ALCMIN_SHIFT 0 /* ALCMIN - [2:0] */
+#define WM8985_ALCMIN_WIDTH 3 /* ALCMIN - [2:0] */
+
+/*
+ * R33 (0x21) - ALC control 2
+ */
+#define WM8985_ALCHLD_MASK 0x00F0 /* ALCHLD - [7:4] */
+#define WM8985_ALCHLD_SHIFT 4 /* ALCHLD - [7:4] */
+#define WM8985_ALCHLD_WIDTH 4 /* ALCHLD - [7:4] */
+#define WM8985_ALCLVL_MASK 0x000F /* ALCLVL - [3:0] */
+#define WM8985_ALCLVL_SHIFT 0 /* ALCLVL - [3:0] */
+#define WM8985_ALCLVL_WIDTH 4 /* ALCLVL - [3:0] */
+
+/*
+ * R34 (0x22) - ALC control 3
+ */
+#define WM8985_ALCMODE 0x0100 /* ALCMODE */
+#define WM8985_ALCMODE_MASK 0x0100 /* ALCMODE */
+#define WM8985_ALCMODE_SHIFT 8 /* ALCMODE */
+#define WM8985_ALCMODE_WIDTH 1 /* ALCMODE */
+#define WM8985_ALCDCY_MASK 0x00F0 /* ALCDCY - [7:4] */
+#define WM8985_ALCDCY_SHIFT 4 /* ALCDCY - [7:4] */
+#define WM8985_ALCDCY_WIDTH 4 /* ALCDCY - [7:4] */
+#define WM8985_ALCATK_MASK 0x000F /* ALCATK - [3:0] */
+#define WM8985_ALCATK_SHIFT 0 /* ALCATK - [3:0] */
+#define WM8985_ALCATK_WIDTH 4 /* ALCATK - [3:0] */
+
+/*
+ * R35 (0x23) - Noise Gate
+ */
+#define WM8985_NGEN 0x0008 /* NGEN */
+#define WM8985_NGEN_MASK 0x0008 /* NGEN */
+#define WM8985_NGEN_SHIFT 3 /* NGEN */
+#define WM8985_NGEN_WIDTH 1 /* NGEN */
+#define WM8985_NGTH_MASK 0x0007 /* NGTH - [2:0] */
+#define WM8985_NGTH_SHIFT 0 /* NGTH - [2:0] */
+#define WM8985_NGTH_WIDTH 3 /* NGTH - [2:0] */
+
+/*
+ * R36 (0x24) - PLL N
+ */
+#define WM8985_PLL_PRESCALE 0x0010 /* PLL_PRESCALE */
+#define WM8985_PLL_PRESCALE_MASK 0x0010 /* PLL_PRESCALE */
+#define WM8985_PLL_PRESCALE_SHIFT 4 /* PLL_PRESCALE */
+#define WM8985_PLL_PRESCALE_WIDTH 1 /* PLL_PRESCALE */
+#define WM8985_PLLN_MASK 0x000F /* PLLN - [3:0] */
+#define WM8985_PLLN_SHIFT 0 /* PLLN - [3:0] */
+#define WM8985_PLLN_WIDTH 4 /* PLLN - [3:0] */
+
+/*
+ * R37 (0x25) - PLL K 1
+ */
+#define WM8985_PLLK_23_18_MASK 0x003F /* PLLK(23:18) - [5:0] */
+#define WM8985_PLLK_23_18_SHIFT 0 /* PLLK(23:18) - [5:0] */
+#define WM8985_PLLK_23_18_WIDTH 6 /* PLLK(23:18) - [5:0] */
+
+/*
+ * R38 (0x26) - PLL K 2
+ */
+#define WM8985_PLLK_17_9_MASK 0x01FF /* PLLK(17:9) - [8:0] */
+#define WM8985_PLLK_17_9_SHIFT 0 /* PLLK(17:9) - [8:0] */
+#define WM8985_PLLK_17_9_WIDTH 9 /* PLLK(17:9) - [8:0] */
+
+/*
+ * R39 (0x27) - PLL K 3
+ */
+#define WM8985_PLLK_8_0_MASK 0x01FF /* PLLK(8:0) - [8:0] */
+#define WM8985_PLLK_8_0_SHIFT 0 /* PLLK(8:0) - [8:0] */
+#define WM8985_PLLK_8_0_WIDTH 9 /* PLLK(8:0) - [8:0] */
+
+/*
+ * R41 (0x29) - 3D control
+ */
+#define WM8985_DEPTH3D_MASK 0x000F /* DEPTH3D - [3:0] */
+#define WM8985_DEPTH3D_SHIFT 0 /* DEPTH3D - [3:0] */
+#define WM8985_DEPTH3D_WIDTH 4 /* DEPTH3D - [3:0] */
+
+/*
+ * R42 (0x2A) - OUT4 to ADC
+ */
+#define WM8985_OUT4_2ADCVOL_MASK 0x01C0 /* OUT4_2ADCVOL - [8:6] */
+#define WM8985_OUT4_2ADCVOL_SHIFT 6 /* OUT4_2ADCVOL - [8:6] */
+#define WM8985_OUT4_2ADCVOL_WIDTH 3 /* OUT4_2ADCVOL - [8:6] */
+#define WM8985_OUT4_2LNR 0x0020 /* OUT4_2LNR */
+#define WM8985_OUT4_2LNR_MASK 0x0020 /* OUT4_2LNR */
+#define WM8985_OUT4_2LNR_SHIFT 5 /* OUT4_2LNR */
+#define WM8985_OUT4_2LNR_WIDTH 1 /* OUT4_2LNR */
+#define WM8985_POBCTRL 0x0004 /* POBCTRL */
+#define WM8985_POBCTRL_MASK 0x0004 /* POBCTRL */
+#define WM8985_POBCTRL_SHIFT 2 /* POBCTRL */
+#define WM8985_POBCTRL_WIDTH 1 /* POBCTRL */
+#define WM8985_DELEN 0x0002 /* DELEN */
+#define WM8985_DELEN_MASK 0x0002 /* DELEN */
+#define WM8985_DELEN_SHIFT 1 /* DELEN */
+#define WM8985_DELEN_WIDTH 1 /* DELEN */
+#define WM8985_OUT1DEL 0x0001 /* OUT1DEL */
+#define WM8985_OUT1DEL_MASK 0x0001 /* OUT1DEL */
+#define WM8985_OUT1DEL_SHIFT 0 /* OUT1DEL */
+#define WM8985_OUT1DEL_WIDTH 1 /* OUT1DEL */
+
+/*
+ * R43 (0x2B) - Beep control
+ */
+#define WM8985_BYPL2RMIX 0x0100 /* BYPL2RMIX */
+#define WM8985_BYPL2RMIX_MASK 0x0100 /* BYPL2RMIX */
+#define WM8985_BYPL2RMIX_SHIFT 8 /* BYPL2RMIX */
+#define WM8985_BYPL2RMIX_WIDTH 1 /* BYPL2RMIX */
+#define WM8985_BYPR2LMIX 0x0080 /* BYPR2LMIX */
+#define WM8985_BYPR2LMIX_MASK 0x0080 /* BYPR2LMIX */
+#define WM8985_BYPR2LMIX_SHIFT 7 /* BYPR2LMIX */
+#define WM8985_BYPR2LMIX_WIDTH 1 /* BYPR2LMIX */
+#define WM8985_MUTERPGA2INV 0x0020 /* MUTERPGA2INV */
+#define WM8985_MUTERPGA2INV_MASK 0x0020 /* MUTERPGA2INV */
+#define WM8985_MUTERPGA2INV_SHIFT 5 /* MUTERPGA2INV */
+#define WM8985_MUTERPGA2INV_WIDTH 1 /* MUTERPGA2INV */
+#define WM8985_INVROUT2 0x0010 /* INVROUT2 */
+#define WM8985_INVROUT2_MASK 0x0010 /* INVROUT2 */
+#define WM8985_INVROUT2_SHIFT 4 /* INVROUT2 */
+#define WM8985_INVROUT2_WIDTH 1 /* INVROUT2 */
+#define WM8985_BEEPVOL_MASK 0x000E /* BEEPVOL - [3:1] */
+#define WM8985_BEEPVOL_SHIFT 1 /* BEEPVOL - [3:1] */
+#define WM8985_BEEPVOL_WIDTH 3 /* BEEPVOL - [3:1] */
+#define WM8985_BEEPEN 0x0001 /* BEEPEN */
+#define WM8985_BEEPEN_MASK 0x0001 /* BEEPEN */
+#define WM8985_BEEPEN_SHIFT 0 /* BEEPEN */
+#define WM8985_BEEPEN_WIDTH 1 /* BEEPEN */
+
+/*
+ * R44 (0x2C) - Input ctrl
+ */
+#define WM8985_MBVSEL 0x0100 /* MBVSEL */
+#define WM8985_MBVSEL_MASK 0x0100 /* MBVSEL */
+#define WM8985_MBVSEL_SHIFT 8 /* MBVSEL */
+#define WM8985_MBVSEL_WIDTH 1 /* MBVSEL */
+#define WM8985_R2_2INPPGA 0x0040 /* R2_2INPPGA */
+#define WM8985_R2_2INPPGA_MASK 0x0040 /* R2_2INPPGA */
+#define WM8985_R2_2INPPGA_SHIFT 6 /* R2_2INPPGA */
+#define WM8985_R2_2INPPGA_WIDTH 1 /* R2_2INPPGA */
+#define WM8985_RIN2INPPGA 0x0020 /* RIN2INPPGA */
+#define WM8985_RIN2INPPGA_MASK 0x0020 /* RIN2INPPGA */
+#define WM8985_RIN2INPPGA_SHIFT 5 /* RIN2INPPGA */
+#define WM8985_RIN2INPPGA_WIDTH 1 /* RIN2INPPGA */
+#define WM8985_RIP2INPPGA 0x0010 /* RIP2INPPGA */
+#define WM8985_RIP2INPPGA_MASK 0x0010 /* RIP2INPPGA */
+#define WM8985_RIP2INPPGA_SHIFT 4 /* RIP2INPPGA */
+#define WM8985_RIP2INPPGA_WIDTH 1 /* RIP2INPPGA */
+#define WM8985_L2_2INPPGA 0x0004 /* L2_2INPPGA */
+#define WM8985_L2_2INPPGA_MASK 0x0004 /* L2_2INPPGA */
+#define WM8985_L2_2INPPGA_SHIFT 2 /* L2_2INPPGA */
+#define WM8985_L2_2INPPGA_WIDTH 1 /* L2_2INPPGA */
+#define WM8985_LIN2INPPGA 0x0002 /* LIN2INPPGA */
+#define WM8985_LIN2INPPGA_MASK 0x0002 /* LIN2INPPGA */
+#define WM8985_LIN2INPPGA_SHIFT 1 /* LIN2INPPGA */
+#define WM8985_LIN2INPPGA_WIDTH 1 /* LIN2INPPGA */
+#define WM8985_LIP2INPPGA 0x0001 /* LIP2INPPGA */
+#define WM8985_LIP2INPPGA_MASK 0x0001 /* LIP2INPPGA */
+#define WM8985_LIP2INPPGA_SHIFT 0 /* LIP2INPPGA */
+#define WM8985_LIP2INPPGA_WIDTH 1 /* LIP2INPPGA */
+
+/*
+ * R45 (0x2D) - Left INP PGA gain ctrl
+ */
+#define WM8985_INPGAVU 0x0100 /* INPGAVU */
+#define WM8985_INPGAVU_MASK 0x0100 /* INPGAVU */
+#define WM8985_INPGAVU_SHIFT 8 /* INPGAVU */
+#define WM8985_INPGAVU_WIDTH 1 /* INPGAVU */
+#define WM8985_INPPGAZCL 0x0080 /* INPPGAZCL */
+#define WM8985_INPPGAZCL_MASK 0x0080 /* INPPGAZCL */
+#define WM8985_INPPGAZCL_SHIFT 7 /* INPPGAZCL */
+#define WM8985_INPPGAZCL_WIDTH 1 /* INPPGAZCL */
+#define WM8985_INPPGAMUTEL 0x0040 /* INPPGAMUTEL */
+#define WM8985_INPPGAMUTEL_MASK 0x0040 /* INPPGAMUTEL */
+#define WM8985_INPPGAMUTEL_SHIFT 6 /* INPPGAMUTEL */
+#define WM8985_INPPGAMUTEL_WIDTH 1 /* INPPGAMUTEL */
+#define WM8985_INPPGAVOLL_MASK 0x003F /* INPPGAVOLL - [5:0] */
+#define WM8985_INPPGAVOLL_SHIFT 0 /* INPPGAVOLL - [5:0] */
+#define WM8985_INPPGAVOLL_WIDTH 6 /* INPPGAVOLL - [5:0] */
+
+/*
+ * R46 (0x2E) - Right INP PGA gain ctrl
+ */
+#define WM8985_INPGAVU 0x0100 /* INPGAVU */
+#define WM8985_INPGAVU_MASK 0x0100 /* INPGAVU */
+#define WM8985_INPGAVU_SHIFT 8 /* INPGAVU */
+#define WM8985_INPGAVU_WIDTH 1 /* INPGAVU */
+#define WM8985_INPPGAZCR 0x0080 /* INPPGAZCR */
+#define WM8985_INPPGAZCR_MASK 0x0080 /* INPPGAZCR */
+#define WM8985_INPPGAZCR_SHIFT 7 /* INPPGAZCR */
+#define WM8985_INPPGAZCR_WIDTH 1 /* INPPGAZCR */
+#define WM8985_INPPGAMUTER 0x0040 /* INPPGAMUTER */
+#define WM8985_INPPGAMUTER_MASK 0x0040 /* INPPGAMUTER */
+#define WM8985_INPPGAMUTER_SHIFT 6 /* INPPGAMUTER */
+#define WM8985_INPPGAMUTER_WIDTH 1 /* INPPGAMUTER */
+#define WM8985_INPPGAVOLR_MASK 0x003F /* INPPGAVOLR - [5:0] */
+#define WM8985_INPPGAVOLR_SHIFT 0 /* INPPGAVOLR - [5:0] */
+#define WM8985_INPPGAVOLR_WIDTH 6 /* INPPGAVOLR - [5:0] */
+
+/*
+ * R47 (0x2F) - Left ADC BOOST ctrl
+ */
+#define WM8985_PGABOOSTL 0x0100 /* PGABOOSTL */
+#define WM8985_PGABOOSTL_MASK 0x0100 /* PGABOOSTL */
+#define WM8985_PGABOOSTL_SHIFT 8 /* PGABOOSTL */
+#define WM8985_PGABOOSTL_WIDTH 1 /* PGABOOSTL */
+#define WM8985_L2_2BOOSTVOL_MASK 0x0070 /* L2_2BOOSTVOL - [6:4] */
+#define WM8985_L2_2BOOSTVOL_SHIFT 4 /* L2_2BOOSTVOL - [6:4] */
+#define WM8985_L2_2BOOSTVOL_WIDTH 3 /* L2_2BOOSTVOL - [6:4] */
+#define WM8985_AUXL2BOOSTVOL_MASK 0x0007 /* AUXL2BOOSTVOL - [2:0] */
+#define WM8985_AUXL2BOOSTVOL_SHIFT 0 /* AUXL2BOOSTVOL - [2:0] */
+#define WM8985_AUXL2BOOSTVOL_WIDTH 3 /* AUXL2BOOSTVOL - [2:0] */
+
+/*
+ * R48 (0x30) - Right ADC BOOST ctrl
+ */
+#define WM8985_PGABOOSTR 0x0100 /* PGABOOSTR */
+#define WM8985_PGABOOSTR_MASK 0x0100 /* PGABOOSTR */
+#define WM8985_PGABOOSTR_SHIFT 8 /* PGABOOSTR */
+#define WM8985_PGABOOSTR_WIDTH 1 /* PGABOOSTR */
+#define WM8985_R2_2BOOSTVOL_MASK 0x0070 /* R2_2BOOSTVOL - [6:4] */
+#define WM8985_R2_2BOOSTVOL_SHIFT 4 /* R2_2BOOSTVOL - [6:4] */
+#define WM8985_R2_2BOOSTVOL_WIDTH 3 /* R2_2BOOSTVOL - [6:4] */
+#define WM8985_AUXR2BOOSTVOL_MASK 0x0007 /* AUXR2BOOSTVOL - [2:0] */
+#define WM8985_AUXR2BOOSTVOL_SHIFT 0 /* AUXR2BOOSTVOL - [2:0] */
+#define WM8985_AUXR2BOOSTVOL_WIDTH 3 /* AUXR2BOOSTVOL - [2:0] */
+
+/*
+ * R49 (0x31) - Output ctrl
+ */
+#define WM8985_DACL2RMIX 0x0040 /* DACL2RMIX */
+#define WM8985_DACL2RMIX_MASK 0x0040 /* DACL2RMIX */
+#define WM8985_DACL2RMIX_SHIFT 6 /* DACL2RMIX */
+#define WM8985_DACL2RMIX_WIDTH 1 /* DACL2RMIX */
+#define WM8985_DACR2LMIX 0x0020 /* DACR2LMIX */
+#define WM8985_DACR2LMIX_MASK 0x0020 /* DACR2LMIX */
+#define WM8985_DACR2LMIX_SHIFT 5 /* DACR2LMIX */
+#define WM8985_DACR2LMIX_WIDTH 1 /* DACR2LMIX */
+#define WM8985_OUT4BOOST 0x0010 /* OUT4BOOST */
+#define WM8985_OUT4BOOST_MASK 0x0010 /* OUT4BOOST */
+#define WM8985_OUT4BOOST_SHIFT 4 /* OUT4BOOST */
+#define WM8985_OUT4BOOST_WIDTH 1 /* OUT4BOOST */
+#define WM8985_OUT3BOOST 0x0008 /* OUT3BOOST */
+#define WM8985_OUT3BOOST_MASK 0x0008 /* OUT3BOOST */
+#define WM8985_OUT3BOOST_SHIFT 3 /* OUT3BOOST */
+#define WM8985_OUT3BOOST_WIDTH 1 /* OUT3BOOST */
+#define WM8985_TSOPCTRL 0x0004 /* TSOPCTRL */
+#define WM8985_TSOPCTRL_MASK 0x0004 /* TSOPCTRL */
+#define WM8985_TSOPCTRL_SHIFT 2 /* TSOPCTRL */
+#define WM8985_TSOPCTRL_WIDTH 1 /* TSOPCTRL */
+#define WM8985_TSDEN 0x0002 /* TSDEN */
+#define WM8985_TSDEN_MASK 0x0002 /* TSDEN */
+#define WM8985_TSDEN_SHIFT 1 /* TSDEN */
+#define WM8985_TSDEN_WIDTH 1 /* TSDEN */
+#define WM8985_VROI 0x0001 /* VROI */
+#define WM8985_VROI_MASK 0x0001 /* VROI */
+#define WM8985_VROI_SHIFT 0 /* VROI */
+#define WM8985_VROI_WIDTH 1 /* VROI */
+
+/*
+ * R50 (0x32) - Left mixer ctrl
+ */
+#define WM8985_AUXLMIXVOL_MASK 0x01C0 /* AUXLMIXVOL - [8:6] */
+#define WM8985_AUXLMIXVOL_SHIFT 6 /* AUXLMIXVOL - [8:6] */
+#define WM8985_AUXLMIXVOL_WIDTH 3 /* AUXLMIXVOL - [8:6] */
+#define WM8985_AUXL2LMIX 0x0020 /* AUXL2LMIX */
+#define WM8985_AUXL2LMIX_MASK 0x0020 /* AUXL2LMIX */
+#define WM8985_AUXL2LMIX_SHIFT 5 /* AUXL2LMIX */
+#define WM8985_AUXL2LMIX_WIDTH 1 /* AUXL2LMIX */
+#define WM8985_BYPLMIXVOL_MASK 0x001C /* BYPLMIXVOL - [4:2] */
+#define WM8985_BYPLMIXVOL_SHIFT 2 /* BYPLMIXVOL - [4:2] */
+#define WM8985_BYPLMIXVOL_WIDTH 3 /* BYPLMIXVOL - [4:2] */
+#define WM8985_BYPL2LMIX 0x0002 /* BYPL2LMIX */
+#define WM8985_BYPL2LMIX_MASK 0x0002 /* BYPL2LMIX */
+#define WM8985_BYPL2LMIX_SHIFT 1 /* BYPL2LMIX */
+#define WM8985_BYPL2LMIX_WIDTH 1 /* BYPL2LMIX */
+#define WM8985_DACL2LMIX 0x0001 /* DACL2LMIX */
+#define WM8985_DACL2LMIX_MASK 0x0001 /* DACL2LMIX */
+#define WM8985_DACL2LMIX_SHIFT 0 /* DACL2LMIX */
+#define WM8985_DACL2LMIX_WIDTH 1 /* DACL2LMIX */
+
+/*
+ * R51 (0x33) - Right mixer ctrl
+ */
+#define WM8985_AUXRMIXVOL_MASK 0x01C0 /* AUXRMIXVOL - [8:6] */
+#define WM8985_AUXRMIXVOL_SHIFT 6 /* AUXRMIXVOL - [8:6] */
+#define WM8985_AUXRMIXVOL_WIDTH 3 /* AUXRMIXVOL - [8:6] */
+#define WM8985_AUXR2RMIX 0x0020 /* AUXR2RMIX */
+#define WM8985_AUXR2RMIX_MASK 0x0020 /* AUXR2RMIX */
+#define WM8985_AUXR2RMIX_SHIFT 5 /* AUXR2RMIX */
+#define WM8985_AUXR2RMIX_WIDTH 1 /* AUXR2RMIX */
+#define WM8985_BYPRMIXVOL_MASK 0x001C /* BYPRMIXVOL - [4:2] */
+#define WM8985_BYPRMIXVOL_SHIFT 2 /* BYPRMIXVOL - [4:2] */
+#define WM8985_BYPRMIXVOL_WIDTH 3 /* BYPRMIXVOL - [4:2] */
+#define WM8985_BYPR2RMIX 0x0002 /* BYPR2RMIX */
+#define WM8985_BYPR2RMIX_MASK 0x0002 /* BYPR2RMIX */
+#define WM8985_BYPR2RMIX_SHIFT 1 /* BYPR2RMIX */
+#define WM8985_BYPR2RMIX_WIDTH 1 /* BYPR2RMIX */
+#define WM8985_DACR2RMIX 0x0001 /* DACR2RMIX */
+#define WM8985_DACR2RMIX_MASK 0x0001 /* DACR2RMIX */
+#define WM8985_DACR2RMIX_SHIFT 0 /* DACR2RMIX */
+#define WM8985_DACR2RMIX_WIDTH 1 /* DACR2RMIX */
+
+/*
+ * R52 (0x34) - LOUT1 (HP) volume ctrl
+ */
+#define WM8985_OUT1VU 0x0100 /* OUT1VU */
+#define WM8985_OUT1VU_MASK 0x0100 /* OUT1VU */
+#define WM8985_OUT1VU_SHIFT 8 /* OUT1VU */
+#define WM8985_OUT1VU_WIDTH 1 /* OUT1VU */
+#define WM8985_LOUT1ZC 0x0080 /* LOUT1ZC */
+#define WM8985_LOUT1ZC_MASK 0x0080 /* LOUT1ZC */
+#define WM8985_LOUT1ZC_SHIFT 7 /* LOUT1ZC */
+#define WM8985_LOUT1ZC_WIDTH 1 /* LOUT1ZC */
+#define WM8985_LOUT1MUTE 0x0040 /* LOUT1MUTE */
+#define WM8985_LOUT1MUTE_MASK 0x0040 /* LOUT1MUTE */
+#define WM8985_LOUT1MUTE_SHIFT 6 /* LOUT1MUTE */
+#define WM8985_LOUT1MUTE_WIDTH 1 /* LOUT1MUTE */
+#define WM8985_LOUT1VOL_MASK 0x003F /* LOUT1VOL - [5:0] */
+#define WM8985_LOUT1VOL_SHIFT 0 /* LOUT1VOL - [5:0] */
+#define WM8985_LOUT1VOL_WIDTH 6 /* LOUT1VOL - [5:0] */
+
+/*
+ * R53 (0x35) - ROUT1 (HP) volume ctrl
+ */
+#define WM8985_OUT1VU 0x0100 /* OUT1VU */
+#define WM8985_OUT1VU_MASK 0x0100 /* OUT1VU */
+#define WM8985_OUT1VU_SHIFT 8 /* OUT1VU */
+#define WM8985_OUT1VU_WIDTH 1 /* OUT1VU */
+#define WM8985_ROUT1ZC 0x0080 /* ROUT1ZC */
+#define WM8985_ROUT1ZC_MASK 0x0080 /* ROUT1ZC */
+#define WM8985_ROUT1ZC_SHIFT 7 /* ROUT1ZC */
+#define WM8985_ROUT1ZC_WIDTH 1 /* ROUT1ZC */
+#define WM8985_ROUT1MUTE 0x0040 /* ROUT1MUTE */
+#define WM8985_ROUT1MUTE_MASK 0x0040 /* ROUT1MUTE */
+#define WM8985_ROUT1MUTE_SHIFT 6 /* ROUT1MUTE */
+#define WM8985_ROUT1MUTE_WIDTH 1 /* ROUT1MUTE */
+#define WM8985_ROUT1VOL_MASK 0x003F /* ROUT1VOL - [5:0] */
+#define WM8985_ROUT1VOL_SHIFT 0 /* ROUT1VOL - [5:0] */
+#define WM8985_ROUT1VOL_WIDTH 6 /* ROUT1VOL - [5:0] */
+
+/*
+ * R54 (0x36) - LOUT2 (SPK) volume ctrl
+ */
+#define WM8985_OUT2VU 0x0100 /* OUT2VU */
+#define WM8985_OUT2VU_MASK 0x0100 /* OUT2VU */
+#define WM8985_OUT2VU_SHIFT 8 /* OUT2VU */
+#define WM8985_OUT2VU_WIDTH 1 /* OUT2VU */
+#define WM8985_LOUT2ZC 0x0080 /* LOUT2ZC */
+#define WM8985_LOUT2ZC_MASK 0x0080 /* LOUT2ZC */
+#define WM8985_LOUT2ZC_SHIFT 7 /* LOUT2ZC */
+#define WM8985_LOUT2ZC_WIDTH 1 /* LOUT2ZC */
+#define WM8985_LOUT2MUTE 0x0040 /* LOUT2MUTE */
+#define WM8985_LOUT2MUTE_MASK 0x0040 /* LOUT2MUTE */
+#define WM8985_LOUT2MUTE_SHIFT 6 /* LOUT2MUTE */
+#define WM8985_LOUT2MUTE_WIDTH 1 /* LOUT2MUTE */
+#define WM8985_LOUT2VOL_MASK 0x003F /* LOUT2VOL - [5:0] */
+#define WM8985_LOUT2VOL_SHIFT 0 /* LOUT2VOL - [5:0] */
+#define WM8985_LOUT2VOL_WIDTH 6 /* LOUT2VOL - [5:0] */
+
+/*
+ * R55 (0x37) - ROUT2 (SPK) volume ctrl
+ */
+#define WM8985_OUT2VU 0x0100 /* OUT2VU */
+#define WM8985_OUT2VU_MASK 0x0100 /* OUT2VU */
+#define WM8985_OUT2VU_SHIFT 8 /* OUT2VU */
+#define WM8985_OUT2VU_WIDTH 1 /* OUT2VU */
+#define WM8985_ROUT2ZC 0x0080 /* ROUT2ZC */
+#define WM8985_ROUT2ZC_MASK 0x0080 /* ROUT2ZC */
+#define WM8985_ROUT2ZC_SHIFT 7 /* ROUT2ZC */
+#define WM8985_ROUT2ZC_WIDTH 1 /* ROUT2ZC */
+#define WM8985_ROUT2MUTE 0x0040 /* ROUT2MUTE */
+#define WM8985_ROUT2MUTE_MASK 0x0040 /* ROUT2MUTE */
+#define WM8985_ROUT2MUTE_SHIFT 6 /* ROUT2MUTE */
+#define WM8985_ROUT2MUTE_WIDTH 1 /* ROUT2MUTE */
+#define WM8985_ROUT2VOL_MASK 0x003F /* ROUT2VOL - [5:0] */
+#define WM8985_ROUT2VOL_SHIFT 0 /* ROUT2VOL - [5:0] */
+#define WM8985_ROUT2VOL_WIDTH 6 /* ROUT2VOL - [5:0] */
+
+/*
+ * R56 (0x38) - OUT3 mixer ctrl
+ */
+#define WM8985_OUT3MUTE 0x0040 /* OUT3MUTE */
+#define WM8985_OUT3MUTE_MASK 0x0040 /* OUT3MUTE */
+#define WM8985_OUT3MUTE_SHIFT 6 /* OUT3MUTE */
+#define WM8985_OUT3MUTE_WIDTH 1 /* OUT3MUTE */
+#define WM8985_OUT4_2OUT3 0x0008 /* OUT4_2OUT3 */
+#define WM8985_OUT4_2OUT3_MASK 0x0008 /* OUT4_2OUT3 */
+#define WM8985_OUT4_2OUT3_SHIFT 3 /* OUT4_2OUT3 */
+#define WM8985_OUT4_2OUT3_WIDTH 1 /* OUT4_2OUT3 */
+#define WM8985_BYPL2OUT3 0x0004 /* BYPL2OUT3 */
+#define WM8985_BYPL2OUT3_MASK 0x0004 /* BYPL2OUT3 */
+#define WM8985_BYPL2OUT3_SHIFT 2 /* BYPL2OUT3 */
+#define WM8985_BYPL2OUT3_WIDTH 1 /* BYPL2OUT3 */
+#define WM8985_LMIX2OUT3 0x0002 /* LMIX2OUT3 */
+#define WM8985_LMIX2OUT3_MASK 0x0002 /* LMIX2OUT3 */
+#define WM8985_LMIX2OUT3_SHIFT 1 /* LMIX2OUT3 */
+#define WM8985_LMIX2OUT3_WIDTH 1 /* LMIX2OUT3 */
+#define WM8985_LDAC2OUT3 0x0001 /* LDAC2OUT3 */
+#define WM8985_LDAC2OUT3_MASK 0x0001 /* LDAC2OUT3 */
+#define WM8985_LDAC2OUT3_SHIFT 0 /* LDAC2OUT3 */
+#define WM8985_LDAC2OUT3_WIDTH 1 /* LDAC2OUT3 */
+
+/*
+ * R57 (0x39) - OUT4 (MONO) mix ctrl
+ */
+#define WM8985_OUT3_2OUT4 0x0080 /* OUT3_2OUT4 */
+#define WM8985_OUT3_2OUT4_MASK 0x0080 /* OUT3_2OUT4 */
+#define WM8985_OUT3_2OUT4_SHIFT 7 /* OUT3_2OUT4 */
+#define WM8985_OUT3_2OUT4_WIDTH 1 /* OUT3_2OUT4 */
+#define WM8985_OUT4MUTE 0x0040 /* OUT4MUTE */
+#define WM8985_OUT4MUTE_MASK 0x0040 /* OUT4MUTE */
+#define WM8985_OUT4MUTE_SHIFT 6 /* OUT4MUTE */
+#define WM8985_OUT4MUTE_WIDTH 1 /* OUT4MUTE */
+#define WM8985_OUT4ATTN 0x0020 /* OUT4ATTN */
+#define WM8985_OUT4ATTN_MASK 0x0020 /* OUT4ATTN */
+#define WM8985_OUT4ATTN_SHIFT 5 /* OUT4ATTN */
+#define WM8985_OUT4ATTN_WIDTH 1 /* OUT4ATTN */
+#define WM8985_LMIX2OUT4 0x0010 /* LMIX2OUT4 */
+#define WM8985_LMIX2OUT4_MASK 0x0010 /* LMIX2OUT4 */
+#define WM8985_LMIX2OUT4_SHIFT 4 /* LMIX2OUT4 */
+#define WM8985_LMIX2OUT4_WIDTH 1 /* LMIX2OUT4 */
+#define WM8985_LDAC2OUT4 0x0008 /* LDAC2OUT4 */
+#define WM8985_LDAC2OUT4_MASK 0x0008 /* LDAC2OUT4 */
+#define WM8985_LDAC2OUT4_SHIFT 3 /* LDAC2OUT4 */
+#define WM8985_LDAC2OUT4_WIDTH 1 /* LDAC2OUT4 */
+#define WM8985_BYPR2OUT4 0x0004 /* BYPR2OUT4 */
+#define WM8985_BYPR2OUT4_MASK 0x0004 /* BYPR2OUT4 */
+#define WM8985_BYPR2OUT4_SHIFT 2 /* BYPR2OUT4 */
+#define WM8985_BYPR2OUT4_WIDTH 1 /* BYPR2OUT4 */
+#define WM8985_RMIX2OUT4 0x0002 /* RMIX2OUT4 */
+#define WM8985_RMIX2OUT4_MASK 0x0002 /* RMIX2OUT4 */
+#define WM8985_RMIX2OUT4_SHIFT 1 /* RMIX2OUT4 */
+#define WM8985_RMIX2OUT4_WIDTH 1 /* RMIX2OUT4 */
+#define WM8985_RDAC2OUT4 0x0001 /* RDAC2OUT4 */
+#define WM8985_RDAC2OUT4_MASK 0x0001 /* RDAC2OUT4 */
+#define WM8985_RDAC2OUT4_SHIFT 0 /* RDAC2OUT4 */
+#define WM8985_RDAC2OUT4_WIDTH 1 /* RDAC2OUT4 */
+
+/*
+ * R60 (0x3C) - OUTPUT ctrl
+ */
+#define WM8985_VIDBUFFTST_MASK 0x01E0 /* VIDBUFFTST - [8:5] */
+#define WM8985_VIDBUFFTST_SHIFT 5 /* VIDBUFFTST - [8:5] */
+#define WM8985_VIDBUFFTST_WIDTH 4 /* VIDBUFFTST - [8:5] */
+#define WM8985_HPTOG 0x0008 /* HPTOG */
+#define WM8985_HPTOG_MASK 0x0008 /* HPTOG */
+#define WM8985_HPTOG_SHIFT 3 /* HPTOG */
+#define WM8985_HPTOG_WIDTH 1 /* HPTOG */
+
+/*
+ * R61 (0x3D) - BIAS CTRL
+ */
+#define WM8985_BIASCUT 0x0100 /* BIASCUT */
+#define WM8985_BIASCUT_MASK 0x0100 /* BIASCUT */
+#define WM8985_BIASCUT_SHIFT 8 /* BIASCUT */
+#define WM8985_BIASCUT_WIDTH 1 /* BIASCUT */
+#define WM8985_HALFIPBIAS 0x0080 /* HALFIPBIAS */
+#define WM8985_HALFIPBIAS_MASK 0x0080 /* HALFIPBIAS */
+#define WM8985_HALFIPBIAS_SHIFT 7 /* HALFIPBIAS */
+#define WM8985_HALFIPBIAS_WIDTH 1 /* HALFIPBIAS */
+#define WM8985_VBBIASTST_MASK 0x0060 /* VBBIASTST - [6:5] */
+#define WM8985_VBBIASTST_SHIFT 5 /* VBBIASTST - [6:5] */
+#define WM8985_VBBIASTST_WIDTH 2 /* VBBIASTST - [6:5] */
+#define WM8985_BUFBIAS_MASK 0x0018 /* BUFBIAS - [4:3] */
+#define WM8985_BUFBIAS_SHIFT 3 /* BUFBIAS - [4:3] */
+#define WM8985_BUFBIAS_WIDTH 2 /* BUFBIAS - [4:3] */
+#define WM8985_ADCBIAS_MASK 0x0006 /* ADCBIAS - [2:1] */
+#define WM8985_ADCBIAS_SHIFT 1 /* ADCBIAS - [2:1] */
+#define WM8985_ADCBIAS_WIDTH 2 /* ADCBIAS - [2:1] */
+#define WM8985_HALFOPBIAS 0x0001 /* HALFOPBIAS */
+#define WM8985_HALFOPBIAS_MASK 0x0001 /* HALFOPBIAS */
+#define WM8985_HALFOPBIAS_SHIFT 0 /* HALFOPBIAS */
+#define WM8985_HALFOPBIAS_WIDTH 1 /* HALFOPBIAS */
+
+enum clk_src {
+ WM8985_CLKSRC_MCLK,
+ WM8985_CLKSRC_PLL
+};
+
+#define WM8985_PLL 0
+
+#endif
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
index 19ad590..d7f2597 100644
--- a/sound/soc/codecs/wm8988.c
+++ b/sound/soc/codecs/wm8988.c
@@ -52,7 +52,7 @@
/* codec private data */
struct wm8988_priv {
unsigned int sysclk;
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
struct snd_pcm_hw_constraint_list *sysclk_constraints;
u16 reg_cache[WM8988_NUM_REG];
};
@@ -608,8 +608,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
u16 iface = snd_soc_read(codec, WM8988_IFACE) & 0x1f3;
u16 srate = snd_soc_read(codec, WM8988_SRATE) & 0x180;
@@ -711,8 +710,8 @@
.digital_mute = wm8988_mute,
};
-struct snd_soc_dai wm8988_dai = {
- .name = "WM8988",
+static struct snd_soc_dai_driver wm8988_dai = {
+ .name = "wm8988-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -730,21 +729,15 @@
.ops = &wm8988_ops,
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(wm8988_dai);
-static int wm8988_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8988_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8988_resume(struct platform_device *pdev)
+static int wm8988_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -763,99 +756,22 @@
return 0;
}
-static struct snd_soc_codec *wm8988_codec;
-
-static int wm8988_probe(struct platform_device *pdev)
+static int wm8988_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
+ struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
-
- if (wm8988_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8988_codec;
- codec = wm8988_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- snd_soc_add_controls(codec, wm8988_snd_controls,
- ARRAY_SIZE(wm8988_snd_controls));
- snd_soc_dapm_new_controls(codec, wm8988_dapm_widgets,
- ARRAY_SIZE(wm8988_dapm_widgets));
- snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
-
- return ret;
-
-pcm_err:
- return ret;
-}
-
-static int wm8988_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8988 = {
- .probe = wm8988_probe,
- .remove = wm8988_remove,
- .suspend = wm8988_suspend,
- .resume = wm8988_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8988);
-
-static int wm8988_register(struct wm8988_priv *wm8988,
- enum snd_soc_control_type control)
-{
- struct snd_soc_codec *codec = &wm8988->codec;
- int ret;
u16 reg;
- if (wm8988_codec) {
- dev_err(codec->dev, "Another WM8988 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8988);
- codec->name = "WM8988";
- codec->owner = THIS_MODULE;
- codec->dai = &wm8988_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(wm8988->reg_cache);
- codec->reg_cache = &wm8988->reg_cache;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8988_set_bias_level;
-
- memcpy(codec->reg_cache, wm8988_reg,
- sizeof(wm8988_reg));
-
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8988->control_type);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
ret = wm8988_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
- goto err;
+ return ret;
}
/* set the update bits (we always update left then right) */
@@ -870,67 +786,96 @@
reg = snd_soc_read(codec, WM8988_RINVOL);
snd_soc_write(codec, WM8988_RINVOL, reg | 0x0100);
- wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_STANDBY);
+ wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- wm8988_dai.dev = codec->dev;
-
- wm8988_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dai(&wm8988_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
+ snd_soc_add_controls(codec, wm8988_snd_controls,
+ ARRAY_SIZE(wm8988_snd_controls));
+ snd_soc_dapm_new_controls(codec, wm8988_dapm_widgets,
+ ARRAY_SIZE(wm8988_dapm_widgets));
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- kfree(wm8988);
- return ret;
}
-static void wm8988_unregister(struct wm8988_priv *wm8988)
+static int wm8988_remove(struct snd_soc_codec *codec)
{
- wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dai(&wm8988_dai);
- snd_soc_unregister_codec(&wm8988->codec);
- kfree(wm8988);
- wm8988_codec = NULL;
+ wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
}
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-static int wm8988_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static struct snd_soc_codec_driver soc_codec_dev_wm8988 = {
+ .probe = wm8988_probe,
+ .remove = wm8988_remove,
+ .suspend = wm8988_suspend,
+ .resume = wm8988_resume,
+ .set_bias_level = wm8988_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8988_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8988_reg,
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8988_spi_probe(struct spi_device *spi)
{
struct wm8988_priv *wm8988;
- struct snd_soc_codec *codec;
+ int ret;
wm8988 = kzalloc(sizeof(struct wm8988_priv), GFP_KERNEL);
if (wm8988 == NULL)
return -ENOMEM;
- codec = &wm8988->codec;
+ wm8988->control_type = SND_SOC_SPI;
+ spi_set_drvdata(spi, wm8988);
- i2c_set_clientdata(i2c, wm8988);
- codec->control_data = i2c;
-
- codec->dev = &i2c->dev;
-
- return wm8988_register(wm8988, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_wm8988, &wm8988_dai, 1);
+ if (ret < 0)
+ kfree(wm8988);
+ return ret;
}
-static int wm8988_i2c_remove(struct i2c_client *client)
+static int __devexit wm8988_spi_remove(struct spi_device *spi)
{
- struct wm8988_priv *wm8988 = i2c_get_clientdata(client);
- wm8988_unregister(wm8988);
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
+ return 0;
+}
+
+static struct spi_driver wm8988_spi_driver = {
+ .driver = {
+ .name = "wm8988-codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8988_spi_probe,
+ .remove = __devexit_p(wm8988_spi_remove),
+};
+#endif /* CONFIG_SPI_MASTER */
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8988_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8988_priv *wm8988;
+ int ret;
+
+ wm8988 = kzalloc(sizeof(struct wm8988_priv), GFP_KERNEL);
+ if (wm8988 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, wm8988);
+ wm8988->control_type = SND_SOC_I2C;
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8988, &wm8988_dai, 1);
+ if (ret < 0)
+ kfree(wm8988);
+ return ret;
+}
+
+static __devexit int wm8988_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -942,67 +887,31 @@
static struct i2c_driver wm8988_i2c_driver = {
.driver = {
- .name = "WM8988",
+ .name = "wm8988-codec",
.owner = THIS_MODULE,
},
- .probe = wm8988_i2c_probe,
- .remove = wm8988_i2c_remove,
+ .probe = wm8988_i2c_probe,
+ .remove = __devexit_p(wm8988_i2c_remove),
.id_table = wm8988_i2c_id,
};
#endif
-#if defined(CONFIG_SPI_MASTER)
-static int __devinit wm8988_spi_probe(struct spi_device *spi)
-{
- struct wm8988_priv *wm8988;
- struct snd_soc_codec *codec;
-
- wm8988 = kzalloc(sizeof(struct wm8988_priv), GFP_KERNEL);
- if (wm8988 == NULL)
- return -ENOMEM;
-
- codec = &wm8988->codec;
- codec->control_data = spi;
- codec->dev = &spi->dev;
-
- dev_set_drvdata(&spi->dev, wm8988);
-
- return wm8988_register(wm8988, SND_SOC_SPI);
-}
-
-static int __devexit wm8988_spi_remove(struct spi_device *spi)
-{
- struct wm8988_priv *wm8988 = dev_get_drvdata(&spi->dev);
-
- wm8988_unregister(wm8988);
-
- return 0;
-}
-
-static struct spi_driver wm8988_spi_driver = {
- .driver = {
- .name = "wm8988",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
- },
- .probe = wm8988_spi_probe,
- .remove = __devexit_p(wm8988_spi_remove),
-};
-#endif
-
static int __init wm8988_modinit(void)
{
- int ret;
-
+ int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8988_i2c_driver);
- if (ret != 0)
- pr_err("WM8988: Unable to register I2C driver: %d\n", ret);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register WM8988 I2C driver: %d\n",
+ ret);
+ }
#endif
#if defined(CONFIG_SPI_MASTER)
ret = spi_register_driver(&wm8988_spi_driver);
- if (ret != 0)
- pr_err("WM8988: Unable to register SPI driver: %d\n", ret);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register WM8988 SPI driver: %d\n",
+ ret);
+ }
#endif
return ret;
}
diff --git a/sound/soc/codecs/wm8988.h b/sound/soc/codecs/wm8988.h
index 4552d37..5c04024 100644
--- a/sound/soc/codecs/wm8988.h
+++ b/sound/soc/codecs/wm8988.h
@@ -54,7 +54,4 @@
#define WM8988_SYSCLK 0
-extern struct snd_soc_dai wm8988_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8988;
-
#endif
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index dd8d909..264828e 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -32,6 +32,7 @@
/* codec private data */
struct wm8990_priv {
+ enum snd_soc_control_type control_type;
unsigned int sysclk;
unsigned int pcmclk;
};
@@ -1114,8 +1115,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
u16 audio1 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_1);
audio1 &= ~WM8990_AIF_WL_MASK;
@@ -1293,10 +1293,9 @@
.set_sysclk = wm8990_set_dai_sysclk,
};
-struct snd_soc_dai wm8990_dai = {
+static struct snd_soc_dai_driver wm8990_dai = {
/* ADC/DAC on primary */
- .name = "WM8990 ADC/DAC Primary",
- .id = 1,
+ .name = "wm8990-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -1311,21 +1310,15 @@
.formats = WM8990_FORMATS,},
.ops = &wm8990_dai_ops,
};
-EXPORT_SYMBOL_GPL(wm8990_dai);
-static int wm8990_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8990_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8990_resume(struct platform_device *pdev)
+static int wm8990_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -1347,40 +1340,20 @@
* initialise the WM8990 driver
* register the mixer and dsp interfaces with the kernel
*/
-static int wm8990_init(struct snd_soc_device *socdev)
+static int wm8990_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = socdev->card->codec;
+ int ret;
u16 reg;
- int ret = 0;
-
- codec->name = "WM8990";
- codec->owner = THIS_MODULE;
- codec->set_bias_level = wm8990_set_bias_level;
- codec->dai = &wm8990_dai;
- codec->num_dai = 2;
- codec->reg_cache_size = ARRAY_SIZE(wm8990_reg);
- codec->reg_cache = kmemdup(wm8990_reg, sizeof(wm8990_reg), GFP_KERNEL);
-
- if (codec->reg_cache == NULL)
- return -ENOMEM;
ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
if (ret < 0) {
printk(KERN_ERR "wm8990: failed to set cache I/O: %d\n", ret);
- goto pcm_err;
+ return ret;
}
wm8990_reset(codec);
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "wm8990: failed to create pcms\n");
- goto pcm_err;
- }
-
/* charge output caps */
- codec->bias_level = SND_SOC_BIAS_OFF;
wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
reg = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_4);
@@ -1400,47 +1373,51 @@
ARRAY_SIZE(wm8990_snd_controls));
wm8990_add_widgets(codec);
- return ret;
-
-pcm_err:
- kfree(codec->reg_cache);
- return ret;
+ return 0;
}
-/* If the i2c layer weren't so broken, we could pass this kind of data
- around */
-static struct snd_soc_device *wm8990_socdev;
+/* power down chip */
+static int wm8990_remove(struct snd_soc_codec *codec)
+{
+ wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8990 = {
+ .probe = wm8990_probe,
+ .remove = wm8990_remove,
+ .suspend = wm8990_suspend,
+ .resume = wm8990_resume,
+ .set_bias_level = wm8990_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8990_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8990_reg,
+};
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-
-/*
- * WM891 2 wire address is determined by GPIO5
- * state during powerup.
- * low = 0x34
- * high = 0x36
- */
-
-static int wm8990_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static __devinit int wm8990_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
{
- struct snd_soc_device *socdev = wm8990_socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct wm8990_priv *wm8990;
int ret;
- i2c_set_clientdata(i2c, codec);
- codec->control_data = i2c;
+ wm8990 = kzalloc(sizeof(struct wm8990_priv), GFP_KERNEL);
+ if (wm8990 == NULL)
+ return -ENOMEM;
- ret = wm8990_init(socdev);
+ i2c_set_clientdata(i2c, wm8990);
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8990, &wm8990_dai, 1);
if (ret < 0)
- pr_err("failed to initialise WM8990\n");
-
+ kfree(wm8990);
return ret;
}
-static int wm8990_i2c_remove(struct i2c_client *client)
+static __devexit int wm8990_i2c_remove(struct i2c_client *client)
{
- struct snd_soc_codec *codec = i2c_get_clientdata(client);
- kfree(codec->reg_cache);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -1452,134 +1429,34 @@
static struct i2c_driver wm8990_i2c_driver = {
.driver = {
- .name = "WM8990 I2C Codec",
+ .name = "wm8990-codec",
.owner = THIS_MODULE,
},
.probe = wm8990_i2c_probe,
- .remove = wm8990_i2c_remove,
+ .remove = __devexit_p(wm8990_i2c_remove),
.id_table = wm8990_i2c_id,
};
-
-static int wm8990_add_i2c_device(struct platform_device *pdev,
- const struct wm8990_setup_data *setup)
-{
- struct i2c_board_info info;
- struct i2c_adapter *adapter;
- struct i2c_client *client;
- int ret;
-
- ret = i2c_add_driver(&wm8990_i2c_driver);
- if (ret != 0) {
- dev_err(&pdev->dev, "can't add i2c driver\n");
- return ret;
- }
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = setup->i2c_address;
- strlcpy(info.type, "wm8990", I2C_NAME_SIZE);
-
- adapter = i2c_get_adapter(setup->i2c_bus);
- if (!adapter) {
- dev_err(&pdev->dev, "can't get i2c adapter %d\n",
- setup->i2c_bus);
- goto err_driver;
- }
-
- client = i2c_new_device(adapter, &info);
- i2c_put_adapter(adapter);
- if (!client) {
- dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
- (unsigned int)info.addr);
- goto err_driver;
- }
-
- return 0;
-
-err_driver:
- i2c_del_driver(&wm8990_i2c_driver);
- return -ENODEV;
-}
#endif
-static int wm8990_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct wm8990_setup_data *setup;
- struct snd_soc_codec *codec;
- struct wm8990_priv *wm8990;
- int ret;
-
- setup = socdev->codec_data;
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
-
- wm8990 = kzalloc(sizeof(struct wm8990_priv), GFP_KERNEL);
- if (wm8990 == NULL) {
- kfree(codec);
- return -ENOMEM;
- }
-
- snd_soc_codec_set_drvdata(codec, wm8990);
- socdev->card->codec = codec;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
- wm8990_socdev = socdev;
-
- ret = -ENODEV;
-
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- if (setup->i2c_address) {
- codec->hw_write = (hw_write_t)i2c_master_send;
- ret = wm8990_add_i2c_device(pdev, setup);
- }
-#endif
-
- if (ret != 0) {
- kfree(snd_soc_codec_get_drvdata(codec));
- kfree(codec);
- }
- return ret;
-}
-
-/* power down chip */
-static int wm8990_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec->control_data)
- wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF);
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- i2c_unregister_device(codec->control_data);
- i2c_del_driver(&wm8990_i2c_driver);
-#endif
- kfree(snd_soc_codec_get_drvdata(codec));
- kfree(codec);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8990 = {
- .probe = wm8990_probe,
- .remove = wm8990_remove,
- .suspend = wm8990_suspend,
- .resume = wm8990_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8990);
-
static int __init wm8990_modinit(void)
{
- return snd_soc_register_dai(&wm8990_dai);
+ int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8990_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8990 I2C driver: %d\n",
+ ret);
+ }
+#endif
+ return ret;
}
module_init(wm8990_modinit);
static void __exit wm8990_exit(void)
{
- snd_soc_unregister_dai(&wm8990_dai);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&wm8990_i2c_driver);
+#endif
}
module_exit(wm8990_exit);
diff --git a/sound/soc/codecs/wm8990.h b/sound/soc/codecs/wm8990.h
index 7114ddc..77c98a4 100644
--- a/sound/soc/codecs/wm8990.h
+++ b/sound/soc/codecs/wm8990.h
@@ -826,18 +826,10 @@
#define WM8990_INMIXR_PWR_BIT 2
#define WM8990_AINRMUX_PWR_BIT 3
-struct wm8990_setup_data {
- unsigned i2c_bus;
- unsigned short i2c_address;
-};
-
#define WM8990_MCLK_DIV 0
#define WM8990_DACCLK_DIV 1
#define WM8990_ADCCLK_DIV 2
#define WM8990_BCLK_DIV 3
-extern struct snd_soc_dai wm8990_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8990;
-
#endif /* __WM8990REGISTERDEFS_H__ */
/*------------------------------ END OF FILE ---------------------------------*/
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index d8d300c..589e3fa 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -229,7 +229,7 @@
u16 reg_cache[WM8993_REGISTER_COUNT];
struct regulator_bulk_data supplies[WM8993_NUM_SUPPLIES];
struct wm8993_platform_data pdata;
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
int master;
int sysclk_source;
int tdm_slots;
@@ -367,10 +367,9 @@
return 0;
}
-static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
+static int _wm8993_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
unsigned int Fref, unsigned int Fout)
{
- struct snd_soc_codec *codec = dai->codec;
struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
u16 reg1, reg4, reg5;
struct _fll_div fll_div;
@@ -456,6 +455,12 @@
return 0;
}
+static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
+ unsigned int Fref, unsigned int Fout)
+{
+ return _wm8993_set_fll(dai->codec, fll_id, source, Fref, Fout);
+}
+
static int configure_clock(struct snd_soc_codec *codec)
{
struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
@@ -1394,8 +1399,8 @@
SNDRV_PCM_FMTBIT_S24_LE |\
SNDRV_PCM_FMTBIT_S32_LE)
-struct snd_soc_dai wm8993_dai = {
- .name = "WM8993",
+static struct snd_soc_dai_driver wm8993_dai = {
+ .name = "wm8993-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -1413,184 +1418,21 @@
.ops = &wm8993_ops,
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(wm8993_dai);
-static struct snd_soc_codec *wm8993_codec;
-
-static int wm8993_probe(struct platform_device *pdev)
+static int wm8993_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- struct wm8993_priv *wm8993;
- int ret = 0;
-
- if (!wm8993_codec) {
- dev_err(&pdev->dev, "I2C device not yet probed\n");
- goto err;
- }
-
- socdev->card->codec = wm8993_codec;
- codec = wm8993_codec;
- wm8993 = snd_soc_codec_get_drvdata(codec);
-
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms\n");
- goto err;
- }
-
- snd_soc_add_controls(codec, wm8993_snd_controls,
- ARRAY_SIZE(wm8993_snd_controls));
- if (wm8993->pdata.num_retune_configs != 0) {
- dev_dbg(codec->dev, "Using ReTune Mobile\n");
- } else {
- dev_dbg(codec->dev, "No ReTune Mobile, using normal EQ\n");
- snd_soc_add_controls(codec, wm8993_eq_controls,
- ARRAY_SIZE(wm8993_eq_controls));
- }
-
- snd_soc_dapm_new_controls(codec, wm8993_dapm_widgets,
- ARRAY_SIZE(wm8993_dapm_widgets));
- wm_hubs_add_analogue_controls(codec);
-
- snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes));
- wm_hubs_add_analogue_routes(codec, wm8993->pdata.lineout1_diff,
- wm8993->pdata.lineout2_diff);
-
- return ret;
-
-err:
- return ret;
-}
-
-static int wm8993_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int wm8993_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
- int fll_fout = wm8993->fll_fout;
- int fll_fref = wm8993->fll_fref;
- int ret;
-
- /* Stop the FLL in an orderly fashion */
- ret = wm8993_set_fll(codec->dai, 0, 0, 0, 0);
- if (ret != 0) {
- dev_err(&pdev->dev, "Failed to stop FLL\n");
- return ret;
- }
-
- wm8993->fll_fout = fll_fout;
- wm8993->fll_fref = fll_fref;
-
- wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- return 0;
-}
-
-static int wm8993_resume(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
- struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
- int ret;
-
- wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- /* Restart the FLL? */
- if (wm8993->fll_fout) {
- int fll_fout = wm8993->fll_fout;
- int fll_fref = wm8993->fll_fref;
-
- wm8993->fll_fref = 0;
- wm8993->fll_fout = 0;
-
- ret = wm8993_set_fll(codec->dai, 0, wm8993->fll_src,
- fll_fref, fll_fout);
- if (ret != 0)
- dev_err(codec->dev, "Failed to restart FLL\n");
- }
-
- return 0;
-}
-#else
-#define wm8993_suspend NULL
-#define wm8993_resume NULL
-#endif
-
-struct snd_soc_codec_device soc_codec_dev_wm8993 = {
- .probe = wm8993_probe,
- .remove = wm8993_remove,
- .suspend = wm8993_suspend,
- .resume = wm8993_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8993);
-
-static int wm8993_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
-{
- struct wm8993_priv *wm8993;
- struct snd_soc_codec *codec;
- unsigned int val;
- int ret;
- int i;
-
- if (wm8993_codec) {
- dev_err(&i2c->dev, "A WM8993 is already registered\n");
- return -EINVAL;
- }
-
- wm8993 = kzalloc(sizeof(struct wm8993_priv), GFP_KERNEL);
- if (wm8993 == NULL)
- return -ENOMEM;
-
- codec = &wm8993->codec;
- if (i2c->dev.platform_data)
- memcpy(&wm8993->pdata, i2c->dev.platform_data,
- sizeof(wm8993->pdata));
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->name = "WM8993";
- codec->volatile_register = wm8993_volatile;
- codec->reg_cache = wm8993->reg_cache;
- codec->reg_cache_size = ARRAY_SIZE(wm8993->reg_cache);
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8993_set_bias_level;
- codec->dai = &wm8993_dai;
- codec->num_dai = 1;
- snd_soc_codec_set_drvdata(codec, wm8993);
+ int ret, i, val;
wm8993->hubs_data.hp_startup_mode = 1;
wm8993->hubs_data.dcs_codes = -2;
- memcpy(wm8993->reg_cache, wm8993_reg_defaults,
- sizeof(wm8993->reg_cache));
-
ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
- i2c_set_clientdata(i2c, wm8993);
- codec->control_data = i2c;
- wm8993_codec = codec;
-
- codec->dev = &i2c->dev;
-
for (i = 0; i < ARRAY_SIZE(wm8993->supplies); i++)
wm8993->supplies[i].supply = wm8993_supply_names[i];
@@ -1598,7 +1440,7 @@
wm8993->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
- goto err;
+ return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies),
@@ -1646,44 +1488,134 @@
wm8993->pdata.jd_thr,
wm8993->pdata.micbias1_lvl,
wm8993->pdata.micbias2_lvl);
-
+
ret = wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
if (ret != 0)
goto err_enable;
- wm8993_dai.dev = codec->dev;
+ snd_soc_add_controls(codec, wm8993_snd_controls,
+ ARRAY_SIZE(wm8993_snd_controls));
+ if (wm8993->pdata.num_retune_configs != 0) {
+ dev_dbg(codec->dev, "Using ReTune Mobile\n");
+ } else {
+ dev_dbg(codec->dev, "No ReTune Mobile, using normal EQ\n");
+ snd_soc_add_controls(codec, wm8993_eq_controls,
+ ARRAY_SIZE(wm8993_eq_controls));
+ }
- ret = snd_soc_register_dai(&wm8993_dai);
- if (ret != 0)
- goto err_bias;
+ snd_soc_dapm_new_controls(codec, wm8993_dapm_widgets,
+ ARRAY_SIZE(wm8993_dapm_widgets));
+ wm_hubs_add_analogue_controls(codec);
- ret = snd_soc_register_codec(codec);
+ snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes));
+ wm_hubs_add_analogue_routes(codec, wm8993->pdata.lineout1_diff,
+ wm8993->pdata.lineout2_diff);
return 0;
-err_bias:
- wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF);
err_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
err_get:
regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
-err:
- wm8993_codec = NULL;
- kfree(wm8993);
return ret;
}
-static int wm8993_i2c_remove(struct i2c_client *client)
+static int wm8993_remove(struct snd_soc_codec *codec)
{
- struct wm8993_priv *wm8993 = i2c_get_clientdata(client);
+ struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
- snd_soc_unregister_codec(&wm8993->codec);
- snd_soc_unregister_dai(&wm8993_dai);
-
- wm8993_set_bias_level(&wm8993->codec, SND_SOC_BIAS_OFF);
+ wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF);
regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
- kfree(wm8993);
+ return 0;
+}
+#ifdef CONFIG_PM
+static int wm8993_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+ struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
+ int fll_fout = wm8993->fll_fout;
+ int fll_fref = wm8993->fll_fref;
+ int ret;
+
+ /* Stop the FLL in an orderly fashion */
+ ret = _wm8993_set_fll(codec, 0, 0, 0, 0);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to stop FLL\n");
+ return ret;
+ }
+
+ wm8993->fll_fout = fll_fout;
+ wm8993->fll_fref = fll_fref;
+
+ wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+static int wm8993_resume(struct snd_soc_codec *codec)
+{
+ struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ /* Restart the FLL? */
+ if (wm8993->fll_fout) {
+ int fll_fout = wm8993->fll_fout;
+ int fll_fref = wm8993->fll_fref;
+
+ wm8993->fll_fref = 0;
+ wm8993->fll_fout = 0;
+
+ ret = _wm8993_set_fll(codec, 0, wm8993->fll_src,
+ fll_fref, fll_fout);
+ if (ret != 0)
+ dev_err(codec->dev, "Failed to restart FLL\n");
+ }
+
+ return 0;
+}
+#else
+#define wm8993_suspend NULL
+#define wm8993_resume NULL
+#endif
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8993 = {
+ .probe = wm8993_probe,
+ .remove = wm8993_remove,
+ .suspend = wm8993_suspend,
+ .resume = wm8993_resume,
+ .set_bias_level = wm8993_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8993_reg_defaults),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8993_reg_defaults,
+ .volatile_register = wm8993_volatile,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8993_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8993_priv *wm8993;
+ int ret;
+
+ wm8993 = kzalloc(sizeof(struct wm8993_priv), GFP_KERNEL);
+ if (wm8993 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, wm8993);
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8993, &wm8993_dai, 1);
+ if (ret < 0)
+ kfree(wm8993);
+ return ret;
+}
+
+static __devexit int wm8993_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -1695,30 +1627,34 @@
static struct i2c_driver wm8993_i2c_driver = {
.driver = {
- .name = "WM8993",
+ .name = "wm8993-codec",
.owner = THIS_MODULE,
},
- .probe = wm8993_i2c_probe,
- .remove = wm8993_i2c_remove,
+ .probe = wm8993_i2c_probe,
+ .remove = __devexit_p(wm8993_i2c_remove),
.id_table = wm8993_i2c_id,
};
-
+#endif
static int __init wm8993_modinit(void)
{
- int ret;
-
+ int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8993_i2c_driver);
- if (ret != 0)
- pr_err("WM8993: Unable to register I2C driver: %d\n", ret);
-
+ if (ret != 0) {
+ pr_err("WM8993: Unable to register I2C driver: %d\n",
+ ret);
+ }
+#endif
return ret;
}
module_init(wm8993_modinit);
static void __exit wm8993_exit(void)
{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&wm8993_i2c_driver);
+#endif
}
module_exit(wm8993_exit);
diff --git a/sound/soc/codecs/wm8993.h b/sound/soc/codecs/wm8993.h
index 30e71ca..2184617 100644
--- a/sound/soc/codecs/wm8993.h
+++ b/sound/soc/codecs/wm8993.h
@@ -1,9 +1,6 @@
#ifndef WM8993_H
#define WM8993_H
-extern struct snd_soc_dai wm8993_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8993;
-
#define WM8993_SYSCLK_MCLK 1
#define WM8993_SYSCLK_FLL 2
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 522249d..0db59c3 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -36,9 +36,6 @@
#include "wm8994.h"
#include "wm_hubs.h"
-static struct snd_soc_codec *wm8994_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8994;
-
struct fll_config {
int src;
int in;
@@ -71,7 +68,9 @@
/* codec private data */
struct wm8994_priv {
struct wm_hubs_data hubs;
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
+ void *control_data;
+ struct snd_soc_codec *codec;
u16 reg_cache[WM8994_REG_CACHE_SIZE + 1];
int sysclk[2];
int sysclk_rate[2];
@@ -99,1581 +98,1580 @@
struct wm8994_pdata *pdata;
};
-static struct {
- unsigned short readable; /* Mask of readable bits */
- unsigned short writable; /* Mask of writable bits */
- unsigned short vol; /* Mask of volatile bits */
+static const struct {
+ unsigned short readable; /* Mask of readable bits */
+ unsigned short writable; /* Mask of writable bits */
} access_masks[] = {
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R0 - Software Reset */
- { 0x3B37, 0x3B37, 0x0000 }, /* R1 - Power Management (1) */
- { 0x6BF0, 0x6BF0, 0x0000 }, /* R2 - Power Management (2) */
- { 0x3FF0, 0x3FF0, 0x0000 }, /* R3 - Power Management (3) */
- { 0x3F3F, 0x3F3F, 0x0000 }, /* R4 - Power Management (4) */
- { 0x3F0F, 0x3F0F, 0x0000 }, /* R5 - Power Management (5) */
- { 0x003F, 0x003F, 0x0000 }, /* R6 - Power Management (6) */
- { 0x0000, 0x0000, 0x0000 }, /* R7 */
- { 0x0000, 0x0000, 0x0000 }, /* R8 */
- { 0x0000, 0x0000, 0x0000 }, /* R9 */
- { 0x0000, 0x0000, 0x0000 }, /* R10 */
- { 0x0000, 0x0000, 0x0000 }, /* R11 */
- { 0x0000, 0x0000, 0x0000 }, /* R12 */
- { 0x0000, 0x0000, 0x0000 }, /* R13 */
- { 0x0000, 0x0000, 0x0000 }, /* R14 */
- { 0x0000, 0x0000, 0x0000 }, /* R15 */
- { 0x0000, 0x0000, 0x0000 }, /* R16 */
- { 0x0000, 0x0000, 0x0000 }, /* R17 */
- { 0x0000, 0x0000, 0x0000 }, /* R18 */
- { 0x0000, 0x0000, 0x0000 }, /* R19 */
- { 0x0000, 0x0000, 0x0000 }, /* R20 */
- { 0x01C0, 0x01C0, 0x0000 }, /* R21 - Input Mixer (1) */
- { 0x0000, 0x0000, 0x0000 }, /* R22 */
- { 0x0000, 0x0000, 0x0000 }, /* R23 */
- { 0x00DF, 0x01DF, 0x0000 }, /* R24 - Left Line Input 1&2 Volume */
- { 0x00DF, 0x01DF, 0x0000 }, /* R25 - Left Line Input 3&4 Volume */
- { 0x00DF, 0x01DF, 0x0000 }, /* R26 - Right Line Input 1&2 Volume */
- { 0x00DF, 0x01DF, 0x0000 }, /* R27 - Right Line Input 3&4 Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R28 - Left Output Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R29 - Right Output Volume */
- { 0x0077, 0x0077, 0x0000 }, /* R30 - Line Outputs Volume */
- { 0x0030, 0x0030, 0x0000 }, /* R31 - HPOUT2 Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R32 - Left OPGA Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R33 - Right OPGA Volume */
- { 0x007F, 0x007F, 0x0000 }, /* R34 - SPKMIXL Attenuation */
- { 0x017F, 0x017F, 0x0000 }, /* R35 - SPKMIXR Attenuation */
- { 0x003F, 0x003F, 0x0000 }, /* R36 - SPKOUT Mixers */
- { 0x003F, 0x003F, 0x0000 }, /* R37 - ClassD */
- { 0x00FF, 0x01FF, 0x0000 }, /* R38 - Speaker Volume Left */
- { 0x00FF, 0x01FF, 0x0000 }, /* R39 - Speaker Volume Right */
- { 0x00FF, 0x00FF, 0x0000 }, /* R40 - Input Mixer (2) */
- { 0x01B7, 0x01B7, 0x0000 }, /* R41 - Input Mixer (3) */
- { 0x01B7, 0x01B7, 0x0000 }, /* R42 - Input Mixer (4) */
- { 0x01C7, 0x01C7, 0x0000 }, /* R43 - Input Mixer (5) */
- { 0x01C7, 0x01C7, 0x0000 }, /* R44 - Input Mixer (6) */
- { 0x01FF, 0x01FF, 0x0000 }, /* R45 - Output Mixer (1) */
- { 0x01FF, 0x01FF, 0x0000 }, /* R46 - Output Mixer (2) */
- { 0x0FFF, 0x0FFF, 0x0000 }, /* R47 - Output Mixer (3) */
- { 0x0FFF, 0x0FFF, 0x0000 }, /* R48 - Output Mixer (4) */
- { 0x0FFF, 0x0FFF, 0x0000 }, /* R49 - Output Mixer (5) */
- { 0x0FFF, 0x0FFF, 0x0000 }, /* R50 - Output Mixer (6) */
- { 0x0038, 0x0038, 0x0000 }, /* R51 - HPOUT2 Mixer */
- { 0x0077, 0x0077, 0x0000 }, /* R52 - Line Mixer (1) */
- { 0x0077, 0x0077, 0x0000 }, /* R53 - Line Mixer (2) */
- { 0x03FF, 0x03FF, 0x0000 }, /* R54 - Speaker Mixer */
- { 0x00C1, 0x00C1, 0x0000 }, /* R55 - Additional Control */
- { 0x00F0, 0x00F0, 0x0000 }, /* R56 - AntiPOP (1) */
- { 0x01EF, 0x01EF, 0x0000 }, /* R57 - AntiPOP (2) */
- { 0x00FF, 0x00FF, 0x0000 }, /* R58 - MICBIAS */
- { 0x000F, 0x000F, 0x0000 }, /* R59 - LDO 1 */
- { 0x0007, 0x0007, 0x0000 }, /* R60 - LDO 2 */
- { 0x0000, 0x0000, 0x0000 }, /* R61 */
- { 0x0000, 0x0000, 0x0000 }, /* R62 */
- { 0x0000, 0x0000, 0x0000 }, /* R63 */
- { 0x0000, 0x0000, 0x0000 }, /* R64 */
- { 0x0000, 0x0000, 0x0000 }, /* R65 */
- { 0x0000, 0x0000, 0x0000 }, /* R66 */
- { 0x0000, 0x0000, 0x0000 }, /* R67 */
- { 0x0000, 0x0000, 0x0000 }, /* R68 */
- { 0x0000, 0x0000, 0x0000 }, /* R69 */
- { 0x0000, 0x0000, 0x0000 }, /* R70 */
- { 0x0000, 0x0000, 0x0000 }, /* R71 */
- { 0x0000, 0x0000, 0x0000 }, /* R72 */
- { 0x0000, 0x0000, 0x0000 }, /* R73 */
- { 0x0000, 0x0000, 0x0000 }, /* R74 */
- { 0x0000, 0x0000, 0x0000 }, /* R75 */
- { 0x8000, 0x8000, 0x0000 }, /* R76 - Charge Pump (1) */
- { 0x0000, 0x0000, 0x0000 }, /* R77 */
- { 0x0000, 0x0000, 0x0000 }, /* R78 */
- { 0x0000, 0x0000, 0x0000 }, /* R79 */
- { 0x0000, 0x0000, 0x0000 }, /* R80 */
- { 0x0301, 0x0301, 0x0000 }, /* R81 - Class W (1) */
- { 0x0000, 0x0000, 0x0000 }, /* R82 */
- { 0x0000, 0x0000, 0x0000 }, /* R83 */
- { 0x333F, 0x333F, 0x0000 }, /* R84 - DC Servo (1) */
- { 0x0FEF, 0x0FEF, 0x0000 }, /* R85 - DC Servo (2) */
- { 0x0000, 0x0000, 0x0000 }, /* R86 */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R87 - DC Servo (4) */
- { 0x0333, 0x0000, 0x0000 }, /* R88 - DC Servo Readback */
- { 0x0000, 0x0000, 0x0000 }, /* R89 */
- { 0x0000, 0x0000, 0x0000 }, /* R90 */
- { 0x0000, 0x0000, 0x0000 }, /* R91 */
- { 0x0000, 0x0000, 0x0000 }, /* R92 */
- { 0x0000, 0x0000, 0x0000 }, /* R93 */
- { 0x0000, 0x0000, 0x0000 }, /* R94 */
- { 0x0000, 0x0000, 0x0000 }, /* R95 */
- { 0x00EE, 0x00EE, 0x0000 }, /* R96 - Analogue HP (1) */
- { 0x0000, 0x0000, 0x0000 }, /* R97 */
- { 0x0000, 0x0000, 0x0000 }, /* R98 */
- { 0x0000, 0x0000, 0x0000 }, /* R99 */
- { 0x0000, 0x0000, 0x0000 }, /* R100 */
- { 0x0000, 0x0000, 0x0000 }, /* R101 */
- { 0x0000, 0x0000, 0x0000 }, /* R102 */
- { 0x0000, 0x0000, 0x0000 }, /* R103 */
- { 0x0000, 0x0000, 0x0000 }, /* R104 */
- { 0x0000, 0x0000, 0x0000 }, /* R105 */
- { 0x0000, 0x0000, 0x0000 }, /* R106 */
- { 0x0000, 0x0000, 0x0000 }, /* R107 */
- { 0x0000, 0x0000, 0x0000 }, /* R108 */
- { 0x0000, 0x0000, 0x0000 }, /* R109 */
- { 0x0000, 0x0000, 0x0000 }, /* R110 */
- { 0x0000, 0x0000, 0x0000 }, /* R111 */
- { 0x0000, 0x0000, 0x0000 }, /* R112 */
- { 0x0000, 0x0000, 0x0000 }, /* R113 */
- { 0x0000, 0x0000, 0x0000 }, /* R114 */
- { 0x0000, 0x0000, 0x0000 }, /* R115 */
- { 0x0000, 0x0000, 0x0000 }, /* R116 */
- { 0x0000, 0x0000, 0x0000 }, /* R117 */
- { 0x0000, 0x0000, 0x0000 }, /* R118 */
- { 0x0000, 0x0000, 0x0000 }, /* R119 */
- { 0x0000, 0x0000, 0x0000 }, /* R120 */
- { 0x0000, 0x0000, 0x0000 }, /* R121 */
- { 0x0000, 0x0000, 0x0000 }, /* R122 */
- { 0x0000, 0x0000, 0x0000 }, /* R123 */
- { 0x0000, 0x0000, 0x0000 }, /* R124 */
- { 0x0000, 0x0000, 0x0000 }, /* R125 */
- { 0x0000, 0x0000, 0x0000 }, /* R126 */
- { 0x0000, 0x0000, 0x0000 }, /* R127 */
- { 0x0000, 0x0000, 0x0000 }, /* R128 */
- { 0x0000, 0x0000, 0x0000 }, /* R129 */
- { 0x0000, 0x0000, 0x0000 }, /* R130 */
- { 0x0000, 0x0000, 0x0000 }, /* R131 */
- { 0x0000, 0x0000, 0x0000 }, /* R132 */
- { 0x0000, 0x0000, 0x0000 }, /* R133 */
- { 0x0000, 0x0000, 0x0000 }, /* R134 */
- { 0x0000, 0x0000, 0x0000 }, /* R135 */
- { 0x0000, 0x0000, 0x0000 }, /* R136 */
- { 0x0000, 0x0000, 0x0000 }, /* R137 */
- { 0x0000, 0x0000, 0x0000 }, /* R138 */
- { 0x0000, 0x0000, 0x0000 }, /* R139 */
- { 0x0000, 0x0000, 0x0000 }, /* R140 */
- { 0x0000, 0x0000, 0x0000 }, /* R141 */
- { 0x0000, 0x0000, 0x0000 }, /* R142 */
- { 0x0000, 0x0000, 0x0000 }, /* R143 */
- { 0x0000, 0x0000, 0x0000 }, /* R144 */
- { 0x0000, 0x0000, 0x0000 }, /* R145 */
- { 0x0000, 0x0000, 0x0000 }, /* R146 */
- { 0x0000, 0x0000, 0x0000 }, /* R147 */
- { 0x0000, 0x0000, 0x0000 }, /* R148 */
- { 0x0000, 0x0000, 0x0000 }, /* R149 */
- { 0x0000, 0x0000, 0x0000 }, /* R150 */
- { 0x0000, 0x0000, 0x0000 }, /* R151 */
- { 0x0000, 0x0000, 0x0000 }, /* R152 */
- { 0x0000, 0x0000, 0x0000 }, /* R153 */
- { 0x0000, 0x0000, 0x0000 }, /* R154 */
- { 0x0000, 0x0000, 0x0000 }, /* R155 */
- { 0x0000, 0x0000, 0x0000 }, /* R156 */
- { 0x0000, 0x0000, 0x0000 }, /* R157 */
- { 0x0000, 0x0000, 0x0000 }, /* R158 */
- { 0x0000, 0x0000, 0x0000 }, /* R159 */
- { 0x0000, 0x0000, 0x0000 }, /* R160 */
- { 0x0000, 0x0000, 0x0000 }, /* R161 */
- { 0x0000, 0x0000, 0x0000 }, /* R162 */
- { 0x0000, 0x0000, 0x0000 }, /* R163 */
- { 0x0000, 0x0000, 0x0000 }, /* R164 */
- { 0x0000, 0x0000, 0x0000 }, /* R165 */
- { 0x0000, 0x0000, 0x0000 }, /* R166 */
- { 0x0000, 0x0000, 0x0000 }, /* R167 */
- { 0x0000, 0x0000, 0x0000 }, /* R168 */
- { 0x0000, 0x0000, 0x0000 }, /* R169 */
- { 0x0000, 0x0000, 0x0000 }, /* R170 */
- { 0x0000, 0x0000, 0x0000 }, /* R171 */
- { 0x0000, 0x0000, 0x0000 }, /* R172 */
- { 0x0000, 0x0000, 0x0000 }, /* R173 */
- { 0x0000, 0x0000, 0x0000 }, /* R174 */
- { 0x0000, 0x0000, 0x0000 }, /* R175 */
- { 0x0000, 0x0000, 0x0000 }, /* R176 */
- { 0x0000, 0x0000, 0x0000 }, /* R177 */
- { 0x0000, 0x0000, 0x0000 }, /* R178 */
- { 0x0000, 0x0000, 0x0000 }, /* R179 */
- { 0x0000, 0x0000, 0x0000 }, /* R180 */
- { 0x0000, 0x0000, 0x0000 }, /* R181 */
- { 0x0000, 0x0000, 0x0000 }, /* R182 */
- { 0x0000, 0x0000, 0x0000 }, /* R183 */
- { 0x0000, 0x0000, 0x0000 }, /* R184 */
- { 0x0000, 0x0000, 0x0000 }, /* R185 */
- { 0x0000, 0x0000, 0x0000 }, /* R186 */
- { 0x0000, 0x0000, 0x0000 }, /* R187 */
- { 0x0000, 0x0000, 0x0000 }, /* R188 */
- { 0x0000, 0x0000, 0x0000 }, /* R189 */
- { 0x0000, 0x0000, 0x0000 }, /* R190 */
- { 0x0000, 0x0000, 0x0000 }, /* R191 */
- { 0x0000, 0x0000, 0x0000 }, /* R192 */
- { 0x0000, 0x0000, 0x0000 }, /* R193 */
- { 0x0000, 0x0000, 0x0000 }, /* R194 */
- { 0x0000, 0x0000, 0x0000 }, /* R195 */
- { 0x0000, 0x0000, 0x0000 }, /* R196 */
- { 0x0000, 0x0000, 0x0000 }, /* R197 */
- { 0x0000, 0x0000, 0x0000 }, /* R198 */
- { 0x0000, 0x0000, 0x0000 }, /* R199 */
- { 0x0000, 0x0000, 0x0000 }, /* R200 */
- { 0x0000, 0x0000, 0x0000 }, /* R201 */
- { 0x0000, 0x0000, 0x0000 }, /* R202 */
- { 0x0000, 0x0000, 0x0000 }, /* R203 */
- { 0x0000, 0x0000, 0x0000 }, /* R204 */
- { 0x0000, 0x0000, 0x0000 }, /* R205 */
- { 0x0000, 0x0000, 0x0000 }, /* R206 */
- { 0x0000, 0x0000, 0x0000 }, /* R207 */
- { 0x0000, 0x0000, 0x0000 }, /* R208 */
- { 0x0000, 0x0000, 0x0000 }, /* R209 */
- { 0x0000, 0x0000, 0x0000 }, /* R210 */
- { 0x0000, 0x0000, 0x0000 }, /* R211 */
- { 0x0000, 0x0000, 0x0000 }, /* R212 */
- { 0x0000, 0x0000, 0x0000 }, /* R213 */
- { 0x0000, 0x0000, 0x0000 }, /* R214 */
- { 0x0000, 0x0000, 0x0000 }, /* R215 */
- { 0x0000, 0x0000, 0x0000 }, /* R216 */
- { 0x0000, 0x0000, 0x0000 }, /* R217 */
- { 0x0000, 0x0000, 0x0000 }, /* R218 */
- { 0x0000, 0x0000, 0x0000 }, /* R219 */
- { 0x0000, 0x0000, 0x0000 }, /* R220 */
- { 0x0000, 0x0000, 0x0000 }, /* R221 */
- { 0x0000, 0x0000, 0x0000 }, /* R222 */
- { 0x0000, 0x0000, 0x0000 }, /* R223 */
- { 0x0000, 0x0000, 0x0000 }, /* R224 */
- { 0x0000, 0x0000, 0x0000 }, /* R225 */
- { 0x0000, 0x0000, 0x0000 }, /* R226 */
- { 0x0000, 0x0000, 0x0000 }, /* R227 */
- { 0x0000, 0x0000, 0x0000 }, /* R228 */
- { 0x0000, 0x0000, 0x0000 }, /* R229 */
- { 0x0000, 0x0000, 0x0000 }, /* R230 */
- { 0x0000, 0x0000, 0x0000 }, /* R231 */
- { 0x0000, 0x0000, 0x0000 }, /* R232 */
- { 0x0000, 0x0000, 0x0000 }, /* R233 */
- { 0x0000, 0x0000, 0x0000 }, /* R234 */
- { 0x0000, 0x0000, 0x0000 }, /* R235 */
- { 0x0000, 0x0000, 0x0000 }, /* R236 */
- { 0x0000, 0x0000, 0x0000 }, /* R237 */
- { 0x0000, 0x0000, 0x0000 }, /* R238 */
- { 0x0000, 0x0000, 0x0000 }, /* R239 */
- { 0x0000, 0x0000, 0x0000 }, /* R240 */
- { 0x0000, 0x0000, 0x0000 }, /* R241 */
- { 0x0000, 0x0000, 0x0000 }, /* R242 */
- { 0x0000, 0x0000, 0x0000 }, /* R243 */
- { 0x0000, 0x0000, 0x0000 }, /* R244 */
- { 0x0000, 0x0000, 0x0000 }, /* R245 */
- { 0x0000, 0x0000, 0x0000 }, /* R246 */
- { 0x0000, 0x0000, 0x0000 }, /* R247 */
- { 0x0000, 0x0000, 0x0000 }, /* R248 */
- { 0x0000, 0x0000, 0x0000 }, /* R249 */
- { 0x0000, 0x0000, 0x0000 }, /* R250 */
- { 0x0000, 0x0000, 0x0000 }, /* R251 */
- { 0x0000, 0x0000, 0x0000 }, /* R252 */
- { 0x0000, 0x0000, 0x0000 }, /* R253 */
- { 0x0000, 0x0000, 0x0000 }, /* R254 */
- { 0x0000, 0x0000, 0x0000 }, /* R255 */
- { 0x000F, 0x0000, 0x0000 }, /* R256 - Chip Revision */
- { 0x0074, 0x0074, 0x0000 }, /* R257 - Control Interface */
- { 0x0000, 0x0000, 0x0000 }, /* R258 */
- { 0x0000, 0x0000, 0x0000 }, /* R259 */
- { 0x0000, 0x0000, 0x0000 }, /* R260 */
- { 0x0000, 0x0000, 0x0000 }, /* R261 */
- { 0x0000, 0x0000, 0x0000 }, /* R262 */
- { 0x0000, 0x0000, 0x0000 }, /* R263 */
- { 0x0000, 0x0000, 0x0000 }, /* R264 */
- { 0x0000, 0x0000, 0x0000 }, /* R265 */
- { 0x0000, 0x0000, 0x0000 }, /* R266 */
- { 0x0000, 0x0000, 0x0000 }, /* R267 */
- { 0x0000, 0x0000, 0x0000 }, /* R268 */
- { 0x0000, 0x0000, 0x0000 }, /* R269 */
- { 0x0000, 0x0000, 0x0000 }, /* R270 */
- { 0x0000, 0x0000, 0x0000 }, /* R271 */
- { 0x807F, 0x837F, 0x0000 }, /* R272 - Write Sequencer Ctrl (1) */
- { 0x017F, 0x0000, 0x0000 }, /* R273 - Write Sequencer Ctrl (2) */
- { 0x0000, 0x0000, 0x0000 }, /* R274 */
- { 0x0000, 0x0000, 0x0000 }, /* R275 */
- { 0x0000, 0x0000, 0x0000 }, /* R276 */
- { 0x0000, 0x0000, 0x0000 }, /* R277 */
- { 0x0000, 0x0000, 0x0000 }, /* R278 */
- { 0x0000, 0x0000, 0x0000 }, /* R279 */
- { 0x0000, 0x0000, 0x0000 }, /* R280 */
- { 0x0000, 0x0000, 0x0000 }, /* R281 */
- { 0x0000, 0x0000, 0x0000 }, /* R282 */
- { 0x0000, 0x0000, 0x0000 }, /* R283 */
- { 0x0000, 0x0000, 0x0000 }, /* R284 */
- { 0x0000, 0x0000, 0x0000 }, /* R285 */
- { 0x0000, 0x0000, 0x0000 }, /* R286 */
- { 0x0000, 0x0000, 0x0000 }, /* R287 */
- { 0x0000, 0x0000, 0x0000 }, /* R288 */
- { 0x0000, 0x0000, 0x0000 }, /* R289 */
- { 0x0000, 0x0000, 0x0000 }, /* R290 */
- { 0x0000, 0x0000, 0x0000 }, /* R291 */
- { 0x0000, 0x0000, 0x0000 }, /* R292 */
- { 0x0000, 0x0000, 0x0000 }, /* R293 */
- { 0x0000, 0x0000, 0x0000 }, /* R294 */
- { 0x0000, 0x0000, 0x0000 }, /* R295 */
- { 0x0000, 0x0000, 0x0000 }, /* R296 */
- { 0x0000, 0x0000, 0x0000 }, /* R297 */
- { 0x0000, 0x0000, 0x0000 }, /* R298 */
- { 0x0000, 0x0000, 0x0000 }, /* R299 */
- { 0x0000, 0x0000, 0x0000 }, /* R300 */
- { 0x0000, 0x0000, 0x0000 }, /* R301 */
- { 0x0000, 0x0000, 0x0000 }, /* R302 */
- { 0x0000, 0x0000, 0x0000 }, /* R303 */
- { 0x0000, 0x0000, 0x0000 }, /* R304 */
- { 0x0000, 0x0000, 0x0000 }, /* R305 */
- { 0x0000, 0x0000, 0x0000 }, /* R306 */
- { 0x0000, 0x0000, 0x0000 }, /* R307 */
- { 0x0000, 0x0000, 0x0000 }, /* R308 */
- { 0x0000, 0x0000, 0x0000 }, /* R309 */
- { 0x0000, 0x0000, 0x0000 }, /* R310 */
- { 0x0000, 0x0000, 0x0000 }, /* R311 */
- { 0x0000, 0x0000, 0x0000 }, /* R312 */
- { 0x0000, 0x0000, 0x0000 }, /* R313 */
- { 0x0000, 0x0000, 0x0000 }, /* R314 */
- { 0x0000, 0x0000, 0x0000 }, /* R315 */
- { 0x0000, 0x0000, 0x0000 }, /* R316 */
- { 0x0000, 0x0000, 0x0000 }, /* R317 */
- { 0x0000, 0x0000, 0x0000 }, /* R318 */
- { 0x0000, 0x0000, 0x0000 }, /* R319 */
- { 0x0000, 0x0000, 0x0000 }, /* R320 */
- { 0x0000, 0x0000, 0x0000 }, /* R321 */
- { 0x0000, 0x0000, 0x0000 }, /* R322 */
- { 0x0000, 0x0000, 0x0000 }, /* R323 */
- { 0x0000, 0x0000, 0x0000 }, /* R324 */
- { 0x0000, 0x0000, 0x0000 }, /* R325 */
- { 0x0000, 0x0000, 0x0000 }, /* R326 */
- { 0x0000, 0x0000, 0x0000 }, /* R327 */
- { 0x0000, 0x0000, 0x0000 }, /* R328 */
- { 0x0000, 0x0000, 0x0000 }, /* R329 */
- { 0x0000, 0x0000, 0x0000 }, /* R330 */
- { 0x0000, 0x0000, 0x0000 }, /* R331 */
- { 0x0000, 0x0000, 0x0000 }, /* R332 */
- { 0x0000, 0x0000, 0x0000 }, /* R333 */
- { 0x0000, 0x0000, 0x0000 }, /* R334 */
- { 0x0000, 0x0000, 0x0000 }, /* R335 */
- { 0x0000, 0x0000, 0x0000 }, /* R336 */
- { 0x0000, 0x0000, 0x0000 }, /* R337 */
- { 0x0000, 0x0000, 0x0000 }, /* R338 */
- { 0x0000, 0x0000, 0x0000 }, /* R339 */
- { 0x0000, 0x0000, 0x0000 }, /* R340 */
- { 0x0000, 0x0000, 0x0000 }, /* R341 */
- { 0x0000, 0x0000, 0x0000 }, /* R342 */
- { 0x0000, 0x0000, 0x0000 }, /* R343 */
- { 0x0000, 0x0000, 0x0000 }, /* R344 */
- { 0x0000, 0x0000, 0x0000 }, /* R345 */
- { 0x0000, 0x0000, 0x0000 }, /* R346 */
- { 0x0000, 0x0000, 0x0000 }, /* R347 */
- { 0x0000, 0x0000, 0x0000 }, /* R348 */
- { 0x0000, 0x0000, 0x0000 }, /* R349 */
- { 0x0000, 0x0000, 0x0000 }, /* R350 */
- { 0x0000, 0x0000, 0x0000 }, /* R351 */
- { 0x0000, 0x0000, 0x0000 }, /* R352 */
- { 0x0000, 0x0000, 0x0000 }, /* R353 */
- { 0x0000, 0x0000, 0x0000 }, /* R354 */
- { 0x0000, 0x0000, 0x0000 }, /* R355 */
- { 0x0000, 0x0000, 0x0000 }, /* R356 */
- { 0x0000, 0x0000, 0x0000 }, /* R357 */
- { 0x0000, 0x0000, 0x0000 }, /* R358 */
- { 0x0000, 0x0000, 0x0000 }, /* R359 */
- { 0x0000, 0x0000, 0x0000 }, /* R360 */
- { 0x0000, 0x0000, 0x0000 }, /* R361 */
- { 0x0000, 0x0000, 0x0000 }, /* R362 */
- { 0x0000, 0x0000, 0x0000 }, /* R363 */
- { 0x0000, 0x0000, 0x0000 }, /* R364 */
- { 0x0000, 0x0000, 0x0000 }, /* R365 */
- { 0x0000, 0x0000, 0x0000 }, /* R366 */
- { 0x0000, 0x0000, 0x0000 }, /* R367 */
- { 0x0000, 0x0000, 0x0000 }, /* R368 */
- { 0x0000, 0x0000, 0x0000 }, /* R369 */
- { 0x0000, 0x0000, 0x0000 }, /* R370 */
- { 0x0000, 0x0000, 0x0000 }, /* R371 */
- { 0x0000, 0x0000, 0x0000 }, /* R372 */
- { 0x0000, 0x0000, 0x0000 }, /* R373 */
- { 0x0000, 0x0000, 0x0000 }, /* R374 */
- { 0x0000, 0x0000, 0x0000 }, /* R375 */
- { 0x0000, 0x0000, 0x0000 }, /* R376 */
- { 0x0000, 0x0000, 0x0000 }, /* R377 */
- { 0x0000, 0x0000, 0x0000 }, /* R378 */
- { 0x0000, 0x0000, 0x0000 }, /* R379 */
- { 0x0000, 0x0000, 0x0000 }, /* R380 */
- { 0x0000, 0x0000, 0x0000 }, /* R381 */
- { 0x0000, 0x0000, 0x0000 }, /* R382 */
- { 0x0000, 0x0000, 0x0000 }, /* R383 */
- { 0x0000, 0x0000, 0x0000 }, /* R384 */
- { 0x0000, 0x0000, 0x0000 }, /* R385 */
- { 0x0000, 0x0000, 0x0000 }, /* R386 */
- { 0x0000, 0x0000, 0x0000 }, /* R387 */
- { 0x0000, 0x0000, 0x0000 }, /* R388 */
- { 0x0000, 0x0000, 0x0000 }, /* R389 */
- { 0x0000, 0x0000, 0x0000 }, /* R390 */
- { 0x0000, 0x0000, 0x0000 }, /* R391 */
- { 0x0000, 0x0000, 0x0000 }, /* R392 */
- { 0x0000, 0x0000, 0x0000 }, /* R393 */
- { 0x0000, 0x0000, 0x0000 }, /* R394 */
- { 0x0000, 0x0000, 0x0000 }, /* R395 */
- { 0x0000, 0x0000, 0x0000 }, /* R396 */
- { 0x0000, 0x0000, 0x0000 }, /* R397 */
- { 0x0000, 0x0000, 0x0000 }, /* R398 */
- { 0x0000, 0x0000, 0x0000 }, /* R399 */
- { 0x0000, 0x0000, 0x0000 }, /* R400 */
- { 0x0000, 0x0000, 0x0000 }, /* R401 */
- { 0x0000, 0x0000, 0x0000 }, /* R402 */
- { 0x0000, 0x0000, 0x0000 }, /* R403 */
- { 0x0000, 0x0000, 0x0000 }, /* R404 */
- { 0x0000, 0x0000, 0x0000 }, /* R405 */
- { 0x0000, 0x0000, 0x0000 }, /* R406 */
- { 0x0000, 0x0000, 0x0000 }, /* R407 */
- { 0x0000, 0x0000, 0x0000 }, /* R408 */
- { 0x0000, 0x0000, 0x0000 }, /* R409 */
- { 0x0000, 0x0000, 0x0000 }, /* R410 */
- { 0x0000, 0x0000, 0x0000 }, /* R411 */
- { 0x0000, 0x0000, 0x0000 }, /* R412 */
- { 0x0000, 0x0000, 0x0000 }, /* R413 */
- { 0x0000, 0x0000, 0x0000 }, /* R414 */
- { 0x0000, 0x0000, 0x0000 }, /* R415 */
- { 0x0000, 0x0000, 0x0000 }, /* R416 */
- { 0x0000, 0x0000, 0x0000 }, /* R417 */
- { 0x0000, 0x0000, 0x0000 }, /* R418 */
- { 0x0000, 0x0000, 0x0000 }, /* R419 */
- { 0x0000, 0x0000, 0x0000 }, /* R420 */
- { 0x0000, 0x0000, 0x0000 }, /* R421 */
- { 0x0000, 0x0000, 0x0000 }, /* R422 */
- { 0x0000, 0x0000, 0x0000 }, /* R423 */
- { 0x0000, 0x0000, 0x0000 }, /* R424 */
- { 0x0000, 0x0000, 0x0000 }, /* R425 */
- { 0x0000, 0x0000, 0x0000 }, /* R426 */
- { 0x0000, 0x0000, 0x0000 }, /* R427 */
- { 0x0000, 0x0000, 0x0000 }, /* R428 */
- { 0x0000, 0x0000, 0x0000 }, /* R429 */
- { 0x0000, 0x0000, 0x0000 }, /* R430 */
- { 0x0000, 0x0000, 0x0000 }, /* R431 */
- { 0x0000, 0x0000, 0x0000 }, /* R432 */
- { 0x0000, 0x0000, 0x0000 }, /* R433 */
- { 0x0000, 0x0000, 0x0000 }, /* R434 */
- { 0x0000, 0x0000, 0x0000 }, /* R435 */
- { 0x0000, 0x0000, 0x0000 }, /* R436 */
- { 0x0000, 0x0000, 0x0000 }, /* R437 */
- { 0x0000, 0x0000, 0x0000 }, /* R438 */
- { 0x0000, 0x0000, 0x0000 }, /* R439 */
- { 0x0000, 0x0000, 0x0000 }, /* R440 */
- { 0x0000, 0x0000, 0x0000 }, /* R441 */
- { 0x0000, 0x0000, 0x0000 }, /* R442 */
- { 0x0000, 0x0000, 0x0000 }, /* R443 */
- { 0x0000, 0x0000, 0x0000 }, /* R444 */
- { 0x0000, 0x0000, 0x0000 }, /* R445 */
- { 0x0000, 0x0000, 0x0000 }, /* R446 */
- { 0x0000, 0x0000, 0x0000 }, /* R447 */
- { 0x0000, 0x0000, 0x0000 }, /* R448 */
- { 0x0000, 0x0000, 0x0000 }, /* R449 */
- { 0x0000, 0x0000, 0x0000 }, /* R450 */
- { 0x0000, 0x0000, 0x0000 }, /* R451 */
- { 0x0000, 0x0000, 0x0000 }, /* R452 */
- { 0x0000, 0x0000, 0x0000 }, /* R453 */
- { 0x0000, 0x0000, 0x0000 }, /* R454 */
- { 0x0000, 0x0000, 0x0000 }, /* R455 */
- { 0x0000, 0x0000, 0x0000 }, /* R456 */
- { 0x0000, 0x0000, 0x0000 }, /* R457 */
- { 0x0000, 0x0000, 0x0000 }, /* R458 */
- { 0x0000, 0x0000, 0x0000 }, /* R459 */
- { 0x0000, 0x0000, 0x0000 }, /* R460 */
- { 0x0000, 0x0000, 0x0000 }, /* R461 */
- { 0x0000, 0x0000, 0x0000 }, /* R462 */
- { 0x0000, 0x0000, 0x0000 }, /* R463 */
- { 0x0000, 0x0000, 0x0000 }, /* R464 */
- { 0x0000, 0x0000, 0x0000 }, /* R465 */
- { 0x0000, 0x0000, 0x0000 }, /* R466 */
- { 0x0000, 0x0000, 0x0000 }, /* R467 */
- { 0x0000, 0x0000, 0x0000 }, /* R468 */
- { 0x0000, 0x0000, 0x0000 }, /* R469 */
- { 0x0000, 0x0000, 0x0000 }, /* R470 */
- { 0x0000, 0x0000, 0x0000 }, /* R471 */
- { 0x0000, 0x0000, 0x0000 }, /* R472 */
- { 0x0000, 0x0000, 0x0000 }, /* R473 */
- { 0x0000, 0x0000, 0x0000 }, /* R474 */
- { 0x0000, 0x0000, 0x0000 }, /* R475 */
- { 0x0000, 0x0000, 0x0000 }, /* R476 */
- { 0x0000, 0x0000, 0x0000 }, /* R477 */
- { 0x0000, 0x0000, 0x0000 }, /* R478 */
- { 0x0000, 0x0000, 0x0000 }, /* R479 */
- { 0x0000, 0x0000, 0x0000 }, /* R480 */
- { 0x0000, 0x0000, 0x0000 }, /* R481 */
- { 0x0000, 0x0000, 0x0000 }, /* R482 */
- { 0x0000, 0x0000, 0x0000 }, /* R483 */
- { 0x0000, 0x0000, 0x0000 }, /* R484 */
- { 0x0000, 0x0000, 0x0000 }, /* R485 */
- { 0x0000, 0x0000, 0x0000 }, /* R486 */
- { 0x0000, 0x0000, 0x0000 }, /* R487 */
- { 0x0000, 0x0000, 0x0000 }, /* R488 */
- { 0x0000, 0x0000, 0x0000 }, /* R489 */
- { 0x0000, 0x0000, 0x0000 }, /* R490 */
- { 0x0000, 0x0000, 0x0000 }, /* R491 */
- { 0x0000, 0x0000, 0x0000 }, /* R492 */
- { 0x0000, 0x0000, 0x0000 }, /* R493 */
- { 0x0000, 0x0000, 0x0000 }, /* R494 */
- { 0x0000, 0x0000, 0x0000 }, /* R495 */
- { 0x0000, 0x0000, 0x0000 }, /* R496 */
- { 0x0000, 0x0000, 0x0000 }, /* R497 */
- { 0x0000, 0x0000, 0x0000 }, /* R498 */
- { 0x0000, 0x0000, 0x0000 }, /* R499 */
- { 0x0000, 0x0000, 0x0000 }, /* R500 */
- { 0x0000, 0x0000, 0x0000 }, /* R501 */
- { 0x0000, 0x0000, 0x0000 }, /* R502 */
- { 0x0000, 0x0000, 0x0000 }, /* R503 */
- { 0x0000, 0x0000, 0x0000 }, /* R504 */
- { 0x0000, 0x0000, 0x0000 }, /* R505 */
- { 0x0000, 0x0000, 0x0000 }, /* R506 */
- { 0x0000, 0x0000, 0x0000 }, /* R507 */
- { 0x0000, 0x0000, 0x0000 }, /* R508 */
- { 0x0000, 0x0000, 0x0000 }, /* R509 */
- { 0x0000, 0x0000, 0x0000 }, /* R510 */
- { 0x0000, 0x0000, 0x0000 }, /* R511 */
- { 0x001F, 0x001F, 0x0000 }, /* R512 - AIF1 Clocking (1) */
- { 0x003F, 0x003F, 0x0000 }, /* R513 - AIF1 Clocking (2) */
- { 0x0000, 0x0000, 0x0000 }, /* R514 */
- { 0x0000, 0x0000, 0x0000 }, /* R515 */
- { 0x001F, 0x001F, 0x0000 }, /* R516 - AIF2 Clocking (1) */
- { 0x003F, 0x003F, 0x0000 }, /* R517 - AIF2 Clocking (2) */
- { 0x0000, 0x0000, 0x0000 }, /* R518 */
- { 0x0000, 0x0000, 0x0000 }, /* R519 */
- { 0x001F, 0x001F, 0x0000 }, /* R520 - Clocking (1) */
- { 0x0777, 0x0777, 0x0000 }, /* R521 - Clocking (2) */
- { 0x0000, 0x0000, 0x0000 }, /* R522 */
- { 0x0000, 0x0000, 0x0000 }, /* R523 */
- { 0x0000, 0x0000, 0x0000 }, /* R524 */
- { 0x0000, 0x0000, 0x0000 }, /* R525 */
- { 0x0000, 0x0000, 0x0000 }, /* R526 */
- { 0x0000, 0x0000, 0x0000 }, /* R527 */
- { 0x00FF, 0x00FF, 0x0000 }, /* R528 - AIF1 Rate */
- { 0x00FF, 0x00FF, 0x0000 }, /* R529 - AIF2 Rate */
- { 0x000F, 0x0000, 0x0000 }, /* R530 - Rate Status */
- { 0x0000, 0x0000, 0x0000 }, /* R531 */
- { 0x0000, 0x0000, 0x0000 }, /* R532 */
- { 0x0000, 0x0000, 0x0000 }, /* R533 */
- { 0x0000, 0x0000, 0x0000 }, /* R534 */
- { 0x0000, 0x0000, 0x0000 }, /* R535 */
- { 0x0000, 0x0000, 0x0000 }, /* R536 */
- { 0x0000, 0x0000, 0x0000 }, /* R537 */
- { 0x0000, 0x0000, 0x0000 }, /* R538 */
- { 0x0000, 0x0000, 0x0000 }, /* R539 */
- { 0x0000, 0x0000, 0x0000 }, /* R540 */
- { 0x0000, 0x0000, 0x0000 }, /* R541 */
- { 0x0000, 0x0000, 0x0000 }, /* R542 */
- { 0x0000, 0x0000, 0x0000 }, /* R543 */
- { 0x0007, 0x0007, 0x0000 }, /* R544 - FLL1 Control (1) */
- { 0x3F77, 0x3F77, 0x0000 }, /* R545 - FLL1 Control (2) */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R546 - FLL1 Control (3) */
- { 0x7FEF, 0x7FEF, 0x0000 }, /* R547 - FLL1 Control (4) */
- { 0x1FDB, 0x1FDB, 0x0000 }, /* R548 - FLL1 Control (5) */
- { 0x0000, 0x0000, 0x0000 }, /* R549 */
- { 0x0000, 0x0000, 0x0000 }, /* R550 */
- { 0x0000, 0x0000, 0x0000 }, /* R551 */
- { 0x0000, 0x0000, 0x0000 }, /* R552 */
- { 0x0000, 0x0000, 0x0000 }, /* R553 */
- { 0x0000, 0x0000, 0x0000 }, /* R554 */
- { 0x0000, 0x0000, 0x0000 }, /* R555 */
- { 0x0000, 0x0000, 0x0000 }, /* R556 */
- { 0x0000, 0x0000, 0x0000 }, /* R557 */
- { 0x0000, 0x0000, 0x0000 }, /* R558 */
- { 0x0000, 0x0000, 0x0000 }, /* R559 */
- { 0x0000, 0x0000, 0x0000 }, /* R560 */
- { 0x0000, 0x0000, 0x0000 }, /* R561 */
- { 0x0000, 0x0000, 0x0000 }, /* R562 */
- { 0x0000, 0x0000, 0x0000 }, /* R563 */
- { 0x0000, 0x0000, 0x0000 }, /* R564 */
- { 0x0000, 0x0000, 0x0000 }, /* R565 */
- { 0x0000, 0x0000, 0x0000 }, /* R566 */
- { 0x0000, 0x0000, 0x0000 }, /* R567 */
- { 0x0000, 0x0000, 0x0000 }, /* R568 */
- { 0x0000, 0x0000, 0x0000 }, /* R569 */
- { 0x0000, 0x0000, 0x0000 }, /* R570 */
- { 0x0000, 0x0000, 0x0000 }, /* R571 */
- { 0x0000, 0x0000, 0x0000 }, /* R572 */
- { 0x0000, 0x0000, 0x0000 }, /* R573 */
- { 0x0000, 0x0000, 0x0000 }, /* R574 */
- { 0x0000, 0x0000, 0x0000 }, /* R575 */
- { 0x0007, 0x0007, 0x0000 }, /* R576 - FLL2 Control (1) */
- { 0x3F77, 0x3F77, 0x0000 }, /* R577 - FLL2 Control (2) */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R578 - FLL2 Control (3) */
- { 0x7FEF, 0x7FEF, 0x0000 }, /* R579 - FLL2 Control (4) */
- { 0x1FDB, 0x1FDB, 0x0000 }, /* R580 - FLL2 Control (5) */
- { 0x0000, 0x0000, 0x0000 }, /* R581 */
- { 0x0000, 0x0000, 0x0000 }, /* R582 */
- { 0x0000, 0x0000, 0x0000 }, /* R583 */
- { 0x0000, 0x0000, 0x0000 }, /* R584 */
- { 0x0000, 0x0000, 0x0000 }, /* R585 */
- { 0x0000, 0x0000, 0x0000 }, /* R586 */
- { 0x0000, 0x0000, 0x0000 }, /* R587 */
- { 0x0000, 0x0000, 0x0000 }, /* R588 */
- { 0x0000, 0x0000, 0x0000 }, /* R589 */
- { 0x0000, 0x0000, 0x0000 }, /* R590 */
- { 0x0000, 0x0000, 0x0000 }, /* R591 */
- { 0x0000, 0x0000, 0x0000 }, /* R592 */
- { 0x0000, 0x0000, 0x0000 }, /* R593 */
- { 0x0000, 0x0000, 0x0000 }, /* R594 */
- { 0x0000, 0x0000, 0x0000 }, /* R595 */
- { 0x0000, 0x0000, 0x0000 }, /* R596 */
- { 0x0000, 0x0000, 0x0000 }, /* R597 */
- { 0x0000, 0x0000, 0x0000 }, /* R598 */
- { 0x0000, 0x0000, 0x0000 }, /* R599 */
- { 0x0000, 0x0000, 0x0000 }, /* R600 */
- { 0x0000, 0x0000, 0x0000 }, /* R601 */
- { 0x0000, 0x0000, 0x0000 }, /* R602 */
- { 0x0000, 0x0000, 0x0000 }, /* R603 */
- { 0x0000, 0x0000, 0x0000 }, /* R604 */
- { 0x0000, 0x0000, 0x0000 }, /* R605 */
- { 0x0000, 0x0000, 0x0000 }, /* R606 */
- { 0x0000, 0x0000, 0x0000 }, /* R607 */
- { 0x0000, 0x0000, 0x0000 }, /* R608 */
- { 0x0000, 0x0000, 0x0000 }, /* R609 */
- { 0x0000, 0x0000, 0x0000 }, /* R610 */
- { 0x0000, 0x0000, 0x0000 }, /* R611 */
- { 0x0000, 0x0000, 0x0000 }, /* R612 */
- { 0x0000, 0x0000, 0x0000 }, /* R613 */
- { 0x0000, 0x0000, 0x0000 }, /* R614 */
- { 0x0000, 0x0000, 0x0000 }, /* R615 */
- { 0x0000, 0x0000, 0x0000 }, /* R616 */
- { 0x0000, 0x0000, 0x0000 }, /* R617 */
- { 0x0000, 0x0000, 0x0000 }, /* R618 */
- { 0x0000, 0x0000, 0x0000 }, /* R619 */
- { 0x0000, 0x0000, 0x0000 }, /* R620 */
- { 0x0000, 0x0000, 0x0000 }, /* R621 */
- { 0x0000, 0x0000, 0x0000 }, /* R622 */
- { 0x0000, 0x0000, 0x0000 }, /* R623 */
- { 0x0000, 0x0000, 0x0000 }, /* R624 */
- { 0x0000, 0x0000, 0x0000 }, /* R625 */
- { 0x0000, 0x0000, 0x0000 }, /* R626 */
- { 0x0000, 0x0000, 0x0000 }, /* R627 */
- { 0x0000, 0x0000, 0x0000 }, /* R628 */
- { 0x0000, 0x0000, 0x0000 }, /* R629 */
- { 0x0000, 0x0000, 0x0000 }, /* R630 */
- { 0x0000, 0x0000, 0x0000 }, /* R631 */
- { 0x0000, 0x0000, 0x0000 }, /* R632 */
- { 0x0000, 0x0000, 0x0000 }, /* R633 */
- { 0x0000, 0x0000, 0x0000 }, /* R634 */
- { 0x0000, 0x0000, 0x0000 }, /* R635 */
- { 0x0000, 0x0000, 0x0000 }, /* R636 */
- { 0x0000, 0x0000, 0x0000 }, /* R637 */
- { 0x0000, 0x0000, 0x0000 }, /* R638 */
- { 0x0000, 0x0000, 0x0000 }, /* R639 */
- { 0x0000, 0x0000, 0x0000 }, /* R640 */
- { 0x0000, 0x0000, 0x0000 }, /* R641 */
- { 0x0000, 0x0000, 0x0000 }, /* R642 */
- { 0x0000, 0x0000, 0x0000 }, /* R643 */
- { 0x0000, 0x0000, 0x0000 }, /* R644 */
- { 0x0000, 0x0000, 0x0000 }, /* R645 */
- { 0x0000, 0x0000, 0x0000 }, /* R646 */
- { 0x0000, 0x0000, 0x0000 }, /* R647 */
- { 0x0000, 0x0000, 0x0000 }, /* R648 */
- { 0x0000, 0x0000, 0x0000 }, /* R649 */
- { 0x0000, 0x0000, 0x0000 }, /* R650 */
- { 0x0000, 0x0000, 0x0000 }, /* R651 */
- { 0x0000, 0x0000, 0x0000 }, /* R652 */
- { 0x0000, 0x0000, 0x0000 }, /* R653 */
- { 0x0000, 0x0000, 0x0000 }, /* R654 */
- { 0x0000, 0x0000, 0x0000 }, /* R655 */
- { 0x0000, 0x0000, 0x0000 }, /* R656 */
- { 0x0000, 0x0000, 0x0000 }, /* R657 */
- { 0x0000, 0x0000, 0x0000 }, /* R658 */
- { 0x0000, 0x0000, 0x0000 }, /* R659 */
- { 0x0000, 0x0000, 0x0000 }, /* R660 */
- { 0x0000, 0x0000, 0x0000 }, /* R661 */
- { 0x0000, 0x0000, 0x0000 }, /* R662 */
- { 0x0000, 0x0000, 0x0000 }, /* R663 */
- { 0x0000, 0x0000, 0x0000 }, /* R664 */
- { 0x0000, 0x0000, 0x0000 }, /* R665 */
- { 0x0000, 0x0000, 0x0000 }, /* R666 */
- { 0x0000, 0x0000, 0x0000 }, /* R667 */
- { 0x0000, 0x0000, 0x0000 }, /* R668 */
- { 0x0000, 0x0000, 0x0000 }, /* R669 */
- { 0x0000, 0x0000, 0x0000 }, /* R670 */
- { 0x0000, 0x0000, 0x0000 }, /* R671 */
- { 0x0000, 0x0000, 0x0000 }, /* R672 */
- { 0x0000, 0x0000, 0x0000 }, /* R673 */
- { 0x0000, 0x0000, 0x0000 }, /* R674 */
- { 0x0000, 0x0000, 0x0000 }, /* R675 */
- { 0x0000, 0x0000, 0x0000 }, /* R676 */
- { 0x0000, 0x0000, 0x0000 }, /* R677 */
- { 0x0000, 0x0000, 0x0000 }, /* R678 */
- { 0x0000, 0x0000, 0x0000 }, /* R679 */
- { 0x0000, 0x0000, 0x0000 }, /* R680 */
- { 0x0000, 0x0000, 0x0000 }, /* R681 */
- { 0x0000, 0x0000, 0x0000 }, /* R682 */
- { 0x0000, 0x0000, 0x0000 }, /* R683 */
- { 0x0000, 0x0000, 0x0000 }, /* R684 */
- { 0x0000, 0x0000, 0x0000 }, /* R685 */
- { 0x0000, 0x0000, 0x0000 }, /* R686 */
- { 0x0000, 0x0000, 0x0000 }, /* R687 */
- { 0x0000, 0x0000, 0x0000 }, /* R688 */
- { 0x0000, 0x0000, 0x0000 }, /* R689 */
- { 0x0000, 0x0000, 0x0000 }, /* R690 */
- { 0x0000, 0x0000, 0x0000 }, /* R691 */
- { 0x0000, 0x0000, 0x0000 }, /* R692 */
- { 0x0000, 0x0000, 0x0000 }, /* R693 */
- { 0x0000, 0x0000, 0x0000 }, /* R694 */
- { 0x0000, 0x0000, 0x0000 }, /* R695 */
- { 0x0000, 0x0000, 0x0000 }, /* R696 */
- { 0x0000, 0x0000, 0x0000 }, /* R697 */
- { 0x0000, 0x0000, 0x0000 }, /* R698 */
- { 0x0000, 0x0000, 0x0000 }, /* R699 */
- { 0x0000, 0x0000, 0x0000 }, /* R700 */
- { 0x0000, 0x0000, 0x0000 }, /* R701 */
- { 0x0000, 0x0000, 0x0000 }, /* R702 */
- { 0x0000, 0x0000, 0x0000 }, /* R703 */
- { 0x0000, 0x0000, 0x0000 }, /* R704 */
- { 0x0000, 0x0000, 0x0000 }, /* R705 */
- { 0x0000, 0x0000, 0x0000 }, /* R706 */
- { 0x0000, 0x0000, 0x0000 }, /* R707 */
- { 0x0000, 0x0000, 0x0000 }, /* R708 */
- { 0x0000, 0x0000, 0x0000 }, /* R709 */
- { 0x0000, 0x0000, 0x0000 }, /* R710 */
- { 0x0000, 0x0000, 0x0000 }, /* R711 */
- { 0x0000, 0x0000, 0x0000 }, /* R712 */
- { 0x0000, 0x0000, 0x0000 }, /* R713 */
- { 0x0000, 0x0000, 0x0000 }, /* R714 */
- { 0x0000, 0x0000, 0x0000 }, /* R715 */
- { 0x0000, 0x0000, 0x0000 }, /* R716 */
- { 0x0000, 0x0000, 0x0000 }, /* R717 */
- { 0x0000, 0x0000, 0x0000 }, /* R718 */
- { 0x0000, 0x0000, 0x0000 }, /* R719 */
- { 0x0000, 0x0000, 0x0000 }, /* R720 */
- { 0x0000, 0x0000, 0x0000 }, /* R721 */
- { 0x0000, 0x0000, 0x0000 }, /* R722 */
- { 0x0000, 0x0000, 0x0000 }, /* R723 */
- { 0x0000, 0x0000, 0x0000 }, /* R724 */
- { 0x0000, 0x0000, 0x0000 }, /* R725 */
- { 0x0000, 0x0000, 0x0000 }, /* R726 */
- { 0x0000, 0x0000, 0x0000 }, /* R727 */
- { 0x0000, 0x0000, 0x0000 }, /* R728 */
- { 0x0000, 0x0000, 0x0000 }, /* R729 */
- { 0x0000, 0x0000, 0x0000 }, /* R730 */
- { 0x0000, 0x0000, 0x0000 }, /* R731 */
- { 0x0000, 0x0000, 0x0000 }, /* R732 */
- { 0x0000, 0x0000, 0x0000 }, /* R733 */
- { 0x0000, 0x0000, 0x0000 }, /* R734 */
- { 0x0000, 0x0000, 0x0000 }, /* R735 */
- { 0x0000, 0x0000, 0x0000 }, /* R736 */
- { 0x0000, 0x0000, 0x0000 }, /* R737 */
- { 0x0000, 0x0000, 0x0000 }, /* R738 */
- { 0x0000, 0x0000, 0x0000 }, /* R739 */
- { 0x0000, 0x0000, 0x0000 }, /* R740 */
- { 0x0000, 0x0000, 0x0000 }, /* R741 */
- { 0x0000, 0x0000, 0x0000 }, /* R742 */
- { 0x0000, 0x0000, 0x0000 }, /* R743 */
- { 0x0000, 0x0000, 0x0000 }, /* R744 */
- { 0x0000, 0x0000, 0x0000 }, /* R745 */
- { 0x0000, 0x0000, 0x0000 }, /* R746 */
- { 0x0000, 0x0000, 0x0000 }, /* R747 */
- { 0x0000, 0x0000, 0x0000 }, /* R748 */
- { 0x0000, 0x0000, 0x0000 }, /* R749 */
- { 0x0000, 0x0000, 0x0000 }, /* R750 */
- { 0x0000, 0x0000, 0x0000 }, /* R751 */
- { 0x0000, 0x0000, 0x0000 }, /* R752 */
- { 0x0000, 0x0000, 0x0000 }, /* R753 */
- { 0x0000, 0x0000, 0x0000 }, /* R754 */
- { 0x0000, 0x0000, 0x0000 }, /* R755 */
- { 0x0000, 0x0000, 0x0000 }, /* R756 */
- { 0x0000, 0x0000, 0x0000 }, /* R757 */
- { 0x0000, 0x0000, 0x0000 }, /* R758 */
- { 0x0000, 0x0000, 0x0000 }, /* R759 */
- { 0x0000, 0x0000, 0x0000 }, /* R760 */
- { 0x0000, 0x0000, 0x0000 }, /* R761 */
- { 0x0000, 0x0000, 0x0000 }, /* R762 */
- { 0x0000, 0x0000, 0x0000 }, /* R763 */
- { 0x0000, 0x0000, 0x0000 }, /* R764 */
- { 0x0000, 0x0000, 0x0000 }, /* R765 */
- { 0x0000, 0x0000, 0x0000 }, /* R766 */
- { 0x0000, 0x0000, 0x0000 }, /* R767 */
- { 0xE1F8, 0xE1F8, 0x0000 }, /* R768 - AIF1 Control (1) */
- { 0xCD1F, 0xCD1F, 0x0000 }, /* R769 - AIF1 Control (2) */
- { 0xF000, 0xF000, 0x0000 }, /* R770 - AIF1 Master/Slave */
- { 0x01F0, 0x01F0, 0x0000 }, /* R771 - AIF1 BCLK */
- { 0x0FFF, 0x0FFF, 0x0000 }, /* R772 - AIF1ADC LRCLK */
- { 0x0FFF, 0x0FFF, 0x0000 }, /* R773 - AIF1DAC LRCLK */
- { 0x0003, 0x0003, 0x0000 }, /* R774 - AIF1DAC Data */
- { 0x0003, 0x0003, 0x0000 }, /* R775 - AIF1ADC Data */
- { 0x0000, 0x0000, 0x0000 }, /* R776 */
- { 0x0000, 0x0000, 0x0000 }, /* R777 */
- { 0x0000, 0x0000, 0x0000 }, /* R778 */
- { 0x0000, 0x0000, 0x0000 }, /* R779 */
- { 0x0000, 0x0000, 0x0000 }, /* R780 */
- { 0x0000, 0x0000, 0x0000 }, /* R781 */
- { 0x0000, 0x0000, 0x0000 }, /* R782 */
- { 0x0000, 0x0000, 0x0000 }, /* R783 */
- { 0xF1F8, 0xF1F8, 0x0000 }, /* R784 - AIF2 Control (1) */
- { 0xFD1F, 0xFD1F, 0x0000 }, /* R785 - AIF2 Control (2) */
- { 0xF000, 0xF000, 0x0000 }, /* R786 - AIF2 Master/Slave */
- { 0x01F0, 0x01F0, 0x0000 }, /* R787 - AIF2 BCLK */
- { 0x0FFF, 0x0FFF, 0x0000 }, /* R788 - AIF2ADC LRCLK */
- { 0x0FFF, 0x0FFF, 0x0000 }, /* R789 - AIF2DAC LRCLK */
- { 0x0003, 0x0003, 0x0000 }, /* R790 - AIF2DAC Data */
- { 0x0003, 0x0003, 0x0000 }, /* R791 - AIF2ADC Data */
- { 0x0000, 0x0000, 0x0000 }, /* R792 */
- { 0x0000, 0x0000, 0x0000 }, /* R793 */
- { 0x0000, 0x0000, 0x0000 }, /* R794 */
- { 0x0000, 0x0000, 0x0000 }, /* R795 */
- { 0x0000, 0x0000, 0x0000 }, /* R796 */
- { 0x0000, 0x0000, 0x0000 }, /* R797 */
- { 0x0000, 0x0000, 0x0000 }, /* R798 */
- { 0x0000, 0x0000, 0x0000 }, /* R799 */
- { 0x0000, 0x0000, 0x0000 }, /* R800 */
- { 0x0000, 0x0000, 0x0000 }, /* R801 */
- { 0x0000, 0x0000, 0x0000 }, /* R802 */
- { 0x0000, 0x0000, 0x0000 }, /* R803 */
- { 0x0000, 0x0000, 0x0000 }, /* R804 */
- { 0x0000, 0x0000, 0x0000 }, /* R805 */
- { 0x0000, 0x0000, 0x0000 }, /* R806 */
- { 0x0000, 0x0000, 0x0000 }, /* R807 */
- { 0x0000, 0x0000, 0x0000 }, /* R808 */
- { 0x0000, 0x0000, 0x0000 }, /* R809 */
- { 0x0000, 0x0000, 0x0000 }, /* R810 */
- { 0x0000, 0x0000, 0x0000 }, /* R811 */
- { 0x0000, 0x0000, 0x0000 }, /* R812 */
- { 0x0000, 0x0000, 0x0000 }, /* R813 */
- { 0x0000, 0x0000, 0x0000 }, /* R814 */
- { 0x0000, 0x0000, 0x0000 }, /* R815 */
- { 0x0000, 0x0000, 0x0000 }, /* R816 */
- { 0x0000, 0x0000, 0x0000 }, /* R817 */
- { 0x0000, 0x0000, 0x0000 }, /* R818 */
- { 0x0000, 0x0000, 0x0000 }, /* R819 */
- { 0x0000, 0x0000, 0x0000 }, /* R820 */
- { 0x0000, 0x0000, 0x0000 }, /* R821 */
- { 0x0000, 0x0000, 0x0000 }, /* R822 */
- { 0x0000, 0x0000, 0x0000 }, /* R823 */
- { 0x0000, 0x0000, 0x0000 }, /* R824 */
- { 0x0000, 0x0000, 0x0000 }, /* R825 */
- { 0x0000, 0x0000, 0x0000 }, /* R826 */
- { 0x0000, 0x0000, 0x0000 }, /* R827 */
- { 0x0000, 0x0000, 0x0000 }, /* R828 */
- { 0x0000, 0x0000, 0x0000 }, /* R829 */
- { 0x0000, 0x0000, 0x0000 }, /* R830 */
- { 0x0000, 0x0000, 0x0000 }, /* R831 */
- { 0x0000, 0x0000, 0x0000 }, /* R832 */
- { 0x0000, 0x0000, 0x0000 }, /* R833 */
- { 0x0000, 0x0000, 0x0000 }, /* R834 */
- { 0x0000, 0x0000, 0x0000 }, /* R835 */
- { 0x0000, 0x0000, 0x0000 }, /* R836 */
- { 0x0000, 0x0000, 0x0000 }, /* R837 */
- { 0x0000, 0x0000, 0x0000 }, /* R838 */
- { 0x0000, 0x0000, 0x0000 }, /* R839 */
- { 0x0000, 0x0000, 0x0000 }, /* R840 */
- { 0x0000, 0x0000, 0x0000 }, /* R841 */
- { 0x0000, 0x0000, 0x0000 }, /* R842 */
- { 0x0000, 0x0000, 0x0000 }, /* R843 */
- { 0x0000, 0x0000, 0x0000 }, /* R844 */
- { 0x0000, 0x0000, 0x0000 }, /* R845 */
- { 0x0000, 0x0000, 0x0000 }, /* R846 */
- { 0x0000, 0x0000, 0x0000 }, /* R847 */
- { 0x0000, 0x0000, 0x0000 }, /* R848 */
- { 0x0000, 0x0000, 0x0000 }, /* R849 */
- { 0x0000, 0x0000, 0x0000 }, /* R850 */
- { 0x0000, 0x0000, 0x0000 }, /* R851 */
- { 0x0000, 0x0000, 0x0000 }, /* R852 */
- { 0x0000, 0x0000, 0x0000 }, /* R853 */
- { 0x0000, 0x0000, 0x0000 }, /* R854 */
- { 0x0000, 0x0000, 0x0000 }, /* R855 */
- { 0x0000, 0x0000, 0x0000 }, /* R856 */
- { 0x0000, 0x0000, 0x0000 }, /* R857 */
- { 0x0000, 0x0000, 0x0000 }, /* R858 */
- { 0x0000, 0x0000, 0x0000 }, /* R859 */
- { 0x0000, 0x0000, 0x0000 }, /* R860 */
- { 0x0000, 0x0000, 0x0000 }, /* R861 */
- { 0x0000, 0x0000, 0x0000 }, /* R862 */
- { 0x0000, 0x0000, 0x0000 }, /* R863 */
- { 0x0000, 0x0000, 0x0000 }, /* R864 */
- { 0x0000, 0x0000, 0x0000 }, /* R865 */
- { 0x0000, 0x0000, 0x0000 }, /* R866 */
- { 0x0000, 0x0000, 0x0000 }, /* R867 */
- { 0x0000, 0x0000, 0x0000 }, /* R868 */
- { 0x0000, 0x0000, 0x0000 }, /* R869 */
- { 0x0000, 0x0000, 0x0000 }, /* R870 */
- { 0x0000, 0x0000, 0x0000 }, /* R871 */
- { 0x0000, 0x0000, 0x0000 }, /* R872 */
- { 0x0000, 0x0000, 0x0000 }, /* R873 */
- { 0x0000, 0x0000, 0x0000 }, /* R874 */
- { 0x0000, 0x0000, 0x0000 }, /* R875 */
- { 0x0000, 0x0000, 0x0000 }, /* R876 */
- { 0x0000, 0x0000, 0x0000 }, /* R877 */
- { 0x0000, 0x0000, 0x0000 }, /* R878 */
- { 0x0000, 0x0000, 0x0000 }, /* R879 */
- { 0x0000, 0x0000, 0x0000 }, /* R880 */
- { 0x0000, 0x0000, 0x0000 }, /* R881 */
- { 0x0000, 0x0000, 0x0000 }, /* R882 */
- { 0x0000, 0x0000, 0x0000 }, /* R883 */
- { 0x0000, 0x0000, 0x0000 }, /* R884 */
- { 0x0000, 0x0000, 0x0000 }, /* R885 */
- { 0x0000, 0x0000, 0x0000 }, /* R886 */
- { 0x0000, 0x0000, 0x0000 }, /* R887 */
- { 0x0000, 0x0000, 0x0000 }, /* R888 */
- { 0x0000, 0x0000, 0x0000 }, /* R889 */
- { 0x0000, 0x0000, 0x0000 }, /* R890 */
- { 0x0000, 0x0000, 0x0000 }, /* R891 */
- { 0x0000, 0x0000, 0x0000 }, /* R892 */
- { 0x0000, 0x0000, 0x0000 }, /* R893 */
- { 0x0000, 0x0000, 0x0000 }, /* R894 */
- { 0x0000, 0x0000, 0x0000 }, /* R895 */
- { 0x0000, 0x0000, 0x0000 }, /* R896 */
- { 0x0000, 0x0000, 0x0000 }, /* R897 */
- { 0x0000, 0x0000, 0x0000 }, /* R898 */
- { 0x0000, 0x0000, 0x0000 }, /* R899 */
- { 0x0000, 0x0000, 0x0000 }, /* R900 */
- { 0x0000, 0x0000, 0x0000 }, /* R901 */
- { 0x0000, 0x0000, 0x0000 }, /* R902 */
- { 0x0000, 0x0000, 0x0000 }, /* R903 */
- { 0x0000, 0x0000, 0x0000 }, /* R904 */
- { 0x0000, 0x0000, 0x0000 }, /* R905 */
- { 0x0000, 0x0000, 0x0000 }, /* R906 */
- { 0x0000, 0x0000, 0x0000 }, /* R907 */
- { 0x0000, 0x0000, 0x0000 }, /* R908 */
- { 0x0000, 0x0000, 0x0000 }, /* R909 */
- { 0x0000, 0x0000, 0x0000 }, /* R910 */
- { 0x0000, 0x0000, 0x0000 }, /* R911 */
- { 0x0000, 0x0000, 0x0000 }, /* R912 */
- { 0x0000, 0x0000, 0x0000 }, /* R913 */
- { 0x0000, 0x0000, 0x0000 }, /* R914 */
- { 0x0000, 0x0000, 0x0000 }, /* R915 */
- { 0x0000, 0x0000, 0x0000 }, /* R916 */
- { 0x0000, 0x0000, 0x0000 }, /* R917 */
- { 0x0000, 0x0000, 0x0000 }, /* R918 */
- { 0x0000, 0x0000, 0x0000 }, /* R919 */
- { 0x0000, 0x0000, 0x0000 }, /* R920 */
- { 0x0000, 0x0000, 0x0000 }, /* R921 */
- { 0x0000, 0x0000, 0x0000 }, /* R922 */
- { 0x0000, 0x0000, 0x0000 }, /* R923 */
- { 0x0000, 0x0000, 0x0000 }, /* R924 */
- { 0x0000, 0x0000, 0x0000 }, /* R925 */
- { 0x0000, 0x0000, 0x0000 }, /* R926 */
- { 0x0000, 0x0000, 0x0000 }, /* R927 */
- { 0x0000, 0x0000, 0x0000 }, /* R928 */
- { 0x0000, 0x0000, 0x0000 }, /* R929 */
- { 0x0000, 0x0000, 0x0000 }, /* R930 */
- { 0x0000, 0x0000, 0x0000 }, /* R931 */
- { 0x0000, 0x0000, 0x0000 }, /* R932 */
- { 0x0000, 0x0000, 0x0000 }, /* R933 */
- { 0x0000, 0x0000, 0x0000 }, /* R934 */
- { 0x0000, 0x0000, 0x0000 }, /* R935 */
- { 0x0000, 0x0000, 0x0000 }, /* R936 */
- { 0x0000, 0x0000, 0x0000 }, /* R937 */
- { 0x0000, 0x0000, 0x0000 }, /* R938 */
- { 0x0000, 0x0000, 0x0000 }, /* R939 */
- { 0x0000, 0x0000, 0x0000 }, /* R940 */
- { 0x0000, 0x0000, 0x0000 }, /* R941 */
- { 0x0000, 0x0000, 0x0000 }, /* R942 */
- { 0x0000, 0x0000, 0x0000 }, /* R943 */
- { 0x0000, 0x0000, 0x0000 }, /* R944 */
- { 0x0000, 0x0000, 0x0000 }, /* R945 */
- { 0x0000, 0x0000, 0x0000 }, /* R946 */
- { 0x0000, 0x0000, 0x0000 }, /* R947 */
- { 0x0000, 0x0000, 0x0000 }, /* R948 */
- { 0x0000, 0x0000, 0x0000 }, /* R949 */
- { 0x0000, 0x0000, 0x0000 }, /* R950 */
- { 0x0000, 0x0000, 0x0000 }, /* R951 */
- { 0x0000, 0x0000, 0x0000 }, /* R952 */
- { 0x0000, 0x0000, 0x0000 }, /* R953 */
- { 0x0000, 0x0000, 0x0000 }, /* R954 */
- { 0x0000, 0x0000, 0x0000 }, /* R955 */
- { 0x0000, 0x0000, 0x0000 }, /* R956 */
- { 0x0000, 0x0000, 0x0000 }, /* R957 */
- { 0x0000, 0x0000, 0x0000 }, /* R958 */
- { 0x0000, 0x0000, 0x0000 }, /* R959 */
- { 0x0000, 0x0000, 0x0000 }, /* R960 */
- { 0x0000, 0x0000, 0x0000 }, /* R961 */
- { 0x0000, 0x0000, 0x0000 }, /* R962 */
- { 0x0000, 0x0000, 0x0000 }, /* R963 */
- { 0x0000, 0x0000, 0x0000 }, /* R964 */
- { 0x0000, 0x0000, 0x0000 }, /* R965 */
- { 0x0000, 0x0000, 0x0000 }, /* R966 */
- { 0x0000, 0x0000, 0x0000 }, /* R967 */
- { 0x0000, 0x0000, 0x0000 }, /* R968 */
- { 0x0000, 0x0000, 0x0000 }, /* R969 */
- { 0x0000, 0x0000, 0x0000 }, /* R970 */
- { 0x0000, 0x0000, 0x0000 }, /* R971 */
- { 0x0000, 0x0000, 0x0000 }, /* R972 */
- { 0x0000, 0x0000, 0x0000 }, /* R973 */
- { 0x0000, 0x0000, 0x0000 }, /* R974 */
- { 0x0000, 0x0000, 0x0000 }, /* R975 */
- { 0x0000, 0x0000, 0x0000 }, /* R976 */
- { 0x0000, 0x0000, 0x0000 }, /* R977 */
- { 0x0000, 0x0000, 0x0000 }, /* R978 */
- { 0x0000, 0x0000, 0x0000 }, /* R979 */
- { 0x0000, 0x0000, 0x0000 }, /* R980 */
- { 0x0000, 0x0000, 0x0000 }, /* R981 */
- { 0x0000, 0x0000, 0x0000 }, /* R982 */
- { 0x0000, 0x0000, 0x0000 }, /* R983 */
- { 0x0000, 0x0000, 0x0000 }, /* R984 */
- { 0x0000, 0x0000, 0x0000 }, /* R985 */
- { 0x0000, 0x0000, 0x0000 }, /* R986 */
- { 0x0000, 0x0000, 0x0000 }, /* R987 */
- { 0x0000, 0x0000, 0x0000 }, /* R988 */
- { 0x0000, 0x0000, 0x0000 }, /* R989 */
- { 0x0000, 0x0000, 0x0000 }, /* R990 */
- { 0x0000, 0x0000, 0x0000 }, /* R991 */
- { 0x0000, 0x0000, 0x0000 }, /* R992 */
- { 0x0000, 0x0000, 0x0000 }, /* R993 */
- { 0x0000, 0x0000, 0x0000 }, /* R994 */
- { 0x0000, 0x0000, 0x0000 }, /* R995 */
- { 0x0000, 0x0000, 0x0000 }, /* R996 */
- { 0x0000, 0x0000, 0x0000 }, /* R997 */
- { 0x0000, 0x0000, 0x0000 }, /* R998 */
- { 0x0000, 0x0000, 0x0000 }, /* R999 */
- { 0x0000, 0x0000, 0x0000 }, /* R1000 */
- { 0x0000, 0x0000, 0x0000 }, /* R1001 */
- { 0x0000, 0x0000, 0x0000 }, /* R1002 */
- { 0x0000, 0x0000, 0x0000 }, /* R1003 */
- { 0x0000, 0x0000, 0x0000 }, /* R1004 */
- { 0x0000, 0x0000, 0x0000 }, /* R1005 */
- { 0x0000, 0x0000, 0x0000 }, /* R1006 */
- { 0x0000, 0x0000, 0x0000 }, /* R1007 */
- { 0x0000, 0x0000, 0x0000 }, /* R1008 */
- { 0x0000, 0x0000, 0x0000 }, /* R1009 */
- { 0x0000, 0x0000, 0x0000 }, /* R1010 */
- { 0x0000, 0x0000, 0x0000 }, /* R1011 */
- { 0x0000, 0x0000, 0x0000 }, /* R1012 */
- { 0x0000, 0x0000, 0x0000 }, /* R1013 */
- { 0x0000, 0x0000, 0x0000 }, /* R1014 */
- { 0x0000, 0x0000, 0x0000 }, /* R1015 */
- { 0x0000, 0x0000, 0x0000 }, /* R1016 */
- { 0x0000, 0x0000, 0x0000 }, /* R1017 */
- { 0x0000, 0x0000, 0x0000 }, /* R1018 */
- { 0x0000, 0x0000, 0x0000 }, /* R1019 */
- { 0x0000, 0x0000, 0x0000 }, /* R1020 */
- { 0x0000, 0x0000, 0x0000 }, /* R1021 */
- { 0x0000, 0x0000, 0x0000 }, /* R1022 */
- { 0x0000, 0x0000, 0x0000 }, /* R1023 */
- { 0x00FF, 0x01FF, 0x0000 }, /* R1024 - AIF1 ADC1 Left Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R1025 - AIF1 ADC1 Right Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R1026 - AIF1 DAC1 Left Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R1027 - AIF1 DAC1 Right Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R1028 - AIF1 ADC2 Left Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R1029 - AIF1 ADC2 Right Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R1030 - AIF1 DAC2 Left Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R1031 - AIF1 DAC2 Right Volume */
- { 0x0000, 0x0000, 0x0000 }, /* R1032 */
- { 0x0000, 0x0000, 0x0000 }, /* R1033 */
- { 0x0000, 0x0000, 0x0000 }, /* R1034 */
- { 0x0000, 0x0000, 0x0000 }, /* R1035 */
- { 0x0000, 0x0000, 0x0000 }, /* R1036 */
- { 0x0000, 0x0000, 0x0000 }, /* R1037 */
- { 0x0000, 0x0000, 0x0000 }, /* R1038 */
- { 0x0000, 0x0000, 0x0000 }, /* R1039 */
- { 0xF800, 0xF800, 0x0000 }, /* R1040 - AIF1 ADC1 Filters */
- { 0x7800, 0x7800, 0x0000 }, /* R1041 - AIF1 ADC2 Filters */
- { 0x0000, 0x0000, 0x0000 }, /* R1042 */
- { 0x0000, 0x0000, 0x0000 }, /* R1043 */
- { 0x0000, 0x0000, 0x0000 }, /* R1044 */
- { 0x0000, 0x0000, 0x0000 }, /* R1045 */
- { 0x0000, 0x0000, 0x0000 }, /* R1046 */
- { 0x0000, 0x0000, 0x0000 }, /* R1047 */
- { 0x0000, 0x0000, 0x0000 }, /* R1048 */
- { 0x0000, 0x0000, 0x0000 }, /* R1049 */
- { 0x0000, 0x0000, 0x0000 }, /* R1050 */
- { 0x0000, 0x0000, 0x0000 }, /* R1051 */
- { 0x0000, 0x0000, 0x0000 }, /* R1052 */
- { 0x0000, 0x0000, 0x0000 }, /* R1053 */
- { 0x0000, 0x0000, 0x0000 }, /* R1054 */
- { 0x0000, 0x0000, 0x0000 }, /* R1055 */
- { 0x02B6, 0x02B6, 0x0000 }, /* R1056 - AIF1 DAC1 Filters (1) */
- { 0x3F00, 0x3F00, 0x0000 }, /* R1057 - AIF1 DAC1 Filters (2) */
- { 0x02B6, 0x02B6, 0x0000 }, /* R1058 - AIF1 DAC2 Filters (1) */
- { 0x3F00, 0x3F00, 0x0000 }, /* R1059 - AIF1 DAC2 Filters (2) */
- { 0x0000, 0x0000, 0x0000 }, /* R1060 */
- { 0x0000, 0x0000, 0x0000 }, /* R1061 */
- { 0x0000, 0x0000, 0x0000 }, /* R1062 */
- { 0x0000, 0x0000, 0x0000 }, /* R1063 */
- { 0x0000, 0x0000, 0x0000 }, /* R1064 */
- { 0x0000, 0x0000, 0x0000 }, /* R1065 */
- { 0x0000, 0x0000, 0x0000 }, /* R1066 */
- { 0x0000, 0x0000, 0x0000 }, /* R1067 */
- { 0x0000, 0x0000, 0x0000 }, /* R1068 */
- { 0x0000, 0x0000, 0x0000 }, /* R1069 */
- { 0x0000, 0x0000, 0x0000 }, /* R1070 */
- { 0x0000, 0x0000, 0x0000 }, /* R1071 */
- { 0x0000, 0x0000, 0x0000 }, /* R1072 */
- { 0x0000, 0x0000, 0x0000 }, /* R1073 */
- { 0x0000, 0x0000, 0x0000 }, /* R1074 */
- { 0x0000, 0x0000, 0x0000 }, /* R1075 */
- { 0x0000, 0x0000, 0x0000 }, /* R1076 */
- { 0x0000, 0x0000, 0x0000 }, /* R1077 */
- { 0x0000, 0x0000, 0x0000 }, /* R1078 */
- { 0x0000, 0x0000, 0x0000 }, /* R1079 */
- { 0x0000, 0x0000, 0x0000 }, /* R1080 */
- { 0x0000, 0x0000, 0x0000 }, /* R1081 */
- { 0x0000, 0x0000, 0x0000 }, /* R1082 */
- { 0x0000, 0x0000, 0x0000 }, /* R1083 */
- { 0x0000, 0x0000, 0x0000 }, /* R1084 */
- { 0x0000, 0x0000, 0x0000 }, /* R1085 */
- { 0x0000, 0x0000, 0x0000 }, /* R1086 */
- { 0x0000, 0x0000, 0x0000 }, /* R1087 */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1088 - AIF1 DRC1 (1) */
- { 0x1FFF, 0x1FFF, 0x0000 }, /* R1089 - AIF1 DRC1 (2) */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1090 - AIF1 DRC1 (3) */
- { 0x07FF, 0x07FF, 0x0000 }, /* R1091 - AIF1 DRC1 (4) */
- { 0x03FF, 0x03FF, 0x0000 }, /* R1092 - AIF1 DRC1 (5) */
- { 0x0000, 0x0000, 0x0000 }, /* R1093 */
- { 0x0000, 0x0000, 0x0000 }, /* R1094 */
- { 0x0000, 0x0000, 0x0000 }, /* R1095 */
- { 0x0000, 0x0000, 0x0000 }, /* R1096 */
- { 0x0000, 0x0000, 0x0000 }, /* R1097 */
- { 0x0000, 0x0000, 0x0000 }, /* R1098 */
- { 0x0000, 0x0000, 0x0000 }, /* R1099 */
- { 0x0000, 0x0000, 0x0000 }, /* R1100 */
- { 0x0000, 0x0000, 0x0000 }, /* R1101 */
- { 0x0000, 0x0000, 0x0000 }, /* R1102 */
- { 0x0000, 0x0000, 0x0000 }, /* R1103 */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1104 - AIF1 DRC2 (1) */
- { 0x1FFF, 0x1FFF, 0x0000 }, /* R1105 - AIF1 DRC2 (2) */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1106 - AIF1 DRC2 (3) */
- { 0x07FF, 0x07FF, 0x0000 }, /* R1107 - AIF1 DRC2 (4) */
- { 0x03FF, 0x03FF, 0x0000 }, /* R1108 - AIF1 DRC2 (5) */
- { 0x0000, 0x0000, 0x0000 }, /* R1109 */
- { 0x0000, 0x0000, 0x0000 }, /* R1110 */
- { 0x0000, 0x0000, 0x0000 }, /* R1111 */
- { 0x0000, 0x0000, 0x0000 }, /* R1112 */
- { 0x0000, 0x0000, 0x0000 }, /* R1113 */
- { 0x0000, 0x0000, 0x0000 }, /* R1114 */
- { 0x0000, 0x0000, 0x0000 }, /* R1115 */
- { 0x0000, 0x0000, 0x0000 }, /* R1116 */
- { 0x0000, 0x0000, 0x0000 }, /* R1117 */
- { 0x0000, 0x0000, 0x0000 }, /* R1118 */
- { 0x0000, 0x0000, 0x0000 }, /* R1119 */
- { 0x0000, 0x0000, 0x0000 }, /* R1120 */
- { 0x0000, 0x0000, 0x0000 }, /* R1121 */
- { 0x0000, 0x0000, 0x0000 }, /* R1122 */
- { 0x0000, 0x0000, 0x0000 }, /* R1123 */
- { 0x0000, 0x0000, 0x0000 }, /* R1124 */
- { 0x0000, 0x0000, 0x0000 }, /* R1125 */
- { 0x0000, 0x0000, 0x0000 }, /* R1126 */
- { 0x0000, 0x0000, 0x0000 }, /* R1127 */
- { 0x0000, 0x0000, 0x0000 }, /* R1128 */
- { 0x0000, 0x0000, 0x0000 }, /* R1129 */
- { 0x0000, 0x0000, 0x0000 }, /* R1130 */
- { 0x0000, 0x0000, 0x0000 }, /* R1131 */
- { 0x0000, 0x0000, 0x0000 }, /* R1132 */
- { 0x0000, 0x0000, 0x0000 }, /* R1133 */
- { 0x0000, 0x0000, 0x0000 }, /* R1134 */
- { 0x0000, 0x0000, 0x0000 }, /* R1135 */
- { 0x0000, 0x0000, 0x0000 }, /* R1136 */
- { 0x0000, 0x0000, 0x0000 }, /* R1137 */
- { 0x0000, 0x0000, 0x0000 }, /* R1138 */
- { 0x0000, 0x0000, 0x0000 }, /* R1139 */
- { 0x0000, 0x0000, 0x0000 }, /* R1140 */
- { 0x0000, 0x0000, 0x0000 }, /* R1141 */
- { 0x0000, 0x0000, 0x0000 }, /* R1142 */
- { 0x0000, 0x0000, 0x0000 }, /* R1143 */
- { 0x0000, 0x0000, 0x0000 }, /* R1144 */
- { 0x0000, 0x0000, 0x0000 }, /* R1145 */
- { 0x0000, 0x0000, 0x0000 }, /* R1146 */
- { 0x0000, 0x0000, 0x0000 }, /* R1147 */
- { 0x0000, 0x0000, 0x0000 }, /* R1148 */
- { 0x0000, 0x0000, 0x0000 }, /* R1149 */
- { 0x0000, 0x0000, 0x0000 }, /* R1150 */
- { 0x0000, 0x0000, 0x0000 }, /* R1151 */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1152 - AIF1 DAC1 EQ Gains (1) */
- { 0xFFC0, 0xFFC0, 0x0000 }, /* R1153 - AIF1 DAC1 EQ Gains (2) */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1154 - AIF1 DAC1 EQ Band 1 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1155 - AIF1 DAC1 EQ Band 1 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1156 - AIF1 DAC1 EQ Band 1 PG */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1157 - AIF1 DAC1 EQ Band 2 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1158 - AIF1 DAC1 EQ Band 2 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1159 - AIF1 DAC1 EQ Band 2 C */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1160 - AIF1 DAC1 EQ Band 2 PG */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1161 - AIF1 DAC1 EQ Band 3 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1162 - AIF1 DAC1 EQ Band 3 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1163 - AIF1 DAC1 EQ Band 3 C */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1164 - AIF1 DAC1 EQ Band 3 PG */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1165 - AIF1 DAC1 EQ Band 4 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1166 - AIF1 DAC1 EQ Band 4 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1167 - AIF1 DAC1 EQ Band 4 C */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1168 - AIF1 DAC1 EQ Band 4 PG */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1169 - AIF1 DAC1 EQ Band 5 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1170 - AIF1 DAC1 EQ Band 5 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1171 - AIF1 DAC1 EQ Band 5 PG */
- { 0x0000, 0x0000, 0x0000 }, /* R1172 */
- { 0x0000, 0x0000, 0x0000 }, /* R1173 */
- { 0x0000, 0x0000, 0x0000 }, /* R1174 */
- { 0x0000, 0x0000, 0x0000 }, /* R1175 */
- { 0x0000, 0x0000, 0x0000 }, /* R1176 */
- { 0x0000, 0x0000, 0x0000 }, /* R1177 */
- { 0x0000, 0x0000, 0x0000 }, /* R1178 */
- { 0x0000, 0x0000, 0x0000 }, /* R1179 */
- { 0x0000, 0x0000, 0x0000 }, /* R1180 */
- { 0x0000, 0x0000, 0x0000 }, /* R1181 */
- { 0x0000, 0x0000, 0x0000 }, /* R1182 */
- { 0x0000, 0x0000, 0x0000 }, /* R1183 */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1184 - AIF1 DAC2 EQ Gains (1) */
- { 0xFFC0, 0xFFC0, 0x0000 }, /* R1185 - AIF1 DAC2 EQ Gains (2) */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1186 - AIF1 DAC2 EQ Band 1 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1187 - AIF1 DAC2 EQ Band 1 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1188 - AIF1 DAC2 EQ Band 1 PG */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1189 - AIF1 DAC2 EQ Band 2 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1190 - AIF1 DAC2 EQ Band 2 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1191 - AIF1 DAC2 EQ Band 2 C */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1192 - AIF1 DAC2 EQ Band 2 PG */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1193 - AIF1 DAC2 EQ Band 3 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1194 - AIF1 DAC2 EQ Band 3 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1195 - AIF1 DAC2 EQ Band 3 C */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1196 - AIF1 DAC2 EQ Band 3 PG */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1197 - AIF1 DAC2 EQ Band 4 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1198 - AIF1 DAC2 EQ Band 4 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1199 - AIF1 DAC2 EQ Band 4 C */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1200 - AIF1 DAC2 EQ Band 4 PG */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1201 - AIF1 DAC2 EQ Band 5 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1202 - AIF1 DAC2 EQ Band 5 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1203 - AIF1 DAC2 EQ Band 5 PG */
- { 0x0000, 0x0000, 0x0000 }, /* R1204 */
- { 0x0000, 0x0000, 0x0000 }, /* R1205 */
- { 0x0000, 0x0000, 0x0000 }, /* R1206 */
- { 0x0000, 0x0000, 0x0000 }, /* R1207 */
- { 0x0000, 0x0000, 0x0000 }, /* R1208 */
- { 0x0000, 0x0000, 0x0000 }, /* R1209 */
- { 0x0000, 0x0000, 0x0000 }, /* R1210 */
- { 0x0000, 0x0000, 0x0000 }, /* R1211 */
- { 0x0000, 0x0000, 0x0000 }, /* R1212 */
- { 0x0000, 0x0000, 0x0000 }, /* R1213 */
- { 0x0000, 0x0000, 0x0000 }, /* R1214 */
- { 0x0000, 0x0000, 0x0000 }, /* R1215 */
- { 0x0000, 0x0000, 0x0000 }, /* R1216 */
- { 0x0000, 0x0000, 0x0000 }, /* R1217 */
- { 0x0000, 0x0000, 0x0000 }, /* R1218 */
- { 0x0000, 0x0000, 0x0000 }, /* R1219 */
- { 0x0000, 0x0000, 0x0000 }, /* R1220 */
- { 0x0000, 0x0000, 0x0000 }, /* R1221 */
- { 0x0000, 0x0000, 0x0000 }, /* R1222 */
- { 0x0000, 0x0000, 0x0000 }, /* R1223 */
- { 0x0000, 0x0000, 0x0000 }, /* R1224 */
- { 0x0000, 0x0000, 0x0000 }, /* R1225 */
- { 0x0000, 0x0000, 0x0000 }, /* R1226 */
- { 0x0000, 0x0000, 0x0000 }, /* R1227 */
- { 0x0000, 0x0000, 0x0000 }, /* R1228 */
- { 0x0000, 0x0000, 0x0000 }, /* R1229 */
- { 0x0000, 0x0000, 0x0000 }, /* R1230 */
- { 0x0000, 0x0000, 0x0000 }, /* R1231 */
- { 0x0000, 0x0000, 0x0000 }, /* R1232 */
- { 0x0000, 0x0000, 0x0000 }, /* R1233 */
- { 0x0000, 0x0000, 0x0000 }, /* R1234 */
- { 0x0000, 0x0000, 0x0000 }, /* R1235 */
- { 0x0000, 0x0000, 0x0000 }, /* R1236 */
- { 0x0000, 0x0000, 0x0000 }, /* R1237 */
- { 0x0000, 0x0000, 0x0000 }, /* R1238 */
- { 0x0000, 0x0000, 0x0000 }, /* R1239 */
- { 0x0000, 0x0000, 0x0000 }, /* R1240 */
- { 0x0000, 0x0000, 0x0000 }, /* R1241 */
- { 0x0000, 0x0000, 0x0000 }, /* R1242 */
- { 0x0000, 0x0000, 0x0000 }, /* R1243 */
- { 0x0000, 0x0000, 0x0000 }, /* R1244 */
- { 0x0000, 0x0000, 0x0000 }, /* R1245 */
- { 0x0000, 0x0000, 0x0000 }, /* R1246 */
- { 0x0000, 0x0000, 0x0000 }, /* R1247 */
- { 0x0000, 0x0000, 0x0000 }, /* R1248 */
- { 0x0000, 0x0000, 0x0000 }, /* R1249 */
- { 0x0000, 0x0000, 0x0000 }, /* R1250 */
- { 0x0000, 0x0000, 0x0000 }, /* R1251 */
- { 0x0000, 0x0000, 0x0000 }, /* R1252 */
- { 0x0000, 0x0000, 0x0000 }, /* R1253 */
- { 0x0000, 0x0000, 0x0000 }, /* R1254 */
- { 0x0000, 0x0000, 0x0000 }, /* R1255 */
- { 0x0000, 0x0000, 0x0000 }, /* R1256 */
- { 0x0000, 0x0000, 0x0000 }, /* R1257 */
- { 0x0000, 0x0000, 0x0000 }, /* R1258 */
- { 0x0000, 0x0000, 0x0000 }, /* R1259 */
- { 0x0000, 0x0000, 0x0000 }, /* R1260 */
- { 0x0000, 0x0000, 0x0000 }, /* R1261 */
- { 0x0000, 0x0000, 0x0000 }, /* R1262 */
- { 0x0000, 0x0000, 0x0000 }, /* R1263 */
- { 0x0000, 0x0000, 0x0000 }, /* R1264 */
- { 0x0000, 0x0000, 0x0000 }, /* R1265 */
- { 0x0000, 0x0000, 0x0000 }, /* R1266 */
- { 0x0000, 0x0000, 0x0000 }, /* R1267 */
- { 0x0000, 0x0000, 0x0000 }, /* R1268 */
- { 0x0000, 0x0000, 0x0000 }, /* R1269 */
- { 0x0000, 0x0000, 0x0000 }, /* R1270 */
- { 0x0000, 0x0000, 0x0000 }, /* R1271 */
- { 0x0000, 0x0000, 0x0000 }, /* R1272 */
- { 0x0000, 0x0000, 0x0000 }, /* R1273 */
- { 0x0000, 0x0000, 0x0000 }, /* R1274 */
- { 0x0000, 0x0000, 0x0000 }, /* R1275 */
- { 0x0000, 0x0000, 0x0000 }, /* R1276 */
- { 0x0000, 0x0000, 0x0000 }, /* R1277 */
- { 0x0000, 0x0000, 0x0000 }, /* R1278 */
- { 0x0000, 0x0000, 0x0000 }, /* R1279 */
- { 0x00FF, 0x01FF, 0x0000 }, /* R1280 - AIF2 ADC Left Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R1281 - AIF2 ADC Right Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R1282 - AIF2 DAC Left Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R1283 - AIF2 DAC Right Volume */
- { 0x0000, 0x0000, 0x0000 }, /* R1284 */
- { 0x0000, 0x0000, 0x0000 }, /* R1285 */
- { 0x0000, 0x0000, 0x0000 }, /* R1286 */
- { 0x0000, 0x0000, 0x0000 }, /* R1287 */
- { 0x0000, 0x0000, 0x0000 }, /* R1288 */
- { 0x0000, 0x0000, 0x0000 }, /* R1289 */
- { 0x0000, 0x0000, 0x0000 }, /* R1290 */
- { 0x0000, 0x0000, 0x0000 }, /* R1291 */
- { 0x0000, 0x0000, 0x0000 }, /* R1292 */
- { 0x0000, 0x0000, 0x0000 }, /* R1293 */
- { 0x0000, 0x0000, 0x0000 }, /* R1294 */
- { 0x0000, 0x0000, 0x0000 }, /* R1295 */
- { 0xF800, 0xF800, 0x0000 }, /* R1296 - AIF2 ADC Filters */
- { 0x0000, 0x0000, 0x0000 }, /* R1297 */
- { 0x0000, 0x0000, 0x0000 }, /* R1298 */
- { 0x0000, 0x0000, 0x0000 }, /* R1299 */
- { 0x0000, 0x0000, 0x0000 }, /* R1300 */
- { 0x0000, 0x0000, 0x0000 }, /* R1301 */
- { 0x0000, 0x0000, 0x0000 }, /* R1302 */
- { 0x0000, 0x0000, 0x0000 }, /* R1303 */
- { 0x0000, 0x0000, 0x0000 }, /* R1304 */
- { 0x0000, 0x0000, 0x0000 }, /* R1305 */
- { 0x0000, 0x0000, 0x0000 }, /* R1306 */
- { 0x0000, 0x0000, 0x0000 }, /* R1307 */
- { 0x0000, 0x0000, 0x0000 }, /* R1308 */
- { 0x0000, 0x0000, 0x0000 }, /* R1309 */
- { 0x0000, 0x0000, 0x0000 }, /* R1310 */
- { 0x0000, 0x0000, 0x0000 }, /* R1311 */
- { 0x02B6, 0x02B6, 0x0000 }, /* R1312 - AIF2 DAC Filters (1) */
- { 0x3F00, 0x3F00, 0x0000 }, /* R1313 - AIF2 DAC Filters (2) */
- { 0x0000, 0x0000, 0x0000 }, /* R1314 */
- { 0x0000, 0x0000, 0x0000 }, /* R1315 */
- { 0x0000, 0x0000, 0x0000 }, /* R1316 */
- { 0x0000, 0x0000, 0x0000 }, /* R1317 */
- { 0x0000, 0x0000, 0x0000 }, /* R1318 */
- { 0x0000, 0x0000, 0x0000 }, /* R1319 */
- { 0x0000, 0x0000, 0x0000 }, /* R1320 */
- { 0x0000, 0x0000, 0x0000 }, /* R1321 */
- { 0x0000, 0x0000, 0x0000 }, /* R1322 */
- { 0x0000, 0x0000, 0x0000 }, /* R1323 */
- { 0x0000, 0x0000, 0x0000 }, /* R1324 */
- { 0x0000, 0x0000, 0x0000 }, /* R1325 */
- { 0x0000, 0x0000, 0x0000 }, /* R1326 */
- { 0x0000, 0x0000, 0x0000 }, /* R1327 */
- { 0x0000, 0x0000, 0x0000 }, /* R1328 */
- { 0x0000, 0x0000, 0x0000 }, /* R1329 */
- { 0x0000, 0x0000, 0x0000 }, /* R1330 */
- { 0x0000, 0x0000, 0x0000 }, /* R1331 */
- { 0x0000, 0x0000, 0x0000 }, /* R1332 */
- { 0x0000, 0x0000, 0x0000 }, /* R1333 */
- { 0x0000, 0x0000, 0x0000 }, /* R1334 */
- { 0x0000, 0x0000, 0x0000 }, /* R1335 */
- { 0x0000, 0x0000, 0x0000 }, /* R1336 */
- { 0x0000, 0x0000, 0x0000 }, /* R1337 */
- { 0x0000, 0x0000, 0x0000 }, /* R1338 */
- { 0x0000, 0x0000, 0x0000 }, /* R1339 */
- { 0x0000, 0x0000, 0x0000 }, /* R1340 */
- { 0x0000, 0x0000, 0x0000 }, /* R1341 */
- { 0x0000, 0x0000, 0x0000 }, /* R1342 */
- { 0x0000, 0x0000, 0x0000 }, /* R1343 */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1344 - AIF2 DRC (1) */
- { 0x1FFF, 0x1FFF, 0x0000 }, /* R1345 - AIF2 DRC (2) */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1346 - AIF2 DRC (3) */
- { 0x07FF, 0x07FF, 0x0000 }, /* R1347 - AIF2 DRC (4) */
- { 0x03FF, 0x03FF, 0x0000 }, /* R1348 - AIF2 DRC (5) */
- { 0x0000, 0x0000, 0x0000 }, /* R1349 */
- { 0x0000, 0x0000, 0x0000 }, /* R1350 */
- { 0x0000, 0x0000, 0x0000 }, /* R1351 */
- { 0x0000, 0x0000, 0x0000 }, /* R1352 */
- { 0x0000, 0x0000, 0x0000 }, /* R1353 */
- { 0x0000, 0x0000, 0x0000 }, /* R1354 */
- { 0x0000, 0x0000, 0x0000 }, /* R1355 */
- { 0x0000, 0x0000, 0x0000 }, /* R1356 */
- { 0x0000, 0x0000, 0x0000 }, /* R1357 */
- { 0x0000, 0x0000, 0x0000 }, /* R1358 */
- { 0x0000, 0x0000, 0x0000 }, /* R1359 */
- { 0x0000, 0x0000, 0x0000 }, /* R1360 */
- { 0x0000, 0x0000, 0x0000 }, /* R1361 */
- { 0x0000, 0x0000, 0x0000 }, /* R1362 */
- { 0x0000, 0x0000, 0x0000 }, /* R1363 */
- { 0x0000, 0x0000, 0x0000 }, /* R1364 */
- { 0x0000, 0x0000, 0x0000 }, /* R1365 */
- { 0x0000, 0x0000, 0x0000 }, /* R1366 */
- { 0x0000, 0x0000, 0x0000 }, /* R1367 */
- { 0x0000, 0x0000, 0x0000 }, /* R1368 */
- { 0x0000, 0x0000, 0x0000 }, /* R1369 */
- { 0x0000, 0x0000, 0x0000 }, /* R1370 */
- { 0x0000, 0x0000, 0x0000 }, /* R1371 */
- { 0x0000, 0x0000, 0x0000 }, /* R1372 */
- { 0x0000, 0x0000, 0x0000 }, /* R1373 */
- { 0x0000, 0x0000, 0x0000 }, /* R1374 */
- { 0x0000, 0x0000, 0x0000 }, /* R1375 */
- { 0x0000, 0x0000, 0x0000 }, /* R1376 */
- { 0x0000, 0x0000, 0x0000 }, /* R1377 */
- { 0x0000, 0x0000, 0x0000 }, /* R1378 */
- { 0x0000, 0x0000, 0x0000 }, /* R1379 */
- { 0x0000, 0x0000, 0x0000 }, /* R1380 */
- { 0x0000, 0x0000, 0x0000 }, /* R1381 */
- { 0x0000, 0x0000, 0x0000 }, /* R1382 */
- { 0x0000, 0x0000, 0x0000 }, /* R1383 */
- { 0x0000, 0x0000, 0x0000 }, /* R1384 */
- { 0x0000, 0x0000, 0x0000 }, /* R1385 */
- { 0x0000, 0x0000, 0x0000 }, /* R1386 */
- { 0x0000, 0x0000, 0x0000 }, /* R1387 */
- { 0x0000, 0x0000, 0x0000 }, /* R1388 */
- { 0x0000, 0x0000, 0x0000 }, /* R1389 */
- { 0x0000, 0x0000, 0x0000 }, /* R1390 */
- { 0x0000, 0x0000, 0x0000 }, /* R1391 */
- { 0x0000, 0x0000, 0x0000 }, /* R1392 */
- { 0x0000, 0x0000, 0x0000 }, /* R1393 */
- { 0x0000, 0x0000, 0x0000 }, /* R1394 */
- { 0x0000, 0x0000, 0x0000 }, /* R1395 */
- { 0x0000, 0x0000, 0x0000 }, /* R1396 */
- { 0x0000, 0x0000, 0x0000 }, /* R1397 */
- { 0x0000, 0x0000, 0x0000 }, /* R1398 */
- { 0x0000, 0x0000, 0x0000 }, /* R1399 */
- { 0x0000, 0x0000, 0x0000 }, /* R1400 */
- { 0x0000, 0x0000, 0x0000 }, /* R1401 */
- { 0x0000, 0x0000, 0x0000 }, /* R1402 */
- { 0x0000, 0x0000, 0x0000 }, /* R1403 */
- { 0x0000, 0x0000, 0x0000 }, /* R1404 */
- { 0x0000, 0x0000, 0x0000 }, /* R1405 */
- { 0x0000, 0x0000, 0x0000 }, /* R1406 */
- { 0x0000, 0x0000, 0x0000 }, /* R1407 */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1408 - AIF2 EQ Gains (1) */
- { 0xFFC0, 0xFFC0, 0x0000 }, /* R1409 - AIF2 EQ Gains (2) */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1410 - AIF2 EQ Band 1 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1411 - AIF2 EQ Band 1 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1412 - AIF2 EQ Band 1 PG */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1413 - AIF2 EQ Band 2 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1414 - AIF2 EQ Band 2 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1415 - AIF2 EQ Band 2 C */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1416 - AIF2 EQ Band 2 PG */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1417 - AIF2 EQ Band 3 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1418 - AIF2 EQ Band 3 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1419 - AIF2 EQ Band 3 C */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1420 - AIF2 EQ Band 3 PG */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1421 - AIF2 EQ Band 4 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1422 - AIF2 EQ Band 4 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1423 - AIF2 EQ Band 4 C */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1424 - AIF2 EQ Band 4 PG */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1425 - AIF2 EQ Band 5 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1426 - AIF2 EQ Band 5 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1427 - AIF2 EQ Band 5 PG */
- { 0x0000, 0x0000, 0x0000 }, /* R1428 */
- { 0x0000, 0x0000, 0x0000 }, /* R1429 */
- { 0x0000, 0x0000, 0x0000 }, /* R1430 */
- { 0x0000, 0x0000, 0x0000 }, /* R1431 */
- { 0x0000, 0x0000, 0x0000 }, /* R1432 */
- { 0x0000, 0x0000, 0x0000 }, /* R1433 */
- { 0x0000, 0x0000, 0x0000 }, /* R1434 */
- { 0x0000, 0x0000, 0x0000 }, /* R1435 */
- { 0x0000, 0x0000, 0x0000 }, /* R1436 */
- { 0x0000, 0x0000, 0x0000 }, /* R1437 */
- { 0x0000, 0x0000, 0x0000 }, /* R1438 */
- { 0x0000, 0x0000, 0x0000 }, /* R1439 */
- { 0x0000, 0x0000, 0x0000 }, /* R1440 */
- { 0x0000, 0x0000, 0x0000 }, /* R1441 */
- { 0x0000, 0x0000, 0x0000 }, /* R1442 */
- { 0x0000, 0x0000, 0x0000 }, /* R1443 */
- { 0x0000, 0x0000, 0x0000 }, /* R1444 */
- { 0x0000, 0x0000, 0x0000 }, /* R1445 */
- { 0x0000, 0x0000, 0x0000 }, /* R1446 */
- { 0x0000, 0x0000, 0x0000 }, /* R1447 */
- { 0x0000, 0x0000, 0x0000 }, /* R1448 */
- { 0x0000, 0x0000, 0x0000 }, /* R1449 */
- { 0x0000, 0x0000, 0x0000 }, /* R1450 */
- { 0x0000, 0x0000, 0x0000 }, /* R1451 */
- { 0x0000, 0x0000, 0x0000 }, /* R1452 */
- { 0x0000, 0x0000, 0x0000 }, /* R1453 */
- { 0x0000, 0x0000, 0x0000 }, /* R1454 */
- { 0x0000, 0x0000, 0x0000 }, /* R1455 */
- { 0x0000, 0x0000, 0x0000 }, /* R1456 */
- { 0x0000, 0x0000, 0x0000 }, /* R1457 */
- { 0x0000, 0x0000, 0x0000 }, /* R1458 */
- { 0x0000, 0x0000, 0x0000 }, /* R1459 */
- { 0x0000, 0x0000, 0x0000 }, /* R1460 */
- { 0x0000, 0x0000, 0x0000 }, /* R1461 */
- { 0x0000, 0x0000, 0x0000 }, /* R1462 */
- { 0x0000, 0x0000, 0x0000 }, /* R1463 */
- { 0x0000, 0x0000, 0x0000 }, /* R1464 */
- { 0x0000, 0x0000, 0x0000 }, /* R1465 */
- { 0x0000, 0x0000, 0x0000 }, /* R1466 */
- { 0x0000, 0x0000, 0x0000 }, /* R1467 */
- { 0x0000, 0x0000, 0x0000 }, /* R1468 */
- { 0x0000, 0x0000, 0x0000 }, /* R1469 */
- { 0x0000, 0x0000, 0x0000 }, /* R1470 */
- { 0x0000, 0x0000, 0x0000 }, /* R1471 */
- { 0x0000, 0x0000, 0x0000 }, /* R1472 */
- { 0x0000, 0x0000, 0x0000 }, /* R1473 */
- { 0x0000, 0x0000, 0x0000 }, /* R1474 */
- { 0x0000, 0x0000, 0x0000 }, /* R1475 */
- { 0x0000, 0x0000, 0x0000 }, /* R1476 */
- { 0x0000, 0x0000, 0x0000 }, /* R1477 */
- { 0x0000, 0x0000, 0x0000 }, /* R1478 */
- { 0x0000, 0x0000, 0x0000 }, /* R1479 */
- { 0x0000, 0x0000, 0x0000 }, /* R1480 */
- { 0x0000, 0x0000, 0x0000 }, /* R1481 */
- { 0x0000, 0x0000, 0x0000 }, /* R1482 */
- { 0x0000, 0x0000, 0x0000 }, /* R1483 */
- { 0x0000, 0x0000, 0x0000 }, /* R1484 */
- { 0x0000, 0x0000, 0x0000 }, /* R1485 */
- { 0x0000, 0x0000, 0x0000 }, /* R1486 */
- { 0x0000, 0x0000, 0x0000 }, /* R1487 */
- { 0x0000, 0x0000, 0x0000 }, /* R1488 */
- { 0x0000, 0x0000, 0x0000 }, /* R1489 */
- { 0x0000, 0x0000, 0x0000 }, /* R1490 */
- { 0x0000, 0x0000, 0x0000 }, /* R1491 */
- { 0x0000, 0x0000, 0x0000 }, /* R1492 */
- { 0x0000, 0x0000, 0x0000 }, /* R1493 */
- { 0x0000, 0x0000, 0x0000 }, /* R1494 */
- { 0x0000, 0x0000, 0x0000 }, /* R1495 */
- { 0x0000, 0x0000, 0x0000 }, /* R1496 */
- { 0x0000, 0x0000, 0x0000 }, /* R1497 */
- { 0x0000, 0x0000, 0x0000 }, /* R1498 */
- { 0x0000, 0x0000, 0x0000 }, /* R1499 */
- { 0x0000, 0x0000, 0x0000 }, /* R1500 */
- { 0x0000, 0x0000, 0x0000 }, /* R1501 */
- { 0x0000, 0x0000, 0x0000 }, /* R1502 */
- { 0x0000, 0x0000, 0x0000 }, /* R1503 */
- { 0x0000, 0x0000, 0x0000 }, /* R1504 */
- { 0x0000, 0x0000, 0x0000 }, /* R1505 */
- { 0x0000, 0x0000, 0x0000 }, /* R1506 */
- { 0x0000, 0x0000, 0x0000 }, /* R1507 */
- { 0x0000, 0x0000, 0x0000 }, /* R1508 */
- { 0x0000, 0x0000, 0x0000 }, /* R1509 */
- { 0x0000, 0x0000, 0x0000 }, /* R1510 */
- { 0x0000, 0x0000, 0x0000 }, /* R1511 */
- { 0x0000, 0x0000, 0x0000 }, /* R1512 */
- { 0x0000, 0x0000, 0x0000 }, /* R1513 */
- { 0x0000, 0x0000, 0x0000 }, /* R1514 */
- { 0x0000, 0x0000, 0x0000 }, /* R1515 */
- { 0x0000, 0x0000, 0x0000 }, /* R1516 */
- { 0x0000, 0x0000, 0x0000 }, /* R1517 */
- { 0x0000, 0x0000, 0x0000 }, /* R1518 */
- { 0x0000, 0x0000, 0x0000 }, /* R1519 */
- { 0x0000, 0x0000, 0x0000 }, /* R1520 */
- { 0x0000, 0x0000, 0x0000 }, /* R1521 */
- { 0x0000, 0x0000, 0x0000 }, /* R1522 */
- { 0x0000, 0x0000, 0x0000 }, /* R1523 */
- { 0x0000, 0x0000, 0x0000 }, /* R1524 */
- { 0x0000, 0x0000, 0x0000 }, /* R1525 */
- { 0x0000, 0x0000, 0x0000 }, /* R1526 */
- { 0x0000, 0x0000, 0x0000 }, /* R1527 */
- { 0x0000, 0x0000, 0x0000 }, /* R1528 */
- { 0x0000, 0x0000, 0x0000 }, /* R1529 */
- { 0x0000, 0x0000, 0x0000 }, /* R1530 */
- { 0x0000, 0x0000, 0x0000 }, /* R1531 */
- { 0x0000, 0x0000, 0x0000 }, /* R1532 */
- { 0x0000, 0x0000, 0x0000 }, /* R1533 */
- { 0x0000, 0x0000, 0x0000 }, /* R1534 */
- { 0x0000, 0x0000, 0x0000 }, /* R1535 */
- { 0x01EF, 0x01EF, 0x0000 }, /* R1536 - DAC1 Mixer Volumes */
- { 0x0037, 0x0037, 0x0000 }, /* R1537 - DAC1 Left Mixer Routing */
- { 0x0037, 0x0037, 0x0000 }, /* R1538 - DAC1 Right Mixer Routing */
- { 0x01EF, 0x01EF, 0x0000 }, /* R1539 - DAC2 Mixer Volumes */
- { 0x0037, 0x0037, 0x0000 }, /* R1540 - DAC2 Left Mixer Routing */
- { 0x0037, 0x0037, 0x0000 }, /* R1541 - DAC2 Right Mixer Routing */
- { 0x0003, 0x0003, 0x0000 }, /* R1542 - AIF1 ADC1 Left Mixer Routing */
- { 0x0003, 0x0003, 0x0000 }, /* R1543 - AIF1 ADC1 Right Mixer Routing */
- { 0x0003, 0x0003, 0x0000 }, /* R1544 - AIF1 ADC2 Left Mixer Routing */
- { 0x0003, 0x0003, 0x0000 }, /* R1545 - AIF1 ADC2 Right mixer Routing */
- { 0x0000, 0x0000, 0x0000 }, /* R1546 */
- { 0x0000, 0x0000, 0x0000 }, /* R1547 */
- { 0x0000, 0x0000, 0x0000 }, /* R1548 */
- { 0x0000, 0x0000, 0x0000 }, /* R1549 */
- { 0x0000, 0x0000, 0x0000 }, /* R1550 */
- { 0x0000, 0x0000, 0x0000 }, /* R1551 */
- { 0x02FF, 0x03FF, 0x0000 }, /* R1552 - DAC1 Left Volume */
- { 0x02FF, 0x03FF, 0x0000 }, /* R1553 - DAC1 Right Volume */
- { 0x02FF, 0x03FF, 0x0000 }, /* R1554 - DAC2 Left Volume */
- { 0x02FF, 0x03FF, 0x0000 }, /* R1555 - DAC2 Right Volume */
- { 0x0003, 0x0003, 0x0000 }, /* R1556 - DAC Softmute */
- { 0x0000, 0x0000, 0x0000 }, /* R1557 */
- { 0x0000, 0x0000, 0x0000 }, /* R1558 */
- { 0x0000, 0x0000, 0x0000 }, /* R1559 */
- { 0x0000, 0x0000, 0x0000 }, /* R1560 */
- { 0x0000, 0x0000, 0x0000 }, /* R1561 */
- { 0x0000, 0x0000, 0x0000 }, /* R1562 */
- { 0x0000, 0x0000, 0x0000 }, /* R1563 */
- { 0x0000, 0x0000, 0x0000 }, /* R1564 */
- { 0x0000, 0x0000, 0x0000 }, /* R1565 */
- { 0x0000, 0x0000, 0x0000 }, /* R1566 */
- { 0x0000, 0x0000, 0x0000 }, /* R1567 */
- { 0x0003, 0x0003, 0x0000 }, /* R1568 - Oversampling */
- { 0x03C3, 0x03C3, 0x0000 }, /* R1569 - Sidetone */
+ { 0xFFFF, 0xFFFF }, /* R0 - Software Reset */
+ { 0x3B37, 0x3B37 }, /* R1 - Power Management (1) */
+ { 0x6BF0, 0x6BF0 }, /* R2 - Power Management (2) */
+ { 0x3FF0, 0x3FF0 }, /* R3 - Power Management (3) */
+ { 0x3F3F, 0x3F3F }, /* R4 - Power Management (4) */
+ { 0x3F0F, 0x3F0F }, /* R5 - Power Management (5) */
+ { 0x003F, 0x003F }, /* R6 - Power Management (6) */
+ { 0x0000, 0x0000 }, /* R7 */
+ { 0x0000, 0x0000 }, /* R8 */
+ { 0x0000, 0x0000 }, /* R9 */
+ { 0x0000, 0x0000 }, /* R10 */
+ { 0x0000, 0x0000 }, /* R11 */
+ { 0x0000, 0x0000 }, /* R12 */
+ { 0x0000, 0x0000 }, /* R13 */
+ { 0x0000, 0x0000 }, /* R14 */
+ { 0x0000, 0x0000 }, /* R15 */
+ { 0x0000, 0x0000 }, /* R16 */
+ { 0x0000, 0x0000 }, /* R17 */
+ { 0x0000, 0x0000 }, /* R18 */
+ { 0x0000, 0x0000 }, /* R19 */
+ { 0x0000, 0x0000 }, /* R20 */
+ { 0x01C0, 0x01C0 }, /* R21 - Input Mixer (1) */
+ { 0x0000, 0x0000 }, /* R22 */
+ { 0x0000, 0x0000 }, /* R23 */
+ { 0x00DF, 0x01DF }, /* R24 - Left Line Input 1&2 Volume */
+ { 0x00DF, 0x01DF }, /* R25 - Left Line Input 3&4 Volume */
+ { 0x00DF, 0x01DF }, /* R26 - Right Line Input 1&2 Volume */
+ { 0x00DF, 0x01DF }, /* R27 - Right Line Input 3&4 Volume */
+ { 0x00FF, 0x01FF }, /* R28 - Left Output Volume */
+ { 0x00FF, 0x01FF }, /* R29 - Right Output Volume */
+ { 0x0077, 0x0077 }, /* R30 - Line Outputs Volume */
+ { 0x0030, 0x0030 }, /* R31 - HPOUT2 Volume */
+ { 0x00FF, 0x01FF }, /* R32 - Left OPGA Volume */
+ { 0x00FF, 0x01FF }, /* R33 - Right OPGA Volume */
+ { 0x007F, 0x007F }, /* R34 - SPKMIXL Attenuation */
+ { 0x017F, 0x017F }, /* R35 - SPKMIXR Attenuation */
+ { 0x003F, 0x003F }, /* R36 - SPKOUT Mixers */
+ { 0x003F, 0x003F }, /* R37 - ClassD */
+ { 0x00FF, 0x01FF }, /* R38 - Speaker Volume Left */
+ { 0x00FF, 0x01FF }, /* R39 - Speaker Volume Right */
+ { 0x00FF, 0x00FF }, /* R40 - Input Mixer (2) */
+ { 0x01B7, 0x01B7 }, /* R41 - Input Mixer (3) */
+ { 0x01B7, 0x01B7 }, /* R42 - Input Mixer (4) */
+ { 0x01C7, 0x01C7 }, /* R43 - Input Mixer (5) */
+ { 0x01C7, 0x01C7 }, /* R44 - Input Mixer (6) */
+ { 0x01FF, 0x01FF }, /* R45 - Output Mixer (1) */
+ { 0x01FF, 0x01FF }, /* R46 - Output Mixer (2) */
+ { 0x0FFF, 0x0FFF }, /* R47 - Output Mixer (3) */
+ { 0x0FFF, 0x0FFF }, /* R48 - Output Mixer (4) */
+ { 0x0FFF, 0x0FFF }, /* R49 - Output Mixer (5) */
+ { 0x0FFF, 0x0FFF }, /* R50 - Output Mixer (6) */
+ { 0x0038, 0x0038 }, /* R51 - HPOUT2 Mixer */
+ { 0x0077, 0x0077 }, /* R52 - Line Mixer (1) */
+ { 0x0077, 0x0077 }, /* R53 - Line Mixer (2) */
+ { 0x03FF, 0x03FF }, /* R54 - Speaker Mixer */
+ { 0x00C1, 0x00C1 }, /* R55 - Additional Control */
+ { 0x00F0, 0x00F0 }, /* R56 - AntiPOP (1) */
+ { 0x01EF, 0x01EF }, /* R57 - AntiPOP (2) */
+ { 0x00FF, 0x00FF }, /* R58 - MICBIAS */
+ { 0x000F, 0x000F }, /* R59 - LDO 1 */
+ { 0x0007, 0x0007 }, /* R60 - LDO 2 */
+ { 0x0000, 0x0000 }, /* R61 */
+ { 0x0000, 0x0000 }, /* R62 */
+ { 0x0000, 0x0000 }, /* R63 */
+ { 0x0000, 0x0000 }, /* R64 */
+ { 0x0000, 0x0000 }, /* R65 */
+ { 0x0000, 0x0000 }, /* R66 */
+ { 0x0000, 0x0000 }, /* R67 */
+ { 0x0000, 0x0000 }, /* R68 */
+ { 0x0000, 0x0000 }, /* R69 */
+ { 0x0000, 0x0000 }, /* R70 */
+ { 0x0000, 0x0000 }, /* R71 */
+ { 0x0000, 0x0000 }, /* R72 */
+ { 0x0000, 0x0000 }, /* R73 */
+ { 0x0000, 0x0000 }, /* R74 */
+ { 0x0000, 0x0000 }, /* R75 */
+ { 0x8000, 0x8000 }, /* R76 - Charge Pump (1) */
+ { 0x0000, 0x0000 }, /* R77 */
+ { 0x0000, 0x0000 }, /* R78 */
+ { 0x0000, 0x0000 }, /* R79 */
+ { 0x0000, 0x0000 }, /* R80 */
+ { 0x0301, 0x0301 }, /* R81 - Class W (1) */
+ { 0x0000, 0x0000 }, /* R82 */
+ { 0x0000, 0x0000 }, /* R83 */
+ { 0x333F, 0x333F }, /* R84 - DC Servo (1) */
+ { 0x0FEF, 0x0FEF }, /* R85 - DC Servo (2) */
+ { 0x0000, 0x0000 }, /* R86 */
+ { 0xFFFF, 0xFFFF }, /* R87 - DC Servo (4) */
+ { 0x0333, 0x0000 }, /* R88 - DC Servo Readback */
+ { 0x0000, 0x0000 }, /* R89 */
+ { 0x0000, 0x0000 }, /* R90 */
+ { 0x0000, 0x0000 }, /* R91 */
+ { 0x0000, 0x0000 }, /* R92 */
+ { 0x0000, 0x0000 }, /* R93 */
+ { 0x0000, 0x0000 }, /* R94 */
+ { 0x0000, 0x0000 }, /* R95 */
+ { 0x00EE, 0x00EE }, /* R96 - Analogue HP (1) */
+ { 0x0000, 0x0000 }, /* R97 */
+ { 0x0000, 0x0000 }, /* R98 */
+ { 0x0000, 0x0000 }, /* R99 */
+ { 0x0000, 0x0000 }, /* R100 */
+ { 0x0000, 0x0000 }, /* R101 */
+ { 0x0000, 0x0000 }, /* R102 */
+ { 0x0000, 0x0000 }, /* R103 */
+ { 0x0000, 0x0000 }, /* R104 */
+ { 0x0000, 0x0000 }, /* R105 */
+ { 0x0000, 0x0000 }, /* R106 */
+ { 0x0000, 0x0000 }, /* R107 */
+ { 0x0000, 0x0000 }, /* R108 */
+ { 0x0000, 0x0000 }, /* R109 */
+ { 0x0000, 0x0000 }, /* R110 */
+ { 0x0000, 0x0000 }, /* R111 */
+ { 0x0000, 0x0000 }, /* R112 */
+ { 0x0000, 0x0000 }, /* R113 */
+ { 0x0000, 0x0000 }, /* R114 */
+ { 0x0000, 0x0000 }, /* R115 */
+ { 0x0000, 0x0000 }, /* R116 */
+ { 0x0000, 0x0000 }, /* R117 */
+ { 0x0000, 0x0000 }, /* R118 */
+ { 0x0000, 0x0000 }, /* R119 */
+ { 0x0000, 0x0000 }, /* R120 */
+ { 0x0000, 0x0000 }, /* R121 */
+ { 0x0000, 0x0000 }, /* R122 */
+ { 0x0000, 0x0000 }, /* R123 */
+ { 0x0000, 0x0000 }, /* R124 */
+ { 0x0000, 0x0000 }, /* R125 */
+ { 0x0000, 0x0000 }, /* R126 */
+ { 0x0000, 0x0000 }, /* R127 */
+ { 0x0000, 0x0000 }, /* R128 */
+ { 0x0000, 0x0000 }, /* R129 */
+ { 0x0000, 0x0000 }, /* R130 */
+ { 0x0000, 0x0000 }, /* R131 */
+ { 0x0000, 0x0000 }, /* R132 */
+ { 0x0000, 0x0000 }, /* R133 */
+ { 0x0000, 0x0000 }, /* R134 */
+ { 0x0000, 0x0000 }, /* R135 */
+ { 0x0000, 0x0000 }, /* R136 */
+ { 0x0000, 0x0000 }, /* R137 */
+ { 0x0000, 0x0000 }, /* R138 */
+ { 0x0000, 0x0000 }, /* R139 */
+ { 0x0000, 0x0000 }, /* R140 */
+ { 0x0000, 0x0000 }, /* R141 */
+ { 0x0000, 0x0000 }, /* R142 */
+ { 0x0000, 0x0000 }, /* R143 */
+ { 0x0000, 0x0000 }, /* R144 */
+ { 0x0000, 0x0000 }, /* R145 */
+ { 0x0000, 0x0000 }, /* R146 */
+ { 0x0000, 0x0000 }, /* R147 */
+ { 0x0000, 0x0000 }, /* R148 */
+ { 0x0000, 0x0000 }, /* R149 */
+ { 0x0000, 0x0000 }, /* R150 */
+ { 0x0000, 0x0000 }, /* R151 */
+ { 0x0000, 0x0000 }, /* R152 */
+ { 0x0000, 0x0000 }, /* R153 */
+ { 0x0000, 0x0000 }, /* R154 */
+ { 0x0000, 0x0000 }, /* R155 */
+ { 0x0000, 0x0000 }, /* R156 */
+ { 0x0000, 0x0000 }, /* R157 */
+ { 0x0000, 0x0000 }, /* R158 */
+ { 0x0000, 0x0000 }, /* R159 */
+ { 0x0000, 0x0000 }, /* R160 */
+ { 0x0000, 0x0000 }, /* R161 */
+ { 0x0000, 0x0000 }, /* R162 */
+ { 0x0000, 0x0000 }, /* R163 */
+ { 0x0000, 0x0000 }, /* R164 */
+ { 0x0000, 0x0000 }, /* R165 */
+ { 0x0000, 0x0000 }, /* R166 */
+ { 0x0000, 0x0000 }, /* R167 */
+ { 0x0000, 0x0000 }, /* R168 */
+ { 0x0000, 0x0000 }, /* R169 */
+ { 0x0000, 0x0000 }, /* R170 */
+ { 0x0000, 0x0000 }, /* R171 */
+ { 0x0000, 0x0000 }, /* R172 */
+ { 0x0000, 0x0000 }, /* R173 */
+ { 0x0000, 0x0000 }, /* R174 */
+ { 0x0000, 0x0000 }, /* R175 */
+ { 0x0000, 0x0000 }, /* R176 */
+ { 0x0000, 0x0000 }, /* R177 */
+ { 0x0000, 0x0000 }, /* R178 */
+ { 0x0000, 0x0000 }, /* R179 */
+ { 0x0000, 0x0000 }, /* R180 */
+ { 0x0000, 0x0000 }, /* R181 */
+ { 0x0000, 0x0000 }, /* R182 */
+ { 0x0000, 0x0000 }, /* R183 */
+ { 0x0000, 0x0000 }, /* R184 */
+ { 0x0000, 0x0000 }, /* R185 */
+ { 0x0000, 0x0000 }, /* R186 */
+ { 0x0000, 0x0000 }, /* R187 */
+ { 0x0000, 0x0000 }, /* R188 */
+ { 0x0000, 0x0000 }, /* R189 */
+ { 0x0000, 0x0000 }, /* R190 */
+ { 0x0000, 0x0000 }, /* R191 */
+ { 0x0000, 0x0000 }, /* R192 */
+ { 0x0000, 0x0000 }, /* R193 */
+ { 0x0000, 0x0000 }, /* R194 */
+ { 0x0000, 0x0000 }, /* R195 */
+ { 0x0000, 0x0000 }, /* R196 */
+ { 0x0000, 0x0000 }, /* R197 */
+ { 0x0000, 0x0000 }, /* R198 */
+ { 0x0000, 0x0000 }, /* R199 */
+ { 0x0000, 0x0000 }, /* R200 */
+ { 0x0000, 0x0000 }, /* R201 */
+ { 0x0000, 0x0000 }, /* R202 */
+ { 0x0000, 0x0000 }, /* R203 */
+ { 0x0000, 0x0000 }, /* R204 */
+ { 0x0000, 0x0000 }, /* R205 */
+ { 0x0000, 0x0000 }, /* R206 */
+ { 0x0000, 0x0000 }, /* R207 */
+ { 0x0000, 0x0000 }, /* R208 */
+ { 0x0000, 0x0000 }, /* R209 */
+ { 0x0000, 0x0000 }, /* R210 */
+ { 0x0000, 0x0000 }, /* R211 */
+ { 0x0000, 0x0000 }, /* R212 */
+ { 0x0000, 0x0000 }, /* R213 */
+ { 0x0000, 0x0000 }, /* R214 */
+ { 0x0000, 0x0000 }, /* R215 */
+ { 0x0000, 0x0000 }, /* R216 */
+ { 0x0000, 0x0000 }, /* R217 */
+ { 0x0000, 0x0000 }, /* R218 */
+ { 0x0000, 0x0000 }, /* R219 */
+ { 0x0000, 0x0000 }, /* R220 */
+ { 0x0000, 0x0000 }, /* R221 */
+ { 0x0000, 0x0000 }, /* R222 */
+ { 0x0000, 0x0000 }, /* R223 */
+ { 0x0000, 0x0000 }, /* R224 */
+ { 0x0000, 0x0000 }, /* R225 */
+ { 0x0000, 0x0000 }, /* R226 */
+ { 0x0000, 0x0000 }, /* R227 */
+ { 0x0000, 0x0000 }, /* R228 */
+ { 0x0000, 0x0000 }, /* R229 */
+ { 0x0000, 0x0000 }, /* R230 */
+ { 0x0000, 0x0000 }, /* R231 */
+ { 0x0000, 0x0000 }, /* R232 */
+ { 0x0000, 0x0000 }, /* R233 */
+ { 0x0000, 0x0000 }, /* R234 */
+ { 0x0000, 0x0000 }, /* R235 */
+ { 0x0000, 0x0000 }, /* R236 */
+ { 0x0000, 0x0000 }, /* R237 */
+ { 0x0000, 0x0000 }, /* R238 */
+ { 0x0000, 0x0000 }, /* R239 */
+ { 0x0000, 0x0000 }, /* R240 */
+ { 0x0000, 0x0000 }, /* R241 */
+ { 0x0000, 0x0000 }, /* R242 */
+ { 0x0000, 0x0000 }, /* R243 */
+ { 0x0000, 0x0000 }, /* R244 */
+ { 0x0000, 0x0000 }, /* R245 */
+ { 0x0000, 0x0000 }, /* R246 */
+ { 0x0000, 0x0000 }, /* R247 */
+ { 0x0000, 0x0000 }, /* R248 */
+ { 0x0000, 0x0000 }, /* R249 */
+ { 0x0000, 0x0000 }, /* R250 */
+ { 0x0000, 0x0000 }, /* R251 */
+ { 0x0000, 0x0000 }, /* R252 */
+ { 0x0000, 0x0000 }, /* R253 */
+ { 0x0000, 0x0000 }, /* R254 */
+ { 0x0000, 0x0000 }, /* R255 */
+ { 0x000F, 0x0000 }, /* R256 - Chip Revision */
+ { 0x0074, 0x0074 }, /* R257 - Control Interface */
+ { 0x0000, 0x0000 }, /* R258 */
+ { 0x0000, 0x0000 }, /* R259 */
+ { 0x0000, 0x0000 }, /* R260 */
+ { 0x0000, 0x0000 }, /* R261 */
+ { 0x0000, 0x0000 }, /* R262 */
+ { 0x0000, 0x0000 }, /* R263 */
+ { 0x0000, 0x0000 }, /* R264 */
+ { 0x0000, 0x0000 }, /* R265 */
+ { 0x0000, 0x0000 }, /* R266 */
+ { 0x0000, 0x0000 }, /* R267 */
+ { 0x0000, 0x0000 }, /* R268 */
+ { 0x0000, 0x0000 }, /* R269 */
+ { 0x0000, 0x0000 }, /* R270 */
+ { 0x0000, 0x0000 }, /* R271 */
+ { 0x807F, 0x837F }, /* R272 - Write Sequencer Ctrl (1) */
+ { 0x017F, 0x0000 }, /* R273 - Write Sequencer Ctrl (2) */
+ { 0x0000, 0x0000 }, /* R274 */
+ { 0x0000, 0x0000 }, /* R275 */
+ { 0x0000, 0x0000 }, /* R276 */
+ { 0x0000, 0x0000 }, /* R277 */
+ { 0x0000, 0x0000 }, /* R278 */
+ { 0x0000, 0x0000 }, /* R279 */
+ { 0x0000, 0x0000 }, /* R280 */
+ { 0x0000, 0x0000 }, /* R281 */
+ { 0x0000, 0x0000 }, /* R282 */
+ { 0x0000, 0x0000 }, /* R283 */
+ { 0x0000, 0x0000 }, /* R284 */
+ { 0x0000, 0x0000 }, /* R285 */
+ { 0x0000, 0x0000 }, /* R286 */
+ { 0x0000, 0x0000 }, /* R287 */
+ { 0x0000, 0x0000 }, /* R288 */
+ { 0x0000, 0x0000 }, /* R289 */
+ { 0x0000, 0x0000 }, /* R290 */
+ { 0x0000, 0x0000 }, /* R291 */
+ { 0x0000, 0x0000 }, /* R292 */
+ { 0x0000, 0x0000 }, /* R293 */
+ { 0x0000, 0x0000 }, /* R294 */
+ { 0x0000, 0x0000 }, /* R295 */
+ { 0x0000, 0x0000 }, /* R296 */
+ { 0x0000, 0x0000 }, /* R297 */
+ { 0x0000, 0x0000 }, /* R298 */
+ { 0x0000, 0x0000 }, /* R299 */
+ { 0x0000, 0x0000 }, /* R300 */
+ { 0x0000, 0x0000 }, /* R301 */
+ { 0x0000, 0x0000 }, /* R302 */
+ { 0x0000, 0x0000 }, /* R303 */
+ { 0x0000, 0x0000 }, /* R304 */
+ { 0x0000, 0x0000 }, /* R305 */
+ { 0x0000, 0x0000 }, /* R306 */
+ { 0x0000, 0x0000 }, /* R307 */
+ { 0x0000, 0x0000 }, /* R308 */
+ { 0x0000, 0x0000 }, /* R309 */
+ { 0x0000, 0x0000 }, /* R310 */
+ { 0x0000, 0x0000 }, /* R311 */
+ { 0x0000, 0x0000 }, /* R312 */
+ { 0x0000, 0x0000 }, /* R313 */
+ { 0x0000, 0x0000 }, /* R314 */
+ { 0x0000, 0x0000 }, /* R315 */
+ { 0x0000, 0x0000 }, /* R316 */
+ { 0x0000, 0x0000 }, /* R317 */
+ { 0x0000, 0x0000 }, /* R318 */
+ { 0x0000, 0x0000 }, /* R319 */
+ { 0x0000, 0x0000 }, /* R320 */
+ { 0x0000, 0x0000 }, /* R321 */
+ { 0x0000, 0x0000 }, /* R322 */
+ { 0x0000, 0x0000 }, /* R323 */
+ { 0x0000, 0x0000 }, /* R324 */
+ { 0x0000, 0x0000 }, /* R325 */
+ { 0x0000, 0x0000 }, /* R326 */
+ { 0x0000, 0x0000 }, /* R327 */
+ { 0x0000, 0x0000 }, /* R328 */
+ { 0x0000, 0x0000 }, /* R329 */
+ { 0x0000, 0x0000 }, /* R330 */
+ { 0x0000, 0x0000 }, /* R331 */
+ { 0x0000, 0x0000 }, /* R332 */
+ { 0x0000, 0x0000 }, /* R333 */
+ { 0x0000, 0x0000 }, /* R334 */
+ { 0x0000, 0x0000 }, /* R335 */
+ { 0x0000, 0x0000 }, /* R336 */
+ { 0x0000, 0x0000 }, /* R337 */
+ { 0x0000, 0x0000 }, /* R338 */
+ { 0x0000, 0x0000 }, /* R339 */
+ { 0x0000, 0x0000 }, /* R340 */
+ { 0x0000, 0x0000 }, /* R341 */
+ { 0x0000, 0x0000 }, /* R342 */
+ { 0x0000, 0x0000 }, /* R343 */
+ { 0x0000, 0x0000 }, /* R344 */
+ { 0x0000, 0x0000 }, /* R345 */
+ { 0x0000, 0x0000 }, /* R346 */
+ { 0x0000, 0x0000 }, /* R347 */
+ { 0x0000, 0x0000 }, /* R348 */
+ { 0x0000, 0x0000 }, /* R349 */
+ { 0x0000, 0x0000 }, /* R350 */
+ { 0x0000, 0x0000 }, /* R351 */
+ { 0x0000, 0x0000 }, /* R352 */
+ { 0x0000, 0x0000 }, /* R353 */
+ { 0x0000, 0x0000 }, /* R354 */
+ { 0x0000, 0x0000 }, /* R355 */
+ { 0x0000, 0x0000 }, /* R356 */
+ { 0x0000, 0x0000 }, /* R357 */
+ { 0x0000, 0x0000 }, /* R358 */
+ { 0x0000, 0x0000 }, /* R359 */
+ { 0x0000, 0x0000 }, /* R360 */
+ { 0x0000, 0x0000 }, /* R361 */
+ { 0x0000, 0x0000 }, /* R362 */
+ { 0x0000, 0x0000 }, /* R363 */
+ { 0x0000, 0x0000 }, /* R364 */
+ { 0x0000, 0x0000 }, /* R365 */
+ { 0x0000, 0x0000 }, /* R366 */
+ { 0x0000, 0x0000 }, /* R367 */
+ { 0x0000, 0x0000 }, /* R368 */
+ { 0x0000, 0x0000 }, /* R369 */
+ { 0x0000, 0x0000 }, /* R370 */
+ { 0x0000, 0x0000 }, /* R371 */
+ { 0x0000, 0x0000 }, /* R372 */
+ { 0x0000, 0x0000 }, /* R373 */
+ { 0x0000, 0x0000 }, /* R374 */
+ { 0x0000, 0x0000 }, /* R375 */
+ { 0x0000, 0x0000 }, /* R376 */
+ { 0x0000, 0x0000 }, /* R377 */
+ { 0x0000, 0x0000 }, /* R378 */
+ { 0x0000, 0x0000 }, /* R379 */
+ { 0x0000, 0x0000 }, /* R380 */
+ { 0x0000, 0x0000 }, /* R381 */
+ { 0x0000, 0x0000 }, /* R382 */
+ { 0x0000, 0x0000 }, /* R383 */
+ { 0x0000, 0x0000 }, /* R384 */
+ { 0x0000, 0x0000 }, /* R385 */
+ { 0x0000, 0x0000 }, /* R386 */
+ { 0x0000, 0x0000 }, /* R387 */
+ { 0x0000, 0x0000 }, /* R388 */
+ { 0x0000, 0x0000 }, /* R389 */
+ { 0x0000, 0x0000 }, /* R390 */
+ { 0x0000, 0x0000 }, /* R391 */
+ { 0x0000, 0x0000 }, /* R392 */
+ { 0x0000, 0x0000 }, /* R393 */
+ { 0x0000, 0x0000 }, /* R394 */
+ { 0x0000, 0x0000 }, /* R395 */
+ { 0x0000, 0x0000 }, /* R396 */
+ { 0x0000, 0x0000 }, /* R397 */
+ { 0x0000, 0x0000 }, /* R398 */
+ { 0x0000, 0x0000 }, /* R399 */
+ { 0x0000, 0x0000 }, /* R400 */
+ { 0x0000, 0x0000 }, /* R401 */
+ { 0x0000, 0x0000 }, /* R402 */
+ { 0x0000, 0x0000 }, /* R403 */
+ { 0x0000, 0x0000 }, /* R404 */
+ { 0x0000, 0x0000 }, /* R405 */
+ { 0x0000, 0x0000 }, /* R406 */
+ { 0x0000, 0x0000 }, /* R407 */
+ { 0x0000, 0x0000 }, /* R408 */
+ { 0x0000, 0x0000 }, /* R409 */
+ { 0x0000, 0x0000 }, /* R410 */
+ { 0x0000, 0x0000 }, /* R411 */
+ { 0x0000, 0x0000 }, /* R412 */
+ { 0x0000, 0x0000 }, /* R413 */
+ { 0x0000, 0x0000 }, /* R414 */
+ { 0x0000, 0x0000 }, /* R415 */
+ { 0x0000, 0x0000 }, /* R416 */
+ { 0x0000, 0x0000 }, /* R417 */
+ { 0x0000, 0x0000 }, /* R418 */
+ { 0x0000, 0x0000 }, /* R419 */
+ { 0x0000, 0x0000 }, /* R420 */
+ { 0x0000, 0x0000 }, /* R421 */
+ { 0x0000, 0x0000 }, /* R422 */
+ { 0x0000, 0x0000 }, /* R423 */
+ { 0x0000, 0x0000 }, /* R424 */
+ { 0x0000, 0x0000 }, /* R425 */
+ { 0x0000, 0x0000 }, /* R426 */
+ { 0x0000, 0x0000 }, /* R427 */
+ { 0x0000, 0x0000 }, /* R428 */
+ { 0x0000, 0x0000 }, /* R429 */
+ { 0x0000, 0x0000 }, /* R430 */
+ { 0x0000, 0x0000 }, /* R431 */
+ { 0x0000, 0x0000 }, /* R432 */
+ { 0x0000, 0x0000 }, /* R433 */
+ { 0x0000, 0x0000 }, /* R434 */
+ { 0x0000, 0x0000 }, /* R435 */
+ { 0x0000, 0x0000 }, /* R436 */
+ { 0x0000, 0x0000 }, /* R437 */
+ { 0x0000, 0x0000 }, /* R438 */
+ { 0x0000, 0x0000 }, /* R439 */
+ { 0x0000, 0x0000 }, /* R440 */
+ { 0x0000, 0x0000 }, /* R441 */
+ { 0x0000, 0x0000 }, /* R442 */
+ { 0x0000, 0x0000 }, /* R443 */
+ { 0x0000, 0x0000 }, /* R444 */
+ { 0x0000, 0x0000 }, /* R445 */
+ { 0x0000, 0x0000 }, /* R446 */
+ { 0x0000, 0x0000 }, /* R447 */
+ { 0x0000, 0x0000 }, /* R448 */
+ { 0x0000, 0x0000 }, /* R449 */
+ { 0x0000, 0x0000 }, /* R450 */
+ { 0x0000, 0x0000 }, /* R451 */
+ { 0x0000, 0x0000 }, /* R452 */
+ { 0x0000, 0x0000 }, /* R453 */
+ { 0x0000, 0x0000 }, /* R454 */
+ { 0x0000, 0x0000 }, /* R455 */
+ { 0x0000, 0x0000 }, /* R456 */
+ { 0x0000, 0x0000 }, /* R457 */
+ { 0x0000, 0x0000 }, /* R458 */
+ { 0x0000, 0x0000 }, /* R459 */
+ { 0x0000, 0x0000 }, /* R460 */
+ { 0x0000, 0x0000 }, /* R461 */
+ { 0x0000, 0x0000 }, /* R462 */
+ { 0x0000, 0x0000 }, /* R463 */
+ { 0x0000, 0x0000 }, /* R464 */
+ { 0x0000, 0x0000 }, /* R465 */
+ { 0x0000, 0x0000 }, /* R466 */
+ { 0x0000, 0x0000 }, /* R467 */
+ { 0x0000, 0x0000 }, /* R468 */
+ { 0x0000, 0x0000 }, /* R469 */
+ { 0x0000, 0x0000 }, /* R470 */
+ { 0x0000, 0x0000 }, /* R471 */
+ { 0x0000, 0x0000 }, /* R472 */
+ { 0x0000, 0x0000 }, /* R473 */
+ { 0x0000, 0x0000 }, /* R474 */
+ { 0x0000, 0x0000 }, /* R475 */
+ { 0x0000, 0x0000 }, /* R476 */
+ { 0x0000, 0x0000 }, /* R477 */
+ { 0x0000, 0x0000 }, /* R478 */
+ { 0x0000, 0x0000 }, /* R479 */
+ { 0x0000, 0x0000 }, /* R480 */
+ { 0x0000, 0x0000 }, /* R481 */
+ { 0x0000, 0x0000 }, /* R482 */
+ { 0x0000, 0x0000 }, /* R483 */
+ { 0x0000, 0x0000 }, /* R484 */
+ { 0x0000, 0x0000 }, /* R485 */
+ { 0x0000, 0x0000 }, /* R486 */
+ { 0x0000, 0x0000 }, /* R487 */
+ { 0x0000, 0x0000 }, /* R488 */
+ { 0x0000, 0x0000 }, /* R489 */
+ { 0x0000, 0x0000 }, /* R490 */
+ { 0x0000, 0x0000 }, /* R491 */
+ { 0x0000, 0x0000 }, /* R492 */
+ { 0x0000, 0x0000 }, /* R493 */
+ { 0x0000, 0x0000 }, /* R494 */
+ { 0x0000, 0x0000 }, /* R495 */
+ { 0x0000, 0x0000 }, /* R496 */
+ { 0x0000, 0x0000 }, /* R497 */
+ { 0x0000, 0x0000 }, /* R498 */
+ { 0x0000, 0x0000 }, /* R499 */
+ { 0x0000, 0x0000 }, /* R500 */
+ { 0x0000, 0x0000 }, /* R501 */
+ { 0x0000, 0x0000 }, /* R502 */
+ { 0x0000, 0x0000 }, /* R503 */
+ { 0x0000, 0x0000 }, /* R504 */
+ { 0x0000, 0x0000 }, /* R505 */
+ { 0x0000, 0x0000 }, /* R506 */
+ { 0x0000, 0x0000 }, /* R507 */
+ { 0x0000, 0x0000 }, /* R508 */
+ { 0x0000, 0x0000 }, /* R509 */
+ { 0x0000, 0x0000 }, /* R510 */
+ { 0x0000, 0x0000 }, /* R511 */
+ { 0x001F, 0x001F }, /* R512 - AIF1 Clocking (1) */
+ { 0x003F, 0x003F }, /* R513 - AIF1 Clocking (2) */
+ { 0x0000, 0x0000 }, /* R514 */
+ { 0x0000, 0x0000 }, /* R515 */
+ { 0x001F, 0x001F }, /* R516 - AIF2 Clocking (1) */
+ { 0x003F, 0x003F }, /* R517 - AIF2 Clocking (2) */
+ { 0x0000, 0x0000 }, /* R518 */
+ { 0x0000, 0x0000 }, /* R519 */
+ { 0x001F, 0x001F }, /* R520 - Clocking (1) */
+ { 0x0777, 0x0777 }, /* R521 - Clocking (2) */
+ { 0x0000, 0x0000 }, /* R522 */
+ { 0x0000, 0x0000 }, /* R523 */
+ { 0x0000, 0x0000 }, /* R524 */
+ { 0x0000, 0x0000 }, /* R525 */
+ { 0x0000, 0x0000 }, /* R526 */
+ { 0x0000, 0x0000 }, /* R527 */
+ { 0x00FF, 0x00FF }, /* R528 - AIF1 Rate */
+ { 0x00FF, 0x00FF }, /* R529 - AIF2 Rate */
+ { 0x000F, 0x0000 }, /* R530 - Rate Status */
+ { 0x0000, 0x0000 }, /* R531 */
+ { 0x0000, 0x0000 }, /* R532 */
+ { 0x0000, 0x0000 }, /* R533 */
+ { 0x0000, 0x0000 }, /* R534 */
+ { 0x0000, 0x0000 }, /* R535 */
+ { 0x0000, 0x0000 }, /* R536 */
+ { 0x0000, 0x0000 }, /* R537 */
+ { 0x0000, 0x0000 }, /* R538 */
+ { 0x0000, 0x0000 }, /* R539 */
+ { 0x0000, 0x0000 }, /* R540 */
+ { 0x0000, 0x0000 }, /* R541 */
+ { 0x0000, 0x0000 }, /* R542 */
+ { 0x0000, 0x0000 }, /* R543 */
+ { 0x0007, 0x0007 }, /* R544 - FLL1 Control (1) */
+ { 0x3F77, 0x3F77 }, /* R545 - FLL1 Control (2) */
+ { 0xFFFF, 0xFFFF }, /* R546 - FLL1 Control (3) */
+ { 0x7FEF, 0x7FEF }, /* R547 - FLL1 Control (4) */
+ { 0x1FDB, 0x1FDB }, /* R548 - FLL1 Control (5) */
+ { 0x0000, 0x0000 }, /* R549 */
+ { 0x0000, 0x0000 }, /* R550 */
+ { 0x0000, 0x0000 }, /* R551 */
+ { 0x0000, 0x0000 }, /* R552 */
+ { 0x0000, 0x0000 }, /* R553 */
+ { 0x0000, 0x0000 }, /* R554 */
+ { 0x0000, 0x0000 }, /* R555 */
+ { 0x0000, 0x0000 }, /* R556 */
+ { 0x0000, 0x0000 }, /* R557 */
+ { 0x0000, 0x0000 }, /* R558 */
+ { 0x0000, 0x0000 }, /* R559 */
+ { 0x0000, 0x0000 }, /* R560 */
+ { 0x0000, 0x0000 }, /* R561 */
+ { 0x0000, 0x0000 }, /* R562 */
+ { 0x0000, 0x0000 }, /* R563 */
+ { 0x0000, 0x0000 }, /* R564 */
+ { 0x0000, 0x0000 }, /* R565 */
+ { 0x0000, 0x0000 }, /* R566 */
+ { 0x0000, 0x0000 }, /* R567 */
+ { 0x0000, 0x0000 }, /* R568 */
+ { 0x0000, 0x0000 }, /* R569 */
+ { 0x0000, 0x0000 }, /* R570 */
+ { 0x0000, 0x0000 }, /* R571 */
+ { 0x0000, 0x0000 }, /* R572 */
+ { 0x0000, 0x0000 }, /* R573 */
+ { 0x0000, 0x0000 }, /* R574 */
+ { 0x0000, 0x0000 }, /* R575 */
+ { 0x0007, 0x0007 }, /* R576 - FLL2 Control (1) */
+ { 0x3F77, 0x3F77 }, /* R577 - FLL2 Control (2) */
+ { 0xFFFF, 0xFFFF }, /* R578 - FLL2 Control (3) */
+ { 0x7FEF, 0x7FEF }, /* R579 - FLL2 Control (4) */
+ { 0x1FDB, 0x1FDB }, /* R580 - FLL2 Control (5) */
+ { 0x0000, 0x0000 }, /* R581 */
+ { 0x0000, 0x0000 }, /* R582 */
+ { 0x0000, 0x0000 }, /* R583 */
+ { 0x0000, 0x0000 }, /* R584 */
+ { 0x0000, 0x0000 }, /* R585 */
+ { 0x0000, 0x0000 }, /* R586 */
+ { 0x0000, 0x0000 }, /* R587 */
+ { 0x0000, 0x0000 }, /* R588 */
+ { 0x0000, 0x0000 }, /* R589 */
+ { 0x0000, 0x0000 }, /* R590 */
+ { 0x0000, 0x0000 }, /* R591 */
+ { 0x0000, 0x0000 }, /* R592 */
+ { 0x0000, 0x0000 }, /* R593 */
+ { 0x0000, 0x0000 }, /* R594 */
+ { 0x0000, 0x0000 }, /* R595 */
+ { 0x0000, 0x0000 }, /* R596 */
+ { 0x0000, 0x0000 }, /* R597 */
+ { 0x0000, 0x0000 }, /* R598 */
+ { 0x0000, 0x0000 }, /* R599 */
+ { 0x0000, 0x0000 }, /* R600 */
+ { 0x0000, 0x0000 }, /* R601 */
+ { 0x0000, 0x0000 }, /* R602 */
+ { 0x0000, 0x0000 }, /* R603 */
+ { 0x0000, 0x0000 }, /* R604 */
+ { 0x0000, 0x0000 }, /* R605 */
+ { 0x0000, 0x0000 }, /* R606 */
+ { 0x0000, 0x0000 }, /* R607 */
+ { 0x0000, 0x0000 }, /* R608 */
+ { 0x0000, 0x0000 }, /* R609 */
+ { 0x0000, 0x0000 }, /* R610 */
+ { 0x0000, 0x0000 }, /* R611 */
+ { 0x0000, 0x0000 }, /* R612 */
+ { 0x0000, 0x0000 }, /* R613 */
+ { 0x0000, 0x0000 }, /* R614 */
+ { 0x0000, 0x0000 }, /* R615 */
+ { 0x0000, 0x0000 }, /* R616 */
+ { 0x0000, 0x0000 }, /* R617 */
+ { 0x0000, 0x0000 }, /* R618 */
+ { 0x0000, 0x0000 }, /* R619 */
+ { 0x0000, 0x0000 }, /* R620 */
+ { 0x0000, 0x0000 }, /* R621 */
+ { 0x0000, 0x0000 }, /* R622 */
+ { 0x0000, 0x0000 }, /* R623 */
+ { 0x0000, 0x0000 }, /* R624 */
+ { 0x0000, 0x0000 }, /* R625 */
+ { 0x0000, 0x0000 }, /* R626 */
+ { 0x0000, 0x0000 }, /* R627 */
+ { 0x0000, 0x0000 }, /* R628 */
+ { 0x0000, 0x0000 }, /* R629 */
+ { 0x0000, 0x0000 }, /* R630 */
+ { 0x0000, 0x0000 }, /* R631 */
+ { 0x0000, 0x0000 }, /* R632 */
+ { 0x0000, 0x0000 }, /* R633 */
+ { 0x0000, 0x0000 }, /* R634 */
+ { 0x0000, 0x0000 }, /* R635 */
+ { 0x0000, 0x0000 }, /* R636 */
+ { 0x0000, 0x0000 }, /* R637 */
+ { 0x0000, 0x0000 }, /* R638 */
+ { 0x0000, 0x0000 }, /* R639 */
+ { 0x0000, 0x0000 }, /* R640 */
+ { 0x0000, 0x0000 }, /* R641 */
+ { 0x0000, 0x0000 }, /* R642 */
+ { 0x0000, 0x0000 }, /* R643 */
+ { 0x0000, 0x0000 }, /* R644 */
+ { 0x0000, 0x0000 }, /* R645 */
+ { 0x0000, 0x0000 }, /* R646 */
+ { 0x0000, 0x0000 }, /* R647 */
+ { 0x0000, 0x0000 }, /* R648 */
+ { 0x0000, 0x0000 }, /* R649 */
+ { 0x0000, 0x0000 }, /* R650 */
+ { 0x0000, 0x0000 }, /* R651 */
+ { 0x0000, 0x0000 }, /* R652 */
+ { 0x0000, 0x0000 }, /* R653 */
+ { 0x0000, 0x0000 }, /* R654 */
+ { 0x0000, 0x0000 }, /* R655 */
+ { 0x0000, 0x0000 }, /* R656 */
+ { 0x0000, 0x0000 }, /* R657 */
+ { 0x0000, 0x0000 }, /* R658 */
+ { 0x0000, 0x0000 }, /* R659 */
+ { 0x0000, 0x0000 }, /* R660 */
+ { 0x0000, 0x0000 }, /* R661 */
+ { 0x0000, 0x0000 }, /* R662 */
+ { 0x0000, 0x0000 }, /* R663 */
+ { 0x0000, 0x0000 }, /* R664 */
+ { 0x0000, 0x0000 }, /* R665 */
+ { 0x0000, 0x0000 }, /* R666 */
+ { 0x0000, 0x0000 }, /* R667 */
+ { 0x0000, 0x0000 }, /* R668 */
+ { 0x0000, 0x0000 }, /* R669 */
+ { 0x0000, 0x0000 }, /* R670 */
+ { 0x0000, 0x0000 }, /* R671 */
+ { 0x0000, 0x0000 }, /* R672 */
+ { 0x0000, 0x0000 }, /* R673 */
+ { 0x0000, 0x0000 }, /* R674 */
+ { 0x0000, 0x0000 }, /* R675 */
+ { 0x0000, 0x0000 }, /* R676 */
+ { 0x0000, 0x0000 }, /* R677 */
+ { 0x0000, 0x0000 }, /* R678 */
+ { 0x0000, 0x0000 }, /* R679 */
+ { 0x0000, 0x0000 }, /* R680 */
+ { 0x0000, 0x0000 }, /* R681 */
+ { 0x0000, 0x0000 }, /* R682 */
+ { 0x0000, 0x0000 }, /* R683 */
+ { 0x0000, 0x0000 }, /* R684 */
+ { 0x0000, 0x0000 }, /* R685 */
+ { 0x0000, 0x0000 }, /* R686 */
+ { 0x0000, 0x0000 }, /* R687 */
+ { 0x0000, 0x0000 }, /* R688 */
+ { 0x0000, 0x0000 }, /* R689 */
+ { 0x0000, 0x0000 }, /* R690 */
+ { 0x0000, 0x0000 }, /* R691 */
+ { 0x0000, 0x0000 }, /* R692 */
+ { 0x0000, 0x0000 }, /* R693 */
+ { 0x0000, 0x0000 }, /* R694 */
+ { 0x0000, 0x0000 }, /* R695 */
+ { 0x0000, 0x0000 }, /* R696 */
+ { 0x0000, 0x0000 }, /* R697 */
+ { 0x0000, 0x0000 }, /* R698 */
+ { 0x0000, 0x0000 }, /* R699 */
+ { 0x0000, 0x0000 }, /* R700 */
+ { 0x0000, 0x0000 }, /* R701 */
+ { 0x0000, 0x0000 }, /* R702 */
+ { 0x0000, 0x0000 }, /* R703 */
+ { 0x0000, 0x0000 }, /* R704 */
+ { 0x0000, 0x0000 }, /* R705 */
+ { 0x0000, 0x0000 }, /* R706 */
+ { 0x0000, 0x0000 }, /* R707 */
+ { 0x0000, 0x0000 }, /* R708 */
+ { 0x0000, 0x0000 }, /* R709 */
+ { 0x0000, 0x0000 }, /* R710 */
+ { 0x0000, 0x0000 }, /* R711 */
+ { 0x0000, 0x0000 }, /* R712 */
+ { 0x0000, 0x0000 }, /* R713 */
+ { 0x0000, 0x0000 }, /* R714 */
+ { 0x0000, 0x0000 }, /* R715 */
+ { 0x0000, 0x0000 }, /* R716 */
+ { 0x0000, 0x0000 }, /* R717 */
+ { 0x0000, 0x0000 }, /* R718 */
+ { 0x0000, 0x0000 }, /* R719 */
+ { 0x0000, 0x0000 }, /* R720 */
+ { 0x0000, 0x0000 }, /* R721 */
+ { 0x0000, 0x0000 }, /* R722 */
+ { 0x0000, 0x0000 }, /* R723 */
+ { 0x0000, 0x0000 }, /* R724 */
+ { 0x0000, 0x0000 }, /* R725 */
+ { 0x0000, 0x0000 }, /* R726 */
+ { 0x0000, 0x0000 }, /* R727 */
+ { 0x0000, 0x0000 }, /* R728 */
+ { 0x0000, 0x0000 }, /* R729 */
+ { 0x0000, 0x0000 }, /* R730 */
+ { 0x0000, 0x0000 }, /* R731 */
+ { 0x0000, 0x0000 }, /* R732 */
+ { 0x0000, 0x0000 }, /* R733 */
+ { 0x0000, 0x0000 }, /* R734 */
+ { 0x0000, 0x0000 }, /* R735 */
+ { 0x0000, 0x0000 }, /* R736 */
+ { 0x0000, 0x0000 }, /* R737 */
+ { 0x0000, 0x0000 }, /* R738 */
+ { 0x0000, 0x0000 }, /* R739 */
+ { 0x0000, 0x0000 }, /* R740 */
+ { 0x0000, 0x0000 }, /* R741 */
+ { 0x0000, 0x0000 }, /* R742 */
+ { 0x0000, 0x0000 }, /* R743 */
+ { 0x0000, 0x0000 }, /* R744 */
+ { 0x0000, 0x0000 }, /* R745 */
+ { 0x0000, 0x0000 }, /* R746 */
+ { 0x0000, 0x0000 }, /* R747 */
+ { 0x0000, 0x0000 }, /* R748 */
+ { 0x0000, 0x0000 }, /* R749 */
+ { 0x0000, 0x0000 }, /* R750 */
+ { 0x0000, 0x0000 }, /* R751 */
+ { 0x0000, 0x0000 }, /* R752 */
+ { 0x0000, 0x0000 }, /* R753 */
+ { 0x0000, 0x0000 }, /* R754 */
+ { 0x0000, 0x0000 }, /* R755 */
+ { 0x0000, 0x0000 }, /* R756 */
+ { 0x0000, 0x0000 }, /* R757 */
+ { 0x0000, 0x0000 }, /* R758 */
+ { 0x0000, 0x0000 }, /* R759 */
+ { 0x0000, 0x0000 }, /* R760 */
+ { 0x0000, 0x0000 }, /* R761 */
+ { 0x0000, 0x0000 }, /* R762 */
+ { 0x0000, 0x0000 }, /* R763 */
+ { 0x0000, 0x0000 }, /* R764 */
+ { 0x0000, 0x0000 }, /* R765 */
+ { 0x0000, 0x0000 }, /* R766 */
+ { 0x0000, 0x0000 }, /* R767 */
+ { 0xE1F8, 0xE1F8 }, /* R768 - AIF1 Control (1) */
+ { 0xCD1F, 0xCD1F }, /* R769 - AIF1 Control (2) */
+ { 0xF000, 0xF000 }, /* R770 - AIF1 Master/Slave */
+ { 0x01F0, 0x01F0 }, /* R771 - AIF1 BCLK */
+ { 0x0FFF, 0x0FFF }, /* R772 - AIF1ADC LRCLK */
+ { 0x0FFF, 0x0FFF }, /* R773 - AIF1DAC LRCLK */
+ { 0x0003, 0x0003 }, /* R774 - AIF1DAC Data */
+ { 0x0003, 0x0003 }, /* R775 - AIF1ADC Data */
+ { 0x0000, 0x0000 }, /* R776 */
+ { 0x0000, 0x0000 }, /* R777 */
+ { 0x0000, 0x0000 }, /* R778 */
+ { 0x0000, 0x0000 }, /* R779 */
+ { 0x0000, 0x0000 }, /* R780 */
+ { 0x0000, 0x0000 }, /* R781 */
+ { 0x0000, 0x0000 }, /* R782 */
+ { 0x0000, 0x0000 }, /* R783 */
+ { 0xF1F8, 0xF1F8 }, /* R784 - AIF2 Control (1) */
+ { 0xFD1F, 0xFD1F }, /* R785 - AIF2 Control (2) */
+ { 0xF000, 0xF000 }, /* R786 - AIF2 Master/Slave */
+ { 0x01F0, 0x01F0 }, /* R787 - AIF2 BCLK */
+ { 0x0FFF, 0x0FFF }, /* R788 - AIF2ADC LRCLK */
+ { 0x0FFF, 0x0FFF }, /* R789 - AIF2DAC LRCLK */
+ { 0x0003, 0x0003 }, /* R790 - AIF2DAC Data */
+ { 0x0003, 0x0003 }, /* R791 - AIF2ADC Data */
+ { 0x0000, 0x0000 }, /* R792 */
+ { 0x0000, 0x0000 }, /* R793 */
+ { 0x0000, 0x0000 }, /* R794 */
+ { 0x0000, 0x0000 }, /* R795 */
+ { 0x0000, 0x0000 }, /* R796 */
+ { 0x0000, 0x0000 }, /* R797 */
+ { 0x0000, 0x0000 }, /* R798 */
+ { 0x0000, 0x0000 }, /* R799 */
+ { 0x0000, 0x0000 }, /* R800 */
+ { 0x0000, 0x0000 }, /* R801 */
+ { 0x0000, 0x0000 }, /* R802 */
+ { 0x0000, 0x0000 }, /* R803 */
+ { 0x0000, 0x0000 }, /* R804 */
+ { 0x0000, 0x0000 }, /* R805 */
+ { 0x0000, 0x0000 }, /* R806 */
+ { 0x0000, 0x0000 }, /* R807 */
+ { 0x0000, 0x0000 }, /* R808 */
+ { 0x0000, 0x0000 }, /* R809 */
+ { 0x0000, 0x0000 }, /* R810 */
+ { 0x0000, 0x0000 }, /* R811 */
+ { 0x0000, 0x0000 }, /* R812 */
+ { 0x0000, 0x0000 }, /* R813 */
+ { 0x0000, 0x0000 }, /* R814 */
+ { 0x0000, 0x0000 }, /* R815 */
+ { 0x0000, 0x0000 }, /* R816 */
+ { 0x0000, 0x0000 }, /* R817 */
+ { 0x0000, 0x0000 }, /* R818 */
+ { 0x0000, 0x0000 }, /* R819 */
+ { 0x0000, 0x0000 }, /* R820 */
+ { 0x0000, 0x0000 }, /* R821 */
+ { 0x0000, 0x0000 }, /* R822 */
+ { 0x0000, 0x0000 }, /* R823 */
+ { 0x0000, 0x0000 }, /* R824 */
+ { 0x0000, 0x0000 }, /* R825 */
+ { 0x0000, 0x0000 }, /* R826 */
+ { 0x0000, 0x0000 }, /* R827 */
+ { 0x0000, 0x0000 }, /* R828 */
+ { 0x0000, 0x0000 }, /* R829 */
+ { 0x0000, 0x0000 }, /* R830 */
+ { 0x0000, 0x0000 }, /* R831 */
+ { 0x0000, 0x0000 }, /* R832 */
+ { 0x0000, 0x0000 }, /* R833 */
+ { 0x0000, 0x0000 }, /* R834 */
+ { 0x0000, 0x0000 }, /* R835 */
+ { 0x0000, 0x0000 }, /* R836 */
+ { 0x0000, 0x0000 }, /* R837 */
+ { 0x0000, 0x0000 }, /* R838 */
+ { 0x0000, 0x0000 }, /* R839 */
+ { 0x0000, 0x0000 }, /* R840 */
+ { 0x0000, 0x0000 }, /* R841 */
+ { 0x0000, 0x0000 }, /* R842 */
+ { 0x0000, 0x0000 }, /* R843 */
+ { 0x0000, 0x0000 }, /* R844 */
+ { 0x0000, 0x0000 }, /* R845 */
+ { 0x0000, 0x0000 }, /* R846 */
+ { 0x0000, 0x0000 }, /* R847 */
+ { 0x0000, 0x0000 }, /* R848 */
+ { 0x0000, 0x0000 }, /* R849 */
+ { 0x0000, 0x0000 }, /* R850 */
+ { 0x0000, 0x0000 }, /* R851 */
+ { 0x0000, 0x0000 }, /* R852 */
+ { 0x0000, 0x0000 }, /* R853 */
+ { 0x0000, 0x0000 }, /* R854 */
+ { 0x0000, 0x0000 }, /* R855 */
+ { 0x0000, 0x0000 }, /* R856 */
+ { 0x0000, 0x0000 }, /* R857 */
+ { 0x0000, 0x0000 }, /* R858 */
+ { 0x0000, 0x0000 }, /* R859 */
+ { 0x0000, 0x0000 }, /* R860 */
+ { 0x0000, 0x0000 }, /* R861 */
+ { 0x0000, 0x0000 }, /* R862 */
+ { 0x0000, 0x0000 }, /* R863 */
+ { 0x0000, 0x0000 }, /* R864 */
+ { 0x0000, 0x0000 }, /* R865 */
+ { 0x0000, 0x0000 }, /* R866 */
+ { 0x0000, 0x0000 }, /* R867 */
+ { 0x0000, 0x0000 }, /* R868 */
+ { 0x0000, 0x0000 }, /* R869 */
+ { 0x0000, 0x0000 }, /* R870 */
+ { 0x0000, 0x0000 }, /* R871 */
+ { 0x0000, 0x0000 }, /* R872 */
+ { 0x0000, 0x0000 }, /* R873 */
+ { 0x0000, 0x0000 }, /* R874 */
+ { 0x0000, 0x0000 }, /* R875 */
+ { 0x0000, 0x0000 }, /* R876 */
+ { 0x0000, 0x0000 }, /* R877 */
+ { 0x0000, 0x0000 }, /* R878 */
+ { 0x0000, 0x0000 }, /* R879 */
+ { 0x0000, 0x0000 }, /* R880 */
+ { 0x0000, 0x0000 }, /* R881 */
+ { 0x0000, 0x0000 }, /* R882 */
+ { 0x0000, 0x0000 }, /* R883 */
+ { 0x0000, 0x0000 }, /* R884 */
+ { 0x0000, 0x0000 }, /* R885 */
+ { 0x0000, 0x0000 }, /* R886 */
+ { 0x0000, 0x0000 }, /* R887 */
+ { 0x0000, 0x0000 }, /* R888 */
+ { 0x0000, 0x0000 }, /* R889 */
+ { 0x0000, 0x0000 }, /* R890 */
+ { 0x0000, 0x0000 }, /* R891 */
+ { 0x0000, 0x0000 }, /* R892 */
+ { 0x0000, 0x0000 }, /* R893 */
+ { 0x0000, 0x0000 }, /* R894 */
+ { 0x0000, 0x0000 }, /* R895 */
+ { 0x0000, 0x0000 }, /* R896 */
+ { 0x0000, 0x0000 }, /* R897 */
+ { 0x0000, 0x0000 }, /* R898 */
+ { 0x0000, 0x0000 }, /* R899 */
+ { 0x0000, 0x0000 }, /* R900 */
+ { 0x0000, 0x0000 }, /* R901 */
+ { 0x0000, 0x0000 }, /* R902 */
+ { 0x0000, 0x0000 }, /* R903 */
+ { 0x0000, 0x0000 }, /* R904 */
+ { 0x0000, 0x0000 }, /* R905 */
+ { 0x0000, 0x0000 }, /* R906 */
+ { 0x0000, 0x0000 }, /* R907 */
+ { 0x0000, 0x0000 }, /* R908 */
+ { 0x0000, 0x0000 }, /* R909 */
+ { 0x0000, 0x0000 }, /* R910 */
+ { 0x0000, 0x0000 }, /* R911 */
+ { 0x0000, 0x0000 }, /* R912 */
+ { 0x0000, 0x0000 }, /* R913 */
+ { 0x0000, 0x0000 }, /* R914 */
+ { 0x0000, 0x0000 }, /* R915 */
+ { 0x0000, 0x0000 }, /* R916 */
+ { 0x0000, 0x0000 }, /* R917 */
+ { 0x0000, 0x0000 }, /* R918 */
+ { 0x0000, 0x0000 }, /* R919 */
+ { 0x0000, 0x0000 }, /* R920 */
+ { 0x0000, 0x0000 }, /* R921 */
+ { 0x0000, 0x0000 }, /* R922 */
+ { 0x0000, 0x0000 }, /* R923 */
+ { 0x0000, 0x0000 }, /* R924 */
+ { 0x0000, 0x0000 }, /* R925 */
+ { 0x0000, 0x0000 }, /* R926 */
+ { 0x0000, 0x0000 }, /* R927 */
+ { 0x0000, 0x0000 }, /* R928 */
+ { 0x0000, 0x0000 }, /* R929 */
+ { 0x0000, 0x0000 }, /* R930 */
+ { 0x0000, 0x0000 }, /* R931 */
+ { 0x0000, 0x0000 }, /* R932 */
+ { 0x0000, 0x0000 }, /* R933 */
+ { 0x0000, 0x0000 }, /* R934 */
+ { 0x0000, 0x0000 }, /* R935 */
+ { 0x0000, 0x0000 }, /* R936 */
+ { 0x0000, 0x0000 }, /* R937 */
+ { 0x0000, 0x0000 }, /* R938 */
+ { 0x0000, 0x0000 }, /* R939 */
+ { 0x0000, 0x0000 }, /* R940 */
+ { 0x0000, 0x0000 }, /* R941 */
+ { 0x0000, 0x0000 }, /* R942 */
+ { 0x0000, 0x0000 }, /* R943 */
+ { 0x0000, 0x0000 }, /* R944 */
+ { 0x0000, 0x0000 }, /* R945 */
+ { 0x0000, 0x0000 }, /* R946 */
+ { 0x0000, 0x0000 }, /* R947 */
+ { 0x0000, 0x0000 }, /* R948 */
+ { 0x0000, 0x0000 }, /* R949 */
+ { 0x0000, 0x0000 }, /* R950 */
+ { 0x0000, 0x0000 }, /* R951 */
+ { 0x0000, 0x0000 }, /* R952 */
+ { 0x0000, 0x0000 }, /* R953 */
+ { 0x0000, 0x0000 }, /* R954 */
+ { 0x0000, 0x0000 }, /* R955 */
+ { 0x0000, 0x0000 }, /* R956 */
+ { 0x0000, 0x0000 }, /* R957 */
+ { 0x0000, 0x0000 }, /* R958 */
+ { 0x0000, 0x0000 }, /* R959 */
+ { 0x0000, 0x0000 }, /* R960 */
+ { 0x0000, 0x0000 }, /* R961 */
+ { 0x0000, 0x0000 }, /* R962 */
+ { 0x0000, 0x0000 }, /* R963 */
+ { 0x0000, 0x0000 }, /* R964 */
+ { 0x0000, 0x0000 }, /* R965 */
+ { 0x0000, 0x0000 }, /* R966 */
+ { 0x0000, 0x0000 }, /* R967 */
+ { 0x0000, 0x0000 }, /* R968 */
+ { 0x0000, 0x0000 }, /* R969 */
+ { 0x0000, 0x0000 }, /* R970 */
+ { 0x0000, 0x0000 }, /* R971 */
+ { 0x0000, 0x0000 }, /* R972 */
+ { 0x0000, 0x0000 }, /* R973 */
+ { 0x0000, 0x0000 }, /* R974 */
+ { 0x0000, 0x0000 }, /* R975 */
+ { 0x0000, 0x0000 }, /* R976 */
+ { 0x0000, 0x0000 }, /* R977 */
+ { 0x0000, 0x0000 }, /* R978 */
+ { 0x0000, 0x0000 }, /* R979 */
+ { 0x0000, 0x0000 }, /* R980 */
+ { 0x0000, 0x0000 }, /* R981 */
+ { 0x0000, 0x0000 }, /* R982 */
+ { 0x0000, 0x0000 }, /* R983 */
+ { 0x0000, 0x0000 }, /* R984 */
+ { 0x0000, 0x0000 }, /* R985 */
+ { 0x0000, 0x0000 }, /* R986 */
+ { 0x0000, 0x0000 }, /* R987 */
+ { 0x0000, 0x0000 }, /* R988 */
+ { 0x0000, 0x0000 }, /* R989 */
+ { 0x0000, 0x0000 }, /* R990 */
+ { 0x0000, 0x0000 }, /* R991 */
+ { 0x0000, 0x0000 }, /* R992 */
+ { 0x0000, 0x0000 }, /* R993 */
+ { 0x0000, 0x0000 }, /* R994 */
+ { 0x0000, 0x0000 }, /* R995 */
+ { 0x0000, 0x0000 }, /* R996 */
+ { 0x0000, 0x0000 }, /* R997 */
+ { 0x0000, 0x0000 }, /* R998 */
+ { 0x0000, 0x0000 }, /* R999 */
+ { 0x0000, 0x0000 }, /* R1000 */
+ { 0x0000, 0x0000 }, /* R1001 */
+ { 0x0000, 0x0000 }, /* R1002 */
+ { 0x0000, 0x0000 }, /* R1003 */
+ { 0x0000, 0x0000 }, /* R1004 */
+ { 0x0000, 0x0000 }, /* R1005 */
+ { 0x0000, 0x0000 }, /* R1006 */
+ { 0x0000, 0x0000 }, /* R1007 */
+ { 0x0000, 0x0000 }, /* R1008 */
+ { 0x0000, 0x0000 }, /* R1009 */
+ { 0x0000, 0x0000 }, /* R1010 */
+ { 0x0000, 0x0000 }, /* R1011 */
+ { 0x0000, 0x0000 }, /* R1012 */
+ { 0x0000, 0x0000 }, /* R1013 */
+ { 0x0000, 0x0000 }, /* R1014 */
+ { 0x0000, 0x0000 }, /* R1015 */
+ { 0x0000, 0x0000 }, /* R1016 */
+ { 0x0000, 0x0000 }, /* R1017 */
+ { 0x0000, 0x0000 }, /* R1018 */
+ { 0x0000, 0x0000 }, /* R1019 */
+ { 0x0000, 0x0000 }, /* R1020 */
+ { 0x0000, 0x0000 }, /* R1021 */
+ { 0x0000, 0x0000 }, /* R1022 */
+ { 0x0000, 0x0000 }, /* R1023 */
+ { 0x00FF, 0x01FF }, /* R1024 - AIF1 ADC1 Left Volume */
+ { 0x00FF, 0x01FF }, /* R1025 - AIF1 ADC1 Right Volume */
+ { 0x00FF, 0x01FF }, /* R1026 - AIF1 DAC1 Left Volume */
+ { 0x00FF, 0x01FF }, /* R1027 - AIF1 DAC1 Right Volume */
+ { 0x00FF, 0x01FF }, /* R1028 - AIF1 ADC2 Left Volume */
+ { 0x00FF, 0x01FF }, /* R1029 - AIF1 ADC2 Right Volume */
+ { 0x00FF, 0x01FF }, /* R1030 - AIF1 DAC2 Left Volume */
+ { 0x00FF, 0x01FF }, /* R1031 - AIF1 DAC2 Right Volume */
+ { 0x0000, 0x0000 }, /* R1032 */
+ { 0x0000, 0x0000 }, /* R1033 */
+ { 0x0000, 0x0000 }, /* R1034 */
+ { 0x0000, 0x0000 }, /* R1035 */
+ { 0x0000, 0x0000 }, /* R1036 */
+ { 0x0000, 0x0000 }, /* R1037 */
+ { 0x0000, 0x0000 }, /* R1038 */
+ { 0x0000, 0x0000 }, /* R1039 */
+ { 0xF800, 0xF800 }, /* R1040 - AIF1 ADC1 Filters */
+ { 0x7800, 0x7800 }, /* R1041 - AIF1 ADC2 Filters */
+ { 0x0000, 0x0000 }, /* R1042 */
+ { 0x0000, 0x0000 }, /* R1043 */
+ { 0x0000, 0x0000 }, /* R1044 */
+ { 0x0000, 0x0000 }, /* R1045 */
+ { 0x0000, 0x0000 }, /* R1046 */
+ { 0x0000, 0x0000 }, /* R1047 */
+ { 0x0000, 0x0000 }, /* R1048 */
+ { 0x0000, 0x0000 }, /* R1049 */
+ { 0x0000, 0x0000 }, /* R1050 */
+ { 0x0000, 0x0000 }, /* R1051 */
+ { 0x0000, 0x0000 }, /* R1052 */
+ { 0x0000, 0x0000 }, /* R1053 */
+ { 0x0000, 0x0000 }, /* R1054 */
+ { 0x0000, 0x0000 }, /* R1055 */
+ { 0x02B6, 0x02B6 }, /* R1056 - AIF1 DAC1 Filters (1) */
+ { 0x3F00, 0x3F00 }, /* R1057 - AIF1 DAC1 Filters (2) */
+ { 0x02B6, 0x02B6 }, /* R1058 - AIF1 DAC2 Filters (1) */
+ { 0x3F00, 0x3F00 }, /* R1059 - AIF1 DAC2 Filters (2) */
+ { 0x0000, 0x0000 }, /* R1060 */
+ { 0x0000, 0x0000 }, /* R1061 */
+ { 0x0000, 0x0000 }, /* R1062 */
+ { 0x0000, 0x0000 }, /* R1063 */
+ { 0x0000, 0x0000 }, /* R1064 */
+ { 0x0000, 0x0000 }, /* R1065 */
+ { 0x0000, 0x0000 }, /* R1066 */
+ { 0x0000, 0x0000 }, /* R1067 */
+ { 0x0000, 0x0000 }, /* R1068 */
+ { 0x0000, 0x0000 }, /* R1069 */
+ { 0x0000, 0x0000 }, /* R1070 */
+ { 0x0000, 0x0000 }, /* R1071 */
+ { 0x0000, 0x0000 }, /* R1072 */
+ { 0x0000, 0x0000 }, /* R1073 */
+ { 0x0000, 0x0000 }, /* R1074 */
+ { 0x0000, 0x0000 }, /* R1075 */
+ { 0x0000, 0x0000 }, /* R1076 */
+ { 0x0000, 0x0000 }, /* R1077 */
+ { 0x0000, 0x0000 }, /* R1078 */
+ { 0x0000, 0x0000 }, /* R1079 */
+ { 0x0000, 0x0000 }, /* R1080 */
+ { 0x0000, 0x0000 }, /* R1081 */
+ { 0x0000, 0x0000 }, /* R1082 */
+ { 0x0000, 0x0000 }, /* R1083 */
+ { 0x0000, 0x0000 }, /* R1084 */
+ { 0x0000, 0x0000 }, /* R1085 */
+ { 0x0000, 0x0000 }, /* R1086 */
+ { 0x0000, 0x0000 }, /* R1087 */
+ { 0xFFFF, 0xFFFF }, /* R1088 - AIF1 DRC1 (1) */
+ { 0x1FFF, 0x1FFF }, /* R1089 - AIF1 DRC1 (2) */
+ { 0xFFFF, 0xFFFF }, /* R1090 - AIF1 DRC1 (3) */
+ { 0x07FF, 0x07FF }, /* R1091 - AIF1 DRC1 (4) */
+ { 0x03FF, 0x03FF }, /* R1092 - AIF1 DRC1 (5) */
+ { 0x0000, 0x0000 }, /* R1093 */
+ { 0x0000, 0x0000 }, /* R1094 */
+ { 0x0000, 0x0000 }, /* R1095 */
+ { 0x0000, 0x0000 }, /* R1096 */
+ { 0x0000, 0x0000 }, /* R1097 */
+ { 0x0000, 0x0000 }, /* R1098 */
+ { 0x0000, 0x0000 }, /* R1099 */
+ { 0x0000, 0x0000 }, /* R1100 */
+ { 0x0000, 0x0000 }, /* R1101 */
+ { 0x0000, 0x0000 }, /* R1102 */
+ { 0x0000, 0x0000 }, /* R1103 */
+ { 0xFFFF, 0xFFFF }, /* R1104 - AIF1 DRC2 (1) */
+ { 0x1FFF, 0x1FFF }, /* R1105 - AIF1 DRC2 (2) */
+ { 0xFFFF, 0xFFFF }, /* R1106 - AIF1 DRC2 (3) */
+ { 0x07FF, 0x07FF }, /* R1107 - AIF1 DRC2 (4) */
+ { 0x03FF, 0x03FF }, /* R1108 - AIF1 DRC2 (5) */
+ { 0x0000, 0x0000 }, /* R1109 */
+ { 0x0000, 0x0000 }, /* R1110 */
+ { 0x0000, 0x0000 }, /* R1111 */
+ { 0x0000, 0x0000 }, /* R1112 */
+ { 0x0000, 0x0000 }, /* R1113 */
+ { 0x0000, 0x0000 }, /* R1114 */
+ { 0x0000, 0x0000 }, /* R1115 */
+ { 0x0000, 0x0000 }, /* R1116 */
+ { 0x0000, 0x0000 }, /* R1117 */
+ { 0x0000, 0x0000 }, /* R1118 */
+ { 0x0000, 0x0000 }, /* R1119 */
+ { 0x0000, 0x0000 }, /* R1120 */
+ { 0x0000, 0x0000 }, /* R1121 */
+ { 0x0000, 0x0000 }, /* R1122 */
+ { 0x0000, 0x0000 }, /* R1123 */
+ { 0x0000, 0x0000 }, /* R1124 */
+ { 0x0000, 0x0000 }, /* R1125 */
+ { 0x0000, 0x0000 }, /* R1126 */
+ { 0x0000, 0x0000 }, /* R1127 */
+ { 0x0000, 0x0000 }, /* R1128 */
+ { 0x0000, 0x0000 }, /* R1129 */
+ { 0x0000, 0x0000 }, /* R1130 */
+ { 0x0000, 0x0000 }, /* R1131 */
+ { 0x0000, 0x0000 }, /* R1132 */
+ { 0x0000, 0x0000 }, /* R1133 */
+ { 0x0000, 0x0000 }, /* R1134 */
+ { 0x0000, 0x0000 }, /* R1135 */
+ { 0x0000, 0x0000 }, /* R1136 */
+ { 0x0000, 0x0000 }, /* R1137 */
+ { 0x0000, 0x0000 }, /* R1138 */
+ { 0x0000, 0x0000 }, /* R1139 */
+ { 0x0000, 0x0000 }, /* R1140 */
+ { 0x0000, 0x0000 }, /* R1141 */
+ { 0x0000, 0x0000 }, /* R1142 */
+ { 0x0000, 0x0000 }, /* R1143 */
+ { 0x0000, 0x0000 }, /* R1144 */
+ { 0x0000, 0x0000 }, /* R1145 */
+ { 0x0000, 0x0000 }, /* R1146 */
+ { 0x0000, 0x0000 }, /* R1147 */
+ { 0x0000, 0x0000 }, /* R1148 */
+ { 0x0000, 0x0000 }, /* R1149 */
+ { 0x0000, 0x0000 }, /* R1150 */
+ { 0x0000, 0x0000 }, /* R1151 */
+ { 0xFFFF, 0xFFFF }, /* R1152 - AIF1 DAC1 EQ Gains (1) */
+ { 0xFFC0, 0xFFC0 }, /* R1153 - AIF1 DAC1 EQ Gains (2) */
+ { 0xFFFF, 0xFFFF }, /* R1154 - AIF1 DAC1 EQ Band 1 A */
+ { 0xFFFF, 0xFFFF }, /* R1155 - AIF1 DAC1 EQ Band 1 B */
+ { 0xFFFF, 0xFFFF }, /* R1156 - AIF1 DAC1 EQ Band 1 PG */
+ { 0xFFFF, 0xFFFF }, /* R1157 - AIF1 DAC1 EQ Band 2 A */
+ { 0xFFFF, 0xFFFF }, /* R1158 - AIF1 DAC1 EQ Band 2 B */
+ { 0xFFFF, 0xFFFF }, /* R1159 - AIF1 DAC1 EQ Band 2 C */
+ { 0xFFFF, 0xFFFF }, /* R1160 - AIF1 DAC1 EQ Band 2 PG */
+ { 0xFFFF, 0xFFFF }, /* R1161 - AIF1 DAC1 EQ Band 3 A */
+ { 0xFFFF, 0xFFFF }, /* R1162 - AIF1 DAC1 EQ Band 3 B */
+ { 0xFFFF, 0xFFFF }, /* R1163 - AIF1 DAC1 EQ Band 3 C */
+ { 0xFFFF, 0xFFFF }, /* R1164 - AIF1 DAC1 EQ Band 3 PG */
+ { 0xFFFF, 0xFFFF }, /* R1165 - AIF1 DAC1 EQ Band 4 A */
+ { 0xFFFF, 0xFFFF }, /* R1166 - AIF1 DAC1 EQ Band 4 B */
+ { 0xFFFF, 0xFFFF }, /* R1167 - AIF1 DAC1 EQ Band 4 C */
+ { 0xFFFF, 0xFFFF }, /* R1168 - AIF1 DAC1 EQ Band 4 PG */
+ { 0xFFFF, 0xFFFF }, /* R1169 - AIF1 DAC1 EQ Band 5 A */
+ { 0xFFFF, 0xFFFF }, /* R1170 - AIF1 DAC1 EQ Band 5 B */
+ { 0xFFFF, 0xFFFF }, /* R1171 - AIF1 DAC1 EQ Band 5 PG */
+ { 0x0000, 0x0000 }, /* R1172 */
+ { 0x0000, 0x0000 }, /* R1173 */
+ { 0x0000, 0x0000 }, /* R1174 */
+ { 0x0000, 0x0000 }, /* R1175 */
+ { 0x0000, 0x0000 }, /* R1176 */
+ { 0x0000, 0x0000 }, /* R1177 */
+ { 0x0000, 0x0000 }, /* R1178 */
+ { 0x0000, 0x0000 }, /* R1179 */
+ { 0x0000, 0x0000 }, /* R1180 */
+ { 0x0000, 0x0000 }, /* R1181 */
+ { 0x0000, 0x0000 }, /* R1182 */
+ { 0x0000, 0x0000 }, /* R1183 */
+ { 0xFFFF, 0xFFFF }, /* R1184 - AIF1 DAC2 EQ Gains (1) */
+ { 0xFFC0, 0xFFC0 }, /* R1185 - AIF1 DAC2 EQ Gains (2) */
+ { 0xFFFF, 0xFFFF }, /* R1186 - AIF1 DAC2 EQ Band 1 A */
+ { 0xFFFF, 0xFFFF }, /* R1187 - AIF1 DAC2 EQ Band 1 B */
+ { 0xFFFF, 0xFFFF }, /* R1188 - AIF1 DAC2 EQ Band 1 PG */
+ { 0xFFFF, 0xFFFF }, /* R1189 - AIF1 DAC2 EQ Band 2 A */
+ { 0xFFFF, 0xFFFF }, /* R1190 - AIF1 DAC2 EQ Band 2 B */
+ { 0xFFFF, 0xFFFF }, /* R1191 - AIF1 DAC2 EQ Band 2 C */
+ { 0xFFFF, 0xFFFF }, /* R1192 - AIF1 DAC2 EQ Band 2 PG */
+ { 0xFFFF, 0xFFFF }, /* R1193 - AIF1 DAC2 EQ Band 3 A */
+ { 0xFFFF, 0xFFFF }, /* R1194 - AIF1 DAC2 EQ Band 3 B */
+ { 0xFFFF, 0xFFFF }, /* R1195 - AIF1 DAC2 EQ Band 3 C */
+ { 0xFFFF, 0xFFFF }, /* R1196 - AIF1 DAC2 EQ Band 3 PG */
+ { 0xFFFF, 0xFFFF }, /* R1197 - AIF1 DAC2 EQ Band 4 A */
+ { 0xFFFF, 0xFFFF }, /* R1198 - AIF1 DAC2 EQ Band 4 B */
+ { 0xFFFF, 0xFFFF }, /* R1199 - AIF1 DAC2 EQ Band 4 C */
+ { 0xFFFF, 0xFFFF }, /* R1200 - AIF1 DAC2 EQ Band 4 PG */
+ { 0xFFFF, 0xFFFF }, /* R1201 - AIF1 DAC2 EQ Band 5 A */
+ { 0xFFFF, 0xFFFF }, /* R1202 - AIF1 DAC2 EQ Band 5 B */
+ { 0xFFFF, 0xFFFF }, /* R1203 - AIF1 DAC2 EQ Band 5 PG */
+ { 0x0000, 0x0000 }, /* R1204 */
+ { 0x0000, 0x0000 }, /* R1205 */
+ { 0x0000, 0x0000 }, /* R1206 */
+ { 0x0000, 0x0000 }, /* R1207 */
+ { 0x0000, 0x0000 }, /* R1208 */
+ { 0x0000, 0x0000 }, /* R1209 */
+ { 0x0000, 0x0000 }, /* R1210 */
+ { 0x0000, 0x0000 }, /* R1211 */
+ { 0x0000, 0x0000 }, /* R1212 */
+ { 0x0000, 0x0000 }, /* R1213 */
+ { 0x0000, 0x0000 }, /* R1214 */
+ { 0x0000, 0x0000 }, /* R1215 */
+ { 0x0000, 0x0000 }, /* R1216 */
+ { 0x0000, 0x0000 }, /* R1217 */
+ { 0x0000, 0x0000 }, /* R1218 */
+ { 0x0000, 0x0000 }, /* R1219 */
+ { 0x0000, 0x0000 }, /* R1220 */
+ { 0x0000, 0x0000 }, /* R1221 */
+ { 0x0000, 0x0000 }, /* R1222 */
+ { 0x0000, 0x0000 }, /* R1223 */
+ { 0x0000, 0x0000 }, /* R1224 */
+ { 0x0000, 0x0000 }, /* R1225 */
+ { 0x0000, 0x0000 }, /* R1226 */
+ { 0x0000, 0x0000 }, /* R1227 */
+ { 0x0000, 0x0000 }, /* R1228 */
+ { 0x0000, 0x0000 }, /* R1229 */
+ { 0x0000, 0x0000 }, /* R1230 */
+ { 0x0000, 0x0000 }, /* R1231 */
+ { 0x0000, 0x0000 }, /* R1232 */
+ { 0x0000, 0x0000 }, /* R1233 */
+ { 0x0000, 0x0000 }, /* R1234 */
+ { 0x0000, 0x0000 }, /* R1235 */
+ { 0x0000, 0x0000 }, /* R1236 */
+ { 0x0000, 0x0000 }, /* R1237 */
+ { 0x0000, 0x0000 }, /* R1238 */
+ { 0x0000, 0x0000 }, /* R1239 */
+ { 0x0000, 0x0000 }, /* R1240 */
+ { 0x0000, 0x0000 }, /* R1241 */
+ { 0x0000, 0x0000 }, /* R1242 */
+ { 0x0000, 0x0000 }, /* R1243 */
+ { 0x0000, 0x0000 }, /* R1244 */
+ { 0x0000, 0x0000 }, /* R1245 */
+ { 0x0000, 0x0000 }, /* R1246 */
+ { 0x0000, 0x0000 }, /* R1247 */
+ { 0x0000, 0x0000 }, /* R1248 */
+ { 0x0000, 0x0000 }, /* R1249 */
+ { 0x0000, 0x0000 }, /* R1250 */
+ { 0x0000, 0x0000 }, /* R1251 */
+ { 0x0000, 0x0000 }, /* R1252 */
+ { 0x0000, 0x0000 }, /* R1253 */
+ { 0x0000, 0x0000 }, /* R1254 */
+ { 0x0000, 0x0000 }, /* R1255 */
+ { 0x0000, 0x0000 }, /* R1256 */
+ { 0x0000, 0x0000 }, /* R1257 */
+ { 0x0000, 0x0000 }, /* R1258 */
+ { 0x0000, 0x0000 }, /* R1259 */
+ { 0x0000, 0x0000 }, /* R1260 */
+ { 0x0000, 0x0000 }, /* R1261 */
+ { 0x0000, 0x0000 }, /* R1262 */
+ { 0x0000, 0x0000 }, /* R1263 */
+ { 0x0000, 0x0000 }, /* R1264 */
+ { 0x0000, 0x0000 }, /* R1265 */
+ { 0x0000, 0x0000 }, /* R1266 */
+ { 0x0000, 0x0000 }, /* R1267 */
+ { 0x0000, 0x0000 }, /* R1268 */
+ { 0x0000, 0x0000 }, /* R1269 */
+ { 0x0000, 0x0000 }, /* R1270 */
+ { 0x0000, 0x0000 }, /* R1271 */
+ { 0x0000, 0x0000 }, /* R1272 */
+ { 0x0000, 0x0000 }, /* R1273 */
+ { 0x0000, 0x0000 }, /* R1274 */
+ { 0x0000, 0x0000 }, /* R1275 */
+ { 0x0000, 0x0000 }, /* R1276 */
+ { 0x0000, 0x0000 }, /* R1277 */
+ { 0x0000, 0x0000 }, /* R1278 */
+ { 0x0000, 0x0000 }, /* R1279 */
+ { 0x00FF, 0x01FF }, /* R1280 - AIF2 ADC Left Volume */
+ { 0x00FF, 0x01FF }, /* R1281 - AIF2 ADC Right Volume */
+ { 0x00FF, 0x01FF }, /* R1282 - AIF2 DAC Left Volume */
+ { 0x00FF, 0x01FF }, /* R1283 - AIF2 DAC Right Volume */
+ { 0x0000, 0x0000 }, /* R1284 */
+ { 0x0000, 0x0000 }, /* R1285 */
+ { 0x0000, 0x0000 }, /* R1286 */
+ { 0x0000, 0x0000 }, /* R1287 */
+ { 0x0000, 0x0000 }, /* R1288 */
+ { 0x0000, 0x0000 }, /* R1289 */
+ { 0x0000, 0x0000 }, /* R1290 */
+ { 0x0000, 0x0000 }, /* R1291 */
+ { 0x0000, 0x0000 }, /* R1292 */
+ { 0x0000, 0x0000 }, /* R1293 */
+ { 0x0000, 0x0000 }, /* R1294 */
+ { 0x0000, 0x0000 }, /* R1295 */
+ { 0xF800, 0xF800 }, /* R1296 - AIF2 ADC Filters */
+ { 0x0000, 0x0000 }, /* R1297 */
+ { 0x0000, 0x0000 }, /* R1298 */
+ { 0x0000, 0x0000 }, /* R1299 */
+ { 0x0000, 0x0000 }, /* R1300 */
+ { 0x0000, 0x0000 }, /* R1301 */
+ { 0x0000, 0x0000 }, /* R1302 */
+ { 0x0000, 0x0000 }, /* R1303 */
+ { 0x0000, 0x0000 }, /* R1304 */
+ { 0x0000, 0x0000 }, /* R1305 */
+ { 0x0000, 0x0000 }, /* R1306 */
+ { 0x0000, 0x0000 }, /* R1307 */
+ { 0x0000, 0x0000 }, /* R1308 */
+ { 0x0000, 0x0000 }, /* R1309 */
+ { 0x0000, 0x0000 }, /* R1310 */
+ { 0x0000, 0x0000 }, /* R1311 */
+ { 0x02B6, 0x02B6 }, /* R1312 - AIF2 DAC Filters (1) */
+ { 0x3F00, 0x3F00 }, /* R1313 - AIF2 DAC Filters (2) */
+ { 0x0000, 0x0000 }, /* R1314 */
+ { 0x0000, 0x0000 }, /* R1315 */
+ { 0x0000, 0x0000 }, /* R1316 */
+ { 0x0000, 0x0000 }, /* R1317 */
+ { 0x0000, 0x0000 }, /* R1318 */
+ { 0x0000, 0x0000 }, /* R1319 */
+ { 0x0000, 0x0000 }, /* R1320 */
+ { 0x0000, 0x0000 }, /* R1321 */
+ { 0x0000, 0x0000 }, /* R1322 */
+ { 0x0000, 0x0000 }, /* R1323 */
+ { 0x0000, 0x0000 }, /* R1324 */
+ { 0x0000, 0x0000 }, /* R1325 */
+ { 0x0000, 0x0000 }, /* R1326 */
+ { 0x0000, 0x0000 }, /* R1327 */
+ { 0x0000, 0x0000 }, /* R1328 */
+ { 0x0000, 0x0000 }, /* R1329 */
+ { 0x0000, 0x0000 }, /* R1330 */
+ { 0x0000, 0x0000 }, /* R1331 */
+ { 0x0000, 0x0000 }, /* R1332 */
+ { 0x0000, 0x0000 }, /* R1333 */
+ { 0x0000, 0x0000 }, /* R1334 */
+ { 0x0000, 0x0000 }, /* R1335 */
+ { 0x0000, 0x0000 }, /* R1336 */
+ { 0x0000, 0x0000 }, /* R1337 */
+ { 0x0000, 0x0000 }, /* R1338 */
+ { 0x0000, 0x0000 }, /* R1339 */
+ { 0x0000, 0x0000 }, /* R1340 */
+ { 0x0000, 0x0000 }, /* R1341 */
+ { 0x0000, 0x0000 }, /* R1342 */
+ { 0x0000, 0x0000 }, /* R1343 */
+ { 0xFFFF, 0xFFFF }, /* R1344 - AIF2 DRC (1) */
+ { 0x1FFF, 0x1FFF }, /* R1345 - AIF2 DRC (2) */
+ { 0xFFFF, 0xFFFF }, /* R1346 - AIF2 DRC (3) */
+ { 0x07FF, 0x07FF }, /* R1347 - AIF2 DRC (4) */
+ { 0x03FF, 0x03FF }, /* R1348 - AIF2 DRC (5) */
+ { 0x0000, 0x0000 }, /* R1349 */
+ { 0x0000, 0x0000 }, /* R1350 */
+ { 0x0000, 0x0000 }, /* R1351 */
+ { 0x0000, 0x0000 }, /* R1352 */
+ { 0x0000, 0x0000 }, /* R1353 */
+ { 0x0000, 0x0000 }, /* R1354 */
+ { 0x0000, 0x0000 }, /* R1355 */
+ { 0x0000, 0x0000 }, /* R1356 */
+ { 0x0000, 0x0000 }, /* R1357 */
+ { 0x0000, 0x0000 }, /* R1358 */
+ { 0x0000, 0x0000 }, /* R1359 */
+ { 0x0000, 0x0000 }, /* R1360 */
+ { 0x0000, 0x0000 }, /* R1361 */
+ { 0x0000, 0x0000 }, /* R1362 */
+ { 0x0000, 0x0000 }, /* R1363 */
+ { 0x0000, 0x0000 }, /* R1364 */
+ { 0x0000, 0x0000 }, /* R1365 */
+ { 0x0000, 0x0000 }, /* R1366 */
+ { 0x0000, 0x0000 }, /* R1367 */
+ { 0x0000, 0x0000 }, /* R1368 */
+ { 0x0000, 0x0000 }, /* R1369 */
+ { 0x0000, 0x0000 }, /* R1370 */
+ { 0x0000, 0x0000 }, /* R1371 */
+ { 0x0000, 0x0000 }, /* R1372 */
+ { 0x0000, 0x0000 }, /* R1373 */
+ { 0x0000, 0x0000 }, /* R1374 */
+ { 0x0000, 0x0000 }, /* R1375 */
+ { 0x0000, 0x0000 }, /* R1376 */
+ { 0x0000, 0x0000 }, /* R1377 */
+ { 0x0000, 0x0000 }, /* R1378 */
+ { 0x0000, 0x0000 }, /* R1379 */
+ { 0x0000, 0x0000 }, /* R1380 */
+ { 0x0000, 0x0000 }, /* R1381 */
+ { 0x0000, 0x0000 }, /* R1382 */
+ { 0x0000, 0x0000 }, /* R1383 */
+ { 0x0000, 0x0000 }, /* R1384 */
+ { 0x0000, 0x0000 }, /* R1385 */
+ { 0x0000, 0x0000 }, /* R1386 */
+ { 0x0000, 0x0000 }, /* R1387 */
+ { 0x0000, 0x0000 }, /* R1388 */
+ { 0x0000, 0x0000 }, /* R1389 */
+ { 0x0000, 0x0000 }, /* R1390 */
+ { 0x0000, 0x0000 }, /* R1391 */
+ { 0x0000, 0x0000 }, /* R1392 */
+ { 0x0000, 0x0000 }, /* R1393 */
+ { 0x0000, 0x0000 }, /* R1394 */
+ { 0x0000, 0x0000 }, /* R1395 */
+ { 0x0000, 0x0000 }, /* R1396 */
+ { 0x0000, 0x0000 }, /* R1397 */
+ { 0x0000, 0x0000 }, /* R1398 */
+ { 0x0000, 0x0000 }, /* R1399 */
+ { 0x0000, 0x0000 }, /* R1400 */
+ { 0x0000, 0x0000 }, /* R1401 */
+ { 0x0000, 0x0000 }, /* R1402 */
+ { 0x0000, 0x0000 }, /* R1403 */
+ { 0x0000, 0x0000 }, /* R1404 */
+ { 0x0000, 0x0000 }, /* R1405 */
+ { 0x0000, 0x0000 }, /* R1406 */
+ { 0x0000, 0x0000 }, /* R1407 */
+ { 0xFFFF, 0xFFFF }, /* R1408 - AIF2 EQ Gains (1) */
+ { 0xFFC0, 0xFFC0 }, /* R1409 - AIF2 EQ Gains (2) */
+ { 0xFFFF, 0xFFFF }, /* R1410 - AIF2 EQ Band 1 A */
+ { 0xFFFF, 0xFFFF }, /* R1411 - AIF2 EQ Band 1 B */
+ { 0xFFFF, 0xFFFF }, /* R1412 - AIF2 EQ Band 1 PG */
+ { 0xFFFF, 0xFFFF }, /* R1413 - AIF2 EQ Band 2 A */
+ { 0xFFFF, 0xFFFF }, /* R1414 - AIF2 EQ Band 2 B */
+ { 0xFFFF, 0xFFFF }, /* R1415 - AIF2 EQ Band 2 C */
+ { 0xFFFF, 0xFFFF }, /* R1416 - AIF2 EQ Band 2 PG */
+ { 0xFFFF, 0xFFFF }, /* R1417 - AIF2 EQ Band 3 A */
+ { 0xFFFF, 0xFFFF }, /* R1418 - AIF2 EQ Band 3 B */
+ { 0xFFFF, 0xFFFF }, /* R1419 - AIF2 EQ Band 3 C */
+ { 0xFFFF, 0xFFFF }, /* R1420 - AIF2 EQ Band 3 PG */
+ { 0xFFFF, 0xFFFF }, /* R1421 - AIF2 EQ Band 4 A */
+ { 0xFFFF, 0xFFFF }, /* R1422 - AIF2 EQ Band 4 B */
+ { 0xFFFF, 0xFFFF }, /* R1423 - AIF2 EQ Band 4 C */
+ { 0xFFFF, 0xFFFF }, /* R1424 - AIF2 EQ Band 4 PG */
+ { 0xFFFF, 0xFFFF }, /* R1425 - AIF2 EQ Band 5 A */
+ { 0xFFFF, 0xFFFF }, /* R1426 - AIF2 EQ Band 5 B */
+ { 0xFFFF, 0xFFFF }, /* R1427 - AIF2 EQ Band 5 PG */
+ { 0x0000, 0x0000 }, /* R1428 */
+ { 0x0000, 0x0000 }, /* R1429 */
+ { 0x0000, 0x0000 }, /* R1430 */
+ { 0x0000, 0x0000 }, /* R1431 */
+ { 0x0000, 0x0000 }, /* R1432 */
+ { 0x0000, 0x0000 }, /* R1433 */
+ { 0x0000, 0x0000 }, /* R1434 */
+ { 0x0000, 0x0000 }, /* R1435 */
+ { 0x0000, 0x0000 }, /* R1436 */
+ { 0x0000, 0x0000 }, /* R1437 */
+ { 0x0000, 0x0000 }, /* R1438 */
+ { 0x0000, 0x0000 }, /* R1439 */
+ { 0x0000, 0x0000 }, /* R1440 */
+ { 0x0000, 0x0000 }, /* R1441 */
+ { 0x0000, 0x0000 }, /* R1442 */
+ { 0x0000, 0x0000 }, /* R1443 */
+ { 0x0000, 0x0000 }, /* R1444 */
+ { 0x0000, 0x0000 }, /* R1445 */
+ { 0x0000, 0x0000 }, /* R1446 */
+ { 0x0000, 0x0000 }, /* R1447 */
+ { 0x0000, 0x0000 }, /* R1448 */
+ { 0x0000, 0x0000 }, /* R1449 */
+ { 0x0000, 0x0000 }, /* R1450 */
+ { 0x0000, 0x0000 }, /* R1451 */
+ { 0x0000, 0x0000 }, /* R1452 */
+ { 0x0000, 0x0000 }, /* R1453 */
+ { 0x0000, 0x0000 }, /* R1454 */
+ { 0x0000, 0x0000 }, /* R1455 */
+ { 0x0000, 0x0000 }, /* R1456 */
+ { 0x0000, 0x0000 }, /* R1457 */
+ { 0x0000, 0x0000 }, /* R1458 */
+ { 0x0000, 0x0000 }, /* R1459 */
+ { 0x0000, 0x0000 }, /* R1460 */
+ { 0x0000, 0x0000 }, /* R1461 */
+ { 0x0000, 0x0000 }, /* R1462 */
+ { 0x0000, 0x0000 }, /* R1463 */
+ { 0x0000, 0x0000 }, /* R1464 */
+ { 0x0000, 0x0000 }, /* R1465 */
+ { 0x0000, 0x0000 }, /* R1466 */
+ { 0x0000, 0x0000 }, /* R1467 */
+ { 0x0000, 0x0000 }, /* R1468 */
+ { 0x0000, 0x0000 }, /* R1469 */
+ { 0x0000, 0x0000 }, /* R1470 */
+ { 0x0000, 0x0000 }, /* R1471 */
+ { 0x0000, 0x0000 }, /* R1472 */
+ { 0x0000, 0x0000 }, /* R1473 */
+ { 0x0000, 0x0000 }, /* R1474 */
+ { 0x0000, 0x0000 }, /* R1475 */
+ { 0x0000, 0x0000 }, /* R1476 */
+ { 0x0000, 0x0000 }, /* R1477 */
+ { 0x0000, 0x0000 }, /* R1478 */
+ { 0x0000, 0x0000 }, /* R1479 */
+ { 0x0000, 0x0000 }, /* R1480 */
+ { 0x0000, 0x0000 }, /* R1481 */
+ { 0x0000, 0x0000 }, /* R1482 */
+ { 0x0000, 0x0000 }, /* R1483 */
+ { 0x0000, 0x0000 }, /* R1484 */
+ { 0x0000, 0x0000 }, /* R1485 */
+ { 0x0000, 0x0000 }, /* R1486 */
+ { 0x0000, 0x0000 }, /* R1487 */
+ { 0x0000, 0x0000 }, /* R1488 */
+ { 0x0000, 0x0000 }, /* R1489 */
+ { 0x0000, 0x0000 }, /* R1490 */
+ { 0x0000, 0x0000 }, /* R1491 */
+ { 0x0000, 0x0000 }, /* R1492 */
+ { 0x0000, 0x0000 }, /* R1493 */
+ { 0x0000, 0x0000 }, /* R1494 */
+ { 0x0000, 0x0000 }, /* R1495 */
+ { 0x0000, 0x0000 }, /* R1496 */
+ { 0x0000, 0x0000 }, /* R1497 */
+ { 0x0000, 0x0000 }, /* R1498 */
+ { 0x0000, 0x0000 }, /* R1499 */
+ { 0x0000, 0x0000 }, /* R1500 */
+ { 0x0000, 0x0000 }, /* R1501 */
+ { 0x0000, 0x0000 }, /* R1502 */
+ { 0x0000, 0x0000 }, /* R1503 */
+ { 0x0000, 0x0000 }, /* R1504 */
+ { 0x0000, 0x0000 }, /* R1505 */
+ { 0x0000, 0x0000 }, /* R1506 */
+ { 0x0000, 0x0000 }, /* R1507 */
+ { 0x0000, 0x0000 }, /* R1508 */
+ { 0x0000, 0x0000 }, /* R1509 */
+ { 0x0000, 0x0000 }, /* R1510 */
+ { 0x0000, 0x0000 }, /* R1511 */
+ { 0x0000, 0x0000 }, /* R1512 */
+ { 0x0000, 0x0000 }, /* R1513 */
+ { 0x0000, 0x0000 }, /* R1514 */
+ { 0x0000, 0x0000 }, /* R1515 */
+ { 0x0000, 0x0000 }, /* R1516 */
+ { 0x0000, 0x0000 }, /* R1517 */
+ { 0x0000, 0x0000 }, /* R1518 */
+ { 0x0000, 0x0000 }, /* R1519 */
+ { 0x0000, 0x0000 }, /* R1520 */
+ { 0x0000, 0x0000 }, /* R1521 */
+ { 0x0000, 0x0000 }, /* R1522 */
+ { 0x0000, 0x0000 }, /* R1523 */
+ { 0x0000, 0x0000 }, /* R1524 */
+ { 0x0000, 0x0000 }, /* R1525 */
+ { 0x0000, 0x0000 }, /* R1526 */
+ { 0x0000, 0x0000 }, /* R1527 */
+ { 0x0000, 0x0000 }, /* R1528 */
+ { 0x0000, 0x0000 }, /* R1529 */
+ { 0x0000, 0x0000 }, /* R1530 */
+ { 0x0000, 0x0000 }, /* R1531 */
+ { 0x0000, 0x0000 }, /* R1532 */
+ { 0x0000, 0x0000 }, /* R1533 */
+ { 0x0000, 0x0000 }, /* R1534 */
+ { 0x0000, 0x0000 }, /* R1535 */
+ { 0x01EF, 0x01EF }, /* R1536 - DAC1 Mixer Volumes */
+ { 0x0037, 0x0037 }, /* R1537 - DAC1 Left Mixer Routing */
+ { 0x0037, 0x0037 }, /* R1538 - DAC1 Right Mixer Routing */
+ { 0x01EF, 0x01EF }, /* R1539 - DAC2 Mixer Volumes */
+ { 0x0037, 0x0037 }, /* R1540 - DAC2 Left Mixer Routing */
+ { 0x0037, 0x0037 }, /* R1541 - DAC2 Right Mixer Routing */
+ { 0x0003, 0x0003 }, /* R1542 - AIF1 ADC1 Left Mixer Routing */
+ { 0x0003, 0x0003 }, /* R1543 - AIF1 ADC1 Right Mixer Routing */
+ { 0x0003, 0x0003 }, /* R1544 - AIF1 ADC2 Left Mixer Routing */
+ { 0x0003, 0x0003 }, /* R1545 - AIF1 ADC2 Right mixer Routing */
+ { 0x0000, 0x0000 }, /* R1546 */
+ { 0x0000, 0x0000 }, /* R1547 */
+ { 0x0000, 0x0000 }, /* R1548 */
+ { 0x0000, 0x0000 }, /* R1549 */
+ { 0x0000, 0x0000 }, /* R1550 */
+ { 0x0000, 0x0000 }, /* R1551 */
+ { 0x02FF, 0x03FF }, /* R1552 - DAC1 Left Volume */
+ { 0x02FF, 0x03FF }, /* R1553 - DAC1 Right Volume */
+ { 0x02FF, 0x03FF }, /* R1554 - DAC2 Left Volume */
+ { 0x02FF, 0x03FF }, /* R1555 - DAC2 Right Volume */
+ { 0x0003, 0x0003 }, /* R1556 - DAC Softmute */
+ { 0x0000, 0x0000 }, /* R1557 */
+ { 0x0000, 0x0000 }, /* R1558 */
+ { 0x0000, 0x0000 }, /* R1559 */
+ { 0x0000, 0x0000 }, /* R1560 */
+ { 0x0000, 0x0000 }, /* R1561 */
+ { 0x0000, 0x0000 }, /* R1562 */
+ { 0x0000, 0x0000 }, /* R1563 */
+ { 0x0000, 0x0000 }, /* R1564 */
+ { 0x0000, 0x0000 }, /* R1565 */
+ { 0x0000, 0x0000 }, /* R1566 */
+ { 0x0000, 0x0000 }, /* R1567 */
+ { 0x0003, 0x0003 }, /* R1568 - Oversampling */
+ { 0x03C3, 0x03C3 }, /* R1569 - Sidetone */
};
static int wm8994_readable(unsigned int reg)
@@ -1902,8 +1900,6 @@
return snd_soc_put_volsw(kcontrol, ucontrol);
}
-
-
static void wm8994_set_drc(struct snd_soc_codec *codec, int drc)
{
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
@@ -1942,7 +1938,7 @@
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+ struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994_pdata *pdata = wm8994->pdata;
int drc = wm8994_get_drc(kcontrol->id.name);
int value = ucontrol->value.integer.value[0];
@@ -2045,7 +2041,7 @@
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+ struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994_pdata *pdata = wm8994->pdata;
int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
int value = ucontrol->value.integer.value[0];
@@ -2067,7 +2063,7 @@
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+ struct wm8994_priv *wm8994 =snd_soc_codec_get_drvdata(codec);
int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
ucontrol->value.enumerated.item[0] = wm8994->retune_mobile_cfg[block];
@@ -2075,6 +2071,22 @@
return 0;
}
+static const char *aifdac_src_text[] = {
+ "Left", "Right"
+};
+
+static const struct soc_enum aif1dacl_src =
+ SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 15, 2, aifdac_src_text);
+
+static const struct soc_enum aif1dacr_src =
+ SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 14, 2, aifdac_src_text);
+
+static const struct soc_enum aif2dacl_src =
+ SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 15, 2, aifdac_src_text);
+
+static const struct soc_enum aif2dacr_src =
+ SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 14, 2, aifdac_src_text);
+
static const struct snd_kcontrol_new wm8994_snd_controls[] = {
SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME,
WM8994_AIF1_ADC1_RIGHT_VOLUME,
@@ -2086,6 +2098,11 @@
WM8994_AIF2_ADC_RIGHT_VOLUME,
1, 119, 0, digital_tlv),
+SOC_ENUM("AIF1DACL Source", aif1dacl_src),
+SOC_ENUM("AIF1DACR Source", aif1dacr_src),
+SOC_ENUM("AIF2DACL Source", aif1dacl_src),
+SOC_ENUM("AIF2DACR Source", aif1dacr_src),
+
SOC_DOUBLE_R_TLV("AIF1DAC1 Volume", WM8994_AIF1_DAC1_LEFT_VOLUME,
WM8994_AIF1_DAC1_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
SOC_DOUBLE_R_TLV("AIF1DAC2 Volume", WM8994_AIF1_DAC2_LEFT_VOLUME,
@@ -2881,10 +2898,9 @@
return 0;
}
-static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
+static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
unsigned int freq_in, unsigned int freq_out)
{
- struct snd_soc_codec *codec = dai->codec;
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
int reg_offset, ret;
struct fll_div fll;
@@ -2995,8 +3011,15 @@
return 0;
}
+
static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 };
+static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
+ unsigned int freq_in, unsigned int freq_out)
+{
+ return _wm8994_set_fll(dai->codec, id, src, freq_in, freq_out);
+}
+
static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
int clk_id, unsigned int freq, int dir)
{
@@ -3313,20 +3336,24 @@
bclk_reg = WM8994_AIF1_BCLK;
rate_reg = WM8994_AIF1_RATE;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
- wm8994->lrclk_shared[0])
+ wm8994->lrclk_shared[0]) {
lrclk_reg = WM8994_AIF1DAC_LRCLK;
- else
+ } else {
lrclk_reg = WM8994_AIF1ADC_LRCLK;
+ dev_dbg(codec->dev, "AIF1 using split LRCLK\n");
+ }
break;
case 2:
aif1_reg = WM8994_AIF2_CONTROL_1;
bclk_reg = WM8994_AIF2_BCLK;
rate_reg = WM8994_AIF2_RATE;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
- wm8994->lrclk_shared[1])
+ wm8994->lrclk_shared[1]) {
lrclk_reg = WM8994_AIF2DAC_LRCLK;
- else
+ } else {
lrclk_reg = WM8994_AIF2ADC_LRCLK;
+ dev_dbg(codec->dev, "AIF2 using split LRCLK\n");
+ }
break;
default:
return -EINVAL;
@@ -3491,7 +3518,7 @@
#define WM8994_RATES SNDRV_PCM_RATE_8000_96000
#define WM8994_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
- SNDRV_PCM_FMTBIT_S24_LE)
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_ops wm8994_aif1_dai_ops = {
.set_sysclk = wm8994_set_dai_sysclk,
@@ -3515,9 +3542,9 @@
.set_tristate = wm8994_set_tristate,
};
-struct snd_soc_dai wm8994_dai[] = {
+static struct snd_soc_dai_driver wm8994_dai[] = {
{
- .name = "WM8994 AIF1",
+ .name = "wm8994-aif1",
.id = 1,
.playback = {
.stream_name = "AIF1 Playback",
@@ -3536,7 +3563,7 @@
.ops = &wm8994_aif1_dai_ops,
},
{
- .name = "WM8994 AIF2",
+ .name = "wm8994-aif2",
.id = 2,
.playback = {
.stream_name = "AIF2 Playback",
@@ -3555,7 +3582,7 @@
.ops = &wm8994_aif2_dai_ops,
},
{
- .name = "WM8994 AIF3",
+ .name = "wm8994-aif3",
.id = 3,
.playback = {
.stream_name = "AIF3 Playback",
@@ -3574,20 +3601,17 @@
.ops = &wm8994_aif3_dai_ops,
}
};
-EXPORT_SYMBOL_GPL(wm8994_dai);
#ifdef CONFIG_PM
-static int wm8994_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
int i, ret;
for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i],
sizeof(struct fll_config));
- ret = wm8994_set_fll(&codec->dai[0], i + 1, 0, 0, 0);
+ ret = _wm8994_set_fll(codec, i + 1, 0, 0, 0);
if (ret < 0)
dev_warn(codec->dev, "Failed to stop FLL%d: %d\n",
i + 1, ret);
@@ -3598,10 +3622,8 @@
return 0;
}
-static int wm8994_resume(struct platform_device *pdev)
+static int wm8994_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
u16 *reg_cache = codec->reg_cache;
int i, ret;
@@ -3630,7 +3652,7 @@
if (!wm8994->fll_suspend[i].out)
continue;
- ret = wm8994_set_fll(&codec->dai[0], i + 1,
+ ret = _wm8994_set_fll(codec, i + 1,
wm8994->fll_suspend[i].src,
wm8994->fll_suspend[i].in,
wm8994->fll_suspend[i].out);
@@ -3648,7 +3670,7 @@
static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
{
- struct snd_soc_codec *codec = &wm8994->codec;
+ struct snd_soc_codec *codec = wm8994->codec;
struct wm8994_pdata *pdata = wm8994->pdata;
struct snd_kcontrol_new controls[] = {
SOC_ENUM_EXT("AIF1.1 EQ Mode",
@@ -3706,16 +3728,16 @@
wm8994->retune_mobile_enum.max = wm8994->num_retune_mobile_texts;
wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts;
- ret = snd_soc_add_controls(&wm8994->codec, controls,
+ ret = snd_soc_add_controls(wm8994->codec, controls,
ARRAY_SIZE(controls));
if (ret != 0)
- dev_err(wm8994->codec.dev,
+ dev_err(wm8994->codec->dev,
"Failed to add ReTune Mobile controls: %d\n", ret);
}
static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
{
- struct snd_soc_codec *codec = &wm8994->codec;
+ struct snd_soc_codec *codec = wm8994->codec;
struct wm8994_pdata *pdata = wm8994->pdata;
int ret, i;
@@ -3747,7 +3769,7 @@
wm8994->drc_texts = kmalloc(sizeof(char *)
* pdata->num_drc_cfgs, GFP_KERNEL);
if (!wm8994->drc_texts) {
- dev_err(wm8994->codec.dev,
+ dev_err(wm8994->codec->dev,
"Failed to allocate %d DRC config texts\n",
pdata->num_drc_cfgs);
return;
@@ -3759,10 +3781,10 @@
wm8994->drc_enum.max = pdata->num_drc_cfgs;
wm8994->drc_enum.texts = wm8994->drc_texts;
- ret = snd_soc_add_controls(&wm8994->codec, controls,
+ ret = snd_soc_add_controls(wm8994->codec, controls,
ARRAY_SIZE(controls));
if (ret != 0)
- dev_err(wm8994->codec.dev,
+ dev_err(wm8994->codec->dev,
"Failed to add DRC mode controls: %d\n", ret);
for (i = 0; i < WM8994_NUM_DRC; i++)
@@ -3775,62 +3797,10 @@
if (pdata->num_retune_mobile_cfgs)
wm8994_handle_retune_mobile_pdata(wm8994);
else
- snd_soc_add_controls(&wm8994->codec, wm8994_eq_controls,
+ snd_soc_add_controls(wm8994->codec, wm8994_eq_controls,
ARRAY_SIZE(wm8994_eq_controls));
}
-static int wm8994_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- if (wm8994_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8994_codec;
- codec = wm8994_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- return ret;
- }
-
- wm8994_handle_pdata(snd_soc_codec_get_drvdata(codec));
-
- wm_hubs_add_analogue_controls(codec);
- snd_soc_add_controls(codec, wm8994_snd_controls,
- ARRAY_SIZE(wm8994_snd_controls));
- snd_soc_dapm_new_controls(codec, wm8994_dapm_widgets,
- ARRAY_SIZE(wm8994_dapm_widgets));
- wm_hubs_add_analogue_routes(codec, 0, 0);
- snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
-
- return 0;
-}
-
-static int wm8994_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8994 = {
- .probe = wm8994_probe,
- .remove = wm8994_remove,
- .suspend = wm8994_suspend,
- .resume = wm8994_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8994);
-
/**
* wm8994_mic_detect - Enable microphone detection via the WM8994 IRQ
*
@@ -3842,7 +3812,7 @@
*
* Enable microphone detection via IRQ on the WM8994. If GPIOs are
* being used to bring out signals to the processor then only platform
- * data configuration is needed for WM8903 and processor GPIOs should
+ * data configuration is needed for WM8994 and processor GPIOs should
* be configured using snd_soc_jack_add_gpios() instead.
*
* Configuration of detection levels is available via the micbias1_lvl
@@ -3889,7 +3859,7 @@
static irqreturn_t wm8994_mic_irq(int irq, void *data)
{
struct wm8994_priv *priv = data;
- struct snd_soc_codec *codec = &priv->codec;
+ struct snd_soc_codec *codec = priv->codec;
int reg;
int report;
@@ -3921,46 +3891,20 @@
return IRQ_HANDLED;
}
-static int wm8994_codec_probe(struct platform_device *pdev)
+static int wm8994_codec_probe(struct snd_soc_codec *codec)
{
- int ret;
struct wm8994_priv *wm8994;
- struct snd_soc_codec *codec;
- int i;
+ int ret, i;
- if (wm8994_codec) {
- dev_err(&pdev->dev, "Another WM8994 is registered\n");
- return -EINVAL;
- }
+ codec->control_data = dev_get_drvdata(codec->dev->parent);
wm8994 = kzalloc(sizeof(struct wm8994_priv), GFP_KERNEL);
- if (!wm8994) {
- dev_err(&pdev->dev, "Failed to allocate private data\n");
+ if (wm8994 == NULL)
return -ENOMEM;
- }
-
- codec = &wm8994->codec;
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
snd_soc_codec_set_drvdata(codec, wm8994);
- codec->control_data = dev_get_drvdata(pdev->dev.parent);
- codec->name = "WM8994";
- codec->owner = THIS_MODULE;
- codec->read = wm8994_read;
- codec->write = wm8994_write;
- codec->readable_register = wm8994_readable;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8994_set_bias_level;
- codec->dai = &wm8994_dai[0];
- codec->num_dai = 3;
- codec->reg_cache_size = WM8994_MAX_REGISTER;
- codec->reg_cache = &wm8994->reg_cache;
- codec->dev = &pdev->dev;
- wm8994->pdata = pdev->dev.parent->platform_data;
+ wm8994->pdata = dev_get_platdata(codec->dev->parent);
+ wm8994->codec = codec;
/* Fill the cache with physical values we inherited; don't reset */
ret = wm8994_bulk_read(codec->control_data, 0,
@@ -3996,25 +3940,25 @@
ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC1_DET,
wm8994_mic_irq, "Mic 1 detect", wm8994);
if (ret != 0)
- dev_warn(&pdev->dev,
+ dev_warn(codec->dev,
"Failed to request Mic1 detect IRQ: %d\n", ret);
ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT,
wm8994_mic_irq, "Mic 1 short", wm8994);
if (ret != 0)
- dev_warn(&pdev->dev,
+ dev_warn(codec->dev,
"Failed to request Mic1 short IRQ: %d\n", ret);
ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC2_DET,
wm8994_mic_irq, "Mic 2 detect", wm8994);
if (ret != 0)
- dev_warn(&pdev->dev,
+ dev_warn(codec->dev,
"Failed to request Mic2 detect IRQ: %d\n", ret);
ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT,
wm8994_mic_irq, "Mic 2 short", wm8994);
if (ret != 0)
- dev_warn(&pdev->dev,
+ dev_warn(codec->dev,
"Failed to request Mic2 short IRQ: %d\n", ret);
/* Remember if AIFnLRCLK is configured as a GPIO. This should be
@@ -4045,13 +3989,8 @@
wm8994->lrclk_shared[1] = 0;
}
- for (i = 0; i < ARRAY_SIZE(wm8994_dai); i++)
- wm8994_dai[i].dev = codec->dev;
-
wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- wm8994_codec = codec;
-
/* Latch volume updates (right only; we always do left then right). */
snd_soc_update_bits(codec, WM8994_AIF1_DAC1_RIGHT_VOLUME,
WM8994_AIF1DAC1_VU, WM8994_AIF1DAC1_VU);
@@ -4088,24 +4027,18 @@
wm8994_update_class_w(codec);
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err_irq;
- }
+ wm8994_handle_pdata(wm8994);
- ret = snd_soc_register_dais(wm8994_dai, ARRAY_SIZE(wm8994_dai));
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
- goto err_codec;
- }
-
- platform_set_drvdata(pdev, wm8994);
+ wm_hubs_add_analogue_controls(codec);
+ snd_soc_add_controls(codec, wm8994_snd_controls,
+ ARRAY_SIZE(wm8994_snd_controls));
+ snd_soc_dapm_new_controls(codec, wm8994_dapm_widgets,
+ ARRAY_SIZE(wm8994_dapm_widgets));
+ wm_hubs_add_analogue_routes(codec, 0, 0);
+ snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
return 0;
-err_codec:
- snd_soc_unregister_codec(codec);
err_irq:
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, wm8994);
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994);
@@ -4116,31 +4049,50 @@
return ret;
}
-static int __devexit wm8994_codec_remove(struct platform_device *pdev)
+static int wm8994_codec_remove(struct snd_soc_codec *codec)
{
- struct wm8994_priv *wm8994 = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = &wm8994->codec;
+ struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dais(wm8994_dai, ARRAY_SIZE(wm8994_dai));
- snd_soc_unregister_codec(&wm8994->codec);
+
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, wm8994);
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994);
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994);
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_DET, wm8994);
kfree(wm8994);
- wm8994_codec = NULL;
return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_wm8994 = {
+ .probe = wm8994_codec_probe,
+ .remove = wm8994_codec_remove,
+ .suspend = wm8994_suspend,
+ .resume = wm8994_resume,
+ .read = wm8994_read,
+ .write = wm8994_write,
+ .set_bias_level = wm8994_set_bias_level,
+};
+
+static int __devinit wm8994_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8994,
+ wm8994_dai, ARRAY_SIZE(wm8994_dai));
+}
+
+static int __devexit wm8994_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
static struct platform_driver wm8994_codec_driver = {
.driver = {
.name = "wm8994-codec",
.owner = THIS_MODULE,
},
- .probe = wm8994_codec_probe,
- .remove = __devexit_p(wm8994_codec_remove),
+ .probe = wm8994_probe,
+ .remove = __devexit_p(wm8994_remove),
};
static __init int wm8994_init(void)
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
index 2e0ca67..d8dce26 100644
--- a/sound/soc/codecs/wm8994.h
+++ b/sound/soc/codecs/wm8994.h
@@ -11,9 +11,6 @@
#include <sound/soc.h>
-extern struct snd_soc_codec_device soc_codec_dev_wm8994;
-extern struct snd_soc_dai wm8994_dai[];
-
/* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */
#define WM8994_SYSCLK_MCLK1 1
#define WM8994_SYSCLK_MCLK2 2
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index 76b37ff..ecc7c37 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -156,7 +156,8 @@
};
struct wm9081_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
+ void *control_data;
u16 reg_cache[WM9081_MAX_REGISTER + 1];
int sysclk_source;
int mclk_rate;
@@ -1212,8 +1213,8 @@
/* We report two channels because the CODEC processes a stereo signal, even
* though it is only capable of handling a mono output.
*/
-struct snd_soc_dai wm9081_dai = {
- .name = "WM9081",
+static struct snd_soc_dai_driver wm9081_dai = {
+ .name = "wm9081-hifi",
.playback = {
.stream_name = "HiFi Playback",
.channels_min = 1,
@@ -1223,34 +1224,42 @@
},
.ops = &wm9081_dai_ops,
};
-EXPORT_SYMBOL_GPL(wm9081_dai);
-
-static struct snd_soc_codec *wm9081_codec;
-
-static int wm9081_probe(struct platform_device *pdev)
+static int wm9081_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- struct wm9081_priv *wm9081;
- int ret = 0;
+ struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+ u16 reg;
- if (wm9081_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
+ codec->control_data = wm9081->control_data;
+ ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm9081->control_type);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
}
- socdev->card->codec = wm9081_codec;
- codec = wm9081_codec;
- wm9081 = snd_soc_codec_get_drvdata(codec);
+ reg = snd_soc_read(codec, WM9081_SOFTWARE_RESET);
+ if (reg != 0x9081) {
+ dev_err(codec->dev, "Device is not a WM9081: ID=0x%x\n", reg);
+ ret = -EINVAL;
+ return ret;
+ }
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ ret = wm9081_reset(codec);
if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
+ dev_err(codec->dev, "Failed to issue reset\n");
+ return ret;
}
+ wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ /* Enable zero cross by default */
+ reg = snd_soc_read(codec, WM9081_ANALOGUE_LINEOUT);
+ snd_soc_write(codec, WM9081_ANALOGUE_LINEOUT, reg | WM9081_LINEOUTZC);
+ reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_PGA);
+ snd_soc_write(codec, WM9081_ANALOGUE_SPEAKER_PGA,
+ reg | WM9081_SPKPGAZC);
+
snd_soc_add_controls(codec, wm9081_snd_controls,
ARRAY_SIZE(wm9081_snd_controls));
if (!wm9081->retune) {
@@ -1265,40 +1274,28 @@
snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
return ret;
-
-pcm_err:
- return ret;
}
-static int wm9081_remove(struct platform_device *pdev)
+static int wm9081_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
+ wm9081_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
#ifdef CONFIG_PM
-static int wm9081_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm9081_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm9081_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm9081_resume(struct platform_device *pdev)
+static int wm9081_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
u16 *reg_cache = codec->reg_cache;
int i;
- for (i = 0; i < codec->reg_cache_size; i++) {
+ for (i = 0; i < codec->driver->reg_cache_size; i++) {
if (i == WM9081_SOFTWARE_RESET)
continue;
@@ -1314,133 +1311,43 @@
#define wm9081_resume NULL
#endif
-struct snd_soc_codec_device soc_codec_dev_wm9081 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm9081 = {
.probe = wm9081_probe,
.remove = wm9081_remove,
.suspend = wm9081_suspend,
.resume = wm9081_resume,
+ .set_bias_level = wm9081_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm9081_reg_defaults),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm9081_reg_defaults,
+ .volatile_register = wm9081_volatile_register,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm9081);
-static int wm9081_register(struct wm9081_priv *wm9081,
- enum snd_soc_control_type control)
-{
- struct snd_soc_codec *codec = &wm9081->codec;
- int ret;
- u16 reg;
-
- if (wm9081_codec) {
- dev_err(codec->dev, "Another WM9081 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm9081);
- codec->name = "WM9081";
- codec->owner = THIS_MODULE;
- codec->dai = &wm9081_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(wm9081->reg_cache);
- codec->reg_cache = &wm9081->reg_cache;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm9081_set_bias_level;
- codec->volatile_register = wm9081_volatile_register;
-
- memcpy(codec->reg_cache, wm9081_reg_defaults,
- sizeof(wm9081_reg_defaults));
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
- }
-
- reg = snd_soc_read(codec, WM9081_SOFTWARE_RESET);
- if (reg != 0x9081) {
- dev_err(codec->dev, "Device is not a WM9081: ID=0x%x\n", reg);
- ret = -EINVAL;
- goto err;
- }
-
- ret = wm9081_reset(codec);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to issue reset\n");
- goto err;
- }
-
- wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- /* Enable zero cross by default */
- reg = snd_soc_read(codec, WM9081_ANALOGUE_LINEOUT);
- snd_soc_write(codec, WM9081_ANALOGUE_LINEOUT, reg | WM9081_LINEOUTZC);
- reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_PGA);
- snd_soc_write(codec, WM9081_ANALOGUE_SPEAKER_PGA,
- reg | WM9081_SPKPGAZC);
-
- wm9081_dai.dev = codec->dev;
-
- wm9081_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dai(&wm9081_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
-
- return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- kfree(wm9081);
- return ret;
-}
-
-static void wm9081_unregister(struct wm9081_priv *wm9081)
-{
- wm9081_set_bias_level(&wm9081->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dai(&wm9081_dai);
- snd_soc_unregister_codec(&wm9081->codec);
- kfree(wm9081);
- wm9081_codec = NULL;
-}
-
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static __devinit int wm9081_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm9081_priv *wm9081;
- struct snd_soc_codec *codec;
+ int ret;
wm9081 = kzalloc(sizeof(struct wm9081_priv), GFP_KERNEL);
if (wm9081 == NULL)
return -ENOMEM;
- codec = &wm9081->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
- wm9081->retune = i2c->dev.platform_data;
-
i2c_set_clientdata(i2c, wm9081);
- codec->control_data = i2c;
+ wm9081->control_data = i2c;
- codec->dev = &i2c->dev;
-
- return wm9081_register(wm9081, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm9081, &wm9081_dai, 1);
+ if (ret < 0)
+ kfree(wm9081);
+ return ret;
}
static __devexit int wm9081_i2c_remove(struct i2c_client *client)
{
- struct wm9081_priv *wm9081 = i2c_get_clientdata(client);
- wm9081_unregister(wm9081);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -1452,31 +1359,34 @@
static struct i2c_driver wm9081_i2c_driver = {
.driver = {
- .name = "wm9081",
+ .name = "wm9081-codec",
.owner = THIS_MODULE,
},
.probe = wm9081_i2c_probe,
.remove = __devexit_p(wm9081_i2c_remove),
.id_table = wm9081_i2c_id,
};
+#endif
static int __init wm9081_modinit(void)
{
- int ret;
-
+ int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm9081_i2c_driver);
if (ret != 0) {
printk(KERN_ERR "Failed to register WM9081 I2C driver: %d\n",
ret);
}
-
+#endif
return ret;
}
module_init(wm9081_modinit);
static void __exit wm9081_exit(void)
{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&wm9081_i2c_driver);
+#endif
}
module_exit(wm9081_exit);
diff --git a/sound/soc/codecs/wm9081.h b/sound/soc/codecs/wm9081.h
index 42d3bc7..871cccb 100644
--- a/sound/soc/codecs/wm9081.h
+++ b/sound/soc/codecs/wm9081.h
@@ -15,9 +15,6 @@
#include <sound/soc.h>
-extern struct snd_soc_dai wm9081_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm9081;
-
/*
* SYSCLK sources
*/
diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c
index 1592250..7a18254 100644
--- a/sound/soc/codecs/wm9090.c
+++ b/sound/soc/codecs/wm9090.c
@@ -34,8 +34,6 @@
#include "wm9090.h"
-static struct snd_soc_codec *wm9090_codec;
-
static const u16 wm9090_reg_defaults[] = {
0x9093, /* R0 - Software Reset */
0x0006, /* R1 - Power Management (1) */
@@ -142,15 +140,10 @@
/* This struct is used to save the context */
struct wm9090_priv {
- /* We're not really registering as a CODEC since ASoC core
- * does not yet support multiple CODECs but having the CODEC
- * structure means we can reuse some of the ASoC core
- * features.
- */
- struct snd_soc_codec codec;
struct mutex mutex;
u16 reg_cache[WM9090_MAX_REGISTER + 1];
struct wm9090_platform_data pdata;
+ void *control_data;
};
static int wm9090_volatile(unsigned int reg)
@@ -523,7 +516,7 @@
case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF) {
/* Restore the register cache */
- for (i = 1; i < codec->reg_cache_size; i++) {
+ for (i = 1; i < codec->driver->reg_cache_size; i++) {
if (reg_cache[i] == wm9090_reg_defaults[i])
continue;
if (wm9090_volatile(i))
@@ -556,136 +549,29 @@
return 0;
}
-static int wm9090_probe(struct platform_device *pdev)
+static int wm9090_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- if (wm9090_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm9090_codec;
- codec = wm9090_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- wm9090_add_controls(codec);
-
- return 0;
-
-pcm_err:
- return ret;
-}
-
-#ifdef CONFIG_PM
-static int wm9090_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- return 0;
-}
-
-static int wm9090_resume(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-#else
-#define wm9090_suspend NULL
-#define wm9090_resume NULL
-#endif
-
-static int wm9090_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm9090 = {
- .probe = wm9090_probe,
- .remove = wm9090_remove,
- .suspend = wm9090_suspend,
- .resume = wm9090_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm9090);
-
-static int wm9090_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
-{
- struct wm9090_priv *wm9090;
- struct snd_soc_codec *codec;
+ struct wm9090_priv *wm9090 = snd_soc_codec_get_drvdata(codec);
int ret;
- wm9090 = kzalloc(sizeof(*wm9090), GFP_KERNEL);
- if (wm9090 == NULL) {
- dev_err(&i2c->dev, "Can not allocate memory\n");
- return -ENOMEM;
- }
- codec = &wm9090->codec;
-
- if (i2c->dev.platform_data)
- memcpy(&wm9090->pdata, i2c->dev.platform_data,
- sizeof(wm9090->pdata));
-
- wm9090_codec = codec;
-
- i2c_set_clientdata(i2c, wm9090);
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->control_data = i2c;
- snd_soc_codec_set_drvdata(codec, wm9090);
- codec->dev = &i2c->dev;
- codec->name = "WM9090";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm9090_set_bias_level,
- codec->reg_cache_size = WM9090_MAX_REGISTER + 1;
- codec->reg_cache = &wm9090->reg_cache;
- codec->volatile_register = wm9090_volatile;
-
+ codec->control_data = wm9090->control_data;
ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
- memcpy(&wm9090->reg_cache, wm9090_reg_defaults,
- sizeof(wm9090->reg_cache));
-
ret = snd_soc_read(codec, WM9090_SOFTWARE_RESET);
if (ret < 0)
- goto err;
+ return ret;
if (ret != wm9090_reg_defaults[WM9090_SOFTWARE_RESET]) {
- dev_err(&i2c->dev, "Device is not a WM9090, ID=%x\n", ret);
- ret = -EINVAL;
- goto err;
+ dev_err(codec->dev, "Device is not a WM9090, ID=%x\n", ret);
+ return -EINVAL;
}
ret = snd_soc_write(codec, WM9090_SOFTWARE_RESET, 0);
if (ret < 0)
- goto err;
+ return ret;
/* Configure some defaults; they will be written out when we
* bring the bias up.
@@ -700,7 +586,7 @@
| WM9090_IN2B_ZC;
wm9090->reg_cache[WM9090_SPEAKER_VOLUME_LEFT] |=
WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC;
- wm9090->reg_cache[WM9090_LEFT_OUTPUT_VOLUME] |=
+ wm9090->reg_cache[WM9090_LEFT_OUTPUT_VOLUME] |=
WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC;
wm9090->reg_cache[WM9090_RIGHT_OUTPUT_VOLUME] |=
WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC;
@@ -709,33 +595,82 @@
wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
- goto err_bias;
- }
+ wm9090_add_controls(codec);
return 0;
+}
-err_bias:
+#ifdef CONFIG_PM
+static int wm9090_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF);
-err:
- kfree(wm9090);
- i2c_set_clientdata(i2c, NULL);
- wm9090_codec = NULL;
+ return 0;
+}
+
+static int wm9090_resume(struct snd_soc_codec *codec)
+{
+ wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ return 0;
+}
+#else
+#define wm9090_suspend NULL
+#define wm9090_resume NULL
+#endif
+
+static int wm9090_remove(struct snd_soc_codec *codec)
+{
+ wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wm9090 = {
+ .probe = wm9090_probe,
+ .remove = wm9090_remove,
+ .suspend = wm9090_suspend,
+ .resume = wm9090_resume,
+ .set_bias_level = wm9090_set_bias_level,
+ .reg_cache_size = (WM9090_MAX_REGISTER + 1),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm9090_reg_defaults,
+ .volatile_register = wm9090_volatile,
+};
+
+static int wm9090_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm9090_priv *wm9090;
+ int ret;
+
+ wm9090 = kzalloc(sizeof(*wm9090), GFP_KERNEL);
+ if (wm9090 == NULL) {
+ dev_err(&i2c->dev, "Can not allocate memory\n");
+ return -ENOMEM;
+ }
+
+ if (i2c->dev.platform_data)
+ memcpy(&wm9090->pdata, i2c->dev.platform_data,
+ sizeof(wm9090->pdata));
+
+ i2c_set_clientdata(i2c, wm9090);
+ wm9090->control_data = i2c;
+ mutex_init(&wm9090->mutex);
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm9090, NULL, 0);
+ if (ret < 0)
+ kfree(wm9090);
return ret;
}
static int wm9090_i2c_remove(struct i2c_client *i2c)
{
struct wm9090_priv *wm9090 = i2c_get_clientdata(i2c);
- struct snd_soc_codec *codec = &wm9090->codec;
- snd_soc_unregister_codec(codec);
- wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ snd_soc_unregister_codec(&i2c->dev);
kfree(wm9090);
- wm9090_codec = NULL;
return 0;
}
@@ -748,7 +683,7 @@
static struct i2c_driver wm9090_i2c_driver = {
.driver = {
- .name = "wm9090",
+ .name = "wm9090-codec",
.owner = THIS_MODULE,
},
.probe = wm9090_i2c_probe,
diff --git a/sound/soc/codecs/wm9090.h b/sound/soc/codecs/wm9090.h
index b08eab9..29b9d9f 100644
--- a/sound/soc/codecs/wm9090.h
+++ b/sound/soc/codecs/wm9090.h
@@ -23,8 +23,6 @@
#ifndef __WM9090_H
#define __WM9090_H
-extern struct snd_soc_codec_device soc_codec_dev_wm9090;
-
/*
* Register values.
*/
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c
index 8793341..a144acd 100644
--- a/sound/soc/codecs/wm9705.c
+++ b/sound/soc/codecs/wm9705.c
@@ -248,8 +248,7 @@
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
int reg;
u16 vra;
@@ -273,9 +272,9 @@
.prepare = ac97_prepare,
};
-struct snd_soc_dai wm9705_dai[] = {
+static struct snd_soc_dai_driver wm9705_dai[] = {
{
- .name = "AC97 HiFi",
+ .name = "wm9705-hifi",
.ac97_control = 1,
.playback = {
.stream_name = "HiFi Playback",
@@ -294,7 +293,7 @@
.ops = &wm9705_dai_ops,
},
{
- .name = "AC97 Aux",
+ .name = "wm9705-aux",
.playback = {
.stream_name = "Aux Playback",
.channels_min = 1,
@@ -304,7 +303,6 @@
},
}
};
-EXPORT_SYMBOL_GPL(wm9705_dai);
static int wm9705_reset(struct snd_soc_codec *codec)
{
@@ -318,20 +316,15 @@
}
#ifdef CONFIG_PM
-static int wm9705_soc_suspend(struct platform_device *pdev, pm_message_t msg)
+static int wm9705_soc_suspend(struct snd_soc_codec *codec, pm_message_t msg)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
soc_ac97_ops.write(codec->ac97, AC97_POWERDOWN, 0xffff);
return 0;
}
-static int wm9705_soc_resume(struct platform_device *pdev)
+static int wm9705_soc_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i, ret;
u16 *cache = codec->reg_cache;
@@ -352,49 +345,18 @@
#define wm9705_soc_resume NULL
#endif
-static int wm9705_soc_probe(struct platform_device *pdev)
+static int wm9705_soc_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
int ret = 0;
printk(KERN_INFO "WM9705 SoC Audio Codec\n");
- socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec),
- GFP_KERNEL);
- if (socdev->card->codec == NULL)
- return -ENOMEM;
- codec = socdev->card->codec;
- mutex_init(&codec->mutex);
-
- codec->reg_cache = kmemdup(wm9705_reg, sizeof(wm9705_reg), GFP_KERNEL);
- if (codec->reg_cache == NULL) {
- ret = -ENOMEM;
- goto cache_err;
- }
- codec->reg_cache_size = sizeof(wm9705_reg);
- codec->reg_cache_step = 2;
-
- codec->name = "WM9705";
- codec->owner = THIS_MODULE;
- codec->dai = wm9705_dai;
- codec->num_dai = ARRAY_SIZE(wm9705_dai);
- codec->write = ac97_write;
- codec->read = ac97_read;
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
if (ret < 0) {
printk(KERN_ERR "wm9705: failed to register AC97 codec\n");
- goto codec_err;
+ return ret;
}
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0)
- goto pcm_err;
-
ret = wm9705_reset(codec);
if (ret)
goto reset_err;
@@ -406,40 +368,62 @@
return 0;
reset_err:
- snd_soc_free_pcms(socdev);
-pcm_err:
snd_soc_free_ac97_codec(codec);
-codec_err:
- kfree(codec->reg_cache);
-cache_err:
- kfree(socdev->card->codec);
- socdev->card->codec = NULL;
return ret;
}
-static int wm9705_soc_remove(struct platform_device *pdev)
+static int wm9705_soc_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec == NULL)
- return 0;
-
- snd_soc_dapm_free(socdev);
- snd_soc_free_pcms(socdev);
snd_soc_free_ac97_codec(codec);
- kfree(codec->reg_cache);
- kfree(codec);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_wm9705 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm9705 = {
.probe = wm9705_soc_probe,
.remove = wm9705_soc_remove,
.suspend = wm9705_soc_suspend,
.resume = wm9705_soc_resume,
+ .read = ac97_read,
+ .write = ac97_write,
+ .reg_cache_size = ARRAY_SIZE(wm9705_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_step = 2,
+ .reg_cache_default = wm9705_reg,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm9705);
+
+static __devinit int wm9705_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_wm9705, wm9705_dai, ARRAY_SIZE(wm9705_dai));
+}
+
+static int __devexit wm9705_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver wm9705_codec_driver = {
+ .driver = {
+ .name = "wm9705-codec",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = wm9705_probe,
+ .remove = __devexit_p(wm9705_remove),
+};
+
+static int __init wm9705_init(void)
+{
+ return platform_driver_register(&wm9705_codec_driver);
+}
+module_init(wm9705_init);
+
+static void __exit wm9705_exit(void)
+{
+ platform_driver_unregister(&wm9705_codec_driver);
+}
+module_exit(wm9705_exit);
MODULE_DESCRIPTION("ASoC WM9705 driver");
MODULE_AUTHOR("Ian Molton");
diff --git a/sound/soc/codecs/wm9705.h b/sound/soc/codecs/wm9705.h
index d380f11..23ea9ce 100644
--- a/sound/soc/codecs/wm9705.h
+++ b/sound/soc/codecs/wm9705.h
@@ -8,7 +8,4 @@
#define WM9705_DAI_AC97_HIFI 0
#define WM9705_DAI_AC97_AUX 1
-extern struct snd_soc_dai wm9705_dai[2];
-extern struct snd_soc_codec_device soc_codec_dev_wm9705;
-
#endif
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index 28790a2..d2f224d 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -478,8 +478,7 @@
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec =rtd->codec;
int reg;
u16 vra;
@@ -499,8 +498,7 @@
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
u16 vra, xsle;
vra = ac97_read(codec, AC97_EXTENDED_STATUS);
@@ -526,9 +524,9 @@
.prepare = ac97_aux_prepare,
};
-struct snd_soc_dai wm9712_dai[] = {
+static struct snd_soc_dai_driver wm9712_dai[] = {
{
- .name = "AC97 HiFi",
+ .name = "wm9712-hifi",
.ac97_control = 1,
.playback = {
.stream_name = "HiFi Playback",
@@ -545,7 +543,7 @@
.ops = &wm9712_dai_ops_hifi,
},
{
- .name = "AC97 Aux",
+ .name = "wm9712-aux",
.playback = {
.stream_name = "Aux Playback",
.channels_min = 1,
@@ -555,7 +553,6 @@
.ops = &wm9712_dai_ops_aux,
}
};
-EXPORT_SYMBOL_GPL(wm9712_dai);
static int wm9712_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
@@ -597,20 +594,15 @@
return -EIO;
}
-static int wm9712_soc_suspend(struct platform_device *pdev,
+static int wm9712_soc_suspend(struct snd_soc_codec *codec,
pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm9712_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm9712_soc_resume(struct platform_device *pdev)
+static int wm9712_soc_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i, ret;
u16 *cache = codec->reg_cache;
@@ -635,51 +627,18 @@
return ret;
}
-static int wm9712_soc_probe(struct platform_device *pdev)
+static int wm9712_soc_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
int ret = 0;
printk(KERN_INFO "WM9711/WM9712 SoC Audio Codec %s\n", WM9712_VERSION);
- socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec),
- GFP_KERNEL);
- if (socdev->card->codec == NULL)
- return -ENOMEM;
- codec = socdev->card->codec;
- mutex_init(&codec->mutex);
-
- codec->reg_cache = kmemdup(wm9712_reg, sizeof(wm9712_reg), GFP_KERNEL);
-
- if (codec->reg_cache == NULL) {
- ret = -ENOMEM;
- goto cache_err;
- }
- codec->reg_cache_size = sizeof(wm9712_reg);
- codec->reg_cache_step = 2;
-
- codec->name = "WM9712";
- codec->owner = THIS_MODULE;
- codec->dai = wm9712_dai;
- codec->num_dai = ARRAY_SIZE(wm9712_dai);
- codec->write = ac97_write;
- codec->read = ac97_read;
- codec->set_bias_level = wm9712_set_bias_level;
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
if (ret < 0) {
printk(KERN_ERR "wm9712: failed to register AC97 codec\n");
- goto codec_err;
+ return ret;
}
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0)
- goto pcm_err;
-
ret = wm9712_reset(codec, 0);
if (ret < 0) {
printk(KERN_ERR "Failed to reset WM9712: AC97 link error\n");
@@ -697,42 +656,63 @@
return 0;
reset_err:
- snd_soc_free_pcms(socdev);
-pcm_err:
snd_soc_free_ac97_codec(codec);
-
-codec_err:
- kfree(codec->reg_cache);
-
-cache_err:
- kfree(socdev->card->codec);
- socdev->card->codec = NULL;
return ret;
}
-static int wm9712_soc_remove(struct platform_device *pdev)
+static int wm9712_soc_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec == NULL)
- return 0;
-
- snd_soc_dapm_free(socdev);
- snd_soc_free_pcms(socdev);
snd_soc_free_ac97_codec(codec);
- kfree(codec->reg_cache);
- kfree(codec);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_wm9712 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm9712 = {
.probe = wm9712_soc_probe,
.remove = wm9712_soc_remove,
.suspend = wm9712_soc_suspend,
.resume = wm9712_soc_resume,
+ .read = ac97_read,
+ .write = ac97_write,
+ .set_bias_level = wm9712_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm9712_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_step = 2,
+ .reg_cache_default = wm9712_reg,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm9712);
+
+static __devinit int wm9712_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_wm9712, wm9712_dai, ARRAY_SIZE(wm9712_dai));
+}
+
+static int __devexit wm9712_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver wm9712_codec_driver = {
+ .driver = {
+ .name = "wm9712-codec",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = wm9712_probe,
+ .remove = __devexit_p(wm9712_remove),
+};
+
+static int __init wm9712_init(void)
+{
+ return platform_driver_register(&wm9712_codec_driver);
+}
+module_init(wm9712_init);
+
+static void __exit wm9712_exit(void)
+{
+ platform_driver_unregister(&wm9712_codec_driver);
+}
+module_exit(wm9712_exit);
MODULE_DESCRIPTION("ASoC WM9711/WM9712 driver");
MODULE_AUTHOR("Liam Girdwood");
diff --git a/sound/soc/codecs/wm9712.h b/sound/soc/codecs/wm9712.h
index d29e8a1..fb69c3a 100644
--- a/sound/soc/codecs/wm9712.h
+++ b/sound/soc/codecs/wm9712.h
@@ -8,7 +8,4 @@
#define WM9712_DAI_AC97_HIFI 0
#define WM9712_DAI_AC97_AUX 1
-extern struct snd_soc_dai wm9712_dai[2];
-extern struct snd_soc_codec_device soc_codec_dev_wm9712;
-
#endif
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index 34e0c91..7da13b0 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -1057,9 +1057,9 @@
.set_tristate = wm9713_set_dai_tristate,
};
-struct snd_soc_dai wm9713_dai[] = {
+static struct snd_soc_dai_driver wm9713_dai[] = {
{
- .name = "AC97 HiFi",
+ .name = "wm9713-hifi",
.ac97_control = 1,
.playback = {
.stream_name = "HiFi Playback",
@@ -1076,7 +1076,7 @@
.ops = &wm9713_dai_ops_hifi,
},
{
- .name = "AC97 Aux",
+ .name = "wm9713-aux",
.playback = {
.stream_name = "Aux Playback",
.channels_min = 1,
@@ -1086,7 +1086,7 @@
.ops = &wm9713_dai_ops_aux,
},
{
- .name = "WM9713 Voice",
+ .name = "wm9713-voice",
.playback = {
.stream_name = "Voice Playback",
.channels_min = 1,
@@ -1103,7 +1103,6 @@
.symmetric_rates = 1,
},
};
-EXPORT_SYMBOL_GPL(wm9713_dai);
int wm9713_reset(struct snd_soc_codec *codec, int try_warm)
{
@@ -1152,11 +1151,9 @@
return 0;
}
-static int wm9713_soc_suspend(struct platform_device *pdev,
+static int wm9713_soc_suspend(struct snd_soc_codec *codec,
pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
u16 reg;
/* Disable everything except touchpanel - that will be handled
@@ -1171,10 +1168,8 @@
return 0;
}
-static int wm9713_soc_resume(struct platform_device *pdev)
+static int wm9713_soc_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
int i, ret;
u16 *cache = codec->reg_cache;
@@ -1204,53 +1199,20 @@
return ret;
}
-static int wm9713_soc_probe(struct platform_device *pdev)
+static int wm9713_soc_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
+ struct wm9713_priv *wm9713;
int ret = 0, reg;
- socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec),
- GFP_KERNEL);
- if (socdev->card->codec == NULL)
+ wm9713 = kzalloc(sizeof(struct wm9713_priv), GFP_KERNEL);
+ if (wm9713 == NULL)
return -ENOMEM;
- codec = socdev->card->codec;
- mutex_init(&codec->mutex);
-
- codec->reg_cache = kmemdup(wm9713_reg, sizeof(wm9713_reg), GFP_KERNEL);
- if (codec->reg_cache == NULL) {
- ret = -ENOMEM;
- goto cache_err;
- }
- codec->reg_cache_size = sizeof(wm9713_reg);
- codec->reg_cache_step = 2;
-
- snd_soc_codec_set_drvdata(codec, kzalloc(sizeof(struct wm9713_priv),
- GFP_KERNEL));
- if (snd_soc_codec_get_drvdata(codec) == NULL) {
- ret = -ENOMEM;
- goto priv_err;
- }
-
- codec->name = "WM9713";
- codec->owner = THIS_MODULE;
- codec->dai = wm9713_dai;
- codec->num_dai = ARRAY_SIZE(wm9713_dai);
- codec->write = ac97_write;
- codec->read = ac97_read;
- codec->set_bias_level = wm9713_set_bias_level;
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
+ snd_soc_codec_set_drvdata(codec, wm9713);
ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
if (ret < 0)
goto codec_err;
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0)
- goto pcm_err;
-
/* do a cold reset for the controller and then try
* a warm reset followed by an optional cold reset for codec */
wm9713_reset(codec, 0);
@@ -1273,46 +1235,67 @@
return 0;
reset_err:
- snd_soc_free_pcms(socdev);
-pcm_err:
snd_soc_free_ac97_codec(codec);
-
codec_err:
- kfree(snd_soc_codec_get_drvdata(codec));
-
-priv_err:
- kfree(codec->reg_cache);
-
-cache_err:
- kfree(socdev->card->codec);
- socdev->card->codec = NULL;
+ kfree(wm9713);
return ret;
}
-static int wm9713_soc_remove(struct platform_device *pdev)
+static int wm9713_soc_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec == NULL)
- return 0;
-
- snd_soc_dapm_free(socdev);
- snd_soc_free_pcms(socdev);
+ struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
snd_soc_free_ac97_codec(codec);
- kfree(snd_soc_codec_get_drvdata(codec));
- kfree(codec->reg_cache);
- kfree(codec);
+ kfree(wm9713);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_wm9713 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm9713 = {
.probe = wm9713_soc_probe,
.remove = wm9713_soc_remove,
.suspend = wm9713_soc_suspend,
.resume = wm9713_soc_resume,
+ .read = ac97_read,
+ .write = ac97_write,
+ .set_bias_level = wm9713_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm9713_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_step = 2,
+ .reg_cache_default = wm9713_reg,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm9713);
+
+static __devinit int wm9713_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_wm9713, wm9713_dai, ARRAY_SIZE(wm9713_dai));
+}
+
+static int __devexit wm9713_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver wm9713_codec_driver = {
+ .driver = {
+ .name = "wm9713-codec",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = wm9713_probe,
+ .remove = __devexit_p(wm9713_remove),
+};
+
+static int __init wm9713_init(void)
+{
+ return platform_driver_register(&wm9713_codec_driver);
+}
+module_init(wm9713_init);
+
+static void __exit wm9713_exit(void)
+{
+ platform_driver_unregister(&wm9713_codec_driver);
+}
+module_exit(wm9713_exit);
MODULE_DESCRIPTION("ASoC WM9713/WM9714 driver");
MODULE_AUTHOR("Liam Girdwood");
diff --git a/sound/soc/codecs/wm9713.h b/sound/soc/codecs/wm9713.h
index 63b8d81..793da86 100644
--- a/sound/soc/codecs/wm9713.h
+++ b/sound/soc/codecs/wm9713.h
@@ -45,9 +45,6 @@
#define WM9713_DAI_AC97_AUX 1
#define WM9713_DAI_PCM_VOICE 2
-extern struct snd_soc_codec_device soc_codec_dev_wm9713;
-extern struct snd_soc_dai wm9713_dai[3];
-
int wm9713_reset(struct snd_soc_codec *codec, int try_warm);
#endif
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index 97f74d6..2b07b17 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -28,12 +28,9 @@
#include <mach/mux.h>
#include "../codecs/tlv320aic3x.h"
-#include "../codecs/cq93vc.h"
-#include "../codecs/spdif_transciever.h"
#include "davinci-pcm.h"
#include "davinci-i2s.h"
#include "davinci-mcasp.h"
-#include "davinci-vcif.h"
#define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \
SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF)
@@ -41,8 +38,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret = 0;
unsigned sysclk;
@@ -87,7 +84,7 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
/* set cpu DAI configuration */
return snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT);
@@ -132,8 +129,10 @@
};
/* Logic for a aic3x as connected on a davinci-evm */
-static int evm_aic3x_init(struct snd_soc_codec *codec)
+static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
/* Add davinci-evm specific widgets */
snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets,
ARRAY_SIZE(aic3x_dapm_widgets));
@@ -161,8 +160,10 @@
static struct snd_soc_dai_link evm_dai = {
.name = "TLV320AIC3X",
.stream_name = "AIC3X",
- .cpu_dai = &davinci_i2s_dai,
- .codec_dai = &aic3x_dai,
+ .cpu_dai_name = "davinci-mcasp.0",
+ .codec_dai_name = "tlv320aic3x-hifi",
+ .codec_name = "tlv320aic3x-codec.0-001a",
+ .platform_name = "davinci-pcm-audio",
.init = evm_aic3x_init,
.ops = &evm_ops,
};
@@ -171,40 +172,49 @@
#ifdef CONFIG_SND_DM365_AIC3X_CODEC
.name = "TLV320AIC3X",
.stream_name = "AIC3X",
- .cpu_dai = &davinci_i2s_dai,
- .codec_dai = &aic3x_dai,
+ .cpu_dai_name = "davinci-i2s",
+ .codec_dai_name = "tlv320aic3x-hifi",
.init = evm_aic3x_init,
+ .codec_name = "tlv320aic3x-codec.0-001a",
.ops = &evm_ops,
#elif defined(CONFIG_SND_DM365_VOICE_CODEC)
.name = "Voice Codec - CQ93VC",
.stream_name = "CQ93",
- .cpu_dai = &davinci_vcif_dai,
- .codec_dai = &cq93vc_dai,
+ .cpu_dai_name = "davinci-vcif",
+ .codec_dai_name = "cq93vc-hifi",
+ .codec_name = "cq93vc-codec",
#endif
+ .platform_name = "davinci-pcm-audio",
};
static struct snd_soc_dai_link dm6467_evm_dai[] = {
{
.name = "TLV320AIC3X",
.stream_name = "AIC3X",
- .cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_I2S_DAI],
- .codec_dai = &aic3x_dai,
+ .cpu_dai_name= "davinci-mcasp.0",
+ .codec_dai_name = "tlv320aic3x-hifi",
+ .platform_name ="davinci-pcm-audio",
+ .codec_name = "tlv320aic3x-codec.0-001a",
.init = evm_aic3x_init,
.ops = &evm_ops,
},
{
.name = "McASP",
.stream_name = "spdif",
- .cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_DIT_DAI],
- .codec_dai = &dit_stub_dai,
+ .cpu_dai_name= "davinci-mcasp.1",
+ .codec_dai_name = "dit-hifi",
+ .codec_name = "spdif_dit",
+ .platform_name = "davinci-pcm-audio",
.ops = &evm_spdif_ops,
},
};
static struct snd_soc_dai_link da8xx_evm_dai = {
.name = "TLV320AIC3X",
.stream_name = "AIC3X",
- .cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_I2S_DAI],
- .codec_dai = &aic3x_dai,
+ .cpu_dai_name= "davinci-mcasp.0",
+ .codec_dai_name = "tlv320aic3x-hifi",
+ .codec_name = "tlv320aic3x-codec.0-001a",
+ .platform_name = "davinci-pcm-audio",
.init = evm_aic3x_init,
.ops = &evm_ops,
};
@@ -212,7 +222,6 @@
/* davinci dm6446, dm355 evm audio machine driver */
static struct snd_soc_card snd_soc_card_evm = {
.name = "DaVinci EVM",
- .platform = &davinci_soc_platform,
.dai_link = &evm_dai,
.num_links = 1,
};
@@ -220,16 +229,13 @@
/* davinci dm365 evm audio machine driver */
static struct snd_soc_card dm365_snd_soc_card_evm = {
.name = "DaVinci DM365 EVM",
- .platform = &davinci_soc_platform,
.dai_link = &dm365_evm_dai,
.num_links = 1,
};
-
/* davinci dm6467 evm audio machine driver */
static struct snd_soc_card dm6467_snd_soc_card_evm = {
.name = "DaVinci DM6467 EVM",
- .platform = &davinci_soc_platform,
.dai_link = dm6467_evm_dai,
.num_links = ARRAY_SIZE(dm6467_evm_dai),
};
@@ -237,82 +243,40 @@
static struct snd_soc_card da830_snd_soc_card = {
.name = "DA830/OMAP-L137 EVM",
.dai_link = &da8xx_evm_dai,
- .platform = &davinci_soc_platform,
.num_links = 1,
};
static struct snd_soc_card da850_snd_soc_card = {
.name = "DA850/OMAP-L138 EVM",
.dai_link = &da8xx_evm_dai,
- .platform = &davinci_soc_platform,
.num_links = 1,
};
-static struct aic3x_setup_data aic3x_setup;
-
-/* evm audio subsystem */
-static struct snd_soc_device evm_snd_devdata = {
- .card = &snd_soc_card_evm,
- .codec_dev = &soc_codec_dev_aic3x,
- .codec_data = &aic3x_setup,
-};
-
-/* evm audio subsystem */
-static struct snd_soc_device dm365_evm_snd_devdata = {
- .card = &dm365_snd_soc_card_evm,
-#ifdef CONFIG_SND_DM365_AIC3X_CODEC
- .codec_dev = &soc_codec_dev_aic3x,
- .codec_data = &aic3x_setup,
-#elif defined(CONFIG_SND_DM365_VOICE_CODEC)
- .codec_dev = &soc_codec_dev_cq93vc,
-#endif
-};
-
-/* evm audio subsystem */
-static struct snd_soc_device dm6467_evm_snd_devdata = {
- .card = &dm6467_snd_soc_card_evm,
- .codec_dev = &soc_codec_dev_aic3x,
- .codec_data = &aic3x_setup,
-};
-
-/* evm audio subsystem */
-static struct snd_soc_device da830_evm_snd_devdata = {
- .card = &da830_snd_soc_card,
- .codec_dev = &soc_codec_dev_aic3x,
- .codec_data = &aic3x_setup,
-};
-
-static struct snd_soc_device da850_evm_snd_devdata = {
- .card = &da850_snd_soc_card,
- .codec_dev = &soc_codec_dev_aic3x,
- .codec_data = &aic3x_setup,
-};
-
static struct platform_device *evm_snd_device;
static int __init evm_init(void)
{
- struct snd_soc_device *evm_snd_dev_data;
+ struct snd_soc_card *evm_snd_dev_data;
int index;
int ret;
if (machine_is_davinci_evm()) {
- evm_snd_dev_data = &evm_snd_devdata;
+ evm_snd_dev_data = &snd_soc_card_evm;
index = 0;
} else if (machine_is_davinci_dm355_evm()) {
- evm_snd_dev_data = &evm_snd_devdata;
+ evm_snd_dev_data = &snd_soc_card_evm;
index = 1;
} else if (machine_is_davinci_dm365_evm()) {
- evm_snd_dev_data = &dm365_evm_snd_devdata;
+ evm_snd_dev_data = &dm365_snd_soc_card_evm;
index = 0;
} else if (machine_is_davinci_dm6467_evm()) {
- evm_snd_dev_data = &dm6467_evm_snd_devdata;
+ evm_snd_dev_data = &dm6467_snd_soc_card_evm;
index = 0;
} else if (machine_is_davinci_da830_evm()) {
- evm_snd_dev_data = &da830_evm_snd_devdata;
+ evm_snd_dev_data = &da830_snd_soc_card;
index = 1;
} else if (machine_is_davinci_da850_evm()) {
- evm_snd_dev_data = &da850_evm_snd_devdata;
+ evm_snd_dev_data = &da850_snd_soc_card;
index = 0;
} else
return -EINVAL;
@@ -322,7 +286,6 @@
return -ENOMEM;
platform_set_drvdata(evm_snd_device, evm_snd_dev_data);
- evm_snd_dev_data->dev = &evm_snd_device->dev;
ret = platform_device_add(evm_snd_device);
if (ret)
platform_device_put(evm_snd_device);
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index 9e8932a..d46b545 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -183,8 +183,7 @@
struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_platform *platform = socdev->card->platform;
+ struct snd_soc_platform *platform = rtd->platform;
int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
u32 spcr;
u32 mask = playback ? DAVINCI_MCBSP_SPCR_XRST : DAVINCI_MCBSP_SPCR_RRST;
@@ -205,8 +204,8 @@
if (playback) {
/* Stop the DMA to avoid data loss */
/* while the transmitter is out of reset to handle XSYNCERR */
- if (platform->pcm_ops->trigger) {
- int ret = platform->pcm_ops->trigger(substream,
+ if (platform->driver->ops->trigger) {
+ int ret = platform->driver->ops->trigger(substream,
SNDRV_PCM_TRIGGER_STOP);
if (ret < 0)
printk(KERN_DEBUG "Playback DMA stop failed\n");
@@ -227,8 +226,8 @@
toggle_clock(dev, playback);
/* Restart the DMA */
- if (platform->pcm_ops->trigger) {
- int ret = platform->pcm_ops->trigger(substream,
+ if (platform->driver->ops->trigger) {
+ int ret = platform->driver->ops->trigger(substream,
SNDRV_PCM_TRIGGER_START);
if (ret < 0)
printk(KERN_DEBUG "Playback DMA start failed\n");
@@ -263,7 +262,7 @@
static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
- struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
+ struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
unsigned int pcr;
unsigned int srgr;
/* Attention srgr is updated by hw_params! */
@@ -404,7 +403,7 @@
static int davinci_i2s_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
int div_id, int div)
{
- struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
+ struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
if (div_id != DAVINCI_MCBSP_CLKGDV)
return -ENODEV;
@@ -417,7 +416,7 @@
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct davinci_mcbsp_dev *dev = dai->private_data;
+ struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
struct davinci_pcm_dma_params *dma_params =
&dev->dma_params[substream->stream];
struct snd_interval *i = NULL;
@@ -427,6 +426,9 @@
snd_pcm_format_t fmt;
unsigned element_cnt = 1;
+ dai->capture_dma_data = dev->dma_params;
+ dai->playback_dma_data = dev->dma_params;
+
/* general line settings */
spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
@@ -569,24 +571,18 @@
static int davinci_i2s_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct davinci_mcbsp_dev *dev = dai->private_data;
+ struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
davinci_mcbsp_stop(dev, playback);
- if ((dev->pcr & DAVINCI_MCBSP_PCR_FSXM) == 0) {
- /* codec is master */
- davinci_mcbsp_start(dev, substream);
- }
return 0;
}
static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct davinci_mcbsp_dev *dev = dai->private_data;
+ struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
int ret = 0;
int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
- if ((dev->pcr & DAVINCI_MCBSP_PCR_FSXM) == 0)
- return 0; /* return if codec is master */
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -608,7 +604,7 @@
static void davinci_i2s_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct davinci_mcbsp_dev *dev = dai->private_data;
+ struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
davinci_mcbsp_stop(dev, playback);
}
@@ -625,9 +621,7 @@
};
-struct snd_soc_dai davinci_i2s_dai = {
- .name = "davinci-i2s",
- .id = 0,
+static struct snd_soc_dai_driver davinci_i2s_dai = {
.playback = {
.channels_min = 2,
.channels_max = 2,
@@ -641,7 +635,6 @@
.ops = &davinci_i2s_dai_ops,
};
-EXPORT_SYMBOL_GPL(davinci_i2s_dai);
static int davinci_i2s_probe(struct platform_device *pdev)
{
@@ -720,10 +713,9 @@
dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start;
dev->dev = &pdev->dev;
- davinci_i2s_dai.private_data = dev;
- davinci_i2s_dai.capture.dma_data = dev->dma_params;
- davinci_i2s_dai.playback.dma_data = dev->dma_params;
- ret = snd_soc_register_dai(&davinci_i2s_dai);
+ dev_set_drvdata(&pdev->dev, dev);
+
+ ret = snd_soc_register_dai(&pdev->dev, &davinci_i2s_dai);
if (ret != 0)
goto err_free_mem;
@@ -739,10 +731,10 @@
static int davinci_i2s_remove(struct platform_device *pdev)
{
- struct davinci_mcbsp_dev *dev = davinci_i2s_dai.private_data;
+ struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev);
struct resource *mem;
- snd_soc_unregister_dai(&davinci_i2s_dai);
+ snd_soc_unregister_dai(&pdev->dev);
clk_disable(dev->clk);
clk_put(dev->clk);
dev->clk = NULL;
@@ -757,7 +749,7 @@
.probe = davinci_i2s_probe,
.remove = davinci_i2s_remove,
.driver = {
- .name = "davinci-asp",
+ .name = "davinci-i2s",
.owner = THIS_MODULE,
},
};
diff --git a/sound/soc/davinci/davinci-i2s.h b/sound/soc/davinci/davinci-i2s.h
index 0b1e77b..48dac3e 100644
--- a/sound/soc/davinci/davinci-i2s.h
+++ b/sound/soc/davinci/davinci-i2s.h
@@ -17,6 +17,4 @@
DAVINCI_MCBSP_CLKGDV, /* Sample rate generator divider */
};
-extern struct snd_soc_dai davinci_i2s_dai;
-
#endif
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index b247208..86918ee 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -422,7 +422,7 @@
static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
- struct davinci_audio_dev *dev = cpu_dai->private_data;
+ struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
void __iomem *base = dev->base;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -709,12 +709,15 @@
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
- struct davinci_audio_dev *dev = cpu_dai->private_data;
+ struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
struct davinci_pcm_dma_params *dma_params =
&dev->dma_params[substream->stream];
int word_length;
u8 fifo_level;
+ cpu_dai->capture_dma_data = dev->dma_params;
+ cpu_dai->playback_dma_data = dev->dma_params;
+
davinci_hw_common_param(dev, substream->stream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
fifo_level = dev->txnumevt;
@@ -761,8 +764,7 @@
static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct davinci_audio_dev *dev = rtd->dai->cpu_dai->private_data;
+ struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
int ret = 0;
switch (cmd) {
@@ -804,10 +806,9 @@
};
-struct snd_soc_dai davinci_mcasp_dai[] = {
+static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
{
- .name = "davinci-i2s",
- .id = 0,
+ .name = "davinci-mcasp.0",
.playback = {
.channels_min = 2,
.channels_max = 2,
@@ -828,8 +829,7 @@
},
{
- .name = "davinci-dit",
- .id = 1,
+ "davinci-mcasp.1",
.playback = {
.channels_min = 1,
.channels_max = 384,
@@ -840,7 +840,6 @@
},
};
-EXPORT_SYMBOL_GPL(davinci_mcasp_dai);
static int davinci_mcasp_probe(struct platform_device *pdev)
{
@@ -899,6 +898,7 @@
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!res) {
dev_err(&pdev->dev, "no DMA resource\n");
+ ret = -ENODEV;
goto err_release_region;
}
@@ -913,15 +913,13 @@
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!res) {
dev_err(&pdev->dev, "no DMA resource\n");
+ ret = -ENODEV;
goto err_release_region;
}
dma_data->channel = res->start;
- davinci_mcasp_dai[pdata->op_mode].private_data = dev;
- davinci_mcasp_dai[pdata->op_mode].capture.dma_data = dev->dma_params;
- davinci_mcasp_dai[pdata->op_mode].playback.dma_data = dev->dma_params;
- davinci_mcasp_dai[pdata->op_mode].dev = &pdev->dev;
- ret = snd_soc_register_dai(&davinci_mcasp_dai[pdata->op_mode]);
+ dev_set_drvdata(&pdev->dev, dev);
+ ret = snd_soc_register_dai(&pdev->dev, &davinci_mcasp_dai[pdata->op_mode]);
if (ret != 0)
goto err_release_region;
@@ -937,12 +935,10 @@
static int davinci_mcasp_remove(struct platform_device *pdev)
{
- struct snd_platform_data *pdata = pdev->dev.platform_data;
- struct davinci_audio_dev *dev;
+ struct davinci_audio_dev *dev = dev_get_drvdata(&pdev->dev);
struct resource *mem;
- snd_soc_unregister_dai(&davinci_mcasp_dai[pdata->op_mode]);
- dev = davinci_mcasp_dai[pdata->op_mode].private_data;
+ snd_soc_unregister_dai(&pdev->dev);
clk_disable(dev->clk);
clk_put(dev->clk);
dev->clk = NULL;
diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h
index e755b51..4681acc 100644
--- a/sound/soc/davinci/davinci-mcasp.h
+++ b/sound/soc/davinci/davinci-mcasp.h
@@ -22,8 +22,6 @@
#include <mach/asp.h>
#include "davinci-pcm.h"
-extern struct snd_soc_dai davinci_mcasp_dai[];
-
#define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_96000
#define DAVINCI_MCASP_I2S_DAI 0
#define DAVINCI_MCASP_DIT_DAI 1
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
index a712411..9d35b8c 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -653,7 +653,7 @@
struct davinci_pcm_dma_params *pa;
struct davinci_pcm_dma_params *params;
- pa = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ pa = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
if (!pa)
return -ENODEV;
params = &pa[substream->stream];
@@ -821,7 +821,7 @@
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = 0xffffffff;
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = davinci_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK,
pcm_hardware_playback.buffer_bytes_max);
@@ -829,7 +829,7 @@
return ret;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
ret = davinci_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE,
pcm_hardware_capture.buffer_bytes_max);
@@ -840,25 +840,44 @@
return 0;
}
-struct snd_soc_platform davinci_soc_platform = {
- .name = "davinci-audio",
- .pcm_ops = &davinci_pcm_ops,
+static struct snd_soc_platform_driver davinci_soc_platform = {
+ .ops = &davinci_pcm_ops,
.pcm_new = davinci_pcm_new,
.pcm_free = davinci_pcm_free,
};
-EXPORT_SYMBOL_GPL(davinci_soc_platform);
-static int __init davinci_soc_platform_init(void)
+static int __devinit davinci_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&davinci_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &davinci_soc_platform);
}
-module_init(davinci_soc_platform_init);
-static void __exit davinci_soc_platform_exit(void)
+static int __devexit davinci_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&davinci_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
}
-module_exit(davinci_soc_platform_exit);
+
+static struct platform_driver davinci_pcm_driver = {
+ .driver = {
+ .name = "davinci-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = davinci_soc_platform_probe,
+ .remove = __devexit_p(davinci_soc_platform_remove),
+};
+
+static int __init snd_davinci_pcm_init(void)
+{
+ return platform_driver_register(&davinci_pcm_driver);
+}
+module_init(snd_davinci_pcm_init);
+
+static void __exit snd_davinci_pcm_exit(void)
+{
+ platform_driver_unregister(&davinci_pcm_driver);
+}
+module_exit(snd_davinci_pcm_exit);
MODULE_AUTHOR("Vladimir Barinov");
MODULE_DESCRIPTION("TI DAVINCI PCM DMA module");
diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h
index b799a02..c0d6c9b 100644
--- a/sound/soc/davinci/davinci-pcm.h
+++ b/sound/soc/davinci/davinci-pcm.h
@@ -28,7 +28,4 @@
unsigned int fifo_level;
};
-
-extern struct snd_soc_platform davinci_soc_platform;
-
#endif
diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c
index 40eccfe..009b652 100644
--- a/sound/soc/davinci/davinci-sffsdr.c
+++ b/sound/soc/davinci/davinci-sffsdr.c
@@ -29,7 +29,6 @@
#include <asm/plat-sffsdr/sffsdr-fpga.h>
#endif
-#include <mach/mcbsp.h>
#include <mach/edma.h>
#include "../codecs/pcm3008.h"
@@ -48,7 +47,7 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int fs;
int ret = 0;
@@ -85,15 +84,16 @@
static struct snd_soc_dai_link sffsdr_dai = {
.name = "PCM3008", /* Codec name */
.stream_name = "PCM3008 HiFi",
- .cpu_dai = &davinci_i2s_dai,
- .codec_dai = &pcm3008_dai,
+ .cpu_dai_name = "davinci-asp.0",
+ .codec_dai_name = "pcm3008-hifi",
+ .codec_name = "pcm3008-codec",
+ .platform_name = "davinci-pcm-audio",
.ops = &sffsdr_ops,
};
/* davinci-sffsdr audio machine driver */
static struct snd_soc_card snd_soc_sffsdr = {
.name = "DaVinci SFFSDR",
- .platform = &davinci_soc_platform,
.dai_link = &sffsdr_dai,
.num_links = 1,
};
@@ -106,11 +106,12 @@
.pdda_pin = GPIO(38),
};
-/* sffsdr audio subsystem */
-static struct snd_soc_device sffsdr_snd_devdata = {
- .card = &snd_soc_sffsdr,
- .codec_dev = &soc_codec_dev_pcm3008,
- .codec_data = &sffsdr_pcm3008_setup,
+struct platform_device pcm3008_codec = {
+ .name = "pcm3008-codec",
+ .id = 0,
+ .dev = {
+ .platform_data = &sffsdr_pcm3008_setup,
+ },
};
static struct resource sffsdr_snd_resources[] = {
@@ -135,14 +136,15 @@
if (!machine_is_sffsdr())
return -EINVAL;
+ platform_device_register(&pcm3008_codec);
+
sffsdr_snd_device = platform_device_alloc("soc-audio", 0);
if (!sffsdr_snd_device) {
printk(KERN_ERR "platform device allocation failed\n");
return -ENOMEM;
}
- platform_set_drvdata(sffsdr_snd_device, &sffsdr_snd_devdata);
- sffsdr_snd_devdata.dev = &sffsdr_snd_device->dev;
+ platform_set_drvdata(sffsdr_snd_device, &snd_soc_sffsdr);
platform_device_add_data(sffsdr_snd_device, &sffsdr_snd_data,
sizeof(sffsdr_snd_data));
@@ -150,7 +152,7 @@
sffsdr_snd_resources,
ARRAY_SIZE(sffsdr_snd_resources));
if (ret) {
- printk(KERN_ERR "platform device add ressources failed\n");
+ printk(KERN_ERR "platform device add resources failed\n");
goto error;
}
@@ -168,6 +170,7 @@
static void __exit sffsdr_exit(void)
{
platform_device_unregister(sffsdr_snd_device);
+ platform_device_unregister(&pcm3008_codec);
}
module_init(sffsdr_init);
diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c
index 4867853..ea232f6 100644
--- a/sound/soc/davinci/davinci-vcif.c
+++ b/sound/soc/davinci/davinci-vcif.c
@@ -36,7 +36,6 @@
#include "davinci-pcm.h"
#include "davinci-i2s.h"
-#include "davinci-vcif.h"
#define MOD_REG_BIT(val, mask, set) do { \
if (set) { \
@@ -55,7 +54,7 @@
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct davinci_vcif_dev *davinci_vcif_dev =
- rtd->dai->cpu_dai->private_data;
+ snd_soc_dai_get_drvdata(rtd->cpu_dai);
struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;
u32 w;
@@ -74,7 +73,7 @@
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct davinci_vcif_dev *davinci_vcif_dev =
- rtd->dai->cpu_dai->private_data;
+ snd_soc_dai_get_drvdata(rtd->cpu_dai);
struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;
u32 w;
@@ -92,12 +91,15 @@
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct davinci_vcif_dev *davinci_vcif_dev = dai->private_data;
+ struct davinci_vcif_dev *davinci_vcif_dev = snd_soc_dai_get_drvdata(dai);
struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;
struct davinci_pcm_dma_params *dma_params =
&davinci_vcif_dev->dma_params[substream->stream];
u32 w;
+ dai->capture_dma_data = davinci_vcif_dev->dma_params;
+ dai->playback_dma_data = davinci_vcif_dev->dma_params;
+
/* Restart the codec before setup */
davinci_vcif_stop(substream);
davinci_vcif_start(substream);
@@ -179,8 +181,7 @@
.hw_params = davinci_vcif_hw_params,
};
-struct snd_soc_dai davinci_vcif_dai = {
- .name = "davinci-vcif",
+static struct snd_soc_dai_driver davinci_vcif_dai = {
.playback = {
.channels_min = 1,
.channels_max = 2,
@@ -194,7 +195,6 @@
.ops = &davinci_vcif_dai_ops,
};
-EXPORT_SYMBOL_GPL(davinci_vcif_dai);
static int davinci_vcif_probe(struct platform_device *pdev)
{
@@ -222,12 +222,9 @@
davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].dma_addr =
davinci_vc->davinci_vcif.dma_rx_addr;
- davinci_vcif_dai.dev = &pdev->dev;
- davinci_vcif_dai.capture.dma_data = davinci_vcif_dev->dma_params;
- davinci_vcif_dai.playback.dma_data = davinci_vcif_dev->dma_params;
- davinci_vcif_dai.private_data = davinci_vcif_dev;
+ dev_set_drvdata(&pdev->dev, davinci_vcif_dev);
- ret = snd_soc_register_dai(&davinci_vcif_dai);
+ ret = snd_soc_register_dai(&pdev->dev, &davinci_vcif_dai);
if (ret != 0) {
dev_err(&pdev->dev, "could not register dai\n");
goto fail;
@@ -243,7 +240,7 @@
static int davinci_vcif_remove(struct platform_device *pdev)
{
- snd_soc_unregister_dai(&davinci_vcif_dai);
+ snd_soc_unregister_dai(&pdev->dev);
return 0;
}
@@ -252,7 +249,7 @@
.probe = davinci_vcif_probe,
.remove = davinci_vcif_remove,
.driver = {
- .name = "davinci_vcif",
+ .name = "davinci-vcif",
.owner = THIS_MODULE,
},
};
diff --git a/sound/soc/davinci/davinci-vcif.h b/sound/soc/davinci/davinci-vcif.h
deleted file mode 100644
index 571c994..0000000
--- a/sound/soc/davinci/davinci-vcif.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * ALSA SoC Voice Codec Interface for TI DAVINCI processor
- *
- * Copyright (C) 2010 Texas Instruments.
- *
- * Author: Miguel Aguilar <miguel.aguilar@ridgerun.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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 _DAVINCI_VCIF_H
-#define _DAVINCI_VCIF_H
-
-extern struct snd_soc_dai davinci_vcif_dai;
-
-#endif
diff --git a/sound/soc/ep93xx/Kconfig b/sound/soc/ep93xx/Kconfig
index f617f56..5742904 100644
--- a/sound/soc/ep93xx/Kconfig
+++ b/sound/soc/ep93xx/Kconfig
@@ -3,11 +3,16 @@
depends on ARCH_EP93XX && SND_SOC
help
Say Y or M if you want to add support for codecs attached to
- the EP93xx I2S interface.
+ the EP93xx I2S or AC97 interfaces.
config SND_EP93XX_SOC_I2S
tristate
+config SND_EP93XX_SOC_AC97
+ tristate
+ select AC97_BUS
+ select SND_SOC_AC97_BUS
+
config SND_EP93XX_SOC_SNAPPERCL15
tristate "SoC Audio support for Bluewater Systems Snapper CL15 module"
depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15
@@ -16,3 +21,12 @@
help
Say Y or M here if you want to add support for I2S audio on the
Bluewater Systems Snapper CL15 module.
+
+config SND_EP93XX_SOC_SIMONE
+ tristate "SoC Audio support for Simplemachines Sim.One board"
+ depends on SND_EP93XX_SOC && MACH_SIM_ONE
+ select SND_EP93XX_SOC_AC97
+ select SND_SOC_AC97_CODEC
+ help
+ Say Y or M here if you want to add support for AC97 audio on the
+ Simplemachines Sim.One board.
diff --git a/sound/soc/ep93xx/Makefile b/sound/soc/ep93xx/Makefile
index 272e60f..8e7977f 100644
--- a/sound/soc/ep93xx/Makefile
+++ b/sound/soc/ep93xx/Makefile
@@ -1,11 +1,15 @@
# EP93xx Platform Support
snd-soc-ep93xx-objs := ep93xx-pcm.o
snd-soc-ep93xx-i2s-objs := ep93xx-i2s.o
+snd-soc-ep93xx-ac97-objs := ep93xx-ac97.o
obj-$(CONFIG_SND_EP93XX_SOC) += snd-soc-ep93xx.o
obj-$(CONFIG_SND_EP93XX_SOC_I2S) += snd-soc-ep93xx-i2s.o
+obj-$(CONFIG_SND_EP93XX_SOC_AC97) += snd-soc-ep93xx-ac97.o
# EP93XX Machine Support
snd-soc-snappercl15-objs := snappercl15.o
+snd-soc-simone-objs := simone.o
obj-$(CONFIG_SND_EP93XX_SOC_SNAPPERCL15) += snd-soc-snappercl15.o
+obj-$(CONFIG_SND_EP93XX_SOC_SIMONE) += snd-soc-simone.o
diff --git a/sound/soc/ep93xx/ep93xx-ac97.c b/sound/soc/ep93xx/ep93xx-ac97.c
new file mode 100644
index 0000000..68a0bae
--- /dev/null
+++ b/sound/soc/ep93xx/ep93xx-ac97.c
@@ -0,0 +1,468 @@
+/*
+ * ASoC driver for Cirrus Logic EP93xx AC97 controller.
+ *
+ * Copyright (c) 2010 Mika Westerberg
+ *
+ * Based on s3c-ac97 ASoC driver by Jaswinder Singh.
+ *
+ * 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/delay.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <sound/core.h>
+#include <sound/ac97_codec.h>
+#include <sound/soc.h>
+
+#include <mach/dma.h>
+#include "ep93xx-pcm.h"
+
+/*
+ * Per channel (1-4) registers.
+ */
+#define AC97CH(n) (((n) - 1) * 0x20)
+
+#define AC97DR(n) (AC97CH(n) + 0x0000)
+
+#define AC97RXCR(n) (AC97CH(n) + 0x0004)
+#define AC97RXCR_REN BIT(0)
+#define AC97RXCR_RX3 BIT(3)
+#define AC97RXCR_RX4 BIT(4)
+#define AC97RXCR_CM BIT(15)
+
+#define AC97TXCR(n) (AC97CH(n) + 0x0008)
+#define AC97TXCR_TEN BIT(0)
+#define AC97TXCR_TX3 BIT(3)
+#define AC97TXCR_TX4 BIT(4)
+#define AC97TXCR_CM BIT(15)
+
+#define AC97SR(n) (AC97CH(n) + 0x000c)
+#define AC97SR_TXFE BIT(1)
+#define AC97SR_TXUE BIT(6)
+
+#define AC97RISR(n) (AC97CH(n) + 0x0010)
+#define AC97ISR(n) (AC97CH(n) + 0x0014)
+#define AC97IE(n) (AC97CH(n) + 0x0018)
+
+/*
+ * Global AC97 controller registers.
+ */
+#define AC97S1DATA 0x0080
+#define AC97S2DATA 0x0084
+#define AC97S12DATA 0x0088
+
+#define AC97RGIS 0x008c
+#define AC97GIS 0x0090
+#define AC97IM 0x0094
+/*
+ * Common bits for RGIS, GIS and IM registers.
+ */
+#define AC97_SLOT2RXVALID BIT(1)
+#define AC97_CODECREADY BIT(5)
+#define AC97_SLOT2TXCOMPLETE BIT(6)
+
+#define AC97EOI 0x0098
+#define AC97EOI_WINT BIT(0)
+#define AC97EOI_CODECREADY BIT(1)
+
+#define AC97GCR 0x009c
+#define AC97GCR_AC97IFE BIT(0)
+
+#define AC97RESET 0x00a0
+#define AC97RESET_TIMEDRESET BIT(0)
+
+#define AC97SYNC 0x00a4
+#define AC97SYNC_TIMEDSYNC BIT(0)
+
+#define AC97_TIMEOUT msecs_to_jiffies(5)
+
+/**
+ * struct ep93xx_ac97_info - EP93xx AC97 controller info structure
+ * @lock: mutex serializing access to the bus (slot 1 & 2 ops)
+ * @dev: pointer to the platform device dev structure
+ * @mem: physical memory resource for the registers
+ * @regs: mapped AC97 controller registers
+ * @irq: AC97 interrupt number
+ * @done: bus ops wait here for an interrupt
+ */
+struct ep93xx_ac97_info {
+ struct mutex lock;
+ struct device *dev;
+ struct resource *mem;
+ void __iomem *regs;
+ int irq;
+ struct completion done;
+};
+
+/* currently ALSA only supports a single AC97 device */
+static struct ep93xx_ac97_info *ep93xx_ac97_info;
+
+static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_out = {
+ .name = "ac97-pcm-out",
+ .dma_port = EP93XX_DMA_M2P_PORT_AAC1,
+};
+
+static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_in = {
+ .name = "ac97-pcm-in",
+ .dma_port = EP93XX_DMA_M2P_PORT_AAC1,
+};
+
+static inline unsigned ep93xx_ac97_read_reg(struct ep93xx_ac97_info *info,
+ unsigned reg)
+{
+ return __raw_readl(info->regs + reg);
+}
+
+static inline void ep93xx_ac97_write_reg(struct ep93xx_ac97_info *info,
+ unsigned reg, unsigned val)
+{
+ __raw_writel(val, info->regs + reg);
+}
+
+static unsigned short ep93xx_ac97_read(struct snd_ac97 *ac97,
+ unsigned short reg)
+{
+ struct ep93xx_ac97_info *info = ep93xx_ac97_info;
+ unsigned short val;
+
+ mutex_lock(&info->lock);
+
+ ep93xx_ac97_write_reg(info, AC97S1DATA, reg);
+ ep93xx_ac97_write_reg(info, AC97IM, AC97_SLOT2RXVALID);
+ if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT)) {
+ dev_warn(info->dev, "timeout reading register %x\n", reg);
+ mutex_unlock(&info->lock);
+ return -ETIMEDOUT;
+ }
+ val = (unsigned short)ep93xx_ac97_read_reg(info, AC97S2DATA);
+
+ mutex_unlock(&info->lock);
+ return val;
+}
+
+static void ep93xx_ac97_write(struct snd_ac97 *ac97,
+ unsigned short reg,
+ unsigned short val)
+{
+ struct ep93xx_ac97_info *info = ep93xx_ac97_info;
+
+ mutex_lock(&info->lock);
+
+ /*
+ * Writes to the codec need to be done so that slot 2 is filled in
+ * before slot 1.
+ */
+ ep93xx_ac97_write_reg(info, AC97S2DATA, val);
+ ep93xx_ac97_write_reg(info, AC97S1DATA, reg);
+
+ ep93xx_ac97_write_reg(info, AC97IM, AC97_SLOT2TXCOMPLETE);
+ if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT))
+ dev_warn(info->dev, "timeout writing register %x\n", reg);
+
+ mutex_unlock(&info->lock);
+}
+
+static void ep93xx_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+ struct ep93xx_ac97_info *info = ep93xx_ac97_info;
+
+ mutex_lock(&info->lock);
+
+ /*
+ * We are assuming that before this functions gets called, the codec
+ * BIT_CLK is stopped by forcing the codec into powerdown mode. We can
+ * control the SYNC signal directly via AC97SYNC register. Using
+ * TIMEDSYNC the controller will keep the SYNC high > 1us.
+ */
+ ep93xx_ac97_write_reg(info, AC97SYNC, AC97SYNC_TIMEDSYNC);
+ ep93xx_ac97_write_reg(info, AC97IM, AC97_CODECREADY);
+ if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT))
+ dev_warn(info->dev, "codec warm reset timeout\n");
+
+ mutex_unlock(&info->lock);
+}
+
+static void ep93xx_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+ struct ep93xx_ac97_info *info = ep93xx_ac97_info;
+
+ mutex_lock(&info->lock);
+
+ /*
+ * For doing cold reset, we disable the AC97 controller interface, clear
+ * WINT and CODECREADY bits, and finally enable the interface again.
+ */
+ ep93xx_ac97_write_reg(info, AC97GCR, 0);
+ ep93xx_ac97_write_reg(info, AC97EOI, AC97EOI_CODECREADY | AC97EOI_WINT);
+ ep93xx_ac97_write_reg(info, AC97GCR, AC97GCR_AC97IFE);
+
+ /*
+ * Now, assert the reset and wait for the codec to become ready.
+ */
+ ep93xx_ac97_write_reg(info, AC97RESET, AC97RESET_TIMEDRESET);
+ ep93xx_ac97_write_reg(info, AC97IM, AC97_CODECREADY);
+ if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT))
+ dev_warn(info->dev, "codec cold reset timeout\n");
+
+ /*
+ * Give the codec some time to come fully out from the reset. This way
+ * we ensure that the subsequent reads/writes will work.
+ */
+ usleep_range(15000, 20000);
+
+ mutex_unlock(&info->lock);
+}
+
+static irqreturn_t ep93xx_ac97_interrupt(int irq, void *dev_id)
+{
+ struct ep93xx_ac97_info *info = dev_id;
+ unsigned status, mask;
+
+ /*
+ * Just mask out the interrupt and wake up the waiting thread.
+ * Interrupts are cleared via reading/writing to slot 1 & 2 registers by
+ * the waiting thread.
+ */
+ status = ep93xx_ac97_read_reg(info, AC97GIS);
+ mask = ep93xx_ac97_read_reg(info, AC97IM);
+ mask &= ~status;
+ ep93xx_ac97_write_reg(info, AC97IM, mask);
+
+ complete(&info->done);
+ return IRQ_HANDLED;
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+ .read = ep93xx_ac97_read,
+ .write = ep93xx_ac97_write,
+ .reset = ep93xx_ac97_cold_reset,
+ .warm_reset = ep93xx_ac97_warm_reset,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct ep93xx_ac97_info *info = snd_soc_dai_get_drvdata(dai);
+ unsigned v = 0;
+
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ /*
+ * Enable compact mode, TX slots 3 & 4, and the TX FIFO
+ * itself.
+ */
+ v |= AC97TXCR_CM;
+ v |= AC97TXCR_TX3 | AC97TXCR_TX4;
+ v |= AC97TXCR_TEN;
+ ep93xx_ac97_write_reg(info, AC97TXCR(1), v);
+ } else {
+ /*
+ * Enable compact mode, RX slots 3 & 4, and the RX FIFO
+ * itself.
+ */
+ v |= AC97RXCR_CM;
+ v |= AC97RXCR_RX3 | AC97RXCR_RX4;
+ v |= AC97RXCR_REN;
+ ep93xx_ac97_write_reg(info, AC97RXCR(1), v);
+ }
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ /*
+ * As per Cirrus EP93xx errata described below:
+ *
+ * http://www.cirrus.com/en/pubs/errata/ER667E2B.pdf
+ *
+ * we will wait for the TX FIFO to be empty before
+ * clearing the TEN bit.
+ */
+ unsigned long timeout = jiffies + AC97_TIMEOUT;
+
+ do {
+ v = ep93xx_ac97_read_reg(info, AC97SR(1));
+ if (time_after(jiffies, timeout)) {
+ dev_warn(info->dev, "TX timeout\n");
+ break;
+ }
+ } while (!(v & (AC97SR_TXFE | AC97SR_TXUE)));
+
+ /* disable the TX FIFO */
+ ep93xx_ac97_write_reg(info, AC97TXCR(1), 0);
+ } else {
+ /* disable the RX FIFO */
+ ep93xx_ac97_write_reg(info, AC97RXCR(1), 0);
+ }
+ break;
+
+ default:
+ dev_warn(info->dev, "unknown command %d\n", cmd);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ep93xx_ac97_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct ep93xx_pcm_dma_params *dma_data;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dma_data = &ep93xx_ac97_pcm_out;
+ else
+ dma_data = &ep93xx_ac97_pcm_in;
+
+ snd_soc_dai_set_dma_data(dai, substream, dma_data);
+ return 0;
+}
+
+static struct snd_soc_dai_ops ep93xx_ac97_dai_ops = {
+ .startup = ep93xx_ac97_startup,
+ .trigger = ep93xx_ac97_trigger,
+};
+
+struct snd_soc_dai_driver ep93xx_ac97_dai = {
+ .name = "ep93xx-ac97",
+ .id = 0,
+ .ac97_control = 1,
+ .playback = {
+ .stream_name = "AC97 Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .stream_name = "AC97 Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &ep93xx_ac97_dai_ops,
+};
+
+static int __devinit ep93xx_ac97_probe(struct platform_device *pdev)
+{
+ struct ep93xx_ac97_info *info;
+ int ret;
+
+ info = kzalloc(sizeof(struct ep93xx_ac97_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ dev_set_drvdata(&pdev->dev, info);
+
+ mutex_init(&info->lock);
+ init_completion(&info->done);
+ info->dev = &pdev->dev;
+
+ info->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!info->mem) {
+ ret = -ENXIO;
+ goto fail_free_info;
+ }
+
+ info->irq = platform_get_irq(pdev, 0);
+ if (!info->irq) {
+ ret = -ENXIO;
+ goto fail_free_info;
+ }
+
+ if (!request_mem_region(info->mem->start, resource_size(info->mem),
+ pdev->name)) {
+ ret = -EBUSY;
+ goto fail_free_info;
+ }
+
+ info->regs = ioremap(info->mem->start, resource_size(info->mem));
+ if (!info->regs) {
+ ret = -ENOMEM;
+ goto fail_release_mem;
+ }
+
+ ret = request_irq(info->irq, ep93xx_ac97_interrupt, IRQF_TRIGGER_HIGH,
+ pdev->name, info);
+ if (ret)
+ goto fail_unmap_mem;
+
+ ep93xx_ac97_info = info;
+ platform_set_drvdata(pdev, info);
+
+ ret = snd_soc_register_dai(&pdev->dev, &ep93xx_ac97_dai);
+ if (ret)
+ goto fail_free_irq;
+
+ return 0;
+
+fail_free_irq:
+ platform_set_drvdata(pdev, NULL);
+ free_irq(info->irq, info);
+fail_unmap_mem:
+ iounmap(info->regs);
+fail_release_mem:
+ release_mem_region(info->mem->start, resource_size(info->mem));
+fail_free_info:
+ kfree(info);
+
+ return ret;
+}
+
+static int __devexit ep93xx_ac97_remove(struct platform_device *pdev)
+{
+ struct ep93xx_ac97_info *info = platform_get_drvdata(pdev);
+
+ snd_soc_unregister_dai(&pdev->dev);
+
+ /* disable the AC97 controller */
+ ep93xx_ac97_write_reg(info, AC97GCR, 0);
+
+ free_irq(info->irq, info);
+ iounmap(info->regs);
+ release_mem_region(info->mem->start, resource_size(info->mem));
+ platform_set_drvdata(pdev, NULL);
+ kfree(info);
+
+ return 0;
+}
+
+static struct platform_driver ep93xx_ac97_driver = {
+ .probe = ep93xx_ac97_probe,
+ .remove = __devexit_p(ep93xx_ac97_remove),
+ .driver = {
+ .name = "ep93xx-ac97",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ep93xx_ac97_init(void)
+{
+ return platform_driver_register(&ep93xx_ac97_driver);
+}
+module_init(ep93xx_ac97_init);
+
+static void __exit ep93xx_ac97_exit(void)
+{
+ platform_driver_unregister(&ep93xx_ac97_driver);
+}
+module_exit(ep93xx_ac97_exit);
+
+MODULE_DESCRIPTION("EP93xx AC97 ASoC Driver");
+MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ep93xx-ac97");
diff --git a/sound/soc/ep93xx/ep93xx-i2s.c b/sound/soc/ep93xx/ep93xx-i2s.c
index 00b9466..4f48733 100644
--- a/sound/soc/ep93xx/ep93xx-i2s.c
+++ b/sound/soc/ep93xx/ep93xx-i2s.c
@@ -31,7 +31,6 @@
#include <mach/dma.h>
#include "ep93xx-pcm.h"
-#include "ep93xx-i2s.h"
#define EP93XX_I2S_TXCLKCFG 0x00
#define EP93XX_I2S_RXCLKCFG 0x04
@@ -145,8 +144,8 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct ep93xx_i2s_info *info = rtd->dai->cpu_dai->private_data;
+ struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
snd_soc_dai_set_dma_data(cpu_dai, substream,
&info->dma_params[substream->stream]);
@@ -156,8 +155,7 @@
static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct ep93xx_i2s_info *info = rtd->dai->cpu_dai->private_data;
+ struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
ep93xx_i2s_disable(info, substream->stream);
}
@@ -165,7 +163,7 @@
static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
- struct ep93xx_i2s_info *info = cpu_dai->private_data;
+ struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(cpu_dai);
unsigned int clk_cfg, lin_ctrl;
clk_cfg = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXCLKCFG);
@@ -242,9 +240,7 @@
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct ep93xx_i2s_info *info = cpu_dai->private_data;
+ struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
unsigned word_len, div, sdiv, lrdiv;
int found = 0, err;
@@ -302,7 +298,7 @@
static int ep93xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
unsigned int freq, int dir)
{
- struct ep93xx_i2s_info *info = cpu_dai->private_data;
+ struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(cpu_dai);
if (dir == SND_SOC_CLOCK_IN || clk_id != 0)
return -EINVAL;
@@ -313,7 +309,7 @@
#ifdef CONFIG_PM
static int ep93xx_i2s_suspend(struct snd_soc_dai *dai)
{
- struct ep93xx_i2s_info *info = dai->private_data;
+ struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
if (!dai->active)
return;
@@ -324,7 +320,7 @@
static int ep93xx_i2s_resume(struct snd_soc_dai *dai)
{
- struct ep93xx_i2s_info *info = dai->private_data;
+ struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
if (!dai->active)
return;
@@ -349,9 +345,7 @@
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
-struct snd_soc_dai ep93xx_i2s_dai = {
- .name = "ep93xx-i2s",
- .id = 0,
+static struct snd_soc_dai_driver ep93xx_i2s_dai = {
.symmetric_rates= 1,
.suspend = ep93xx_i2s_suspend,
.resume = ep93xx_i2s_resume,
@@ -369,7 +363,6 @@
},
.ops = &ep93xx_i2s_dai_ops,
};
-EXPORT_SYMBOL_GPL(ep93xx_i2s_dai);
static int ep93xx_i2s_probe(struct platform_device *pdev)
{
@@ -383,8 +376,7 @@
goto fail;
}
- ep93xx_i2s_dai.dev = &pdev->dev;
- ep93xx_i2s_dai.private_data = info;
+ dev_set_drvdata(&pdev->dev, info);
info->dma_params = ep93xx_i2s_dma_params;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -424,7 +416,7 @@
goto fail_put_sclk;
}
- err = snd_soc_register_dai(&ep93xx_i2s_dai);
+ err = snd_soc_register_dai(&pdev->dev, &ep93xx_i2s_dai);
if (err)
goto fail_put_lrclk;
@@ -447,9 +439,9 @@
static int __devexit ep93xx_i2s_remove(struct platform_device *pdev)
{
- struct ep93xx_i2s_info *info = ep93xx_i2s_dai.private_data;
+ struct ep93xx_i2s_info *info = dev_get_drvdata(&pdev->dev);
- snd_soc_unregister_dai(&ep93xx_i2s_dai);
+ snd_soc_unregister_dai(&pdev->dev);
clk_put(info->lrclk);
clk_put(info->sclk);
clk_put(info->mclk);
diff --git a/sound/soc/ep93xx/ep93xx-i2s.h b/sound/soc/ep93xx/ep93xx-i2s.h
deleted file mode 100644
index 3bd4ebf..0000000
--- a/sound/soc/ep93xx/ep93xx-i2s.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * linux/sound/soc/ep93xx-i2s.h
- * EP93xx I2S driver
- *
- * Copyright (C) 2010 Ryan Mallon <ryan@bluewatersys.com>
- *
- * 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 _EP93XX_SND_SOC_I2S_H
-#define _EP93XX_SND_SOC_I2S_H
-
-extern struct snd_soc_dai ep93xx_i2s_dai;
-
-#endif /* _EP93XX_SND_SOC_I2S_H */
diff --git a/sound/soc/ep93xx/ep93xx-pcm.c b/sound/soc/ep93xx/ep93xx-pcm.c
index 4ba9384..2f121dd 100644
--- a/sound/soc/ep93xx/ep93xx-pcm.c
+++ b/sound/soc/ep93xx/ep93xx-pcm.c
@@ -95,7 +95,7 @@
static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *soc_rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = soc_rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = soc_rtd->cpu_dai;
struct ep93xx_pcm_dma_params *dma_params;
struct ep93xx_runtime_data *rtd;
int ret;
@@ -276,14 +276,14 @@
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = 0xffffffff;
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
return ret;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
@@ -293,22 +293,41 @@
return 0;
}
-struct snd_soc_platform ep93xx_soc_platform = {
- .name = "ep93xx-audio",
- .pcm_ops = &ep93xx_pcm_ops,
+static struct snd_soc_platform_driver ep93xx_soc_platform = {
+ .ops = &ep93xx_pcm_ops,
.pcm_new = &ep93xx_pcm_new,
.pcm_free = &ep93xx_pcm_free_dma_buffers,
};
-EXPORT_SYMBOL_GPL(ep93xx_soc_platform);
+
+static int __devinit ep93xx_soc_platform_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_platform(&pdev->dev, &ep93xx_soc_platform);
+}
+
+static int __devexit ep93xx_soc_platform_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver ep93xx_pcm_driver = {
+ .driver = {
+ .name = "ep93xx-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = ep93xx_soc_platform_probe,
+ .remove = __devexit_p(ep93xx_soc_platform_remove),
+};
static int __init ep93xx_soc_platform_init(void)
{
- return snd_soc_register_platform(&ep93xx_soc_platform);
+ return platform_driver_register(&ep93xx_pcm_driver);
}
static void __exit ep93xx_soc_platform_exit(void)
{
- snd_soc_unregister_platform(&ep93xx_soc_platform);
+ platform_driver_unregister(&ep93xx_pcm_driver);
}
module_init(ep93xx_soc_platform_init);
diff --git a/sound/soc/ep93xx/ep93xx-pcm.h b/sound/soc/ep93xx/ep93xx-pcm.h
index 4ffdd3f..111e112 100644
--- a/sound/soc/ep93xx/ep93xx-pcm.h
+++ b/sound/soc/ep93xx/ep93xx-pcm.h
@@ -17,6 +17,4 @@
int dma_port;
};
-extern struct snd_soc_platform ep93xx_soc_platform;
-
#endif /* _EP93XX_SND_SOC_PCM_H */
diff --git a/sound/soc/ep93xx/simone.c b/sound/soc/ep93xx/simone.c
new file mode 100644
index 0000000..4b0d199
--- /dev/null
+++ b/sound/soc/ep93xx/simone.c
@@ -0,0 +1,89 @@
+/*
+ * simone.c -- ASoC audio for Simplemachines Sim.One board
+ *
+ * Copyright (c) 2010 Mika Westerberg
+ *
+ * Based on snappercl15 machine driver by Ryan Mallon.
+ *
+ * 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/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+
+#include "ep93xx-pcm.h"
+
+static struct snd_soc_dai_link simone_dai = {
+ .name = "AC97",
+ .stream_name = "AC97 HiFi",
+ .cpu_dai_name = "ep93xx-ac97",
+ .codec_dai_name = "ac97-hifi",
+ .codec_name = "ac97-codec",
+ .platform_name = "ep93xx-pcm-audio",
+};
+
+static struct snd_soc_card snd_soc_simone = {
+ .name = "Sim.One",
+ .dai_link = &simone_dai,
+ .num_links = 1,
+};
+
+static struct platform_device *simone_snd_ac97_device;
+static struct platform_device *simone_snd_device;
+
+static int __init simone_init(void)
+{
+ int ret;
+
+ if (!machine_is_sim_one())
+ return -ENODEV;
+
+ simone_snd_ac97_device = platform_device_alloc("ac97-codec", -1);
+ if (!simone_snd_ac97_device)
+ return -ENOMEM;
+
+ ret = platform_device_add(simone_snd_ac97_device);
+ if (ret)
+ goto fail;
+
+ simone_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!simone_snd_device) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ platform_set_drvdata(simone_snd_device, &snd_soc_simone);
+ ret = platform_device_add(simone_snd_device);
+ if (ret) {
+ platform_device_put(simone_snd_device);
+ goto fail;
+ }
+
+ return ret;
+
+fail:
+ platform_device_put(simone_snd_ac97_device);
+ return ret;
+}
+module_init(simone_init);
+
+static void __exit simone_exit(void)
+{
+ platform_device_unregister(simone_snd_device);
+ platform_device_unregister(simone_snd_ac97_device);
+}
+module_exit(simone_exit);
+
+MODULE_DESCRIPTION("ALSA SoC Simplemachines Sim.One");
+MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ep93xx/snappercl15.c b/sound/soc/ep93xx/snappercl15.c
index 64955340..28ab5ff 100644
--- a/sound/soc/ep93xx/snappercl15.c
+++ b/sound/soc/ep93xx/snappercl15.c
@@ -22,7 +22,6 @@
#include "../codecs/tlv320aic23.h"
#include "ep93xx-pcm.h"
-#include "ep93xx-i2s.h"
#define CODEC_CLOCK 5644800
@@ -30,8 +29,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int err;
err = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
@@ -77,8 +76,10 @@
{"MICIN", NULL, "Mic Jack"},
};
-static int snappercl15_tlv320aic23_init(struct snd_soc_codec *codec)
+static int snappercl15_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
ARRAY_SIZE(tlv320aic23_dapm_widgets));
@@ -89,24 +90,20 @@
static struct snd_soc_dai_link snappercl15_dai = {
.name = "tlv320aic23",
.stream_name = "AIC23",
- .cpu_dai = &ep93xx_i2s_dai,
- .codec_dai = &tlv320aic23_dai,
+ .cpu_dai_name = "ep93xx-i2s",
+ .codec_dai_name = "tlv320aic23-hifi",
+ .codec_name = "tlv320aic23-codec.0-001a",
+ .platform_name = "ep93xx-pcm-audio",
.init = snappercl15_tlv320aic23_init,
.ops = &snappercl15_ops,
};
static struct snd_soc_card snd_soc_snappercl15 = {
.name = "Snapper CL15",
- .platform = &ep93xx_soc_platform,
.dai_link = &snappercl15_dai,
.num_links = 1,
};
-static struct snd_soc_device snappercl15_snd_devdata = {
- .card = &snd_soc_snappercl15,
- .codec_dev = &soc_codec_dev_tlv320aic23,
-};
-
static struct platform_device *snappercl15_snd_device;
static int __init snappercl15_init(void)
@@ -126,8 +123,7 @@
if (!snappercl15_snd_device)
return -ENOMEM;
- platform_set_drvdata(snappercl15_snd_device, &snappercl15_snd_devdata);
- snappercl15_snd_devdata.dev = &snappercl15_snd_device->dev;
+ platform_set_drvdata(snappercl15_snd_device, &snd_soc_snappercl15);
ret = platform_device_add(snappercl15_snd_device);
if (ret)
platform_device_put(snappercl15_snd_device);
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 8cb65cc..d754d34 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -1,27 +1,36 @@
-config SND_SOC_OF_SIMPLE
- tristate
-
config SND_MPC52xx_DMA
tristate
-# ASoC platform support for the Freescale MPC8610 SOC. This compiles drivers
-# for the SSI and the Elo DMA controller. You will still need to select
-# a platform driver and a codec driver.
-config SND_SOC_MPC8610
+# ASoC platform support for the Freescale PowerPC SOCs that have an SSI and
+# an Elo DMA controller, such as the MPC8610 and P1022. You will still need to
+# select a platform driver and a codec driver.
+config SND_SOC_POWERPC_SSI
tristate
- depends on MPC8610
+ depends on FSL_SOC
config SND_SOC_MPC8610_HPCD
tristate "ALSA SoC support for the Freescale MPC8610 HPCD board"
# I2C is necessary for the CS4270 driver
depends on MPC8610_HPCD && I2C
- select SND_SOC_MPC8610
+ select SND_SOC_POWERPC_SSI
select SND_SOC_CS4270
select SND_SOC_CS4270_VD33_ERRATA
default y if MPC8610_HPCD
help
Say Y if you want to enable audio on the Freescale MPC8610 HPCD.
+config SND_SOC_P1022_DS
+ tristate "ALSA SoC support for the Freescale P1022 DS board"
+ # I2C is necessary for the WM8776 driver
+ depends on P1022_DS && I2C
+ select SND_SOC_POWERPC_SSI
+ select SND_SOC_WM8776
+ default y if P1022_DS
+ help
+ Say Y if you want to enable audio on the Freescale P1022 DS board.
+ This will also include the Wolfson Microelectronics WM8776 codec
+ driver.
+
config SND_SOC_MPC5200_I2S
tristate "Freescale MPC5200 PSC in I2S mode driver"
depends on PPC_MPC52xx && PPC_BESTCOMM
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index a83a739..b4a38c0 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -1,14 +1,15 @@
-# Simple machine driver that extracts configuration from the OF device tree
-obj-$(CONFIG_SND_SOC_OF_SIMPLE) += soc-of-simple.o
-
# MPC8610 HPCD Machine Support
snd-soc-mpc8610-hpcd-objs := mpc8610_hpcd.o
obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += snd-soc-mpc8610-hpcd.o
-# MPC8610 Platform Support
+# P1022 DS Machine Support
+snd-soc-p1022-ds-objs := p1022_ds.o
+obj-$(CONFIG_SND_SOC_P1022_DS) += snd-soc-p1022-ds.o
+
+# Freescale PowerPC SSI/DMA Platform Support
snd-soc-fsl-ssi-objs := fsl_ssi.o
snd-soc-fsl-dma-objs := fsl_dma.o
-obj-$(CONFIG_SND_SOC_MPC8610) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o
+obj-$(CONFIG_SND_SOC_POWERPC_SSI) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o
# MPC5200 Platform Support
obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
diff --git a/sound/soc/fsl/efika-audio-fabric.c b/sound/soc/fsl/efika-audio-fabric.c
index 1a5b8e0..53251e6 100644
--- a/sound/soc/fsl/efika-audio-fabric.c
+++ b/sound/soc/fsl/efika-audio-fabric.c
@@ -24,7 +24,6 @@
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include <sound/soc.h>
-#include <sound/soc-of-simple.h>
#include "mpc5200_dma.h"
#include "mpc5200_psc_ac97.h"
@@ -32,21 +31,24 @@
#define DRV_NAME "efika-audio-fabric"
-static struct snd_soc_device device;
static struct snd_soc_card card;
static struct snd_soc_dai_link efika_fabric_dai[] = {
{
.name = "AC97",
.stream_name = "AC97 Analog",
- .codec_dai = &stac9766_dai[STAC9766_DAI_AC97_ANALOG],
- .cpu_dai = &psc_ac97_dai[MPC5200_AC97_NORMAL],
+ .codec_dai_name = "stac9766-hifi-analog",
+ .cpu_dai_name = "mpc5200-psc-ac97.0",
+ .platform_name = "mpc5200-pcm-audio",
+ .codec_name = "stac9766-codec",
},
{
.name = "AC97",
.stream_name = "AC97 IEC958",
- .codec_dai = &stac9766_dai[STAC9766_DAI_AC97_DIGITAL],
- .cpu_dai = &psc_ac97_dai[MPC5200_AC97_SPDIF],
+ .codec_dai_name = "stac9766-hifi-IEC958",
+ .cpu_dai_name = "mpc5200-psc-ac97.1",
+ .platform_name = "mpc5200-pcm-audio",
+ .codec_name = "stac9766-codec",
},
};
@@ -58,13 +60,10 @@
if (!of_machine_is_compatible("bplan,efika"))
return -ENODEV;
- card.platform = &mpc5200_audio_dma_platform;
card.name = "Efika";
card.dai_link = efika_fabric_dai;
card.num_links = ARRAY_SIZE(efika_fabric_dai);
- device.card = &card;
- device.codec_dev = &soc_codec_dev_stac9766;
pdev = platform_device_alloc("soc-audio", 1);
if (!pdev) {
@@ -72,8 +71,7 @@
return -ENODEV;
}
- platform_set_drvdata(pdev, &device);
- device.dev = &pdev->dev;
+ platform_set_drvdata(pdev, &card);
rc = platform_device_add(pdev);
if (rc) {
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index 410c749..4cf98c0 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -3,10 +3,11 @@
*
* Author: Timur Tabi <timur@freescale.com>
*
- * Copyright 2007-2008 Freescale Semiconductor, Inc. This file is licensed
- * under the terms of the GNU General Public License version 2. This
- * program is licensed "as is" without any warranty of any kind, whether
- * express or implied.
+ * Copyright 2007-2010 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
*
* This driver implements ASoC support for the Elo DMA controller, which is
* the DMA controller on Freescale 83xx, 85xx, and 86xx SOCs. In ALSA terms,
@@ -20,6 +21,9 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/gfp.h>
+#include <linux/of_platform.h>
+#include <linux/list.h>
+#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -29,6 +33,7 @@
#include <asm/io.h>
#include "fsl_dma.h"
+#include "fsl_ssi.h" /* For the offset of stx0 and srx0 */
/*
* The formats that the DMA controller supports, which is anything
@@ -52,26 +57,16 @@
#define FSLDMA_PCM_RATES (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_192000 | \
SNDRV_PCM_RATE_CONTINUOUS)
-/* DMA global data. This structure is used by fsl_dma_open() to determine
- * which DMA channels to assign to a substream. Unfortunately, ASoC V1 does
- * not allow the machine driver to provide this information to the PCM
- * driver in advance, and there's no way to differentiate between the two
- * DMA controllers. So for now, this driver only supports one SSI device
- * using two DMA channels. We cannot support multiple DMA devices.
- *
- * ssi_stx_phys: bus address of SSI STX register
- * ssi_srx_phys: bus address of SSI SRX register
- * dma_channel: pointer to the DMA channel's registers
- * irq: IRQ for this DMA channel
- * assigned: set to 1 if that DMA channel is assigned to a substream
- */
-static struct {
+struct dma_object {
+ struct snd_soc_platform_driver dai;
dma_addr_t ssi_stx_phys;
dma_addr_t ssi_srx_phys;
- struct ccsr_dma_channel __iomem *dma_channel[2];
- unsigned int irq[2];
- unsigned int assigned[2];
-} dma_global_data;
+ unsigned int ssi_fifo_depth;
+ struct ccsr_dma_channel __iomem *channel;
+ unsigned int irq;
+ bool assigned;
+ char path[1];
+};
/*
* The number of DMA links to use. Two is the bare minimum, but if you
@@ -88,8 +83,6 @@
* structure.
*
* @link[]: array of link descriptors
- * @controller_id: which DMA controller (0, 1, ...)
- * @channel_id: which DMA channel on the controller (0, 1, 2, ...)
* @dma_channel: pointer to the DMA channel's registers
* @irq: IRQ for this DMA channel
* @substream: pointer to the substream object, needed by the ISR
@@ -104,12 +97,11 @@
*/
struct fsl_dma_private {
struct fsl_dma_link_descriptor link[NUM_DMA_LINKS];
- unsigned int controller_id;
- unsigned int channel_id;
struct ccsr_dma_channel __iomem *dma_channel;
unsigned int irq;
struct snd_pcm_substream *substream;
dma_addr_t ssi_sxx_phys;
+ unsigned int ssi_fifo_depth;
dma_addr_t ld_buf_phys;
unsigned int current_link;
dma_addr_t dma_buf_phys;
@@ -185,13 +177,23 @@
struct fsl_dma_link_descriptor *link =
&dma_private->link[dma_private->current_link];
- /* Update our link descriptors to point to the next period */
- if (dma_private->substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- link->source_addr =
- cpu_to_be32(dma_private->dma_buf_next);
- else
- link->dest_addr =
- cpu_to_be32(dma_private->dma_buf_next);
+ /* Update our link descriptors to point to the next period. On a 36-bit
+ * system, we also need to update the ESAD bits. We also set (keep) the
+ * snoop bits. See the comments in fsl_dma_hw_params() about snooping.
+ */
+ if (dma_private->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ link->source_addr = cpu_to_be32(dma_private->dma_buf_next);
+#ifdef CONFIG_PHYS_64BIT
+ link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP |
+ upper_32_bits(dma_private->dma_buf_next));
+#endif
+ } else {
+ link->dest_addr = cpu_to_be32(dma_private->dma_buf_next);
+#ifdef CONFIG_PHYS_64BIT
+ link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP |
+ upper_32_bits(dma_private->dma_buf_next));
+#endif
+ }
/* Update our variables for next time */
dma_private->dma_buf_next += dma_private->period_size;
@@ -212,6 +214,9 @@
static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
{
struct fsl_dma_private *dma_private = dev_id;
+ struct snd_pcm_substream *substream = dma_private->substream;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct device *dev = rtd->platform->dev;
struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
irqreturn_t ret = IRQ_NONE;
u32 sr, sr2 = 0;
@@ -222,11 +227,8 @@
sr = in_be32(&dma_channel->sr);
if (sr & CCSR_DMA_SR_TE) {
- dev_err(dma_private->substream->pcm->card->dev,
- "DMA transmit error (controller=%u channel=%u irq=%u\n",
- dma_private->controller_id,
- dma_private->channel_id, irq);
- fsl_dma_abort_stream(dma_private->substream);
+ dev_err(dev, "dma transmit error\n");
+ fsl_dma_abort_stream(substream);
sr2 |= CCSR_DMA_SR_TE;
ret = IRQ_HANDLED;
}
@@ -235,11 +237,8 @@
ret = IRQ_HANDLED;
if (sr & CCSR_DMA_SR_PE) {
- dev_err(dma_private->substream->pcm->card->dev,
- "DMA%u programming error (channel=%u irq=%u)\n",
- dma_private->controller_id,
- dma_private->channel_id, irq);
- fsl_dma_abort_stream(dma_private->substream);
+ dev_err(dev, "dma programming error\n");
+ fsl_dma_abort_stream(substream);
sr2 |= CCSR_DMA_SR_PE;
ret = IRQ_HANDLED;
}
@@ -253,8 +252,6 @@
ret = IRQ_HANDLED;
if (sr & CCSR_DMA_SR_EOSI) {
- struct snd_pcm_substream *substream = dma_private->substream;
-
/* Tell ALSA we completed a period. */
snd_pcm_period_elapsed(substream);
@@ -288,11 +285,19 @@
* This function is called when the codec driver calls snd_soc_new_pcms(),
* once for each .dai_link in the machine driver's snd_soc_card
* structure.
+ *
+ * snd_dma_alloc_pages() is just a front-end to dma_alloc_coherent(), which
+ * (currently) always allocates the DMA buffer in lowmem, even if GFP_HIGHMEM
+ * is specified. Therefore, any DMA buffers we allocate will always be in low
+ * memory, but we support for 36-bit physical addresses anyway.
+ *
+ * Regardless of where the memory is actually allocated, since the device can
+ * technically DMA to any 36-bit address, we do need to set the DMA mask to 36.
*/
static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
struct snd_pcm *pcm)
{
- static u64 fsl_dma_dmamask = DMA_BIT_MASK(32);
+ static u64 fsl_dma_dmamask = DMA_BIT_MASK(36);
int ret;
if (!card->dev->dma_mask)
@@ -301,25 +306,29 @@
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = fsl_dma_dmamask;
- ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
- fsl_dma_hardware.buffer_bytes_max,
- &pcm->streams[0].substream->dma_buffer);
- if (ret) {
- dev_err(card->dev,
- "Can't allocate playback DMA buffer (size=%u)\n",
- fsl_dma_hardware.buffer_bytes_max);
- return -ENOMEM;
+ /* Some codecs have separate DAIs for playback and capture, so we
+ * should allocate a DMA buffer only for the streams that are valid.
+ */
+
+ if (dai->driver->playback.channels_min) {
+ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
+ fsl_dma_hardware.buffer_bytes_max,
+ &pcm->streams[0].substream->dma_buffer);
+ if (ret) {
+ dev_err(card->dev, "can't alloc playback dma buffer\n");
+ return ret;
+ }
}
- ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
- fsl_dma_hardware.buffer_bytes_max,
- &pcm->streams[1].substream->dma_buffer);
- if (ret) {
- snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
- dev_err(card->dev,
- "Can't allocate capture DMA buffer (size=%u)\n",
- fsl_dma_hardware.buffer_bytes_max);
- return -ENOMEM;
+ if (dai->driver->capture.channels_min) {
+ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
+ fsl_dma_hardware.buffer_bytes_max,
+ &pcm->streams[1].substream->dma_buffer);
+ if (ret) {
+ snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
+ dev_err(card->dev, "can't alloc capture dma buffer\n");
+ return ret;
+ }
}
return 0;
@@ -390,6 +399,10 @@
static int fsl_dma_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct device *dev = rtd->platform->dev;
+ struct dma_object *dma =
+ container_of(rtd->platform->driver, struct dma_object, dai);
struct fsl_dma_private *dma_private;
struct ccsr_dma_channel __iomem *dma_channel;
dma_addr_t ld_buf_phys;
@@ -407,52 +420,45 @@
ret = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0) {
- dev_err(substream->pcm->card->dev, "invalid buffer size\n");
+ dev_err(dev, "invalid buffer size\n");
return ret;
}
channel = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
- if (dma_global_data.assigned[channel]) {
- dev_err(substream->pcm->card->dev,
- "DMA channel already assigned\n");
+ if (dma->assigned) {
+ dev_err(dev, "dma channel already assigned\n");
return -EBUSY;
}
- dma_private = dma_alloc_coherent(substream->pcm->card->dev,
- sizeof(struct fsl_dma_private), &ld_buf_phys, GFP_KERNEL);
+ dma_private = dma_alloc_coherent(dev, sizeof(struct fsl_dma_private),
+ &ld_buf_phys, GFP_KERNEL);
if (!dma_private) {
- dev_err(substream->pcm->card->dev,
- "can't allocate DMA private data\n");
+ dev_err(dev, "can't allocate dma private data\n");
return -ENOMEM;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- dma_private->ssi_sxx_phys = dma_global_data.ssi_stx_phys;
+ dma_private->ssi_sxx_phys = dma->ssi_stx_phys;
else
- dma_private->ssi_sxx_phys = dma_global_data.ssi_srx_phys;
+ dma_private->ssi_sxx_phys = dma->ssi_srx_phys;
- dma_private->dma_channel = dma_global_data.dma_channel[channel];
- dma_private->irq = dma_global_data.irq[channel];
+ dma_private->ssi_fifo_depth = dma->ssi_fifo_depth;
+ dma_private->dma_channel = dma->channel;
+ dma_private->irq = dma->irq;
dma_private->substream = substream;
dma_private->ld_buf_phys = ld_buf_phys;
dma_private->dma_buf_phys = substream->dma_buffer.addr;
- /* We only support one DMA controller for now */
- dma_private->controller_id = 0;
- dma_private->channel_id = channel;
-
ret = request_irq(dma_private->irq, fsl_dma_isr, 0, "DMA", dma_private);
if (ret) {
- dev_err(substream->pcm->card->dev,
- "can't register ISR for IRQ %u (ret=%i)\n",
+ dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
dma_private->irq, ret);
- dma_free_coherent(substream->pcm->card->dev,
- sizeof(struct fsl_dma_private),
+ dma_free_coherent(dev, sizeof(struct fsl_dma_private),
dma_private, dma_private->ld_buf_phys);
return ret;
}
- dma_global_data.assigned[channel] = 1;
+ dma->assigned = 1;
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
snd_soc_set_runtime_hwparams(substream, &fsl_dma_hardware);
@@ -546,13 +552,15 @@
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct fsl_dma_private *dma_private = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct device *dev = rtd->platform->dev;
/* Number of bits per sample */
- unsigned int sample_size =
+ unsigned int sample_bits =
snd_pcm_format_physical_width(params_format(hw_params));
/* Number of bytes per frame */
- unsigned int frame_size = 2 * (sample_size / 8);
+ unsigned int sample_bytes = sample_bits / 8;
/* Bus address of SSI STX register */
dma_addr_t ssi_sxx_phys = dma_private->ssi_sxx_phys;
@@ -592,7 +600,7 @@
* that offset here. While we're at it, also tell the DMA controller
* how much data to transfer per sample.
*/
- switch (sample_size) {
+ switch (sample_bits) {
case 8:
mr |= CCSR_DMA_MR_DAHTS_1 | CCSR_DMA_MR_SAHTS_1;
ssi_sxx_phys += 3;
@@ -606,23 +614,42 @@
break;
default:
/* We should never get here */
- dev_err(substream->pcm->card->dev,
- "unsupported sample size %u\n", sample_size);
+ dev_err(dev, "unsupported sample size %u\n", sample_bits);
return -EINVAL;
}
/*
- * BWC should always be a multiple of the frame size. BWC determines
- * how many bytes are sent/received before the DMA controller checks the
- * SSI to see if it needs to stop. For playback, the transmit FIFO can
- * hold three frames, so we want to send two frames at a time. For
- * capture, the receive FIFO is triggered when it contains one frame, so
- * we want to receive one frame at a time.
+ * BWC determines how many bytes are sent/received before the DMA
+ * controller checks the SSI to see if it needs to stop. BWC should
+ * always be a multiple of the frame size, so that we always transmit
+ * whole frames. Each frame occupies two slots in the FIFO. The
+ * parameter for CCSR_DMA_MR_BWC() is rounded down the next power of two
+ * (MR[BWC] can only represent even powers of two).
+ *
+ * To simplify the process, we set BWC to the largest value that is
+ * less than or equal to the FIFO watermark. For playback, this ensures
+ * that we transfer the maximum amount without overrunning the FIFO.
+ * For capture, this ensures that we transfer the maximum amount without
+ * underrunning the FIFO.
+ *
+ * f = SSI FIFO depth
+ * w = SSI watermark value (which equals f - 2)
+ * b = DMA bandwidth count (in bytes)
+ * s = sample size (in bytes, which equals frame_size * 2)
+ *
+ * For playback, we never transmit more than the transmit FIFO
+ * watermark, otherwise we might write more data than the FIFO can hold.
+ * The watermark is equal to the FIFO depth minus two.
+ *
+ * For capture, two equations must hold:
+ * w > f - (b / s)
+ * w >= b / s
+ *
+ * So, b > 2 * s, but b must also be <= s * w. To simplify, we set
+ * b = s * w, which is equal to
+ * (dma_private->ssi_fifo_depth - 2) * sample_bytes.
*/
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- mr |= CCSR_DMA_MR_BWC(2 * frame_size);
- else
- mr |= CCSR_DMA_MR_BWC(frame_size);
+ mr |= CCSR_DMA_MR_BWC((dma_private->ssi_fifo_depth - 2) * sample_bytes);
out_be32(&dma_channel->mr, mr);
@@ -631,12 +658,7 @@
link->count = cpu_to_be32(period_size);
- /* Even though the DMA controller supports 36-bit addressing,
- * for simplicity we allow only 32-bit addresses for the audio
- * buffer itself. This was enforced in fsl_dma_new() with the
- * DMA mask.
- *
- * The snoop bit tells the DMA controller whether it should tell
+ /* The snoop bit tells the DMA controller whether it should tell
* the ECM to snoop during a read or write to an address. For
* audio, we use DMA to transfer data between memory and an I/O
* device (the SSI's STX0 or SRX0 register). Snooping is only
@@ -651,20 +673,24 @@
* flush out the data for the previous period. So if you
* increased period_bytes_min to a large enough size, you might
* get more performance by not snooping, and you'll still be
- * okay.
+ * okay. You'll need to update fsl_dma_update_pointers() also.
*/
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
link->source_addr = cpu_to_be32(temp_addr);
- link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP);
+ link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP |
+ upper_32_bits(temp_addr));
link->dest_addr = cpu_to_be32(ssi_sxx_phys);
- link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP);
+ link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP |
+ upper_32_bits(ssi_sxx_phys));
} else {
link->source_addr = cpu_to_be32(ssi_sxx_phys);
- link->source_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP);
+ link->source_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP |
+ upper_32_bits(ssi_sxx_phys));
link->dest_addr = cpu_to_be32(temp_addr);
- link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP);
+ link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP |
+ upper_32_bits(temp_addr));
}
temp_addr += period_size;
@@ -689,14 +715,29 @@
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct fsl_dma_private *dma_private = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct device *dev = rtd->platform->dev;
struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
dma_addr_t position;
snd_pcm_uframes_t frames;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ /* Obtain the current DMA pointer, but don't read the ESAD bits if we
+ * only have 32-bit DMA addresses. This function is typically called
+ * in interrupt context, so we need to optimize it.
+ */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
position = in_be32(&dma_channel->sar);
- else
+#ifdef CONFIG_PHYS_64BIT
+ position |= (u64)(in_be32(&dma_channel->satr) &
+ CCSR_DMA_ATR_ESAD_MASK) << 32;
+#endif
+ } else {
position = in_be32(&dma_channel->dar);
+#ifdef CONFIG_PHYS_64BIT
+ position |= (u64)(in_be32(&dma_channel->datr) &
+ CCSR_DMA_ATR_ESAD_MASK) << 32;
+#endif
+ }
/*
* When capture is started, the SSI immediately starts to fill its FIFO.
@@ -710,8 +751,7 @@
if ((position < dma_private->dma_buf_phys) ||
(position > dma_private->dma_buf_end)) {
- dev_err(substream->pcm->card->dev,
- "dma pointer is out of range, halting stream\n");
+ dev_err(dev, "dma pointer is out of range, halting stream\n");
return SNDRV_PCM_POS_XRUN;
}
@@ -772,26 +812,28 @@
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct fsl_dma_private *dma_private = runtime->private_data;
- int dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct device *dev = rtd->platform->dev;
+ struct dma_object *dma =
+ container_of(rtd->platform->driver, struct dma_object, dai);
if (dma_private) {
if (dma_private->irq)
free_irq(dma_private->irq, dma_private);
if (dma_private->ld_buf_phys) {
- dma_unmap_single(substream->pcm->card->dev,
- dma_private->ld_buf_phys,
- sizeof(dma_private->link), DMA_TO_DEVICE);
+ dma_unmap_single(dev, dma_private->ld_buf_phys,
+ sizeof(dma_private->link),
+ DMA_TO_DEVICE);
}
/* Deallocate the fsl_dma_private structure */
- dma_free_coherent(substream->pcm->card->dev,
- sizeof(struct fsl_dma_private),
- dma_private, dma_private->ld_buf_phys);
+ dma_free_coherent(dev, sizeof(struct fsl_dma_private),
+ dma_private, dma_private->ld_buf_phys);
substream->runtime->private_data = NULL;
}
- dma_global_data.assigned[dir] = 0;
+ dma->assigned = 0;
return 0;
}
@@ -814,6 +856,37 @@
}
}
+/**
+ * find_ssi_node -- returns the SSI node that points to his DMA channel node
+ *
+ * Although this DMA driver attempts to operate independently of the other
+ * devices, it still needs to determine some information about the SSI device
+ * that it's working with. Unfortunately, the device tree does not contain
+ * a pointer from the DMA channel node to the SSI node -- the pointer goes the
+ * other way. So we need to scan the device tree for SSI nodes until we find
+ * the one that points to the given DMA channel node. It's ugly, but at least
+ * it's contained in this one function.
+ */
+static struct device_node *find_ssi_node(struct device_node *dma_channel_np)
+{
+ struct device_node *ssi_np, *np;
+
+ for_each_compatible_node(ssi_np, NULL, "fsl,mpc8610-ssi") {
+ /* Check each DMA phandle to see if it points to us. We
+ * assume that device_node pointers are a valid comparison.
+ */
+ np = of_parse_phandle(ssi_np, "fsl,playback-dma", 0);
+ if (np == dma_channel_np)
+ return ssi_np;
+
+ np = of_parse_phandle(ssi_np, "fsl,capture-dma", 0);
+ if (np == dma_channel_np)
+ return ssi_np;
+ }
+
+ return NULL;
+}
+
static struct snd_pcm_ops fsl_dma_ops = {
.open = fsl_dma_open,
.close = fsl_dma_close,
@@ -823,59 +896,114 @@
.pointer = fsl_dma_pointer,
};
-struct snd_soc_platform fsl_soc_platform = {
- .name = "fsl-dma",
- .pcm_ops = &fsl_dma_ops,
- .pcm_new = fsl_dma_new,
- .pcm_free = fsl_dma_free_dma_buffers,
+static int __devinit fsl_soc_dma_probe(struct platform_device *pdev,
+ const struct of_device_id *match)
+ {
+ struct dma_object *dma;
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *ssi_np;
+ struct resource res;
+ const uint32_t *iprop;
+ int ret;
+
+ /* Find the SSI node that points to us. */
+ ssi_np = find_ssi_node(np);
+ if (!ssi_np) {
+ dev_err(&pdev->dev, "cannot find parent SSI node\n");
+ return -ENODEV;
+ }
+
+ ret = of_address_to_resource(ssi_np, 0, &res);
+ if (ret) {
+ dev_err(&pdev->dev, "could not determine resources for %s\n",
+ ssi_np->full_name);
+ of_node_put(ssi_np);
+ return ret;
+ }
+
+ dma = kzalloc(sizeof(*dma) + strlen(np->full_name), GFP_KERNEL);
+ if (!dma) {
+ dev_err(&pdev->dev, "could not allocate dma object\n");
+ of_node_put(ssi_np);
+ return -ENOMEM;
+ }
+
+ strcpy(dma->path, np->full_name);
+ dma->dai.ops = &fsl_dma_ops;
+ dma->dai.pcm_new = fsl_dma_new;
+ dma->dai.pcm_free = fsl_dma_free_dma_buffers;
+
+ /* Store the SSI-specific information that we need */
+ dma->ssi_stx_phys = res.start + offsetof(struct ccsr_ssi, stx0);
+ dma->ssi_srx_phys = res.start + offsetof(struct ccsr_ssi, srx0);
+
+ iprop = of_get_property(ssi_np, "fsl,fifo-depth", NULL);
+ if (iprop)
+ dma->ssi_fifo_depth = *iprop;
+ else
+ /* Older 8610 DTs didn't have the fifo-depth property */
+ dma->ssi_fifo_depth = 8;
+
+ of_node_put(ssi_np);
+
+ ret = snd_soc_register_platform(&pdev->dev, &dma->dai);
+ if (ret) {
+ dev_err(&pdev->dev, "could not register platform\n");
+ kfree(dma);
+ return ret;
+ }
+
+ dma->channel = of_iomap(np, 0);
+ dma->irq = irq_of_parse_and_map(np, 0);
+
+ dev_set_drvdata(&pdev->dev, dma);
+
+ return 0;
+}
+
+static int __devexit fsl_soc_dma_remove(struct platform_device *pdev)
+{
+ struct dma_object *dma = dev_get_drvdata(&pdev->dev);
+
+ snd_soc_unregister_platform(&pdev->dev);
+ iounmap(dma->channel);
+ irq_dispose_mapping(dma->irq);
+ kfree(dma);
+
+ return 0;
+}
+
+static const struct of_device_id fsl_soc_dma_ids[] = {
+ { .compatible = "fsl,ssi-dma-channel", },
+ {}
};
-EXPORT_SYMBOL_GPL(fsl_soc_platform);
+MODULE_DEVICE_TABLE(of, fsl_soc_dma_ids);
-/**
- * fsl_dma_configure: store the DMA parameters from the fabric driver.
- *
- * This function is called by the ASoC fabric driver to give us the DMA and
- * SSI channel information.
- *
- * Unfortunately, ASoC V1 does make it possible to determine the DMA/SSI
- * data when a substream is created, so for now we need to store this data
- * into a global variable. This means that we can only support one DMA
- * controller, and hence only one SSI.
- */
-int fsl_dma_configure(struct fsl_dma_info *dma_info)
+static struct of_platform_driver fsl_soc_dma_driver = {
+ .driver = {
+ .name = "fsl-pcm-audio",
+ .owner = THIS_MODULE,
+ .of_match_table = fsl_soc_dma_ids,
+ },
+ .probe = fsl_soc_dma_probe,
+ .remove = __devexit_p(fsl_soc_dma_remove),
+};
+
+static int __init fsl_soc_dma_init(void)
{
- static int initialized;
+ pr_info("Freescale Elo DMA ASoC PCM Driver\n");
- /* We only support one DMA controller for now */
- if (initialized)
- return 0;
-
- dma_global_data.ssi_stx_phys = dma_info->ssi_stx_phys;
- dma_global_data.ssi_srx_phys = dma_info->ssi_srx_phys;
- dma_global_data.dma_channel[0] = dma_info->dma_channel[0];
- dma_global_data.dma_channel[1] = dma_info->dma_channel[1];
- dma_global_data.irq[0] = dma_info->dma_irq[0];
- dma_global_data.irq[1] = dma_info->dma_irq[1];
- dma_global_data.assigned[0] = 0;
- dma_global_data.assigned[1] = 0;
-
- initialized = 1;
- return 1;
+ return of_register_platform_driver(&fsl_soc_dma_driver);
}
-EXPORT_SYMBOL_GPL(fsl_dma_configure);
-static int __init fsl_soc_platform_init(void)
+static void __exit fsl_soc_dma_exit(void)
{
- return snd_soc_register_platform(&fsl_soc_platform);
+ of_unregister_platform_driver(&fsl_soc_dma_driver);
}
-module_init(fsl_soc_platform_init);
-static void __exit fsl_soc_platform_exit(void)
-{
- snd_soc_unregister_platform(&fsl_soc_platform);
-}
-module_exit(fsl_soc_platform_exit);
+module_init(fsl_soc_dma_init);
+module_exit(fsl_soc_dma_exit);
MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
-MODULE_DESCRIPTION("Freescale Elo DMA ASoC PCM module");
-MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Freescale Elo DMA ASoC PCM Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/fsl_dma.h b/sound/soc/fsl/fsl_dma.h
index 385d4a4..78fee97 100644
--- a/sound/soc/fsl/fsl_dma.h
+++ b/sound/soc/fsl/fsl_dma.h
@@ -126,24 +126,4 @@
u8 res[4]; /* Reserved */
} __attribute__ ((aligned(32), packed));
-/* DMA information needed to create a snd_soc_dai object
- *
- * ssi_stx_phys: bus address of SSI STX register to use
- * ssi_srx_phys: bus address of SSI SRX register to use
- * dma[0]: points to the DMA channel to use for playback
- * dma[1]: points to the DMA channel to use for capture
- * dma_irq[0]: IRQ of the DMA channel to use for playback
- * dma_irq[1]: IRQ of the DMA channel to use for capture
- */
-struct fsl_dma_info {
- dma_addr_t ssi_stx_phys;
- dma_addr_t ssi_srx_phys;
- struct ccsr_dma_channel __iomem *dma_channel[2];
- unsigned int dma_irq[2];
-};
-
-extern struct snd_soc_platform fsl_soc_platform;
-
-int fsl_dma_configure(struct fsl_dma_info *dma_info);
-
#endif
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 762c1b8..4cc167a 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -3,10 +3,11 @@
*
* Author: Timur Tabi <timur@freescale.com>
*
- * Copyright 2007-2008 Freescale Semiconductor, Inc. This file is licensed
- * under the terms of the GNU General Public License version 2. This
- * program is licensed "as is" without any warranty of any kind, whether
- * express or implied.
+ * Copyright 2007-2010 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
*/
#include <linux/init.h>
@@ -15,6 +16,7 @@
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/of_platform.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -22,8 +24,6 @@
#include <sound/initval.h>
#include <sound/soc.h>
-#include <asm/immap_86xx.h>
-
#include "fsl_ssi.h"
/**
@@ -71,33 +71,32 @@
/**
* fsl_ssi_private: per-SSI private data
*
- * @name: short name for this device ("SSI0", "SSI1", etc)
* @ssi: pointer to the SSI's registers
* @ssi_phys: physical address of the SSI registers
* @irq: IRQ of this SSI
* @first_stream: pointer to the stream that was opened first
* @second_stream: pointer to second stream
- * @dev: struct device pointer
* @playback: the number of playback streams opened
* @capture: the number of capture streams opened
* @asynchronous: 0=synchronous mode, 1=asynchronous mode
* @cpu_dai: the CPU DAI for this device
* @dev_attr: the sysfs device attribute structure
* @stats: SSI statistics
+ * @name: name for this device
*/
struct fsl_ssi_private {
- char name[8];
struct ccsr_ssi __iomem *ssi;
dma_addr_t ssi_phys;
unsigned int irq;
struct snd_pcm_substream *first_stream;
struct snd_pcm_substream *second_stream;
- struct device *dev;
unsigned int playback;
unsigned int capture;
int asynchronous;
- struct snd_soc_dai cpu_dai;
+ unsigned int fifo_depth;
+ struct snd_soc_dai_driver cpu_dai_drv;
struct device_attribute dev_attr;
+ struct platform_device *pdev;
struct {
unsigned int rfrc;
@@ -122,6 +121,8 @@
unsigned int tfe1;
unsigned int tfe0;
} stats;
+
+ char name[1];
};
/**
@@ -280,7 +281,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
+ struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
/*
* If this is the first stream opened, then request the IRQ
@@ -290,6 +291,7 @@
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
int ret;
+ /* The 'name' should not have any slashes in it. */
ret = request_irq(ssi_private->irq, fsl_ssi_isr, 0,
ssi_private->name, ssi_private);
if (ret < 0) {
@@ -336,11 +338,20 @@
/*
* Set the watermark for transmit FIFI 0 and receive FIFO 0. We
- * don't use FIFO 1. Since the SSI only supports stereo, the
- * watermark should never be an odd number.
+ * don't use FIFO 1. We program the transmit water to signal a
+ * DMA transfer if there are only two (or fewer) elements left
+ * in the FIFO. Two elements equals one frame (left channel,
+ * right channel). This value, however, depends on the depth of
+ * the transmit buffer.
+ *
+ * We program the receive FIFO to notify us if at least two
+ * elements (one frame) have been written to the FIFO. We could
+ * make this value larger (and maybe we should), but this way
+ * data will be written to memory as soon as it's available.
*/
out_be32(&ssi->sfcsr,
- CCSR_SSI_SFCSR_TFWM0(6) | CCSR_SSI_SFCSR_RFWM0(2));
+ CCSR_SSI_SFCSR_TFWM0(ssi_private->fifo_depth - 2) |
+ CCSR_SSI_SFCSR_RFWM0(ssi_private->fifo_depth - 2));
/*
* We keep the SSI disabled because if we enable it, then the
@@ -422,7 +433,7 @@
static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *cpu_dai)
{
- struct fsl_ssi_private *ssi_private = cpu_dai->private_data;
+ struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
if (substream == ssi_private->first_stream) {
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
@@ -458,7 +469,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
+ struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
switch (cmd) {
@@ -497,7 +508,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
+ struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
ssi_private->playback--;
@@ -523,56 +534,15 @@
}
}
-/**
- * fsl_ssi_set_sysclk: set the clock frequency and direction
- *
- * This function is called by the machine driver to tell us what the clock
- * frequency and direction are.
- *
- * Currently, we only support operating as a clock slave (SND_SOC_CLOCK_IN),
- * and we don't care about the frequency. Return an error if the direction
- * is not SND_SOC_CLOCK_IN.
- *
- * @clk_id: reserved, should be zero
- * @freq: the frequency of the given clock ID, currently ignored
- * @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master)
- */
-static int fsl_ssi_set_sysclk(struct snd_soc_dai *cpu_dai,
- int clk_id, unsigned int freq, int dir)
-{
-
- return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL;
-}
-
-/**
- * fsl_ssi_set_fmt: set the serial format.
- *
- * This function is called by the machine driver to tell us what serial
- * format to use.
- *
- * Currently, we only support I2S mode. Return an error if the format is
- * not SND_SOC_DAIFMT_I2S.
- *
- * @format: one of SND_SOC_DAIFMT_xxx
- */
-static int fsl_ssi_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
-{
- return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL;
-}
-
-/**
- * fsl_ssi_dai_template: template CPU DAI for the SSI
- */
static struct snd_soc_dai_ops fsl_ssi_dai_ops = {
.startup = fsl_ssi_startup,
.hw_params = fsl_ssi_hw_params,
.shutdown = fsl_ssi_shutdown,
.trigger = fsl_ssi_trigger,
- .set_sysclk = fsl_ssi_set_sysclk,
- .set_fmt = fsl_ssi_set_fmt,
};
-static struct snd_soc_dai fsl_ssi_dai_template = {
+/* Template for the CPU dai driver structure */
+static struct snd_soc_dai_driver fsl_ssi_dai_template = {
.playback = {
/* The SSI does not support monaural audio. */
.channels_min = 2,
@@ -640,95 +610,195 @@
}
/**
- * fsl_ssi_create_dai: create a snd_soc_dai structure
- *
- * This function is called by the machine driver to create a snd_soc_dai
- * structure. The function creates an ssi_private object, which contains
- * the snd_soc_dai. It also creates the sysfs statistics device.
+ * Make every character in a string lower-case
*/
-struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info)
+static void make_lowercase(char *s)
{
- struct snd_soc_dai *fsl_ssi_dai;
+ char *p = s;
+ char c;
+
+ while ((c = *p)) {
+ if ((c >= 'A') && (c <= 'Z'))
+ *p = c + ('a' - 'A');
+ p++;
+ }
+}
+
+static int __devinit fsl_ssi_probe(struct platform_device *pdev,
+ const struct of_device_id *match)
+{
struct fsl_ssi_private *ssi_private;
int ret = 0;
- struct device_attribute *dev_attr;
+ struct device_attribute *dev_attr = NULL;
+ struct device_node *np = pdev->dev.of_node;
+ const char *p, *sprop;
+ const uint32_t *iprop;
+ struct resource res;
+ char name[64];
- ssi_private = kzalloc(sizeof(struct fsl_ssi_private), GFP_KERNEL);
- if (!ssi_private) {
- dev_err(ssi_info->dev, "could not allocate DAI object\n");
- return NULL;
+ /* SSIs that are not connected on the board should have a
+ * status = "disabled"
+ * property in their device tree nodes.
+ */
+ if (!of_device_is_available(np))
+ return -ENODEV;
+
+ /* Check for a codec-handle property. */
+ if (!of_get_property(np, "codec-handle", NULL)) {
+ dev_err(&pdev->dev, "missing codec-handle property\n");
+ return -ENODEV;
}
- memcpy(&ssi_private->cpu_dai, &fsl_ssi_dai_template,
- sizeof(struct snd_soc_dai));
- fsl_ssi_dai = &ssi_private->cpu_dai;
- dev_attr = &ssi_private->dev_attr;
+ /* We only support the SSI in "I2S Slave" mode */
+ sprop = of_get_property(np, "fsl,mode", NULL);
+ if (!sprop || strcmp(sprop, "i2s-slave")) {
+ dev_notice(&pdev->dev, "mode %s is unsupported\n", sprop);
+ return -ENODEV;
+ }
- sprintf(ssi_private->name, "ssi%u", (u8) ssi_info->id);
- ssi_private->ssi = ssi_info->ssi;
- ssi_private->ssi_phys = ssi_info->ssi_phys;
- ssi_private->irq = ssi_info->irq;
- ssi_private->dev = ssi_info->dev;
- ssi_private->asynchronous = ssi_info->asynchronous;
+ /* The DAI name is the last part of the full name of the node. */
+ p = strrchr(np->full_name, '/') + 1;
+ ssi_private = kzalloc(sizeof(struct fsl_ssi_private) + strlen(p),
+ GFP_KERNEL);
+ if (!ssi_private) {
+ dev_err(&pdev->dev, "could not allocate DAI object\n");
+ return -ENOMEM;
+ }
- dev_set_drvdata(ssi_private->dev, fsl_ssi_dai);
+ strcpy(ssi_private->name, p);
+
+ /* Initialize this copy of the CPU DAI driver structure */
+ memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template,
+ sizeof(fsl_ssi_dai_template));
+ ssi_private->cpu_dai_drv.name = ssi_private->name;
+
+ /* Get the addresses and IRQ */
+ ret = of_address_to_resource(np, 0, &res);
+ if (ret) {
+ dev_err(&pdev->dev, "could not determine device resources\n");
+ kfree(ssi_private);
+ return ret;
+ }
+ ssi_private->ssi = ioremap(res.start, 1 + res.end - res.start);
+ ssi_private->ssi_phys = res.start;
+ ssi_private->irq = irq_of_parse_and_map(np, 0);
+
+ /* Are the RX and the TX clocks locked? */
+ if (of_find_property(np, "fsl,ssi-asynchronous", NULL))
+ ssi_private->asynchronous = 1;
+ else
+ ssi_private->cpu_dai_drv.symmetric_rates = 1;
+
+ /* Determine the FIFO depth. */
+ iprop = of_get_property(np, "fsl,fifo-depth", NULL);
+ if (iprop)
+ ssi_private->fifo_depth = *iprop;
+ else
+ /* Older 8610 DTs didn't have the fifo-depth property */
+ ssi_private->fifo_depth = 8;
/* Initialize the the device_attribute structure */
- dev_attr->attr.name = "ssi-stats";
+ dev_attr = &ssi_private->dev_attr;
+ dev_attr->attr.name = "statistics";
dev_attr->attr.mode = S_IRUGO;
dev_attr->show = fsl_sysfs_ssi_show;
- ret = device_create_file(ssi_private->dev, dev_attr);
+ ret = device_create_file(&pdev->dev, dev_attr);
if (ret) {
- dev_err(ssi_info->dev, "could not create sysfs %s file\n",
+ dev_err(&pdev->dev, "could not create sysfs %s file\n",
ssi_private->dev_attr.attr.name);
- kfree(fsl_ssi_dai);
- return NULL;
+ goto error;
}
- fsl_ssi_dai->private_data = ssi_private;
- fsl_ssi_dai->name = ssi_private->name;
- fsl_ssi_dai->id = ssi_info->id;
- fsl_ssi_dai->dev = ssi_info->dev;
- fsl_ssi_dai->symmetric_rates = 1;
+ /* Register with ASoC */
+ dev_set_drvdata(&pdev->dev, ssi_private);
- ret = snd_soc_register_dai(fsl_ssi_dai);
- if (ret != 0) {
- dev_err(ssi_info->dev, "failed to register DAI: %d\n", ret);
- kfree(fsl_ssi_dai);
- return NULL;
+ ret = snd_soc_register_dai(&pdev->dev, &ssi_private->cpu_dai_drv);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
+ goto error;
}
- return fsl_ssi_dai;
+ /* Trigger the machine driver's probe function. The platform driver
+ * name of the machine driver is taken from the /model property of the
+ * device tree. We also pass the address of the CPU DAI driver
+ * structure.
+ */
+ sprop = of_get_property(of_find_node_by_path("/"), "model", NULL);
+ /* Sometimes the model name has a "fsl," prefix, so we strip that. */
+ p = strrchr(sprop, ',');
+ if (p)
+ sprop = p + 1;
+ snprintf(name, sizeof(name), "snd-soc-%s", sprop);
+ make_lowercase(name);
+
+ ssi_private->pdev =
+ platform_device_register_data(&pdev->dev, name, 0, NULL, 0);
+ if (IS_ERR(ssi_private->pdev)) {
+ ret = PTR_ERR(ssi_private->pdev);
+ dev_err(&pdev->dev, "failed to register platform: %d\n", ret);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ snd_soc_unregister_dai(&pdev->dev);
+ dev_set_drvdata(&pdev->dev, NULL);
+ if (dev_attr)
+ device_remove_file(&pdev->dev, dev_attr);
+ irq_dispose_mapping(ssi_private->irq);
+ iounmap(ssi_private->ssi);
+ kfree(ssi_private);
+
+ return ret;
}
-EXPORT_SYMBOL_GPL(fsl_ssi_create_dai);
-/**
- * fsl_ssi_destroy_dai: destroy the snd_soc_dai object
- *
- * This function undoes the operations of fsl_ssi_create_dai()
- */
-void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai)
+static int fsl_ssi_remove(struct platform_device *pdev)
{
- struct fsl_ssi_private *ssi_private =
- container_of(fsl_ssi_dai, struct fsl_ssi_private, cpu_dai);
+ struct fsl_ssi_private *ssi_private = dev_get_drvdata(&pdev->dev);
- device_remove_file(ssi_private->dev, &ssi_private->dev_attr);
-
- snd_soc_unregister_dai(&ssi_private->cpu_dai);
+ platform_device_unregister(ssi_private->pdev);
+ snd_soc_unregister_dai(&pdev->dev);
+ device_remove_file(&pdev->dev, &ssi_private->dev_attr);
kfree(ssi_private);
+ dev_set_drvdata(&pdev->dev, NULL);
+
+ return 0;
}
-EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai);
+
+static const struct of_device_id fsl_ssi_ids[] = {
+ { .compatible = "fsl,mpc8610-ssi", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, fsl_ssi_ids);
+
+static struct of_platform_driver fsl_ssi_driver = {
+ .driver = {
+ .name = "fsl-ssi-dai",
+ .owner = THIS_MODULE,
+ .of_match_table = fsl_ssi_ids,
+ },
+ .probe = fsl_ssi_probe,
+ .remove = fsl_ssi_remove,
+};
static int __init fsl_ssi_init(void)
{
printk(KERN_INFO "Freescale Synchronous Serial Interface (SSI) ASoC Driver\n");
- return 0;
+ return of_register_platform_driver(&fsl_ssi_driver);
}
+
+static void __exit fsl_ssi_exit(void)
+{
+ of_unregister_platform_driver(&fsl_ssi_driver);
+}
+
module_init(fsl_ssi_init);
+module_exit(fsl_ssi_exit);
MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h
index eade01f..2173000 100644
--- a/sound/soc/fsl/fsl_ssi.h
+++ b/sound/soc/fsl/fsl_ssi.h
@@ -196,31 +196,5 @@
#define CCSR_SSI_SOR_WAIT(x) (((x) & 3) << CCSR_SSI_SOR_WAIT_SHIFT)
#define CCSR_SSI_SOR_SYNRST 0x00000001
-/* Instantiation data for an SSI interface
- *
- * This structure contains all the information that the the SSI driver needs
- * to instantiate an SSI interface with ALSA. The machine driver should
- * create this structure, fill it in, call fsl_ssi_create_dai(), and then
- * delete the structure.
- *
- * id: which SSI this is (0, 1, etc. )
- * ssi: pointer to the SSI's registers
- * ssi_phys: physical address of the SSI registers
- * irq: IRQ of this SSI
- * dev: struct device, used to create the sysfs statistics file
- * asynchronous: 0=synchronous mode, 1=asynchronous mode
-*/
-struct fsl_ssi_info {
- unsigned int id;
- struct ccsr_ssi __iomem *ssi;
- dma_addr_t ssi_phys;
- unsigned int irq;
- struct device *dev;
- int asynchronous;
-};
-
-struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info);
-void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai);
-
#endif
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
index 3dcd146..dce6b55 100644
--- a/sound/soc/fsl/mpc5200_dma.c
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -9,6 +9,8 @@
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
#include <sound/soc.h>
@@ -107,7 +109,7 @@
static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
struct snd_pcm_runtime *runtime = substream->runtime;
struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
@@ -212,7 +214,7 @@
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
struct psc_dma_stream *s;
int rc;
@@ -239,7 +241,7 @@
static int psc_dma_close(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
struct psc_dma_stream *s;
dev_dbg(psc_dma->dev, "psc_dma_close(substream=%p)\n", substream);
@@ -264,7 +266,7 @@
psc_dma_pointer(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
struct psc_dma_stream *s;
dma_addr_t count;
@@ -302,11 +304,11 @@
struct snd_pcm *pcm)
{
struct snd_soc_pcm_runtime *rtd = pcm->private_data;
- struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
size_t size = psc_dma_hardware.buffer_bytes_max;
int rc = 0;
- dev_dbg(rtd->socdev->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n",
+ dev_dbg(rtd->platform->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n",
card, dai, pcm);
if (!card->dev->dma_mask)
@@ -328,8 +330,8 @@
goto capture_alloc_err;
}
- if (rtd->socdev->card->codec->ac97)
- rtd->socdev->card->codec->ac97->private_data = psc_dma;
+ if (rtd->codec->ac97)
+ rtd->codec->ac97->private_data = psc_dma;
return 0;
@@ -349,7 +351,7 @@
struct snd_pcm_substream *substream;
int stream;
- dev_dbg(rtd->socdev->dev, "psc_dma_free(pcm=%p)\n", pcm);
+ dev_dbg(rtd->platform->dev, "psc_dma_free(pcm=%p)\n", pcm);
for (stream = 0; stream < 2; stream++) {
substream = pcm->streams[stream].substream;
@@ -361,15 +363,14 @@
}
}
-struct snd_soc_platform mpc5200_audio_dma_platform = {
- .name = "mpc5200-psc-audio",
- .pcm_ops = &psc_dma_ops,
+static struct snd_soc_platform_driver mpc5200_audio_dma_platform = {
+ .ops = &psc_dma_ops,
.pcm_new = &psc_dma_new,
.pcm_free = &psc_dma_free,
};
-EXPORT_SYMBOL_GPL(mpc5200_audio_dma_platform);
-int mpc5200_audio_dma_create(struct platform_device *op)
+static int mpc5200_hpcd_probe(struct of_device *op,
+ const struct of_device_id *match)
{
phys_addr_t fifo;
struct psc_dma *psc_dma;
@@ -475,7 +476,7 @@
dev_set_drvdata(&op->dev, psc_dma);
/* Tell the ASoC OF helpers about it */
- return snd_soc_register_platform(&mpc5200_audio_dma_platform);
+ return snd_soc_register_platform(&op->dev, &mpc5200_audio_dma_platform);
out_irq:
free_irq(psc_dma->irq, psc_dma);
free_irq(psc_dma->capture.irq, &psc_dma->capture);
@@ -486,15 +487,14 @@
iounmap(regs);
return ret;
}
-EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create);
-int mpc5200_audio_dma_destroy(struct platform_device *op)
+static int mpc5200_hpcd_remove(struct of_device *op)
{
struct psc_dma *psc_dma = dev_get_drvdata(&op->dev);
dev_dbg(&op->dev, "mpc5200_audio_dma_destroy()\n");
- snd_soc_unregister_platform(&mpc5200_audio_dma_platform);
+ snd_soc_unregister_platform(&op->dev);
bcom_gen_bd_rx_release(psc_dma->capture.bcom_task);
bcom_gen_bd_tx_release(psc_dma->playback.bcom_task);
@@ -510,7 +510,35 @@
return 0;
}
-EXPORT_SYMBOL_GPL(mpc5200_audio_dma_destroy);
+
+static struct of_device_id mpc5200_hpcd_match[] = {
+ {
+ .compatible = "fsl,mpc5200-pcm",
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mpc5200_hpcd_match);
+
+static struct of_platform_driver mpc5200_hpcd_of_driver = {
+ .owner = THIS_MODULE,
+ .name = "mpc5200-pcm-audio",
+ .match_table = mpc5200_hpcd_match,
+ .probe = mpc5200_hpcd_probe,
+ .remove = mpc5200_hpcd_remove,
+};
+
+static int __init mpc5200_hpcd_init(void)
+{
+ return of_register_platform_driver(&mpc5200_hpcd_of_driver);
+}
+
+static void __exit mpc5200_hpcd_exit(void)
+{
+ of_unregister_platform_driver(&mpc5200_hpcd_of_driver);
+}
+
+module_init(mpc5200_hpcd_init);
+module_exit(mpc5200_hpcd_exit);
MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
MODULE_DESCRIPTION("Freescale MPC5200 PSC in DMA mode ASoC Driver");
diff --git a/sound/soc/fsl/mpc5200_dma.h b/sound/soc/fsl/mpc5200_dma.h
index ca99586..a3c0cd5 100644
--- a/sound/soc/fsl/mpc5200_dma.h
+++ b/sound/soc/fsl/mpc5200_dma.h
@@ -81,9 +81,4 @@
return &psc_dma->playback;
}
-int mpc5200_audio_dma_create(struct platform_device *op);
-int mpc5200_audio_dma_destroy(struct platform_device *op);
-
-extern struct snd_soc_platform mpc5200_audio_dma_platform;
-
#endif /* __SOUND_SOC_FSL_MPC5200_DMA_H__ */
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
index a956023..40acc8e 100644
--- a/sound/soc/fsl/mpc5200_psc_ac97.c
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -143,7 +143,7 @@
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
- struct psc_dma *psc_dma = cpu_dai->private_data;
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
@@ -166,7 +166,7 @@
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
- struct psc_dma *psc_dma = cpu_dai->private_data;
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
dev_dbg(psc_dma->dev, "%s(substream=%p)\n", __func__, substream);
@@ -181,8 +181,7 @@
static int psc_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(dai);
struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
switch (cmd) {
@@ -207,10 +206,9 @@
return 0;
}
-static int psc_ac97_probe(struct platform_device *pdev,
- struct snd_soc_dai *cpu_dai)
+static int psc_ac97_probe(struct snd_soc_dai *cpu_dai)
{
- struct psc_dma *psc_dma = cpu_dai->private_data;
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
/* Go */
@@ -237,9 +235,8 @@
.hw_params = psc_ac97_hw_digital_params,
};
-struct snd_soc_dai psc_ac97_dai[] = {
+static struct snd_soc_dai_driver psc_ac97_dai[] = {
{
- .name = "AC97",
.ac97_control = 1,
.probe = psc_ac97_probe,
.playback = {
@@ -257,7 +254,6 @@
.ops = &psc_ac97_analog_ops,
},
{
- .name = "SPDIF",
.ac97_control = 1,
.playback = {
.channels_min = 1,
@@ -268,7 +264,6 @@
},
.ops = &psc_ac97_digital_ops,
} };
-EXPORT_SYMBOL_GPL(psc_ac97_dai);
@@ -280,18 +275,11 @@
static int __devinit psc_ac97_of_probe(struct platform_device *op,
const struct of_device_id *match)
{
- int rc, i;
+ int rc;
struct snd_ac97 ac97;
struct mpc52xx_psc __iomem *regs;
- rc = mpc5200_audio_dma_create(op);
- if (rc != 0)
- return rc;
-
- for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++)
- psc_ac97_dai[i].dev = &op->dev;
-
- rc = snd_soc_register_dais(psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
+ rc = snd_soc_register_dais(&op->dev, psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
if (rc != 0) {
dev_err(&op->dev, "Failed to register DAI\n");
return rc;
@@ -301,9 +289,6 @@
regs = psc_dma->psc_regs;
ac97.private_data = psc_dma;
- for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++)
- psc_ac97_dai[i].private_data = psc_dma;
-
psc_dma->imr = 0;
out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);
@@ -319,7 +304,8 @@
static int __devexit psc_ac97_of_remove(struct platform_device *op)
{
- return mpc5200_audio_dma_destroy(op);
+ snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_ac97_dai));
+ return 0;
}
/* Match table for of_platform binding */
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.h b/sound/soc/fsl/mpc5200_psc_ac97.h
index 4bc18c3..e881e78 100644
--- a/sound/soc/fsl/mpc5200_psc_ac97.h
+++ b/sound/soc/fsl/mpc5200_psc_ac97.h
@@ -7,8 +7,6 @@
#ifndef __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__
#define __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__
-extern struct snd_soc_dai psc_ac97_dai[];
-
#define MPC5200_AC97_NORMAL 0
#define MPC5200_AC97_SPDIF 1
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c
index 534f04c..74ffed4 100644
--- a/sound/soc/fsl/mpc5200_psc_i2s.c
+++ b/sound/soc/fsl/mpc5200_psc_i2s.c
@@ -40,7 +40,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
u32 mode;
dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
@@ -88,7 +88,7 @@
static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
{
- struct psc_dma *psc_dma = cpu_dai->private_data;
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
dev_dbg(psc_dma->dev, "psc_i2s_set_sysclk(cpu_dai=%p, dir=%i)\n",
cpu_dai, dir);
return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL;
@@ -107,7 +107,7 @@
*/
static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
{
- struct psc_dma *psc_dma = cpu_dai->private_data;
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
dev_dbg(psc_dma->dev, "psc_i2s_set_fmt(cpu_dai=%p, format=%i)\n",
cpu_dai, format);
return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL;
@@ -129,8 +129,7 @@
.set_fmt = psc_i2s_set_fmt,
};
-struct snd_soc_dai psc_i2s_dai[] = {{
- .name = "I2S",
+static struct snd_soc_dai_driver psc_i2s_dai[] = {{
.playback = {
.channels_min = 2,
.channels_max = 2,
@@ -145,7 +144,6 @@
},
.ops = &psc_i2s_dai_ops,
} };
-EXPORT_SYMBOL_GPL(psc_i2s_dai);
/* ---------------------------------------------------------------------
* OF platform bus binding code:
@@ -159,11 +157,7 @@
struct psc_dma *psc_dma;
struct mpc52xx_psc __iomem *regs;
- rc = mpc5200_audio_dma_create(op);
- if (rc != 0)
- return rc;
-
- rc = snd_soc_register_dais(psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
+ rc = snd_soc_register_dais(&op->dev, psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
if (rc != 0) {
pr_err("Failed to register DAI\n");
return 0;
@@ -207,7 +201,8 @@
static int __devexit psc_i2s_of_remove(struct platform_device *op)
{
- return mpc5200_audio_dma_destroy(op);
+ snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_i2s_dai));
+ return 0;
}
/* Match table for of_platform binding */
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index 3b13b8d..0d7dcf1 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -1,85 +1,97 @@
/**
- * Freescale MPC8610HPCD ALSA SoC Fabric driver
+ * Freescale MPC8610HPCD ALSA SoC Machine driver
*
* Author: Timur Tabi <timur@freescale.com>
*
- * Copyright 2007-2008 Freescale Semiconductor, Inc. This file is licensed
- * under the terms of the GNU General Public License version 2. This
- * program is licensed "as is" without any warranty of any kind, whether
- * express or implied.
+ * Copyright 2007-2010 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
*/
-#include <linux/slab.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/of_device.h>
-#include <linux/of_platform.h>
+#include <linux/slab.h>
#include <sound/soc.h>
-#include <asm/immap_86xx.h>
+#include <asm/fsl_guts.h>
-#include "../codecs/cs4270.h"
#include "fsl_dma.h"
#include "fsl_ssi.h"
+/* There's only one global utilities register */
+static phys_addr_t guts_phys;
+
+#define DAI_NAME_SIZE 32
+
/**
- * mpc8610_hpcd_data: fabric-specific ASoC device data
+ * mpc8610_hpcd_data: machine-specific ASoC device data
*
* This structure contains data for a single sound platform device on an
* MPC8610 HPCD. Some of the data is taken from the device tree.
*/
struct mpc8610_hpcd_data {
- struct snd_soc_device sound_devdata;
- struct snd_soc_dai_link dai;
- struct snd_soc_card machine;
+ struct snd_soc_dai_link dai[2];
+ struct snd_soc_card card;
unsigned int dai_format;
unsigned int codec_clk_direction;
unsigned int cpu_clk_direction;
unsigned int clk_frequency;
- struct ccsr_guts __iomem *guts;
- struct ccsr_ssi __iomem *ssi;
- unsigned int ssi_id; /* 0 = SSI1, 1 = SSI2, etc */
- unsigned int ssi_irq;
- unsigned int dma_id; /* 0 = DMA1, 1 = DMA2, etc */
- unsigned int dma_irq[2];
- struct ccsr_dma_channel __iomem *dma[2];
+ unsigned int ssi_id; /* 0 = SSI1, 1 = SSI2, etc */
+ unsigned int dma_id[2]; /* 0 = DMA1, 1 = DMA2, etc */
unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/
+ char codec_dai_name[DAI_NAME_SIZE];
+ char codec_name[DAI_NAME_SIZE];
+ char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */
};
/**
* mpc8610_hpcd_machine_probe: initialize the board
*
- * This function is called when platform_device_add() is called. It is used
- * to initialize the board-specific hardware.
+ * This function is used to initialize the board-specific hardware.
*
* Here we program the DMACR and PMUXCR registers.
*/
static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device)
{
+ struct snd_soc_card *card = platform_get_drvdata(sound_device);
struct mpc8610_hpcd_data *machine_data =
- sound_device->dev.platform_data;
+ container_of(card, struct mpc8610_hpcd_data, card);
+ struct ccsr_guts_86xx __iomem *guts;
+
+ guts = ioremap(guts_phys, sizeof(struct ccsr_guts_86xx));
+ if (!guts) {
+ dev_err(card->dev, "could not map global utilities\n");
+ return -ENOMEM;
+ }
/* Program the signal routing between the SSI and the DMA */
- guts_set_dmacr(machine_data->guts, machine_data->dma_id,
- machine_data->dma_channel_id[0], CCSR_GUTS_DMACR_DEV_SSI);
- guts_set_dmacr(machine_data->guts, machine_data->dma_id,
- machine_data->dma_channel_id[1], CCSR_GUTS_DMACR_DEV_SSI);
+ guts_set_dmacr(guts, machine_data->dma_id[0],
+ machine_data->dma_channel_id[0],
+ CCSR_GUTS_DMACR_DEV_SSI);
+ guts_set_dmacr(guts, machine_data->dma_id[1],
+ machine_data->dma_channel_id[1],
+ CCSR_GUTS_DMACR_DEV_SSI);
- guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id,
- machine_data->dma_channel_id[0], 0);
- guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id,
- machine_data->dma_channel_id[1], 0);
+ guts_set_pmuxcr_dma(guts, machine_data->dma_id[0],
+ machine_data->dma_channel_id[0], 0);
+ guts_set_pmuxcr_dma(guts, machine_data->dma_id[1],
+ machine_data->dma_channel_id[1], 0);
switch (machine_data->ssi_id) {
case 0:
- clrsetbits_be32(&machine_data->guts->pmuxcr,
+ clrsetbits_be32(&guts->pmuxcr,
CCSR_GUTS_PMUXCR_SSI1_MASK, CCSR_GUTS_PMUXCR_SSI1_SSI);
break;
case 1:
- clrsetbits_be32(&machine_data->guts->pmuxcr,
+ clrsetbits_be32(&guts->pmuxcr,
CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_SSI);
break;
}
+ iounmap(guts);
+
return 0;
}
@@ -93,38 +105,15 @@
static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
struct mpc8610_hpcd_data *machine_data =
- rtd->socdev->dev->platform_data;
+ container_of(rtd->card, struct mpc8610_hpcd_data, card);
+ struct device *dev = rtd->card->dev;
int ret = 0;
- /* Tell the CPU driver what the serial protocol is. */
- ret = snd_soc_dai_set_fmt(cpu_dai, machine_data->dai_format);
- if (ret < 0) {
- dev_err(substream->pcm->card->dev,
- "could not set CPU driver audio format\n");
- return ret;
- }
-
/* Tell the codec driver what the serial protocol is. */
- ret = snd_soc_dai_set_fmt(codec_dai, machine_data->dai_format);
+ ret = snd_soc_dai_set_fmt(rtd->codec_dai, machine_data->dai_format);
if (ret < 0) {
- dev_err(substream->pcm->card->dev,
- "could not set codec driver audio format\n");
- return ret;
- }
-
- /*
- * Tell the CPU driver what the clock frequency is, and whether it's a
- * slave or master.
- */
- ret = snd_soc_dai_set_sysclk(cpu_dai, 0,
- machine_data->clk_frequency,
- machine_data->cpu_clk_direction);
- if (ret < 0) {
- dev_err(substream->pcm->card->dev,
- "could not set CPU driver clock parameters\n");
+ dev_err(dev, "could not set codec driver audio format\n");
return ret;
}
@@ -132,12 +121,11 @@
* Tell the codec driver what the MCLK frequency is, and whether it's
* a slave or master.
*/
- ret = snd_soc_dai_set_sysclk(codec_dai, 0,
- machine_data->clk_frequency,
- machine_data->codec_clk_direction);
+ ret = snd_soc_dai_set_sysclk(rtd->codec_dai, 0,
+ machine_data->clk_frequency,
+ machine_data->codec_clk_direction);
if (ret < 0) {
- dev_err(substream->pcm->card->dev,
- "could not set codec driver clock params\n");
+ dev_err(dev, "could not set codec driver clock params\n");
return ret;
}
@@ -150,116 +138,255 @@
* This function is called to remove the sound device for one SSI. We
* de-program the DMACR and PMUXCR register.
*/
-int mpc8610_hpcd_machine_remove(struct platform_device *sound_device)
+static int mpc8610_hpcd_machine_remove(struct platform_device *sound_device)
{
+ struct snd_soc_card *card = platform_get_drvdata(sound_device);
struct mpc8610_hpcd_data *machine_data =
- sound_device->dev.platform_data;
+ container_of(card, struct mpc8610_hpcd_data, card);
+ struct ccsr_guts_86xx __iomem *guts;
+
+ guts = ioremap(guts_phys, sizeof(struct ccsr_guts_86xx));
+ if (!guts) {
+ dev_err(card->dev, "could not map global utilities\n");
+ return -ENOMEM;
+ }
/* Restore the signal routing */
- guts_set_dmacr(machine_data->guts, machine_data->dma_id,
- machine_data->dma_channel_id[0], 0);
- guts_set_dmacr(machine_data->guts, machine_data->dma_id,
- machine_data->dma_channel_id[1], 0);
+ guts_set_dmacr(guts, machine_data->dma_id[0],
+ machine_data->dma_channel_id[0], 0);
+ guts_set_dmacr(guts, machine_data->dma_id[1],
+ machine_data->dma_channel_id[1], 0);
switch (machine_data->ssi_id) {
case 0:
- clrsetbits_be32(&machine_data->guts->pmuxcr,
+ clrsetbits_be32(&guts->pmuxcr,
CCSR_GUTS_PMUXCR_SSI1_MASK, CCSR_GUTS_PMUXCR_SSI1_LA);
break;
case 1:
- clrsetbits_be32(&machine_data->guts->pmuxcr,
+ clrsetbits_be32(&guts->pmuxcr,
CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_LA);
break;
}
+ iounmap(guts);
+
return 0;
}
/**
- * mpc8610_hpcd_ops: ASoC fabric driver operations
+ * mpc8610_hpcd_ops: ASoC machine driver operations
*/
static struct snd_soc_ops mpc8610_hpcd_ops = {
.startup = mpc8610_hpcd_startup,
};
/**
- * mpc8610_hpcd_probe: OF probe function for the fabric driver
+ * get_node_by_phandle_name - get a node by its phandle name
*
- * This function gets called when an SSI node is found in the device tree.
+ * This function takes a node, the name of a property in that node, and a
+ * compatible string. Assuming the property is a phandle to another node,
+ * it returns that node, (optionally) if that node is compatible.
*
- * Although this is a fabric driver, the SSI node is the "master" node with
+ * If the property is not a phandle, or the node it points to is not compatible
+ * with the specific string, then NULL is returned.
+ */
+static struct device_node *get_node_by_phandle_name(struct device_node *np,
+ const char *name,
+ const char *compatible)
+{
+ const phandle *ph;
+ int len;
+
+ ph = of_get_property(np, name, &len);
+ if (!ph || (len != sizeof(phandle)))
+ return NULL;
+
+ np = of_find_node_by_phandle(*ph);
+ if (!np)
+ return NULL;
+
+ if (compatible && !of_device_is_compatible(np, compatible)) {
+ of_node_put(np);
+ return NULL;
+ }
+
+ return np;
+}
+
+/**
+ * get_parent_cell_index -- return the cell-index of the parent of a node
+ *
+ * Return the value of the cell-index property of the parent of the given
+ * node. This is used for DMA channel nodes that need to know the DMA ID
+ * of the controller they are on.
+ */
+static int get_parent_cell_index(struct device_node *np)
+{
+ struct device_node *parent = of_get_parent(np);
+ const u32 *iprop;
+
+ if (!parent)
+ return -1;
+
+ iprop = of_get_property(parent, "cell-index", NULL);
+ of_node_put(parent);
+
+ if (!iprop)
+ return -1;
+
+ return *iprop;
+}
+
+/**
+ * codec_node_dev_name - determine the dev_name for a codec node
+ *
+ * This function determines the dev_name for an I2C node. This is the name
+ * that would be returned by dev_name() if this device_node were part of a
+ * 'struct device' It's ugly and hackish, but it works.
+ *
+ * The dev_name for such devices include the bus number and I2C address. For
+ * example, "cs4270-codec.0-004f".
+ */
+static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
+{
+ const u32 *iprop;
+ int bus, addr;
+ char temp[DAI_NAME_SIZE];
+
+ of_modalias_node(np, temp, DAI_NAME_SIZE);
+
+ iprop = of_get_property(np, "reg", NULL);
+ if (!iprop)
+ return -EINVAL;
+
+ addr = *iprop;
+
+ bus = get_parent_cell_index(np);
+ if (bus < 0)
+ return bus;
+
+ snprintf(buf, len, "%s-codec.%u-%04x", temp, bus, addr);
+
+ return 0;
+}
+
+static int get_dma_channel(struct device_node *ssi_np,
+ const char *compatible,
+ struct snd_soc_dai_link *dai,
+ unsigned int *dma_channel_id,
+ unsigned int *dma_id)
+{
+ struct resource res;
+ struct device_node *dma_channel_np;
+ const u32 *iprop;
+ int ret;
+
+ dma_channel_np = get_node_by_phandle_name(ssi_np, compatible,
+ "fsl,ssi-dma-channel");
+ if (!dma_channel_np)
+ return -EINVAL;
+
+ /* Determine the dev_name for the device_node. This code mimics the
+ * behavior of of_device_make_bus_id(). We need this because ASoC uses
+ * the dev_name() of the device to match the platform (DMA) device with
+ * the CPU (SSI) device. It's all ugly and hackish, but it works (for
+ * now).
+ *
+ * dai->platform name should already point to an allocated buffer.
+ */
+ ret = of_address_to_resource(dma_channel_np, 0, &res);
+ if (ret)
+ return ret;
+ snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s",
+ (unsigned long long) res.start, dma_channel_np->name);
+
+ iprop = of_get_property(dma_channel_np, "cell-index", NULL);
+ if (!iprop) {
+ of_node_put(dma_channel_np);
+ return -EINVAL;
+ }
+
+ *dma_channel_id = *iprop;
+ *dma_id = get_parent_cell_index(dma_channel_np);
+ of_node_put(dma_channel_np);
+
+ return 0;
+}
+
+/**
+ * mpc8610_hpcd_probe: platform probe function for the machine driver
+ *
+ * Although this is a machine driver, the SSI node is the "master" node with
* respect to audio hardware connections. Therefore, we create a new ASoC
* device for each new SSI node that has a codec attached.
- *
- * FIXME: Currently, we only support one DMA controller, so if there are
- * multiple SSI nodes with codecs, only the first will be supported.
- *
- * FIXME: Even if we did support multiple DMA controllers, we have no
- * mechanism for assigning DMA controllers and channels to the individual
- * SSI devices. We also probably aren't compatible with the generic Elo DMA
- * device driver.
*/
-static int mpc8610_hpcd_probe(struct platform_device *ofdev,
- const struct of_device_id *match)
+static int mpc8610_hpcd_probe(struct platform_device *pdev)
{
- struct device_node *np = ofdev->dev.of_node;
+ struct device *dev = pdev->dev.parent;
+ /* ssi_pdev is the platform device for the SSI node that probed us */
+ struct platform_device *ssi_pdev =
+ container_of(dev, struct platform_device, dev);
+ struct device_node *np = ssi_pdev->dev.of_node;
struct device_node *codec_np = NULL;
- struct device_node *guts_np = NULL;
- struct device_node *dma_np = NULL;
- struct device_node *dma_channel_np = NULL;
- const phandle *codec_ph;
- const char *sprop;
- const u32 *iprop;
- struct resource res;
struct platform_device *sound_device = NULL;
struct mpc8610_hpcd_data *machine_data;
- struct fsl_ssi_info ssi_info;
- struct fsl_dma_info dma_info;
int ret = -ENODEV;
- unsigned int playback_dma_channel;
- unsigned int capture_dma_channel;
+ const char *sprop;
+ const u32 *iprop;
+
+ /* We are only interested in SSIs with a codec phandle in them,
+ * so let's make sure this SSI has one. The MPC8610 HPCD only
+ * knows about the CS4270 codec, so reject anything else.
+ */
+ codec_np = get_node_by_phandle_name(np, "codec-handle",
+ "cirrus,cs4270");
+ if (!codec_np) {
+ dev_err(dev, "invalid codec node\n");
+ return -EINVAL;
+ }
machine_data = kzalloc(sizeof(struct mpc8610_hpcd_data), GFP_KERNEL);
if (!machine_data)
return -ENOMEM;
- memset(&ssi_info, 0, sizeof(ssi_info));
- memset(&dma_info, 0, sizeof(dma_info));
+ machine_data->dai[0].cpu_dai_name = dev_name(&ssi_pdev->dev);
+ machine_data->dai[0].ops = &mpc8610_hpcd_ops;
- ssi_info.dev = &ofdev->dev;
+ /* Determine the codec name, it will be used as the codec DAI name */
+ ret = codec_node_dev_name(codec_np, machine_data->codec_name,
+ DAI_NAME_SIZE);
+ if (ret) {
+ dev_err(&pdev->dev, "invalid codec node %s\n",
+ codec_np->full_name);
+ ret = -EINVAL;
+ goto error;
+ }
+ machine_data->dai[0].codec_name = machine_data->codec_name;
- /*
- * We are only interested in SSIs with a codec phandle in them, so let's
- * make sure this SSI has one.
+ /* The DAI name from the codec (snd_soc_dai_driver.name) */
+ machine_data->dai[0].codec_dai_name = "cs4270-hifi";
+
+ /* We register two DAIs per SSI, one for playback and the other for
+ * capture. Currently, we only support codecs that have one DAI for
+ * both playback and capture.
*/
- codec_ph = of_get_property(np, "codec-handle", NULL);
- if (!codec_ph)
- goto error;
-
- codec_np = of_find_node_by_phandle(*codec_ph);
- if (!codec_np)
- goto error;
-
- /* The MPC8610 HPCD only knows about the CS4270 codec, so reject
- anything else. */
- if (!of_device_is_compatible(codec_np, "cirrus,cs4270"))
- goto error;
+ memcpy(&machine_data->dai[1], &machine_data->dai[0],
+ sizeof(struct snd_soc_dai_link));
/* Get the device ID */
iprop = of_get_property(np, "cell-index", NULL);
if (!iprop) {
- dev_err(&ofdev->dev, "cell-index property not found\n");
+ dev_err(&pdev->dev, "cell-index property not found\n");
ret = -EINVAL;
goto error;
}
machine_data->ssi_id = *iprop;
- ssi_info.id = *iprop;
/* Get the serial format and clock direction. */
sprop = of_get_property(np, "fsl,mode", NULL);
if (!sprop) {
- dev_err(&ofdev->dev, "fsl,mode property not found\n");
+ dev_err(&pdev->dev, "fsl,mode property not found\n");
ret = -EINVAL;
goto error;
}
@@ -269,15 +396,14 @@
machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
- /*
- * In i2s-slave mode, the codec has its own clock source, so we
+ /* In i2s-slave mode, the codec has its own clock source, so we
* need to get the frequency from the device tree and pass it to
* the codec driver.
*/
iprop = of_get_property(codec_np, "clock-frequency", NULL);
if (!iprop || !*iprop) {
- dev_err(&ofdev->dev, "codec bus-frequency property "
- "is missing or invalid\n");
+ dev_err(&pdev->dev, "codec bus-frequency "
+ "property is missing or invalid\n");
ret = -EINVAL;
goto error;
}
@@ -311,317 +437,153 @@
machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
} else {
- dev_err(&ofdev->dev,
- "unrecognized fsl,mode property \"%s\"\n", sprop);
+ dev_err(&pdev->dev,
+ "unrecognized fsl,mode property '%s'\n", sprop);
ret = -EINVAL;
goto error;
}
if (!machine_data->clk_frequency) {
- dev_err(&ofdev->dev, "unknown clock frequency\n");
+ dev_err(&pdev->dev, "unknown clock frequency\n");
ret = -EINVAL;
goto error;
}
- /* Read the SSI information from the device tree */
- ret = of_address_to_resource(np, 0, &res);
+ /* Find the playback DMA channel to use. */
+ machine_data->dai[0].platform_name = machine_data->platform_name[0];
+ ret = get_dma_channel(np, "fsl,playback-dma", &machine_data->dai[0],
+ &machine_data->dma_channel_id[0],
+ &machine_data->dma_id[0]);
if (ret) {
- dev_err(&ofdev->dev, "could not obtain SSI address\n");
- goto error;
- }
- if (!res.start) {
- dev_err(&ofdev->dev, "invalid SSI address\n");
- goto error;
- }
- ssi_info.ssi_phys = res.start;
-
- machine_data->ssi = ioremap(ssi_info.ssi_phys, sizeof(struct ccsr_ssi));
- if (!machine_data->ssi) {
- dev_err(&ofdev->dev, "could not map SSI address %x\n",
- ssi_info.ssi_phys);
- ret = -EINVAL;
- goto error;
- }
- ssi_info.ssi = machine_data->ssi;
-
-
- /* Get the IRQ of the SSI */
- machine_data->ssi_irq = irq_of_parse_and_map(np, 0);
- if (!machine_data->ssi_irq) {
- dev_err(&ofdev->dev, "could not get SSI IRQ\n");
- ret = -EINVAL;
- goto error;
- }
- ssi_info.irq = machine_data->ssi_irq;
-
- /* Do we want to use asynchronous mode? */
- ssi_info.asynchronous =
- of_find_property(np, "fsl,ssi-asynchronous", NULL) ? 1 : 0;
- if (ssi_info.asynchronous)
- dev_info(&ofdev->dev, "using asynchronous mode\n");
-
- /* Map the global utilities registers. */
- guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts");
- if (!guts_np) {
- dev_err(&ofdev->dev, "could not obtain address of GUTS\n");
- ret = -EINVAL;
- goto error;
- }
- machine_data->guts = of_iomap(guts_np, 0);
- of_node_put(guts_np);
- if (!machine_data->guts) {
- dev_err(&ofdev->dev, "could not map GUTS\n");
- ret = -EINVAL;
+ dev_err(&pdev->dev, "missing/invalid playback DMA phandle\n");
goto error;
}
- /* Find the DMA channels to use. Both SSIs need to use the same DMA
- * controller, so let's use DMA#1.
- */
- for_each_compatible_node(dma_np, NULL, "fsl,mpc8610-dma") {
- iprop = of_get_property(dma_np, "cell-index", NULL);
- if (iprop && (*iprop == 0)) {
- of_node_put(dma_np);
- break;
- }
- }
- if (!dma_np) {
- dev_err(&ofdev->dev, "could not find DMA node\n");
- ret = -EINVAL;
- goto error;
- }
- machine_data->dma_id = *iprop;
-
- /* SSI1 needs to use DMA Channels 0 and 1, and SSI2 needs to use DMA
- * channels 2 and 3. This is just how the MPC8610 is wired
- * internally.
- */
- playback_dma_channel = (machine_data->ssi_id == 0) ? 0 : 2;
- capture_dma_channel = (machine_data->ssi_id == 0) ? 1 : 3;
-
- /*
- * Find the DMA channels to use.
- */
- while ((dma_channel_np = of_get_next_child(dma_np, dma_channel_np))) {
- iprop = of_get_property(dma_channel_np, "cell-index", NULL);
- if (iprop && (*iprop == playback_dma_channel)) {
- /* dma_channel[0] and dma_irq[0] are for playback */
- dma_info.dma_channel[0] = of_iomap(dma_channel_np, 0);
- dma_info.dma_irq[0] =
- irq_of_parse_and_map(dma_channel_np, 0);
- machine_data->dma_channel_id[0] = *iprop;
- continue;
- }
- if (iprop && (*iprop == capture_dma_channel)) {
- /* dma_channel[1] and dma_irq[1] are for capture */
- dma_info.dma_channel[1] = of_iomap(dma_channel_np, 0);
- dma_info.dma_irq[1] =
- irq_of_parse_and_map(dma_channel_np, 0);
- machine_data->dma_channel_id[1] = *iprop;
- continue;
- }
- }
- if (!dma_info.dma_channel[0] || !dma_info.dma_channel[1] ||
- !dma_info.dma_irq[0] || !dma_info.dma_irq[1]) {
- dev_err(&ofdev->dev, "could not find DMA channels\n");
- ret = -EINVAL;
+ /* Find the capture DMA channel to use. */
+ machine_data->dai[1].platform_name = machine_data->platform_name[1];
+ ret = get_dma_channel(np, "fsl,capture-dma", &machine_data->dai[1],
+ &machine_data->dma_channel_id[1],
+ &machine_data->dma_id[1]);
+ if (ret) {
+ dev_err(&pdev->dev, "missing/invalid capture DMA phandle\n");
goto error;
}
- dma_info.ssi_stx_phys = ssi_info.ssi_phys +
- offsetof(struct ccsr_ssi, stx0);
- dma_info.ssi_srx_phys = ssi_info.ssi_phys +
- offsetof(struct ccsr_ssi, srx0);
+ /* Initialize our DAI data structure. */
+ machine_data->dai[0].stream_name = "playback";
+ machine_data->dai[1].stream_name = "capture";
+ machine_data->dai[0].name = machine_data->dai[0].stream_name;
+ machine_data->dai[1].name = machine_data->dai[1].stream_name;
- /* We have the DMA information, so tell the DMA driver what it is */
- if (!fsl_dma_configure(&dma_info)) {
- dev_err(&ofdev->dev, "could not instantiate DMA device\n");
- ret = -EBUSY;
- goto error;
- }
-
- /*
- * Initialize our DAI data structure. We should probably get this
- * information from the device tree.
- */
- machine_data->dai.name = "CS4270";
- machine_data->dai.stream_name = "CS4270";
-
- machine_data->dai.cpu_dai = fsl_ssi_create_dai(&ssi_info);
- machine_data->dai.codec_dai = &cs4270_dai; /* The codec_dai we want */
- machine_data->dai.ops = &mpc8610_hpcd_ops;
-
- machine_data->machine.probe = mpc8610_hpcd_machine_probe;
- machine_data->machine.remove = mpc8610_hpcd_machine_remove;
- machine_data->machine.name = "MPC8610 HPCD";
- machine_data->machine.num_links = 1;
- machine_data->machine.dai_link = &machine_data->dai;
+ machine_data->card.probe = mpc8610_hpcd_machine_probe;
+ machine_data->card.remove = mpc8610_hpcd_machine_remove;
+ machine_data->card.name = pdev->name; /* The platform driver name */
+ machine_data->card.num_links = 2;
+ machine_data->card.dai_link = machine_data->dai;
/* Allocate a new audio platform device structure */
sound_device = platform_device_alloc("soc-audio", -1);
if (!sound_device) {
- dev_err(&ofdev->dev, "platform device allocation failed\n");
+ dev_err(&pdev->dev, "platform device alloc failed\n");
ret = -ENOMEM;
goto error;
}
- machine_data->sound_devdata.card = &machine_data->machine;
- machine_data->sound_devdata.codec_dev = &soc_codec_device_cs4270;
- machine_data->machine.platform = &fsl_soc_platform;
+ /* Associate the card data with the sound device */
+ platform_set_drvdata(sound_device, &machine_data->card);
- sound_device->dev.platform_data = machine_data;
-
-
- /* Set the platform device and ASoC device to point to each other */
- platform_set_drvdata(sound_device, &machine_data->sound_devdata);
-
- machine_data->sound_devdata.dev = &sound_device->dev;
-
-
- /* Tell ASoC to probe us. This will call mpc8610_hpcd_machine.probe(),
- if it exists. */
+ /* Register with ASoC */
ret = platform_device_add(sound_device);
-
if (ret) {
- dev_err(&ofdev->dev, "platform device add failed\n");
+ dev_err(&pdev->dev, "platform device add failed\n");
goto error;
}
- dev_set_drvdata(&ofdev->dev, sound_device);
+ of_node_put(codec_np);
return 0;
error:
of_node_put(codec_np);
- of_node_put(guts_np);
- of_node_put(dma_np);
- of_node_put(dma_channel_np);
if (sound_device)
platform_device_unregister(sound_device);
- if (machine_data->dai.cpu_dai)
- fsl_ssi_destroy_dai(machine_data->dai.cpu_dai);
-
- if (ssi_info.ssi)
- iounmap(ssi_info.ssi);
-
- if (ssi_info.irq)
- irq_dispose_mapping(ssi_info.irq);
-
- if (dma_info.dma_channel[0])
- iounmap(dma_info.dma_channel[0]);
-
- if (dma_info.dma_channel[1])
- iounmap(dma_info.dma_channel[1]);
-
- if (dma_info.dma_irq[0])
- irq_dispose_mapping(dma_info.dma_irq[0]);
-
- if (dma_info.dma_irq[1])
- irq_dispose_mapping(dma_info.dma_irq[1]);
-
- if (machine_data->guts)
- iounmap(machine_data->guts);
-
kfree(machine_data);
return ret;
}
/**
- * mpc8610_hpcd_remove: remove the OF device
+ * mpc8610_hpcd_remove: remove the platform device
*
- * This function is called when the OF device is removed.
+ * This function is called when the platform device is removed.
*/
-static int mpc8610_hpcd_remove(struct platform_device *ofdev)
+static int __devexit mpc8610_hpcd_remove(struct platform_device *pdev)
{
- struct platform_device *sound_device = dev_get_drvdata(&ofdev->dev);
+ struct platform_device *sound_device = dev_get_drvdata(&pdev->dev);
+ struct snd_soc_card *card = platform_get_drvdata(sound_device);
struct mpc8610_hpcd_data *machine_data =
- sound_device->dev.platform_data;
+ container_of(card, struct mpc8610_hpcd_data, card);
platform_device_unregister(sound_device);
- if (machine_data->dai.cpu_dai)
- fsl_ssi_destroy_dai(machine_data->dai.cpu_dai);
-
- if (machine_data->ssi)
- iounmap(machine_data->ssi);
-
- if (machine_data->dma[0])
- iounmap(machine_data->dma[0]);
-
- if (machine_data->dma[1])
- iounmap(machine_data->dma[1]);
-
- if (machine_data->dma_irq[0])
- irq_dispose_mapping(machine_data->dma_irq[0]);
-
- if (machine_data->dma_irq[1])
- irq_dispose_mapping(machine_data->dma_irq[1]);
-
- if (machine_data->guts)
- iounmap(machine_data->guts);
-
kfree(machine_data);
sound_device->dev.platform_data = NULL;
- dev_set_drvdata(&ofdev->dev, NULL);
+ dev_set_drvdata(&pdev->dev, NULL);
return 0;
}
-static struct of_device_id mpc8610_hpcd_match[] = {
- {
- .compatible = "fsl,mpc8610-ssi",
- },
- {}
-};
-MODULE_DEVICE_TABLE(of, mpc8610_hpcd_match);
-
-static struct of_platform_driver mpc8610_hpcd_of_driver = {
+static struct platform_driver mpc8610_hpcd_driver = {
+ .probe = mpc8610_hpcd_probe,
+ .remove = __devexit_p(mpc8610_hpcd_remove),
.driver = {
- .name = "mpc8610_hpcd",
+ /* The name must match the 'model' property in the device tree,
+ * in lowercase letters.
+ */
+ .name = "snd-soc-mpc8610hpcd",
.owner = THIS_MODULE,
- .of_match_table = mpc8610_hpcd_match,
},
- .probe = mpc8610_hpcd_probe,
- .remove = mpc8610_hpcd_remove,
};
/**
- * mpc8610_hpcd_init: fabric driver initialization.
+ * mpc8610_hpcd_init: machine driver initialization.
*
* This function is called when this module is loaded.
*/
static int __init mpc8610_hpcd_init(void)
{
- int ret;
+ struct device_node *guts_np;
+ struct resource res;
- printk(KERN_INFO "Freescale MPC8610 HPCD ALSA SoC fabric driver\n");
+ pr_info("Freescale MPC8610 HPCD ALSA SoC machine driver\n");
- ret = of_register_platform_driver(&mpc8610_hpcd_of_driver);
+ /* Get the physical address of the global utilities registers */
+ guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts");
+ if (of_address_to_resource(guts_np, 0, &res)) {
+ pr_err("mpc8610-hpcd: missing/invalid global utilities node\n");
+ return -EINVAL;
+ }
+ guts_phys = res.start;
- if (ret)
- printk(KERN_ERR
- "mpc8610-hpcd: failed to register platform driver\n");
-
- return ret;
+ return platform_driver_register(&mpc8610_hpcd_driver);
}
/**
- * mpc8610_hpcd_exit: fabric driver exit
+ * mpc8610_hpcd_exit: machine driver exit
*
* This function is called when this driver is unloaded.
*/
static void __exit mpc8610_hpcd_exit(void)
{
- of_unregister_platform_driver(&mpc8610_hpcd_of_driver);
+ platform_driver_unregister(&mpc8610_hpcd_driver);
}
module_init(mpc8610_hpcd_init);
module_exit(mpc8610_hpcd_exit);
MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
-MODULE_DESCRIPTION("Freescale MPC8610 HPCD ALSA SoC fabric driver");
-MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Freescale MPC8610 HPCD ALSA SoC machine driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c
new file mode 100644
index 0000000..63b9eaa
--- /dev/null
+++ b/sound/soc/fsl/p1022_ds.c
@@ -0,0 +1,591 @@
+/**
+ * Freescale P1022DS ALSA SoC Machine driver
+ *
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <asm/fsl_guts.h>
+
+#include "fsl_dma.h"
+#include "fsl_ssi.h"
+
+/* P1022-specific PMUXCR and DMUXCR bit definitions */
+
+#define CCSR_GUTS_PMUXCR_UART0_I2C1_MASK 0x0001c000
+#define CCSR_GUTS_PMUXCR_UART0_I2C1_UART0_SSI 0x00010000
+#define CCSR_GUTS_PMUXCR_UART0_I2C1_SSI 0x00018000
+
+#define CCSR_GUTS_PMUXCR_SSI_DMA_TDM_MASK 0x00000c00
+#define CCSR_GUTS_PMUXCR_SSI_DMA_TDM_SSI 0x00000000
+
+#define CCSR_GUTS_DMUXCR_PAD 1 /* DMA controller/channel set to pad */
+#define CCSR_GUTS_DMUXCR_SSI 2 /* DMA controller/channel set to SSI */
+
+/*
+ * Set the DMACR register in the GUTS
+ *
+ * The DMACR register determines the source of initiated transfers for each
+ * channel on each DMA controller. Rather than have a bunch of repetitive
+ * macros for the bit patterns, we just have a function that calculates
+ * them.
+ *
+ * guts: Pointer to GUTS structure
+ * co: The DMA controller (0 or 1)
+ * ch: The channel on the DMA controller (0, 1, 2, or 3)
+ * device: The device to set as the target (CCSR_GUTS_DMUXCR_xxx)
+ */
+static inline void guts_set_dmuxcr(struct ccsr_guts_85xx __iomem *guts,
+ unsigned int co, unsigned int ch, unsigned int device)
+{
+ unsigned int shift = 16 + (8 * (1 - co) + 2 * (3 - ch));
+
+ clrsetbits_be32(&guts->dmuxcr, 3 << shift, device << shift);
+}
+
+/* There's only one global utilities register */
+static phys_addr_t guts_phys;
+
+#define DAI_NAME_SIZE 32
+
+/**
+ * machine_data: machine-specific ASoC device data
+ *
+ * This structure contains data for a single sound platform device on an
+ * P1022 DS. Some of the data is taken from the device tree.
+ */
+struct machine_data {
+ struct snd_soc_dai_link dai[2];
+ struct snd_soc_card card;
+ unsigned int dai_format;
+ unsigned int codec_clk_direction;
+ unsigned int cpu_clk_direction;
+ unsigned int clk_frequency;
+ unsigned int ssi_id; /* 0 = SSI1, 1 = SSI2, etc */
+ unsigned int dma_id[2]; /* 0 = DMA1, 1 = DMA2, etc */
+ unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/
+ char codec_name[DAI_NAME_SIZE];
+ char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */
+};
+
+/**
+ * p1022_ds_machine_probe: initialize the board
+ *
+ * This function is used to initialize the board-specific hardware.
+ *
+ * Here we program the DMACR and PMUXCR registers.
+ */
+static int p1022_ds_machine_probe(struct platform_device *sound_device)
+{
+ struct snd_soc_card *card = platform_get_drvdata(sound_device);
+ struct machine_data *mdata =
+ container_of(card, struct machine_data, card);
+ struct ccsr_guts_85xx __iomem *guts;
+
+ guts = ioremap(guts_phys, sizeof(struct ccsr_guts_85xx));
+ if (!guts) {
+ dev_err(card->dev, "could not map global utilities\n");
+ return -ENOMEM;
+ }
+
+ /* Enable SSI Tx signal */
+ clrsetbits_be32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_UART0_I2C1_MASK,
+ CCSR_GUTS_PMUXCR_UART0_I2C1_UART0_SSI);
+
+ /* Enable SSI Rx signal */
+ clrsetbits_be32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_SSI_DMA_TDM_MASK,
+ CCSR_GUTS_PMUXCR_SSI_DMA_TDM_SSI);
+
+ /* Enable DMA Channel for SSI */
+ guts_set_dmuxcr(guts, mdata->dma_id[0], mdata->dma_channel_id[0],
+ CCSR_GUTS_DMUXCR_SSI);
+
+ guts_set_dmuxcr(guts, mdata->dma_id[1], mdata->dma_channel_id[1],
+ CCSR_GUTS_DMUXCR_SSI);
+
+ iounmap(guts);
+
+ return 0;
+}
+
+/**
+ * p1022_ds_startup: program the board with various hardware parameters
+ *
+ * This function takes board-specific information, like clock frequencies
+ * and serial data formats, and passes that information to the codec and
+ * transport drivers.
+ */
+static int p1022_ds_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct machine_data *mdata =
+ container_of(rtd->card, struct machine_data, card);
+ struct device *dev = rtd->card->dev;
+ int ret = 0;
+
+ /* Tell the codec driver what the serial protocol is. */
+ ret = snd_soc_dai_set_fmt(rtd->codec_dai, mdata->dai_format);
+ if (ret < 0) {
+ dev_err(dev, "could not set codec driver audio format\n");
+ return ret;
+ }
+
+ /*
+ * Tell the codec driver what the MCLK frequency is, and whether it's
+ * a slave or master.
+ */
+ ret = snd_soc_dai_set_sysclk(rtd->codec_dai, 0, mdata->clk_frequency,
+ mdata->codec_clk_direction);
+ if (ret < 0) {
+ dev_err(dev, "could not set codec driver clock params\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * p1022_ds_machine_remove: Remove the sound device
+ *
+ * This function is called to remove the sound device for one SSI. We
+ * de-program the DMACR and PMUXCR register.
+ */
+static int p1022_ds_machine_remove(struct platform_device *sound_device)
+{
+ struct snd_soc_card *card = platform_get_drvdata(sound_device);
+ struct machine_data *mdata =
+ container_of(card, struct machine_data, card);
+ struct ccsr_guts_85xx __iomem *guts;
+
+ guts = ioremap(guts_phys, sizeof(struct ccsr_guts_85xx));
+ if (!guts) {
+ dev_err(card->dev, "could not map global utilities\n");
+ return -ENOMEM;
+ }
+
+ /* Restore the signal routing */
+ clrbits32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_UART0_I2C1_MASK);
+ clrbits32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_SSI_DMA_TDM_MASK);
+ guts_set_dmuxcr(guts, mdata->dma_id[0], mdata->dma_channel_id[0], 0);
+ guts_set_dmuxcr(guts, mdata->dma_id[1], mdata->dma_channel_id[1], 0);
+
+ iounmap(guts);
+
+ return 0;
+}
+
+/**
+ * p1022_ds_ops: ASoC machine driver operations
+ */
+static struct snd_soc_ops p1022_ds_ops = {
+ .startup = p1022_ds_startup,
+};
+
+/**
+ * get_node_by_phandle_name - get a node by its phandle name
+ *
+ * This function takes a node, the name of a property in that node, and a
+ * compatible string. Assuming the property is a phandle to another node,
+ * it returns that node, (optionally) if that node is compatible.
+ *
+ * If the property is not a phandle, or the node it points to is not compatible
+ * with the specific string, then NULL is returned.
+ */
+static struct device_node *get_node_by_phandle_name(struct device_node *np,
+ const char *name, const char *compatible)
+{
+ np = of_parse_phandle(np, name, 0);
+ if (!np)
+ return NULL;
+
+ if (!of_device_is_compatible(np, compatible)) {
+ of_node_put(np);
+ return NULL;
+ }
+
+ return np;
+}
+
+/**
+ * get_parent_cell_index -- return the cell-index of the parent of a node
+ *
+ * Return the value of the cell-index property of the parent of the given
+ * node. This is used for DMA channel nodes that need to know the DMA ID
+ * of the controller they are on.
+ */
+static int get_parent_cell_index(struct device_node *np)
+{
+ struct device_node *parent = of_get_parent(np);
+ const u32 *iprop;
+ int ret = -1;
+
+ if (!parent)
+ return -1;
+
+ iprop = of_get_property(parent, "cell-index", NULL);
+ if (iprop)
+ ret = *iprop;
+
+ of_node_put(parent);
+
+ return ret;
+}
+
+/**
+ * codec_node_dev_name - determine the dev_name for a codec node
+ *
+ * This function determines the dev_name for an I2C node. This is the name
+ * that would be returned by dev_name() if this device_node were part of a
+ * 'struct device' It's ugly and hackish, but it works.
+ *
+ * The dev_name for such devices include the bus number and I2C address. For
+ * example, "cs4270-codec.0-004f".
+ */
+static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
+{
+ const u32 *iprop;
+ int bus, addr;
+ char temp[DAI_NAME_SIZE];
+
+ of_modalias_node(np, temp, DAI_NAME_SIZE);
+
+ iprop = of_get_property(np, "reg", NULL);
+ if (!iprop)
+ return -EINVAL;
+
+ addr = *iprop;
+
+ bus = get_parent_cell_index(np);
+ if (bus < 0)
+ return bus;
+
+ snprintf(buf, len, "%s-codec.%u-%04x", temp, bus, addr);
+
+ return 0;
+}
+
+static int get_dma_channel(struct device_node *ssi_np,
+ const char *compatible,
+ struct snd_soc_dai_link *dai,
+ unsigned int *dma_channel_id,
+ unsigned int *dma_id)
+{
+ struct resource res;
+ struct device_node *dma_channel_np;
+ const u32 *iprop;
+ int ret;
+
+ dma_channel_np = get_node_by_phandle_name(ssi_np, compatible,
+ "fsl,ssi-dma-channel");
+ if (!dma_channel_np)
+ return -EINVAL;
+
+ /* Determine the dev_name for the device_node. This code mimics the
+ * behavior of of_device_make_bus_id(). We need this because ASoC uses
+ * the dev_name() of the device to match the platform (DMA) device with
+ * the CPU (SSI) device. It's all ugly and hackish, but it works (for
+ * now).
+ *
+ * dai->platform name should already point to an allocated buffer.
+ */
+ ret = of_address_to_resource(dma_channel_np, 0, &res);
+ if (ret)
+ return ret;
+ snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s",
+ (unsigned long long) res.start, dma_channel_np->name);
+
+ iprop = of_get_property(dma_channel_np, "cell-index", NULL);
+ if (!iprop) {
+ of_node_put(dma_channel_np);
+ return -EINVAL;
+ }
+
+ *dma_channel_id = *iprop;
+ *dma_id = get_parent_cell_index(dma_channel_np);
+ of_node_put(dma_channel_np);
+
+ return 0;
+}
+
+/**
+ * p1022_ds_probe: platform probe function for the machine driver
+ *
+ * Although this is a machine driver, the SSI node is the "master" node with
+ * respect to audio hardware connections. Therefore, we create a new ASoC
+ * device for each new SSI node that has a codec attached.
+ */
+static int p1022_ds_probe(struct platform_device *pdev)
+{
+ struct device *dev = pdev->dev.parent;
+ /* ssi_pdev is the platform device for the SSI node that probed us */
+ struct platform_device *ssi_pdev =
+ container_of(dev, struct platform_device, dev);
+ struct device_node *np = ssi_pdev->dev.of_node;
+ struct device_node *codec_np = NULL;
+ struct platform_device *sound_device = NULL;
+ struct machine_data *mdata;
+ int ret = -ENODEV;
+ const char *sprop;
+ const u32 *iprop;
+
+ /* Find the codec node for this SSI. */
+ codec_np = of_parse_phandle(np, "codec-handle", 0);
+ if (!codec_np) {
+ dev_err(dev, "could not find codec node\n");
+ return -EINVAL;
+ }
+
+ mdata = kzalloc(sizeof(struct machine_data), GFP_KERNEL);
+ if (!mdata) {
+ ret = -ENOMEM;
+ goto error_put;
+ }
+
+ mdata->dai[0].cpu_dai_name = dev_name(&ssi_pdev->dev);
+ mdata->dai[0].ops = &p1022_ds_ops;
+
+ /* Determine the codec name, it will be used as the codec DAI name */
+ ret = codec_node_dev_name(codec_np, mdata->codec_name, DAI_NAME_SIZE);
+ if (ret) {
+ dev_err(&pdev->dev, "invalid codec node %s\n",
+ codec_np->full_name);
+ ret = -EINVAL;
+ goto error;
+ }
+ mdata->dai[0].codec_name = mdata->codec_name;
+
+ /* We register two DAIs per SSI, one for playback and the other for
+ * capture. We support codecs that have separate DAIs for both playback
+ * and capture.
+ */
+ memcpy(&mdata->dai[1], &mdata->dai[0], sizeof(struct snd_soc_dai_link));
+
+ /* The DAI names from the codec (snd_soc_dai_driver.name) */
+ mdata->dai[0].codec_dai_name = "wm8776-hifi-playback";
+ mdata->dai[1].codec_dai_name = "wm8776-hifi-capture";
+
+ /* Get the device ID */
+ iprop = of_get_property(np, "cell-index", NULL);
+ if (!iprop) {
+ dev_err(&pdev->dev, "cell-index property not found\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ mdata->ssi_id = *iprop;
+
+ /* Get the serial format and clock direction. */
+ sprop = of_get_property(np, "fsl,mode", NULL);
+ if (!sprop) {
+ dev_err(&pdev->dev, "fsl,mode property not found\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (strcasecmp(sprop, "i2s-slave") == 0) {
+ mdata->dai_format = SND_SOC_DAIFMT_I2S;
+ mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;
+ mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;
+
+ /* In i2s-slave mode, the codec has its own clock source, so we
+ * need to get the frequency from the device tree and pass it to
+ * the codec driver.
+ */
+ iprop = of_get_property(codec_np, "clock-frequency", NULL);
+ if (!iprop || !*iprop) {
+ dev_err(&pdev->dev, "codec bus-frequency "
+ "property is missing or invalid\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ mdata->clk_frequency = *iprop;
+ } else if (strcasecmp(sprop, "i2s-master") == 0) {
+ mdata->dai_format = SND_SOC_DAIFMT_I2S;
+ mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
+ mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;
+ } else if (strcasecmp(sprop, "lj-slave") == 0) {
+ mdata->dai_format = SND_SOC_DAIFMT_LEFT_J;
+ mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;
+ mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;
+ } else if (strcasecmp(sprop, "lj-master") == 0) {
+ mdata->dai_format = SND_SOC_DAIFMT_LEFT_J;
+ mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
+ mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;
+ } else if (strcasecmp(sprop, "rj-slave") == 0) {
+ mdata->dai_format = SND_SOC_DAIFMT_RIGHT_J;
+ mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;
+ mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;
+ } else if (strcasecmp(sprop, "rj-master") == 0) {
+ mdata->dai_format = SND_SOC_DAIFMT_RIGHT_J;
+ mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
+ mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;
+ } else if (strcasecmp(sprop, "ac97-slave") == 0) {
+ mdata->dai_format = SND_SOC_DAIFMT_AC97;
+ mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;
+ mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;
+ } else if (strcasecmp(sprop, "ac97-master") == 0) {
+ mdata->dai_format = SND_SOC_DAIFMT_AC97;
+ mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
+ mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;
+ } else {
+ dev_err(&pdev->dev,
+ "unrecognized fsl,mode property '%s'\n", sprop);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (!mdata->clk_frequency) {
+ dev_err(&pdev->dev, "unknown clock frequency\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Find the playback DMA channel to use. */
+ mdata->dai[0].platform_name = mdata->platform_name[0];
+ ret = get_dma_channel(np, "fsl,playback-dma", &mdata->dai[0],
+ &mdata->dma_channel_id[0],
+ &mdata->dma_id[0]);
+ if (ret) {
+ dev_err(&pdev->dev, "missing/invalid playback DMA phandle\n");
+ goto error;
+ }
+
+ /* Find the capture DMA channel to use. */
+ mdata->dai[1].platform_name = mdata->platform_name[1];
+ ret = get_dma_channel(np, "fsl,capture-dma", &mdata->dai[1],
+ &mdata->dma_channel_id[1],
+ &mdata->dma_id[1]);
+ if (ret) {
+ dev_err(&pdev->dev, "missing/invalid capture DMA phandle\n");
+ goto error;
+ }
+
+ /* Initialize our DAI data structure. */
+ mdata->dai[0].stream_name = "playback";
+ mdata->dai[1].stream_name = "capture";
+ mdata->dai[0].name = mdata->dai[0].stream_name;
+ mdata->dai[1].name = mdata->dai[1].stream_name;
+
+ mdata->card.probe = p1022_ds_machine_probe;
+ mdata->card.remove = p1022_ds_machine_remove;
+ mdata->card.name = pdev->name; /* The platform driver name */
+ mdata->card.num_links = 2;
+ mdata->card.dai_link = mdata->dai;
+
+ /* Allocate a new audio platform device structure */
+ sound_device = platform_device_alloc("soc-audio", -1);
+ if (!sound_device) {
+ dev_err(&pdev->dev, "platform device alloc failed\n");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ /* Associate the card data with the sound device */
+ platform_set_drvdata(sound_device, &mdata->card);
+
+ /* Register with ASoC */
+ ret = platform_device_add(sound_device);
+ if (ret) {
+ dev_err(&pdev->dev, "platform device add failed\n");
+ goto error;
+ }
+
+ of_node_put(codec_np);
+
+ return 0;
+
+error:
+ if (sound_device)
+ platform_device_unregister(sound_device);
+
+ kfree(mdata);
+error_put:
+ of_node_put(codec_np);
+ return ret;
+}
+
+/**
+ * p1022_ds_remove: remove the platform device
+ *
+ * This function is called when the platform device is removed.
+ */
+static int __devexit p1022_ds_remove(struct platform_device *pdev)
+{
+ struct platform_device *sound_device = dev_get_drvdata(&pdev->dev);
+ struct snd_soc_card *card = platform_get_drvdata(sound_device);
+ struct machine_data *mdata =
+ container_of(card, struct machine_data, card);
+
+ platform_device_unregister(sound_device);
+
+ kfree(mdata);
+ sound_device->dev.platform_data = NULL;
+
+ dev_set_drvdata(&pdev->dev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver p1022_ds_driver = {
+ .probe = p1022_ds_probe,
+ .remove = __devexit_p(p1022_ds_remove),
+ .driver = {
+ /* The name must match the 'model' property in the device tree,
+ * in lowercase letters, but only the part after that last
+ * comma. This is because some model properties have a "fsl,"
+ * prefix.
+ */
+ .name = "snd-soc-p1022",
+ .owner = THIS_MODULE,
+ },
+};
+
+/**
+ * p1022_ds_init: machine driver initialization.
+ *
+ * This function is called when this module is loaded.
+ */
+static int __init p1022_ds_init(void)
+{
+ struct device_node *guts_np;
+ struct resource res;
+
+ pr_info("Freescale P1022 DS ALSA SoC machine driver\n");
+
+ /* Get the physical address of the global utilities registers */
+ guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");
+ if (of_address_to_resource(guts_np, 0, &res)) {
+ pr_err("p1022-ds: missing/invalid global utilities node\n");
+ return -EINVAL;
+ }
+ guts_phys = res.start;
+ of_node_put(guts_np);
+
+ return platform_driver_register(&p1022_ds_driver);
+}
+
+/**
+ * p1022_ds_exit: machine driver exit
+ *
+ * This function is called when this driver is unloaded.
+ */
+static void __exit p1022_ds_exit(void)
+{
+ platform_driver_unregister(&p1022_ds_driver);
+}
+
+module_init(p1022_ds_init);
+module_exit(p1022_ds_exit);
+
+MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
+MODULE_DESCRIPTION("Freescale P1022 DS ALSA SoC machine driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c
index 6644cba..fe15bb2 100644
--- a/sound/soc/fsl/pcm030-audio-fabric.c
+++ b/sound/soc/fsl/pcm030-audio-fabric.c
@@ -32,21 +32,24 @@
#define DRV_NAME "pcm030-audio-fabric"
-static struct snd_soc_device device;
static struct snd_soc_card card;
static struct snd_soc_dai_link pcm030_fabric_dai[] = {
{
.name = "AC97",
.stream_name = "AC97 Analog",
- .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
- .cpu_dai = &psc_ac97_dai[MPC5200_AC97_NORMAL],
+ .codec_dai_name = "wm9712-hifi",
+ .cpu_dai_name = "mpc5200-psc-ac97.0",
+ .platform_name = "mpc5200-pcm-audio",
+ .codec_name = "wm9712-codec",
},
{
.name = "AC97",
.stream_name = "AC97 IEC958",
- .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
- .cpu_dai = &psc_ac97_dai[MPC5200_AC97_SPDIF],
+ .codec_dai_name = "wm9712-aux",
+ .cpu_dai_name = "mpc5200-psc-ac97.1",
+ .platform_name = "mpc5200-pcm-audio",
+ ..codec_name = "wm9712-codec",
},
};
@@ -58,22 +61,18 @@
if (!of_machine_is_compatible("phytec,pcm030"))
return -ENODEV;
- card.platform = &mpc5200_audio_dma_platform;
+
card.name = "pcm030";
card.dai_link = pcm030_fabric_dai;
card.num_links = ARRAY_SIZE(pcm030_fabric_dai);
- device.card = &card;
- device.codec_dev = &soc_codec_dev_wm9712;
-
pdev = platform_device_alloc("soc-audio", 1);
if (!pdev) {
pr_err("pcm030_fabric_init: platform_device_alloc() failed\n");
return -ENODEV;
}
- platform_set_drvdata(pdev, &device);
- device.dev = &pdev->dev;
+ platform_set_drvdata(pdev, &card);
rc = platform_device_add(pdev);
if (rc) {
diff --git a/sound/soc/fsl/soc-of-simple.c b/sound/soc/fsl/soc-of-simple.c
deleted file mode 100644
index 3bc13fd..0000000
--- a/sound/soc/fsl/soc-of-simple.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * OF helpers for ALSA SoC Layer
- *
- * Copyright (C) 2008, Secret Lab Technologies Ltd.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pm.h>
-#include <linux/bitops.h>
-#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-of-simple.h>
-#include <sound/initval.h>
-
-MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("ALSA SoC OpenFirmware bindings");
-
-static DEFINE_MUTEX(of_snd_soc_mutex);
-static LIST_HEAD(of_snd_soc_device_list);
-static int of_snd_soc_next_index;
-
-struct of_snd_soc_device {
- int id;
- struct list_head list;
- struct snd_soc_device device;
- struct snd_soc_card card;
- struct snd_soc_dai_link dai_link;
- struct platform_device *pdev;
- struct device_node *platform_node;
- struct device_node *codec_node;
-};
-
-static struct snd_soc_ops of_snd_soc_ops = {
-};
-
-static struct of_snd_soc_device *
-of_snd_soc_get_device(struct device_node *codec_node)
-{
- struct of_snd_soc_device *of_soc;
-
- list_for_each_entry(of_soc, &of_snd_soc_device_list, list) {
- if (of_soc->codec_node == codec_node)
- return of_soc;
- }
-
- of_soc = kzalloc(sizeof(struct of_snd_soc_device), GFP_KERNEL);
- if (!of_soc)
- return NULL;
-
- /* Initialize the structure and add it to the global list */
- of_soc->codec_node = codec_node;
- of_soc->id = of_snd_soc_next_index++;
- of_soc->card.dai_link = &of_soc->dai_link;
- of_soc->card.num_links = 1;
- of_soc->device.card = &of_soc->card;
- of_soc->dai_link.ops = &of_snd_soc_ops;
- list_add(&of_soc->list, &of_snd_soc_device_list);
-
- return of_soc;
-}
-
-static void of_snd_soc_register_device(struct of_snd_soc_device *of_soc)
-{
- struct platform_device *pdev;
- int rc;
-
- /* Only register the device if both the codec and platform have
- * been registered */
- if ((!of_soc->device.codec_data) || (!of_soc->platform_node))
- return;
-
- pr_info("platform<-->codec match achieved; registering machine\n");
-
- pdev = platform_device_alloc("soc-audio", of_soc->id);
- if (!pdev) {
- pr_err("of_soc: platform_device_alloc() failed\n");
- return;
- }
-
- pdev->dev.platform_data = of_soc;
- platform_set_drvdata(pdev, &of_soc->device);
- of_soc->device.dev = &pdev->dev;
-
- /* The ASoC device is complete; register it */
- rc = platform_device_add(pdev);
- if (rc) {
- pr_err("of_soc: platform_device_add() failed\n");
- return;
- }
-
-}
-
-int of_snd_soc_register_codec(struct snd_soc_codec_device *codec_dev,
- void *codec_data, struct snd_soc_dai *dai,
- struct device_node *node)
-{
- struct of_snd_soc_device *of_soc;
- int rc = 0;
-
- pr_info("registering ASoC codec driver: %s\n", node->full_name);
-
- mutex_lock(&of_snd_soc_mutex);
- of_soc = of_snd_soc_get_device(node);
- if (!of_soc) {
- rc = -ENOMEM;
- goto out;
- }
-
- /* Store the codec data */
- of_soc->device.codec_data = codec_data;
- of_soc->device.codec_dev = codec_dev;
- of_soc->dai_link.name = (char *)node->name;
- of_soc->dai_link.stream_name = (char *)node->name;
- of_soc->dai_link.codec_dai = dai;
-
- /* Now try to register the SoC device */
- of_snd_soc_register_device(of_soc);
-
- out:
- mutex_unlock(&of_snd_soc_mutex);
- return rc;
-}
-EXPORT_SYMBOL_GPL(of_snd_soc_register_codec);
-
-int of_snd_soc_register_platform(struct snd_soc_platform *platform,
- struct device_node *node,
- struct snd_soc_dai *cpu_dai)
-{
- struct of_snd_soc_device *of_soc;
- struct device_node *codec_node;
- const phandle *handle;
- int len, rc = 0;
-
- pr_info("registering ASoC platform driver: %s\n", node->full_name);
-
- handle = of_get_property(node, "codec-handle", &len);
- if (!handle || len < sizeof(handle))
- return -ENODEV;
- codec_node = of_find_node_by_phandle(*handle);
- if (!codec_node)
- return -ENODEV;
- pr_info("looking for codec: %s\n", codec_node->full_name);
-
- mutex_lock(&of_snd_soc_mutex);
- of_soc = of_snd_soc_get_device(codec_node);
- if (!of_soc) {
- rc = -ENOMEM;
- goto out;
- }
-
- of_soc->platform_node = node;
- of_soc->dai_link.cpu_dai = cpu_dai;
- of_soc->card.platform = platform;
- of_soc->card.name = of_soc->dai_link.cpu_dai->name;
-
- /* Now try to register the SoC device */
- of_snd_soc_register_device(of_soc);
-
- out:
- mutex_unlock(&of_snd_soc_mutex);
- return rc;
-}
-EXPORT_SYMBOL_GPL(of_snd_soc_register_platform);
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig
index 687c76f..642270a 100644
--- a/sound/soc/imx/Kconfig
+++ b/sound/soc/imx/Kconfig
@@ -8,12 +8,24 @@
Say Y or M if you want to add support for codecs attached to
the i.MX SSI interface.
+
if SND_IMX_SOC
+config SND_MXC_SOC_SSI
+ tristate
+
+config SND_MXC_SOC_FIQ
+ tristate
+
+config SND_MXC_SOC_MX2
+ tristate
+
config SND_MXC_SOC_WM1133_EV1
tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted"
depends on MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL
select SND_SOC_WM8350
+ select SND_MXC_SOC_SSI
+ select SND_MXC_SOC_FIQ
help
Enable support for audio on the i.MX31ADS with the WM1133-EV1
PMIC board with WM8835x fitted.
@@ -22,6 +34,8 @@
tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
depends on MACH_PCM043 || MACH_PCA100
select SND_SOC_WM9712
+ select SND_MXC_SOC_SSI
+ select SND_MXC_SOC_FIQ
help
Say Y if you want to add support for SoC audio on Phytec phyCORE
and phyCARD boards in AC97 mode
@@ -32,6 +46,8 @@
|| MACH_EUKREA_MBIMXSD25_BASEBOARD \
|| MACH_EUKREA_MBIMXSD35_BASEBOARD
select SND_SOC_TLV320AIC23
+ select SND_MXC_SOC_SSI
+ select SND_MXC_SOC_FIQ
help
Enable I2S based access to the TLV320AIC23B codec attached
to the SSI interface
diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile
index 7bc57ba..b67fc02 100644
--- a/sound/soc/imx/Makefile
+++ b/sound/soc/imx/Makefile
@@ -1,11 +1,11 @@
# i.MX Platform Support
-snd-soc-imx-objs := imx-ssi.o imx-pcm-fiq.o
-
-ifdef CONFIG_MACH_MX27
-snd-soc-imx-objs += imx-pcm-dma-mx2.o
-endif
+snd-soc-imx-objs := imx-ssi.o
+snd-soc-imx-fiq-objs := imx-pcm-fiq.o
+snd-soc-imx-mx2-objs := imx-pcm-dma-mx2.o
obj-$(CONFIG_SND_IMX_SOC) += snd-soc-imx.o
+obj-$(CONFIG_SND_MXC_SOC_FIQ) += snd-soc-imx-fiq.o
+obj-$(CONFIG_SND_MXC_SOC_MX2) += snd-soc-imx-mx2.o
# i.MX Machine Support
snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
diff --git a/sound/soc/imx/eukrea-tlv320.c b/sound/soc/imx/eukrea-tlv320.c
index f15dfbd..b596752 100644
--- a/sound/soc/imx/eukrea-tlv320.c
+++ b/sound/soc/imx/eukrea-tlv320.c
@@ -79,22 +79,19 @@
static struct snd_soc_dai_link eukrea_tlv320_dai = {
.name = "tlv320aic23",
.stream_name = "TLV320AIC23",
- .codec_dai = &tlv320aic23_dai,
+ .codec_dai = "tlv320aic23-hifi",
+ .platform_name = "imx-pcm-audio.0",
+ .codec_name = "tlv320aic23-codec.0-001a",
+ .cpu_dai = "imx-ssi.0",
.ops = &eukrea_tlv320_snd_ops,
};
static struct snd_soc_card eukrea_tlv320 = {
.name = "cpuimx-audio",
- .platform = &imx_soc_platform,
.dai_link = &eukrea_tlv320_dai,
.num_links = 1,
};
-static struct snd_soc_device eukrea_tlv320_snd_devdata = {
- .card = &eukrea_tlv320,
- .codec_dev = &soc_codec_dev_tlv320aic23,
-};
-
static struct platform_device *eukrea_tlv320_snd_device;
static int __init eukrea_tlv320_init(void)
@@ -110,10 +107,7 @@
if (!eukrea_tlv320_snd_device)
return -ENOMEM;
- eukrea_tlv320_dai.cpu_dai = &imx_ssi_pcm_dai[0];
-
- platform_set_drvdata(eukrea_tlv320_snd_device, &eukrea_tlv320_snd_devdata);
- eukrea_tlv320_snd_devdata.dev = &eukrea_tlv320_snd_device->dev;
+ platform_set_drvdata(eukrea_tlv320_snd_device, &eukrea_tlv320);
ret = platform_device_add(eukrea_tlv320_snd_device);
if (ret) {
diff --git a/sound/soc/imx/imx-pcm-dma-mx2.c b/sound/soc/imx/imx-pcm-dma-mx2.c
index 0a595da..fd493ee 100644
--- a/sound/soc/imx/imx-pcm-dma-mx2.c
+++ b/sound/soc/imx/imx-pcm-dma-mx2.c
@@ -103,7 +103,7 @@
struct imx_pcm_runtime_data *iprtd = runtime->private_data;
int ret;
- dma_params = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
iprtd->dma = imx_dma_request_by_prio(DRV_NAME, DMA_PRIO_HIGH);
if (iprtd->dma < 0) {
@@ -213,7 +213,7 @@
struct imx_pcm_runtime_data *iprtd = runtime->private_data;
int err;
- dma_params = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
iprtd->substream = substream;
iprtd->buf = (unsigned int *)substream->dma_buffer.area;
@@ -318,19 +318,42 @@
.mmap = snd_imx_pcm_mmap,
};
-static struct snd_soc_platform imx_soc_platform_dma = {
- .name = "imx-audio",
- .pcm_ops = &imx_pcm_ops,
+static struct snd_soc_platform_driver imx_soc_platform_mx2 = {
+ .ops = &imx_pcm_ops,
.pcm_new = imx_pcm_new,
.pcm_free = imx_pcm_free,
};
-struct snd_soc_platform *imx_ssi_dma_mx2_init(struct platform_device *pdev,
- struct imx_ssi *ssi)
+static int __devinit imx_soc_platform_probe(struct platform_device *pdev)
{
- ssi->dma_params_tx.burstsize = DMA_TXFIFO_BURST;
- ssi->dma_params_rx.burstsize = DMA_RXFIFO_BURST;
-
- return &imx_soc_platform_dma;
+ return snd_soc_register_platform(&pdev->dev, &imx_soc_platform_mx2);
}
+static int __devexit imx_soc_platform_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver imx_pcm_driver = {
+ .driver = {
+ .name = "imx-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = imx_soc_platform_probe,
+ .remove = __devexit_p(imx_soc_platform_remove),
+};
+
+static int __init snd_imx_pcm_init(void)
+{
+ return platform_driver_register(&imx_pcm_driver);
+}
+module_init(snd_imx_pcm_init);
+
+static void __exit snd_imx_pcm_exit(void)
+{
+ platform_driver_unregister(&imx_pcm_driver);
+}
+module_exit(snd_imx_pcm_exit);
+
diff --git a/sound/soc/imx/imx-pcm-fiq.c b/sound/soc/imx/imx-pcm-fiq.c
index b2bf272..413b78d 100644
--- a/sound/soc/imx/imx-pcm-fiq.c
+++ b/sound/soc/imx/imx-pcm-fiq.c
@@ -236,6 +236,8 @@
.mmap = snd_imx_pcm_mmap,
};
+static int ssi_irq = 0;
+
static int imx_pcm_fiq_new(struct snd_card *card, struct snd_soc_dai *dai,
struct snd_pcm *pcm)
{
@@ -245,7 +247,7 @@
if (ret)
return ret;
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
struct snd_pcm_substream *substream =
pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
struct snd_dma_buffer *buf = &substream->dma_buffer;
@@ -253,7 +255,7 @@
imx_ssi_fiq_tx_buffer = (unsigned long)buf->area;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
struct snd_pcm_substream *substream =
pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
struct snd_dma_buffer *buf = &substream->dma_buffer;
@@ -267,24 +269,32 @@
return 0;
}
-static struct snd_soc_platform imx_soc_platform_fiq = {
- .pcm_ops = &imx_pcm_ops,
+static void imx_pcm_fiq_free(struct snd_pcm *pcm)
+{
+ mxc_set_irq_fiq(ssi_irq, 0);
+ release_fiq(&fh);
+ imx_pcm_free(pcm);
+}
+
+static struct snd_soc_platform_driver imx_soc_platform_fiq = {
+ .ops = &imx_pcm_ops,
.pcm_new = imx_pcm_fiq_new,
- .pcm_free = imx_pcm_free,
+ .pcm_free = imx_pcm_fiq_free,
};
-struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev,
- struct imx_ssi *ssi)
+static int __devinit imx_soc_platform_probe(struct platform_device *pdev)
{
- int ret = 0;
+ struct imx_ssi *ssi = platform_get_drvdata(pdev);
+ int ret;
ret = claim_fiq(&fh);
if (ret) {
dev_err(&pdev->dev, "failed to claim fiq: %d", ret);
- return ERR_PTR(ret);
+ return ret;
}
mxc_set_irq_fiq(ssi->irq, 1);
+ ssi_irq = ssi->irq;
imx_pcm_fiq = ssi->irq;
@@ -293,13 +303,43 @@
ssi->dma_params_tx.burstsize = 4;
ssi->dma_params_rx.burstsize = 6;
- return &imx_soc_platform_fiq;
-}
+ ret = snd_soc_register_platform(&pdev->dev, &imx_soc_platform_fiq);
+ if (ret)
+ goto failed_register;
-void imx_ssi_fiq_exit(struct platform_device *pdev,
- struct imx_ssi *ssi)
-{
- mxc_set_irq_fiq(ssi->irq, 0);
+ return 0;
+
+failed_register:
+ mxc_set_irq_fiq(ssi_irq, 0);
release_fiq(&fh);
+
+ return ret;
}
+static int __devexit imx_soc_platform_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver imx_pcm_driver = {
+ .driver = {
+ .name = "imx-fiq-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = imx_soc_platform_probe,
+ .remove = __devexit_p(imx_soc_platform_remove),
+};
+
+static int __init snd_imx_pcm_init(void)
+{
+ return platform_driver_register(&imx_pcm_driver);
+}
+module_init(snd_imx_pcm_init);
+
+static void __exit snd_imx_pcm_exit(void)
+{
+ platform_driver_unregister(&imx_pcm_driver);
+}
+module_exit(snd_imx_pcm_exit);
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
index c81da05..d4bd345 100644
--- a/sound/soc/imx/imx-ssi.c
+++ b/sound/soc/imx/imx-ssi.c
@@ -61,7 +61,7 @@
static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
{
- struct imx_ssi *ssi = cpu_dai->private_data;
+ struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
u32 sccr;
sccr = readl(ssi->base + SSI_STCCR);
@@ -86,7 +86,7 @@
*/
static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
{
- struct imx_ssi *ssi = cpu_dai->private_data;
+ struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
u32 strcr = 0, scr;
scr = readl(ssi->base + SSI_SCR) & ~(SSI_SCR_SYN | SSI_SCR_NET);
@@ -164,7 +164,7 @@
static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
{
- struct imx_ssi *ssi = cpu_dai->private_data;
+ struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
u32 scr;
scr = readl(ssi->base + SSI_SCR);
@@ -192,7 +192,7 @@
static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
int div_id, int div)
{
- struct imx_ssi *ssi = cpu_dai->private_data;
+ struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
u32 stccr, srccr;
stccr = readl(ssi->base + SSI_STCCR);
@@ -241,7 +241,7 @@
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
- struct imx_ssi *ssi = cpu_dai->private_data;
+ struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
struct imx_pcm_dma_params *dma_data;
u32 reg, sccr;
@@ -282,9 +282,7 @@
static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct imx_ssi *ssi = cpu_dai->private_data;
+ struct imx_ssi *ssi = snd_soc_dai_get_drvdata(dai);
unsigned int sier_bits, sier;
unsigned int scr;
@@ -353,22 +351,6 @@
.trigger = imx_ssi_trigger,
};
-static struct snd_soc_dai imx_ssi_dai = {
- .playback = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_96000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
- .capture = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_96000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
- .ops = &imx_ssi_pcm_dai_ops,
-};
-
int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
@@ -384,6 +366,7 @@
runtime->dma_bytes);
return ret;
}
+EXPORT_SYMBOL_GPL(snd_imx_pcm_mmap);
static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
{
@@ -415,14 +398,14 @@
card->dev->dma_mask = &imx_pcm_dmamask;
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = imx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto out;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
ret = imx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
@@ -432,6 +415,7 @@
out:
return ret;
}
+EXPORT_SYMBOL_GPL(imx_pcm_new);
void imx_pcm_free(struct snd_pcm *pcm)
{
@@ -453,14 +437,40 @@
buf->area = NULL;
}
}
+EXPORT_SYMBOL_GPL(imx_pcm_free);
-struct snd_soc_platform imx_soc_platform = {
- .name = "imx-audio",
+static struct snd_soc_dai_driver imx_ssi_dai = {
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &imx_ssi_pcm_dai_ops,
};
-EXPORT_SYMBOL_GPL(imx_soc_platform);
-static struct snd_soc_dai imx_ac97_dai = {
- .name = "AC97",
+static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
+{
+ struct imx_ssi *ssi = dev_get_drvdata(dai->dev);
+ uint32_t val;
+
+ snd_soc_dai_set_drvdata(dai, ssi);
+
+ val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) |
+ SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize);
+ writel(val, ssi->base + SSI_SFCSR);
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver imx_ac97_dai = {
+ .probe = imx_ssi_dai_probe,
.ac97_control = 1,
.playback = {
.stream_name = "AC97 Playback",
@@ -580,25 +590,18 @@
};
EXPORT_SYMBOL_GPL(soc_ac97_ops);
-struct snd_soc_dai imx_ssi_pcm_dai[2];
-EXPORT_SYMBOL_GPL(imx_ssi_pcm_dai);
-
static int imx_ssi_probe(struct platform_device *pdev)
{
struct resource *res;
struct imx_ssi *ssi;
struct imx_ssi_platform_data *pdata = pdev->dev.platform_data;
- struct snd_soc_platform *platform;
int ret = 0;
- unsigned int val;
- struct snd_soc_dai *dai = &imx_ssi_pcm_dai[pdev->id];
-
- if (dai->id >= ARRAY_SIZE(imx_ssi_pcm_dai))
- return -EINVAL;
+ struct snd_soc_dai_driver *dai;
ssi = kzalloc(sizeof(*ssi), GFP_KERNEL);
if (!ssi)
return -ENOMEM;
+ dev_set_drvdata(&pdev->dev, ssi);
if (pdata) {
ssi->ac97_reset = pdata->ac97_reset;
@@ -643,9 +646,9 @@
}
ac97_ssi = ssi;
setup_channel_to_ac97(ssi);
- memcpy(dai, &imx_ac97_dai, sizeof(imx_ac97_dai));
+ dai = &imx_ac97_dai;
} else
- memcpy(dai, &imx_ssi_dai, sizeof(imx_ssi_dai));
+ dai = &imx_ssi_dai;
writel(0x0, ssi->base + SSI_SIER);
@@ -660,37 +663,36 @@
if (res)
ssi->dma_params_rx.dma = res->start;
- dai->id = pdev->id;
- dai->dev = &pdev->dev;
- dai->name = kasprintf(GFP_KERNEL, "imx-ssi.%d", pdev->id);
- dai->private_data = ssi;
-
if ((cpu_is_mx27() || cpu_is_mx21()) &&
!(ssi->flags & IMX_SSI_USE_AC97) &&
(ssi->flags & IMX_SSI_DMA)) {
ssi->flags |= IMX_SSI_DMA;
- platform = imx_ssi_dma_mx2_init(pdev, ssi);
- } else
- platform = imx_ssi_fiq_init(pdev, ssi);
+ }
- imx_soc_platform.pcm_ops = platform->pcm_ops;
- imx_soc_platform.pcm_new = platform->pcm_new;
- imx_soc_platform.pcm_free = platform->pcm_free;
+ platform_set_drvdata(pdev, ssi);
- val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) |
- SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize);
- writel(val, ssi->base + SSI_SFCSR);
-
- ret = snd_soc_register_dai(dai);
+ ret = snd_soc_register_dai(&pdev->dev, dai);
if (ret) {
dev_err(&pdev->dev, "register DAI failed\n");
goto failed_register;
}
- platform_set_drvdata(pdev, ssi);
+ ssi->soc_platform_pdev = platform_device_alloc("imx-fiq-pcm-audio", pdev->id);
+ if (!ssi->soc_platform_pdev)
+ goto failed_pdev_alloc;
+ platform_set_drvdata(ssi->soc_platform_pdev, ssi);
+ ret = platform_device_add(ssi->soc_platform_pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add platform device\n");
+ goto failed_pdev_add;
+ }
return 0;
+failed_pdev_add:
+ platform_device_put(ssi->soc_platform_pdev);
+failed_pdev_alloc:
+ snd_soc_unregister_dai(&pdev->dev);
failed_register:
failed_ac97:
iounmap(ssi->base);
@@ -709,16 +711,15 @@
{
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct imx_ssi *ssi = platform_get_drvdata(pdev);
- struct snd_soc_dai *dai = &imx_ssi_pcm_dai[pdev->id];
- snd_soc_unregister_dai(dai);
+ platform_device_del(ssi->soc_platform_pdev);
+ platform_device_put(ssi->soc_platform_pdev);
+
+ snd_soc_unregister_dai(&pdev->dev);
if (ssi->flags & IMX_SSI_USE_AC97)
ac97_ssi = NULL;
- if (!(ssi->flags & IMX_SSI_DMA))
- imx_ssi_fiq_exit(pdev, ssi);
-
iounmap(ssi->base);
release_mem_region(res->start, resource_size(res));
clk_disable(ssi->clk);
@@ -733,34 +734,19 @@
.remove = __devexit_p(imx_ssi_remove),
.driver = {
- .name = DRV_NAME,
+ .name = "imx-ssi",
.owner = THIS_MODULE,
},
};
static int __init imx_ssi_init(void)
{
- int ret;
-
- ret = snd_soc_register_platform(&imx_soc_platform);
- if (ret) {
- pr_err("failed to register soc platform: %d\n", ret);
- return ret;
- }
-
- ret = platform_driver_register(&imx_ssi_driver);
- if (ret) {
- snd_soc_unregister_platform(&imx_soc_platform);
- return ret;
- }
-
- return 0;
+ return platform_driver_register(&imx_ssi_driver);
}
static void __exit imx_ssi_exit(void)
{
platform_driver_unregister(&imx_ssi_driver);
- snd_soc_unregister_platform(&imx_soc_platform);
}
module_init(imx_ssi_init);
diff --git a/sound/soc/imx/imx-ssi.h b/sound/soc/imx/imx-ssi.h
index 55f26eb..53b780d 100644
--- a/sound/soc/imx/imx-ssi.h
+++ b/sound/soc/imx/imx-ssi.h
@@ -183,9 +183,6 @@
#define IMX_SSI_RX_DIV_PSR 4
#define IMX_SSI_RX_DIV_PM 5
-extern struct snd_soc_dai imx_ssi_pcm_dai[2];
-extern struct snd_soc_platform imx_soc_platform;
-
#define DRV_NAME "imx-ssi"
struct imx_pcm_dma_params {
@@ -197,7 +194,7 @@
struct imx_ssi {
struct platform_device *ac97_dev;
- struct snd_soc_device imx_ac97;
+ struct snd_soc_dai *imx_ac97;
struct clk *clk;
void __iomem *base;
int irq;
@@ -213,6 +210,8 @@
struct imx_pcm_dma_params dma_params_tx;
int enabled;
+
+ struct platform_device *soc_platform_pdev;
};
struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev,
diff --git a/sound/soc/imx/phycore-ac97.c b/sound/soc/imx/phycore-ac97.c
index a8307d5..6a65dd7 100644
--- a/sound/soc/imx/phycore-ac97.c
+++ b/sound/soc/imx/phycore-ac97.c
@@ -32,23 +32,20 @@
{
.name = "HiFi",
.stream_name = "HiFi",
- .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+ .codec_dai_name = "wm9712-hifi",
+ .codec_name = "wm9712-codec",
+ .cpu_dai_name = "imx-ssi.0",
+ .platform_name = "imx-fiq-pcm-audio.0",
.ops = &imx_phycore_hifi_ops,
},
};
static struct snd_soc_card imx_phycore = {
.name = "PhyCORE-audio",
- .platform = &imx_soc_platform,
.dai_link = imx_phycore_dai_ac97,
.num_links = ARRAY_SIZE(imx_phycore_dai_ac97),
};
-static struct snd_soc_device imx_phycore_snd_devdata = {
- .card = &imx_phycore,
- .codec_dev = &soc_codec_dev_wm9712,
-};
-
static struct platform_device *imx_phycore_snd_device;
static int __init imx_phycore_init(void)
@@ -63,10 +60,12 @@
if (!imx_phycore_snd_device)
return -ENOMEM;
- imx_phycore_dai_ac97[0].cpu_dai = &imx_ssi_pcm_dai[0];
+ platform_set_drvdata(imx_phycore_snd_device, &imx_phycore);
+ ret = platform_device_add(imx_phycore_snd_device);
- platform_set_drvdata(imx_phycore_snd_device, &imx_phycore_snd_devdata);
- imx_phycore_snd_devdata.dev = &imx_phycore_snd_device->dev;
+ imx_phycore_snd_device = platform_device_alloc("wm9712-codec", -1);
+ if (!imx_phycore_snd_device)
+ return -ENOMEM;
ret = platform_device_add(imx_phycore_snd_device);
if (ret) {
diff --git a/sound/soc/imx/wm1133-ev1.c b/sound/soc/imx/wm1133-ev1.c
index a6e7d94..30fdb15 100644
--- a/sound/soc/imx/wm1133-ev1.c
+++ b/sound/soc/imx/wm1133-ev1.c
@@ -82,8 +82,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int i, found = 0;
snd_pcm_format_t format = params_format(params);
unsigned int rate = params_rate(params);
@@ -210,9 +210,9 @@
{ .pin = "Mic2 Jack", .mask = SND_JACK_MICROPHONE },
};
-static int wm1133_ev1_init(struct snd_soc_codec *codec)
+static int wm1133_ev1_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_card *card = codec->socdev->card;
+ struct snd_soc_codec *codec = rtd->codec;
snd_soc_dapm_new_controls(codec, wm1133_ev1_widgets,
ARRAY_SIZE(wm1133_ev1_widgets));
@@ -221,13 +221,13 @@
ARRAY_SIZE(wm1133_ev1_map));
/* Headphone jack detection */
- snd_soc_jack_new(card, "Headphone", SND_JACK_HEADPHONE, &hp_jack);
+ snd_soc_jack_new(codec, "Headphone", SND_JACK_HEADPHONE, &hp_jack);
snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
hp_jack_pins);
wm8350_hp_jack_detect(codec, WM8350_JDR, &hp_jack, SND_JACK_HEADPHONE);
/* Microphone jack detection */
- snd_soc_jack_new(card, "Microphone",
+ snd_soc_jack_new(codec, "Microphone",
SND_JACK_MICROPHONE | SND_JACK_BTN_0, &mic_jack);
snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
mic_jack_pins);
@@ -243,8 +243,10 @@
static struct snd_soc_dai_link wm1133_ev1_dai = {
.name = "WM1133-EV1",
.stream_name = "Audio",
- .cpu_dai = &imx_ssi_pcm_dai[0],
- .codec_dai = &wm8350_dai,
+ .cpu_dai_name = "imx-ssi.0",
+ .codec_dai_name = "wm8350-hifi",
+ .platform_name = "imx-fiq-pcm-audio.0",
+ .codec_name = "wm8350-codec.0-0x1a",
.init = wm1133_ev1_init,
.ops = &wm1133_ev1_ops,
.symmetric_rates = 1,
@@ -252,16 +254,10 @@
static struct snd_soc_card wm1133_ev1 = {
.name = "WM1133-EV1",
- .platform = &imx_soc_platform,
.dai_link = &wm1133_ev1_dai,
.num_links = 1,
};
-static struct snd_soc_device wm1133_ev1_snd_devdata = {
- .card = &wm1133_ev1,
- .codec_dev = &soc_codec_dev_wm8350,
-};
-
static struct platform_device *wm1133_ev1_snd_device;
static int __init wm1133_ev1_audio_init(void)
@@ -286,8 +282,7 @@
if (!wm1133_ev1_snd_device)
return -ENOMEM;
- platform_set_drvdata(wm1133_ev1_snd_device, &wm1133_ev1_snd_devdata);
- wm1133_ev1_snd_devdata.dev = &wm1133_ev1_snd_device->dev;
+ platform_set_drvdata(wm1133_ev1_snd_device, &wm1133_ev1);
ret = platform_device_add(wm1133_ev1_snd_device);
if (ret)
diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c
index eb518f0..f3cffd1 100644
--- a/sound/soc/jz4740/jz4740-i2s.c
+++ b/sound/soc/jz4740/jz4740-i2s.c
@@ -106,15 +106,10 @@
writel(value, i2s->base + reg);
}
-static inline struct jz4740_i2s *jz4740_dai_to_i2s(struct snd_soc_dai *dai)
-{
- return dai->private_data;
-}
-
static int jz4740_i2s_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+ struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
uint32_t conf, ctrl;
if (dai->active)
@@ -136,7 +131,7 @@
static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+ struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
uint32_t conf;
if (!dai->active)
@@ -152,7 +147,7 @@
static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+ struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
uint32_t ctrl;
uint32_t mask;
@@ -186,7 +181,7 @@
static int jz4740_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
- struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+ struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
uint32_t format = 0;
uint32_t conf;
@@ -238,7 +233,7 @@
static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
- struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+ struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
enum jz4740_dma_width dma_width;
struct jz4740_pcm_config *pcm_config;
unsigned int sample_size;
@@ -288,7 +283,7 @@
static int jz4740_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned int freq, int dir)
{
- struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+ struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
struct clk *parent;
int ret = 0;
@@ -312,7 +307,7 @@
static int jz4740_i2s_suspend(struct snd_soc_dai *dai)
{
- struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+ struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
uint32_t conf;
if (dai->active) {
@@ -330,7 +325,7 @@
static int jz4740_i2s_resume(struct snd_soc_dai *dai)
{
- struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+ struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
uint32_t conf;
clk_enable(i2s->clk_aic);
@@ -346,58 +341,7 @@
return 0;
}
-static int jz4740_i2s_probe(struct platform_device *pdev, struct snd_soc_dai *dai)
-{
- struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
- uint32_t conf;
-
- conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) |
- (8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) |
- JZ_AIC_CONF_OVERFLOW_PLAY_LAST |
- JZ_AIC_CONF_I2S |
- JZ_AIC_CONF_INTERNAL_CODEC;
-
- jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, JZ_AIC_CONF_RESET);
- jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
-
- return 0;
-}
-
-static struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
- .startup = jz4740_i2s_startup,
- .shutdown = jz4740_i2s_shutdown,
- .trigger = jz4740_i2s_trigger,
- .hw_params = jz4740_i2s_hw_params,
- .set_fmt = jz4740_i2s_set_fmt,
- .set_sysclk = jz4740_i2s_set_sysclk,
-};
-
-#define JZ4740_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \
- SNDRV_PCM_FMTBIT_S16_LE)
-
-struct snd_soc_dai jz4740_i2s_dai = {
- .name = "jz4740-i2s",
- .probe = jz4740_i2s_probe,
- .playback = {
- .channels_min = 1,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_48000,
- .formats = JZ4740_I2S_FMTS,
- },
- .capture = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_48000,
- .formats = JZ4740_I2S_FMTS,
- },
- .symmetric_rates = 1,
- .ops = &jz4740_i2s_dai_ops,
- .suspend = jz4740_i2s_suspend,
- .resume = jz4740_i2s_resume,
-};
-EXPORT_SYMBOL_GPL(jz4740_i2s_dai);
-
-static void __devinit jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s)
+static void jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s)
{
struct jz4740_dma_config *dma_config;
@@ -420,6 +364,68 @@
i2s->pcm_config_capture.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO;
}
+static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+ struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+ uint32_t conf;
+
+ clk_enable(i2s->clk_aic);
+
+ jz4740_i2c_init_pcm_config(i2s);
+
+ conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) |
+ (8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) |
+ JZ_AIC_CONF_OVERFLOW_PLAY_LAST |
+ JZ_AIC_CONF_I2S |
+ JZ_AIC_CONF_INTERNAL_CODEC;
+
+ jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, JZ_AIC_CONF_RESET);
+ jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
+
+ return 0;
+}
+
+static int jz4740_i2s_dai_remove(struct snd_soc_dai *dai)
+{
+ struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+ clk_disable(i2s->clk_aic);
+ return 0;
+}
+
+static struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
+ .startup = jz4740_i2s_startup,
+ .shutdown = jz4740_i2s_shutdown,
+ .trigger = jz4740_i2s_trigger,
+ .hw_params = jz4740_i2s_hw_params,
+ .set_fmt = jz4740_i2s_set_fmt,
+ .set_sysclk = jz4740_i2s_set_sysclk,
+};
+
+#define JZ4740_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \
+ SNDRV_PCM_FMTBIT_S16_LE)
+
+static struct snd_soc_dai_driver jz4740_i2s_dai = {
+ .probe = jz4740_i2s_dai_probe,
+ .remove = jz4740_i2s_dai_remove,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = JZ4740_I2S_FMTS,
+ },
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = JZ4740_I2S_FMTS,
+ },
+ .symmetric_rates = 1,
+ .ops = &jz4740_i2s_dai_ops,
+ .suspend = jz4740_i2s_suspend,
+ .resume = jz4740_i2s_resume,
+};
+
static int __devinit jz4740_i2s_dev_probe(struct platform_device *pdev)
{
struct jz4740_i2s *i2s;
@@ -463,24 +469,17 @@
goto err_clk_put_aic;
}
- clk_enable(i2s->clk_aic);
-
- jz4740_i2c_init_pcm_config(i2s);
-
- jz4740_i2s_dai.private_data = i2s;
- ret = snd_soc_register_dai(&jz4740_i2s_dai);
+ platform_set_drvdata(pdev, i2s);
+ ret = snd_soc_register_dai(&pdev->dev, &jz4740_i2s_dai);
if (ret) {
dev_err(&pdev->dev, "Failed to register DAI\n");
goto err_clk_put_i2s;
}
- platform_set_drvdata(pdev, i2s);
-
return 0;
err_clk_put_i2s:
- clk_disable(i2s->clk_aic);
clk_put(i2s->clk_i2s);
err_clk_put_aic:
clk_put(i2s->clk_aic);
@@ -498,9 +497,8 @@
{
struct jz4740_i2s *i2s = platform_get_drvdata(pdev);
- snd_soc_unregister_dai(&jz4740_i2s_dai);
+ snd_soc_unregister_dai(&pdev->dev);
- clk_disable(i2s->clk_aic);
clk_put(i2s->clk_i2s);
clk_put(i2s->clk_aic);
diff --git a/sound/soc/jz4740/jz4740-i2s.h b/sound/soc/jz4740/jz4740-i2s.h
index da22ed8..5e49339 100644
--- a/sound/soc/jz4740/jz4740-i2s.h
+++ b/sound/soc/jz4740/jz4740-i2s.h
@@ -13,6 +13,4 @@
#define JZ4740_I2S_BIT_CLK 0
-extern struct snd_soc_dai jz4740_i2s_dai;
-
#endif
diff --git a/sound/soc/jz4740/jz4740-pcm.c b/sound/soc/jz4740/jz4740-pcm.c
index ee68d85..fb1483f 100644
--- a/sound/soc/jz4740/jz4740-pcm.c
+++ b/sound/soc/jz4740/jz4740-pcm.c
@@ -109,7 +109,7 @@
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct jz4740_pcm_config *config;
- config = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ config = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
if (!config)
return 0;
@@ -310,14 +310,14 @@
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = jz4740_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto err;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
ret = jz4740_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
@@ -328,22 +328,20 @@
return ret;
}
-struct snd_soc_platform jz4740_soc_platform = {
- .name = "jz4740-pcm",
- .pcm_ops = &jz4740_pcm_ops,
+static struct snd_soc_platform_driver jz4740_soc_platform = {
+ .ops = &jz4740_pcm_ops,
.pcm_new = jz4740_pcm_new,
.pcm_free = jz4740_pcm_free,
};
-EXPORT_SYMBOL_GPL(jz4740_soc_platform);
static int __devinit jz4740_pcm_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&jz4740_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &jz4740_soc_platform);
}
static int __devexit jz4740_pcm_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&jz4740_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
return 0;
}
@@ -351,7 +349,7 @@
.probe = jz4740_pcm_probe,
.remove = __devexit_p(jz4740_pcm_remove),
.driver = {
- .name = "jz4740-pcm",
+ .name = "jz4740-pcm-audio",
.owner = THIS_MODULE,
},
};
diff --git a/sound/soc/jz4740/jz4740-pcm.h b/sound/soc/jz4740/jz4740-pcm.h
index e3f221e..1220cbb 100644
--- a/sound/soc/jz4740/jz4740-pcm.h
+++ b/sound/soc/jz4740/jz4740-pcm.h
@@ -11,8 +11,6 @@
#include <linux/dma-mapping.h>
#include <asm/mach-jz4740/dma.h>
-/* platform data */
-extern struct snd_soc_platform jz4740_soc_platform;
struct jz4740_pcm_config {
struct jz4740_dma_config dma_config;
diff --git a/sound/soc/jz4740/qi_lb60.c b/sound/soc/jz4740/qi_lb60.c
index f15f491..ef1a99e 100644
--- a/sound/soc/jz4740/qi_lb60.c
+++ b/sound/soc/jz4740/qi_lb60.c
@@ -22,11 +22,6 @@
#include <sound/soc-dapm.h>
#include <linux/gpio.h>
-#include "../codecs/jz4740.h"
-#include "jz4740-pcm.h"
-#include "jz4740-i2s.h"
-
-
#define QI_LB60_SND_GPIO JZ_GPIO_PORTB(29)
#define QI_LB60_AMP_GPIO JZ_GPIO_PORTD(4)
@@ -60,10 +55,11 @@
SND_SOC_DAIFMT_NB_NF | \
SND_SOC_DAIFMT_CBM_CFM)
-static int qi_lb60_codec_init(struct snd_soc_codec *codec)
+static int qi_lb60_codec_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
- struct snd_soc_dai *cpu_dai = codec->socdev->card->dai_link->cpu_dai;
snd_soc_dapm_nc_pin(codec, "LIN");
snd_soc_dapm_nc_pin(codec, "RIN");
@@ -84,8 +80,10 @@
static struct snd_soc_dai_link qi_lb60_dai = {
.name = "jz4740",
.stream_name = "jz4740",
- .cpu_dai = &jz4740_i2s_dai,
- .codec_dai = &jz4740_codec_dai,
+ .cpu_dai_name = "jz4740-i2s",
+ .platform_name = "jz4740-pcm-audio",
+ .codec_dai_name = "jz4740-hifi",
+ .codec_name = "jz4740-codec",
.init = qi_lb60_codec_init,
};
@@ -93,12 +91,6 @@
.name = "QI LB60",
.dai_link = &qi_lb60_dai,
.num_links = 1,
- .platform = &jz4740_soc_platform,
-};
-
-static struct snd_soc_device qi_lb60_snd_devdata = {
- .card = &qi_lb60,
- .codec_dev = &soc_codec_dev_jz4740_codec,
};
static struct platform_device *qi_lb60_snd_device;
@@ -129,8 +121,7 @@
gpio_direction_output(QI_LB60_SND_GPIO, 0);
gpio_direction_output(QI_LB60_AMP_GPIO, 0);
- platform_set_drvdata(qi_lb60_snd_device, &qi_lb60_snd_devdata);
- qi_lb60_snd_devdata.dev = &qi_lb60_snd_device->dev;
+ platform_set_drvdata(qi_lb60_snd_device, &qi_lb60);
ret = platform_device_add(qi_lb60_snd_device);
if (ret) {
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c
index a30205b..0fd6a63 100644
--- a/sound/soc/kirkwood/kirkwood-dma.c
+++ b/sound/soc/kirkwood/kirkwood-dma.c
@@ -2,6 +2,7 @@
* kirkwood-dma.c
*
* (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
*
* 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
@@ -18,7 +19,6 @@
#include <linux/dma-mapping.h>
#include <linux/mbus.h>
#include <sound/soc.h>
-#include "kirkwood-dma.h"
#include "kirkwood.h"
#define KIRKWOOD_RATES \
@@ -123,9 +123,10 @@
int err;
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
- struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+ struct snd_soc_platform *platform = soc_runtime->platform;
+ struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
struct kirkwood_dma_data *priv;
- struct kirkwood_dma_priv *prdata = cpu_dai->private_data;
+ struct kirkwood_dma_priv *prdata = snd_soc_platform_get_drvdata(platform);
unsigned long addr;
priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
@@ -151,7 +152,7 @@
if (err < 0)
return err;
- if (soc_runtime->dai->cpu_dai->private_data == NULL) {
+ if (prdata == NULL) {
prdata = kzalloc(sizeof(struct kirkwood_dma_priv), GFP_KERNEL);
if (prdata == NULL)
return -ENOMEM;
@@ -165,7 +166,7 @@
return -EBUSY;
}
- soc_runtime->dai->cpu_dai->private_data = prdata;
+ snd_soc_platform_set_drvdata(platform, prdata);
/*
* Enable Error interrupts. We're only ack'ing them but
@@ -191,8 +192,9 @@
static int kirkwood_dma_close(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
- struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
- struct kirkwood_dma_priv *prdata = cpu_dai->private_data;
+ struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
+ struct snd_soc_platform *platform = soc_runtime->platform;
+ struct kirkwood_dma_priv *prdata = snd_soc_platform_get_drvdata(platform);
struct kirkwood_dma_data *priv;
priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
@@ -209,7 +211,7 @@
writel(0, priv->io + KIRKWOOD_ERR_MASK);
free_irq(priv->irq, prdata);
kfree(prdata);
- soc_runtime->dai->cpu_dai->private_data = NULL;
+ snd_soc_platform_set_drvdata(platform, NULL);
}
return 0;
@@ -236,7 +238,7 @@
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
- struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
struct kirkwood_dma_data *priv;
unsigned long size, count;
@@ -265,7 +267,7 @@
*substream)
{
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
- struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
struct kirkwood_dma_data *priv;
snd_pcm_uframes_t count;
@@ -320,14 +322,14 @@
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = 0xffffffff;
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = kirkwood_dma_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
return ret;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
ret = kirkwood_dma_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
@@ -357,27 +359,46 @@
}
}
-struct snd_soc_platform kirkwood_soc_platform = {
- .name = "kirkwood-dma",
- .pcm_ops = &kirkwood_dma_ops,
+static struct snd_soc_platform_driver kirkwood_soc_platform = {
+ .ops = &kirkwood_dma_ops,
.pcm_new = kirkwood_dma_new,
.pcm_free = kirkwood_dma_free_dma_buffers,
};
-EXPORT_SYMBOL_GPL(kirkwood_soc_platform);
-static int __init kirkwood_soc_platform_init(void)
+static int __devinit kirkwood_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&kirkwood_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &kirkwood_soc_platform);
}
-module_init(kirkwood_soc_platform_init);
-static void __exit kirkwood_soc_platform_exit(void)
+static int __devexit kirkwood_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&kirkwood_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
}
-module_exit(kirkwood_soc_platform_exit);
-MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+static struct platform_driver kirkwood_pcm_driver = {
+ .driver = {
+ .name = "kirkwood-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = kirkwood_soc_platform_probe,
+ .remove = __devexit_p(kirkwood_soc_platform_remove),
+};
+
+static int __init kirkwood_pcm_init(void)
+{
+ return platform_driver_register(&kirkwood_pcm_driver);
+}
+module_init(kirkwood_pcm_init);
+
+static void __exit kirkwood_pcm_exit(void)
+{
+ platform_driver_unregister(&kirkwood_pcm_driver);
+}
+module_exit(kirkwood_pcm_exit);
+
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
MODULE_DESCRIPTION("Marvell Kirkwood Audio DMA module");
MODULE_LICENSE("GPL");
-
+MODULE_ALIAS("platform:kirkwood-pcm-audio");
diff --git a/sound/soc/kirkwood/kirkwood-dma.h b/sound/soc/kirkwood/kirkwood-dma.h
deleted file mode 100644
index ba4454c..0000000
--- a/sound/soc/kirkwood/kirkwood-dma.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * kirkwood-dma.h
- *
- * (c) 2010 Arnaud Patard <apatard@mandriva.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; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#ifndef _KIRKWOOD_DMA_H
-#define _KIRKWOOD_DMA_H
-
-extern struct snd_soc_platform kirkwood_soc_platform;
-
-#endif
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c
index 981ffc2..a33fc51 100644
--- a/sound/soc/kirkwood/kirkwood-i2s.c
+++ b/sound/soc/kirkwood/kirkwood-i2s.c
@@ -2,6 +2,7 @@
* kirkwood-i2s.c
*
* (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
*
* 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
@@ -20,7 +21,6 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <plat/audio.h>
-#include "kirkwood-i2s.h"
#include "kirkwood.h"
#define DRV_NAME "kirkwood-i2s"
@@ -33,13 +33,10 @@
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
-
-struct snd_soc_dai kirkwood_i2s_dai;
-static struct kirkwood_dma_data *priv;
-
static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
+ struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(cpu_dai);
unsigned long mask;
unsigned long value;
@@ -101,10 +98,20 @@
} while (value == 0);
}
+static int kirkwood_i2s_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_set_dma_data(dai, substream, priv);
+ return 0;
+}
+
static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
+ struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
unsigned int i2s_reg, reg;
unsigned long i2s_value, value;
@@ -171,6 +178,7 @@
static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
+ struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
unsigned long value;
/*
@@ -244,6 +252,7 @@
static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
+ struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
unsigned long value;
value = readl(priv->io + KIRKWOOD_RECCTL);
@@ -323,9 +332,9 @@
return 0;
}
-static int kirkwood_i2s_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int kirkwood_i2s_probe(struct snd_soc_dai *dai)
{
+ struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
unsigned long value;
unsigned int reg_data;
@@ -359,21 +368,20 @@
}
-static void kirkwood_i2s_remove(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int kirkwood_i2s_remove(struct snd_soc_dai *dai)
{
+ return 0;
}
static struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
+ .startup = kirkwood_i2s_startup,
.trigger = kirkwood_i2s_trigger,
.hw_params = kirkwood_i2s_hw_params,
.set_fmt = kirkwood_i2s_set_fmt,
};
-struct snd_soc_dai kirkwood_i2s_dai = {
- .name = DRV_NAME,
- .id = 0,
+static struct snd_soc_dai_driver kirkwood_i2s_dai = {
.probe = kirkwood_i2s_probe,
.remove = kirkwood_i2s_remove,
.playback = {
@@ -388,13 +396,13 @@
.formats = KIRKWOOD_I2S_FORMATS,},
.ops = &kirkwood_i2s_dai_ops,
};
-EXPORT_SYMBOL_GPL(kirkwood_i2s_dai);
static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
{
struct resource *mem;
struct kirkwood_asoc_platform_data *data =
pdev->dev.platform_data;
+ struct kirkwood_dma_data *priv;
int err;
priv = kzalloc(sizeof(struct kirkwood_dma_data), GFP_KERNEL);
@@ -403,6 +411,7 @@
err = -ENOMEM;
goto error;
}
+ dev_set_drvdata(&pdev->dev, priv);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
@@ -441,10 +450,7 @@
priv->dram = data->dram;
priv->burst = data->burst;
- kirkwood_i2s_dai.capture.dma_data = priv;
- kirkwood_i2s_dai.playback.dma_data = priv;
-
- return snd_soc_register_dai(&kirkwood_i2s_dai);
+ return snd_soc_register_dai(&pdev->dev, &kirkwood_i2s_dai);
err_ioremap:
iounmap(priv->io);
@@ -458,12 +464,13 @@
static __devexit int kirkwood_i2s_dev_remove(struct platform_device *pdev)
{
- if (priv) {
- iounmap(priv->io);
- release_mem_region(priv->mem->start, SZ_16K);
- kfree(priv);
- }
- snd_soc_unregister_dai(&kirkwood_i2s_dai);
+ struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev);
+
+ snd_soc_unregister_dai(&pdev->dev);
+ iounmap(priv->io);
+ release_mem_region(priv->mem->start, SZ_16K);
+ kfree(priv);
+
return 0;
}
@@ -489,7 +496,7 @@
module_exit(kirkwood_i2s_exit);
/* Module information */
-MODULE_AUTHOR("Arnaud Patard, <apatard@mandriva.com>");
+MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>");
MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:kirkwood-i2s");
diff --git a/sound/soc/kirkwood/kirkwood-i2s.h b/sound/soc/kirkwood/kirkwood-i2s.h
deleted file mode 100644
index c5595c6..0000000
--- a/sound/soc/kirkwood/kirkwood-i2s.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * kirkwood-i2s.h
- *
- * (c) 2010 Arnaud Patard <apatard@mandriva.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; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#ifndef _KIRKWOOD_I2S_H
-#define _KIRKWOOD_I2S_H
-
-extern struct snd_soc_dai kirkwood_i2s_dai;
-
-#endif
diff --git a/sound/soc/kirkwood/kirkwood-openrd.c b/sound/soc/kirkwood/kirkwood-openrd.c
index 0353d06..9d7c81e 100644
--- a/sound/soc/kirkwood/kirkwood-openrd.c
+++ b/sound/soc/kirkwood/kirkwood-openrd.c
@@ -2,6 +2,7 @@
* kirkwood-openrd.c
*
* (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
*
* 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
@@ -18,16 +19,14 @@
#include <mach/kirkwood.h>
#include <plat/audio.h>
#include <asm/mach-types.h>
-#include "kirkwood-i2s.h"
-#include "kirkwood-dma.h"
#include "../codecs/cs42l51.h"
static int openrd_client_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
unsigned int freq, fmt;
@@ -66,8 +65,10 @@
{
.name = "CS42L51",
.stream_name = "CS42L51 HiFi",
- .cpu_dai = &kirkwood_i2s_dai,
- .codec_dai = &cs42l51_dai,
+ .cpu_dai_name = "kirkwood-i2s",
+ .platform_name = "kirkwood-pcm-audio",
+ .codec_dai_name = "cs42l51-hifi",
+ .codec_name = "cs42l51-codec.0-004a",
.ops = &openrd_client_ops,
},
};
@@ -75,16 +76,10 @@
static struct snd_soc_card openrd_client = {
.name = "OpenRD Client",
- .platform = &kirkwood_soc_platform,
.dai_link = openrd_client_dai,
.num_links = ARRAY_SIZE(openrd_client_dai),
};
-static struct snd_soc_device openrd_client_snd_devdata = {
- .card = &openrd_client,
- .codec_dev = &soc_codec_device_cs42l51,
-};
-
static struct platform_device *openrd_client_snd_device;
static int __init openrd_client_init(void)
@@ -99,8 +94,7 @@
return -ENOMEM;
platform_set_drvdata(openrd_client_snd_device,
- &openrd_client_snd_devdata);
- openrd_client_snd_devdata.dev = &openrd_client_snd_device->dev;
+ &openrd_client);
ret = platform_device_add(openrd_client_snd_device);
if (ret) {
@@ -120,7 +114,7 @@
module_exit(openrd_client_exit);
/* Module information */
-MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
MODULE_DESCRIPTION("ALSA SoC OpenRD Client");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:soc-audio");
diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c
index caa7c90..293dc74 100644
--- a/sound/soc/nuc900/nuc900-ac97.c
+++ b/sound/soc/nuc900/nuc900-ac97.c
@@ -20,7 +20,6 @@
#include <sound/pcm.h>
#include <sound/initval.h>
#include <sound/soc.h>
-#include <linux/device.h>
#include <linux/clk.h>
#include <mach/mfp.h>
@@ -297,8 +296,7 @@
.trigger = nuc900_ac97_trigger,
};
-struct snd_soc_dai nuc900_ac97_dai = {
- .name = "nuc900-ac97",
+static struct snd_soc_dai_driver nuc900_ac97_dai = {
.probe = nuc900_ac97_probe,
.remove = nuc900_ac97_remove,
.ac97_control = 1,
@@ -316,7 +314,6 @@
},
.ops = &nuc900_ac97_dai_ops,
}
-EXPORT_SYMBOL_GPL(nuc900_ac97_dai);
static int __devinit nuc900_ac97_drvprobe(struct platform_device *pdev)
{
@@ -365,9 +362,7 @@
nuc900_ac97_data = nuc900_audio;
- nuc900_audio->dev = nuc900_ac97_dai.dev = &pdev->dev;
-
- ret = snd_soc_register_dai(&nuc900_ac97_dai);
+ ret = snd_soc_register_dai(&pdev->dev, &nuc900_ac97_dai);
if (ret)
goto out3;
@@ -390,7 +385,7 @@
static int __devexit nuc900_ac97_drvremove(struct platform_device *pdev)
{
- snd_soc_unregister_dai(&nuc900_ac97_dai);
+ snd_soc_unregister_dai(&pdev->dev);
clk_put(nuc900_ac97_data->clk);
iounmap(nuc900_ac97_data->mmio);
@@ -404,7 +399,7 @@
static struct platform_driver nuc900_ac97_driver = {
.driver = {
- .name = "nuc900-audio",
+ .name = "nuc900-ac97",
.owner = THIS_MODULE,
},
.probe = nuc900_ac97_drvprobe,
diff --git a/sound/soc/nuc900/nuc900-audio.c b/sound/soc/nuc900/nuc900-audio.c
index 72e6f51..161f5b6 100644
--- a/sound/soc/nuc900/nuc900-audio.c
+++ b/sound/soc/nuc900/nuc900-audio.c
@@ -20,26 +20,21 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
-#include "../codecs/ac97.h"
#include "nuc900-audio.h"
static struct snd_soc_dai_link nuc900evb_ac97_dai = {
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &nuc900_ac97_dai,
- .codec_dai = &ac97_dai,
+ .cpu_dai_name = "nuc900-ac97",
+ .codec_dai_name = "ac97-hifi",
+ .codec_name = "ac97-codec",
+ .platform_name = "nuc900-pcm-audio",
};
static struct snd_soc_card nuc900evb_audio_machine = {
.name = "NUC900EVB_AC97",
.dai_link = &nuc900evb_ac97_dai,
.num_links = 1,
- .platform = &nuc900_soc_platform,
-};
-
-static struct snd_soc_device nuc900evb_ac97_devdata = {
- .card = &nuc900evb_audio_machine,
- .codec_dev = &soc_codec_dev_ac97,
};
static struct platform_device *nuc900evb_asoc_dev;
@@ -54,9 +49,8 @@
goto out;
/* nuc900 board audio device */
- platform_set_drvdata(nuc900evb_asoc_dev, &nuc900evb_ac97_devdata);
+ platform_set_drvdata(nuc900evb_asoc_dev, &nuc900evb_audio_machine);
- nuc900evb_ac97_devdata.dev = &nuc900evb_asoc_dev->dev;
ret = platform_device_add(nuc900evb_asoc_dev);
if (ret) {
diff --git a/sound/soc/nuc900/nuc900-audio.h b/sound/soc/nuc900/nuc900-audio.h
index 3038f51..aeed8ea 100644
--- a/sound/soc/nuc900/nuc900-audio.h
+++ b/sound/soc/nuc900/nuc900-audio.h
@@ -110,8 +110,4 @@
};
-extern struct nuc900_audio *nuc900_ac97_data;
-extern struct snd_soc_dai nuc900_ac97_dai;
-extern struct snd_soc_platform nuc900_soc_platform;
-
#endif /*end _NUC900_AUDIO_H */
diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c
index e81e803..195d1ac 100644
--- a/sound/soc/nuc900/nuc900-pcm.c
+++ b/sound/soc/nuc900/nuc900-pcm.c
@@ -328,26 +328,44 @@
return 0;
}
-struct snd_soc_platform nuc900_soc_platform = {
- .name = "nuc900-dma",
- .pcm_ops = &nuc900_dma_ops,
+static struct snd_soc_platform_driver nuc900_soc_platform = {
+ .ops = &nuc900_dma_ops,
.pcm_new = nuc900_dma_new,
.pcm_free = nuc900_dma_free_dma_buffers,
}
-EXPORT_SYMBOL_GPL(nuc900_soc_platform);
-static int __init nuc900_soc_platform_init(void)
+static int __devinit nuc900_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&nuc900_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &nuc900_soc_platform);
}
-static void __exit nuc900_soc_platform_exit(void)
+static int __devexit nuc900_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&nuc900_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
}
-module_init(nuc900_soc_platform_init);
-module_exit(nuc900_soc_platform_exit);
+static struct platform_driver nuc900_pcm_driver = {
+ .driver = {
+ .name = "nuc900-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = nuc900_soc_platform_probe,
+ .remove = __devexit_p(nuc900_soc_platform_remove),
+};
+
+static int __init nuc900_pcm_init(void)
+{
+ return platform_driver_register(&nuc900_pcm_driver);
+}
+module_init(nuc900_pcm_init);
+
+static void __exit nuc900_pcm_exit(void)
+{
+ platform_driver_unregister(&nuc900_pcm_driver);
+}
+module_exit(nuc900_pcm_exit);
MODULE_AUTHOR("Wan ZongShun, <mcuos.com@gmail.com>");
MODULE_DESCRIPTION("nuc900 Audio DMA module");
diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c
index 135901b..979dd50 100644
--- a/sound/soc/omap/am3517evm.c
+++ b/sound/soc/omap/am3517evm.c
@@ -40,8 +40,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* Set codec DAI configuration */
@@ -111,8 +111,10 @@
{"MICIN", NULL, "Mic In"},
};
-static int am3517evm_aic23_init(struct snd_soc_codec *codec)
+static int am3517evm_aic23_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
/* Add am3517-evm specific widgets */
snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
ARRAY_SIZE(tlv320aic23_dapm_widgets));
@@ -134,8 +136,10 @@
static struct snd_soc_dai_link am3517evm_dai = {
.name = "TLV320AIC23",
.stream_name = "AIC23",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &tlv320aic23_dai,
+ .cpu_dai_name ="omap-mcbsp-dai.0",
+ .codec_dai_name = "tlv320aic23-hifi",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "tlv320aic23-codec",
.init = am3517evm_aic23_init,
.ops = &am3517evm_ops,
};
@@ -143,27 +147,18 @@
/* Audio machine driver */
static struct snd_soc_card snd_soc_am3517evm = {
.name = "am3517evm",
- .platform = &omap_soc_platform,
.dai_link = &am3517evm_dai,
.num_links = 1,
};
-/* Audio subsystem */
-static struct snd_soc_device am3517evm_snd_devdata = {
- .card = &snd_soc_am3517evm,
- .codec_dev = &soc_codec_dev_tlv320aic23,
-};
-
static struct platform_device *am3517evm_snd_device;
static int __init am3517evm_soc_init(void)
{
int ret;
- if (!machine_is_omap3517evm()) {
- pr_err("Not OMAP3517 / AM3517 EVM!\n");
+ if (!machine_is_omap3517evm())
return -ENODEV;
- }
pr_info("OMAP3517 / AM3517 EVM SoC init\n");
am3517evm_snd_device = platform_device_alloc("soc-audio", -1);
@@ -172,9 +167,7 @@
return -ENOMEM;
}
- platform_set_drvdata(am3517evm_snd_device, &am3517evm_snd_devdata);
- am3517evm_snd_devdata.dev = &am3517evm_snd_device->dev;
- *(unsigned int *)am3517evm_dai.cpu_dai->private_data = 0; /* McBSP1 */
+ platform_set_drvdata(am3517evm_snd_device, &snd_soc_am3517evm);
ret = platform_device_add(am3517evm_snd_device);
if (ret)
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index b0f618e..438146a 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -99,7 +99,7 @@
int pin, changed = 0;
/* Refuse any mode changes if we are not able to control the codec. */
- if (!codec->control_data)
+ if (!codec->hw_write)
return -EUNATCH;
if (ucontrol->value.enumerated.item[0] >= control->max)
@@ -268,10 +268,32 @@
ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_CODEC, 0);
}
+/*
+ * Used for passing a codec structure pointer
+ * from the board initialization code to the tty line discipline.
+ */
+static struct snd_soc_codec *cx20442_codec;
+
/* Line discipline .open() */
static int cx81801_open(struct tty_struct *tty)
{
- return v253_ops.open(tty);
+ int ret;
+
+ if (!cx20442_codec)
+ return -ENODEV;
+
+ /*
+ * Pass the codec structure pointer for use by other ldisc callbacks,
+ * both the card and the codec specific parts.
+ */
+ tty->disc_data = cx20442_codec;
+
+ ret = v253_ops.open(tty);
+
+ if (ret < 0)
+ tty->disc_data = NULL;
+
+ return ret;
}
/* Line discipline .close() */
@@ -281,11 +303,14 @@
del_timer_sync(&cx81801_timer);
- v253_ops.close(tty);
-
/* Prevent the hook switch from further changing the DAPM pins */
INIT_LIST_HEAD(&ams_delta_hook_switch.pins);
+ if (!codec)
+ return;
+
+ v253_ops.close(tty);
+
/* Revert back to default audio input/output constellation */
snd_soc_dapm_disable_pin(codec, "Mouthpiece");
snd_soc_dapm_enable_pin(codec, "Earpiece");
@@ -310,7 +335,10 @@
const unsigned char *c;
int apply, ret;
- if (!codec->control_data) {
+ if (!codec)
+ return;
+
+ if (!codec->hw_write) {
/* First modem response, complete setup procedure */
/* Initialize timer used for config pulse generation */
@@ -323,7 +351,7 @@
ARRAY_SIZE(ams_delta_hook_switch_pins),
ams_delta_hook_switch_pins);
if (ret)
- dev_warn(codec->socdev->card->dev,
+ dev_warn(codec->dev,
"Failed to link hook switch to DAPM pins, "
"will continue with hook switch unlinked.\n");
@@ -383,7 +411,7 @@
struct snd_soc_pcm_runtime *rtd = substream->private_data;
/* Set cpu DAI configuration */
- return snd_soc_dai_set_fmt(rtd->dai->cpu_dai,
+ return snd_soc_dai_set_fmt(rtd->cpu_dai,
SND_SOC_DAIFMT_DSP_A |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM);
@@ -398,7 +426,7 @@
static int ams_delta_set_bias_level(struct snd_soc_card *card,
enum snd_soc_bias_level level)
{
- struct snd_soc_codec *codec = card->codec;
+ struct snd_soc_codec *codec = card->rtd->codec;
switch (level) {
case SND_SOC_BIAS_ON:
@@ -461,18 +489,22 @@
* Card initialization
*/
-static int ams_delta_cx20442_init(struct snd_soc_codec *codec)
+static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *codec_dai = codec->dai;
- struct snd_soc_card *card = codec->socdev->card;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_card *card = rtd->card;
int ret;
/* Codec is ready, now add/activate board specific controls */
+ /* Store a pointer to the codec structure for tty ldisc use */
+ cx20442_codec = codec;
+
/* Set up digital mute if not provided by the codec */
- if (!codec_dai->ops) {
- codec_dai->ops = &ams_delta_dai_ops;
- } else if (!codec_dai->ops->digital_mute) {
- codec_dai->ops->digital_mute = ams_delta_digital_mute;
+ if (!codec_dai->driver->ops) {
+ codec_dai->driver->ops = &ams_delta_dai_ops;
+ } else if (!codec_dai->driver->ops->digital_mute) {
+ codec_dai->driver->ops->digital_mute = ams_delta_digital_mute;
} else {
ams_delta_ops.startup = ams_delta_startup;
ams_delta_ops.shutdown = ams_delta_shutdown;
@@ -483,7 +515,7 @@
/* Add hook switch - can be used to control the codec from userspace
* even if line discipline fails */
- ret = snd_soc_jack_new(card, "hook_switch",
+ ret = snd_soc_jack_new(rtd->codec, "hook_switch",
SND_JACK_HEADSET, &ams_delta_hook_switch);
if (ret)
dev_warn(card->dev,
@@ -551,27 +583,22 @@
static struct snd_soc_dai_link ams_delta_dai_link = {
.name = "CX20442",
.stream_name = "CX20442",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &cx20442_dai,
+ .cpu_dai_name ="omap-mcbsp-dai.0",
+ .codec_dai_name = "cx20442-voice",
.init = ams_delta_cx20442_init,
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "cx20442-codec",
.ops = &ams_delta_ops,
};
/* Audio card driver */
static struct snd_soc_card ams_delta_audio_card = {
.name = "AMS_DELTA",
- .platform = &omap_soc_platform,
.dai_link = &ams_delta_dai_link,
.num_links = 1,
.set_bias_level = ams_delta_set_bias_level,
};
-/* Audio subsystem */
-static struct snd_soc_device ams_delta_snd_soc_device = {
- .card = &ams_delta_audio_card,
- .codec_dev = &cx20442_codec_dev,
-};
-
/* Module init/exit */
static struct platform_device *ams_delta_audio_platform_device;
static struct platform_device *cx20442_platform_device;
@@ -589,9 +616,7 @@
return -ENOMEM;
platform_set_drvdata(ams_delta_audio_platform_device,
- &ams_delta_snd_soc_device);
- ams_delta_snd_soc_device.dev = &ams_delta_audio_platform_device->dev;
- *(unsigned int *)ams_delta_dai_link.cpu_dai->private_data = OMAP_MCBSP1;
+ &ams_delta_audio_card);
ret = platform_device_add(ams_delta_audio_platform_device);
if (ret)
@@ -601,8 +626,8 @@
* Codec platform device could be registered from elsewhere (board?),
* but I do it here as it makes sense only if used with the card.
*/
- cx20442_platform_device = platform_device_register_simple("cx20442",
- -1, NULL, 0);
+ cx20442_platform_device =
+ platform_device_register_simple("cx20442-codec", -1, NULL, 0);
return 0;
err:
platform_device_put(ams_delta_audio_platform_device);
@@ -612,19 +637,6 @@
static void __exit ams_delta_module_exit(void)
{
- struct snd_soc_codec *codec;
- struct tty_struct *tty;
-
- if (ams_delta_audio_card.codec) {
- codec = ams_delta_audio_card.codec;
-
- if (codec->control_data) {
- tty = codec->control_data;
-
- tty_hangup(tty);
- }
- }
-
if (tty_unregister_ldisc(N_V253) != 0)
dev_warn(&ams_delta_audio_platform_device->dev,
"failed to unregister V253 line discipline\n");
diff --git a/sound/soc/omap/igep0020.c b/sound/soc/omap/igep0020.c
index 3583c42..fd3a40f 100644
--- a/sound/soc/omap/igep0020.c
+++ b/sound/soc/omap/igep0020.c
@@ -33,14 +33,13 @@
#include "omap-mcbsp.h"
#include "omap-pcm.h"
-#include "../codecs/twl4030.h"
static int igep2_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* Set codec DAI configuration */
@@ -82,35 +81,28 @@
static struct snd_soc_dai_link igep2_dai = {
.name = "TWL4030",
.stream_name = "TWL4030",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+ .cpu_dai_name = "omap-mcbsp-dai.1",
+ .codec_dai_name = "twl4030-hifi",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "twl4030-codec",
.ops = &igep2_ops,
};
/* Audio machine driver */
static struct snd_soc_card snd_soc_card_igep2 = {
.name = "igep2",
- .platform = &omap_soc_platform,
.dai_link = &igep2_dai,
.num_links = 1,
};
-/* Audio subsystem */
-static struct snd_soc_device igep2_snd_devdata = {
- .card = &snd_soc_card_igep2,
- .codec_dev = &soc_codec_dev_twl4030,
-};
-
static struct platform_device *igep2_snd_device;
static int __init igep2_soc_init(void)
{
int ret;
- if (!machine_is_igep0020()) {
- pr_debug("Not IGEP v2!\n");
+ if (!machine_is_igep0020())
return -ENODEV;
- }
printk(KERN_INFO "IGEP v2 SoC init\n");
igep2_snd_device = platform_device_alloc("soc-audio", -1);
@@ -119,9 +111,7 @@
return -ENOMEM;
}
- platform_set_drvdata(igep2_snd_device, &igep2_snd_devdata);
- igep2_snd_devdata.dev = &igep2_snd_device->dev;
- *(unsigned int *)igep2_dai.cpu_dai->private_data = 1; /* McBSP2 */
+ platform_set_drvdata(igep2_snd_device, &snd_soc_card_igep2);
ret = platform_device_add(igep2_snd_device);
if (ret)
diff --git a/sound/soc/omap/mcpdm.c b/sound/soc/omap/mcpdm.c
index 90b8bf7..928f037 100644
--- a/sound/soc/omap/mcpdm.c
+++ b/sound/soc/omap/mcpdm.c
@@ -402,7 +402,7 @@
return 0;
}
-static int __devinit omap_mcpdm_probe(struct platform_device *pdev)
+int __devinit omap_mcpdm_probe(struct platform_device *pdev)
{
struct resource *res;
int ret = 0;
@@ -449,7 +449,7 @@
return ret;
}
-static int __devexit omap_mcpdm_remove(struct platform_device *pdev)
+int __devexit omap_mcpdm_remove(struct platform_device *pdev)
{
struct omap_mcpdm *mcpdm_ptr = platform_get_drvdata(pdev);
@@ -468,18 +468,3 @@
return 0;
}
-static struct platform_driver omap_mcpdm_driver = {
- .probe = omap_mcpdm_probe,
- .remove = __devexit_p(omap_mcpdm_remove),
- .driver = {
- .name = "omap-mcpdm",
- },
-};
-
-static struct platform_device *omap_mcpdm_device;
-
-static int __init omap_mcpdm_init(void)
-{
- return platform_driver_register(&omap_mcpdm_driver);
-}
-arch_initcall(omap_mcpdm_init);
diff --git a/sound/soc/omap/mcpdm.h b/sound/soc/omap/mcpdm.h
index 7bb326e..df3e16f 100644
--- a/sound/soc/omap/mcpdm.h
+++ b/sound/soc/omap/mcpdm.h
@@ -149,3 +149,5 @@
extern int omap_mcpdm_request(void);
extern void omap_mcpdm_free(void);
extern int omap_mcpdm_set_offset(int offset1, int offset2);
+int __devinit omap_mcpdm_probe(struct platform_device *pdev);
+int __devexit omap_mcpdm_remove(struct platform_device *pdev);
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index 08e09d7..a3b6d89 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -97,7 +97,7 @@
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
@@ -115,8 +115,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int err;
/* Set codec DAI configuration */
@@ -271,8 +271,9 @@
n810_get_input, n810_set_input),
};
-static int n810_aic33_init(struct snd_soc_codec *codec)
+static int n810_aic33_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int err;
/* Not connected */
@@ -307,8 +308,10 @@
static struct snd_soc_dai_link n810_dai = {
.name = "TLV320AIC33",
.stream_name = "AIC33",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &aic3x_dai,
+ .cpu_dai_name = "omap-mcbsp-dai.1",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "tlv320aic3x-codec.2-0018",
+ .codec_dai_name = "tlv320aic3x-hifi",
.init = n810_aic33_init,
.ops = &n810_ops,
};
@@ -316,33 +319,12 @@
/* Audio machine driver */
static struct snd_soc_card snd_soc_n810 = {
.name = "N810",
- .platform = &omap_soc_platform,
.dai_link = &n810_dai,
.num_links = 1,
};
-/* Audio private data */
-static struct aic3x_setup_data n810_aic33_setup = {
- .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
- .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
-};
-
-/* Audio subsystem */
-static struct snd_soc_device n810_snd_devdata = {
- .card = &snd_soc_n810,
- .codec_dev = &soc_codec_dev_aic3x,
- .codec_data = &n810_aic33_setup,
-};
-
static struct platform_device *n810_snd_device;
-/* temporary i2c device creation until this can be moved into the machine
- * support file.
-*/
-static struct i2c_board_info i2c_device[] = {
- { I2C_BOARD_INFO("tlv320aic3x", 0x1b), }
-};
-
static int __init n810_soc_init(void)
{
int err;
@@ -351,15 +333,11 @@
if (!(machine_is_nokia_n810() || machine_is_nokia_n810_wimax()))
return -ENODEV;
- i2c_register_board_info(1, i2c_device, ARRAY_SIZE(i2c_device));
-
n810_snd_device = platform_device_alloc("soc-audio", -1);
if (!n810_snd_device)
return -ENOMEM;
- platform_set_drvdata(n810_snd_device, &n810_snd_devdata);
- n810_snd_devdata.dev = &n810_snd_device->dev;
- *(unsigned int *)n810_dai.cpu_dai->private_data = 1; /* McBSP2 */
+ platform_set_drvdata(n810_snd_device, &snd_soc_n810);
err = platform_device_add(n810_snd_device);
if (err)
goto err1;
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 86f2139..9969618 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -62,8 +62,6 @@
int wlen;
};
-#define to_mcbsp(priv) container_of((priv), struct omap_mcbsp_data, bus_id)
-
static struct omap_mcbsp_data mcbsp_data[NUM_LINKS];
/*
@@ -153,13 +151,13 @@
static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
struct omap_pcm_dma_data *dma_data;
int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id);
int words;
- dma_data = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
/* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
@@ -203,11 +201,9 @@
}
static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
int bus_id = mcbsp_data->bus_id;
int err = 0;
@@ -249,11 +245,9 @@
}
static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
if (!cpu_dai->active) {
omap_mcbsp_free(mcbsp_data->bus_id);
@@ -262,11 +256,9 @@
}
static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
switch (cmd) {
@@ -295,8 +287,8 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
u16 fifo_use;
snd_pcm_sframes_t delay;
@@ -317,11 +309,9 @@
static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
struct omap_pcm_dma_data *dma_data;
int dma, bus_id = mcbsp_data->bus_id;
@@ -496,7 +486,7 @@
static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
- struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
unsigned int temp_fmt = fmt;
@@ -596,7 +586,7 @@
static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
int div_id, int div)
{
- struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
if (div_id != OMAP_MCBSP_CLKGDV)
@@ -699,7 +689,7 @@
int clk_id, unsigned int freq,
int dir)
{
- struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
int err = 0;
@@ -733,7 +723,7 @@
return err;
}
-static struct snd_soc_dai_ops omap_mcbsp_dai_ops = {
+static struct snd_soc_dai_ops mcbsp_dai_ops = {
.startup = omap_mcbsp_dai_startup,
.shutdown = omap_mcbsp_dai_shutdown,
.trigger = omap_mcbsp_dai_trigger,
@@ -744,43 +734,32 @@
.set_sysclk = omap_mcbsp_dai_set_dai_sysclk,
};
-#define OMAP_MCBSP_DAI_BUILDER(link_id) \
-{ \
- .name = "omap-mcbsp-dai-"#link_id, \
- .id = (link_id), \
- .playback = { \
- .channels_min = 1, \
- .channels_max = 16, \
- .rates = OMAP_MCBSP_RATES, \
- .formats = SNDRV_PCM_FMTBIT_S16_LE | \
- SNDRV_PCM_FMTBIT_S32_LE, \
- }, \
- .capture = { \
- .channels_min = 1, \
- .channels_max = 16, \
- .rates = OMAP_MCBSP_RATES, \
- .formats = SNDRV_PCM_FMTBIT_S16_LE | \
- SNDRV_PCM_FMTBIT_S32_LE, \
- }, \
- .ops = &omap_mcbsp_dai_ops, \
- .private_data = &mcbsp_data[(link_id)].bus_id, \
+static int mcbsp_dai_probe(struct snd_soc_dai *dai)
+{
+ mcbsp_data[dai->id].bus_id = dai->id;
+ snd_soc_dai_set_drvdata(dai, &mcbsp_data[dai->id].bus_id);
+ return 0;
}
-struct snd_soc_dai omap_mcbsp_dai[] = {
- OMAP_MCBSP_DAI_BUILDER(0),
- OMAP_MCBSP_DAI_BUILDER(1),
-#if NUM_LINKS >= 3
- OMAP_MCBSP_DAI_BUILDER(2),
-#endif
-#if NUM_LINKS == 5
- OMAP_MCBSP_DAI_BUILDER(3),
- OMAP_MCBSP_DAI_BUILDER(4),
-#endif
+static struct snd_soc_dai_driver omap_mcbsp_dai =
+{
+ .probe = mcbsp_dai_probe,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 16,
+ .rates = OMAP_MCBSP_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 16,
+ .rates = OMAP_MCBSP_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mcbsp_dai_ops,
};
-EXPORT_SYMBOL_GPL(omap_mcbsp_dai);
-
-int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
+static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct soc_mixer_control *mc =
@@ -910,16 +889,36 @@
}
EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls);
+static __devinit int asoc_mcbsp_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_dai(&pdev->dev, &omap_mcbsp_dai);
+}
+
+static int __devexit asoc_mcbsp_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dai(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver asoc_mcbsp_driver = {
+ .driver = {
+ .name = "omap-mcbsp-dai",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = asoc_mcbsp_probe,
+ .remove = __devexit_p(asoc_mcbsp_remove),
+};
+
static int __init snd_omap_mcbsp_init(void)
{
- return snd_soc_register_dais(omap_mcbsp_dai,
- ARRAY_SIZE(omap_mcbsp_dai));
+ return platform_driver_register(&asoc_mcbsp_driver);
}
module_init(snd_omap_mcbsp_init);
static void __exit snd_omap_mcbsp_exit(void)
{
- snd_soc_unregister_dais(omap_mcbsp_dai, ARRAY_SIZE(omap_mcbsp_dai));
+ platform_driver_unregister(&asoc_mcbsp_driver);
}
module_exit(snd_omap_mcbsp_exit);
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h
index 6c363e5..ffdcc5a 100644
--- a/sound/soc/omap/omap-mcbsp.h
+++ b/sound/soc/omap/omap-mcbsp.h
@@ -55,8 +55,6 @@
#define NUM_LINKS 5
#endif
-extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS];
-
int omap_mcbsp_st_add_controls(struct snd_soc_codec *codec, int mcbsp_id);
#endif
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
index b7f4f7e..f161c2f 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -36,7 +36,6 @@
#include <plat/dma.h>
#include <plat/mcbsp.h>
#include "mcpdm.h"
-#include "omap-mcpdm.h"
#include "omap-pcm.h"
struct omap_mcpdm_data {
@@ -89,11 +88,9 @@
static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
int err = 0;
- if (!cpu_dai->active)
+ if (!dai->active)
err = omap_mcpdm_request();
return err;
@@ -102,19 +99,14 @@
static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-
- if (!cpu_dai->active)
+ if (!dai->active)
omap_mcpdm_free();
}
static int omap_mcpdm_dai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct omap_mcpdm_data *mcpdm_priv = cpu_dai->private_data;
+ struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai);
int stream = substream->stream;
int err = 0;
@@ -143,14 +135,12 @@
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct omap_mcpdm_data *mcpdm_priv = cpu_dai->private_data;
+ struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai);
struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links;
int stream = substream->stream;
int channels, err, link_mask = 0;
- snd_soc_dai_set_dma_data(cpu_dai, substream,
+ snd_soc_dai_set_dma_data(dai, substream,
&omap_mcpdm_dai_dma_params[stream]);
channels = params_channels(params);
@@ -189,9 +179,7 @@
static int omap_mcpdm_dai_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct omap_mcpdm_data *mcpdm_priv = cpu_dai->private_data;
+ struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai);
struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links;
int stream = substream->stream;
int err;
@@ -215,9 +203,14 @@
#define OMAP_MCPDM_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
#define OMAP_MCPDM_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
-struct snd_soc_dai omap_mcpdm_dai = {
- .name = "omap-mcpdm",
- .id = -1,
+static int omap_mcpdm_dai_probe(struct snd_soc_dai *dai)
+{
+ snd_soc_dai_set_drvdata(dai, &mcpdm_data);
+ return 0;
+}
+
+static struct snd_soc_dai_driver omap_mcpdm_dai = {
+ .probe = omap_mcpdm_dai_probe,
.playback = {
.channels_min = 1,
.channels_max = 4,
@@ -231,19 +224,47 @@
.formats = OMAP_MCPDM_FORMATS,
},
.ops = &omap_mcpdm_dai_ops,
- .private_data = &mcpdm_data,
};
-EXPORT_SYMBOL_GPL(omap_mcpdm_dai);
+
+static __devinit int asoc_mcpdm_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ ret = omap_mcpdm_probe(pdev);
+ if (ret < 0)
+ return ret;
+ ret = snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai);
+ if (ret < 0)
+ omap_mcpdm_remove(pdev);
+ return ret;
+}
+
+static int __devexit asoc_mcpdm_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dai(&pdev->dev);
+ omap_mcpdm_remove(pdev);
+ return 0;
+}
+
+static struct platform_driver asoc_mcpdm_driver = {
+ .driver = {
+ .name = "omap-mcpdm-dai",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = asoc_mcpdm_probe,
+ .remove = __devexit_p(asoc_mcpdm_remove),
+};
static int __init snd_omap_mcpdm_init(void)
{
- return snd_soc_register_dai(&omap_mcpdm_dai);
+ return platform_driver_register(&asoc_mcpdm_driver);
}
module_init(snd_omap_mcpdm_init);
static void __exit snd_omap_mcpdm_exit(void)
{
- snd_soc_unregister_dai(&omap_mcpdm_dai);
+ platform_driver_unregister(&asoc_mcpdm_driver);
}
module_exit(snd_omap_mcpdm_exit);
diff --git a/sound/soc/omap/omap-mcpdm.h b/sound/soc/omap/omap-mcpdm.h
deleted file mode 100644
index 73b80d5..0000000
--- a/sound/soc/omap/omap-mcpdm.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * omap-mcpdm.h
- *
- * Copyright (C) 2009 Texas Instruments
- *
- * Contact: Misael Lopez Cruz <x0052729@ti.com>
- *
- * 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.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __OMAP_MCPDM_H__
-#define __OMAP_MCPDM_H__
-
-extern struct snd_soc_dai omap_mcpdm_dai;
-
-#endif /* End of __OMAP_MCPDM_H__ */
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index 1e52190..8caeb8d 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -101,9 +101,10 @@
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct omap_runtime_data *prtd = runtime->private_data;
struct omap_pcm_dma_data *dma_data;
+
int err = 0;
- dma_data = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
/* return if this is a bufferless transfer e.g.
* codec <--> BT codec or GSM modem -- lg FIXME */
@@ -374,14 +375,14 @@
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(64);
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = omap_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto out;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
ret = omap_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
@@ -392,25 +393,45 @@
return ret;
}
-struct snd_soc_platform omap_soc_platform = {
- .name = "omap-pcm-audio",
- .pcm_ops = &omap_pcm_ops,
+static struct snd_soc_platform_driver omap_soc_platform = {
+ .ops = &omap_pcm_ops,
.pcm_new = omap_pcm_new,
.pcm_free = omap_pcm_free_dma_buffers,
};
-EXPORT_SYMBOL_GPL(omap_soc_platform);
-static int __init omap_soc_platform_init(void)
+static __devinit int omap_pcm_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&omap_soc_platform);
+ return snd_soc_register_platform(&pdev->dev,
+ &omap_soc_platform);
}
-module_init(omap_soc_platform_init);
-static void __exit omap_soc_platform_exit(void)
+static int __devexit omap_pcm_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&omap_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
}
-module_exit(omap_soc_platform_exit);
+
+static struct platform_driver omap_pcm_driver = {
+ .driver = {
+ .name = "omap-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = omap_pcm_probe,
+ .remove = __devexit_p(omap_pcm_remove),
+};
+
+static int __init snd_omap_pcm_init(void)
+{
+ return platform_driver_register(&omap_pcm_driver);
+}
+module_init(snd_omap_pcm_init);
+
+static void __exit snd_omap_pcm_exit(void)
+{
+ platform_driver_unregister(&omap_pcm_driver);
+}
+module_exit(snd_omap_pcm_exit);
MODULE_AUTHOR("Jarkko Nikula <jhnikula@gmail.com>");
MODULE_DESCRIPTION("OMAP PCM DMA module");
diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h
index b19975d..fea0515 100644
--- a/sound/soc/omap/omap-pcm.h
+++ b/sound/soc/omap/omap-pcm.h
@@ -35,6 +35,4 @@
int packet_size; /* packet size only in PACKET mode */
};
-extern struct snd_soc_platform omap_soc_platform;
-
#endif
diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c
index c7adea3..cf3fc8a 100644
--- a/sound/soc/omap/omap2evm.c
+++ b/sound/soc/omap/omap2evm.c
@@ -35,15 +35,13 @@
#include "omap-mcbsp.h"
#include "omap-pcm.h"
-#include "../codecs/twl4030.h"
static int omap2evm_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+ struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* Set codec DAI configuration */
@@ -85,35 +83,28 @@
static struct snd_soc_dai_link omap2evm_dai = {
.name = "TWL4030",
.stream_name = "TWL4030",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+ .cpu_dai_name = "omap-mcbsp-dai.1",
+ .codec_dai_name = "twl4030-hifi",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "twl4030-codec",
.ops = &omap2evm_ops,
};
/* Audio machine driver */
static struct snd_soc_card snd_soc_omap2evm = {
.name = "omap2evm",
- .platform = &omap_soc_platform,
.dai_link = &omap2evm_dai,
.num_links = 1,
};
-/* Audio subsystem */
-static struct snd_soc_device omap2evm_snd_devdata = {
- .card = &snd_soc_omap2evm,
- .codec_dev = &soc_codec_dev_twl4030,
-};
-
static struct platform_device *omap2evm_snd_device;
static int __init omap2evm_soc_init(void)
{
int ret;
- if (!machine_is_omap2evm()) {
- pr_debug("Not omap2evm!\n");
+ if (!machine_is_omap2evm())
return -ENODEV;
- }
printk(KERN_INFO "omap2evm SoC init\n");
omap2evm_snd_device = platform_device_alloc("soc-audio", -1);
@@ -122,9 +113,7 @@
return -ENOMEM;
}
- platform_set_drvdata(omap2evm_snd_device, &omap2evm_snd_devdata);
- omap2evm_snd_devdata.dev = &omap2evm_snd_device->dev;
- *(unsigned int *)omap2evm_dai.cpu_dai->private_data = 1; /* McBSP2 */
+ platform_set_drvdata(omap2evm_snd_device, &snd_soc_omap2evm);
ret = platform_device_add(omap2evm_snd_device);
if (ret)
diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c
index 240e097..e56832b 100644
--- a/sound/soc/omap/omap3beagle.c
+++ b/sound/soc/omap/omap3beagle.c
@@ -33,14 +33,13 @@
#include "omap-mcbsp.h"
#include "omap-pcm.h"
-#include "../codecs/twl4030.h"
static int omap3beagle_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int fmt;
int ret;
@@ -92,35 +91,29 @@
static struct snd_soc_dai_link omap3beagle_dai = {
.name = "TWL4030",
.stream_name = "TWL4030",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+ .cpu_dai_name = "omap-mcbsp-dai.1",
+ .platform_name = "omap-pcm-audio",
+ .codec_dai_name = "twl4030-hifi",
+ .codec_name = "twl4030-codec",
.ops = &omap3beagle_ops,
};
/* Audio machine driver */
static struct snd_soc_card snd_soc_omap3beagle = {
.name = "omap3beagle",
- .platform = &omap_soc_platform,
+ .owner = THIS_MODULE,
.dai_link = &omap3beagle_dai,
.num_links = 1,
};
-/* Audio subsystem */
-static struct snd_soc_device omap3beagle_snd_devdata = {
- .card = &snd_soc_omap3beagle,
- .codec_dev = &soc_codec_dev_twl4030,
-};
-
static struct platform_device *omap3beagle_snd_device;
static int __init omap3beagle_soc_init(void)
{
int ret;
- if (!(machine_is_omap3_beagle() || machine_is_devkit8000())) {
- pr_debug("Not OMAP3 Beagle or Devkit8000!\n");
+ if (!(machine_is_omap3_beagle() || machine_is_devkit8000()))
return -ENODEV;
- }
pr_info("OMAP3 Beagle/Devkit8000 SoC init\n");
omap3beagle_snd_device = platform_device_alloc("soc-audio", -1);
@@ -129,9 +122,7 @@
return -ENOMEM;
}
- platform_set_drvdata(omap3beagle_snd_device, &omap3beagle_snd_devdata);
- omap3beagle_snd_devdata.dev = &omap3beagle_snd_device->dev;
- *(unsigned int *)omap3beagle_dai.cpu_dai->private_data = 1; /* McBSP2 */
+ platform_set_drvdata(omap3beagle_snd_device, &snd_soc_omap3beagle);
ret = platform_device_add(omap3beagle_snd_device);
if (ret)
diff --git a/sound/soc/omap/omap3evm.c b/sound/soc/omap/omap3evm.c
index dfcb344..810f1e36 100644
--- a/sound/soc/omap/omap3evm.c
+++ b/sound/soc/omap/omap3evm.c
@@ -31,14 +31,13 @@
#include "omap-mcbsp.h"
#include "omap-pcm.h"
-#include "../codecs/twl4030.h"
static int omap3evm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* Set codec DAI configuration */
@@ -80,42 +79,28 @@
static struct snd_soc_dai_link omap3evm_dai = {
.name = "TWL4030",
.stream_name = "TWL4030",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+ .cpu_dai_name = "omap-mcbsp-dai.1",
+ .codec_dai_name = "twl4030-hifi",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "twl4030-codec",
.ops = &omap3evm_ops,
};
/* Audio machine driver */
static struct snd_soc_card snd_soc_omap3evm = {
.name = "omap3evm",
- .platform = &omap_soc_platform,
.dai_link = &omap3evm_dai,
.num_links = 1,
};
-/* twl4030 setup */
-static struct twl4030_setup_data twl4030_setup = {
- .ramp_delay_value = 4,
- .sysclk = 26000,
-};
-
-/* Audio subsystem */
-static struct snd_soc_device omap3evm_snd_devdata = {
- .card = &snd_soc_omap3evm,
- .codec_dev = &soc_codec_dev_twl4030,
- .codec_data = &twl4030_setup,
-};
-
static struct platform_device *omap3evm_snd_device;
static int __init omap3evm_soc_init(void)
{
int ret;
- if (!machine_is_omap3evm()) {
- pr_err("Not OMAP3 EVM!\n");
+ if (!machine_is_omap3evm())
return -ENODEV;
- }
pr_info("OMAP3 EVM SoC init\n");
omap3evm_snd_device = platform_device_alloc("soc-audio", -1);
@@ -124,10 +109,7 @@
return -ENOMEM;
}
- platform_set_drvdata(omap3evm_snd_device, &omap3evm_snd_devdata);
- omap3evm_snd_devdata.dev = &omap3evm_snd_device->dev;
- *(unsigned int *)omap3evm_dai.cpu_dai->private_data = 1;
-
+ platform_set_drvdata(omap3evm_snd_device, &snd_soc_omap3evm);
ret = platform_device_add(omap3evm_snd_device);
if (ret)
goto err1;
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c
index 9eecac1..dbd9d96 100644
--- a/sound/soc/omap/omap3pandora.c
+++ b/sound/soc/omap/omap3pandora.c
@@ -31,10 +31,10 @@
#include <sound/soc-dapm.h>
#include <asm/mach-types.h>
+#include <plat/mcbsp.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
-#include "../codecs/twl4030.h"
#define OMAP3_PANDORA_DAC_POWER_GPIO 118
#define OMAP3_PANDORA_AMP_POWER_GPIO 14
@@ -47,8 +47,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS;
int ret;
@@ -167,8 +167,9 @@
{"Mic Bias 2", NULL, "Mic (external)"},
};
-static int omap3pandora_out_init(struct snd_soc_codec *codec)
+static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int ret;
/* All TWL4030 output pins are floating */
@@ -194,8 +195,9 @@
return snd_soc_dapm_sync(codec);
}
-static int omap3pandora_in_init(struct snd_soc_codec *codec)
+static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int ret;
/* Not comnnected */
@@ -224,15 +226,19 @@
{
.name = "PCM1773",
.stream_name = "HiFi Out",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+ .cpu_dai_name = "omap-mcbsp-dai.1",
+ .codec_dai_name = "twl4030-hifi",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "twl4030-codec",
.ops = &omap3pandora_ops,
.init = omap3pandora_out_init,
}, {
.name = "TWL4030",
.stream_name = "Line/Mic In",
- .cpu_dai = &omap_mcbsp_dai[1],
- .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+ .cpu_dai_name = "omap-mcbsp-dai.3",
+ .codec_dai_name = "twl4030-hifi",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "twl4030-codec",
.ops = &omap3pandora_ops,
.init = omap3pandora_in_init,
}
@@ -241,17 +247,10 @@
/* SoC card */
static struct snd_soc_card snd_soc_card_omap3pandora = {
.name = "omap3pandora",
- .platform = &omap_soc_platform,
.dai_link = omap3pandora_dai,
.num_links = ARRAY_SIZE(omap3pandora_dai),
};
-/* Audio subsystem */
-static struct snd_soc_device omap3pandora_snd_data = {
- .card = &snd_soc_card_omap3pandora,
- .codec_dev = &soc_codec_dev_twl4030,
-};
-
static struct platform_device *omap3pandora_snd_device;
static int __init omap3pandora_soc_init(void)
@@ -294,10 +293,7 @@
goto fail1;
}
- platform_set_drvdata(omap3pandora_snd_device, &omap3pandora_snd_data);
- omap3pandora_snd_data.dev = &omap3pandora_snd_device->dev;
- *(unsigned int *)omap_mcbsp_dai[0].private_data = 1; /* McBSP2 */
- *(unsigned int *)omap_mcbsp_dai[1].private_data = 3; /* McBSP4 */
+ platform_set_drvdata(omap3pandora_snd_device, &snd_soc_card_omap3pandora);
ret = platform_device_add(omap3pandora_snd_device);
if (ret) {
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c
index 498ca2e..f0e6625 100644
--- a/sound/soc/omap/osk5912.c
+++ b/sound/soc/omap/osk5912.c
@@ -55,8 +55,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int err;
/* Set codec DAI configuration */
@@ -113,8 +113,9 @@
{"MICIN", NULL, "Mic Jack"},
};
-static int osk_tlv320aic23_init(struct snd_soc_codec *codec)
+static int osk_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
/* Add osk5912 specific widgets */
snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
@@ -136,8 +137,10 @@
static struct snd_soc_dai_link osk_dai = {
.name = "TLV320AIC23",
.stream_name = "AIC23",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &tlv320aic23_dai,
+ .cpu_dai_name = "omap-mcbsp-dai.0",
+ .codec_dai_name = "tlv320aic23-hifi",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "tlv320aic23-codec",
.init = osk_tlv320aic23_init,
.ops = &osk_ops,
};
@@ -145,17 +148,10 @@
/* Audio machine driver */
static struct snd_soc_card snd_soc_card_osk = {
.name = "OSK5912",
- .platform = &omap_soc_platform,
.dai_link = &osk_dai,
.num_links = 1,
};
-/* Audio subsystem */
-static struct snd_soc_device osk_snd_devdata = {
- .card = &snd_soc_card_osk,
- .codec_dev = &soc_codec_dev_tlv320aic23,
-};
-
static struct platform_device *osk_snd_device;
static int __init osk_soc_init(void)
@@ -171,9 +167,7 @@
if (!osk_snd_device)
return -ENOMEM;
- platform_set_drvdata(osk_snd_device, &osk_snd_devdata);
- osk_snd_devdata.dev = &osk_snd_device->dev;
- *(unsigned int *)osk_dai.cpu_dai->private_data = 0; /* McBSP1 */
+ platform_set_drvdata(osk_snd_device, &snd_soc_card_osk);
err = platform_device_add(osk_snd_device);
if (err)
goto err1;
diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c
index c25f527..e95a607 100644
--- a/sound/soc/omap/overo.c
+++ b/sound/soc/omap/overo.c
@@ -33,14 +33,13 @@
#include "omap-mcbsp.h"
#include "omap-pcm.h"
-#include "../codecs/twl4030.h"
static int overo_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* Set codec DAI configuration */
@@ -82,25 +81,20 @@
static struct snd_soc_dai_link overo_dai = {
.name = "TWL4030",
.stream_name = "TWL4030",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+ .cpu_dai_name = "omap-mcbsp-dai.1",
+ .codec_dai_name = "twl4030-hifi",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "twl4030-codec",
.ops = &overo_ops,
};
/* Audio machine driver */
static struct snd_soc_card snd_soc_card_overo = {
.name = "overo",
- .platform = &omap_soc_platform,
.dai_link = &overo_dai,
.num_links = 1,
};
-/* Audio subsystem */
-static struct snd_soc_device overo_snd_devdata = {
- .card = &snd_soc_card_overo,
- .codec_dev = &soc_codec_dev_twl4030,
-};
-
static struct platform_device *overo_snd_device;
static int __init overo_soc_init(void)
@@ -119,9 +113,7 @@
return -ENOMEM;
}
- platform_set_drvdata(overo_snd_device, &overo_snd_devdata);
- overo_snd_devdata.dev = &overo_snd_device->dev;
- *(unsigned int *)overo_dai.cpu_dai->private_data = 1; /* McBSP2 */
+ platform_set_drvdata(overo_snd_device, &snd_soc_card_overo);
ret = platform_device_add(overo_snd_device);
if (ret)
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index 88052d2..04b5723 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -31,6 +31,7 @@
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
+#include <plat/mcbsp.h>
#include <asm/mach-types.h>
@@ -76,7 +77,7 @@
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
@@ -89,8 +90,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int err;
/* Set codec DAI configuration */
@@ -145,9 +146,9 @@
struct snd_kcontrol *k, int event)
{
if (SND_SOC_DAPM_EVENT_ON(event))
- gpio_set_value(RX51_SPEAKER_AMP_TWL_GPIO, 1);
+ gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 1);
else
- gpio_set_value(RX51_SPEAKER_AMP_TWL_GPIO, 0);
+ gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 0);
return 0;
}
@@ -240,9 +241,9 @@
rx51_get_jack, rx51_set_jack),
};
-static int rx51_aic34_init(struct snd_soc_codec *codec)
+static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_card *card = codec->socdev->card;
+ struct snd_soc_codec *codec = rtd->codec;
int err;
/* Set up NC codec pins */
@@ -266,7 +267,7 @@
snd_soc_dapm_sync(codec);
/* AV jack detection */
- err = snd_soc_jack_new(card, "AV Jack",
+ err = snd_soc_jack_new(codec, "AV Jack",
SND_JACK_VIDEOOUT, &rx51_av_jack);
if (err)
return err;
@@ -282,32 +283,20 @@
{
.name = "TLV320AIC34",
.stream_name = "AIC34",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &aic3x_dai,
+ .cpu_dai_name = "omap-mcbsp-dai.1",
+ .codec_dai_name = "tlv320aic3x-hifi",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "tlv320aic3x-codec.2-0018",
.init = rx51_aic34_init,
.ops = &rx51_ops,
},
};
-/* Audio private data */
-static struct aic3x_setup_data rx51_aic34_setup = {
- .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
- .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
-};
-
/* Audio card */
static struct snd_soc_card rx51_sound_card = {
.name = "RX-51",
.dai_link = rx51_dai,
.num_links = ARRAY_SIZE(rx51_dai),
- .platform = &omap_soc_platform,
-};
-
-/* Audio subsystem */
-static struct snd_soc_device rx51_snd_devdata = {
- .card = &rx51_sound_card,
- .codec_dev = &soc_codec_dev_aic3x,
- .codec_data = &rx51_aic34_setup,
};
static struct platform_device *rx51_snd_device;
@@ -330,9 +319,7 @@
goto err1;
}
- platform_set_drvdata(rx51_snd_device, &rx51_snd_devdata);
- rx51_snd_devdata.dev = &rx51_snd_device->dev;
- *(unsigned int *)rx51_dai[0].cpu_dai->private_data = 1; /* McBSP2 */
+ platform_set_drvdata(rx51_snd_device, &rx51_sound_card);
err = platform_device_add(rx51_snd_device);
if (err)
diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
index 3c85c0f..07fbcf7 100644
--- a/sound/soc/omap/sdp3430.c
+++ b/sound/soc/omap/sdp3430.c
@@ -36,9 +36,11 @@
#include <mach/gpio.h>
#include <plat/mcbsp.h>
+/* Register descriptions for twl4030 codec part */
+#include <linux/mfd/twl4030-codec.h>
+
#include "omap-mcbsp.h"
#include "omap-pcm.h"
-#include "../codecs/twl4030.h"
/* TWL4030 PMBR1 Register */
#define TWL4030_INTBR_PMBR1 0x0D
@@ -51,8 +53,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* Set codec DAI configuration */
@@ -94,8 +96,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* Set codec DAI configuration */
@@ -186,8 +188,9 @@
{"Headset Stereophone", NULL, "HSOR"},
};
-static int sdp3430_twl4030_init(struct snd_soc_codec *codec)
+static int sdp3430_twl4030_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int ret;
/* Add SDP3430 specific widgets */
@@ -225,7 +228,7 @@
return ret;
/* Headset jack detection */
- ret = snd_soc_jack_new(&snd_soc_sdp3430, "Headset Jack",
+ ret = snd_soc_jack_new(codec, "Headset Jack",
SND_JACK_HEADSET, &hs_jack);
if (ret)
return ret;
@@ -241,14 +244,15 @@
return ret;
}
-static int sdp3430_twl4030_voice_init(struct snd_soc_codec *codec)
+static int sdp3430_twl4030_voice_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
unsigned short reg;
/* Enable voice interface */
- reg = codec->read(codec, TWL4030_REG_VOICE_IF);
+ reg = codec->driver->read(codec, TWL4030_REG_VOICE_IF);
reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN;
- codec->write(codec, TWL4030_REG_VOICE_IF, reg);
+ codec->driver->write(codec, TWL4030_REG_VOICE_IF, reg);
return 0;
}
@@ -259,16 +263,20 @@
{
.name = "TWL4030 I2S",
.stream_name = "TWL4030 Audio",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+ .cpu_dai_name = "omap-mcbsp-dai.1",
+ .codec_dai_name = "twl4030-hifi",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "twl4030-codec",
.init = sdp3430_twl4030_init,
.ops = &sdp3430_ops,
},
{
.name = "TWL4030 PCM",
.stream_name = "TWL4030 Voice",
- .cpu_dai = &omap_mcbsp_dai[1],
- .codec_dai = &twl4030_dai[TWL4030_DAI_VOICE],
+ .cpu_dai_name = "omap-mcbsp-dai.2",
+ .codec_dai_name = "twl4030-voice",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "twl4030-codec",
.init = sdp3430_twl4030_voice_init,
.ops = &sdp3430_voice_ops,
},
@@ -277,25 +285,10 @@
/* Audio machine driver */
static struct snd_soc_card snd_soc_sdp3430 = {
.name = "SDP3430",
- .platform = &omap_soc_platform,
.dai_link = sdp3430_dai,
.num_links = ARRAY_SIZE(sdp3430_dai),
};
-/* twl4030 setup */
-static struct twl4030_setup_data twl4030_setup = {
- .ramp_delay_value = 3,
- .sysclk = 26000,
- .hs_extmute = 1,
-};
-
-/* Audio subsystem */
-static struct snd_soc_device sdp3430_snd_devdata = {
- .card = &snd_soc_sdp3430,
- .codec_dev = &soc_codec_dev_twl4030,
- .codec_data = &twl4030_setup,
-};
-
static struct platform_device *sdp3430_snd_device;
static int __init sdp3430_soc_init(void)
@@ -303,10 +296,8 @@
int ret;
u8 pin_mux;
- if (!machine_is_omap_3430sdp()) {
- pr_debug("Not SDP3430!\n");
+ if (!machine_is_omap_3430sdp())
return -ENODEV;
- }
printk(KERN_INFO "SDP3430 SoC init\n");
sdp3430_snd_device = platform_device_alloc("soc-audio", -1);
@@ -315,10 +306,7 @@
return -ENOMEM;
}
- platform_set_drvdata(sdp3430_snd_device, &sdp3430_snd_devdata);
- sdp3430_snd_devdata.dev = &sdp3430_snd_device->dev;
- *(unsigned int *)sdp3430_dai[0].cpu_dai->private_data = 1; /* McBSP2 */
- *(unsigned int *)sdp3430_dai[1].cpu_dai->private_data = 2; /* McBSP3 */
+ platform_set_drvdata(sdp3430_snd_device, &snd_soc_sdp3430);
/* Set TWL4030 GPIO6 as EXTMUTE signal */
twl_i2c_read_u8(TWL4030_MODULE_INTBR, &pin_mux,
diff --git a/sound/soc/omap/sdp4430.c b/sound/soc/omap/sdp4430.c
index 4ebbde6..4b4463d 100644
--- a/sound/soc/omap/sdp4430.c
+++ b/sound/soc/omap/sdp4430.c
@@ -31,7 +31,6 @@
#include <plat/mux.h>
#include "mcpdm.h"
-#include "omap-mcpdm.h"
#include "omap-pcm.h"
#include "../codecs/twl6040.h"
@@ -41,7 +40,7 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
int clk_id, freq;
int ret;
@@ -60,6 +59,7 @@
printk(KERN_ERR "can't set codec system clock\n");
return ret;
}
+ return ret;
}
static struct snd_soc_ops sdp4430_ops = {
@@ -126,8 +126,9 @@
{"Earphone Spk", NULL, "EP"},
};
-static int sdp4430_twl6040_init(struct snd_soc_codec *codec)
+static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int ret;
/* Add SDP4430 specific controls */
@@ -164,8 +165,10 @@
static struct snd_soc_dai_link sdp4430_dai = {
.name = "TWL6040",
.stream_name = "TWL6040",
- .cpu_dai = &omap_mcpdm_dai,
- .codec_dai = &twl6040_dai,
+ .cpu_dai_name ="omap-mcpdm-dai",
+ .codec_dai_name = "twl6040-hifi",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "twl6040-codec",
.init = sdp4430_twl6040_init,
.ops = &sdp4430_ops,
};
@@ -173,27 +176,18 @@
/* Audio machine driver */
static struct snd_soc_card snd_soc_sdp4430 = {
.name = "SDP4430",
- .platform = &omap_soc_platform,
.dai_link = &sdp4430_dai,
.num_links = 1,
};
-/* Audio subsystem */
-static struct snd_soc_device sdp4430_snd_devdata = {
- .card = &snd_soc_sdp4430,
- .codec_dev = &soc_codec_dev_twl6040,
-};
-
static struct platform_device *sdp4430_snd_device;
static int __init sdp4430_soc_init(void)
{
int ret;
- if (!machine_is_omap_4430sdp()) {
- pr_debug("Not SDP4430!\n");
+ if (!machine_is_omap_4430sdp())
return -ENODEV;
- }
printk(KERN_INFO "SDP4430 SoC init\n");
sdp4430_snd_device = platform_device_alloc("soc-audio", -1);
@@ -202,8 +196,7 @@
return -ENOMEM;
}
- platform_set_drvdata(sdp4430_snd_device, &sdp4430_snd_devdata);
- sdp4430_snd_devdata.dev = &sdp4430_snd_device->dev;
+ platform_set_drvdata(sdp4430_snd_device, &snd_soc_sdp4430);
ret = platform_device_add(sdp4430_snd_device);
if (ret)
diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c
index 50a94ee7..718031e 100644
--- a/sound/soc/omap/zoom2.c
+++ b/sound/soc/omap/zoom2.c
@@ -29,21 +29,23 @@
#include <asm/mach-types.h>
#include <mach/hardware.h>
#include <mach/gpio.h>
+#include <mach/board-zoom.h>
#include <plat/mcbsp.h>
+/* Register descriptions for twl4030 codec part */
+#include <linux/mfd/twl4030-codec.h>
+
#include "omap-mcbsp.h"
#include "omap-pcm.h"
-#include "../codecs/twl4030.h"
#define ZOOM2_HEADSET_MUX_GPIO (OMAP_MAX_GPIO_LINES + 15)
-#define ZOOM2_HEADSET_EXTMUTE_GPIO 153
static int zoom2_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* Set codec DAI configuration */
@@ -85,8 +87,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* Set codec DAI configuration */
@@ -157,8 +159,9 @@
{"Aux In", NULL, "AUXR"},
};
-static int zoom2_twl4030_init(struct snd_soc_codec *codec)
+static int zoom2_twl4030_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int ret;
/* Add Zoom2 specific widgets */
@@ -192,14 +195,15 @@
return ret;
}
-static int zoom2_twl4030_voice_init(struct snd_soc_codec *codec)
+static int zoom2_twl4030_voice_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
unsigned short reg;
/* Enable voice interface */
- reg = codec->read(codec, TWL4030_REG_VOICE_IF);
+ reg = codec->driver->read(codec, TWL4030_REG_VOICE_IF);
reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN;
- codec->write(codec, TWL4030_REG_VOICE_IF, reg);
+ codec->driver->write(codec, TWL4030_REG_VOICE_IF, reg);
return 0;
}
@@ -209,16 +213,20 @@
{
.name = "TWL4030 I2S",
.stream_name = "TWL4030 Audio",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+ .cpu_dai_name = "omap-mcbsp-dai.1",
+ .codec_dai_name = "twl4030-hifi",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "twl4030-codec",
.init = zoom2_twl4030_init,
.ops = &zoom2_ops,
},
{
.name = "TWL4030 PCM",
.stream_name = "TWL4030 Voice",
- .cpu_dai = &omap_mcbsp_dai[1],
- .codec_dai = &twl4030_dai[TWL4030_DAI_VOICE],
+ .cpu_dai_name = "omap-mcbsp-dai.2",
+ .codec_dai_name = "twl4030-voice",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "twl4030-codec",
.init = zoom2_twl4030_voice_init,
.ops = &zoom2_voice_ops,
},
@@ -227,42 +235,18 @@
/* Audio machine driver */
static struct snd_soc_card snd_soc_zoom2 = {
.name = "Zoom2",
- .platform = &omap_soc_platform,
.dai_link = zoom2_dai,
.num_links = ARRAY_SIZE(zoom2_dai),
};
-/* EXTMUTE callback function */
-void zoom2_set_hs_extmute(int mute)
-{
- gpio_set_value(ZOOM2_HEADSET_EXTMUTE_GPIO, mute);
-}
-
-/* twl4030 setup */
-static struct twl4030_setup_data twl4030_setup = {
- .ramp_delay_value = 3, /* 161 ms */
- .sysclk = 26000,
- .hs_extmute = 1,
- .set_hs_extmute = zoom2_set_hs_extmute,
-};
-
-/* Audio subsystem */
-static struct snd_soc_device zoom2_snd_devdata = {
- .card = &snd_soc_zoom2,
- .codec_dev = &soc_codec_dev_twl4030,
- .codec_data = &twl4030_setup,
-};
-
static struct platform_device *zoom2_snd_device;
static int __init zoom2_soc_init(void)
{
int ret;
- if (!machine_is_omap_zoom2()) {
- pr_debug("Not Zoom2!\n");
+ if (!machine_is_omap_zoom2())
return -ENODEV;
- }
printk(KERN_INFO "Zoom2 SoC init\n");
zoom2_snd_device = platform_device_alloc("soc-audio", -1);
@@ -271,11 +255,7 @@
return -ENOMEM;
}
- platform_set_drvdata(zoom2_snd_device, &zoom2_snd_devdata);
- zoom2_snd_devdata.dev = &zoom2_snd_device->dev;
- *(unsigned int *)zoom2_dai[0].cpu_dai->private_data = 1; /* McBSP2 */
- *(unsigned int *)zoom2_dai[1].cpu_dai->private_data = 2; /* McBSP3 */
-
+ platform_set_drvdata(zoom2_snd_device, &snd_soc_zoom2);
ret = platform_device_add(zoom2_snd_device);
if (ret)
goto err1;
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index e30c832..37f191b 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -117,6 +117,24 @@
Say Y if you want to add support for SoC audio on
Palm T|X, T5, E2 or LifeDrive handheld computer.
+config SND_SOC_SAARB
+ tristate "SoC Audio support for Marvell Saarb"
+ depends on SND_PXA2XX_SOC && MACH_SAARB
+ select SND_PXA_SOC_SSP
+ select SND_SOC_88PM860X
+ help
+ Say Y if you want to add support for SoC audio on the
+ Marvell Saarb reference platform.
+
+config SND_SOC_TAVOREVB3
+ tristate "SoC Audio support for Marvell Tavor EVB3"
+ depends on SND_PXA2XX_SOC && MACH_TAVOREVB3
+ select SND_PXA_SOC_SSP
+ select SND_SOC_88PM860X
+ help
+ Say Y if you want to add support for SoC audio on the
+ Marvell Saarb reference platform.
+
config SND_SOC_ZYLONITE
tristate "SoC Audio support for Marvell Zylonite"
depends on SND_PXA2XX_SOC && MACH_ZYLONITE
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile
index caa03d8..0766016 100644
--- a/sound/soc/pxa/Makefile
+++ b/sound/soc/pxa/Makefile
@@ -19,6 +19,8 @@
snd-soc-spitz-objs := spitz.o
snd-soc-em-x270-objs := em-x270.o
snd-soc-palm27x-objs := palm27x.o
+snd-soc-saarb-objs := saarb.o
+snd-soc-tavorevb3-objs := tavorevb3.o
snd-soc-zylonite-objs := zylonite.o
snd-soc-magician-objs := magician.o
snd-soc-mioa701-objs := mioa701_wm9713.o
@@ -38,6 +40,8 @@
obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o
obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
obj-$(CONFIG_SND_PXA2XX_SOC_Z2) += snd-soc-z2.o
+obj-$(CONFIG_SND_SOC_SAARB) += snd-soc-saarb.o
+obj-$(CONFIG_SND_SOC_TAVOREVB3) += snd-soc-tavorevb3.o
obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o
obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c
index fefe1a5..97e9423 100644
--- a/sound/soc/pxa/corgi.c
+++ b/sound/soc/pxa/corgi.c
@@ -30,7 +30,6 @@
#include <mach/audio.h>
#include "../codecs/wm8731.h"
-#include "pxa2xx-pcm.h"
#include "pxa2xx-i2s.h"
#define CORGI_HP 0
@@ -99,7 +98,7 @@
static int corgi_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
/* check the jack status at stream startup */
corgi_ext_control(codec);
@@ -118,8 +117,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int clk = 0;
int ret = 0;
@@ -150,7 +149,7 @@
return ret;
/* set the codec system clock for DAC and ADC */
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, clk,
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk,
SND_SOC_CLOCK_IN);
if (ret < 0)
return ret;
@@ -272,8 +271,9 @@
/*
* Logic for a wm8731 as connected on a Sharp SL-C7x0 Device
*/
-static int corgi_wm8731_init(struct snd_soc_codec *codec)
+static int corgi_wm8731_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int err;
snd_soc_dapm_nc_pin(codec, "LLINEIN");
@@ -300,8 +300,10 @@
static struct snd_soc_dai_link corgi_dai = {
.name = "WM8731",
.stream_name = "WM8731",
- .cpu_dai = &pxa_i2s_dai,
- .codec_dai = &wm8731_dai,
+ .cpu_dai_name = "pxa-is2-dai",
+ .codec_dai_name = "wm8731-hifi",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm8731-codec-0.001a",
.init = corgi_wm8731_init,
.ops = &corgi_ops,
};
@@ -309,17 +311,10 @@
/* corgi audio machine driver */
static struct snd_soc_card snd_soc_corgi = {
.name = "Corgi",
- .platform = &pxa2xx_soc_platform,
.dai_link = &corgi_dai,
.num_links = 1,
};
-/* corgi audio subsystem */
-static struct snd_soc_device corgi_snd_devdata = {
- .card = &snd_soc_corgi,
- .codec_dev = &soc_codec_dev_wm8731,
-};
-
static struct platform_device *corgi_snd_device;
static int __init corgi_init(void)
@@ -334,8 +329,7 @@
if (!corgi_snd_device)
return -ENOMEM;
- platform_set_drvdata(corgi_snd_device, &corgi_snd_devdata);
- corgi_snd_devdata.dev = &corgi_snd_device->dev;
+ platform_set_drvdata(corgi_snd_device, &snd_soc_corgi);
ret = platform_device_add(corgi_snd_device);
if (ret)
diff --git a/sound/soc/pxa/e740_wm9705.c b/sound/soc/pxa/e740_wm9705.c
index 7cd2f89..c82cedb 100644
--- a/sound/soc/pxa/e740_wm9705.c
+++ b/sound/soc/pxa/e740_wm9705.c
@@ -24,7 +24,6 @@
#include <asm/mach-types.h>
#include "../codecs/wm9705.h"
-#include "pxa2xx-pcm.h"
#include "pxa2xx-ac97.h"
@@ -90,8 +89,10 @@
{"Mic Amp", NULL, "Mic (Internal)"},
};
-static int e740_ac97_init(struct snd_soc_codec *codec)
+static int e740_ac97_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
snd_soc_dapm_nc_pin(codec, "HPOUTL");
snd_soc_dapm_nc_pin(codec, "HPOUTR");
snd_soc_dapm_nc_pin(codec, "PHONE");
@@ -116,30 +117,28 @@
{
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
- .codec_dai = &wm9705_dai[WM9705_DAI_AC97_HIFI],
+ .cpu_dai_name = "pxa-ac97.0",
+ .codec_dai_name = "wm9705-hifi",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm9705-codec",
.init = e740_ac97_init,
},
{
.name = "AC97 Aux",
.stream_name = "AC97 Aux",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
- .codec_dai = &wm9705_dai[WM9705_DAI_AC97_AUX],
+ .cpu_dai_name = "pxa-ac97.1",
+ .codec_dai_name = "wm9705-aux",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm9705-codec",
},
};
static struct snd_soc_card e740 = {
.name = "Toshiba e740",
- .platform = &pxa2xx_soc_platform,
.dai_link = e740_dai,
.num_links = ARRAY_SIZE(e740_dai),
};
-static struct snd_soc_device e740_snd_devdata = {
- .card = &e740,
- .codec_dev = &soc_codec_dev_wm9705,
-};
-
static struct platform_device *e740_snd_device;
static int __init e740_init(void)
@@ -178,8 +177,7 @@
goto free_apwr_gpio;
}
- platform_set_drvdata(e740_snd_device, &e740_snd_devdata);
- e740_snd_devdata.dev = &e740_snd_device->dev;
+ platform_set_drvdata(e740_snd_device, &e740);
ret = platform_device_add(e740_snd_device);
if (!ret)
@@ -200,6 +198,9 @@
static void __exit e740_exit(void)
{
platform_device_unregister(e740_snd_device);
+ gpio_free(GPIO_E740_WM9705_nAVDD2);
+ gpio_free(GPIO_E740_AMP_ON);
+ gpio_free(GPIO_E740_MIC_ON);
}
module_init(e740_init);
diff --git a/sound/soc/pxa/e750_wm9705.c b/sound/soc/pxa/e750_wm9705.c
index 8dceccc..4c14380 100644
--- a/sound/soc/pxa/e750_wm9705.c
+++ b/sound/soc/pxa/e750_wm9705.c
@@ -24,7 +24,6 @@
#include <asm/mach-types.h>
#include "../codecs/wm9705.h"
-#include "pxa2xx-pcm.h"
#include "pxa2xx-ac97.h"
static int e750_spk_amp_event(struct snd_soc_dapm_widget *w,
@@ -72,8 +71,10 @@
{"MIC1", NULL, "Mic (Internal)"},
};
-static int e750_ac97_init(struct snd_soc_codec *codec)
+static int e750_ac97_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
snd_soc_dapm_nc_pin(codec, "LOUT");
snd_soc_dapm_nc_pin(codec, "ROUT");
snd_soc_dapm_nc_pin(codec, "PHONE");
@@ -98,31 +99,29 @@
{
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
- .codec_dai = &wm9705_dai[WM9705_DAI_AC97_HIFI],
+ .cpu_dai_name = "pxa-ac97.0",
+ .codec_dai_name = "wm9705-hifi",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm9705-codec",
.init = e750_ac97_init,
/* use ops to check startup state */
},
{
.name = "AC97 Aux",
.stream_name = "AC97 Aux",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
- .codec_dai = &wm9705_dai[WM9705_DAI_AC97_AUX],
+ .cpu_dai_name = "pxa-ac97.1",
+ .codec_dai_name ="wm9705-aux",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm9705-codec",
},
};
static struct snd_soc_card e750 = {
.name = "Toshiba e750",
- .platform = &pxa2xx_soc_platform,
.dai_link = e750_dai,
.num_links = ARRAY_SIZE(e750_dai),
};
-static struct snd_soc_device e750_snd_devdata = {
- .card = &e750,
- .codec_dev = &soc_codec_dev_wm9705,
-};
-
static struct platform_device *e750_snd_device;
static int __init e750_init(void)
@@ -154,8 +153,7 @@
goto free_spk_amp_gpio;
}
- platform_set_drvdata(e750_snd_device, &e750_snd_devdata);
- e750_snd_devdata.dev = &e750_snd_device->dev;
+ platform_set_drvdata(e750_snd_device, &e750);
ret = platform_device_add(e750_snd_device);
if (!ret)
diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c
index bc019cd..d42e5fe 100644
--- a/sound/soc/pxa/e800_wm9712.c
+++ b/sound/soc/pxa/e800_wm9712.c
@@ -23,7 +23,6 @@
#include <mach/eseries-gpio.h>
#include "../codecs/wm9712.h"
-#include "pxa2xx-pcm.h"
#include "pxa2xx-ac97.h"
static int e800_spk_amp_event(struct snd_soc_dapm_widget *w,
@@ -73,8 +72,10 @@
{"MIC2", NULL, "Mic (Internal2)"},
};
-static int e800_ac97_init(struct snd_soc_codec *codec)
+static int e800_ac97_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
snd_soc_dapm_new_controls(codec, e800_dapm_widgets,
ARRAY_SIZE(e800_dapm_widgets));
@@ -88,30 +89,28 @@
{
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
- .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+ .cpu_dai_name = "pxa-ac97.0",
+ .codec_dai_name = "wm9712-hifi",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm9712-codec",
.init = e800_ac97_init,
},
{
.name = "AC97 Aux",
.stream_name = "AC97 Aux",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
- .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+ .cpu_dai_name = "pxa-ac97.1",
+ .codec_dai_name ="wm9712-aux",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm9712-codec",
},
};
static struct snd_soc_card e800 = {
.name = "Toshiba e800",
- .platform = &pxa2xx_soc_platform,
.dai_link = e800_dai,
.num_links = ARRAY_SIZE(e800_dai),
};
-static struct snd_soc_device e800_snd_devdata = {
- .card = &e800,
- .codec_dev = &soc_codec_dev_wm9712,
-};
-
static struct platform_device *e800_snd_device;
static int __init e800_init(void)
@@ -141,8 +140,7 @@
if (!e800_snd_device)
return -ENOMEM;
- platform_set_drvdata(e800_snd_device, &e800_snd_devdata);
- e800_snd_devdata.dev = &e800_snd_device->dev;
+ platform_set_drvdata(e800_snd_device, &e800);
ret = platform_device_add(e800_snd_device);
if (!ret)
diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c
index f4756e4..eadf9d3 100644
--- a/sound/soc/pxa/em-x270.c
+++ b/sound/soc/pxa/em-x270.c
@@ -32,36 +32,33 @@
#include <mach/audio.h>
#include "../codecs/wm9712.h"
-#include "pxa2xx-pcm.h"
#include "pxa2xx-ac97.h"
static struct snd_soc_dai_link em_x270_dai[] = {
{
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
- .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+ .cpu_dai_name = "pxa-ac97.0",
+ .codec_dai_name = "wm9712-hifi",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm9712-codec",
},
{
.name = "AC97 Aux",
.stream_name = "AC97 Aux",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
- .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+ .cpu_dai_name = "pxa-ac97.1",
+ .codec_dai_name ="wm9712-aux",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm9712-codec",
},
};
static struct snd_soc_card em_x270 = {
.name = "EM-X270",
- .platform = &pxa2xx_soc_platform,
.dai_link = em_x270_dai,
.num_links = ARRAY_SIZE(em_x270_dai),
};
-static struct snd_soc_device em_x270_snd_devdata = {
- .card = &em_x270,
- .codec_dev = &soc_codec_dev_wm9712,
-};
-
static struct platform_device *em_x270_snd_device;
static int __init em_x270_init(void)
@@ -76,8 +73,7 @@
if (!em_x270_snd_device)
return -ENOMEM;
- platform_set_drvdata(em_x270_snd_device, &em_x270_snd_devdata);
- em_x270_snd_devdata.dev = &em_x270_snd_device->dev;
+ platform_set_drvdata(em_x270_snd_device, &em_x270);
ret = platform_device_add(em_x270_snd_device);
if (ret)
diff --git a/sound/soc/pxa/imote2.c b/sound/soc/pxa/imote2.c
index 405587a..154fc6f 100644
--- a/sound/soc/pxa/imote2.c
+++ b/sound/soc/pxa/imote2.c
@@ -6,14 +6,13 @@
#include "../codecs/wm8940.h"
#include "pxa2xx-i2s.h"
-#include "pxa2xx-pcm.h"
static int imote2_asoc_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int clk = 0;
int ret;
@@ -64,23 +63,19 @@
static struct snd_soc_dai_link imote2_dai = {
.name = "WM8940",
.stream_name = "WM8940",
- .cpu_dai = &pxa_i2s_dai,
- .codec_dai = &wm8940_dai,
+ .cpu_dai_name = "pxa2xx-i2s",
+ .codec_dai_name = "wm8940-hifi",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm8940-codec.0-0034",
.ops = &imote2_asoc_ops,
};
static struct snd_soc_card snd_soc_imote2 = {
.name = "Imote2",
- .platform = &pxa2xx_soc_platform,
.dai_link = &imote2_dai,
.num_links = 1,
};
-static struct snd_soc_device imote2_snd_devdata = {
- .card = &snd_soc_imote2,
- .codec_dev = &soc_codec_dev_wm8940,
-};
-
static struct platform_device *imote2_snd_device;
static int __init imote2_asoc_init(void)
@@ -93,8 +88,7 @@
if (!imote2_snd_device)
return -ENOMEM;
- platform_set_drvdata(imote2_snd_device, &imote2_snd_devdata);
- imote2_snd_devdata.dev = &imote2_snd_device->dev;
+ platform_set_drvdata(imote2_snd_device, &snd_soc_imote2);
ret = platform_device_add(imote2_snd_device);
if (ret)
platform_device_put(imote2_snd_device);
diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c
index 4c8d99a..b8207ce 100644
--- a/sound/soc/pxa/magician.c
+++ b/sound/soc/pxa/magician.c
@@ -32,7 +32,6 @@
#include <mach/magician.h>
#include <asm/mach-types.h>
#include "../codecs/uda1380.h"
-#include "pxa2xx-pcm.h"
#include "pxa2xx-i2s.h"
#include "pxa-ssp.h"
@@ -71,7 +70,7 @@
static int magician_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
/* check the jack status at stream startup */
magician_ext_control(codec);
@@ -86,8 +85,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int acps, acds, width, rate;
unsigned int div4 = PXA_SSP_CLK_SCDB_4;
int ret = 0;
@@ -227,8 +226,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret = 0;
/* set codec DAI configuration */
@@ -393,8 +392,9 @@
/*
* Logic for a uda1380 as connected on a HTC Magician
*/
-static int magician_uda1380_init(struct snd_soc_codec *codec)
+static int magician_uda1380_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int err;
/* NC codec pins */
@@ -427,16 +427,20 @@
{
.name = "uda1380",
.stream_name = "UDA1380 Playback",
- .cpu_dai = &pxa_ssp_dai[PXA_DAI_SSP1],
- .codec_dai = &uda1380_dai[UDA1380_DAI_PLAYBACK],
+ .cpu_dai_name = "pxa-ssp-dai.0",
+ .codec_dai_name = "uda1380-hifi-playback",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "uda1380-codec.0-0018",
.init = magician_uda1380_init,
.ops = &magician_playback_ops,
},
{
.name = "uda1380",
.stream_name = "UDA1380 Capture",
- .cpu_dai = &pxa_i2s_dai,
- .codec_dai = &uda1380_dai[UDA1380_DAI_CAPTURE],
+ .cpu_dai_name = "pxa2xx-i2s",
+ .codec_dai_name = "uda1380-hifi-capture",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "uda1380-codec.0-0018",
.ops = &magician_capture_ops,
}
};
@@ -446,13 +450,7 @@
.name = "Magician",
.dai_link = magician_dai,
.num_links = ARRAY_SIZE(magician_dai),
- .platform = &pxa2xx_soc_platform,
-};
-/* magician audio subsystem */
-static struct snd_soc_device magician_snd_devdata = {
- .card = &snd_soc_card_magician,
- .codec_dev = &soc_codec_dev_uda1380,
};
static struct platform_device *magician_snd_device;
@@ -514,8 +512,7 @@
goto err_pdev;
}
- platform_set_drvdata(magician_snd_device, &magician_snd_devdata);
- magician_snd_devdata.dev = &magician_snd_device->dev;
+ platform_set_drvdata(magician_snd_device, &snd_soc_card_magician);
ret = platform_device_add(magician_snd_device);
if (ret) {
platform_device_put(magician_snd_device);
diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c
index 19eda8b..f284cc5 100644
--- a/sound/soc/pxa/mioa701_wm9713.c
+++ b/sound/soc/pxa/mioa701_wm9713.c
@@ -54,7 +54,6 @@
#include <sound/initval.h>
#include <sound/ac97_codec.h>
-#include "pxa2xx-pcm.h"
#include "pxa2xx-ac97.h"
#include "../codecs/wm9713.h"
@@ -128,8 +127,9 @@
{"Rear Speaker", NULL, "SPKR"},
};
-static int mioa701_wm9713_init(struct snd_soc_codec *codec)
+static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
unsigned short reg;
/* Add mioa701 specific widgets */
@@ -139,12 +139,12 @@
snd_soc_dapm_add_routes(codec, ARRAY_AND_SIZE(audio_map));
/* Prepare GPIO8 for rear speaker amplifier */
- reg = codec->read(codec, AC97_GPIO_CFG);
- codec->write(codec, AC97_GPIO_CFG, reg | 0x0100);
+ reg = codec->driver->read(codec, AC97_GPIO_CFG);
+ codec->driver->write(codec, AC97_GPIO_CFG, reg | 0x0100);
/* Prepare MIC input */
- reg = codec->read(codec, AC97_3D_CONTROL);
- codec->write(codec, AC97_3D_CONTROL, reg | 0xc000);
+ reg = codec->driver->read(codec, AC97_3D_CONTROL);
+ codec->driver->write(codec, AC97_3D_CONTROL, reg | 0xc000);
snd_soc_dapm_enable_pin(codec, "Front Speaker");
snd_soc_dapm_enable_pin(codec, "Rear Speaker");
@@ -162,32 +162,30 @@
{
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
- .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI],
+ .cpu_dai_name = "pxa-ac97.0",
+ .codec_dai_name = "wm9713-hifi",
+ .codec_name = "wm9713-codec",
.init = mioa701_wm9713_init,
+ .platform_name = "pxa-pcm-audio",
.ops = &mioa701_ops,
},
{
.name = "AC97 Aux",
.stream_name = "AC97 Aux",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
- .codec_dai = &wm9713_dai[WM9713_DAI_AC97_AUX],
+ .cpu_dai_name = "pxa-ac97.1",
+ .codec_dai_name ="wm9713-aux",
+ .codec_name = "wm9713-codec",
+ .platform_name = "pxa-pcm-audio",
.ops = &mioa701_ops,
},
};
static struct snd_soc_card mioa701 = {
.name = "MioA701",
- .platform = &pxa2xx_soc_platform,
.dai_link = mioa701_dai,
.num_links = ARRAY_SIZE(mioa701_dai),
};
-static struct snd_soc_device mioa701_snd_devdata = {
- .card = &mioa701,
- .codec_dev = &soc_codec_dev_wm9713,
-};
-
static struct platform_device *mioa701_snd_device;
static int mioa701_wm9713_probe(struct platform_device *pdev)
@@ -205,8 +203,7 @@
if (!mioa701_snd_device)
return -ENOMEM;
- platform_set_drvdata(mioa701_snd_device, &mioa701_snd_devdata);
- mioa701_snd_devdata.dev = &mioa701_snd_device->dev;
+ platform_set_drvdata(mioa701_snd_device, &mioa701);
ret = platform_device_add(mioa701_snd_device);
if (!ret)
diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c
index 1f96e32..13f6d48 100644
--- a/sound/soc/pxa/palm27x.c
+++ b/sound/soc/pxa/palm27x.c
@@ -29,7 +29,6 @@
#include <mach/palmasoc.h>
#include "../codecs/wm9712.h"
-#include "pxa2xx-pcm.h"
#include "pxa2xx-ac97.h"
static struct snd_soc_jack hs_jack;
@@ -75,8 +74,9 @@
static struct snd_soc_card palm27x_asoc;
-static int palm27x_ac97_init(struct snd_soc_codec *codec)
+static int palm27x_ac97_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int err;
/* add palm27x specific widgets */
@@ -112,7 +112,7 @@
return err;
/* Jack detection API stuff */
- err = snd_soc_jack_new(&palm27x_asoc, "Headphone Jack",
+ err = snd_soc_jack_new(codec, "Headphone Jack",
SND_JACK_HEADPHONE, &hs_jack);
if (err)
return err;
@@ -132,30 +132,28 @@
{
.name = "AC97 HiFi",
.stream_name = "AC97 HiFi",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
- .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+ .cpu_dai_name = "pxa-ac97.0",
+ .codec_dai_name = "wm9712-hifi",
+ .codec_name = "wm9712-codec",
+ .platform_name = "pxa-pcm-audio",
.init = palm27x_ac97_init,
},
{
.name = "AC97 Aux",
.stream_name = "AC97 Aux",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
- .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+ .cpu_dai_name = "pxa-ac97.1",
+ .codec_dai_name = "wm9712-aux",
+ .codec_name = "wm9712-codec",
+ .platform_name = "pxa-pcm-audio",
},
};
static struct snd_soc_card palm27x_asoc = {
.name = "Palm/PXA27x",
- .platform = &pxa2xx_soc_platform,
.dai_link = palm27x_dai,
.num_links = ARRAY_SIZE(palm27x_dai),
};
-static struct snd_soc_device palm27x_snd_devdata = {
- .card = &palm27x_asoc,
- .codec_dev = &soc_codec_dev_wm9712,
-};
-
static struct platform_device *palm27x_snd_device;
static int palm27x_asoc_probe(struct platform_device *pdev)
@@ -178,8 +176,7 @@
if (!palm27x_snd_device)
return -ENOMEM;
- platform_set_drvdata(palm27x_snd_device, &palm27x_snd_devdata);
- palm27x_snd_devdata.dev = &palm27x_snd_device->dev;
+ platform_set_drvdata(palm27x_snd_device, &palm27x_asoc);
ret = platform_device_add(palm27x_snd_device);
if (ret != 0)
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c
index c5f36e0..af84ee9 100644
--- a/sound/soc/pxa/poodle.c
+++ b/sound/soc/pxa/poodle.c
@@ -31,7 +31,6 @@
#include <mach/audio.h>
#include "../codecs/wm8731.h"
-#include "pxa2xx-pcm.h"
#include "pxa2xx-i2s.h"
#define POODLE_HP 1
@@ -76,7 +75,7 @@
static int poodle_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
/* check the jack status at stream startup */
poodle_ext_control(codec);
@@ -97,8 +96,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int clk = 0;
int ret = 0;
@@ -129,7 +128,7 @@
return ret;
/* set the codec system clock for DAC and ADC */
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, clk,
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk,
SND_SOC_CLOCK_IN);
if (ret < 0)
return ret;
@@ -237,8 +236,9 @@
/*
* Logic for a wm8731 as connected on a Sharp SL-C7x0 Device
*/
-static int poodle_wm8731_init(struct snd_soc_codec *codec)
+static int poodle_wm8731_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int err;
snd_soc_dapm_nc_pin(codec, "LLINEIN");
@@ -266,8 +266,10 @@
static struct snd_soc_dai_link poodle_dai = {
.name = "WM8731",
.stream_name = "WM8731",
- .cpu_dai = &pxa_i2s_dai,
- .codec_dai = &wm8731_dai,
+ .cpu_dai_name = "pxa2xx-i2s",
+ .codec_dai_name = "wm8731-hifi",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm8731-codec.0-001a",
.init = poodle_wm8731_init,
.ops = &poodle_ops,
};
@@ -275,15 +277,9 @@
/* poodle audio machine driver */
static struct snd_soc_card snd_soc_poodle = {
.name = "Poodle",
- .platform = &pxa2xx_soc_platform,
.dai_link = &poodle_dai,
.num_links = 1,
-};
-
-/* poodle audio subsystem */
-static struct snd_soc_device poodle_snd_devdata = {
- .card = &snd_soc_poodle,
- .codec_dev = &soc_codec_dev_wm8731,
+ .owner = THIS_MODULE,
};
static struct platform_device *poodle_snd_device;
@@ -307,8 +303,7 @@
if (!poodle_snd_device)
return -ENOMEM;
- platform_set_drvdata(poodle_snd_device, &poodle_snd_devdata);
- poodle_snd_devdata.dev = &poodle_snd_device->dev;
+ platform_set_drvdata(poodle_snd_device, &snd_soc_poodle);
ret = platform_device_add(poodle_snd_device);
if (ret)
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index a1fd23e..b439eee 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -35,7 +35,7 @@
#include <mach/audio.h>
#include <plat/ssp.h>
-#include "pxa2xx-pcm.h"
+#include "../../arm/pxa2xx-pcm.h"
#include "pxa-ssp.h"
/*
@@ -108,11 +108,9 @@
}
static int pxa_ssp_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
int ret = 0;
@@ -128,11 +126,9 @@
}
static void pxa_ssp_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
if (!cpu_dai->active) {
@@ -148,7 +144,7 @@
static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai)
{
- struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
if (!cpu_dai->active)
@@ -166,7 +162,7 @@
static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai)
{
- struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
uint32_t sssr = SSSR_ROR | SSSR_TUR | SSSR_BCE;
@@ -230,7 +226,7 @@
static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
{
- struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
int val;
@@ -287,7 +283,7 @@
static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
int div_id, int div)
{
- struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
int val;
@@ -338,7 +334,7 @@
static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
int source, unsigned int freq_in, unsigned int freq_out)
{
- struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
u32 ssacd = pxa_ssp_read_reg(ssp, SSACD) & ~0x70;
@@ -407,7 +403,7 @@
static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
{
- struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
u32 sscr0;
@@ -442,7 +438,7 @@
static int pxa_ssp_set_dai_tristate(struct snd_soc_dai *cpu_dai,
int tristate)
{
- struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
u32 sscr1;
@@ -464,11 +460,9 @@
static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
- struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
- u32 sscr0;
- u32 sscr1;
- u32 sspsp;
+ u32 sscr0, sscr1, sspsp, scfr;
/* check if we need to change anything at all */
if (priv->dai_fmt == fmt)
@@ -483,16 +477,16 @@
/* reset port settings */
sscr0 = pxa_ssp_read_reg(ssp, SSCR0) &
- (SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
+ ~(SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
sscr1 = SSCR1_RxTresh(8) | SSCR1_TxTresh(7);
sspsp = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
- sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR;
+ sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR | SSCR1_SCFR;
break;
case SND_SOC_DAIFMT_CBM_CFS:
- sscr1 |= SSCR1_SCLKDIR;
+ sscr1 |= SSCR1_SCLKDIR | SSCR1_SCFR;
break;
case SND_SOC_DAIFMT_CBS_CFS:
break;
@@ -538,6 +532,17 @@
pxa_ssp_write_reg(ssp, SSCR1, sscr1);
pxa_ssp_write_reg(ssp, SSPSP, sspsp);
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBM_CFS:
+ scfr = pxa_ssp_read_reg(ssp, SSCR1) | SSCR1_SCFR;
+ pxa_ssp_write_reg(ssp, SSCR1, scfr);
+
+ while (pxa_ssp_read_reg(ssp, SSSR) & SSSR_BSY)
+ cpu_relax();
+ break;
+ }
+
dump_registers(ssp);
/* Since we are configuring the timings for the format by hand
@@ -555,11 +560,9 @@
*/
static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
int chn = params_channels(params);
u32 sscr0;
@@ -568,7 +571,7 @@
int ttsa = pxa_ssp_read_reg(ssp, SSTSA) & 0xf;
struct pxa2xx_pcm_dma_params *dma_data;
- dma_data = snd_soc_dai_get_dma_data(dai, substream);
+ dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
/* generate correct DMA params */
kfree(dma_data);
@@ -581,7 +584,7 @@
((chn == 2) && (ttsa != 1)) || (width == 32),
substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
- snd_soc_dai_set_dma_data(dai, substream, dma_data);
+ snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
/* we can only change the settings if the port is not in use */
if (pxa_ssp_read_reg(ssp, SSCR0) & SSCR0_SSE)
@@ -589,10 +592,8 @@
/* clear selected SSP bits */
sscr0 = pxa_ssp_read_reg(ssp, SSCR0) & ~(SSCR0_DSS | SSCR0_EDSS);
- pxa_ssp_write_reg(ssp, SSCR0, sscr0);
/* bit size */
- sscr0 = pxa_ssp_read_reg(ssp, SSCR0);
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
#ifdef CONFIG_PXA3xx
@@ -668,12 +669,10 @@
}
static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
int ret = 0;
- struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
int val;
@@ -729,8 +728,7 @@
return ret;
}
-static int pxa_ssp_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int pxa_ssp_probe(struct snd_soc_dai *dai)
{
struct ssp_priv *priv;
int ret;
@@ -746,7 +744,7 @@
}
priv->dai_fmt = (unsigned int) -1;
- dai->private_data = priv;
+ snd_soc_dai_set_drvdata(dai, priv);
return 0;
@@ -755,11 +753,13 @@
return ret;
}
-static void pxa_ssp_remove(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int pxa_ssp_remove(struct snd_soc_dai *dai)
{
- struct ssp_priv *priv = dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(dai);
+
pxa_ssp_free(priv->ssp);
+ kfree(priv);
+ return 0;
}
#define PXA_SSP_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
@@ -784,10 +784,7 @@
.set_tristate = pxa_ssp_set_dai_tristate,
};
-struct snd_soc_dai pxa_ssp_dai[] = {
- {
- .name = "pxa2xx-ssp1",
- .id = 0,
+static struct snd_soc_dai_driver pxa_ssp_dai = {
.probe = pxa_ssp_probe,
.remove = pxa_ssp_remove,
.suspend = pxa_ssp_suspend,
@@ -805,81 +802,38 @@
.formats = PXA_SSP_FORMATS,
},
.ops = &pxa_ssp_dai_ops,
- },
- { .name = "pxa2xx-ssp2",
- .id = 1,
- .probe = pxa_ssp_probe,
- .remove = pxa_ssp_remove,
- .suspend = pxa_ssp_suspend,
- .resume = pxa_ssp_resume,
- .playback = {
- .channels_min = 1,
- .channels_max = 8,
- .rates = PXA_SSP_RATES,
- .formats = PXA_SSP_FORMATS,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 8,
- .rates = PXA_SSP_RATES,
- .formats = PXA_SSP_FORMATS,
- },
- .ops = &pxa_ssp_dai_ops,
- },
- {
- .name = "pxa2xx-ssp3",
- .id = 2,
- .probe = pxa_ssp_probe,
- .remove = pxa_ssp_remove,
- .suspend = pxa_ssp_suspend,
- .resume = pxa_ssp_resume,
- .playback = {
- .channels_min = 1,
- .channels_max = 8,
- .rates = PXA_SSP_RATES,
- .formats = PXA_SSP_FORMATS,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 8,
- .rates = PXA_SSP_RATES,
- .formats = PXA_SSP_FORMATS,
- },
- .ops = &pxa_ssp_dai_ops,
- },
- {
- .name = "pxa2xx-ssp4",
- .id = 3,
- .probe = pxa_ssp_probe,
- .remove = pxa_ssp_remove,
- .suspend = pxa_ssp_suspend,
- .resume = pxa_ssp_resume,
- .playback = {
- .channels_min = 1,
- .channels_max = 8,
- .rates = PXA_SSP_RATES,
- .formats = PXA_SSP_FORMATS,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 8,
- .rates = PXA_SSP_RATES,
- .formats = PXA_SSP_FORMATS,
- },
- .ops = &pxa_ssp_dai_ops,
- },
};
-EXPORT_SYMBOL_GPL(pxa_ssp_dai);
+
+static __devinit int asoc_ssp_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_dai(&pdev->dev, &pxa_ssp_dai);
+}
+
+static int __devexit asoc_ssp_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dai(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver asoc_ssp_driver = {
+ .driver = {
+ .name = "pxa-ssp-dai",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = asoc_ssp_probe,
+ .remove = __devexit_p(asoc_ssp_remove),
+};
static int __init pxa_ssp_init(void)
{
- return snd_soc_register_dais(pxa_ssp_dai, ARRAY_SIZE(pxa_ssp_dai));
+ return platform_driver_register(&asoc_ssp_driver);
}
module_init(pxa_ssp_init);
static void __exit pxa_ssp_exit(void)
{
- snd_soc_unregister_dais(pxa_ssp_dai, ARRAY_SIZE(pxa_ssp_dai));
+ platform_driver_unregister(&asoc_ssp_driver);
}
module_exit(pxa_ssp_exit);
diff --git a/sound/soc/pxa/pxa-ssp.h b/sound/soc/pxa/pxa-ssp.h
index 91deadd..bc79da2 100644
--- a/sound/soc/pxa/pxa-ssp.h
+++ b/sound/soc/pxa/pxa-ssp.h
@@ -42,6 +42,4 @@
#define PXA_SSP_PLL_OUT 0
-extern struct snd_soc_dai pxa_ssp_dai[4];
-
#endif
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index d314115..ac51c6d 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -24,7 +24,6 @@
#include <mach/dma.h>
#include <mach/audio.h>
-#include "pxa2xx-pcm.h"
#include "pxa2xx-ac97.h"
static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97)
@@ -104,24 +103,21 @@
#define pxa2xx_ac97_resume NULL
#endif
-static int pxa2xx_ac97_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int pxa2xx_ac97_probe(struct snd_soc_dai *dai)
{
return pxa2xx_ac97_hw_probe(to_platform_device(dai->dev));
}
-static void pxa2xx_ac97_remove(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int pxa2xx_ac97_remove(struct snd_soc_dai *dai)
{
pxa2xx_ac97_hw_remove(to_platform_device(dai->dev));
+ return 0;
}
static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
struct pxa2xx_pcm_dma_params *dma_data;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -136,10 +132,8 @@
static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
struct pxa2xx_pcm_dma_params *dma_data;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -154,11 +148,8 @@
static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
return -ENODEV;
else
@@ -188,10 +179,9 @@
* There is only 1 physical AC97 interface for pxa2xx, but it
* has extra fifo's that can be used for aux DACs and ADCs.
*/
-struct snd_soc_dai pxa_ac97_dai[] = {
+static struct snd_soc_dai_driver pxa_ac97_dai[] = {
{
.name = "pxa2xx-ac97",
- .id = 0,
.ac97_control = 1,
.probe = pxa2xx_ac97_probe,
.remove = pxa2xx_ac97_remove,
@@ -213,7 +203,6 @@
},
{
.name = "pxa2xx-ac97-aux",
- .id = 1,
.ac97_control = 1,
.playback = {
.stream_name = "AC97 Aux Playback",
@@ -231,7 +220,6 @@
},
{
.name = "pxa2xx-ac97-mic",
- .id = 2,
.ac97_control = 1,
.capture = {
.stream_name = "AC97 Mic Capture",
@@ -243,36 +231,26 @@
},
};
-EXPORT_SYMBOL_GPL(pxa_ac97_dai);
EXPORT_SYMBOL_GPL(soc_ac97_ops);
-static int __devinit pxa2xx_ac97_dev_probe(struct platform_device *pdev)
+static __devinit int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
{
- int i;
- pxa2xx_audio_ops_t *pdata = pdev->dev.platform_data;
-
- if (pdev->id >= 0) {
+ if (pdev->id != -1) {
dev_err(&pdev->dev, "PXA2xx has only one AC97 port.\n");
return -ENXIO;
}
- for (i = 0; i < ARRAY_SIZE(pxa_ac97_dai); i++) {
- pxa_ac97_dai[i].dev = &pdev->dev;
- if (pdata && pdata->codec_pdata[0])
- pxa_ac97_dai[i].ac97_pdata = pdata->codec_pdata[0];
- }
-
/* Punt most of the init to the SoC probe; we may need the machine
* driver to do interesting things with the clocking to get us up
* and running.
*/
- return snd_soc_register_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai));
+ return snd_soc_register_dais(&pdev->dev, pxa_ac97_dai,
+ ARRAY_SIZE(pxa_ac97_dai));
}
static int __devexit pxa2xx_ac97_dev_remove(struct platform_device *pdev)
{
- snd_soc_unregister_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai));
-
+ snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(pxa_ac97_dai));
return 0;
}
diff --git a/sound/soc/pxa/pxa2xx-ac97.h b/sound/soc/pxa/pxa2xx-ac97.h
index e390de8..eda891e 100644
--- a/sound/soc/pxa/pxa2xx-ac97.h
+++ b/sound/soc/pxa/pxa2xx-ac97.h
@@ -14,8 +14,6 @@
#define PXA2XX_DAI_AC97_AUX 1
#define PXA2XX_DAI_AC97_MIC 2
-extern struct snd_soc_dai pxa_ac97_dai[3];
-
/* platform data */
extern struct snd_ac97_bus_ops pxa2xx_ac97_ops;
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index c1a52757..11be595 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -27,7 +27,6 @@
#include <mach/dma.h>
#include <mach/audio.h>
-#include "pxa2xx-pcm.h"
#include "pxa2xx-i2s.h"
/*
@@ -80,6 +79,7 @@
};
static struct pxa_i2s_port pxa_i2s;
static struct clk *clk_i2s;
+static int clk_ena = 0;
static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = {
.name = "I2S PCM Stereo out",
@@ -101,7 +101,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
if (IS_ERR(clk_i2s))
return PTR_ERR(clk_i2s);
@@ -162,13 +162,11 @@
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
struct pxa2xx_pcm_dma_params *dma_data;
BUG_ON(IS_ERR(clk_i2s));
clk_enable(clk_i2s);
- dai->private_data = dai;
+ clk_ena = 1;
pxa_i2s_wait();
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -176,7 +174,7 @@
else
dma_data = &pxa2xx_i2s_pcm_stereo_in;
- snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
+ snd_soc_dai_set_dma_data(dai, substream, dma_data);
/* is port used by another stream */
if (!(SACR0 & SACR0_ENB)) {
@@ -259,9 +257,9 @@
if ((SACR1 & (SACR1_DREC | SACR1_DRPL)) == (SACR1_DREC | SACR1_DRPL)) {
SACR0 &= ~SACR0_ENB;
pxa_i2s_wait();
- if (dai->private_data != NULL) {
+ if (clk_ena) {
clk_disable(clk_i2s);
- dai->private_data = NULL;
+ clk_ena = 0;
}
}
}
@@ -300,6 +298,35 @@
#define pxa2xx_i2s_resume NULL
#endif
+static int pxa2xx_i2s_probe(struct snd_soc_dai *dai)
+{
+ clk_i2s = clk_get(dai->dev, "I2SCLK");
+ if (IS_ERR(clk_i2s))
+ return PTR_ERR(clk_i2s);
+
+ /*
+ * PXA Developer's Manual:
+ * If SACR0[ENB] is toggled in the middle of a normal operation,
+ * the SACR0[RST] bit must also be set and cleared to reset all
+ * I2S controller registers.
+ */
+ SACR0 = SACR0_RST;
+ SACR0 = 0;
+ /* Make sure RPL and REC are disabled */
+ SACR1 = SACR1_DRPL | SACR1_DREC;
+ /* Along with FIFO servicing */
+ SAIMR &= ~(SAIMR_RFS | SAIMR_TFS);
+
+ return 0;
+}
+
+static int pxa2xx_i2s_remove(struct snd_soc_dai *dai)
+{
+ clk_put(clk_i2s);
+ clk_i2s = ERR_PTR(-ENOENT);
+ return 0;
+}
+
#define PXA2XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
@@ -313,9 +340,9 @@
.set_sysclk = pxa2xx_i2s_set_dai_sysclk,
};
-struct snd_soc_dai pxa_i2s_dai = {
- .name = "pxa2xx-i2s",
- .id = 0,
+static struct snd_soc_dai_driver pxa_i2s_dai = {
+ .probe = pxa2xx_i2s_probe,
+ .remove = pxa2xx_i2s_remove,
.suspend = pxa2xx_i2s_suspend,
.resume = pxa2xx_i2s_resume,
.playback = {
@@ -332,49 +359,20 @@
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(pxa_i2s_dai);
-
-static int pxa2xx_i2s_probe(struct platform_device *dev)
+static int pxa2xx_i2s_drv_probe(struct platform_device *pdev)
{
- int ret;
-
- clk_i2s = clk_get(&dev->dev, "I2SCLK");
- if (IS_ERR(clk_i2s))
- return PTR_ERR(clk_i2s);
-
- pxa_i2s_dai.dev = &dev->dev;
- pxa_i2s_dai.private_data = NULL;
- ret = snd_soc_register_dai(&pxa_i2s_dai);
- if (ret != 0)
- clk_put(clk_i2s);
-
- /*
- * PXA Developer's Manual:
- * If SACR0[ENB] is toggled in the middle of a normal operation,
- * the SACR0[RST] bit must also be set and cleared to reset all
- * I2S controller registers.
- */
- SACR0 = SACR0_RST;
- SACR0 = 0;
- /* Make sure RPL and REC are disabled */
- SACR1 = SACR1_DRPL | SACR1_DREC;
- /* Along with FIFO servicing */
- SAIMR &= ~(SAIMR_RFS | SAIMR_TFS);
-
- return ret;
+ return snd_soc_register_dai(&pdev->dev, &pxa_i2s_dai);
}
-static int __devexit pxa2xx_i2s_remove(struct platform_device *dev)
+static int __devexit pxa2xx_i2s_drv_remove(struct platform_device *pdev)
{
- snd_soc_unregister_dai(&pxa_i2s_dai);
- clk_put(clk_i2s);
- clk_i2s = ERR_PTR(-ENOENT);
+ snd_soc_unregister_dai(&pdev->dev);
return 0;
}
static struct platform_driver pxa2xx_i2s_driver = {
- .probe = pxa2xx_i2s_probe,
- .remove = __devexit_p(pxa2xx_i2s_remove),
+ .probe = pxa2xx_i2s_drv_probe,
+ .remove = __devexit_p(pxa2xx_i2s_drv_remove),
.driver = {
.name = "pxa2xx-i2s",
@@ -400,3 +398,4 @@
MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
MODULE_DESCRIPTION("pxa2xx I2S SoC Interface");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-i2s");
diff --git a/sound/soc/pxa/pxa2xx-i2s.h b/sound/soc/pxa/pxa2xx-i2s.h
index e2def44..070f3c6 100644
--- a/sound/soc/pxa/pxa2xx-i2s.h
+++ b/sound/soc/pxa/pxa2xx-i2s.h
@@ -15,6 +15,4 @@
/* I2S clock */
#define PXA2XX_I2S_SYSCLK 0
-extern struct snd_soc_dai pxa_i2s_dai;
-
#endif
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c
index adc7e6f..02fb664 100644
--- a/sound/soc/pxa/pxa2xx-pcm.c
+++ b/sound/soc/pxa/pxa2xx-pcm.c
@@ -16,7 +16,6 @@
#include <sound/soc.h>
#include <sound/pxa2xx-lib.h>
-#include "pxa2xx-pcm.h"
#include "../../arm/pxa2xx-pcm.h"
static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
@@ -28,7 +27,7 @@
struct pxa2xx_pcm_dma_params *dma;
int ret;
- dma = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ dma = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
/* return if this is a bufferless transfer e.g.
* codec <--> BT codec or GSM modem -- lg FIXME */
@@ -95,14 +94,14 @@
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto out;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
@@ -112,25 +111,44 @@
return ret;
}
-struct snd_soc_platform pxa2xx_soc_platform = {
- .name = "pxa2xx-audio",
- .pcm_ops = &pxa2xx_pcm_ops,
+static struct snd_soc_platform_driver pxa2xx_soc_platform = {
+ .ops = &pxa2xx_pcm_ops,
.pcm_new = pxa2xx_soc_pcm_new,
.pcm_free = pxa2xx_pcm_free_dma_buffers,
};
-EXPORT_SYMBOL_GPL(pxa2xx_soc_platform);
-static int __init pxa2xx_soc_platform_init(void)
+static int __devinit pxa2xx_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&pxa2xx_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &pxa2xx_soc_platform);
}
-module_init(pxa2xx_soc_platform_init);
-static void __exit pxa2xx_soc_platform_exit(void)
+static int __devexit pxa2xx_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&pxa2xx_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
}
-module_exit(pxa2xx_soc_platform_exit);
+
+static struct platform_driver pxa_pcm_driver = {
+ .driver = {
+ .name = "pxa-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = pxa2xx_soc_platform_probe,
+ .remove = __devexit_p(pxa2xx_soc_platform_remove),
+};
+
+static int __init snd_pxa_pcm_init(void)
+{
+ return platform_driver_register(&pxa_pcm_driver);
+}
+module_init(snd_pxa_pcm_init);
+
+static void __exit snd_pxa_pcm_exit(void)
+{
+ platform_driver_unregister(&pxa_pcm_driver);
+}
+module_exit(snd_pxa_pcm_exit);
MODULE_AUTHOR("Nicolas Pitre");
MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module");
diff --git a/sound/soc/pxa/pxa2xx-pcm.h b/sound/soc/pxa/pxa2xx-pcm.h
deleted file mode 100644
index 60c3b20..0000000
--- a/sound/soc/pxa/pxa2xx-pcm.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * linux/sound/arm/pxa2xx-pcm.h -- ALSA PCM interface for the Intel PXA2xx chip
- *
- * Author: Nicolas Pitre
- * Created: Nov 30, 2004
- * Copyright: MontaVista Software, 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 _PXA2XX_PCM_H
-#define _PXA2XX_PCM_H
-
-/* platform data */
-extern struct snd_soc_platform pxa2xx_soc_platform;
-
-#endif
diff --git a/sound/soc/pxa/raumfeld.c b/sound/soc/pxa/raumfeld.c
index 7e3f416..2cda82bc 100644
--- a/sound/soc/pxa/raumfeld.c
+++ b/sound/soc/pxa/raumfeld.c
@@ -26,9 +26,6 @@
#include <asm/mach-types.h>
-#include "../codecs/cs4270.h"
-#include "../codecs/ak4104.h"
-#include "pxa2xx-pcm.h"
#include "pxa-ssp.h"
#define GPIO_SPDIF_RESET (38)
@@ -71,7 +68,7 @@
static int raumfeld_cs4270_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
/* set freq to 0 to enable all possible codec sample rates */
return snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
@@ -80,7 +77,7 @@
static void raumfeld_cs4270_shutdown(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
/* set freq to 0 to enable all possible codec sample rates */
snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
@@ -90,8 +87,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int fmt, clk = 0;
int ret = 0;
@@ -167,32 +164,14 @@
return 0;
}
-static struct snd_soc_dai_link raumfeld_line_dai = {
- .name = "CS4270",
- .stream_name = "CS4270",
- .cpu_dai = &pxa_ssp_dai[PXA_DAI_SSP1],
- .codec_dai = &cs4270_dai,
- .ops = &raumfeld_cs4270_ops,
-};
-
-static struct snd_soc_card snd_soc_line_raumfeld = {
- .name = "Raumfeld analog",
- .platform = &pxa2xx_soc_platform,
- .dai_link = &raumfeld_line_dai,
- .suspend_post = raumfeld_line_suspend,
- .resume_pre = raumfeld_line_resume,
- .num_links = 1,
-};
-
-
/* AK4104 */
static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int fmt, ret = 0, clk = 0;
switch (params_rate(params)) {
@@ -247,34 +226,35 @@
.hw_params = raumfeld_ak4104_hw_params,
};
-static struct snd_soc_dai_link raumfeld_spdif_dai = {
+static struct snd_soc_dai_link raumfeld_dai[] = {
+{
.name = "ak4104",
.stream_name = "Playback",
- .cpu_dai = &pxa_ssp_dai[PXA_DAI_SSP2],
- .codec_dai = &ak4104_dai,
+ .cpu_dai_name = "pxa-ssp-dai.1",
+ .codec_dai_name = "ak4104-hifi",
+ .platform_name = "pxa-pcm-audio",
.ops = &raumfeld_ak4104_ops,
+ .codec_name = "ak4104-codec.0",
+},
+{
+ .name = "CS4270",
+ .stream_name = "CS4270",
+ .cpu_dai_name = "pxa-ssp-dai.0",
+ .platform_name = "pxa-pcm-audio",
+ .codec_dai_name = "cs4270-hifi",
+ .codec_name = "cs4270-codec.0-0048",
+ .ops = &raumfeld_cs4270_ops,
+},};
+
+static struct snd_soc_card snd_soc_raumfeld = {
+ .name = "Raumfeld",
+ .dai_link = raumfeld_dai,
+ .suspend_post = raumfeld_line_suspend,
+ .resume_pre = raumfeld_line_resume,
+ .num_links = ARRAY_SIZE(raumfeld_dai),
};
-static struct snd_soc_card snd_soc_spdif_raumfeld = {
- .name = "Raumfeld S/PDIF",
- .platform = &pxa2xx_soc_platform,
- .dai_link = &raumfeld_spdif_dai,
- .num_links = 1
-};
-
-/* raumfeld_audio audio subsystem */
-static struct snd_soc_device raumfeld_line_devdata = {
- .card = &snd_soc_line_raumfeld,
- .codec_dev = &soc_codec_device_cs4270,
-};
-
-static struct snd_soc_device raumfeld_spdif_devdata = {
- .card = &snd_soc_spdif_raumfeld,
- .codec_dev = &soc_codec_device_ak4104,
-};
-
-static struct platform_device *raumfeld_audio_line_device;
-static struct platform_device *raumfeld_audio_spdif_device;
+static struct platform_device *raumfeld_audio_device;
static int __init raumfeld_audio_init(void)
{
@@ -292,38 +272,19 @@
set_max9485_clk(MAX9485_MCLK_FREQ_122880);
- /* LINE */
- raumfeld_audio_line_device = platform_device_alloc("soc-audio", 0);
- if (!raumfeld_audio_line_device)
+ /* Register LINE and SPDIF */
+ raumfeld_audio_device = platform_device_alloc("soc-audio", 0);
+ if (!raumfeld_audio_device)
return -ENOMEM;
- platform_set_drvdata(raumfeld_audio_line_device,
- &raumfeld_line_devdata);
- raumfeld_line_devdata.dev = &raumfeld_audio_line_device->dev;
- ret = platform_device_add(raumfeld_audio_line_device);
- if (ret)
- platform_device_put(raumfeld_audio_line_device);
+ platform_set_drvdata(raumfeld_audio_device,
+ &snd_soc_raumfeld);
+ ret = platform_device_add(raumfeld_audio_device);
/* no S/PDIF on Speakers */
if (machine_is_raumfeld_speaker())
return ret;
- /* S/PDIF */
- raumfeld_audio_spdif_device = platform_device_alloc("soc-audio", 1);
- if (!raumfeld_audio_spdif_device) {
- platform_device_put(raumfeld_audio_line_device);
- return -ENOMEM;
- }
-
- platform_set_drvdata(raumfeld_audio_spdif_device,
- &raumfeld_spdif_devdata);
- raumfeld_spdif_devdata.dev = &raumfeld_audio_spdif_device->dev;
- ret = platform_device_add(raumfeld_audio_spdif_device);
- if (ret) {
- platform_device_put(raumfeld_audio_line_device);
- platform_device_put(raumfeld_audio_spdif_device);
- }
-
raumfeld_enable_audio(true);
return ret;
@@ -333,10 +294,7 @@
{
raumfeld_enable_audio(false);
- platform_device_unregister(raumfeld_audio_line_device);
-
- if (machine_is_raumfeld_connector())
- platform_device_unregister(raumfeld_audio_spdif_device);
+ platform_device_unregister(raumfeld_audio_device);
i2c_unregister_device(max9486_client);
diff --git a/sound/soc/pxa/saarb.c b/sound/soc/pxa/saarb.c
new file mode 100644
index 0000000..d63cb47
--- /dev/null
+++ b/sound/soc/pxa/saarb.c
@@ -0,0 +1,200 @@
+/*
+ * saarb.c -- SoC audio for saarb
+ *
+ * Copyright (C) 2010 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * 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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+
+#include <asm/mach-types.h>
+
+#include "../codecs/88pm860x-codec.h"
+#include "pxa-ssp.h"
+
+static int saarb_pm860x_init(struct snd_soc_pcm_runtime *rtd);
+
+static struct platform_device *saarb_snd_device;
+
+static struct snd_soc_jack hs_jack, mic_jack;
+
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+ { .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE, },
+};
+
+static struct snd_soc_jack_pin mic_jack_pins[] = {
+ { .pin = "Headset Mic 2", .mask = SND_JACK_MICROPHONE, },
+};
+
+/* saarb machine dapm widgets */
+static const struct snd_soc_dapm_widget saarb_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Stereophone", NULL),
+ SND_SOC_DAPM_LINE("Lineout Out 1", NULL),
+ SND_SOC_DAPM_LINE("Lineout Out 2", NULL),
+ SND_SOC_DAPM_SPK("Ext Speaker", NULL),
+ SND_SOC_DAPM_MIC("Ext Mic 1", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Ext Mic 3", NULL),
+};
+
+/* saarb machine audio map */
+static const struct snd_soc_dapm_route audio_map[] = {
+ {"Headset Stereophone", NULL, "HS1"},
+ {"Headset Stereophone", NULL, "HS2"},
+
+ {"Ext Speaker", NULL, "LSP"},
+ {"Ext Speaker", NULL, "LSN"},
+
+ {"Lineout Out 1", NULL, "LINEOUT1"},
+ {"Lineout Out 2", NULL, "LINEOUT2"},
+
+ {"MIC1P", NULL, "Mic1 Bias"},
+ {"MIC1N", NULL, "Mic1 Bias"},
+ {"Mic1 Bias", NULL, "Ext Mic 1"},
+
+ {"MIC2P", NULL, "Mic1 Bias"},
+ {"MIC2N", NULL, "Mic1 Bias"},
+ {"Mic1 Bias", NULL, "Headset Mic 2"},
+
+ {"MIC3P", NULL, "Mic3 Bias"},
+ {"MIC3N", NULL, "Mic3 Bias"},
+ {"Mic3 Bias", NULL, "Ext Mic 3"},
+};
+
+static int saarb_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int width = snd_pcm_format_physical_width(params_format(params));
+ int ret;
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_NET_PLL, 0,
+ PM860X_CLK_DIR_OUT);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, 0, PM860X_CLK_DIR_OUT);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 3, 3, 2, width);
+
+ return ret;
+}
+
+static struct snd_soc_ops saarb_i2s_ops = {
+ .hw_params = saarb_i2s_hw_params,
+};
+
+static struct snd_soc_dai_link saarb_dai[] = {
+ {
+ .name = "88PM860x I2S",
+ .stream_name = "I2S Audio",
+ .cpu_dai_name = "pxa-ssp-dai.1",
+ .codec_dai_name = "88pm860x-i2s",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "88pm860x-codec",
+ .init = saarb_pm860x_init,
+ .ops = &saarb_i2s_ops,
+ },
+};
+
+static struct snd_soc_card snd_soc_card_saarb = {
+ .name = "Saarb",
+ .dai_link = saarb_dai,
+ .num_links = ARRAY_SIZE(saarb_dai),
+};
+
+static int saarb_pm860x_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ int ret;
+
+ snd_soc_dapm_new_controls(codec, saarb_dapm_widgets,
+ ARRAY_SIZE(saarb_dapm_widgets));
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ /* connected pins */
+ snd_soc_dapm_enable_pin(codec, "Ext Speaker");
+ snd_soc_dapm_enable_pin(codec, "Ext Mic 1");
+ snd_soc_dapm_enable_pin(codec, "Ext Mic 3");
+ snd_soc_dapm_disable_pin(codec, "Headset Mic 2");
+ snd_soc_dapm_disable_pin(codec, "Headset Stereophone");
+
+ ret = snd_soc_dapm_sync(codec);
+ if (ret)
+ return ret;
+
+ /* Headset jack detection */
+ snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE
+ | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
+ &hs_jack);
+ snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
+ hs_jack_pins);
+ snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE,
+ &mic_jack);
+ snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
+ mic_jack_pins);
+
+ /* headphone, microphone detection & headset short detection */
+ pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE,
+ SND_JACK_BTN_0, SND_JACK_BTN_1, SND_JACK_BTN_2);
+ pm860x_mic_jack_detect(codec, &hs_jack, SND_JACK_MICROPHONE);
+ return 0;
+}
+
+static int __init saarb_init(void)
+{
+ int ret;
+
+ if (!machine_is_saarb())
+ return -ENODEV;
+ saarb_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!saarb_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(saarb_snd_device, &snd_soc_card_saarb);
+
+ ret = platform_device_add(saarb_snd_device);
+ if (ret)
+ platform_device_put(saarb_snd_device);
+
+ return ret;
+}
+
+static void __exit saarb_exit(void)
+{
+ platform_device_unregister(saarb_snd_device);
+}
+
+module_init(saarb_init);
+module_exit(saarb_exit);
+
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_DESCRIPTION("ALSA SoC 88PM860x Saarb");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c
index d256f5f..f470f36 100644
--- a/sound/soc/pxa/spitz.c
+++ b/sound/soc/pxa/spitz.c
@@ -28,7 +28,6 @@
#include <asm/mach-types.h>
#include <mach/spitz.h>
#include "../codecs/wm8750.h"
-#include "pxa2xx-pcm.h"
#include "pxa2xx-i2s.h"
#define SPITZ_HP 0
@@ -107,7 +106,7 @@
static int spitz_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
/* check the jack status at stream startup */
spitz_ext_control(codec);
@@ -118,8 +117,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int clk = 0;
int ret = 0;
@@ -274,8 +273,9 @@
/*
* Logic for a wm8750 as connected on a Sharp SL-Cxx00 Device
*/
-static int spitz_wm8750_init(struct snd_soc_codec *codec)
+static int spitz_wm8750_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int err;
/* NC codec pins */
@@ -308,8 +308,10 @@
static struct snd_soc_dai_link spitz_dai = {
.name = "wm8750",
.stream_name = "WM8750",
- .cpu_dai = &pxa_i2s_dai,
- .codec_dai = &wm8750_dai,
+ .cpu_dai_name = "pxa-is2",
+ .codec_dai_name = "wm8750-hifi",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm8750-codec.0-001a",
.init = spitz_wm8750_init,
.ops = &spitz_ops,
};
@@ -317,17 +319,10 @@
/* spitz audio machine driver */
static struct snd_soc_card snd_soc_spitz = {
.name = "Spitz",
- .platform = &pxa2xx_soc_platform,
.dai_link = &spitz_dai,
.num_links = 1,
};
-/* spitz audio subsystem */
-static struct snd_soc_device spitz_snd_devdata = {
- .card = &snd_soc_spitz,
- .codec_dev = &soc_codec_dev_wm8750,
-};
-
static struct platform_device *spitz_snd_device;
static int __init spitz_init(void)
@@ -341,8 +336,7 @@
if (!spitz_snd_device)
return -ENOMEM;
- platform_set_drvdata(spitz_snd_device, &spitz_snd_devdata);
- spitz_snd_devdata.dev = &spitz_snd_device->dev;
+ platform_set_drvdata(spitz_snd_device, &snd_soc_spitz);
ret = platform_device_add(spitz_snd_device);
if (ret)
diff --git a/sound/soc/pxa/tavorevb3.c b/sound/soc/pxa/tavorevb3.c
new file mode 100644
index 0000000..248c283
--- /dev/null
+++ b/sound/soc/pxa/tavorevb3.c
@@ -0,0 +1,200 @@
+/*
+ * tavorevb3.c -- SoC audio for Tavor EVB3
+ *
+ * Copyright (C) 2010 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * 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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+
+#include <asm/mach-types.h>
+
+#include "../codecs/88pm860x-codec.h"
+#include "pxa-ssp.h"
+
+static int evb3_pm860x_init(struct snd_soc_pcm_runtime *rtd);
+
+static struct platform_device *evb3_snd_device;
+
+static struct snd_soc_jack hs_jack, mic_jack;
+
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+ { .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE, },
+};
+
+static struct snd_soc_jack_pin mic_jack_pins[] = {
+ { .pin = "Headset Mic 2", .mask = SND_JACK_MICROPHONE, },
+};
+
+/* tavorevb3 machine dapm widgets */
+static const struct snd_soc_dapm_widget evb3_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+ SND_SOC_DAPM_LINE("Lineout Out 1", NULL),
+ SND_SOC_DAPM_LINE("Lineout Out 2", NULL),
+ SND_SOC_DAPM_SPK("Ext Speaker", NULL),
+ SND_SOC_DAPM_MIC("Ext Mic 1", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic 2", NULL),
+ SND_SOC_DAPM_MIC("Ext Mic 3", NULL),
+};
+
+/* tavorevb3 machine audio map */
+static const struct snd_soc_dapm_route audio_map[] = {
+ {"Headset Stereophone", NULL, "HS1"},
+ {"Headset Stereophone", NULL, "HS2"},
+
+ {"Ext Speaker", NULL, "LSP"},
+ {"Ext Speaker", NULL, "LSN"},
+
+ {"Lineout Out 1", NULL, "LINEOUT1"},
+ {"Lineout Out 2", NULL, "LINEOUT2"},
+
+ {"MIC1P", NULL, "Mic1 Bias"},
+ {"MIC1N", NULL, "Mic1 Bias"},
+ {"Mic1 Bias", NULL, "Ext Mic 1"},
+
+ {"MIC2P", NULL, "Mic1 Bias"},
+ {"MIC2N", NULL, "Mic1 Bias"},
+ {"Mic1 Bias", NULL, "Headset Mic 2"},
+
+ {"MIC3P", NULL, "Mic3 Bias"},
+ {"MIC3N", NULL, "Mic3 Bias"},
+ {"Mic3 Bias", NULL, "Ext Mic 3"},
+};
+
+static int evb3_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int width = snd_pcm_format_physical_width(params_format(params));
+ int ret;
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_NET_PLL, 0,
+ PM860X_CLK_DIR_OUT);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, 0, PM860X_CLK_DIR_OUT);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 3, 3, 2, width);
+ return ret;
+}
+
+static struct snd_soc_ops evb3_i2s_ops = {
+ .hw_params = evb3_i2s_hw_params,
+};
+
+static struct snd_soc_dai_link evb3_dai[] = {
+ {
+ .name = "88PM860x I2S",
+ .stream_name = "I2S Audio",
+ .cpu_dai_name = "pxa-ssp-dai.1",
+ .codec_dai_name = "88pm860x-i2s",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "88pm860x-codec",
+ .init = evb3_pm860x_init,
+ .ops = &evb3_i2s_ops,
+ },
+};
+
+static struct snd_soc_card snd_soc_card_evb3 = {
+ .name = "Tavor EVB3",
+ .dai_link = evb3_dai,
+ .num_links = ARRAY_SIZE(evb3_dai),
+};
+
+static int evb3_pm860x_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ int ret;
+
+ snd_soc_dapm_new_controls(codec, evb3_dapm_widgets,
+ ARRAY_SIZE(evb3_dapm_widgets));
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ /* connected pins */
+ snd_soc_dapm_enable_pin(codec, "Ext Speaker");
+ snd_soc_dapm_enable_pin(codec, "Ext Mic 1");
+ snd_soc_dapm_enable_pin(codec, "Ext Mic 3");
+ snd_soc_dapm_disable_pin(codec, "Headset Mic 2");
+ snd_soc_dapm_disable_pin(codec, "Headset Stereophone");
+
+ ret = snd_soc_dapm_sync(codec);
+ if (ret)
+ return ret;
+
+ /* Headset jack detection */
+ snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE
+ | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
+ &hs_jack);
+ snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
+ hs_jack_pins);
+ snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE,
+ &mic_jack);
+ snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
+ mic_jack_pins);
+
+ /* headphone, microphone detection & headset short detection */
+ pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE,
+ SND_JACK_BTN_0, SND_JACK_BTN_1, SND_JACK_BTN_2);
+ pm860x_mic_jack_detect(codec, &hs_jack, SND_JACK_MICROPHONE);
+ return 0;
+}
+
+static int __init tavorevb3_init(void)
+{
+ int ret;
+
+ if (!machine_is_tavorevb3())
+ return -ENODEV;
+ evb3_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!evb3_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(evb3_snd_device, &snd_soc_card_evb3);
+
+ ret = platform_device_add(evb3_snd_device);
+ if (ret)
+ platform_device_put(evb3_snd_device);
+
+ return ret;
+}
+
+static void __exit tavorevb3_exit(void)
+{
+ platform_device_unregister(evb3_snd_device);
+}
+
+module_init(tavorevb3_init);
+module_exit(tavorevb3_exit);
+
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_DESCRIPTION("ALSA SoC 88PM860x Tavor EVB3");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c
index dbbd3e9..a3bfb2e 100644
--- a/sound/soc/pxa/tosa.c
+++ b/sound/soc/pxa/tosa.c
@@ -33,7 +33,6 @@
#include <mach/audio.h>
#include "../codecs/wm9712.h"
-#include "pxa2xx-pcm.h"
#include "pxa2xx-ac97.h"
static struct snd_soc_card tosa;
@@ -80,7 +79,7 @@
static int tosa_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->card->codec;
/* check the jack status at stream startup */
tosa_ext_control(codec);
@@ -184,8 +183,9 @@
tosa_set_spk),
};
-static int tosa_ac97_init(struct snd_soc_codec *codec)
+static int tosa_ac97_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int err;
snd_soc_dapm_nc_pin(codec, "OUT3");
@@ -212,16 +212,20 @@
{
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
- .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+ .cpu_dai_name = "pxa-ac97.0",
+ .codec_dai_name = "wm9712-hifi",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm9712-codec",
.init = tosa_ac97_init,
.ops = &tosa_ops,
},
{
.name = "AC97 Aux",
.stream_name = "AC97 Aux",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
- .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+ .cpu_dai_name = "pxa-ac97.1",
+ .codec_dai_name = "wm9712-aux",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm9712-codec",
.ops = &tosa_ops,
},
};
@@ -248,18 +252,12 @@
static struct snd_soc_card tosa = {
.name = "Tosa",
- .platform = &pxa2xx_soc_platform,
.dai_link = tosa_dai,
.num_links = ARRAY_SIZE(tosa_dai),
.probe = tosa_probe,
.remove = tosa_remove,
};
-static struct snd_soc_device tosa_snd_devdata = {
- .card = &tosa,
- .codec_dev = &soc_codec_dev_wm9712,
-};
-
static struct platform_device *tosa_snd_device;
static int __init tosa_init(void)
@@ -275,8 +273,7 @@
goto err_alloc;
}
- platform_set_drvdata(tosa_snd_device, &tosa_snd_devdata);
- tosa_snd_devdata.dev = &tosa_snd_device->dev;
+ platform_set_drvdata(tosa_snd_device, &tosa);
ret = platform_device_add(tosa_snd_device);
if (!ret)
diff --git a/sound/soc/pxa/z2.c b/sound/soc/pxa/z2.c
index 4e4d2fa..4cc841b 100644
--- a/sound/soc/pxa/z2.c
+++ b/sound/soc/pxa/z2.c
@@ -30,7 +30,6 @@
#include <mach/z2.h>
#include "../codecs/wm8750.h"
-#include "pxa2xx-pcm.h"
#include "pxa2xx-i2s.h"
static struct snd_soc_card snd_soc_z2;
@@ -39,8 +38,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int clk = 0;
int ret = 0;
@@ -138,8 +137,9 @@
/*
* Logic for a wm8750 as connected on a Z2 Device
*/
-static int z2_wm8750_init(struct snd_soc_codec *codec)
+static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int ret;
/* NC codec pins */
@@ -160,7 +160,7 @@
goto err;
/* Jack detection API stuff */
- ret = snd_soc_jack_new(&snd_soc_z2, "Headset Jack", SND_JACK_HEADSET,
+ ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET,
&hs_jack);
if (ret)
goto err;
@@ -189,8 +189,10 @@
static struct snd_soc_dai_link z2_dai = {
.name = "wm8750",
.stream_name = "WM8750",
- .cpu_dai = &pxa_i2s_dai,
- .codec_dai = &wm8750_dai,
+ .cpu_dai_name = "pxa2xx-i2s",
+ .codec_dai_name = "wm8750-hifi",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm8750-codec.0-001a",
.init = z2_wm8750_init,
.ops = &z2_ops,
};
@@ -198,17 +200,10 @@
/* z2 audio machine driver */
static struct snd_soc_card snd_soc_z2 = {
.name = "Z2",
- .platform = &pxa2xx_soc_platform,
.dai_link = &z2_dai,
.num_links = 1,
};
-/* z2 audio subsystem */
-static struct snd_soc_device z2_snd_devdata = {
- .card = &snd_soc_z2,
- .codec_dev = &soc_codec_dev_wm8750,
-};
-
static struct platform_device *z2_snd_device;
static int __init z2_init(void)
@@ -222,8 +217,7 @@
if (!z2_snd_device)
return -ENOMEM;
- platform_set_drvdata(z2_snd_device, &z2_snd_devdata);
- z2_snd_devdata.dev = &z2_snd_device->dev;
+ platform_set_drvdata(z2_snd_device, &snd_soc_z2);
ret = platform_device_add(z2_snd_device);
if (ret)
diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c
index dd678ae..d27e05a 100644
--- a/sound/soc/pxa/zylonite.c
+++ b/sound/soc/pxa/zylonite.c
@@ -23,7 +23,6 @@
#include <sound/soc-dapm.h>
#include "../codecs/wm9713.h"
-#include "pxa2xx-pcm.h"
#include "pxa2xx-ac97.h"
#include "pxa-ssp.h"
@@ -71,10 +70,12 @@
{ "Multiactor", NULL, "SPKR" },
};
-static int zylonite_wm9713_init(struct snd_soc_codec *codec)
+static int zylonite_wm9713_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
if (clk_pout)
- snd_soc_dai_set_pll(&codec->dai[0], 0, 0,
+ snd_soc_dai_set_pll(rtd->codec_dai, 0, 0,
clk_get_rate(pout), 0);
snd_soc_dapm_new_controls(codec, zylonite_dapm_widgets,
@@ -94,8 +95,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0;
unsigned int wm9713_div = 0;
int ret = 0;
@@ -163,21 +164,27 @@
{
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
- .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI],
+ .codec_name = "wm9713-codec",
+ .platform_name = "pxa-pcm-audio",
+ .cpu_dai_name = "pxa-ac97.0",
+ .codec_name = "wm9713-hifi",
.init = zylonite_wm9713_init,
},
{
.name = "AC97 Aux",
.stream_name = "AC97 Aux",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
- .codec_dai = &wm9713_dai[WM9713_DAI_AC97_AUX],
+ .codec_name = "wm9713-codec",
+ .platform_name = "pxa-pcm-audio",
+ .cpu_dai_name = "pxa-ac97.1",
+ .codec_name = "wm9713-aux",
},
{
.name = "WM9713 Voice",
.stream_name = "WM9713 Voice",
- .cpu_dai = &pxa_ssp_dai[PXA_DAI_SSP3],
- .codec_dai = &wm9713_dai[WM9713_DAI_PCM_VOICE],
+ .codec_name = "wm9713-codec",
+ .platform_name = "pxa-pcm-audio",
+ .cpu_dai_name = "pxa-ssp-dai.2",
+ .codec_name = "wm9713-voice",
.ops = &zylonite_voice_ops,
},
};
@@ -248,14 +255,9 @@
.remove = &zylonite_remove,
.suspend_post = &zylonite_suspend_post,
.resume_pre = &zylonite_resume_pre,
- .platform = &pxa2xx_soc_platform,
.dai_link = zylonite_dai,
.num_links = ARRAY_SIZE(zylonite_dai),
-};
-
-static struct snd_soc_device zylonite_snd_ac97_devdata = {
- .card = &zylonite,
- .codec_dev = &soc_codec_dev_wm9713,
+ .owner = THIS_MODULE,
};
static struct platform_device *zylonite_snd_ac97_device;
@@ -268,9 +270,7 @@
if (!zylonite_snd_ac97_device)
return -ENOMEM;
- platform_set_drvdata(zylonite_snd_ac97_device,
- &zylonite_snd_ac97_devdata);
- zylonite_snd_ac97_devdata.dev = &zylonite_snd_ac97_device->dev;
+ platform_set_drvdata(zylonite_snd_ac97_device, &zylonite);
ret = platform_device_add(zylonite_snd_ac97_device);
if (ret != 0)
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index 213963ac..8a6b53c 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -36,6 +36,10 @@
tristate
select SND_SOC_AC97_BUS
+config SND_S5P_SOC_SPDIF
+ tristate
+ select SND_SOC_SPDIF
+
config SND_S3C24XX_SOC_NEO1973_WM8753
tristate "SoC I2S Audio support for NEO1973 - WM8753"
depends on SND_S3C24XX_SOC && MACH_NEO1973_GTA01
@@ -118,6 +122,14 @@
select SND_SOC_TLV320AIC3X
select SND_S3C24XX_SOC_SIMTEC
+config SND_S3C24XX_SOC_RX1950_UDA1380
+ tristate "Audio support for the HP iPAQ RX1950"
+ depends on SND_S3C24XX_SOC && MACH_RX1950
+ select SND_S3C24XX_SOC_I2S
+ select SND_SOC_UDA1380
+ help
+ This driver provides audio support for HP iPAQ RX1950 PDA.
+
config SND_SOC_SMDK_WM9713
tristate "SoC AC97 Audio support for SMDK with WM9713"
depends on SND_S3C24XX_SOC && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
@@ -131,3 +143,28 @@
depends on SND_S3C24XX_SOC && MACH_SMARTQ
select SND_S3C64XX_SOC_I2S
select SND_SOC_WM8750
+
+config SND_S5PC110_SOC_AQUILA_WM8994
+ tristate "SoC I2S Audio support for AQUILA - WM8994"
+ depends on SND_S3C24XX_SOC && MACH_AQUILA
+ select SND_S3C64XX_SOC_I2S_V4
+ select SND_SOC_WM8994
+ help
+ Say Y if you want to add support for SoC audio on aquila
+ with the WM8994.
+
+config SND_S5PV210_SOC_GONI_WM8994
+ tristate "SoC I2S Audio support for GONI - WM8994"
+ depends on SND_S3C24XX_SOC && MACH_GONI
+ select SND_S3C64XX_SOC_I2S_V4
+ select SND_SOC_WM8994
+ help
+ Say Y if you want to add support for SoC audio on goni
+ with the WM8994.
+
+config SND_SOC_SMDK_SPDIF
+ tristate "SoC S/PDIF Audio support for SMDK"
+ depends on SND_S3C24XX_SOC && (MACH_SMDKC100 || MACH_SMDKC110 || MACH_SMDKV210)
+ select SND_S5P_SOC_SPDIF
+ help
+ Say Y if you want to add support for SoC S/PDIF audio on the SMDK.
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index 50172c3..ee8f41d 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -7,6 +7,7 @@
snd-soc-s3c64xx-i2s-v4-objs := s3c64xx-i2s-v4.o
snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
snd-soc-s3c-pcm-objs := s3c-pcm.o
+snd-soc-samsung-spdif-objs := spdif.o
obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
@@ -16,6 +17,7 @@
obj-$(CONFIG_SND_S3C64XX_SOC_I2S_V4) += snd-soc-s3c64xx-i2s-v4.o
obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
obj-$(CONFIG_SND_S3C_SOC_PCM) += snd-soc-s3c-pcm.o
+obj-$(CONFIG_SND_S5P_SOC_SPDIF) += snd-soc-samsung-spdif.o
# S3C24XX Machine Support
snd-soc-jive-wm8750-objs := jive_wm8750.o
@@ -27,9 +29,13 @@
snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o
snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o
snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o
+snd-soc-rx1950-uda1380-objs := rx1950_uda1380.o
snd-soc-smdk64xx-wm8580-objs := smdk64xx_wm8580.o
snd-soc-smdk-wm9713-objs := smdk_wm9713.o
snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
+snd-soc-aquila-wm8994-objs := aquila_wm8994.o
+snd-soc-goni-wm8994-objs := goni_wm8994.o
+snd-soc-smdk-spdif-objs := smdk_spdif.o
obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o
obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
@@ -40,6 +46,10 @@
obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC) += snd-soc-s3c24xx-simtec.o
obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o
obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o
+obj-$(CONFIG_SND_S3C24XX_SOC_RX1950_UDA1380) += snd-soc-rx1950-uda1380.o
obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o
obj-$(CONFIG_SND_SOC_SMDK_WM9713) += snd-soc-smdk-wm9713.o
obj-$(CONFIG_SND_S3C64XX_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
+obj-$(CONFIG_SND_S5PC110_SOC_AQUILA_WM8994) += snd-soc-aquila-wm8994.o
+obj-$(CONFIG_SND_S5PV210_SOC_GONI_WM8994) += snd-soc-goni-wm8994.o
+obj-$(CONFIG_SND_SOC_SMDK_SPDIF) += snd-soc-smdk-spdif.o
diff --git a/sound/soc/s3c24xx/aquila_wm8994.c b/sound/soc/s3c24xx/aquila_wm8994.c
new file mode 100644
index 0000000..235d197
--- /dev/null
+++ b/sound/soc/s3c24xx/aquila_wm8994.c
@@ -0,0 +1,295 @@
+/*
+ * aquila_wm8994.c
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Chanwoo Choi <cw00.choi@samsung.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; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <asm/mach-types.h>
+#include <mach/gpio.h>
+#include <mach/regs-clock.h>
+
+#include <linux/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/registers.h>
+#include "../codecs/wm8994.h"
+#include "s3c-dma.h"
+#include "s3c64xx-i2s.h"
+
+static struct snd_soc_card aquila;
+static struct platform_device *aquila_snd_device;
+
+/* 3.5 pie jack */
+static struct snd_soc_jack jack;
+
+/* 3.5 pie jack detection DAPM pins */
+static struct snd_soc_jack_pin jack_pins[] = {
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ }, {
+ .pin = "Headset Stereophone",
+ .mask = SND_JACK_HEADPHONE | SND_JACK_MECHANICAL |
+ SND_JACK_AVOUT,
+ },
+};
+
+/* 3.5 pie jack detection gpios */
+static struct snd_soc_jack_gpio jack_gpios[] = {
+ {
+ .gpio = S5PV210_GPH0(6),
+ .name = "DET_3.5",
+ .report = SND_JACK_HEADSET | SND_JACK_MECHANICAL |
+ SND_JACK_AVOUT,
+ .debounce_time = 200,
+ },
+};
+
+static const struct snd_soc_dapm_widget aquila_dapm_widgets[] = {
+ SND_SOC_DAPM_SPK("Ext Spk", NULL),
+ SND_SOC_DAPM_SPK("Ext Rcv", NULL),
+ SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Main Mic", NULL),
+ SND_SOC_DAPM_MIC("2nd Mic", NULL),
+ SND_SOC_DAPM_LINE("Radio In", NULL),
+};
+
+static const struct snd_soc_dapm_route aquila_dapm_routes[] = {
+ {"Ext Spk", NULL, "SPKOUTLP"},
+ {"Ext Spk", NULL, "SPKOUTLN"},
+
+ {"Ext Rcv", NULL, "HPOUT2N"},
+ {"Ext Rcv", NULL, "HPOUT2P"},
+
+ {"Headset Stereophone", NULL, "HPOUT1L"},
+ {"Headset Stereophone", NULL, "HPOUT1R"},
+
+ {"IN1RN", NULL, "Headset Mic"},
+ {"IN1RP", NULL, "Headset Mic"},
+
+ {"IN1RN", NULL, "2nd Mic"},
+ {"IN1RP", NULL, "2nd Mic"},
+
+ {"IN1LN", NULL, "Main Mic"},
+ {"IN1LP", NULL, "Main Mic"},
+
+ {"IN2LN", NULL, "Radio In"},
+ {"IN2RN", NULL, "Radio In"},
+};
+
+static int aquila_wm8994_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ int ret;
+
+ /* add aquila specific widgets */
+ snd_soc_dapm_new_controls(codec, aquila_dapm_widgets,
+ ARRAY_SIZE(aquila_dapm_widgets));
+
+ /* set up aquila specific audio routes */
+ snd_soc_dapm_add_routes(codec, aquila_dapm_routes,
+ ARRAY_SIZE(aquila_dapm_routes));
+
+ /* set endpoints to not connected */
+ snd_soc_dapm_nc_pin(codec, "IN2LP:VXRN");
+ snd_soc_dapm_nc_pin(codec, "IN2RP:VXRP");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT1N");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT1P");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT2N");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT2P");
+ snd_soc_dapm_nc_pin(codec, "SPKOUTRN");
+ snd_soc_dapm_nc_pin(codec, "SPKOUTRP");
+
+ snd_soc_dapm_sync(codec);
+
+ /* Headset jack detection */
+ ret = snd_soc_jack_new(&aquila, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_MECHANICAL | SND_JACK_AVOUT,
+ &jack);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_jack_add_pins(&jack, ARRAY_SIZE(jack_pins), jack_pins);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_jack_add_gpios(&jack, ARRAY_SIZE(jack_gpios), jack_gpios);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int aquila_hifi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ unsigned int pll_out = 24000000;
+ int ret = 0;
+
+ /* set the cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set the cpu system clock */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_PCLK,
+ 0, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec FLL */
+ ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, 0, pll_out,
+ params_rate(params) * 256);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
+ params_rate(params) * 256, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_ops aquila_hifi_ops = {
+ .hw_params = aquila_hifi_hw_params,
+};
+
+static int aquila_voice_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ unsigned int pll_out = 24000000;
+ int ret = 0;
+
+ if (params_rate(params) != 8000)
+ return -EINVAL;
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
+ SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec FLL */
+ ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, 0, pll_out,
+ params_rate(params) * 256);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2,
+ params_rate(params) * 256, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver voice_dai = {
+ .name = "aquila-voice-dai",
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+};
+
+static struct snd_soc_ops aquila_voice_ops = {
+ .hw_params = aquila_voice_hw_params,
+};
+
+static struct snd_soc_dai_link aquila_dai[] = {
+{
+ .name = "WM8994",
+ .stream_name = "WM8994 HiFi",
+ .cpu_dai_name = "s3c64xx-i2s-v4",
+ .codec_dai_name = "wm8994-hifi",
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8994-codec.0-0x1a",
+ .init = aquila_wm8994_init,
+ .ops = &aquila_hifi_ops,
+}, {
+ .name = "WM8994 Voice",
+ .stream_name = "Voice",
+ .cpu_dai_name = "aquila-voice-dai",
+ .codec_dai_name = "wm8994-voice",
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8994-codec.0-0x1a",
+ .ops = &aquila_voice_ops,
+},
+};
+
+static struct snd_soc_card aquila = {
+ .name = "aquila",
+ .dai_link = aquila_dai,
+ .num_links = ARRAY_SIZE(aquila_dai),
+};
+
+static int __init aquila_init(void)
+{
+ int ret;
+
+ if (!machine_is_aquila())
+ return -ENODEV;
+
+ aquila_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!aquila_snd_device)
+ return -ENOMEM;
+
+ /* register voice DAI here */
+ ret = snd_soc_register_dai(&aquila_snd_device->dev, &voice_dai);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(aquila_snd_device, &aquila);
+ ret = platform_device_add(aquila_snd_device);
+
+ if (ret)
+ platform_device_put(aquila_snd_device);
+
+ return ret;
+}
+
+static void __exit aquila_exit(void)
+{
+ platform_device_unregister(aquila_snd_device);
+}
+
+module_init(aquila_init);
+module_exit(aquila_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("ALSA SoC WM8994 Aquila(S5PC110)");
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/goni_wm8994.c b/sound/soc/s3c24xx/goni_wm8994.c
new file mode 100644
index 0000000..694f702
--- /dev/null
+++ b/sound/soc/s3c24xx/goni_wm8994.c
@@ -0,0 +1,298 @@
+/*
+ * goni_wm8994.c
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Chanwoo Choi <cw00.choi@samsung.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; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <asm/mach-types.h>
+#include <mach/gpio.h>
+#include <mach/regs-clock.h>
+
+#include <linux/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/registers.h>
+#include "../codecs/wm8994.h"
+#include "s3c-dma.h"
+#include "s3c64xx-i2s.h"
+
+static struct snd_soc_card goni;
+static struct platform_device *goni_snd_device;
+
+/* 3.5 pie jack */
+static struct snd_soc_jack jack;
+
+/* 3.5 pie jack detection DAPM pins */
+static struct snd_soc_jack_pin jack_pins[] = {
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ }, {
+ .pin = "Headset Stereophone",
+ .mask = SND_JACK_HEADPHONE | SND_JACK_MECHANICAL |
+ SND_JACK_AVOUT,
+ },
+};
+
+/* 3.5 pie jack detection gpios */
+static struct snd_soc_jack_gpio jack_gpios[] = {
+ {
+ .gpio = S5PV210_GPH0(6),
+ .name = "DET_3.5",
+ .report = SND_JACK_HEADSET | SND_JACK_MECHANICAL |
+ SND_JACK_AVOUT,
+ .debounce_time = 200,
+ },
+};
+
+static const struct snd_soc_dapm_widget goni_dapm_widgets[] = {
+ SND_SOC_DAPM_SPK("Ext Left Spk", NULL),
+ SND_SOC_DAPM_SPK("Ext Right Spk", NULL),
+ SND_SOC_DAPM_SPK("Ext Rcv", NULL),
+ SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Main Mic", NULL),
+ SND_SOC_DAPM_MIC("2nd Mic", NULL),
+ SND_SOC_DAPM_LINE("Radio In", NULL),
+};
+
+static const struct snd_soc_dapm_route goni_dapm_routes[] = {
+ {"Ext Left Spk", NULL, "SPKOUTLP"},
+ {"Ext Left Spk", NULL, "SPKOUTLN"},
+
+ {"Ext Right Spk", NULL, "SPKOUTRP"},
+ {"Ext Right Spk", NULL, "SPKOUTRN"},
+
+ {"Ext Rcv", NULL, "HPOUT2N"},
+ {"Ext Rcv", NULL, "HPOUT2P"},
+
+ {"Headset Stereophone", NULL, "HPOUT1L"},
+ {"Headset Stereophone", NULL, "HPOUT1R"},
+
+ {"IN1RN", NULL, "Headset Mic"},
+ {"IN1RP", NULL, "Headset Mic"},
+
+ {"IN1RN", NULL, "2nd Mic"},
+ {"IN1RP", NULL, "2nd Mic"},
+
+ {"IN1LN", NULL, "Main Mic"},
+ {"IN1LP", NULL, "Main Mic"},
+
+ {"IN2LN", NULL, "Radio In"},
+ {"IN2RN", NULL, "Radio In"},
+};
+
+static int goni_wm8994_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ int ret;
+
+ /* add goni specific widgets */
+ snd_soc_dapm_new_controls(codec, goni_dapm_widgets,
+ ARRAY_SIZE(goni_dapm_widgets));
+
+ /* set up goni specific audio routes */
+ snd_soc_dapm_add_routes(codec, goni_dapm_routes,
+ ARRAY_SIZE(goni_dapm_routes));
+
+ /* set endpoints to not connected */
+ snd_soc_dapm_nc_pin(codec, "IN2LP:VXRN");
+ snd_soc_dapm_nc_pin(codec, "IN2RP:VXRP");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT1N");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT1P");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT2N");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT2P");
+
+ snd_soc_dapm_sync(codec);
+
+ /* Headset jack detection */
+ ret = snd_soc_jack_new(&goni, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_MECHANICAL | SND_JACK_AVOUT,
+ &jack);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_jack_add_pins(&jack, ARRAY_SIZE(jack_pins), jack_pins);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_jack_add_gpios(&jack, ARRAY_SIZE(jack_gpios), jack_gpios);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int goni_hifi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ unsigned int pll_out = 24000000;
+ int ret = 0;
+
+ /* set the cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set the cpu system clock */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_PCLK,
+ 0, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec FLL */
+ ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, 0, pll_out,
+ params_rate(params) * 256);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
+ params_rate(params) * 256, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_ops goni_hifi_ops = {
+ .hw_params = goni_hifi_hw_params,
+};
+
+static int goni_voice_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ unsigned int pll_out = 24000000;
+ int ret = 0;
+
+ if (params_rate(params) != 8000)
+ return -EINVAL;
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
+ SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec FLL */
+ ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, 0, pll_out,
+ params_rate(params) * 256);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2,
+ params_rate(params) * 256, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver voice_dai = {
+ .name = "goni-voice-dai",
+ .id = 0,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+};
+
+static struct snd_soc_ops goni_voice_ops = {
+ .hw_params = goni_voice_hw_params,
+};
+
+static struct snd_soc_dai_link goni_dai[] = {
+{
+ .name = "WM8994",
+ .stream_name = "WM8994 HiFi",
+ .cpu_dai_name = "s3c64xx-i2s-v4",
+ .codec_dai_name = "wm8994-hifi",
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8994-codec.0-0x1a",
+ .init = goni_wm8994_init,
+ .ops = &goni_hifi_ops,
+}, {
+ .name = "WM8994 Voice",
+ .stream_name = "Voice",
+ .cpu_dai_name = "goni-voice-dai",
+ .codec_dai_name = "wm8994-voice",
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8994-codec.0-0x1a",
+ .ops = &goni_voice_ops,
+},
+};
+
+static struct snd_soc_card goni = {
+ .name = "goni",
+ .dai_link = goni_dai,
+ .num_links = ARRAY_SIZE(goni_dai),
+};
+
+static int __init goni_init(void)
+{
+ int ret;
+
+ if (!machine_is_goni())
+ return -ENODEV;
+
+ goni_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!goni_snd_device)
+ return -ENOMEM;
+
+ /* register voice DAI here */
+ ret = snd_soc_register_dai(&goni_snd_device->dev, &voice_dai);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(goni_snd_device, &goni);
+ ret = platform_device_add(goni_snd_device);
+
+ if (ret)
+ platform_device_put(goni_snd_device);
+
+ return ret;
+}
+
+static void __exit goni_exit(void)
+{
+ platform_device_unregister(goni_snd_device);
+}
+
+module_init(goni_init);
+module_exit(goni_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("ALSA SoC WM8994 GONI(S5PV210)");
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/jive_wm8750.c b/sound/soc/s3c24xx/jive_wm8750.c
index 8c108b1..49605cd 100644
--- a/sound/soc/s3c24xx/jive_wm8750.c
+++ b/sound/soc/s3c24xx/jive_wm8750.c
@@ -49,8 +49,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct s3c_i2sv2_rate_calc div;
unsigned int clk = 0;
int ret = 0;
@@ -108,8 +108,9 @@
.hw_params = jive_hw_params,
};
-static int jive_wm8750_init(struct snd_soc_codec *codec)
+static int jive_wm8750_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int err;
/* These endpoints are not being used. */
@@ -138,8 +139,10 @@
static struct snd_soc_dai_link jive_dai = {
.name = "wm8750",
.stream_name = "WM8750",
- .cpu_dai = &s3c2412_i2s_dai,
- .codec_dai = &wm8750_dai,
+ .cpu_dai_name = "s3c2412-i2s",
+ .codec_dai_name = "wm8750-hifi",
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8750-codec.0-0x1a",
.init = jive_wm8750_init,
.ops = &jive_ops,
};
@@ -147,17 +150,10 @@
/* jive audio machine driver */
static struct snd_soc_card snd_soc_machine_jive = {
.name = "Jive",
- .platform = &s3c24xx_soc_platform,
.dai_link = &jive_dai,
.num_links = 1,
};
-/* jive audio subsystem */
-static struct snd_soc_device jive_snd_devdata = {
- .card = &snd_soc_machine_jive,
- .codec_dev = &soc_codec_dev_wm8750,
-};
-
static struct platform_device *jive_snd_device;
static int __init jive_init(void)
@@ -173,8 +169,7 @@
if (!jive_snd_device)
return -ENOMEM;
- platform_set_drvdata(jive_snd_device, &jive_snd_devdata);
- jive_snd_devdata.dev = &jive_snd_device->dev;
+ platform_set_drvdata(jive_snd_device, &snd_soc_machine_jive);
ret = platform_device_add(jive_snd_device);
if (ret)
diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c
index ffa954f..abe64ab 100644
--- a/sound/soc/s3c24xx/ln2440sbc_alc650.c
+++ b/sound/soc/s3c24xx/ln2440sbc_alc650.c
@@ -23,7 +23,6 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
-#include "../codecs/ac97.h"
#include "s3c-dma.h"
#include "s3c-ac97.h"
@@ -33,23 +32,19 @@
{
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM],
- .codec_dai = &ac97_dai,
+ .cpu_dai_name = "s3c-ac97",
+ .codec_dai_name = "ac97-hifi",
+ .codec_name = "ac97-codec",
+ .platform_name = "s3c24xx-pcm-audio",
},
};
static struct snd_soc_card ln2440sbc = {
.name = "LN2440SBC",
- .platform = &s3c24xx_soc_platform,
.dai_link = ln2440sbc_dai,
.num_links = ARRAY_SIZE(ln2440sbc_dai),
};
-static struct snd_soc_device ln2440sbc_snd_ac97_devdata = {
- .card = &ln2440sbc,
- .codec_dev = &soc_codec_dev_ac97,
-};
-
static struct platform_device *ln2440sbc_snd_ac97_device;
static int __init ln2440sbc_init(void)
@@ -60,9 +55,7 @@
if (!ln2440sbc_snd_ac97_device)
return -ENOMEM;
- platform_set_drvdata(ln2440sbc_snd_ac97_device,
- &ln2440sbc_snd_ac97_devdata);
- ln2440sbc_snd_ac97_devdata.dev = &ln2440sbc_snd_ac97_device->dev;
+ platform_set_drvdata(ln2440sbc_snd_ac97_device, &ln2440sbc);
ret = platform_device_add(ln2440sbc_snd_ac97_device);
if (ret)
diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
index 209c259..e97bdf1 100644
--- a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
@@ -41,8 +41,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, bclk = 0;
int ret = 0;
unsigned long iis_clkrate;
@@ -130,7 +130,7 @@
static int neo1973_gta02_hifi_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
/* disable the PLL */
return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
@@ -149,7 +149,7 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
unsigned int pcmdiv = 0;
int ret = 0;
unsigned long iis_clkrate;
@@ -182,7 +182,7 @@
if (ret < 0)
return ret;
- /* configue and enable PLL for 12.288MHz output */
+ /* configure and enable PLL for 12.288MHz output */
ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
iis_clkrate / 4, 12288000);
if (ret < 0)
@@ -194,7 +194,7 @@
static int neo1973_gta02_voice_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
/* disable the PLL */
return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
@@ -262,7 +262,7 @@
struct snd_kcontrol *k,
int event)
{
- gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(value));
+ gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(event));
return 0;
}
@@ -330,8 +330,9 @@
* This is an example machine initialisation for a wm8753 connected to a
* neo1973 GTA02.
*/
-static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec)
+static int neo1973_gta02_wm8753_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int err;
/* set up NC codec pins */
@@ -378,9 +379,8 @@
/*
* BT Codec DAI
*/
-static struct snd_soc_dai bt_dai = {
- .name = "Bluetooth",
- .id = 0,
+static struct snd_soc_dai_driver bt_dai = {
+ .name = "bluetooth-dai",
.playback = {
.channels_min = 1,
.channels_max = 1,
@@ -397,32 +397,30 @@
{ /* Hifi Playback - for similatious use with voice below */
.name = "WM8753",
.stream_name = "WM8753 HiFi",
- .cpu_dai = &s3c24xx_i2s_dai,
- .codec_dai = &wm8753_dai[WM8753_DAI_HIFI],
+ .cpu_dai_name = "s3c24xx-i2s",
+ .codec_dai_name = "wm8753-hifi",
.init = neo1973_gta02_wm8753_init,
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8753-codec.0-0x1a",
.ops = &neo1973_gta02_hifi_ops,
},
{ /* Voice via BT */
.name = "Bluetooth",
.stream_name = "Voice",
- .cpu_dai = &bt_dai,
- .codec_dai = &wm8753_dai[WM8753_DAI_VOICE],
+ .cpu_dai_name = "bluetooth-dai",
+ .codec_dai_name = "wm8753-voice",
.ops = &neo1973_gta02_voice_ops,
+ .codec_name = "wm8753-codec.0-0x1a",
+ .platform_name = "s3c24xx-pcm-audio",
},
};
static struct snd_soc_card neo1973_gta02 = {
.name = "neo1973-gta02",
- .platform = &s3c24xx_soc_platform,
.dai_link = neo1973_gta02_dai,
.num_links = ARRAY_SIZE(neo1973_gta02_dai),
};
-static struct snd_soc_device neo1973_gta02_snd_devdata = {
- .card = &neo1973_gta02,
- .codec_dev = &soc_codec_dev_wm8753,
-};
-
static struct platform_device *neo1973_gta02_snd_device;
static int __init neo1973_gta02_init(void)
@@ -435,18 +433,18 @@
return -ENODEV;
}
- /* register bluetooth DAI here */
- ret = snd_soc_register_dai(&bt_dai);
- if (ret)
- return ret;
-
neo1973_gta02_snd_device = platform_device_alloc("soc-audio", -1);
if (!neo1973_gta02_snd_device)
return -ENOMEM;
- platform_set_drvdata(neo1973_gta02_snd_device,
- &neo1973_gta02_snd_devdata);
- neo1973_gta02_snd_devdata.dev = &neo1973_gta02_snd_device->dev;
+ /* register bluetooth DAI here */
+ ret = snd_soc_register_dai(&neo1973_gta02_snd_device->dev, -1, &bt_dai);
+ if (ret) {
+ platform_device_put(neo1973_gta02_snd_device);
+ return ret;
+ }
+
+ platform_set_drvdata(neo1973_gta02_snd_device, &neo1973_gta02);
ret = platform_device_add(neo1973_gta02_snd_device);
if (ret) {
@@ -461,7 +459,7 @@
goto err_unregister_device;
}
- ret = gpio_direction_output(GTA02_GPIO_AMP_HP_IN, 1);
+ ret = gpio_direction_output(GTA02_GPIO_HP_IN, 1);
if (ret) {
pr_err("gta02_wm8753: Failed to configure GPIO %d\n", GTA02_GPIO_HP_IN);
goto err_free_gpio_hp_in;
@@ -493,7 +491,7 @@
static void __exit neo1973_gta02_exit(void)
{
- snd_soc_unregister_dai(&bt_dai);
+ snd_soc_unregister_dai(&neo1973_gta02_snd_device->dev, -1);
platform_device_unregister(neo1973_gta02_snd_device);
gpio_free(GTA02_GPIO_HP_IN);
gpio_free(GTA02_GPIO_AMP_SHUT);
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
index 0cb4f86..f4f2ee7 100644
--- a/sound/soc/s3c24xx/neo1973_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_wm8753.c
@@ -57,8 +57,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, bclk = 0;
int ret = 0;
unsigned long iis_clkrate;
@@ -147,7 +147,7 @@
static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
pr_debug("Entered %s\n", __func__);
@@ -167,7 +167,7 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
unsigned int pcmdiv = 0;
int ret = 0;
unsigned long iis_clkrate;
@@ -201,7 +201,7 @@
if (ret < 0)
return ret;
- /* configue and enable PLL for 12.288MHz output */
+ /* configure and enable PLL for 12.288MHz output */
ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
iis_clkrate / 4, 12288000);
if (ret < 0)
@@ -213,7 +213,7 @@
static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
pr_debug("Entered %s\n", __func__);
@@ -499,8 +499,9 @@
* neo1973 II. It is missing logic to detect hp/mic insertions and logic
* to re-route the audio in such an event.
*/
-static int neo1973_wm8753_init(struct snd_soc_codec *codec)
+static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int err;
pr_debug("Entered %s\n", __func__);
@@ -538,8 +539,7 @@
* BT Codec DAI
*/
static struct snd_soc_dai bt_dai = {
- .name = "Bluetooth",
- .id = 0,
+ .name = "bluetooth-dai",
.playback = {
.channels_min = 1,
.channels_max = 1,
@@ -556,32 +556,30 @@
{ /* Hifi Playback - for similatious use with voice below */
.name = "WM8753",
.stream_name = "WM8753 HiFi",
- .cpu_dai = &s3c24xx_i2s_dai,
- .codec_dai = &wm8753_dai[WM8753_DAI_HIFI],
+ .platform_name = "s3c24xx-pcm-audio",
+ .cpu_dai_name = "s3c24xx-i2s",
+ .codec_dai_name = "wm8753-hifi",
+ .codec_name = "wm8753-codec.0-0x1a",
.init = neo1973_wm8753_init,
.ops = &neo1973_hifi_ops,
},
{ /* Voice via BT */
.name = "Bluetooth",
.stream_name = "Voice",
- .cpu_dai = &bt_dai,
- .codec_dai = &wm8753_dai[WM8753_DAI_VOICE],
+ .platform_name = "s3c24xx-pcm-audio",
+ .cpu_dai_name = "bluetooth-dai",
+ .codec_dai_name = "wm8753-voice",
+ .codec_name = "wm8753-codec.0-0x1a",
.ops = &neo1973_voice_ops,
},
};
static struct snd_soc_card neo1973 = {
.name = "neo1973",
- .platform = &s3c24xx_soc_platform,
.dai_link = neo1973_dai,
.num_links = ARRAY_SIZE(neo1973_dai),
};
-static struct snd_soc_device neo1973_snd_devdata = {
- .card = &neo1973,
- .codec_dev = &soc_codec_dev_wm8753,
-};
-
static int lm4857_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -673,8 +671,7 @@
if (!neo1973_snd_device)
return -ENOMEM;
- platform_set_drvdata(neo1973_snd_device, &neo1973_snd_devdata);
- neo1973_snd_devdata.dev = &neo1973_snd_device->dev;
+ platform_set_drvdata(neo1973_snd_device, &neo1973);
ret = platform_device_add(neo1973_snd_device);
if (ret) {
diff --git a/sound/soc/s3c24xx/rx1950_uda1380.c b/sound/soc/s3c24xx/rx1950_uda1380.c
new file mode 100644
index 0000000..ffd5cf2
--- /dev/null
+++ b/sound/soc/s3c24xx/rx1950_uda1380.c
@@ -0,0 +1,333 @@
+/*
+ * rx1950.c -- ALSA Soc Audio Layer
+ *
+ * Copyright (c) 2010 Vasily Khoruzhick <anarsoul@gmail.com>
+ *
+ * Based on smdk2440.c and magician.c
+ *
+ * Authors: Graeme Gregory graeme.gregory@wolfsonmicro.com
+ * Philipp Zabel <philipp.zabel@gmail.com>
+ * Denis Grigoriev <dgreenday@gmail.com>
+ * Vasily Khoruzhick <anarsoul@gmail.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; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/uda1380.h>
+#include <sound/jack.h>
+
+#include <plat/regs-iis.h>
+
+#include <mach/regs-clock.h>
+
+#include <asm/mach-types.h>
+
+#include "s3c-dma.h"
+#include "s3c24xx-i2s.h"
+#include "../codecs/uda1380.h"
+
+static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd);
+static int rx1950_startup(struct snd_pcm_substream *substream);
+static int rx1950_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params);
+static int rx1950_spk_power(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
+
+static unsigned int rates[] = {
+ 16000,
+ 44100,
+ 48000,
+ 88200,
+};
+
+static struct snd_pcm_hw_constraint_list hw_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+
+static struct snd_soc_jack hp_jack;
+
+static struct snd_soc_jack_pin hp_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Speaker",
+ .mask = SND_JACK_HEADPHONE,
+ .invert = 1,
+ },
+};
+
+static struct snd_soc_jack_gpio hp_jack_gpios[] = {
+ [0] = {
+ .gpio = S3C2410_GPG(12),
+ .name = "hp-gpio",
+ .report = SND_JACK_HEADPHONE,
+ .invert = 1,
+ .debounce_time = 200,
+ },
+};
+
+static struct snd_soc_ops rx1950_ops = {
+ .startup = rx1950_startup,
+ .hw_params = rx1950_hw_params,
+};
+
+/* s3c24xx digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link rx1950_uda1380_dai[] = {
+ {
+ .name = "uda1380",
+ .stream_name = "UDA1380 Duplex",
+ .cpu_dai_name = "s3c24xx-iis",
+ .codec_dai_name = "uda1380-hifi",
+ .init = rx1950_uda1380_init,
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "uda1380-codec.0-001a",
+ .ops = &rx1950_ops,
+ },
+};
+
+static struct snd_soc_card rx1950_asoc = {
+ .name = "rx1950",
+ .dai_link = rx1950_uda1380_dai,
+ .num_links = ARRAY_SIZE(rx1950_uda1380_dai),
+};
+
+/* rx1950 machine dapm widgets */
+static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_SPK("Speaker", rx1950_spk_power),
+};
+
+/* rx1950 machine audio_map */
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* headphone connected to VOUTLHP, VOUTRHP */
+ {"Headphone Jack", NULL, "VOUTLHP"},
+ {"Headphone Jack", NULL, "VOUTRHP"},
+
+ /* ext speaker connected to VOUTL, VOUTR */
+ {"Speaker", NULL, "VOUTL"},
+ {"Speaker", NULL, "VOUTR"},
+
+ /* mic is connected to VINM */
+ {"VINM", NULL, "Mic Jack"},
+};
+
+static struct platform_device *s3c24xx_snd_device;
+static struct clk *xtal;
+
+static int rx1950_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ runtime->hw.rate_min = hw_rates.list[0];
+ runtime->hw.rate_max = hw_rates.list[hw_rates.count - 1];
+ runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
+
+ return snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &hw_rates);
+}
+
+static int rx1950_spk_power(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ gpio_set_value(S3C2410_GPA(1), 1);
+ else
+ gpio_set_value(S3C2410_GPA(1), 0);
+
+ return 0;
+}
+
+static int rx1950_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int div;
+ int ret;
+ unsigned int rate = params_rate(params);
+ int clk_source, fs_mode;
+
+ switch (rate) {
+ case 16000:
+ case 48000:
+ clk_source = S3C24XX_CLKSRC_PCLK;
+ fs_mode = S3C2410_IISMOD_256FS;
+ div = s3c24xx_i2s_get_clockrate() / (256 * rate);
+ if (s3c24xx_i2s_get_clockrate() % (256 * rate) > (128 * rate))
+ div++;
+ break;
+ case 44100:
+ case 88200:
+ clk_source = S3C24XX_CLKSRC_MPLL;
+ fs_mode = S3C2410_IISMOD_256FS;
+ div = clk_get_rate(xtal) / (256 * rate);
+ if (clk_get_rate(xtal) % (256 * rate) > (128 * rate))
+ div++;
+ break;
+ default:
+ printk(KERN_ERR "%s: rate %d is not supported\n",
+ __func__, rate);
+ return -EINVAL;
+ }
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* select clock source */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source, rate,
+ SND_SOC_CLOCK_OUT);
+ if (ret < 0)
+ return ret;
+
+ /* set MCLK division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
+ S3C2410_IISMOD_384FS);
+ if (ret < 0)
+ return ret;
+
+ /* set BCLK division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
+ S3C2410_IISMOD_32FS);
+ if (ret < 0)
+ return ret;
+
+ /* set prescaler division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+ S3C24XX_PRESCALE(div, div));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ int err;
+
+ /* Add rx1950 specific widgets */
+ err = snd_soc_dapm_new_controls(codec, uda1380_dapm_widgets,
+ ARRAY_SIZE(uda1380_dapm_widgets));
+
+ if (err)
+ return err;
+
+ /* Set up rx1950 specific audio path audio_mapnects */
+ err = snd_soc_dapm_add_routes(codec, audio_map,
+ ARRAY_SIZE(audio_map));
+
+ if (err)
+ return err;
+
+ snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+ snd_soc_dapm_enable_pin(codec, "Speaker");
+
+ snd_soc_dapm_sync(codec);
+
+ snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
+ &hp_jack);
+
+ snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
+ hp_jack_pins);
+
+ snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
+ hp_jack_gpios);
+
+ return 0;
+}
+
+static int __init rx1950_init(void)
+{
+ int ret;
+
+ if (!machine_is_rx1950())
+ return -ENODEV;
+
+ /* configure some gpios */
+ ret = gpio_request(S3C2410_GPA(1), "speaker-power");
+ if (ret)
+ goto err_gpio;
+
+ ret = gpio_direction_output(S3C2410_GPA(1), 0);
+ if (ret)
+ goto err_gpio_conf;
+
+ s3c24xx_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!s3c24xx_snd_device) {
+ ret = -ENOMEM;
+ goto err_plat_alloc;
+ }
+
+ platform_set_drvdata(s3c24xx_snd_device, &rx1950_asoc);
+ ret = platform_device_add(s3c24xx_snd_device);
+
+ if (ret) {
+ platform_device_put(s3c24xx_snd_device);
+ goto err_plat_add;
+ }
+
+ xtal = clk_get(&s3c24xx_snd_device->dev, "xtal");
+
+ if (IS_ERR(xtal)) {
+ ret = PTR_ERR(xtal);
+ platform_device_unregister(s3c24xx_snd_device);
+ goto err_clk;
+ }
+
+ return 0;
+
+err_clk:
+err_plat_add:
+err_plat_alloc:
+err_gpio_conf:
+ gpio_free(S3C2410_GPA(1));
+
+err_gpio:
+ return ret;
+}
+
+static void __exit rx1950_exit(void)
+{
+ platform_device_unregister(s3c24xx_snd_device);
+ snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
+ hp_jack_gpios);
+ clk_put(xtal);
+ gpio_free(S3C2410_GPA(1));
+}
+
+module_init(rx1950_init);
+module_exit(rx1950_exit);
+
+/* Module information */
+MODULE_AUTHOR("Vasily Khoruzhick");
+MODULE_DESCRIPTION("ALSA SoC RX1950");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c-ac97.c b/sound/soc/s3c24xx/s3c-ac97.c
index 31f6d45..f891eb7 100644
--- a/sound/soc/s3c24xx/s3c-ac97.c
+++ b/sound/soc/s3c24xx/s3c-ac97.c
@@ -89,7 +89,7 @@
writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
- printk(KERN_ERR "AC97: Unable to activate!");
+ pr_err("AC97: Unable to activate!");
}
static unsigned short s3c_ac97_read(struct snd_ac97 *ac97,
@@ -115,14 +115,15 @@
writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
- printk(KERN_ERR "AC97: Unable to read!");
+ pr_err("AC97: Unable to read!");
stat = readl(s3c_ac97.regs + S3C_AC97_STAT);
addr = (stat >> 16) & 0x7f;
data = (stat & 0xffff);
if (addr != reg)
- printk(KERN_ERR "s3c-ac97: req addr = %02x, rep addr = %02x\n", reg, addr);
+ pr_err("s3c-ac97: req addr = %02x, rep addr = %02x\n",
+ reg, addr);
mutex_unlock(&s3c_ac97.lock);
@@ -151,7 +152,7 @@
writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
- printk(KERN_ERR "AC97: Unable to write!");
+ pr_err("AC97: Unable to write!");
ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ;
@@ -162,6 +163,7 @@
static void s3c_ac97_cold_reset(struct snd_ac97 *ac97)
{
+ pr_debug("AC97: Cold reset\n");
writel(S3C_AC97_GLBCTRL_COLDRESET,
s3c_ac97.regs + S3C_AC97_GLBCTRL);
msleep(1);
@@ -178,6 +180,8 @@
if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
return; /* Return if already active */
+ pr_debug("AC97: Warm reset\n");
+
writel(S3C_AC97_GLBCTRL_WARMRESET, s3c_ac97.regs + S3C_AC97_GLBCTRL);
msleep(1);
@@ -222,7 +226,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct s3c_dma_params *dma_data;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -241,7 +245,7 @@
u32 ac_glbctrl;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct s3c_dma_params *dma_data =
- snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
@@ -277,7 +281,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
return -ENODEV;
@@ -293,7 +297,7 @@
u32 ac_glbctrl;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct s3c_dma_params *dma_data =
- snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
ac_glbctrl &= ~S3C_AC97_GLBCTRL_MICINTM_MASK;
@@ -328,10 +332,9 @@
.trigger = s3c_ac97_mic_trigger,
};
-struct snd_soc_dai s3c_ac97_dai[] = {
+static struct snd_soc_dai_driver s3c_ac97_dai[] = {
[S3C_AC97_DAI_PCM] = {
.name = "s3c-ac97",
- .id = S3C_AC97_DAI_PCM,
.ac97_control = 1,
.playback = {
.stream_name = "AC97 Playback",
@@ -349,7 +352,6 @@
},
[S3C_AC97_DAI_MIC] = {
.name = "s3c-ac97-mic",
- .id = S3C_AC97_DAI_MIC,
.ac97_control = 1,
.capture = {
.stream_name = "AC97 Mic Capture",
@@ -360,7 +362,6 @@
.ops = &s3c_ac97_mic_dai_ops,
},
};
-EXPORT_SYMBOL_GPL(s3c_ac97_dai);
static __devinit int s3c_ac97_probe(struct platform_device *pdev)
{
@@ -445,14 +446,12 @@
ret = request_irq(irq_res->start, s3c_ac97_irq,
IRQF_DISABLED, "AC97", NULL);
if (ret < 0) {
- printk(KERN_ERR "s3c-ac97: interrupt request failed.\n");
+ dev_err(&pdev->dev, "s3c-ac97: interrupt request failed.\n");
goto err4;
}
- s3c_ac97_dai[S3C_AC97_DAI_PCM].dev = &pdev->dev;
- s3c_ac97_dai[S3C_AC97_DAI_MIC].dev = &pdev->dev;
-
- ret = snd_soc_register_dais(s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
+ ret = snd_soc_register_dais(&pdev->dev, s3c_ac97_dai,
+ ARRAY_SIZE(s3c_ac97_dai));
if (ret)
goto err5;
@@ -476,7 +475,7 @@
{
struct resource *mem_res, *irq_res;
- snd_soc_unregister_dais(s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
+ snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai));
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (irq_res)
@@ -518,3 +517,4 @@
MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
MODULE_DESCRIPTION("AC97 driver for the Samsung SoC");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c-ac97");
diff --git a/sound/soc/s3c24xx/s3c-ac97.h b/sound/soc/s3c24xx/s3c-ac97.h
index 2781983..5dcedd0 100644
--- a/sound/soc/s3c24xx/s3c-ac97.h
+++ b/sound/soc/s3c24xx/s3c-ac97.h
@@ -18,6 +18,4 @@
#define S3C_AC97_DAI_PCM 0
#define S3C_AC97_DAI_MIC 1
-extern struct snd_soc_dai s3c_ac97_dai[];
-
#endif /* __S3C_AC97_H_ */
diff --git a/sound/soc/s3c24xx/s3c-dma.c b/sound/soc/s3c24xx/s3c-dma.c
index 1b61c23..243f79b 100644
--- a/sound/soc/s3c24xx/s3c-dma.c
+++ b/sound/soc/s3c24xx/s3c-dma.c
@@ -94,8 +94,7 @@
if ((pos + len) > prtd->dma_end) {
len = prtd->dma_end - pos;
- pr_debug(KERN_DEBUG "%s: corrected dma len %ld\n",
- __func__, len);
+ pr_debug("%s: corrected dma len %ld\n", __func__, len);
}
ret = s3c2410_dma_enqueue(prtd->params->channel,
@@ -147,7 +146,7 @@
struct snd_soc_pcm_runtime *rtd = substream->private_data;
unsigned long totbytes = params_buffer_bytes(params);
struct s3c_dma_params *dma =
- snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
int ret = 0;
@@ -441,14 +440,14 @@
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = 0xffffffff;
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = s3c_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto out;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
ret = s3c_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
@@ -458,26 +457,46 @@
return ret;
}
-struct snd_soc_platform s3c24xx_soc_platform = {
- .name = "s3c24xx-audio",
- .pcm_ops = &s3c_dma_ops,
+static struct snd_soc_platform_driver s3c24xx_soc_platform = {
+ .ops = &s3c_dma_ops,
.pcm_new = s3c_dma_new,
.pcm_free = s3c_dma_free_dma_buffers,
};
-EXPORT_SYMBOL_GPL(s3c24xx_soc_platform);
-static int __init s3c24xx_soc_platform_init(void)
+static int __devinit s3c24xx_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&s3c24xx_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &s3c24xx_soc_platform);
}
-module_init(s3c24xx_soc_platform_init);
-static void __exit s3c24xx_soc_platform_exit(void)
+static int __devexit s3c24xx_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&s3c24xx_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
}
-module_exit(s3c24xx_soc_platform_exit);
+
+static struct platform_driver s3c24xx_pcm_driver = {
+ .driver = {
+ .name = "s3c24xx-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = s3c24xx_soc_platform_probe,
+ .remove = __devexit_p(s3c24xx_soc_platform_remove),
+};
+
+static int __init snd_s3c24xx_pcm_init(void)
+{
+ return platform_driver_register(&s3c24xx_pcm_driver);
+}
+module_init(snd_s3c24xx_pcm_init);
+
+static void __exit snd_s3c24xx_pcm_exit(void)
+{
+ platform_driver_unregister(&s3c24xx_pcm_driver);
+}
+module_exit(snd_s3c24xx_pcm_exit);
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
MODULE_DESCRIPTION("Samsung S3C Audio DMA module");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c24xx-pcm-audio");
diff --git a/sound/soc/s3c24xx/s3c-dma.h b/sound/soc/s3c24xx/s3c-dma.h
index 69bb6bf..748c07d 100644
--- a/sound/soc/s3c24xx/s3c-dma.h
+++ b/sound/soc/s3c24xx/s3c-dma.h
@@ -25,7 +25,6 @@
#define S3C24XX_DAI_I2S 0
/* platform data */
-extern struct snd_soc_platform s3c24xx_soc_platform;
extern struct snd_ac97_bus_ops s3c24xx_ac97_ops;
#endif
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c
index 64376b2..b3866d5 100644
--- a/sound/soc/s3c24xx/s3c-i2s-v2.c
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.c
@@ -49,7 +49,7 @@
static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
{
- return cpu_dai->private_data;
+ return snd_soc_dai_get_drvdata(cpu_dai);
}
#define bit_set(v, b) (((v) & (b)) ? 1 : 0)
@@ -307,11 +307,9 @@
static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
- struct snd_soc_dai *socdai)
+ struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai_link *dai = rtd->dai;
- struct s3c_i2sv2_info *i2s = to_info(dai->cpu_dai);
+ struct s3c_i2sv2_info *i2s = to_info(dai);
struct s3c_dma_params *dma_data;
u32 iismod;
@@ -322,7 +320,7 @@
else
dma_data = i2s->dma_capture;
- snd_soc_dai_set_dma_data(dai->cpu_dai, substream, dma_data);
+ snd_soc_dai_set_dma_data(dai, substream, dma_data);
/* Working copies of register */
iismod = readl(i2s->regs + S3C2412_IISMOD);
@@ -396,12 +394,12 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct s3c_i2sv2_info *i2s = to_info(rtd->dai->cpu_dai);
+ struct s3c_i2sv2_info *i2s = to_info(rtd->cpu_dai);
int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
unsigned long irqs;
int ret = 0;
struct s3c_dma_params *dma_data =
- snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
pr_debug("Entered %s\n", __func__);
@@ -640,36 +638,17 @@
}
EXPORT_SYMBOL_GPL(s3c_i2sv2_iis_calc_rate);
-int s3c_i2sv2_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai,
+int s3c_i2sv2_probe(struct snd_soc_dai *dai,
struct s3c_i2sv2_info *i2s,
unsigned long base)
{
- struct device *dev = &pdev->dev;
+ struct device *dev = dai->dev;
unsigned int iismod;
i2s->dev = dev;
/* record our i2s structure for later use in the callbacks */
- dai->private_data = i2s;
-
- if (!base) {
- struct resource *res = platform_get_resource(pdev,
- IORESOURCE_MEM,
- 0);
- if (!res) {
- dev_err(dev, "Unable to get register resource\n");
- return -ENXIO;
- }
-
- if (!request_mem_region(res->start, resource_size(res),
- "s3c64xx-i2s-v4")) {
- dev_err(dev, "Unable to request register region\n");
- return -EBUSY;
- }
-
- base = res->start;
- }
+ snd_soc_dai_set_drvdata(dai, i2s);
i2s->regs = ioremap(base, 0x100);
if (i2s->regs == NULL) {
@@ -752,9 +731,10 @@
#define s3c2412_i2s_resume NULL
#endif
-int s3c_i2sv2_register_dai(struct snd_soc_dai *dai)
+int s3c_i2sv2_register_dai(struct device *dev, int id,
+ struct snd_soc_dai_driver *drv)
{
- struct snd_soc_dai_ops *ops = dai->ops;
+ struct snd_soc_dai_ops *ops = drv->ops;
ops->trigger = s3c2412_i2s_trigger;
if (!ops->hw_params)
@@ -767,10 +747,10 @@
if (!ops->delay)
ops->delay = s3c2412_i2s_delay;
- dai->suspend = s3c2412_i2s_suspend;
- dai->resume = s3c2412_i2s_resume;
+ drv->suspend = s3c2412_i2s_suspend;
+ drv->resume = s3c2412_i2s_resume;
- return snd_soc_register_dai(dai);
+ return snd_soc_register_dai(dev, drv);
}
EXPORT_SYMBOL_GPL(s3c_i2sv2_register_dai);
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.h b/sound/soc/s3c24xx/s3c-i2s-v2.h
index 766f43a..d458301 100644
--- a/sound/soc/s3c24xx/s3c-i2s-v2.h
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.h
@@ -66,6 +66,8 @@
u32 suspend_iismod;
u32 suspend_iiscon;
u32 suspend_iispsr;
+
+ unsigned long base;
};
extern struct clk *s3c_i2sv2_get_clock(struct snd_soc_dai *cpu_dai);
@@ -81,23 +83,24 @@
/**
* s3c_i2sv2_probe - probe for i2s device helper
- * @pdev: The platform device supplied to the original probe.
* @dai: The ASoC DAI structure supplied to the original probe.
* @i2s: Our local i2s structure to fill in.
* @base: The base address for the registers.
*/
-extern int s3c_i2sv2_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai,
+extern int s3c_i2sv2_probe(struct snd_soc_dai *dai,
struct s3c_i2sv2_info *i2s,
unsigned long base);
/**
* s3c_i2sv2_register_dai - register dai with soc core
- * @dai: The snd_soc_dai structure to register
+ * @dev: DAI device
+ * @id: DAI ID
+ * @drv: The driver structure to register
*
* Fill in any missing fields and then register the given dai with the
* soc core.
*/
-extern int s3c_i2sv2_register_dai(struct snd_soc_dai *dai);
+extern int s3c_i2sv2_register_dai(struct device *dev, int id,
+ struct snd_soc_dai_driver *drv);
#endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */
diff --git a/sound/soc/s3c24xx/s3c-pcm.c b/sound/soc/s3c24xx/s3c-pcm.c
index 326f0a9..2e020e1 100644
--- a/sound/soc/s3c24xx/s3c-pcm.c
+++ b/sound/soc/s3c24xx/s3c-pcm.c
@@ -64,11 +64,6 @@
static struct s3c_pcm_info s3c_pcm[2];
-static inline struct s3c_pcm_info *to_info(struct snd_soc_dai *cpu_dai)
-{
- return cpu_dai->private_data;
-}
-
static void s3c_pcm_snd_txctrl(struct s3c_pcm_info *pcm, int on)
{
void __iomem *regs = pcm->regs;
@@ -83,7 +78,7 @@
ctl |= S3C_PCM_CTL_TXDMA_EN;
ctl |= S3C_PCM_CTL_TXFIFO_EN;
ctl |= S3C_PCM_CTL_ENABLE;
- ctl |= (0x20<<S3C_PCM_CTL_TXDIPSTICK_SHIFT);
+ ctl |= (0x4<<S3C_PCM_CTL_TXDIPSTICK_SHIFT);
clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
} else {
ctl &= ~S3C_PCM_CTL_TXDMA_EN;
@@ -107,11 +102,14 @@
ctl = readl(regs + S3C_PCM_CTL);
clkctl = readl(regs + S3C_PCM_CLKCTL);
+ ctl &= ~(S3C_PCM_CTL_RXDIPSTICK_MASK
+ << S3C_PCM_CTL_RXDIPSTICK_SHIFT);
if (on) {
ctl |= S3C_PCM_CTL_RXDMA_EN;
ctl |= S3C_PCM_CTL_RXFIFO_EN;
ctl |= S3C_PCM_CTL_ENABLE;
+ ctl |= (0x20<<S3C_PCM_CTL_RXDIPSTICK_SHIFT);
clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
} else {
ctl &= ~S3C_PCM_CTL_RXDMA_EN;
@@ -132,7 +130,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct s3c_pcm_info *pcm = to_info(rtd->dai->cpu_dai);
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
unsigned long flags;
dev_dbg(pcm->dev, "Entered %s\n", __func__);
@@ -176,8 +174,7 @@
struct snd_soc_dai *socdai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai_link *dai = rtd->dai;
- struct s3c_pcm_info *pcm = to_info(dai->cpu_dai);
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
struct s3c_dma_params *dma_data;
void __iomem *regs = pcm->regs;
struct clk *clk;
@@ -192,7 +189,7 @@
else
dma_data = pcm->dma_capture;
- snd_soc_dai_set_dma_data(dai->cpu_dai, substream, dma_data);
+ snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
/* Strictly check for sample size */
switch (params_format(params)) {
@@ -242,7 +239,7 @@
static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
- struct s3c_pcm_info *pcm = to_info(cpu_dai);
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
void __iomem *regs = pcm->regs;
unsigned long flags;
int ret = 0;
@@ -313,7 +310,7 @@
static int s3c_pcm_set_clkdiv(struct snd_soc_dai *cpu_dai,
int div_id, int div)
{
- struct s3c_pcm_info *pcm = to_info(cpu_dai);
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
switch (div_id) {
case S3C_PCM_SCLK_PER_FS:
@@ -330,7 +327,7 @@
static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
{
- struct s3c_pcm_info *pcm = to_info(cpu_dai);
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
void __iomem *regs = pcm->regs;
u32 clkctl = readl(regs + S3C_PCM_CLKCTL);
@@ -366,10 +363,7 @@
#define S3C_PCM_RATES SNDRV_PCM_RATE_8000_96000
-#define S3C_PCM_DECLARE(n) \
-{ \
- .name = "samsung-pcm", \
- .id = (n), \
+#define S3C_PCM_DAI_DECLARE \
.symmetric_rates = 1, \
.ops = &s3c_pcm_dai_ops, \
.playback = { \
@@ -383,19 +377,23 @@
.channels_max = 2, \
.rates = S3C_PCM_RATES, \
.formats = SNDRV_PCM_FMTBIT_S16_LE, \
- }, \
-}
+ }
-struct snd_soc_dai s3c_pcm_dai[] = {
- S3C_PCM_DECLARE(0),
- S3C_PCM_DECLARE(1),
+struct snd_soc_dai_driver s3c_pcm_dai[] = {
+ [0] = {
+ .name = "samsung-pcm.0",
+ S3C_PCM_DAI_DECLARE,
+ },
+ [1] = {
+ .name = "samsung-pcm.1",
+ S3C_PCM_DAI_DECLARE,
+ },
};
EXPORT_SYMBOL_GPL(s3c_pcm_dai);
static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
{
struct s3c_pcm_info *pcm;
- struct snd_soc_dai *dai;
struct resource *mem_res, *dmatx_res, *dmarx_res;
struct s3c_audio_pdata *pcm_pdata;
int ret;
@@ -437,9 +435,6 @@
spin_lock_init(&pcm->lock);
- dai = &s3c_pcm_dai[pdev->id];
- dai->dev = &pdev->dev;
-
/* Default is 128fs */
pcm->sclk_per_fs = 128;
@@ -452,7 +447,7 @@
clk_enable(pcm->cclk);
/* record our pcm structure for later use in the callbacks */
- dai->private_data = pcm;
+ dev_set_drvdata(&pdev->dev, pcm);
if (!request_mem_region(mem_res->start,
resource_size(mem_res), "samsung-pcm")) {
@@ -476,7 +471,7 @@
}
clk_enable(pcm->pclk);
- ret = snd_soc_register_dai(dai);
+ ret = snd_soc_register_dai(&pdev->dev, &s3c_pcm_dai[pdev->id]);
if (ret != 0) {
dev_err(&pdev->dev, "failed to get pcm_clock\n");
goto err5;
@@ -514,6 +509,8 @@
struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id];
struct resource *mem_res;
+ snd_soc_unregister_dai(&pdev->dev);
+
iounmap(pcm->regs);
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -552,3 +549,4 @@
MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
MODULE_DESCRIPTION("S3C PCM Controller Driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-pcm");
diff --git a/sound/soc/s3c24xx/s3c-pcm.h b/sound/soc/s3c24xx/s3c-pcm.h
index 69ff997..f60baa1 100644
--- a/sound/soc/s3c24xx/s3c-pcm.h
+++ b/sound/soc/s3c24xx/s3c-pcm.h
@@ -22,7 +22,8 @@
/* PCM_CTL Bit-Fields */
#define S3C_PCM_CTL_TXDIPSTICK_MASK (0x3f)
#define S3C_PCM_CTL_TXDIPSTICK_SHIFT (13)
-#define S3C_PCM_CTL_RXDIPSTICK_MSK (0x3f<<7)
+#define S3C_PCM_CTL_RXDIPSTICK_MASK (0x3f)
+#define S3C_PCM_CTL_RXDIPSTICK_SHIFT (7)
#define S3C_PCM_CTL_TXDMA_EN (0x1<<6)
#define S3C_PCM_CTL_RXDMA_EN (0x1<<5)
#define S3C_PCM_CTL_TXMSB_AFTER_FSYNC (0x1<<4)
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c
index 709adef..4a861cf 100644
--- a/sound/soc/s3c24xx/s3c2412-i2s.c
+++ b/sound/soc/s3c24xx/s3c2412-i2s.c
@@ -65,26 +65,20 @@
static struct s3c_i2sv2_info s3c2412_i2s;
-static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
-{
- return cpu_dai->private_data;
-}
-
-static int s3c2412_i2s_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int s3c2412_i2s_probe(struct snd_soc_dai *dai)
{
int ret;
pr_debug("Entered %s\n", __func__);
- ret = s3c_i2sv2_probe(pdev, dai, &s3c2412_i2s, S3C2410_PA_IIS);
+ ret = s3c_i2sv2_probe(dai, &s3c2412_i2s, S3C2410_PA_IIS);
if (ret)
return ret;
s3c2412_i2s.dma_capture = &s3c2412_i2s_pcm_stereo_in;
s3c2412_i2s.dma_playback = &s3c2412_i2s_pcm_stereo_out;
- s3c2412_i2s.iis_cclk = clk_get(&pdev->dev, "i2sclk");
+ s3c2412_i2s.iis_cclk = clk_get(dai->dev, "i2sclk");
if (s3c2412_i2s.iis_cclk == NULL) {
pr_err("failed to get i2sclk clock\n");
iounmap(s3c2412_i2s.regs);
@@ -108,11 +102,20 @@
return 0;
}
+static int s3c2412_i2s_remove(struct snd_soc_dai *dai)
+{
+ clk_disable(s3c2412_i2s.iis_cclk);
+ clk_put(s3c2412_i2s.iis_cclk);
+ iounmap(s3c2412_i2s.regs);
+
+ return 0;
+}
+
static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
- struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
+ struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(cpu_dai);
struct s3c_dma_params *dma_data;
u32 iismod;
@@ -152,10 +155,9 @@
.hw_params = s3c2412_i2s_hw_params,
};
-struct snd_soc_dai s3c2412_i2s_dai = {
- .name = "s3c2412-i2s",
- .id = 0,
+static struct snd_soc_dai_driver s3c2412_i2s_dai = {
.probe = s3c2412_i2s_probe,
+ .remove = s3c2412_i2s_remove,
.playback = {
.channels_min = 2,
.channels_max = 2,
@@ -170,17 +172,36 @@
},
.ops = &s3c2412_i2s_dai_ops,
};
-EXPORT_SYMBOL_GPL(s3c2412_i2s_dai);
+
+static __devinit int s3c2412_iis_dev_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_dai(&pdev->dev, &s3c2412_i2s_dai);
+}
+
+static __devexit int s3c2412_iis_dev_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dai(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver s3c2412_iis_driver = {
+ .probe = s3c2412_iis_dev_probe,
+ .remove = s3c2412_iis_dev_remove,
+ .driver = {
+ .name = "s3c2412-iis",
+ .owner = THIS_MODULE,
+ },
+};
static int __init s3c2412_i2s_init(void)
{
- return s3c_i2sv2_register_dai(&s3c2412_i2s_dai);
+ return platform_driver_register(&s3c2412_iis_driver);
}
module_init(s3c2412_i2s_init);
static void __exit s3c2412_i2s_exit(void)
{
- snd_soc_unregister_dai(&s3c2412_i2s_dai);
+ platform_driver_unregister(&s3c2412_iis_driver);
}
module_exit(s3c2412_i2s_exit);
@@ -188,3 +209,4 @@
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
MODULE_DESCRIPTION("S3C2412 I2S SoC Interface");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c2412-iis");
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.h b/sound/soc/s3c24xx/s3c2412-i2s.h
index 0b5686b..01a0471 100644
--- a/sound/soc/s3c24xx/s3c2412-i2s.h
+++ b/sound/soc/s3c24xx/s3c2412-i2s.h
@@ -24,6 +24,4 @@
#define S3C2412_CLKSRC_PCLK S3C_I2SV2_CLKSRC_PCLK
#define S3C2412_CLKSRC_I2SCLK S3C_I2SV2_CLKSRC_AUDIOBUS
-extern struct snd_soc_dai s3c2412_i2s_dai;
-
#endif /* __SND_SOC_S3C24XX_S3C2412_I2S_H */
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c
index c3ac890..e060daa 100644
--- a/sound/soc/s3c24xx/s3c24xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c24xx-i2s.c
@@ -252,7 +252,7 @@
else
dma_data = &s3c24xx_i2s_pcm_stereo_in;
- snd_soc_dai_set_dma_data(rtd->dai->cpu_dai, substream, dma_data);
+ snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
/* Working copies of register */
iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
@@ -280,9 +280,8 @@
struct snd_soc_dai *dai)
{
int ret = 0;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct s3c_dma_params *dma_data =
- snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ snd_soc_dai_get_dma_data(dai, substream);
pr_debug("Entered %s\n", __func__);
@@ -387,8 +386,7 @@
}
EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate);
-static int s3c24xx_i2s_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int s3c24xx_i2s_probe(struct snd_soc_dai *dai)
{
pr_debug("Entered %s\n", __func__);
@@ -396,7 +394,7 @@
if (s3c24xx_i2s.regs == NULL)
return -ENXIO;
- s3c24xx_i2s.iis_clk = clk_get(&pdev->dev, "iis");
+ s3c24xx_i2s.iis_clk = clk_get(dai->dev, "iis");
if (s3c24xx_i2s.iis_clk == NULL) {
pr_err("failed to get iis_clock\n");
iounmap(s3c24xx_i2s.regs);
@@ -465,9 +463,7 @@
.set_sysclk = s3c24xx_i2s_set_sysclk,
};
-struct snd_soc_dai s3c24xx_i2s_dai = {
- .name = "s3c24xx-i2s",
- .id = 0,
+static struct snd_soc_dai_driver s3c24xx_i2s_dai = {
.probe = s3c24xx_i2s_probe,
.suspend = s3c24xx_i2s_suspend,
.resume = s3c24xx_i2s_resume,
@@ -483,17 +479,36 @@
.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
.ops = &s3c24xx_i2s_dai_ops,
};
-EXPORT_SYMBOL_GPL(s3c24xx_i2s_dai);
+
+static __devinit int s3c24xx_iis_dev_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_dai(&pdev->dev, &s3c24xx_i2s_dai);
+}
+
+static __devexit int s3c24xx_iis_dev_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dai(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver s3c24xx_iis_driver = {
+ .probe = s3c24xx_iis_dev_probe,
+ .remove = s3c24xx_iis_dev_remove,
+ .driver = {
+ .name = "s3c24xx-iis",
+ .owner = THIS_MODULE,
+ },
+};
static int __init s3c24xx_i2s_init(void)
{
- return snd_soc_register_dai(&s3c24xx_i2s_dai);
+ return platform_driver_register(&s3c24xx_iis_driver);
}
module_init(s3c24xx_i2s_init);
static void __exit s3c24xx_i2s_exit(void)
{
- snd_soc_unregister_dai(&s3c24xx_i2s_dai);
+ platform_driver_unregister(&s3c24xx_iis_driver);
}
module_exit(s3c24xx_i2s_exit);
@@ -501,3 +516,4 @@
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
MODULE_DESCRIPTION("s3c24xx I2S SoC Interface");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c24xx-iis");
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.h b/sound/soc/s3c24xx/s3c24xx-i2s.h
index 726d91c..f9ca04e 100644
--- a/sound/soc/s3c24xx/s3c24xx-i2s.h
+++ b/sound/soc/s3c24xx/s3c24xx-i2s.h
@@ -32,6 +32,4 @@
u32 s3c24xx_i2s_get_clockrate(void);
-extern struct snd_soc_dai s3c24xx_i2s_dai;
-
#endif /*S3C24XXI2S_H_*/
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.c b/sound/soc/s3c24xx/s3c24xx_simtec.c
index 4984754..c4c1114 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec.c
+++ b/sound/soc/s3c24xx/s3c24xx_simtec.c
@@ -139,8 +139,10 @@
speaker_unmute_get, speaker_unmute_put),
};
-void simtec_audio_init(struct snd_soc_codec *codec)
+void simtec_audio_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
if (pdata->amp_gpio > 0) {
pr_debug("%s: adding amp routes\n", __func__);
@@ -170,8 +172,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* Set the CODEC as the bus clock master, I2S */
@@ -319,12 +321,12 @@
#endif
int __devinit simtec_audio_core_probe(struct platform_device *pdev,
- struct snd_soc_device *socdev)
+ struct snd_soc_card *card)
{
struct platform_device *snd_dev;
int ret;
- socdev->card->dai_link->ops = &simtec_snd_ops;
+ card->dai_link->ops = &simtec_snd_ops;
pdata = pdev->dev.platform_data;
if (!pdata) {
@@ -353,8 +355,7 @@
goto err_gpio;
}
- platform_set_drvdata(snd_dev, socdev);
- socdev->dev = &snd_dev->dev;
+ platform_set_drvdata(snd_dev, card);
ret = platform_device_add(snd_dev);
if (ret) {
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.h b/sound/soc/s3c24xx/s3c24xx_simtec.h
index e18faee..e63d5ff 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec.h
+++ b/sound/soc/s3c24xx/s3c24xx_simtec.h
@@ -7,10 +7,10 @@
* published by the Free Software Foundation.
*/
-extern void simtec_audio_init(struct snd_soc_codec *codec);
+extern void simtec_audio_init(struct snd_soc_pcm_runtime *rtd);
extern int simtec_audio_core_probe(struct platform_device *pdev,
- struct snd_soc_device *socdev);
+ struct snd_soc_card *card);
extern int simtec_audio_remove(struct platform_device *pdev);
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
index bdf8951..f884537 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
+++ b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
@@ -73,8 +73,10 @@
* Attach our controls and configure the necessary codec
* mappings for our sound card instance.
*/
-static int simtec_hermes_init(struct snd_soc_codec *codec)
+static int simtec_hermes_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
snd_soc_dapm_new_controls(codec, dapm_widgets,
ARRAY_SIZE(dapm_widgets));
@@ -85,42 +87,33 @@
snd_soc_dapm_enable_pin(codec, "Line Out");
snd_soc_dapm_enable_pin(codec, "Mic Jack");
- simtec_audio_init(codec);
+ simtec_audio_init(rtd);
snd_soc_dapm_sync(codec);
return 0;
}
-static struct aic3x_setup_data codec_setup = {
-};
-
static struct snd_soc_dai_link simtec_dai_aic33 = {
.name = "tlv320aic33",
.stream_name = "TLV320AIC33",
- .cpu_dai = &s3c24xx_i2s_dai,
- .codec_dai = &aic3x_dai,
+ .codec_name = "tlv320aic3x-codec.0-0x1a",
+ .cpu_dai_name = "s3c24xx-i2s",
+ .codec_dai_name = "tlv320aic3x-hifi",
+ .platform_name = "s3c24xx-pcm-audio",
.init = simtec_hermes_init,
};
/* simtec audio machine driver */
static struct snd_soc_card snd_soc_machine_simtec_aic33 = {
.name = "Simtec-Hermes",
- .platform = &s3c24xx_soc_platform,
.dai_link = &simtec_dai_aic33,
.num_links = 1,
};
-/* simtec audio subsystem */
-static struct snd_soc_device simtec_snd_devdata_aic33 = {
- .card = &snd_soc_machine_simtec_aic33,
- .codec_dev = &soc_codec_dev_aic3x,
- .codec_data = &codec_setup,
-};
-
static int __devinit simtec_audio_hermes_probe(struct platform_device *pd)
{
dev_info(&pd->dev, "probing....\n");
- return simtec_audio_core_probe(pd, &simtec_snd_devdata_aic33);
+ return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic33);
}
static struct platform_driver simtec_audio_hermes_platdrv = {
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
index 185c0ac..c096759 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
+++ b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
@@ -62,8 +62,10 @@
* Attach our controls and configure the necessary codec
* mappings for our sound card instance.
*/
-static int simtec_tlv320aic23_init(struct snd_soc_codec *codec)
+static int simtec_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
snd_soc_dapm_new_controls(codec, dapm_widgets,
ARRAY_SIZE(dapm_widgets));
@@ -74,7 +76,7 @@
snd_soc_dapm_enable_pin(codec, "Line Out");
snd_soc_dapm_enable_pin(codec, "Mic Jack");
- simtec_audio_init(codec);
+ simtec_audio_init(rtd);
snd_soc_dapm_sync(codec);
return 0;
@@ -83,28 +85,23 @@
static struct snd_soc_dai_link simtec_dai_aic23 = {
.name = "tlv320aic23",
.stream_name = "TLV320AIC23",
- .cpu_dai = &s3c24xx_i2s_dai,
- .codec_dai = &tlv320aic23_dai,
+ .codec_name = "tlv320aic3x-codec.0-0x1a",
+ .cpu_dai_name = "s3c24xx-i2s",
+ .codec_dai_name = "tlv320aic3x-hifi",
+ .platform_name = "s3c24xx-pcm-audio",
.init = simtec_tlv320aic23_init,
};
/* simtec audio machine driver */
static struct snd_soc_card snd_soc_machine_simtec_aic23 = {
.name = "Simtec",
- .platform = &s3c24xx_soc_platform,
.dai_link = &simtec_dai_aic23,
.num_links = 1,
};
-/* simtec audio subsystem */
-static struct snd_soc_device simtec_snd_devdata_aic23 = {
- .card = &snd_soc_machine_simtec_aic23,
- .codec_dev = &soc_codec_dev_tlv320aic23,
-};
-
static int __devinit simtec_audio_tlv320aic23_probe(struct platform_device *pd)
{
- return simtec_audio_core_probe(pd, &simtec_snd_devdata_aic23);
+ return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic23);
}
static struct platform_driver simtec_audio_tlv320aic23_platdrv = {
diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c
index 052d596..bd48ffb 100644
--- a/sound/soc/s3c24xx/s3c24xx_uda134x.c
+++ b/sound/soc/s3c24xx/s3c24xx_uda134x.c
@@ -133,8 +133,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int clk = 0;
int ret = 0;
int clk_source, fs_mode;
@@ -227,14 +227,15 @@
static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
.name = "UDA134X",
.stream_name = "UDA134X",
- .codec_dai = &uda134x_dai,
- .cpu_dai = &s3c24xx_i2s_dai,
+ .codec_name = "uda134x-hifi",
+ .codec_dai_name = "uda134x-hifi",
+ .cpu_dai_name = "s3c24xx-i2s",
.ops = &s3c24xx_uda134x_ops,
+ .platform_name = "s3c24xx-pcm-audio",
};
static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
.name = "S3C24XX_UDA134X",
- .platform = &s3c24xx_soc_platform,
.dai_link = &s3c24xx_uda134x_dai_link,
.num_links = 1,
};
@@ -256,6 +257,7 @@
gpio_set_value(s3c24xx_uda134x_l3_pins->l3_mode, v > 0);
}
+/* FIXME - This must be codec platform data but in which board file ?? */
static struct uda134x_platform_data s3c24xx_uda134x = {
.l3 = {
.setdat = setdat,
@@ -270,12 +272,6 @@
},
};
-static struct snd_soc_device s3c24xx_uda134x_snd_devdata = {
- .card = &snd_soc_s3c24xx_uda134x,
- .codec_dev = &soc_codec_dev_uda134x,
- .codec_data = &s3c24xx_uda134x,
-};
-
static int s3c24xx_uda134x_setup_pin(int pin, char *fun)
{
if (gpio_request(pin, "s3c24xx_uda134x") < 0) {
@@ -325,8 +321,7 @@
}
platform_set_drvdata(s3c24xx_uda134x_snd_device,
- &s3c24xx_uda134x_snd_devdata);
- s3c24xx_uda134x_snd_devdata.dev = &s3c24xx_uda134x_snd_device->dev;
+ &snd_soc_s3c24xx_uda134x);
ret = platform_device_add(s3c24xx_uda134x_snd_device);
if (ret) {
printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: Unable to add\n");
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s-v4.c b/sound/soc/s3c24xx/s3c64xx-i2s-v4.c
index 06db130..a962847 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s-v4.c
+++ b/sound/soc/s3c24xx/s3c64xx-i2s-v4.c
@@ -16,9 +16,7 @@
#include <sound/soc.h>
#include <sound/pcm_params.h>
-#include <mach/gpio-bank-c.h>
-#include <mach/gpio-bank-h.h>
-#include <plat/gpio-cfg.h>
+#include <plat/audio.h>
#include <mach/map.h>
#include <mach/dma.h>
@@ -39,34 +37,23 @@
static struct s3c_dma_params s3c64xx_i2sv4_pcm_stereo_in;
static struct s3c_i2sv2_info s3c64xx_i2sv4;
-struct snd_soc_dai s3c64xx_i2s_v4_dai;
-EXPORT_SYMBOL_GPL(s3c64xx_i2s_v4_dai);
-
-static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
+static int s3c64xx_i2sv4_probe(struct snd_soc_dai *dai)
{
- return cpu_dai->private_data;
-}
+ struct s3c_i2sv2_info *i2s = &s3c64xx_i2sv4;
+ int ret = 0;
-static int s3c64xx_i2sv4_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
-{
- /* configure GPIO for i2s port */
- s3c_gpio_cfgpin(S3C64XX_GPC(4), S3C64XX_GPC4_I2S_V40_DO0);
- s3c_gpio_cfgpin(S3C64XX_GPC(5), S3C64XX_GPC5_I2S_V40_DO1);
- s3c_gpio_cfgpin(S3C64XX_GPC(7), S3C64XX_GPC7_I2S_V40_DO2);
- s3c_gpio_cfgpin(S3C64XX_GPH(6), S3C64XX_GPH6_I2S_V40_BCLK);
- s3c_gpio_cfgpin(S3C64XX_GPH(7), S3C64XX_GPH7_I2S_V40_CDCLK);
- s3c_gpio_cfgpin(S3C64XX_GPH(8), S3C64XX_GPH8_I2S_V40_LRCLK);
- s3c_gpio_cfgpin(S3C64XX_GPH(9), S3C64XX_GPH9_I2S_V40_DI);
+ snd_soc_dai_set_drvdata(dai, i2s);
- return 0;
+ ret = s3c_i2sv2_probe(dai, i2s, i2s->base);
+
+ return ret;
}
static int s3c_i2sv4_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
- struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
+ struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(cpu_dai);
struct s3c_dma_params *dma_data;
u32 iismod;
@@ -104,51 +91,79 @@
.hw_params = s3c_i2sv4_hw_params,
};
+static struct snd_soc_dai_driver s3c64xx_i2s_v4_dai = {
+ .symmetric_rates = 1,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = S3C64XX_I2S_RATES,
+ .formats = S3C64XX_I2S_FMTS,
+ },
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = S3C64XX_I2S_RATES,
+ .formats = S3C64XX_I2S_FMTS,
+ },
+ .probe = s3c64xx_i2sv4_probe,
+ .ops = &s3c64xx_i2sv4_dai_ops,
+};
+
static __devinit int s3c64xx_i2sv4_dev_probe(struct platform_device *pdev)
{
+ struct s3c_audio_pdata *i2s_pdata;
struct s3c_i2sv2_info *i2s;
- struct snd_soc_dai *dai;
+ struct resource *res;
int ret;
i2s = &s3c64xx_i2sv4;
- dai = &s3c64xx_i2s_v4_dai;
-
- if (dai->dev) {
- dev_dbg(dai->dev, "%s: \
- I2Sv4 instance already registered!\n", __func__);
- return -EBUSY;
- }
-
- dai->dev = &pdev->dev;
- dai->name = "s3c64xx-i2s-v4";
- dai->id = 0;
- dai->symmetric_rates = 1;
- dai->playback.channels_min = 2;
- dai->playback.channels_max = 2;
- dai->playback.rates = S3C64XX_I2S_RATES;
- dai->playback.formats = S3C64XX_I2S_FMTS;
- dai->capture.channels_min = 2;
- dai->capture.channels_max = 2;
- dai->capture.rates = S3C64XX_I2S_RATES;
- dai->capture.formats = S3C64XX_I2S_FMTS;
- dai->probe = s3c64xx_i2sv4_probe;
- dai->ops = &s3c64xx_i2sv4_dai_ops;
i2s->feature |= S3C_FEATURE_CDCLKCON;
i2s->dma_capture = &s3c64xx_i2sv4_pcm_stereo_in;
i2s->dma_playback = &s3c64xx_i2sv4_pcm_stereo_out;
- i2s->dma_capture->channel = DMACH_HSI_I2SV40_RX;
- i2s->dma_capture->dma_addr = S3C64XX_PA_IISV4 + S3C2412_IISRXD;
- i2s->dma_playback->channel = DMACH_HSI_I2SV40_TX;
- i2s->dma_playback->dma_addr = S3C64XX_PA_IISV4 + S3C2412_IISTXD;
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get I2S-TX dma resource\n");
+ return -ENXIO;
+ }
+ i2s->dma_playback->channel = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get I2S-RX dma resource\n");
+ return -ENXIO;
+ }
+ i2s->dma_capture->channel = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get I2S SFR address\n");
+ return -ENXIO;
+ }
+
+ if (!request_mem_region(res->start, resource_size(res),
+ "s3c64xx-i2s-v4")) {
+ dev_err(&pdev->dev, "Unable to request SFR region\n");
+ return -EBUSY;
+ }
+ i2s->dma_capture->dma_addr = res->start + S3C2412_IISRXD;
+ i2s->dma_playback->dma_addr = res->start + S3C2412_IISTXD;
i2s->dma_capture->client = &s3c64xx_dma_client_in;
i2s->dma_capture->dma_size = 4;
i2s->dma_playback->client = &s3c64xx_dma_client_out;
i2s->dma_playback->dma_size = 4;
+ i2s->base = res->start;
+
+ i2s_pdata = pdev->dev.platform_data;
+ if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
+ dev_err(&pdev->dev, "Unable to configure gpio\n");
+ return -EINVAL;
+ }
+
i2s->iis_cclk = clk_get(&pdev->dev, "audio-bus");
if (IS_ERR(i2s->iis_cclk)) {
dev_err(&pdev->dev, "failed to get audio-bus\n");
@@ -158,19 +173,13 @@
clk_enable(i2s->iis_cclk);
- ret = s3c_i2sv2_probe(pdev, dai, i2s, 0);
- if (ret)
- goto err_clk;
-
- ret = s3c_i2sv2_register_dai(dai);
+ ret = s3c_i2sv2_register_dai(&pdev->dev, pdev->id, &s3c64xx_i2s_v4_dai);
if (ret != 0)
goto err_i2sv2;
return 0;
err_i2sv2:
- /* Not implemented for I2Sv2 core yet */
-err_clk:
clk_put(i2s->iis_cclk);
err:
return ret;
@@ -178,7 +187,18 @@
static __devexit int s3c64xx_i2sv4_dev_remove(struct platform_device *pdev)
{
- dev_err(&pdev->dev, "Device removal not yet supported\n");
+ struct s3c_i2sv2_info *i2s = &s3c64xx_i2sv4;
+ struct resource *res;
+
+ snd_soc_unregister_dai(&pdev->dev);
+ clk_put(i2s->iis_cclk);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, resource_size(res));
+ else
+ dev_warn(&pdev->dev, "Unable to get I2S SFR address\n");
+
return 0;
}
@@ -207,3 +227,4 @@
MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
MODULE_DESCRIPTION("S3C64XX I2Sv4 SoC Interface");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c64xx-iis-v4");
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c
index 1d85cb8..ae7acb6 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.c
@@ -12,15 +12,15 @@
* published by the Free Software Foundation.
*/
+#include <linux/module.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/io.h>
+#include <linux/slab.h>
#include <sound/soc.h>
-#include <mach/gpio-bank-d.h>
-#include <mach/gpio-bank-e.h>
-#include <plat/gpio-cfg.h>
+#include <plat/audio.h>
#include <mach/map.h>
#include <mach/dma.h>
@@ -46,45 +46,107 @@
static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_in[MAX_I2SV3];
static struct s3c_i2sv2_info s3c64xx_i2s[MAX_I2SV3];
-struct snd_soc_dai s3c64xx_i2s_dai[MAX_I2SV3];
-EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai);
-
-static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
+struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai)
{
- return cpu_dai->private_data;
+ struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(dai);
+ u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
+
+ if (iismod & S3C2412_IISMOD_IMS_SYSMUX)
+ return i2s->iis_cclk;
+ else
+ return i2s->iis_pclk;
}
+EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clock);
-static int s3c64xx_i2s_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int s3c64xx_i2s_probe(struct snd_soc_dai *dai)
{
- /* configure GPIO for i2s port */
- switch (dai->id) {
- case 0:
- s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_I2S0_CLK);
- s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_I2S0_CDCLK);
- s3c_gpio_cfgpin(S3C64XX_GPD(2), S3C64XX_GPD2_I2S0_LRCLK);
- s3c_gpio_cfgpin(S3C64XX_GPD(3), S3C64XX_GPD3_I2S0_DI);
- s3c_gpio_cfgpin(S3C64XX_GPD(4), S3C64XX_GPD4_I2S0_D0);
- break;
- case 1:
- s3c_gpio_cfgpin(S3C64XX_GPE(0), S3C64XX_GPE0_I2S1_CLK);
- s3c_gpio_cfgpin(S3C64XX_GPE(1), S3C64XX_GPE1_I2S1_CDCLK);
- s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_I2S1_LRCLK);
- s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_I2S1_DI);
- s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_I2S1_D0);
+ struct s3c_i2sv2_info *i2s;
+ int ret;
+
+ if (dai->id >= MAX_I2SV3) {
+ dev_err(dai->dev, "id %d out of range\n", dai->id);
+ return -EINVAL;
}
+ i2s = &s3c64xx_i2s[dai->id];
+ snd_soc_dai_set_drvdata(dai, i2s);
+
+ i2s->iis_cclk = clk_get(dai->dev, "audio-bus");
+ if (IS_ERR(i2s->iis_cclk)) {
+ dev_err(dai->dev, "failed to get audio-bus\n");
+ ret = PTR_ERR(i2s->iis_cclk);
+ goto err;
+ }
+
+ clk_enable(i2s->iis_cclk);
+
+ ret = s3c_i2sv2_probe(dai, i2s, i2s->base);
+ if (ret)
+ goto err_clk;
+
+ return 0;
+
+err_clk:
+ clk_disable(i2s->iis_cclk);
+ clk_put(i2s->iis_cclk);
+err:
+ kfree(i2s);
+ return ret;
+}
+
+static int s3c64xx_i2s_remove(struct snd_soc_dai *dai)
+{
+ struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(dai);
+
+ clk_disable(i2s->iis_cclk);
+ clk_put(i2s->iis_cclk);
+ kfree(i2s);
return 0;
}
-
static struct snd_soc_dai_ops s3c64xx_i2s_dai_ops;
+static struct snd_soc_dai_driver s3c64xx_i2s_dai[MAX_I2SV3] = {
+{
+ .name = "s3c64xx-i2s-0",
+ .probe = s3c64xx_i2s_probe,
+ .remove = s3c64xx_i2s_remove,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = S3C64XX_I2S_RATES,
+ .formats = S3C64XX_I2S_FMTS,},
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = S3C64XX_I2S_RATES,
+ .formats = S3C64XX_I2S_FMTS,},
+ .ops = &s3c64xx_i2s_dai_ops,
+ .symmetric_rates = 1,
+}, {
+ .name = "s3c64xx-i2s-1",
+ .probe = s3c64xx_i2s_probe,
+ .remove = s3c64xx_i2s_remove,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = S3C64XX_I2S_RATES,
+ .formats = S3C64XX_I2S_FMTS,},
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = S3C64XX_I2S_RATES,
+ .formats = S3C64XX_I2S_FMTS,},
+ .ops = &s3c64xx_i2s_dai_ops,
+ .symmetric_rates = 1,
+},};
+
static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev)
{
+ struct s3c_audio_pdata *i2s_pdata;
struct s3c_i2sv2_info *i2s;
- struct snd_soc_dai *dai;
- int ret;
+ struct resource *res;
+ int i, ret;
if (pdev->id >= MAX_I2SV3) {
dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
@@ -92,74 +154,63 @@
}
i2s = &s3c64xx_i2s[pdev->id];
- dai = &s3c64xx_i2s_dai[pdev->id];
- dai->dev = &pdev->dev;
- dai->name = "s3c64xx-i2s";
- dai->id = pdev->id;
- dai->symmetric_rates = 1;
- dai->playback.channels_min = 2;
- dai->playback.channels_max = 2;
- dai->playback.rates = S3C64XX_I2S_RATES;
- dai->playback.formats = S3C64XX_I2S_FMTS;
- dai->capture.channels_min = 2;
- dai->capture.channels_max = 2;
- dai->capture.rates = S3C64XX_I2S_RATES;
- dai->capture.formats = S3C64XX_I2S_FMTS;
- dai->probe = s3c64xx_i2s_probe;
- dai->ops = &s3c64xx_i2s_dai_ops;
-
- i2s->feature |= S3C_FEATURE_CDCLKCON;
i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id];
i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id];
- if (pdev->id == 0) {
- i2s->dma_capture->channel = DMACH_I2S0_IN;
- i2s->dma_capture->dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISRXD;
- i2s->dma_playback->channel = DMACH_I2S0_OUT;
- i2s->dma_playback->dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISTXD;
- } else {
- i2s->dma_capture->channel = DMACH_I2S1_IN;
- i2s->dma_capture->dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISRXD;
- i2s->dma_playback->channel = DMACH_I2S1_OUT;
- i2s->dma_playback->dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISTXD;
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get I2S-TX dma resource\n");
+ return -ENXIO;
}
+ i2s->dma_playback->channel = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get I2S-RX dma resource\n");
+ return -ENXIO;
+ }
+ i2s->dma_capture->channel = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get I2S SFR address\n");
+ return -ENXIO;
+ }
+
+ if (!request_mem_region(res->start, resource_size(res),
+ "s3c64xx-i2s")) {
+ dev_err(&pdev->dev, "Unable to request SFR region\n");
+ return -EBUSY;
+ }
+ i2s->base = res->start;
+
+ i2s_pdata = pdev->dev.platform_data;
+ if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
+ dev_err(&pdev->dev, "Unable to configure gpio\n");
+ return -EINVAL;
+ }
+ i2s->dma_capture->dma_addr = res->start + S3C2412_IISRXD;
+ i2s->dma_playback->dma_addr = res->start + S3C2412_IISTXD;
i2s->dma_capture->client = &s3c64xx_dma_client_in;
i2s->dma_capture->dma_size = 4;
i2s->dma_playback->client = &s3c64xx_dma_client_out;
i2s->dma_playback->dma_size = 4;
- i2s->iis_cclk = clk_get(&pdev->dev, "audio-bus");
- if (IS_ERR(i2s->iis_cclk)) {
- dev_err(&pdev->dev, "failed to get audio-bus\n");
- ret = PTR_ERR(i2s->iis_cclk);
- goto err;
+ for (i = 0; i < ARRAY_SIZE(s3c64xx_i2s_dai); i++) {
+ ret = s3c_i2sv2_register_dai(&pdev->dev, i,
+ &s3c64xx_i2s_dai[i]);
+ if (ret != 0)
+ return ret;
}
- clk_enable(i2s->iis_cclk);
-
- ret = s3c_i2sv2_probe(pdev, dai, i2s, 0);
- if (ret)
- goto err_clk;
-
- ret = s3c_i2sv2_register_dai(dai);
- if (ret != 0)
- goto err_i2sv2;
-
return 0;
-
-err_i2sv2:
- /* Not implemented for I2Sv2 core yet */
-err_clk:
- clk_put(i2s->iis_cclk);
-err:
- return ret;
}
static __devexit int s3c64xx_iis_dev_remove(struct platform_device *pdev)
{
- dev_err(&pdev->dev, "Device removal not yet supported\n");
+ snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c64xx_i2s_dai));
return 0;
}
@@ -188,3 +239,4 @@
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
MODULE_DESCRIPTION("S3C64XX I2S SoC Interface");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c64xx-iis");
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.h b/sound/soc/s3c24xx/s3c64xx-i2s.h
index 7a40f43..de4075d 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s.h
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.h
@@ -36,7 +36,6 @@
(SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S24_LE)
-extern struct snd_soc_dai s3c64xx_i2s_dai[];
-extern struct snd_soc_dai s3c64xx_i2s_v4_dai;
+struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai);
#endif /* __SND_SOC_S3C24XX_S3C64XX_I2S_H */
diff --git a/sound/soc/s3c24xx/smartq_wm8987.c b/sound/soc/s3c24xx/smartq_wm8987.c
index b480348..dd20ca7 100644
--- a/sound/soc/s3c24xx/smartq_wm8987.c
+++ b/sound/soc/s3c24xx/smartq_wm8987.c
@@ -211,8 +211,10 @@
{
.name = "wm8987",
.stream_name = "SmartQ Hi-Fi",
- .cpu_dai = &s3c64xx_i2s_dai[0],
- .codec_dai = &wm8750_dai,
+ .cpu_dai_name = "s3c64xx-i2s.0",
+ .codec_dai_name = "wm8750-hifi",
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8750-codec.0-0x1a",
.init = smartq_wm8987_init,
.ops = &smartq_hifi_ops,
},
@@ -220,16 +222,10 @@
static struct snd_soc_card snd_soc_smartq = {
.name = "SmartQ",
- .platform = &s3c24xx_soc_platform,
.dai_link = smartq_dai,
.num_links = ARRAY_SIZE(smartq_dai),
};
-static struct snd_soc_device smartq_snd_devdata = {
- .card = &snd_soc_smartq,
- .codec_dev = &soc_codec_dev_wm8750,
-};
-
static struct platform_device *smartq_snd_device;
static int __init smartq_init(void)
@@ -245,8 +241,7 @@
if (!smartq_snd_device)
return -ENOMEM;
- platform_set_drvdata(smartq_snd_device, &smartq_snd_devdata);
- smartq_snd_devdata.dev = &smartq_snd_device->dev;
+ platform_set_drvdata(smartq_snd_device, &snd_soc_smartq);
ret = platform_device_add(smartq_snd_device);
if (ret) {
diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c
index 3622588..4613288 100644
--- a/sound/soc/s3c24xx/smdk2443_wm9710.c
+++ b/sound/soc/s3c24xx/smdk2443_wm9710.c
@@ -19,7 +19,6 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
-#include "../codecs/ac97.h"
#include "s3c-dma.h"
#include "s3c-ac97.h"
@@ -29,23 +28,19 @@
{
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM],
- .codec_dai = &ac97_dai,
+ .cpu_dai_name = "s3c-ac97",
+ .codec_dai_name = "ac97-hifi",
+ .codec_name = "ac97-codec",
+ .platform_name = "s3c24xx-pcm-audio",
},
};
static struct snd_soc_card smdk2443 = {
.name = "SMDK2443",
- .platform = &s3c24xx_soc_platform,
.dai_link = smdk2443_dai,
.num_links = ARRAY_SIZE(smdk2443_dai),
};
-static struct snd_soc_device smdk2443_snd_ac97_devdata = {
- .card = &smdk2443,
- .codec_dev = &soc_codec_dev_ac97,
-};
-
static struct platform_device *smdk2443_snd_ac97_device;
static int __init smdk2443_init(void)
@@ -56,9 +51,7 @@
if (!smdk2443_snd_ac97_device)
return -ENOMEM;
- platform_set_drvdata(smdk2443_snd_ac97_device,
- &smdk2443_snd_ac97_devdata);
- smdk2443_snd_ac97_devdata.dev = &smdk2443_snd_ac97_device->dev;
+ platform_set_drvdata(smdk2443_snd_ac97_device, &smdk2443);
ret = platform_device_add(smdk2443_snd_ac97_device);
if (ret)
diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c
index 07e8e51..052e499 100644
--- a/sound/soc/s3c24xx/smdk64xx_wm8580.c
+++ b/sound/soc/s3c24xx/smdk64xx_wm8580.c
@@ -22,6 +22,12 @@
#include "s3c-dma.h"
#include "s3c64xx-i2s.h"
+/*
+ * Default CFG switch settings to use this driver:
+ *
+ * SMDK6410: Set CFG1 1-3 Off, CFG2 1-4 On
+ */
+
/* SMDK64XX has a 12MHZ crystal attached to WM8580 */
#define SMDK64XX_WM8580_FREQ 12000000
@@ -29,8 +35,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
unsigned int pll_out;
int bfs, rfs, ret;
@@ -107,14 +113,13 @@
if (ret < 0)
return ret;
- /* Explicitly set WM8580-DAC to source from MCLK */
- ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_DAC_CLKSEL,
- WM8580_CLKSRC_MCLK);
+ ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
+ SMDK64XX_WM8580_FREQ, pll_out);
if (ret < 0)
return ret;
- ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
- SMDK64XX_WM8580_FREQ, pll_out);
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA,
+ pll_out, SND_SOC_CLOCK_IN);
if (ret < 0)
return ret;
@@ -138,9 +143,9 @@
/* SMDK64xx Playback widgets */
static const struct snd_soc_dapm_widget wm8580_dapm_widgets_pbk[] = {
- SND_SOC_DAPM_HP("Front-L/R", NULL),
- SND_SOC_DAPM_HP("Center/Sub", NULL),
- SND_SOC_DAPM_HP("Rear-L/R", NULL),
+ SND_SOC_DAPM_HP("Front", NULL),
+ SND_SOC_DAPM_HP("Center+Sub", NULL),
+ SND_SOC_DAPM_HP("Rear", NULL),
};
/* SMDK64xx Capture widgets */
@@ -162,20 +167,22 @@
/* SMDK-PAIFRX connections */
static const struct snd_soc_dapm_route audio_map_rx[] = {
/* Front Left/Right are fed VOUT1L/R */
- {"Front-L/R", NULL, "VOUT1L"},
- {"Front-L/R", NULL, "VOUT1R"},
+ {"Front", NULL, "VOUT1L"},
+ {"Front", NULL, "VOUT1R"},
/* Center/Sub are fed VOUT2L/R */
- {"Center/Sub", NULL, "VOUT2L"},
- {"Center/Sub", NULL, "VOUT2R"},
+ {"Center+Sub", NULL, "VOUT2L"},
+ {"Center+Sub", NULL, "VOUT2R"},
/* Rear Left/Right are fed VOUT3L/R */
- {"Rear-L/R", NULL, "VOUT3L"},
- {"Rear-L/R", NULL, "VOUT3R"},
+ {"Rear", NULL, "VOUT3L"},
+ {"Rear", NULL, "VOUT3R"},
};
-static int smdk64xx_wm8580_init_paiftx(struct snd_soc_codec *codec)
+static int smdk64xx_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
/* Add smdk64xx specific Capture widgets */
snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_cpt,
ARRAY_SIZE(wm8580_dapm_widgets_cpt));
@@ -194,8 +201,10 @@
return 0;
}
-static int smdk64xx_wm8580_init_paifrx(struct snd_soc_codec *codec)
+static int smdk64xx_wm8580_init_paifrx(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
/* Add smdk64xx specific Playback widgets */
snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_pbk,
ARRAY_SIZE(wm8580_dapm_widgets_pbk));
@@ -213,33 +222,31 @@
{ /* Primary Playback i/f */
.name = "WM8580 PAIF RX",
.stream_name = "Playback",
- .cpu_dai = &s3c64xx_i2s_v4_dai,
- .codec_dai = &wm8580_dai[WM8580_DAI_PAIFRX],
+ .cpu_dai_name = "s3c64xx-iis-v4",
+ .codec_dai_name = "wm8580-hifi-playback",
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8580-codec.0-001b",
.init = smdk64xx_wm8580_init_paifrx,
.ops = &smdk64xx_ops,
},
{ /* Primary Capture i/f */
.name = "WM8580 PAIF TX",
.stream_name = "Capture",
- .cpu_dai = &s3c64xx_i2s_v4_dai,
- .codec_dai = &wm8580_dai[WM8580_DAI_PAIFTX],
+ .cpu_dai_name = "s3c64xx-iis-v4",
+ .codec_dai_name = "wm8580-hifi-capture",
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8580-codec.0-001b",
.init = smdk64xx_wm8580_init_paiftx,
.ops = &smdk64xx_ops,
},
};
static struct snd_soc_card smdk64xx = {
- .name = "smdk64xx",
- .platform = &s3c24xx_soc_platform,
+ .name = "SMDK64xx 5.1",
.dai_link = smdk64xx_dai,
.num_links = ARRAY_SIZE(smdk64xx_dai),
};
-static struct snd_soc_device smdk64xx_snd_devdata = {
- .card = &smdk64xx,
- .codec_dev = &soc_codec_dev_wm8580,
-};
-
static struct platform_device *smdk64xx_snd_device;
static int __init smdk64xx_audio_init(void)
@@ -250,8 +257,7 @@
if (!smdk64xx_snd_device)
return -ENOMEM;
- platform_set_drvdata(smdk64xx_snd_device, &smdk64xx_snd_devdata);
- smdk64xx_snd_devdata.dev = &smdk64xx_snd_device->dev;
+ platform_set_drvdata(smdk64xx_snd_device, &smdk64xx);
ret = platform_device_add(smdk64xx_snd_device);
if (ret)
diff --git a/sound/soc/s3c24xx/smdk_spdif.c b/sound/soc/s3c24xx/smdk_spdif.c
new file mode 100644
index 0000000..f31d22a
--- /dev/null
+++ b/sound/soc/s3c24xx/smdk_spdif.c
@@ -0,0 +1,223 @@
+/*
+ * smdk_spdif.c -- S/PDIF audio for SMDK
+ *
+ * Copyright 2010 Samsung Electronics Co. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+
+#include <plat/devs.h>
+
+#include <sound/soc.h>
+
+#include "s3c-dma.h"
+#include "spdif.h"
+
+/* Audio clock settings are belonged to board specific part. Every
+ * board can set audio source clock setting which is matched with H/W
+ * like this function-'set_audio_clock_heirachy'.
+ */
+static int set_audio_clock_heirachy(struct platform_device *pdev)
+{
+ struct clk *fout_epll, *mout_epll, *sclk_audio0, *sclk_spdif;
+ int ret;
+
+ fout_epll = clk_get(NULL, "fout_epll");
+ if (IS_ERR(fout_epll)) {
+ printk(KERN_WARNING "%s: Cannot find fout_epll.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ mout_epll = clk_get(NULL, "mout_epll");
+ if (IS_ERR(fout_epll)) {
+ printk(KERN_WARNING "%s: Cannot find mout_epll.\n",
+ __func__);
+ ret = -EINVAL;
+ goto out1;
+ }
+
+ sclk_audio0 = clk_get(&pdev->dev, "sclk_audio");
+ if (IS_ERR(sclk_audio0)) {
+ printk(KERN_WARNING "%s: Cannot find sclk_audio.\n",
+ __func__);
+ ret = -EINVAL;
+ goto out2;
+ }
+
+ sclk_spdif = clk_get(NULL, "sclk_spdif");
+ if (IS_ERR(fout_epll)) {
+ printk(KERN_WARNING "%s: Cannot find sclk_spdif.\n",
+ __func__);
+ ret = -EINVAL;
+ goto out3;
+ }
+
+ /* Set audio clock heirachy for S/PDIF */
+ clk_set_parent(mout_epll, fout_epll);
+ clk_set_parent(sclk_audio0, mout_epll);
+ clk_set_parent(sclk_spdif, sclk_audio0);
+
+ clk_put(sclk_spdif);
+out3:
+ clk_put(sclk_audio0);
+out2:
+ clk_put(mout_epll);
+out1:
+ clk_put(fout_epll);
+
+ return ret;
+}
+
+/* We should haved to set clock directly on this part because of clock
+ * scheme of Samsudng SoCs did not support to set rates from abstrct
+ * clock of it's heirachy.
+ */
+static int set_audio_clock_rate(unsigned long epll_rate,
+ unsigned long audio_rate)
+{
+ struct clk *fout_epll, *sclk_spdif;
+
+ fout_epll = clk_get(NULL, "fout_epll");
+ if (IS_ERR(fout_epll)) {
+ printk(KERN_ERR "%s: failed to get fout_epll\n", __func__);
+ return -ENOENT;
+ }
+
+ clk_set_rate(fout_epll, epll_rate);
+ clk_put(fout_epll);
+
+ sclk_spdif = clk_get(NULL, "sclk_spdif");
+ if (IS_ERR(sclk_spdif)) {
+ printk(KERN_ERR "%s: failed to get sclk_spdif\n", __func__);
+ return -ENOENT;
+ }
+
+ clk_set_rate(sclk_spdif, audio_rate);
+ clk_put(sclk_spdif);
+
+ return 0;
+}
+
+static int smdk_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ unsigned long pll_out, rclk_rate;
+ int ret, ratio;
+
+ switch (params_rate(params)) {
+ case 44100:
+ pll_out = 45158400;
+ break;
+ case 32000:
+ case 48000:
+ case 96000:
+ pll_out = 49152000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Setting ratio to 512fs helps to use S/PDIF with HDMI without
+ * modify S/PDIF ASoC machine driver.
+ */
+ ratio = 512;
+ rclk_rate = params_rate(params) * ratio;
+
+ /* Set audio source clock rates */
+ ret = set_audio_clock_rate(pll_out, rclk_rate);
+ if (ret < 0)
+ return ret;
+
+ /* Set S/PDIF uses internal source clock */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, SND_SOC_SPDIF_INT_MCLK,
+ rclk_rate, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+static struct snd_soc_ops smdk_spdif_ops = {
+ .hw_params = smdk_hw_params,
+};
+
+static struct snd_soc_card smdk;
+
+static struct snd_soc_dai_link smdk_dai = {
+ .name = "S/PDIF",
+ .stream_name = "S/PDIF PCM Playback",
+ .platform_name = "s3c24xx-pcm-audio",
+ .cpu_dai_name = "samsung-spdif",
+ .codec_dai_name = "dit-hifi",
+ .codec_name = "spdif-dit",
+ .ops = &smdk_spdif_ops,
+};
+
+static struct snd_soc_card smdk = {
+ .name = "SMDK-S/PDIF",
+ .dai_link = &smdk_dai,
+ .num_links = 1,
+};
+
+static struct platform_device *smdk_snd_spdif_dit_device;
+static struct platform_device *smdk_snd_spdif_device;
+
+static int __init smdk_init(void)
+{
+ int ret;
+
+ smdk_snd_spdif_dit_device = platform_device_alloc("spdif-dit", -1);
+ if (!smdk_snd_spdif_dit_device)
+ return -ENOMEM;
+
+ ret = platform_device_add(smdk_snd_spdif_dit_device);
+ if (ret)
+ goto err2;
+
+ smdk_snd_spdif_device = platform_device_alloc("soc-audio", -1);
+ if (!smdk_snd_spdif_device) {
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ platform_set_drvdata(smdk_snd_spdif_device, &smdk);
+
+ ret = platform_device_add(smdk_snd_spdif_device);
+ if (ret)
+ goto err1;
+
+ /* Set audio clock heirachy manually */
+ ret = set_audio_clock_heirachy(smdk_snd_spdif_device);
+ if (ret)
+ goto err1;
+
+ return 0;
+err1:
+ platform_device_put(smdk_snd_spdif_device);
+err2:
+ platform_device_put(smdk_snd_spdif_dit_device);
+ return ret;
+}
+
+static void __exit smdk_exit(void)
+{
+ platform_device_unregister(smdk_snd_spdif_device);
+}
+
+module_init(smdk_init);
+module_exit(smdk_exit);
+
+MODULE_AUTHOR("Seungwhan Youn, <sw.youn@samsung.com>");
+MODULE_DESCRIPTION("ALSA SoC SMDK+S/PDIF");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/smdk_wm9713.c b/sound/soc/s3c24xx/smdk_wm9713.c
index 5527b9e..33ba8fd 100644
--- a/sound/soc/s3c24xx/smdk_wm9713.c
+++ b/sound/soc/s3c24xx/smdk_wm9713.c
@@ -15,7 +15,6 @@
#include <linux/device.h>
#include <sound/soc.h>
-#include "../codecs/wm9713.h"
#include "s3c-dma.h"
#include "s3c-ac97.h"
@@ -46,46 +45,57 @@
static struct snd_soc_dai_link smdk_dai = {
.name = "AC97",
.stream_name = "AC97 PCM",
- .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM],
- .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI],
+ .platform_name = "s3c24xx-pcm-audio",
+ .cpu_dai_name = "s3c-ac97",
+ .codec_dai_name = "wm9713-hifi",
+ .codec_name = "wm9713-codec",
};
static struct snd_soc_card smdk = {
- .name = "SMDK",
- .platform = &s3c24xx_soc_platform,
+ .name = "SMDK WM9713",
.dai_link = &smdk_dai,
.num_links = 1,
};
-static struct snd_soc_device smdk_snd_ac97_devdata = {
- .card = &smdk,
- .codec_dev = &soc_codec_dev_wm9713,
-};
-
+static struct platform_device *smdk_snd_wm9713_device;
static struct platform_device *smdk_snd_ac97_device;
static int __init smdk_init(void)
{
int ret;
- smdk_snd_ac97_device = platform_device_alloc("soc-audio", -1);
- if (!smdk_snd_ac97_device)
+ smdk_snd_wm9713_device = platform_device_alloc("wm9713-codec", -1);
+ if (!smdk_snd_wm9713_device)
return -ENOMEM;
- platform_set_drvdata(smdk_snd_ac97_device,
- &smdk_snd_ac97_devdata);
- smdk_snd_ac97_devdata.dev = &smdk_snd_ac97_device->dev;
+ ret = platform_device_add(smdk_snd_wm9713_device);
+ if (ret)
+ goto err;
+
+ smdk_snd_ac97_device = platform_device_alloc("soc-audio", -1);
+ if (!smdk_snd_ac97_device) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ platform_set_drvdata(smdk_snd_ac97_device, &smdk);
ret = platform_device_add(smdk_snd_ac97_device);
- if (ret)
+ if (ret) {
platform_device_put(smdk_snd_ac97_device);
+ goto err;
+ }
+ return 0;
+err:
+ platform_device_put(smdk_snd_wm9713_device);
return ret;
}
static void __exit smdk_exit(void)
{
platform_device_unregister(smdk_snd_ac97_device);
+ platform_device_unregister(smdk_snd_wm9713_device);
}
module_init(smdk_init);
diff --git a/sound/soc/s3c24xx/spdif.c b/sound/soc/s3c24xx/spdif.c
new file mode 100644
index 0000000..ce554e9
--- /dev/null
+++ b/sound/soc/s3c24xx/spdif.c
@@ -0,0 +1,501 @@
+/* sound/soc/s3c24xx/spdif.c
+ *
+ * ALSA SoC Audio Layer - Samsung S/PDIF Controller driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ * http://www.samsung.com/
+ *
+ * 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/clk.h>
+#include <linux/io.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <plat/audio.h>
+#include <mach/dma.h>
+
+#include "s3c-dma.h"
+#include "spdif.h"
+
+/* Registers */
+#define CLKCON 0x00
+#define CON 0x04
+#define BSTAS 0x08
+#define CSTAS 0x0C
+#define DATA_OUTBUF 0x10
+#define DCNT 0x14
+#define BSTAS_S 0x18
+#define DCNT_S 0x1C
+
+#define CLKCTL_MASK 0x7
+#define CLKCTL_MCLK_EXT (0x1 << 2)
+#define CLKCTL_PWR_ON (0x1 << 0)
+
+#define CON_MASK 0x3ffffff
+#define CON_FIFO_TH_SHIFT 19
+#define CON_FIFO_TH_MASK (0x7 << 19)
+#define CON_USERDATA_23RDBIT (0x1 << 12)
+
+#define CON_SW_RESET (0x1 << 5)
+
+#define CON_MCLKDIV_MASK (0x3 << 3)
+#define CON_MCLKDIV_256FS (0x0 << 3)
+#define CON_MCLKDIV_384FS (0x1 << 3)
+#define CON_MCLKDIV_512FS (0x2 << 3)
+
+#define CON_PCM_MASK (0x3 << 1)
+#define CON_PCM_16BIT (0x0 << 1)
+#define CON_PCM_20BIT (0x1 << 1)
+#define CON_PCM_24BIT (0x2 << 1)
+
+#define CON_PCM_DATA (0x1 << 0)
+
+#define CSTAS_MASK 0x3fffffff
+#define CSTAS_SAMP_FREQ_MASK (0xF << 24)
+#define CSTAS_SAMP_FREQ_44 (0x0 << 24)
+#define CSTAS_SAMP_FREQ_48 (0x2 << 24)
+#define CSTAS_SAMP_FREQ_32 (0x3 << 24)
+#define CSTAS_SAMP_FREQ_96 (0xA << 24)
+
+#define CSTAS_CATEGORY_MASK (0xFF << 8)
+#define CSTAS_CATEGORY_CODE_CDP (0x01 << 8)
+
+#define CSTAS_NO_COPYRIGHT (0x1 << 2)
+
+/**
+ * struct samsung_spdif_info - Samsung S/PDIF Controller information
+ * @lock: Spin lock for S/PDIF.
+ * @dev: The parent device passed to use from the probe.
+ * @regs: The pointer to the device register block.
+ * @clk_rate: Current clock rate for calcurate ratio.
+ * @pclk: The peri-clock pointer for spdif master operation.
+ * @sclk: The source clock pointer for making sync signals.
+ * @save_clkcon: Backup clkcon reg. in suspend.
+ * @save_con: Backup con reg. in suspend.
+ * @save_cstas: Backup cstas reg. in suspend.
+ * @dma_playback: DMA information for playback channel.
+ */
+struct samsung_spdif_info {
+ spinlock_t lock;
+ struct device *dev;
+ void __iomem *regs;
+ unsigned long clk_rate;
+ struct clk *pclk;
+ struct clk *sclk;
+ u32 saved_clkcon;
+ u32 saved_con;
+ u32 saved_cstas;
+ struct s3c_dma_params *dma_playback;
+};
+
+static struct s3c2410_dma_client spdif_dma_client_out = {
+ .name = "S/PDIF Stereo out",
+};
+
+static struct s3c_dma_params spdif_stereo_out;
+static struct samsung_spdif_info spdif_info;
+
+static inline struct samsung_spdif_info *to_info(struct snd_soc_dai *cpu_dai)
+{
+ return snd_soc_dai_get_drvdata(cpu_dai);
+}
+
+static void spdif_snd_txctrl(struct samsung_spdif_info *spdif, int on)
+{
+ void __iomem *regs = spdif->regs;
+ u32 clkcon;
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
+ if (on)
+ writel(clkcon | CLKCTL_PWR_ON, regs + CLKCON);
+ else
+ writel(clkcon & ~CLKCTL_PWR_ON, regs + CLKCON);
+}
+
+static int spdif_set_sysclk(struct snd_soc_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct samsung_spdif_info *spdif = to_info(cpu_dai);
+ u32 clkcon;
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ clkcon = readl(spdif->regs + CLKCON);
+
+ if (clk_id == SND_SOC_SPDIF_INT_MCLK)
+ clkcon &= ~CLKCTL_MCLK_EXT;
+ else
+ clkcon |= CLKCTL_MCLK_EXT;
+
+ writel(clkcon, spdif->regs + CLKCON);
+
+ spdif->clk_rate = freq;
+
+ return 0;
+}
+
+static int spdif_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
+ unsigned long flags;
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ spin_lock_irqsave(&spdif->lock, flags);
+ spdif_snd_txctrl(spdif, 1);
+ spin_unlock_irqrestore(&spdif->lock, flags);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ spin_lock_irqsave(&spdif->lock, flags);
+ spdif_snd_txctrl(spdif, 0);
+ spin_unlock_irqrestore(&spdif->lock, flags);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int spdif_sysclk_ratios[] = {
+ 512, 384, 256,
+};
+
+static int spdif_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *socdai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
+ void __iomem *regs = spdif->regs;
+ struct s3c_dma_params *dma_data;
+ u32 con, clkcon, cstas;
+ unsigned long flags;
+ int i, ratio;
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dma_data = spdif->dma_playback;
+ else {
+ dev_err(spdif->dev, "Capture is not supported\n");
+ return -EINVAL;
+ }
+
+ snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
+
+ spin_lock_irqsave(&spdif->lock, flags);
+
+ con = readl(regs + CON) & CON_MASK;
+ cstas = readl(regs + CSTAS) & CSTAS_MASK;
+ clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
+
+ con &= ~CON_FIFO_TH_MASK;
+ con |= (0x7 << CON_FIFO_TH_SHIFT);
+ con |= CON_USERDATA_23RDBIT;
+ con |= CON_PCM_DATA;
+
+ con &= ~CON_PCM_MASK;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ con |= CON_PCM_16BIT;
+ break;
+ default:
+ dev_err(spdif->dev, "Unsupported data size.\n");
+ goto err;
+ }
+
+ ratio = spdif->clk_rate / params_rate(params);
+ for (i = 0; i < ARRAY_SIZE(spdif_sysclk_ratios); i++)
+ if (ratio == spdif_sysclk_ratios[i])
+ break;
+ if (i == ARRAY_SIZE(spdif_sysclk_ratios)) {
+ dev_err(spdif->dev, "Invalid clock ratio %ld/%d\n",
+ spdif->clk_rate, params_rate(params));
+ goto err;
+ }
+
+ con &= ~CON_MCLKDIV_MASK;
+ switch (ratio) {
+ case 256:
+ con |= CON_MCLKDIV_256FS;
+ break;
+ case 384:
+ con |= CON_MCLKDIV_384FS;
+ break;
+ case 512:
+ con |= CON_MCLKDIV_512FS;
+ break;
+ }
+
+ cstas &= ~CSTAS_SAMP_FREQ_MASK;
+ switch (params_rate(params)) {
+ case 44100:
+ cstas |= CSTAS_SAMP_FREQ_44;
+ break;
+ case 48000:
+ cstas |= CSTAS_SAMP_FREQ_48;
+ break;
+ case 32000:
+ cstas |= CSTAS_SAMP_FREQ_32;
+ break;
+ case 96000:
+ cstas |= CSTAS_SAMP_FREQ_96;
+ break;
+ default:
+ dev_err(spdif->dev, "Invalid sampling rate %d\n",
+ params_rate(params));
+ goto err;
+ }
+
+ cstas &= ~CSTAS_CATEGORY_MASK;
+ cstas |= CSTAS_CATEGORY_CODE_CDP;
+ cstas |= CSTAS_NO_COPYRIGHT;
+
+ writel(con, regs + CON);
+ writel(cstas, regs + CSTAS);
+ writel(clkcon, regs + CLKCON);
+
+ spin_unlock_irqrestore(&spdif->lock, flags);
+
+ return 0;
+err:
+ spin_unlock_irqrestore(&spdif->lock, flags);
+ return -EINVAL;
+}
+
+static void spdif_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
+ void __iomem *regs = spdif->regs;
+ u32 con, clkcon;
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ con = readl(regs + CON) & CON_MASK;
+ clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
+
+ writel(con | CON_SW_RESET, regs + CON);
+ cpu_relax();
+
+ writel(clkcon & ~CLKCTL_PWR_ON, regs + CLKCON);
+}
+
+#ifdef CONFIG_PM
+static int spdif_suspend(struct snd_soc_dai *cpu_dai)
+{
+ struct samsung_spdif_info *spdif = to_info(cpu_dai);
+ u32 con = spdif->saved_con;
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ spdif->saved_clkcon = readl(spdif->regs + CLKCON) & CLKCTL_MASK;
+ spdif->saved_con = readl(spdif->regs + CON) & CON_MASK;
+ spdif->saved_cstas = readl(spdif->regs + CSTAS) & CSTAS_MASK;
+
+ writel(con | CON_SW_RESET, spdif->regs + CON);
+ cpu_relax();
+
+ return 0;
+}
+
+static int spdif_resume(struct snd_soc_dai *cpu_dai)
+{
+ struct samsung_spdif_info *spdif = to_info(cpu_dai);
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ writel(spdif->saved_clkcon, spdif->regs + CLKCON);
+ writel(spdif->saved_con, spdif->regs + CON);
+ writel(spdif->saved_cstas, spdif->regs + CSTAS);
+
+ return 0;
+}
+#else
+#define spdif_suspend NULL
+#define spdif_resume NULL
+#endif
+
+static struct snd_soc_dai_ops spdif_dai_ops = {
+ .set_sysclk = spdif_set_sysclk,
+ .trigger = spdif_trigger,
+ .hw_params = spdif_hw_params,
+ .shutdown = spdif_shutdown,
+};
+
+struct snd_soc_dai_driver samsung_spdif_dai = {
+ .name = "samsung-spdif",
+ .playback = {
+ .stream_name = "S/PDIF Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = (SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_96000),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE, },
+ .ops = &spdif_dai_ops,
+ .suspend = spdif_suspend,
+ .resume = spdif_resume,
+};
+
+static __devinit int spdif_probe(struct platform_device *pdev)
+{
+ struct s3c_audio_pdata *spdif_pdata;
+ struct resource *mem_res, *dma_res;
+ struct samsung_spdif_info *spdif;
+ int ret;
+
+ spdif_pdata = pdev->dev.platform_data;
+
+ dev_dbg(&pdev->dev, "Entered %s\n", __func__);
+
+ dma_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!dma_res) {
+ dev_err(&pdev->dev, "Unable to get dma resource.\n");
+ return -ENXIO;
+ }
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem_res) {
+ dev_err(&pdev->dev, "Unable to get register resource.\n");
+ return -ENXIO;
+ }
+
+ if (spdif_pdata && spdif_pdata->cfg_gpio
+ && spdif_pdata->cfg_gpio(pdev)) {
+ dev_err(&pdev->dev, "Unable to configure GPIO pins\n");
+ return -EINVAL;
+ }
+
+ spdif = &spdif_info;
+ spdif->dev = &pdev->dev;
+
+ spin_lock_init(&spdif->lock);
+
+ spdif->pclk = clk_get(&pdev->dev, "spdif");
+ if (IS_ERR(spdif->pclk)) {
+ dev_err(&pdev->dev, "failed to get peri-clock\n");
+ ret = -ENOENT;
+ goto err0;
+ }
+ clk_enable(spdif->pclk);
+
+ spdif->sclk = clk_get(&pdev->dev, "sclk_spdif");
+ if (IS_ERR(spdif->sclk)) {
+ dev_err(&pdev->dev, "failed to get internal source clock\n");
+ ret = -ENOENT;
+ goto err1;
+ }
+ clk_enable(spdif->sclk);
+
+ /* Request S/PDIF Register's memory region */
+ if (!request_mem_region(mem_res->start,
+ resource_size(mem_res), "samsung-spdif")) {
+ dev_err(&pdev->dev, "Unable to request register region\n");
+ ret = -EBUSY;
+ goto err2;
+ }
+
+ spdif->regs = ioremap(mem_res->start, 0x100);
+ if (spdif->regs == NULL) {
+ dev_err(&pdev->dev, "Cannot ioremap registers\n");
+ ret = -ENXIO;
+ goto err3;
+ }
+
+ dev_set_drvdata(&pdev->dev, spdif);
+
+ ret = snd_soc_register_dai(&pdev->dev, &samsung_spdif_dai);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "fail to register dai\n");
+ goto err4;
+ }
+
+ spdif_stereo_out.dma_size = 2;
+ spdif_stereo_out.client = &spdif_dma_client_out;
+ spdif_stereo_out.dma_addr = mem_res->start + DATA_OUTBUF;
+ spdif_stereo_out.channel = dma_res->start;
+
+ spdif->dma_playback = &spdif_stereo_out;
+
+ return 0;
+
+err4:
+ iounmap(spdif->regs);
+err3:
+ release_mem_region(mem_res->start, resource_size(mem_res));
+err2:
+ clk_disable(spdif->sclk);
+ clk_put(spdif->sclk);
+err1:
+ clk_disable(spdif->pclk);
+ clk_put(spdif->pclk);
+err0:
+ return ret;
+}
+
+static __devexit int spdif_remove(struct platform_device *pdev)
+{
+ struct samsung_spdif_info *spdif = &spdif_info;
+ struct resource *mem_res;
+
+ snd_soc_unregister_dai(&pdev->dev);
+
+ iounmap(spdif->regs);
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (mem_res)
+ release_mem_region(mem_res->start, resource_size(mem_res));
+
+ clk_disable(spdif->sclk);
+ clk_put(spdif->sclk);
+ clk_disable(spdif->pclk);
+ clk_put(spdif->pclk);
+
+ return 0;
+}
+
+static struct platform_driver samsung_spdif_driver = {
+ .probe = spdif_probe,
+ .remove = spdif_remove,
+ .driver = {
+ .name = "samsung-spdif",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init spdif_init(void)
+{
+ return platform_driver_register(&samsung_spdif_driver);
+}
+module_init(spdif_init);
+
+static void __exit spdif_exit(void)
+{
+ platform_driver_unregister(&samsung_spdif_driver);
+}
+module_exit(spdif_exit);
+
+MODULE_AUTHOR("Seungwhan Youn, <sw.youn@samsung.com>");
+MODULE_DESCRIPTION("Samsung S/PDIF Controller Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-spdif");
diff --git a/sound/soc/s3c24xx/spdif.h b/sound/soc/s3c24xx/spdif.h
new file mode 100644
index 0000000..3ed5559
--- /dev/null
+++ b/sound/soc/s3c24xx/spdif.h
@@ -0,0 +1,19 @@
+/* sound/soc/s3c24xx/spdif.h
+ *
+ * ALSA SoC Audio Layer - Samsung S/PDIF Controller driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ * http://www.samsung.com/
+ *
+ * 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 __SND_SOC_SAMSUNG_SPDIF_H
+#define __SND_SOC_SAMSUNG_SPDIF_H __FILE__
+
+#define SND_SOC_SPDIF_INT_MCLK 0
+#define SND_SOC_SPDIF_EXT_MCLK 1
+
+#endif /* __SND_SOC_SAMSUNG_SPDIF_H */
diff --git a/sound/soc/s6000/s6000-i2s.c b/sound/soc/s6000/s6000-i2s.c
index 59e3fa7..8778faa 100644
--- a/sound/soc/s6000/s6000-i2s.c
+++ b/sound/soc/s6000/s6000-i2s.c
@@ -140,7 +140,7 @@
static void s6000_i2s_start(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct s6000_i2s_dev *dev = rtd->dai->cpu_dai->private_data;
+ struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(rtd->cpu_dai);
int channel;
channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
@@ -152,7 +152,7 @@
static void s6000_i2s_stop(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct s6000_i2s_dev *dev = rtd->dai->cpu_dai->private_data;
+ struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(rtd->cpu_dai);
int channel;
channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
@@ -194,7 +194,7 @@
static unsigned int s6000_i2s_check_xrun(struct snd_soc_dai *cpu_dai)
{
- struct s6000_i2s_dev *dev = cpu_dai->private_data;
+ struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
unsigned int errors;
unsigned int ret;
@@ -232,7 +232,7 @@
static int s6000_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
- struct s6000_i2s_dev *dev = cpu_dai->private_data;
+ struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
u32 w;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -273,7 +273,7 @@
static int s6000_i2s_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
{
- struct s6000_i2s_dev *dev = dai->private_data;
+ struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
if (!div || (div & 1) || div > (S6_I2S_DIV_MASK + 1) * 2)
return -EINVAL;
@@ -287,7 +287,7 @@
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct s6000_i2s_dev *dev = dai->private_data;
+ struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
int interf;
u32 w = 0;
@@ -326,15 +326,17 @@
return 0;
}
-static int s6000_i2s_dai_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int s6000_i2s_dai_probe(struct snd_soc_dai *dai)
{
- struct s6000_i2s_dev *dev = dai->private_data;
- struct s6000_snd_platform_data *pdata = pdev->dev.platform_data;
+ struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+ struct s6000_snd_platform_data *pdata = dai->dev->platform_data;
if (!pdata)
return -EINVAL;
+ dai->capture_dma_data = &dev->dma_params;
+ dai->playback_dma_data = &dev->dma_params;
+
dev->wide = pdata->wide;
dev->channel_in = pdata->channel_in;
dev->channel_out = pdata->channel_out;
@@ -352,10 +354,10 @@
dev->channel_in = 0;
dev->channel_out = 1;
- dai->capture.channels_min = 2 * dev->lines_in;
- dai->capture.channels_max = dai->capture.channels_min;
- dai->playback.channels_min = 2 * dev->lines_out;
- dai->playback.channels_max = dai->playback.channels_min;
+ dai->driver->capture.channels_min = 2 * dev->lines_in;
+ dai->driver->capture.channels_max = dai->driver->capture.channels_min;
+ dai->driver->playback.channels_min = 2 * dev->lines_out;
+ dai->driver->playback.channels_max = dai->driver->playback.channels_min;
for (i = 0; i < dev->lines_out; i++)
s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), S6_I2S_OUT);
@@ -372,10 +374,10 @@
if (dev->lines_in > 1 || dev->lines_out > 1)
return -EINVAL;
- dai->capture.channels_min = 2 * dev->lines_in;
- dai->capture.channels_max = 8 * dev->lines_in;
- dai->playback.channels_min = 2 * dev->lines_out;
- dai->playback.channels_max = 8 * dev->lines_out;
+ dai->driver->capture.channels_min = 2 * dev->lines_in;
+ dai->driver->capture.channels_max = 8 * dev->lines_in;
+ dai->driver->playback.channels_min = 2 * dev->lines_out;
+ dai->driver->playback.channels_max = 8 * dev->lines_out;
if (dev->lines_in)
cfg[dev->channel_in] = S6_I2S_IN;
@@ -413,9 +415,7 @@
.hw_params = s6000_i2s_hw_params,
};
-struct snd_soc_dai s6000_i2s_dai = {
- .name = "s6000-i2s",
- .id = 0,
+static struct snd_soc_dai_driver s6000_i2s_dai = {
.probe = s6000_i2s_dai_probe,
.playback = {
.channels_min = 2,
@@ -435,7 +435,6 @@
},
.ops = &s6000_i2s_dai_ops,
}
-EXPORT_SYMBOL_GPL(s6000_i2s_dai);
static int __devinit s6000_i2s_probe(struct platform_device *pdev)
{
@@ -513,11 +512,7 @@
ret = -ENOMEM;
goto err_release_dma2;
}
-
- s6000_i2s_dai.dev = &pdev->dev;
- s6000_i2s_dai.private_data = dev;
- s6000_i2s_dai.capture.dma_data = &dev->dma_params;
- s6000_i2s_dai.playback.dma_data = &dev->dma_params;
+ dev_set_drvdata(&pdev->dev, dev);
dev->sifbase = sifmem->start;
dev->scbbase = mmio;
@@ -548,7 +543,7 @@
S6_I2S_INT_UNDERRUN |
S6_I2S_INT_OVERRUN);
- ret = snd_soc_register_dai(&s6000_i2s_dai);
+ ret = snd_soc_register_dai(&pdev->dev, &s6000_i2s_dai);
if (ret)
goto err_release_dev;
@@ -573,17 +568,16 @@
static void __devexit s6000_i2s_remove(struct platform_device *pdev)
{
- struct s6000_i2s_dev *dev = s6000_i2s_dai.private_data;
+ struct s6000_i2s_dev *dev = dev_get_drvdata(&pdev->dev);
struct resource *region;
void __iomem *mmio = dev->scbbase;
- snd_soc_unregister_dai(&s6000_i2s_dai);
+ snd_soc_unregister_dai(&pdev->dev);
s6000_i2s_stop_channel(dev, 0);
s6000_i2s_stop_channel(dev, 1);
s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, 0);
- s6000_i2s_dai.private_data = 0;
kfree(dev);
region = platform_get_resource(pdev, IORESOURCE_DMA, 0);
diff --git a/sound/soc/s6000/s6000-i2s.h b/sound/soc/s6000/s6000-i2s.h
index 2375fdf..86aa192 100644
--- a/sound/soc/s6000/s6000-i2s.h
+++ b/sound/soc/s6000/s6000-i2s.h
@@ -12,8 +12,6 @@
#ifndef _S6000_I2S_H
#define _S6000_I2S_H
-extern struct snd_soc_dai s6000_i2s_dai;
-
struct s6000_snd_platform_data {
int lines_in;
int lines_out;
diff --git a/sound/soc/s6000/s6000-pcm.c b/sound/soc/s6000/s6000-pcm.c
index 9c7f7f0..271fd22 100644
--- a/sound/soc/s6000/s6000-pcm.c
+++ b/sound/soc/s6000/s6000-pcm.c
@@ -65,7 +65,7 @@
dma_addr_t dma_pos;
dma_addr_t src, dst;
- par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+ par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
period_size = snd_pcm_lib_period_bytes(substream);
dma_offset = prtd->period * period_size;
@@ -103,23 +103,25 @@
{
struct snd_pcm *pcm = data;
struct snd_soc_pcm_runtime *runtime = pcm->private_data;
- struct s6000_pcm_dma_params *params =
- snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
struct s6000_runtime_data *prtd;
unsigned int has_xrun;
int i, ret = IRQ_NONE;
- u32 channel[2] = {
- [SNDRV_PCM_STREAM_PLAYBACK] = params->dma_out,
- [SNDRV_PCM_STREAM_CAPTURE] = params->dma_in
- };
- has_xrun = params->check_xrun(runtime->dai->cpu_dai);
-
- for (i = 0; i < ARRAY_SIZE(channel); ++i) {
+ for (i = 0; i < 2; ++i) {
struct snd_pcm_substream *substream = pcm->streams[i].substream;
+ struct s6000_pcm_dma_params *params =
+ snd_soc_dai_get_dma_data(runtime->cpu_dai, substream);
+ u32 channel;
unsigned int pending;
- if (!channel[i])
+ if (substream == SNDRV_PCM_STREAM_PLAYBACK)
+ channel = params->dma_out;
+ else
+ channel = params->dma_in;
+
+ has_xrun = params->check_xrun(runtime->cpu_dai);
+
+ if (!channel)
continue;
if (unlikely(has_xrun & (1 << i)) &&
@@ -130,8 +132,8 @@
ret = IRQ_HANDLED;
}
- pending = s6dmac_int_sources(DMA_MASK_DMAC(channel[i]),
- DMA_INDEX_CHNL(channel[i]));
+ pending = s6dmac_int_sources(DMA_MASK_DMAC(channel),
+ DMA_INDEX_CHNL(channel));
if (pending & 1) {
ret = IRQ_HANDLED;
@@ -139,10 +141,10 @@
snd_pcm_running(substream))) {
snd_pcm_period_elapsed(substream);
dev_dbg(pcm->dev, "period elapsed %x %x\n",
- s6dmac_cur_src(DMA_MASK_DMAC(channel[i]),
- DMA_INDEX_CHNL(channel[i])),
- s6dmac_cur_dst(DMA_MASK_DMAC(channel[i]),
- DMA_INDEX_CHNL(channel[i])));
+ s6dmac_cur_src(DMA_MASK_DMAC(channel),
+ DMA_INDEX_CHNL(channel)),
+ s6dmac_cur_dst(DMA_MASK_DMAC(channel),
+ DMA_INDEX_CHNL(channel)));
prtd = substream->runtime->private_data;
spin_lock(&prtd->lock);
s6000_pcm_enqueue_dma(substream);
@@ -154,16 +156,16 @@
if (pending & (1 << 3))
printk(KERN_WARNING
"s6000-pcm: DMA %x Underflow\n",
- channel[i]);
+ channel);
if (pending & (1 << 4))
printk(KERN_WARNING
"s6000-pcm: DMA %x Overflow\n",
- channel[i]);
+ channel);
if (pending & 0x1e0)
printk(KERN_WARNING
"s6000-pcm: DMA %x Master Error "
"(mask %x)\n",
- channel[i], pending >> 5);
+ channel, pending >> 5);
}
}
@@ -180,7 +182,7 @@
int srcinc;
u32 dma;
- par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+ par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
spin_lock_irqsave(&prtd->lock, flags);
@@ -221,7 +223,7 @@
unsigned long flags;
u32 channel;
- par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+ par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
channel = par->dma_out;
@@ -246,7 +248,7 @@
struct s6000_pcm_dma_params *par;
int ret;
- par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+ par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
ret = par->trigger(substream, cmd, 0);
if (ret < 0)
@@ -291,7 +293,7 @@
unsigned int offset;
dma_addr_t count;
- par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+ par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
spin_lock_irqsave(&prtd->lock, flags);
@@ -321,7 +323,7 @@
struct s6000_runtime_data *prtd;
int ret;
- par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+ par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
snd_soc_set_runtime_hwparams(substream, &s6000_pcm_hardware);
ret = snd_pcm_hw_constraint_step(runtime, 0,
@@ -385,7 +387,7 @@
return ret;
}
- par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+ par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
if (par->same_rate) {
spin_lock(&par->lock);
@@ -407,7 +409,7 @@
{
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
struct s6000_pcm_dma_params *par =
- snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+ snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
spin_lock(&par->lock);
par->in_use &= ~(1 << substream->stream);
@@ -433,7 +435,7 @@
{
struct snd_soc_pcm_runtime *runtime = pcm->private_data;
struct s6000_pcm_dma_params *params =
- snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+ snd_soc_dai_get_dma_data(runtime->cpu_dai, pcm->streams[0].substream);
free_irq(params->irq, pcm);
snd_pcm_lib_preallocate_free_for_all(pcm);
@@ -448,7 +450,8 @@
struct s6000_pcm_dma_params *params;
int res;
- params = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+ params = snd_soc_dai_get_dma_data(runtime->cpu_dai,
+ pcm->streams[0].substream);
if (!card->dev->dma_mask)
card->dev->dma_mask = &s6000_pcm_dmamask;
@@ -490,25 +493,44 @@
return 0;
}
-struct snd_soc_platform s6000_soc_platform = {
- .name = "s6000-audio",
- .pcm_ops = &s6000_pcm_ops,
+static struct snd_soc_platform_driver s6000_soc_platform = {
+ .ops = &s6000_pcm_ops,
.pcm_new = s6000_pcm_new,
.pcm_free = s6000_pcm_free,
};
-EXPORT_SYMBOL_GPL(s6000_soc_platform);
-static int __init s6000_pcm_init(void)
+static int __devinit s6000_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&s6000_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &s6000_soc_platform);
}
-module_init(s6000_pcm_init);
-static void __exit s6000_pcm_exit(void)
+static int __devexit s6000_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&s6000_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
}
-module_exit(s6000_pcm_exit);
+
+static struct platform_driver s6000_pcm_driver = {
+ .driver = {
+ .name = "s6000-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = s6000_soc_platform_probe,
+ .remove = __devexit_p(s6000_soc_platform_remove),
+};
+
+static int __init snd_s6000_pcm_init(void)
+{
+ return platform_driver_register(&s6000_pcm_driver);
+}
+module_init(snd_s6000_pcm_init);
+
+static void __exit snd_s6000_pcm_exit(void)
+{
+ platform_driver_unregister(&s6000_pcm_driver);
+}
+module_exit(snd_s6000_pcm_exit);
MODULE_AUTHOR("Daniel Gloeckner");
MODULE_DESCRIPTION("Stretch s6000 family PCM DMA module");
diff --git a/sound/soc/s6000/s6000-pcm.h b/sound/soc/s6000/s6000-pcm.h
index 96f23f6..09d9b88 100644
--- a/sound/soc/s6000/s6000-pcm.h
+++ b/sound/soc/s6000/s6000-pcm.h
@@ -30,6 +30,4 @@
int rate;
};
-extern struct snd_soc_platform s6000_soc_platform;
-
#endif
diff --git a/sound/soc/s6000/s6105-ipcam.c b/sound/soc/s6000/s6105-ipcam.c
index c1b40ac..96c05e1 100644
--- a/sound/soc/s6000/s6105-ipcam.c
+++ b/sound/soc/s6000/s6105-ipcam.c
@@ -32,8 +32,8 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret = 0;
/* set codec DAI configuration */
@@ -134,8 +134,10 @@
};
/* Logic for a aic3x as connected on the s6105 ip camera ref design */
-static int s6105_aic3x_init(struct snd_soc_codec *codec)
+static int s6105_aic3x_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
/* Add s6105 specific widgets */
snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets,
ARRAY_SIZE(aic3x_dapm_widgets));
@@ -165,7 +167,7 @@
snd_soc_dapm_sync(codec);
- snd_ctl_add(codec->card, snd_ctl_new1(&audio_out_mux, codec));
+ snd_ctl_add(codec->snd_card, snd_ctl_new1(&audio_out_mux, codec));
return 0;
}
@@ -174,8 +176,10 @@
static struct snd_soc_dai_link s6105_dai = {
.name = "TLV320AIC31",
.stream_name = "AIC31",
- .cpu_dai = &s6000_i2s_dai,
- .codec_dai = &aic3x_dai,
+ .cpu_dai_name = "s6000-i2s",
+ .codec_dai_name = "tlv320aic3x-hifi",
+ .platform_name = "s6000-pcm-audio",
+ .codec_name = "tlv320aic3x-codec.0-001a",
.init = s6105_aic3x_init,
.ops = &s6105_ops,
};
@@ -183,22 +187,10 @@
/* s6105 audio machine driver */
static struct snd_soc_card snd_soc_card_s6105 = {
.name = "Stretch IP Camera",
- .platform = &s6000_soc_platform,
.dai_link = &s6105_dai,
.num_links = 1,
};
-/* s6105 audio private data */
-static struct aic3x_setup_data s6105_aic3x_setup = {
-};
-
-/* s6105 audio subsystem */
-static struct snd_soc_device s6105_snd_devdata = {
- .card = &snd_soc_card_s6105,
- .codec_dev = &soc_codec_dev_aic3x,
- .codec_data = &s6105_aic3x_setup,
-};
-
static struct s6000_snd_platform_data __initdata s6105_snd_data = {
.wide = 0,
.channel_in = 0,
@@ -227,8 +219,7 @@
if (!s6105_snd_device)
return -ENOMEM;
- platform_set_drvdata(s6105_snd_device, &s6105_snd_devdata);
- s6105_snd_devdata.dev = &s6105_snd_device->dev;
+ platform_set_drvdata(s6105_snd_device, &snd_soc_card_s6105);
platform_device_add_data(s6105_snd_device, &s6105_snd_data,
sizeof(s6105_snd_data));
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index 52d7e8e..7f0a496 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -47,7 +47,7 @@
AC97 unit of the SH7760.
config SND_FSI_AK4642
- bool "FSI-AK4642 sound support"
+ tristate "FSI-AK4642 sound support"
depends on SND_SOC_SH4_FSI && I2C_SH_MOBILE
select SND_SOC_AK4642
help
@@ -55,13 +55,20 @@
FSI - AK4642 unit
config SND_FSI_DA7210
- bool "FSI-DA7210 sound support"
+ tristate "FSI-DA7210 sound support"
depends on SND_SOC_SH4_FSI && I2C_SH_MOBILE
select SND_SOC_DA7210
help
This option enables generic sound support for the
FSI - DA7210 unit
+config SND_FSI_HDMI
+ tristate "FSI-HDMI sound support"
+ depends on SND_SOC_SH4_FSI && FB_SH_MOBILE_HDMI
+ help
+ This option enables generic sound support for the
+ FSI - HDMI unit
+
config SND_SIU_MIGOR
tristate "SIU sound support on Migo-R"
depends on SH_MIGOR
diff --git a/sound/soc/sh/Makefile b/sound/soc/sh/Makefile
index 8a5a192..94476d4 100644
--- a/sound/soc/sh/Makefile
+++ b/sound/soc/sh/Makefile
@@ -16,9 +16,11 @@
snd-soc-sh7760-ac97-objs := sh7760-ac97.o
snd-soc-fsi-ak4642-objs := fsi-ak4642.o
snd-soc-fsi-da7210-objs := fsi-da7210.o
+snd-soc-fsi-hdmi-objs := fsi-hdmi.o
snd-soc-migor-objs := migor.o
obj-$(CONFIG_SND_SH7760_AC97) += snd-soc-sh7760-ac97.o
obj-$(CONFIG_SND_FSI_AK4642) += snd-soc-fsi-ak4642.o
obj-$(CONFIG_SND_FSI_DA7210) += snd-soc-fsi-da7210.o
+obj-$(CONFIG_SND_FSI_HDMI) += snd-soc-fsi-hdmi.o
obj-$(CONFIG_SND_SIU_MIGOR) += snd-soc-migor.o
diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c
index 0d8bdf0..c326d29 100644
--- a/sound/soc/sh/dma-sh7760.c
+++ b/sound/soc/sh/dma-sh7760.c
@@ -137,7 +137,7 @@
static int camelot_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+ struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
int ret, dmairq;
@@ -150,7 +150,7 @@
ret = dmabrg_request_irq(dmairq, camelot_rxdma, cam);
if (unlikely(ret)) {
pr_debug("audio unit %d irqs already taken!\n",
- rtd->dai->cpu_dai->id);
+ rtd->cpu_dai->id);
return -EBUSY;
}
(void)dmabrg_request_irq(dmairq + 1,camelot_rxdma, cam);
@@ -159,7 +159,7 @@
ret = dmabrg_request_irq(dmairq, camelot_txdma, cam);
if (unlikely(ret)) {
pr_debug("audio unit %d irqs already taken!\n",
- rtd->dai->cpu_dai->id);
+ rtd->cpu_dai->id);
return -EBUSY;
}
(void)dmabrg_request_irq(dmairq + 1, camelot_txdma, cam);
@@ -170,7 +170,7 @@
static int camelot_pcm_close(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+ struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
int dmairq;
@@ -191,7 +191,7 @@
struct snd_pcm_hw_params *hw_params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+ struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
int ret;
@@ -219,7 +219,7 @@
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+ struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
pr_debug("PCM data: addr 0x%08ulx len %d\n",
(u32)runtime->dma_addr, runtime->dma_bytes);
@@ -266,7 +266,7 @@
static int camelot_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+ struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
switch (cmd) {
@@ -293,7 +293,7 @@
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+ struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
unsigned long pos;
@@ -342,25 +342,44 @@
return 0;
}
-struct snd_soc_platform sh7760_soc_platform = {
- .name = "sh7760-pcm",
+static struct snd_soc_platform sh7760_soc_platform = {
.pcm_ops = &camelot_pcm_ops,
.pcm_new = camelot_pcm_new,
.pcm_free = camelot_pcm_free,
};
-EXPORT_SYMBOL_GPL(sh7760_soc_platform);
-static int __init sh7760_soc_platform_init(void)
+static int __devinit sh7760_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&sh7760_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &sh7760_soc_platform);
}
-module_init(sh7760_soc_platform_init);
-static void __exit sh7760_soc_platform_exit(void)
+static int __devexit sh7760_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&sh7760_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
}
-module_exit(sh7760_soc_platform_exit);
+
+static struct platform_driver sh7760_pcm_driver = {
+ .driver = {
+ .name = "sh7760-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = sh7760_soc_platform_probe,
+ .remove = __devexit_p(sh7760_soc_platform_remove),
+};
+
+static int __init snd_sh7760_pcm_init(void)
+{
+ return platform_driver_register(&sh7760_pcm_driver);
+}
+module_init(snd_sh7760_pcm_init);
+
+static void __exit snd_sh7760_pcm_exit(void)
+{
+ platform_driver_unregister(&sh7760_pcm_driver);
+}
+module_exit(snd_sh7760_pcm_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SH7760 Audio DMA (DMABRG) driver");
diff --git a/sound/soc/sh/fsi-ak4642.c b/sound/soc/sh/fsi-ak4642.c
index dad575a..d96602d 100644
--- a/sound/soc/sh/fsi-ak4642.c
+++ b/sound/soc/sh/fsi-ak4642.c
@@ -11,17 +11,17 @@
#include <linux/platform_device.h>
#include <sound/sh_fsi.h>
-#include <../sound/soc/codecs/ak4642.h>
-static int fsi_ak4642_dai_init(struct snd_soc_codec *codec)
+static int fsi_ak4642_dai_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_dai *dai = rtd->codec_dai;
int ret;
- ret = snd_soc_dai_set_fmt(&ak4642_dai, SND_SOC_DAIFMT_CBM_CFM);
+ ret = snd_soc_dai_set_fmt(dai, SND_SOC_DAIFMT_CBM_CFM);
if (ret < 0)
return ret;
- ret = snd_soc_dai_set_sysclk(&ak4642_dai, 0, 11289600, 0);
+ ret = snd_soc_dai_set_sysclk(dai, 0, 11289600, 0);
return ret;
}
@@ -29,24 +29,25 @@
static struct snd_soc_dai_link fsi_dai_link = {
.name = "AK4642",
.stream_name = "AK4642",
- .cpu_dai = &fsi_soc_dai[FSI_PORT_A],
- .codec_dai = &ak4642_dai,
+ .cpu_dai_name = "fsia-dai", /* fsi A */
+ .codec_dai_name = "ak4642-hifi",
+#ifdef CONFIG_MACH_AP4EVB
+ .platform_name = "sh_fsi2",
+ .codec_name = "ak4642-codec.0-0013",
+#else
+ .platform_name = "sh_fsi.0",
+ .codec_name = "ak4642-codec.0-0012",
+#endif
.init = fsi_ak4642_dai_init,
.ops = NULL,
};
static struct snd_soc_card fsi_soc_card = {
- .name = "FSI",
- .platform = &fsi_soc_platform,
+ .name = "FSI (AK4642)",
.dai_link = &fsi_dai_link,
.num_links = 1,
};
-static struct snd_soc_device fsi_snd_devdata = {
- .card = &fsi_soc_card,
- .codec_dev = &soc_codec_dev_ak4642,
-};
-
static struct platform_device *fsi_snd_device;
static int __init fsi_ak4642_init(void)
@@ -57,9 +58,7 @@
if (!fsi_snd_device)
goto out;
- platform_set_drvdata(fsi_snd_device,
- &fsi_snd_devdata);
- fsi_snd_devdata.dev = &fsi_snd_device->dev;
+ platform_set_drvdata(fsi_snd_device, &fsi_soc_card);
ret = platform_device_add(fsi_snd_device);
if (ret)
diff --git a/sound/soc/sh/fsi-da7210.c b/sound/soc/sh/fsi-da7210.c
index 121bbb0..a6adb6e 100644
--- a/sound/soc/sh/fsi-da7210.c
+++ b/sound/soc/sh/fsi-da7210.c
@@ -12,11 +12,12 @@
#include <linux/platform_device.h>
#include <sound/sh_fsi.h>
-#include "../codecs/da7210.h"
-static int fsi_da7210_init(struct snd_soc_codec *codec)
+static int fsi_da7210_init(struct snd_soc_pcm_runtime *rtd)
{
- return snd_soc_dai_set_fmt(&da7210_dai,
+ struct snd_soc_dai *dai = rtd->codec_dai;
+
+ return snd_soc_dai_set_fmt(dai,
SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM);
}
@@ -24,23 +25,19 @@
static struct snd_soc_dai_link fsi_da7210_dai = {
.name = "DA7210",
.stream_name = "DA7210",
- .cpu_dai = &fsi_soc_dai[FSI_PORT_B],
- .codec_dai = &da7210_dai,
+ .cpu_dai_name = "fsib-dai", /* FSI B */
+ .codec_dai_name = "da7210-hifi",
+ .platform_name = "sh_fsi.0",
+ .codec_name = "da7210-codec.0-001a",
.init = fsi_da7210_init,
};
static struct snd_soc_card fsi_soc_card = {
- .name = "FSI",
- .platform = &fsi_soc_platform,
+ .name = "FSI (DA7210)",
.dai_link = &fsi_da7210_dai,
.num_links = 1,
};
-static struct snd_soc_device fsi_da7210_snd_devdata = {
- .card = &fsi_soc_card,
- .codec_dev = &soc_codec_dev_da7210,
-};
-
static struct platform_device *fsi_da7210_snd_device;
static int __init fsi_da7210_sound_init(void)
@@ -51,8 +48,7 @@
if (!fsi_da7210_snd_device)
return -ENOMEM;
- platform_set_drvdata(fsi_da7210_snd_device, &fsi_da7210_snd_devdata);
- fsi_da7210_snd_devdata.dev = &fsi_da7210_snd_device->dev;
+ platform_set_drvdata(fsi_da7210_snd_device, &fsi_soc_card);
ret = platform_device_add(fsi_da7210_snd_device);
if (ret)
platform_device_put(fsi_da7210_snd_device);
diff --git a/sound/soc/sh/fsi-hdmi.c b/sound/soc/sh/fsi-hdmi.c
new file mode 100644
index 0000000..a52dd8e
--- /dev/null
+++ b/sound/soc/sh/fsi-hdmi.c
@@ -0,0 +1,60 @@
+/*
+ * FSI - HDMI sound support
+ *
+ * Copyright (C) 2010 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/platform_device.h>
+#include <sound/sh_fsi.h>
+
+static struct snd_soc_dai_link fsi_dai_link = {
+ .name = "HDMI",
+ .stream_name = "HDMI",
+ .cpu_dai_name = "fsib-dai", /* fsi B */
+ .codec_dai_name = "sh_mobile_hdmi-hifi",
+ .platform_name = "sh_fsi2",
+ .codec_name = "sh-mobile-hdmi",
+};
+
+static struct snd_soc_card fsi_soc_card = {
+ .name = "FSI (SH MOBILE HDMI)",
+ .dai_link = &fsi_dai_link,
+ .num_links = 1,
+};
+
+static struct platform_device *fsi_snd_device;
+
+static int __init fsi_hdmi_init(void)
+{
+ int ret = -ENOMEM;
+
+ fsi_snd_device = platform_device_alloc("soc-audio", FSI_PORT_B);
+ if (!fsi_snd_device)
+ goto out;
+
+ platform_set_drvdata(fsi_snd_device, &fsi_soc_card);
+ ret = platform_device_add(fsi_snd_device);
+
+ if (ret)
+ platform_device_put(fsi_snd_device);
+
+out:
+ return ret;
+}
+
+static void __exit fsi_hdmi_exit(void)
+{
+ platform_device_unregister(fsi_snd_device);
+}
+
+module_init(fsi_hdmi_init);
+module_exit(fsi_hdmi_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic SH4 FSI-HDMI sound card");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 58c6bec..507e709 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -80,11 +80,12 @@
#define B_CLK 0x00000010
#define A_CLK 0x00000001
-/* INT_ST */
-#define INT_B_IN (1 << 12)
-#define INT_B_OUT (1 << 8)
-#define INT_A_IN (1 << 4)
-#define INT_A_OUT (1 << 0)
+/* IO SHIFT / MACRO */
+#define BI_SHIFT 12
+#define BO_SHIFT 8
+#define AI_SHIFT 4
+#define AO_SHIFT 0
+#define AB_IO(param, shift) (param << shift)
/* SOFT_RST */
#define PBSR (1 << 12) /* Port B Software Reset */
@@ -93,33 +94,43 @@
#define FSISR (1 << 0) /* Software Reset */
/* FIFO_SZ */
-#define OUT_SZ_MASK 0x7
-#define BO_SZ_SHIFT 8
-#define AO_SZ_SHIFT 0
+#define FIFO_SZ_MASK 0x7
#define FSI_RATES SNDRV_PCM_RATE_8000_96000
#define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
-/************************************************************************
+/*
+ * FSI driver use below type name for variable
+ *
+ * xxx_len : data length
+ * xxx_width : data width
+ * xxx_offset : data offset
+ * xxx_num : number of data
+ */
+/*
+ * struct
+ */
- struct
+struct fsi_stream {
+ struct snd_pcm_substream *substream;
+ int fifo_max_num;
+ int chan_num;
-************************************************************************/
+ int buff_offset;
+ int buff_len;
+ int period_len;
+ int period_num;
+};
+
struct fsi_priv {
void __iomem *base;
- struct snd_pcm_substream *substream;
struct fsi_master *master;
- int fifo_max;
- int chan;
-
- int byte_offset;
- int period_len;
- int buffer_len;
- int periods;
+ struct fsi_stream playback;
+ struct fsi_stream capture;
u32 mst_ctrl;
};
@@ -142,13 +153,10 @@
spinlock_t lock;
};
-/************************************************************************
+/*
+ * basic read write function
+ */
-
- basic read write function
-
-
-************************************************************************/
static void __fsi_reg_write(u32 reg, u32 data)
{
/* valid data area is 24bit */
@@ -251,13 +259,10 @@
spin_unlock_irqrestore(&master->lock, flags);
}
-/************************************************************************
+/*
+ * basic function
+ */
-
- basic function
-
-
-************************************************************************/
static struct fsi_master *fsi_get_master(struct fsi_priv *fsi)
{
return fsi->master;
@@ -271,16 +276,19 @@
static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai_link *machine = rtd->dai;
- return machine->cpu_dai;
+ return rtd->cpu_dai;
}
static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream)
{
struct snd_soc_dai *dai = fsi_get_dai(substream);
+ struct fsi_master *master = snd_soc_dai_get_drvdata(dai);
- return dai->private_data;
+ if (dai->id == 0)
+ return &master->fsia;
+ else
+ return &master->fsib;
}
static u32 fsi_get_info_flags(struct fsi_priv *fsi)
@@ -292,6 +300,22 @@
master->info->portb_flags;
}
+static inline int fsi_stream_is_play(int stream)
+{
+ return stream == SNDRV_PCM_STREAM_PLAYBACK;
+}
+
+static inline int fsi_is_play(struct snd_pcm_substream *substream)
+{
+ return fsi_stream_is_play(substream->stream);
+}
+
+static inline struct fsi_stream *fsi_get_stream(struct fsi_priv *fsi,
+ int is_play)
+{
+ return is_play ? &fsi->playback : &fsi->capture;
+}
+
static int fsi_is_master_mode(struct fsi_priv *fsi, int is_play)
{
u32 mode;
@@ -307,63 +331,144 @@
return (mode & flags) != mode;
}
-static u32 fsi_port_ab_io_bit(struct fsi_priv *fsi, int is_play)
+static u32 fsi_get_port_shift(struct fsi_priv *fsi, int is_play)
{
int is_porta = fsi_is_port_a(fsi);
- u32 data;
+ u32 shift;
if (is_porta)
- data = is_play ? (1 << 0) : (1 << 4);
+ shift = is_play ? AO_SHIFT : AI_SHIFT;
else
- data = is_play ? (1 << 8) : (1 << 12);
+ shift = is_play ? BO_SHIFT : BI_SHIFT;
- return data;
+ return shift;
}
static void fsi_stream_push(struct fsi_priv *fsi,
+ int is_play,
struct snd_pcm_substream *substream,
u32 buffer_len,
u32 period_len)
{
- fsi->substream = substream;
- fsi->buffer_len = buffer_len;
- fsi->period_len = period_len;
- fsi->byte_offset = 0;
- fsi->periods = 0;
+ struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+
+ io->substream = substream;
+ io->buff_len = buffer_len;
+ io->buff_offset = 0;
+ io->period_len = period_len;
+ io->period_num = 0;
}
-static void fsi_stream_pop(struct fsi_priv *fsi)
+static void fsi_stream_pop(struct fsi_priv *fsi, int is_play)
{
- fsi->substream = NULL;
- fsi->buffer_len = 0;
- fsi->period_len = 0;
- fsi->byte_offset = 0;
- fsi->periods = 0;
+ struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+
+ io->substream = NULL;
+ io->buff_len = 0;
+ io->buff_offset = 0;
+ io->period_len = 0;
+ io->period_num = 0;
}
-static int fsi_get_fifo_residue(struct fsi_priv *fsi, int is_play)
+static int fsi_get_fifo_data_num(struct fsi_priv *fsi, int is_play)
{
u32 status;
u32 reg = is_play ? DOFF_ST : DIFF_ST;
- int residue;
+ struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+ int data_num;
status = fsi_reg_read(fsi, reg);
- residue = 0x1ff & (status >> 8);
- residue *= fsi->chan;
+ data_num = 0x1ff & (status >> 8);
+ data_num *= io->chan_num;
- return residue;
+ return data_num;
}
-/************************************************************************
+static int fsi_len2num(int len, int width)
+{
+ return len / width;
+}
+
+#define fsi_num2offset(a, b) fsi_num2len(a, b)
+static int fsi_num2len(int num, int width)
+{
+ return num * width;
+}
+
+static int fsi_get_frame_width(struct fsi_priv *fsi, int is_play)
+{
+ struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+ struct snd_pcm_substream *substream = io->substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ return frames_to_bytes(runtime, 1) / io->chan_num;
+}
+
+/*
+ * dma function
+ */
+
+static u8 *fsi_dma_get_area(struct fsi_priv *fsi, int stream)
+{
+ int is_play = fsi_stream_is_play(stream);
+ struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+
+ return io->substream->runtime->dma_area + io->buff_offset;
+}
+
+static void fsi_dma_soft_push16(struct fsi_priv *fsi, int num)
+{
+ u16 *start;
+ int i;
+
+ start = (u16 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_PLAYBACK);
+
+ for (i = 0; i < num; i++)
+ fsi_reg_write(fsi, DODT, ((u32)*(start + i) << 8));
+}
+
+static void fsi_dma_soft_pop16(struct fsi_priv *fsi, int num)
+{
+ u16 *start;
+ int i;
+
+ start = (u16 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_CAPTURE);
- irq function
+ for (i = 0; i < num; i++)
+ *(start + i) = (u16)(fsi_reg_read(fsi, DIDT) >> 8);
+}
+
+static void fsi_dma_soft_push32(struct fsi_priv *fsi, int num)
+{
+ u32 *start;
+ int i;
+
+ start = (u32 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_PLAYBACK);
-************************************************************************/
+ for (i = 0; i < num; i++)
+ fsi_reg_write(fsi, DODT, *(start + i));
+}
+
+static void fsi_dma_soft_pop32(struct fsi_priv *fsi, int num)
+{
+ u32 *start;
+ int i;
+
+ start = (u32 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_CAPTURE);
+
+ for (i = 0; i < num; i++)
+ *(start + i) = fsi_reg_read(fsi, DIDT);
+}
+
+/*
+ * irq function
+ */
+
static void fsi_irq_enable(struct fsi_priv *fsi, int is_play)
{
- u32 data = fsi_port_ab_io_bit(fsi, is_play);
+ u32 data = AB_IO(1, fsi_get_port_shift(fsi, is_play));
struct fsi_master *master = fsi_get_master(fsi);
fsi_master_mask_set(master, master->core->imsk, data, data);
@@ -372,7 +477,7 @@
static void fsi_irq_disable(struct fsi_priv *fsi, int is_play)
{
- u32 data = fsi_port_ab_io_bit(fsi, is_play);
+ u32 data = AB_IO(1, fsi_get_port_shift(fsi, is_play));
struct fsi_master *master = fsi_get_master(fsi);
fsi_master_mask_set(master, master->core->imsk, data, 0);
@@ -394,20 +499,18 @@
u32 data = 0;
struct fsi_master *master = fsi_get_master(fsi);
- data |= fsi_port_ab_io_bit(fsi, 0);
- data |= fsi_port_ab_io_bit(fsi, 1);
+ data |= AB_IO(1, fsi_get_port_shift(fsi, 0));
+ data |= AB_IO(1, fsi_get_port_shift(fsi, 1));
/* clear interrupt factor */
fsi_master_mask_set(master, master->core->int_st, data, 0);
}
-/************************************************************************
-
-
- SPDIF master clock function
-
-These functions are used later FSI2
-************************************************************************/
+/*
+ * SPDIF master clock function
+ *
+ * These functions are used later FSI2
+ */
static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
{
struct fsi_master *master = fsi_get_master(fsi);
@@ -424,13 +527,10 @@
fsi_master_mask_set(master, fsi->mst_ctrl, val, 0);
}
-/************************************************************************
+/*
+ * ctrl function
+ */
-
- ctrl function
-
-
-************************************************************************/
static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable)
{
u32 val = fsi_is_port_a(fsi) ? (1 << 0) : (1 << 4);
@@ -447,14 +547,15 @@
struct snd_soc_dai *dai)
{
struct fsi_master *master = fsi_get_master(fsi);
+ struct fsi_stream *io = fsi_get_stream(fsi, is_play);
u32 ctrl, shift, i;
/* get on-chip RAM capacity */
shift = fsi_master_read(master, FIFO_SZ);
- shift >>= fsi_is_port_a(fsi) ? AO_SZ_SHIFT : BO_SZ_SHIFT;
- shift &= OUT_SZ_MASK;
- fsi->fifo_max = 256 << shift;
- dev_dbg(dai->dev, "fifo = %d words\n", fsi->fifo_max);
+ shift >>= fsi_get_port_shift(fsi, is_play);
+ shift &= FIFO_SZ_MASK;
+ io->fifo_max_num = 256 << shift;
+ dev_dbg(dai->dev, "fifo = %d words\n", io->fifo_max_num);
/*
* The maximum number of sample data varies depending
@@ -475,9 +576,10 @@
* 7 channels: 32 ( 32 x 7 = 224)
* 8 channels: 32 ( 32 x 8 = 256)
*/
- for (i = 1; i < fsi->chan; i <<= 1)
- fsi->fifo_max >>= 1;
- dev_dbg(dai->dev, "%d channel %d store\n", fsi->chan, fsi->fifo_max);
+ for (i = 1; i < io->chan_num; i <<= 1)
+ io->fifo_max_num >>= 1;
+ dev_dbg(dai->dev, "%d channel %d store\n",
+ io->chan_num, io->fifo_max_num);
ctrl = is_play ? DOFF_CTL : DIFF_CTL;
@@ -500,84 +602,114 @@
mdelay(10);
}
-/* playback interrupt */
-static int fsi_data_push(struct fsi_priv *fsi, int startup)
+static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int startup, int stream)
{
struct snd_pcm_runtime *runtime;
struct snd_pcm_substream *substream = NULL;
- u32 status;
- int send;
- int fifo_free;
- int width;
- u8 *start;
- int i, over_period;
+ int is_play = fsi_stream_is_play(stream);
+ struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+ u32 status_reg = is_play ? DOFF_ST : DIFF_ST;
+ int data_residue_num;
+ int data_num;
+ int data_num_max;
+ int ch_width;
+ int over_period;
+ void (*fn)(struct fsi_priv *fsi, int size);
if (!fsi ||
- !fsi->substream ||
- !fsi->substream->runtime)
+ !io->substream ||
+ !io->substream->runtime)
return -EINVAL;
over_period = 0;
- substream = fsi->substream;
+ substream = io->substream;
runtime = substream->runtime;
/* FSI FIFO has limit.
* So, this driver can not send periods data at a time
*/
- if (fsi->byte_offset >=
- fsi->period_len * (fsi->periods + 1)) {
+ if (io->buff_offset >=
+ fsi_num2offset(io->period_num + 1, io->period_len)) {
over_period = 1;
- fsi->periods = (fsi->periods + 1) % runtime->periods;
+ io->period_num = (io->period_num + 1) % runtime->periods;
- if (0 == fsi->periods)
- fsi->byte_offset = 0;
+ if (0 == io->period_num)
+ io->buff_offset = 0;
}
/* get 1 channel data width */
- width = frames_to_bytes(runtime, 1) / fsi->chan;
+ ch_width = fsi_get_frame_width(fsi, is_play);
- /* get send size for alsa */
- send = (fsi->buffer_len - fsi->byte_offset) / width;
+ /* get residue data number of alsa */
+ data_residue_num = fsi_len2num(io->buff_len - io->buff_offset,
+ ch_width);
- /* get FIFO free size */
- fifo_free = (fsi->fifo_max * fsi->chan) - fsi_get_fifo_residue(fsi, 1);
+ if (is_play) {
+ /*
+ * for play-back
+ *
+ * data_num_max : number of FSI fifo free space
+ * data_num : number of ALSA residue data
+ */
+ data_num_max = io->fifo_max_num * io->chan_num;
+ data_num_max -= fsi_get_fifo_data_num(fsi, is_play);
- /* size check */
- if (fifo_free < send)
- send = fifo_free;
+ data_num = data_residue_num;
- start = runtime->dma_area;
- start += fsi->byte_offset;
+ switch (ch_width) {
+ case 2:
+ fn = fsi_dma_soft_push16;
+ break;
+ case 4:
+ fn = fsi_dma_soft_push32;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ /*
+ * for capture
+ *
+ * data_num_max : number of ALSA free space
+ * data_num : number of data in FSI fifo
+ */
+ data_num_max = data_residue_num;
+ data_num = fsi_get_fifo_data_num(fsi, is_play);
- switch (width) {
- case 2:
- for (i = 0; i < send; i++)
- fsi_reg_write(fsi, DODT,
- ((u32)*((u16 *)start + i) << 8));
- break;
- case 4:
- for (i = 0; i < send; i++)
- fsi_reg_write(fsi, DODT, *((u32 *)start + i));
- break;
- default:
- return -EINVAL;
+ switch (ch_width) {
+ case 2:
+ fn = fsi_dma_soft_pop16;
+ break;
+ case 4:
+ fn = fsi_dma_soft_pop32;
+ break;
+ default:
+ return -EINVAL;
+ }
}
- fsi->byte_offset += send * width;
+ data_num = min(data_num, data_num_max);
- status = fsi_reg_read(fsi, DOFF_ST);
+ fn(fsi, data_num);
+
+ /* update buff_offset */
+ io->buff_offset += fsi_num2offset(data_num, ch_width);
+
+ /* check fifo status */
if (!startup) {
struct snd_soc_dai *dai = fsi_get_dai(substream);
+ u32 status = fsi_reg_read(fsi, status_reg);
if (status & ERR_OVER)
dev_err(dai->dev, "over run\n");
if (status & ERR_UNDER)
dev_err(dai->dev, "under run\n");
}
- fsi_reg_write(fsi, DOFF_ST, 0);
+ fsi_reg_write(fsi, status_reg, 0);
- fsi_irq_enable(fsi, 1);
+ /* re-enable irq */
+ fsi_irq_enable(fsi, is_play);
if (over_period)
snd_pcm_period_elapsed(substream);
@@ -587,85 +719,12 @@
static int fsi_data_pop(struct fsi_priv *fsi, int startup)
{
- struct snd_pcm_runtime *runtime;
- struct snd_pcm_substream *substream = NULL;
- u32 status;
- int free;
- int fifo_fill;
- int width;
- u8 *start;
- int i, over_period;
+ return fsi_fifo_data_ctrl(fsi, startup, SNDRV_PCM_STREAM_CAPTURE);
+}
- if (!fsi ||
- !fsi->substream ||
- !fsi->substream->runtime)
- return -EINVAL;
-
- over_period = 0;
- substream = fsi->substream;
- runtime = substream->runtime;
-
- /* FSI FIFO has limit.
- * So, this driver can not send periods data at a time
- */
- if (fsi->byte_offset >=
- fsi->period_len * (fsi->periods + 1)) {
-
- over_period = 1;
- fsi->periods = (fsi->periods + 1) % runtime->periods;
-
- if (0 == fsi->periods)
- fsi->byte_offset = 0;
- }
-
- /* get 1 channel data width */
- width = frames_to_bytes(runtime, 1) / fsi->chan;
-
- /* get free space for alsa */
- free = (fsi->buffer_len - fsi->byte_offset) / width;
-
- /* get recv size */
- fifo_fill = fsi_get_fifo_residue(fsi, 0);
-
- if (free < fifo_fill)
- fifo_fill = free;
-
- start = runtime->dma_area;
- start += fsi->byte_offset;
-
- switch (width) {
- case 2:
- for (i = 0; i < fifo_fill; i++)
- *((u16 *)start + i) =
- (u16)(fsi_reg_read(fsi, DIDT) >> 8);
- break;
- case 4:
- for (i = 0; i < fifo_fill; i++)
- *((u32 *)start + i) = fsi_reg_read(fsi, DIDT);
- break;
- default:
- return -EINVAL;
- }
-
- fsi->byte_offset += fifo_fill * width;
-
- status = fsi_reg_read(fsi, DIFF_ST);
- if (!startup) {
- struct snd_soc_dai *dai = fsi_get_dai(substream);
-
- if (status & ERR_OVER)
- dev_err(dai->dev, "over run\n");
- if (status & ERR_UNDER)
- dev_err(dai->dev, "under run\n");
- }
- fsi_reg_write(fsi, DIFF_ST, 0);
-
- fsi_irq_enable(fsi, 0);
-
- if (over_period)
- snd_pcm_period_elapsed(substream);
-
- return 0;
+static int fsi_data_push(struct fsi_priv *fsi, int startup)
+{
+ return fsi_fifo_data_ctrl(fsi, startup, SNDRV_PCM_STREAM_PLAYBACK);
}
static irqreturn_t fsi_interrupt(int irq, void *data)
@@ -677,13 +736,13 @@
fsi_master_mask_set(master, SOFT_RST, IR, 0);
fsi_master_mask_set(master, SOFT_RST, IR, IR);
- if (int_st & INT_A_OUT)
+ if (int_st & AB_IO(1, AO_SHIFT))
fsi_data_push(&master->fsia, 0);
- if (int_st & INT_B_OUT)
+ if (int_st & AB_IO(1, BO_SHIFT))
fsi_data_push(&master->fsib, 0);
- if (int_st & INT_A_IN)
+ if (int_st & AB_IO(1, AI_SHIFT))
fsi_data_pop(&master->fsia, 0);
- if (int_st & INT_B_IN)
+ if (int_st & AB_IO(1, BI_SHIFT))
fsi_data_pop(&master->fsib, 0);
fsi_irq_clear_all_status(master);
@@ -691,25 +750,24 @@
return IRQ_HANDLED;
}
-/************************************************************************
+/*
+ * dai ops
+ */
-
- dai ops
-
-
-************************************************************************/
static int fsi_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct fsi_priv *fsi = fsi_get_priv(substream);
- u32 flags = fsi_get_info_flags(fsi);
struct fsi_master *master = fsi_get_master(fsi);
+ struct fsi_stream *io;
+ u32 flags = fsi_get_info_flags(fsi);
u32 fmt;
u32 reg;
u32 data;
- int is_play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+ int is_play = fsi_is_play(substream);
int is_master;
- int ret = 0;
+
+ io = fsi_get_stream(fsi, is_play);
pm_runtime_get_sync(dai->dev);
@@ -741,29 +799,29 @@
switch (fmt) {
case SH_FSI_FMT_MONO:
data = CR_MONO;
- fsi->chan = 1;
+ io->chan_num = 1;
break;
case SH_FSI_FMT_MONO_DELAY:
data = CR_MONO_D;
- fsi->chan = 1;
+ io->chan_num = 1;
break;
case SH_FSI_FMT_PCM:
data = CR_PCM;
- fsi->chan = 2;
+ io->chan_num = 2;
break;
case SH_FSI_FMT_I2S:
data = CR_I2S;
- fsi->chan = 2;
+ io->chan_num = 2;
break;
case SH_FSI_FMT_TDM:
- fsi->chan = is_play ?
+ io->chan_num = is_play ?
SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
- data = CR_TDM | (fsi->chan - 1);
+ data = CR_TDM | (io->chan_num - 1);
break;
case SH_FSI_FMT_TDM_DELAY:
- fsi->chan = is_play ?
+ io->chan_num = is_play ?
SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
- data = CR_TDM_D | (fsi->chan - 1);
+ data = CR_TDM_D | (io->chan_num - 1);
break;
case SH_FSI_FMT_SPDIF:
if (master->core->ver < 2) {
@@ -771,7 +829,7 @@
return -EINVAL;
}
data = CR_SPDIF;
- fsi->chan = 2;
+ io->chan_num = 2;
fsi_spdif_clk_ctrl(fsi, 1);
fsi_reg_mask_set(fsi, OUT_SEL, 0x0010, 0x0010);
break;
@@ -788,14 +846,14 @@
/* fifo init */
fsi_fifo_init(fsi, is_play, dai);
- return ret;
+ return 0;
}
static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct fsi_priv *fsi = fsi_get_priv(substream);
- int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ int is_play = fsi_is_play(substream);
fsi_irq_disable(fsi, is_play);
fsi_clk_ctrl(fsi, 0);
@@ -808,19 +866,19 @@
{
struct fsi_priv *fsi = fsi_get_priv(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
- int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ int is_play = fsi_is_play(substream);
int ret = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- fsi_stream_push(fsi, substream,
+ fsi_stream_push(fsi, is_play, substream,
frames_to_bytes(runtime, runtime->buffer_size),
frames_to_bytes(runtime, runtime->period_size));
ret = is_play ? fsi_data_push(fsi, 1) : fsi_data_pop(fsi, 1);
break;
case SNDRV_PCM_TRIGGER_STOP:
fsi_irq_disable(fsi, is_play);
- fsi_stream_pop(fsi);
+ fsi_stream_pop(fsi, is_play);
break;
}
@@ -835,7 +893,7 @@
struct fsi_master *master = fsi_get_master(fsi);
int (*set_rate)(int is_porta, int rate) = master->info->set_rate;
int fsi_ver = master->core->ver;
- int is_play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+ int is_play = fsi_is_play(substream);
int ret;
/* if slave mode, set_rate is not needed */
@@ -916,13 +974,10 @@
.hw_params = fsi_dai_hw_params,
};
-/************************************************************************
+/*
+ * pcm ops
+ */
-
- pcm ops
-
-
-************************************************************************/
static struct snd_pcm_hardware fsi_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP |
@@ -971,9 +1026,10 @@
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct fsi_priv *fsi = fsi_get_priv(substream);
+ struct fsi_stream *io = fsi_get_stream(fsi, fsi_is_play(substream));
long location;
- location = (fsi->byte_offset - 1);
+ location = (io->buff_offset - 1);
if (location < 0)
location = 0;
@@ -988,13 +1044,10 @@
.pointer = fsi_pointer,
};
-/************************************************************************
+/*
+ * snd_soc_platform
+ */
-
- snd_soc_platform
-
-
-************************************************************************/
#define PREALLOC_BUFFER (32 * 1024)
#define PREALLOC_BUFFER_MAX (32 * 1024)
@@ -1018,17 +1071,13 @@
PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
}
-/************************************************************************
+/*
+ * alsa struct
+ */
-
- alsa struct
-
-
-************************************************************************/
-struct snd_soc_dai fsi_soc_dai[] = {
+static struct snd_soc_dai_driver fsi_soc_dai[] = {
{
- .name = "FSIA",
- .id = 0,
+ .name = "fsia-dai",
.playback = {
.rates = FSI_RATES,
.formats = FSI_FMTS,
@@ -1044,8 +1093,7 @@
.ops = &fsi_dai_ops,
},
{
- .name = "FSIB",
- .id = 1,
+ .name = "fsib-dai",
.playback = {
.rates = FSI_RATES,
.formats = FSI_FMTS,
@@ -1061,23 +1109,17 @@
.ops = &fsi_dai_ops,
},
};
-EXPORT_SYMBOL_GPL(fsi_soc_dai);
-struct snd_soc_platform fsi_soc_platform = {
- .name = "fsi-pcm",
- .pcm_ops = &fsi_pcm_ops,
+static struct snd_soc_platform_driver fsi_soc_platform = {
+ .ops = &fsi_pcm_ops,
.pcm_new = fsi_pcm_new,
.pcm_free = fsi_pcm_free,
};
-EXPORT_SYMBOL_GPL(fsi_soc_platform);
-/************************************************************************
+/*
+ * platform function
+ */
-
- platform function
-
-
-************************************************************************/
static int fsi_probe(struct platform_device *pdev)
{
struct fsi_master *master;
@@ -1132,11 +1174,7 @@
pm_runtime_enable(&pdev->dev);
pm_runtime_resume(&pdev->dev);
-
- fsi_soc_dai[0].dev = &pdev->dev;
- fsi_soc_dai[0].private_data = &master->fsia;
- fsi_soc_dai[1].dev = &pdev->dev;
- fsi_soc_dai[1].private_data = &master->fsib;
+ dev_set_drvdata(&pdev->dev, master);
fsi_soft_all_reset(master);
@@ -1147,13 +1185,13 @@
goto exit_iounmap;
}
- ret = snd_soc_register_platform(&fsi_soc_platform);
+ ret = snd_soc_register_platform(&pdev->dev, &fsi_soc_platform);
if (ret < 0) {
dev_err(&pdev->dev, "cannot snd soc register\n");
goto exit_free_irq;
}
- return snd_soc_register_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
+ return snd_soc_register_dais(&pdev->dev, fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
exit_free_irq:
free_irq(irq, master);
@@ -1171,10 +1209,10 @@
{
struct fsi_master *master;
- master = fsi_get_master(fsi_soc_dai[0].private_data);
+ master = dev_get_drvdata(&pdev->dev);
- snd_soc_unregister_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
- snd_soc_unregister_platform(&fsi_soc_platform);
+ snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai));
+ snd_soc_unregister_platform(&pdev->dev);
pm_runtime_disable(&pdev->dev);
@@ -1183,11 +1221,6 @@
iounmap(master->base);
kfree(master);
- fsi_soc_dai[0].dev = NULL;
- fsi_soc_dai[0].private_data = NULL;
- fsi_soc_dai[1].dev = NULL;
- fsi_soc_dai[1].private_data = NULL;
-
return 0;
}
@@ -1229,11 +1262,13 @@
static struct platform_device_id fsi_id_table[] = {
{ "sh_fsi", (kernel_ulong_t)&fsi1_core },
{ "sh_fsi2", (kernel_ulong_t)&fsi2_core },
+ {},
};
+MODULE_DEVICE_TABLE(platform, fsi_id_table);
static struct platform_driver fsi_driver = {
.driver = {
- .name = "sh_fsi",
+ .name = "fsi-pcm-audio",
.pm = &fsi_pm_ops,
},
.probe = fsi_probe,
@@ -1250,6 +1285,7 @@
{
platform_driver_unregister(&fsi_driver);
}
+
module_init(fsi_mobile_init);
module_exit(fsi_mobile_exit);
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c
index 41db75a..c87e3ff 100644
--- a/sound/soc/sh/hac.c
+++ b/sound/soc/sh/hac.c
@@ -239,8 +239,7 @@
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct hac_priv *hac = &hac_cpu_data[rtd->dai->cpu_dai->id];
+ struct hac_priv *hac = &hac_cpu_data[dai->id];
int d = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
switch (params->msbits) {
@@ -271,10 +270,9 @@
.hw_params = hac_hw_params,
};
-struct snd_soc_dai sh4_hac_dai[] = {
+static struct snd_soc_dai_driver sh4_hac_dai[] = {
{
- .name = "HAC0",
- .id = 0,
+ .name = "hac-dai.0",
.ac97_control = 1,
.playback = {
.rates = AC97_RATES,
@@ -292,8 +290,7 @@
},
#ifdef CONFIG_CPU_SUBTYPE_SH7760
{
- .name = "HAC1",
- .ac97_control = 1,
+ .name = "hac-dai.1",
.id = 1,
.playback = {
.rates = AC97_RATES,
@@ -312,19 +309,40 @@
},
#endif
};
-EXPORT_SYMBOL_GPL(sh4_hac_dai);
-static int __init sh4_hac_init(void)
+static int __devinit hac_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_dais(sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai));
+ return snd_soc_register_dais(&pdev->dev, sh4_hac_dai,
+ ARRAY_SIZE(sh4_hac_dai));
}
-module_init(sh4_hac_init);
-static void __exit sh4_hac_exit(void)
+static int __devexit hac_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_dais(sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai));
+ snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sh4_hac_dai));
+ return 0;
}
-module_exit(sh4_hac_exit);
+
+static struct platform_driver hac_pcm_driver = {
+ .driver = {
+ .name = "hac-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = hac_soc_platform_probe,
+ .remove = __devexit_p(hac_soc_platform_remove),
+};
+
+static int __init sh4_hac_pcm_init(void)
+{
+ return platform_driver_register(&hac_pcm_driver);
+}
+module_init(sh4_hac_pcm_init);
+
+static void __exit sh4_hac_pcm_exit(void)
+{
+ platform_driver_unregister(&hac_pcm_driver);
+}
+module_exit(sh4_hac_pcm_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SuperH onchip HAC (AC97) audio driver");
diff --git a/sound/soc/sh/migor.c b/sound/soc/sh/migor.c
index b823a5c..ac6c49c 100644
--- a/sound/soc/sh/migor.c
+++ b/sound/soc/sh/migor.c
@@ -12,6 +12,7 @@
#include <linux/firmware.h>
#include <linux/module.h>
+#include <asm/clkdev.h>
#include <asm/clock.h>
#include <cpu/sh7722.h>
@@ -40,17 +41,17 @@
};
static struct clk siumckb_clk = {
- .name = "siumckb_clk",
- .id = -1,
.ops = &siumckb_clk_ops,
.rate = 0, /* initialised at run-time */
};
+static struct clk_lookup *siumckb_lookup;
+
static int migor_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
unsigned int rate = params_rate(params);
@@ -68,7 +69,7 @@
if (ret < 0)
return ret;
- ret = snd_soc_dai_set_fmt(rtd->dai->cpu_dai, SND_SOC_DAIFMT_NB_IF |
+ ret = snd_soc_dai_set_fmt(rtd->cpu_dai, SND_SOC_DAIFMT_NB_IF |
SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS);
if (ret < 0)
return ret;
@@ -81,7 +82,7 @@
clk_set_rate(&siumckb_clk, codec_freq);
dev_dbg(codec_dai->dev, "%s: configure %luHz\n", __func__, codec_freq);
- ret = snd_soc_dai_set_sysclk(rtd->dai->cpu_dai, SIU_CLKB_EXT,
+ ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, SIU_CLKB_EXT,
codec_freq / 2, SND_SOC_CLOCK_IN);
if (!ret)
@@ -93,7 +94,7 @@
static int migor_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
if (use_count) {
use_count--;
@@ -136,8 +137,10 @@
{ "Mic Bias", NULL, "External Microphone" },
};
-static int migor_dai_init(struct snd_soc_codec *codec)
+static int migor_dai_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
snd_soc_dapm_new_controls(codec, migor_dapm_widgets,
ARRAY_SIZE(migor_dapm_widgets));
@@ -150,8 +153,10 @@
static struct snd_soc_dai_link migor_dai = {
.name = "wm8978",
.stream_name = "WM8978",
- .cpu_dai = &siu_i2s_dai,
- .codec_dai = &wm8978_dai,
+ .cpu_dai_name = "siu-i2s-dai",
+ .codec_dai_name = "wm8978-hifi",
+ .platform_name = "siu-pcm-audio",
+ .codec_name = "wm8978.0-001a",
.ops = &migor_dai_ops,
.init = migor_dai_init,
};
@@ -159,17 +164,10 @@
/* migor audio machine driver */
static struct snd_soc_card snd_soc_migor = {
.name = "Migo-R",
- .platform = &siu_platform,
.dai_link = &migor_dai,
.num_links = 1,
};
-/* migor audio subsystem */
-static struct snd_soc_device migor_snd_devdata = {
- .card = &snd_soc_migor,
- .codec_dev = &soc_codec_dev_wm8978,
-};
-
static struct platform_device *migor_snd_device;
static int __init migor_init(void)
@@ -180,6 +178,13 @@
if (ret < 0)
return ret;
+ siumckb_lookup = clkdev_alloc(&siumckb_clk, "siumckb_clk", NULL);
+ if (!siumckb_lookup) {
+ ret = -ENOMEM;
+ goto eclkdevalloc;
+ }
+ clkdev_add(siumckb_lookup);
+
/* Port number used on this machine: port B */
migor_snd_device = platform_device_alloc("soc-audio", 1);
if (!migor_snd_device) {
@@ -187,9 +192,7 @@
goto epdevalloc;
}
- platform_set_drvdata(migor_snd_device, &migor_snd_devdata);
-
- migor_snd_devdata.dev = &migor_snd_device->dev;
+ platform_set_drvdata(migor_snd_device, &snd_soc_migor);
ret = platform_device_add(migor_snd_device);
if (ret)
@@ -200,12 +203,15 @@
epdevadd:
platform_device_put(migor_snd_device);
epdevalloc:
+ clkdev_drop(siumckb_lookup);
+eclkdevalloc:
clk_unregister(&siumckb_clk);
return ret;
}
static void __exit migor_exit(void)
{
+ clkdev_drop(siumckb_lookup);
clk_unregister(&siumckb_clk);
platform_device_unregister(migor_snd_device);
}
diff --git a/sound/soc/sh/sh7760-ac97.c b/sound/soc/sh/sh7760-ac97.c
index ce7f95b..b897f7b 100644
--- a/sound/soc/sh/sh7760-ac97.c
+++ b/sound/soc/sh/sh7760-ac97.c
@@ -15,41 +15,35 @@
#include <sound/soc-dapm.h>
#include <asm/io.h>
-#include "../codecs/ac97.h"
-
#define IPSEL 0xFE400034
/* platform specific structs can be declared here */
-extern struct snd_soc_dai sh4_hac_dai[2];
-extern struct snd_soc_platform sh7760_soc_platform;
+extern struct snd_soc_dai_driver sh4_hac_dai[2];
+extern struct snd_soc_platform_driver sh7760_soc_platform;
-static int machine_init(struct snd_soc_codec *codec)
+static int machine_init(struct snd_soc_pcm_runtime *rtd)
{
- snd_soc_dapm_sync(codec);
+ snd_soc_dapm_sync(rtd->codec);
return 0;
}
static struct snd_soc_dai_link sh7760_ac97_dai = {
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &sh4_hac_dai[0], /* HAC0 */
- .codec_dai = &ac97_dai,
+ .cpu_dai_name = "hac-dai.0", /* HAC0 */
+ .codec_dai_name = "ac97-hifi",
+ .platform_name = "sh7760-pcm-audio",
+ .codec_name = "ac97-codec",
.init = machine_init,
.ops = NULL,
};
static struct snd_soc_card sh7760_ac97_soc_machine = {
.name = "SH7760 AC97",
- .platform = &sh7760_soc_platform,
.dai_link = &sh7760_ac97_dai,
.num_links = 1,
};
-static struct snd_soc_device sh7760_ac97_snd_devdata = {
- .card = &sh7760_ac97_soc_machine,
- .codec_dev = &soc_codec_dev_ac97,
-};
-
static struct platform_device *sh7760_ac97_snd_device;
static int __init sh7760_ac97_init(void)
@@ -67,8 +61,7 @@
goto out;
platform_set_drvdata(sh7760_ac97_snd_device,
- &sh7760_ac97_snd_devdata);
- sh7760_ac97_snd_devdata.dev = &sh7760_ac97_snd_device->dev;
+ &sh7760_ac97_soc_machine);
ret = platform_device_add(sh7760_ac97_snd_device);
if (ret)
diff --git a/sound/soc/sh/siu.h b/sound/soc/sh/siu.h
index 492b1ca..9f4dcb9 100644
--- a/sound/soc/sh/siu.h
+++ b/sound/soc/sh/siu.h
@@ -98,7 +98,9 @@
SIU_CLKB_EXT
};
+struct device;
struct siu_info {
+ struct device *dev;
int port_id;
u32 __iomem *pram;
u32 __iomem *xram;
@@ -181,8 +183,8 @@
#define SIU_BRGBSEL (0x108 / sizeof(u32))
#define SIU_BRRB (0x10c / sizeof(u32))
-extern struct snd_soc_platform siu_platform;
-extern struct snd_soc_dai siu_i2s_dai;
+extern struct snd_soc_platform_driver siu_platform;
+extern struct siu_info *siu_i2s_data;
int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card);
void siu_free_port(struct siu_port *port_info);
diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/sh/siu_dai.c
index eeed5ed..af53b64 100644
--- a/sound/soc/sh/siu_dai.c
+++ b/sound/soc/sh/siu_dai.c
@@ -71,6 +71,8 @@
struct format_flag capture;
};
+struct siu_info *siu_i2s_data;
+
static struct port_flag siu_flags[SIU_PORT_NUM] = {
[SIU_PORT_A] = {
.playback = {
@@ -104,13 +106,13 @@
static void siu_dai_start(struct siu_port *port_info)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
u32 __iomem *base = info->reg;
dev_dbg(port_info->pcm->card->dev, "%s\n", __func__);
/* Turn on SIU clock */
- pm_runtime_get_sync(siu_i2s_dai.dev);
+ pm_runtime_get_sync(info->dev);
/* Issue software reset to siu */
siu_write32(base + SIU_SRCTL, 0);
@@ -148,21 +150,21 @@
siu_write32(base + SIU_SBDVCB, port_info->capture.volume);
}
-static void siu_dai_stop(void)
+static void siu_dai_stop(struct siu_port *port_info)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
u32 __iomem *base = info->reg;
/* SIU software reset */
siu_write32(base + SIU_SRCTL, 0);
/* Turn off SIU clock */
- pm_runtime_put_sync(siu_i2s_dai.dev);
+ pm_runtime_put_sync(info->dev);
}
static void siu_dai_spbAselect(struct siu_port *port_info)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
struct siu_firmware *fw = &info->fw;
u32 *ydef = fw->yram0;
u32 idx;
@@ -187,7 +189,7 @@
static void siu_dai_spbBselect(struct siu_port *port_info)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
struct siu_firmware *fw = &info->fw;
u32 *ydef = fw->yram0;
u32 idx;
@@ -207,7 +209,7 @@
static void siu_dai_open(struct siu_stream *siu_stream)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
u32 __iomem *base = info->reg;
u32 srctl, ifctl;
@@ -238,7 +240,7 @@
*/
static void siu_dai_pcmdatapack(struct siu_stream *siu_stream)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
u32 __iomem *base = info->reg;
u32 dpak;
@@ -258,7 +260,7 @@
static int siu_dai_spbstart(struct siu_port *port_info)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
u32 __iomem *base = info->reg;
struct siu_firmware *fw = &info->fw;
u32 *ydef = fw->yram0;
@@ -323,7 +325,7 @@
static void siu_dai_spbstop(struct siu_port *port_info)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
u32 __iomem *base = info->reg;
siu_write32(base + SIU_SBACTIV, 0);
@@ -402,7 +404,7 @@
{
struct siu_port *port_info = snd_kcontrol_chip(kctrl);
struct device *dev = port_info->pcm->card->dev;
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
u32 __iomem *base = info->reg;
u32 new_vol;
u32 cur_vol;
@@ -510,7 +512,7 @@
static int siu_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = snd_soc_dai_get_drvdata(dai);
struct snd_pcm_runtime *rt = substream->runtime;
struct siu_port *port_info = siu_port_info(substream);
int ret;
@@ -532,7 +534,7 @@
static void siu_dai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = snd_soc_dai_get_drvdata(dai);
struct siu_port *port_info = siu_port_info(substream);
dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__,
@@ -548,7 +550,7 @@
/* during stmread or stmwrite ? */
BUG_ON(port_info->playback.rw_flg || port_info->capture.rw_flg);
siu_dai_spbstop(port_info);
- siu_dai_stop();
+ siu_dai_stop(port_info);
}
}
@@ -556,7 +558,7 @@
static int siu_dai_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = snd_soc_dai_get_drvdata(dai);
struct snd_pcm_runtime *rt = substream->runtime;
struct siu_port *port_info = siu_port_info(substream);
struct siu_stream *siu_stream;
@@ -605,7 +607,7 @@
static int siu_dai_set_fmt(struct snd_soc_dai *dai,
unsigned int fmt)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = snd_soc_dai_get_drvdata(dai);
u32 __iomem *base = info->reg;
u32 ifctl;
@@ -671,21 +673,37 @@
return -EINVAL;
}
- siu_clk = clk_get(siu_i2s_dai.dev, siu_name);
- if (IS_ERR(siu_clk))
+ siu_clk = clk_get(dai->dev, siu_name);
+ if (IS_ERR(siu_clk)) {
+ dev_err(dai->dev, "%s: cannot get a SIU clock: %ld\n", __func__,
+ PTR_ERR(siu_clk));
return PTR_ERR(siu_clk);
-
- parent_clk = clk_get(siu_i2s_dai.dev, parent_name);
- if (!IS_ERR(parent_clk)) {
- ret = clk_set_parent(siu_clk, parent_clk);
- if (!ret)
- clk_set_rate(siu_clk, freq);
- clk_put(parent_clk);
}
+ parent_clk = clk_get(dai->dev, parent_name);
+ if (IS_ERR(parent_clk)) {
+ ret = PTR_ERR(parent_clk);
+ dev_err(dai->dev, "cannot get a SIU clock parent: %d\n", ret);
+ goto epclkget;
+ }
+
+ ret = clk_set_parent(siu_clk, parent_clk);
+ if (ret < 0) {
+ dev_err(dai->dev, "cannot reparent the SIU clock: %d\n", ret);
+ goto eclksetp;
+ }
+
+ ret = clk_set_rate(siu_clk, freq);
+ if (ret < 0)
+ dev_err(dai->dev, "cannot set SIU clock rate: %d\n", ret);
+
+ /* TODO: when clkdev gets reference counting we'll move these to siu_dai_shutdown() */
+eclksetp:
+ clk_put(parent_clk);
+epclkget:
clk_put(siu_clk);
- return 0;
+ return ret;
}
static struct snd_soc_dai_ops siu_dai_ops = {
@@ -696,9 +714,8 @@
.set_fmt = siu_dai_set_fmt,
};
-struct snd_soc_dai siu_i2s_dai = {
- .name = "sh-siu",
- .id = 0,
+static struct snd_soc_dai_driver siu_i2s_dai = {
+ .name = "siu-i2s-dai",
.playback = {
.channels_min = 2,
.channels_max = 2,
@@ -713,7 +730,6 @@
},
.ops = &siu_dai_ops,
};
-EXPORT_SYMBOL_GPL(siu_i2s_dai);
static int __devinit siu_probe(struct platform_device *pdev)
{
@@ -725,6 +741,8 @@
info = kmalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
+ siu_i2s_data = info;
+ info->dev = &pdev->dev;
ret = request_firmware(&fw_entry, "siu_spb.bin", &pdev->dev);
if (ret)
@@ -767,14 +785,14 @@
if (!info->reg)
goto emapreg;
- siu_i2s_dai.dev = &pdev->dev;
- siu_i2s_dai.private_data = info;
+ dev_set_drvdata(&pdev->dev, info);
- ret = snd_soc_register_dais(&siu_i2s_dai, 1);
+ /* register using ARRAY version so we can keep dai name */
+ ret = snd_soc_register_dais(&pdev->dev, &siu_i2s_dai, 1);
if (ret < 0)
goto edaiinit;
- ret = snd_soc_register_platform(&siu_platform);
+ ret = snd_soc_register_platform(&pdev->dev, &siu_platform);
if (ret < 0)
goto esocregp;
@@ -783,7 +801,7 @@
return ret;
esocregp:
- snd_soc_unregister_dais(&siu_i2s_dai, 1);
+ snd_soc_unregister_dai(&pdev->dev);
edaiinit:
iounmap(info->reg);
emapreg:
@@ -804,13 +822,13 @@
static int __devexit siu_remove(struct platform_device *pdev)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = dev_get_drvdata(&pdev->dev);
struct resource *res;
pm_runtime_disable(&pdev->dev);
- snd_soc_unregister_platform(&siu_platform);
- snd_soc_unregister_dais(&siu_i2s_dai, 1);
+ snd_soc_unregister_platform(&pdev->dev);
+ snd_soc_unregister_dai(&pdev->dev);
iounmap(info->reg);
iounmap(info->yram);
@@ -826,7 +844,8 @@
static struct platform_driver siu_driver = {
.driver = {
- .name = "sh_siu",
+ .owner = THIS_MODULE,
+ .name = "siu-pcm-audio",
},
.probe = siu_probe,
.remove = __devexit_p(siu_remove),
diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c
index 36170be..d6c79fa 100644
--- a/sound/soc/sh/siu_pcm.c
+++ b/sound/soc/sh/siu_pcm.c
@@ -48,7 +48,7 @@
/* transfersize is number of u32 dma transfers per period */
static int siu_pcm_stmwrite_stop(struct siu_port *port_info)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
u32 __iomem *base = info->reg;
struct siu_stream *siu_stream = &port_info->playback;
u32 stfifo;
@@ -114,7 +114,7 @@
static int siu_pcm_wr_set(struct siu_port *port_info,
dma_addr_t buff, u32 size)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
u32 __iomem *base = info->reg;
struct siu_stream *siu_stream = &port_info->playback;
struct snd_pcm_substream *substream = siu_stream->substream;
@@ -161,7 +161,7 @@
static int siu_pcm_rd_set(struct siu_port *port_info,
dma_addr_t buff, size_t size)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
u32 __iomem *base = info->reg;
struct siu_stream *siu_stream = &port_info->capture;
struct snd_pcm_substream *substream = siu_stream->substream;
@@ -270,7 +270,7 @@
static int siu_pcm_stmread_stop(struct siu_port *port_info)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
u32 __iomem *base = info->reg;
struct siu_stream *siu_stream = &port_info->capture;
struct device *dev = siu_stream->substream->pcm->card->dev;
@@ -294,7 +294,7 @@
static int siu_pcm_hw_params(struct snd_pcm_substream *ss,
struct snd_pcm_hw_params *hw_params)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
struct device *dev = ss->pcm->card->dev;
int ret;
@@ -309,7 +309,7 @@
static int siu_pcm_hw_free(struct snd_pcm_substream *ss)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
struct siu_port *port_info = siu_port_info(ss);
struct device *dev = ss->pcm->card->dev;
struct siu_stream *siu_stream;
@@ -340,11 +340,12 @@
static int siu_pcm_open(struct snd_pcm_substream *ss)
{
/* Playback / Capture */
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct snd_soc_pcm_runtime *rtd = ss->private_data;
+ struct siu_platform *pdata = rtd->platform->dev->platform_data;
+ struct siu_info *info = siu_i2s_data;
struct siu_port *port_info = siu_port_info(ss);
struct siu_stream *siu_stream;
u32 port = info->port_id;
- struct siu_platform *pdata = siu_i2s_dai.dev->platform_data;
struct device *dev = ss->pcm->card->dev;
dma_cap_mask_t mask;
struct sh_dmae_slave *param;
@@ -381,7 +382,7 @@
static int siu_pcm_close(struct snd_pcm_substream *ss)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
struct device *dev = ss->pcm->card->dev;
struct siu_port *port_info = siu_port_info(ss);
struct siu_stream *siu_stream;
@@ -403,7 +404,7 @@
static int siu_pcm_prepare(struct snd_pcm_substream *ss)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
struct siu_port *port_info = siu_port_info(ss);
struct device *dev = ss->pcm->card->dev;
struct snd_pcm_runtime *rt = ss->runtime;
@@ -449,7 +450,7 @@
static int siu_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
struct device *dev = ss->pcm->card->dev;
struct siu_port *port_info = siu_port_info(ss);
int ret;
@@ -492,7 +493,7 @@
static snd_pcm_uframes_t siu_pcm_pointer_dma(struct snd_pcm_substream *ss)
{
struct device *dev = ss->pcm->card->dev;
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
u32 __iomem *base = info->reg;
struct siu_port *port_info = siu_port_info(ss);
struct snd_pcm_runtime *rt = ss->runtime;
@@ -528,7 +529,7 @@
struct snd_pcm *pcm)
{
/* card->dev == socdev->dev, see snd_soc_new_pcms() */
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
struct platform_device *pdev = to_platform_device(card->dev);
int ret;
int i;
@@ -605,9 +606,8 @@
.pointer = siu_pcm_pointer_dma,
};
-struct snd_soc_platform siu_platform = {
- .name = "siu-audio",
- .pcm_ops = &siu_pcm_ops,
+struct snd_soc_platform_driver siu_platform = {
+ .ops = &siu_pcm_ops,
.pcm_new = siu_pcm_new,
.pcm_free = siu_pcm_free,
};
diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c
index b378096..40bbdf1 100644
--- a/sound/soc/sh/ssi.c
+++ b/sound/soc/sh/ssi.c
@@ -92,8 +92,7 @@
static int ssi_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+ struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
if (ssi->inuse) {
pr_debug("ssi: already in use!\n");
return -EBUSY;
@@ -105,8 +104,7 @@
static void ssi_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+ struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
ssi->inuse = 0;
}
@@ -114,8 +112,7 @@
static int ssi_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+ struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -135,8 +132,7 @@
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+ struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
unsigned long ssicr = SSIREG(SSICR);
unsigned int bits, channels, swl, recv, i;
@@ -346,10 +342,9 @@
.set_fmt = ssi_set_fmt,
};
-struct snd_soc_dai sh4_ssi_dai[] = {
+struct snd_soc_dai_driver sh4_ssi_dai[] = {
{
- .name = "SSI0",
- .id = 0,
+ .name = "ssi-dai.0",
.playback = {
.rates = SSI_RATES,
.formats = SSI_FMTS,
@@ -366,8 +361,7 @@
},
#ifdef CONFIG_CPU_SUBTYPE_SH7760
{
- .name = "SSI1",
- .id = 1,
+ .name = "ssi-dai.1",
.playback = {
.rates = SSI_RATES,
.formats = SSI_FMTS,
@@ -384,19 +378,40 @@
},
#endif
};
-EXPORT_SYMBOL_GPL(sh4_ssi_dai);
-static int __init sh4_ssi_init(void)
+static int __devinit sh4_soc_dai_probe(struct platform_device *pdev)
{
- return snd_soc_register_dais(sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai));
+ return snd_soc_register_dais(&pdev->dev, sh4_ssi_dai,
+ ARRAY_SIZE(sh4_ssi_dai));
}
-module_init(sh4_ssi_init);
-static void __exit sh4_ssi_exit(void)
+static int __devexit sh4_soc_dai_remove(struct platform_device *pdev)
{
- snd_soc_unregister_dais(sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai));
+ snd_soc_unregister_dai(&pdev->dev, ARRAY_SIZE(sh4_ssi_dai));
+ return 0;
}
-module_exit(sh4_ssi_exit);
+
+static struct platform_driver sh4_ssi_driver = {
+ .driver = {
+ .name = "sh4-ssi-dai",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = sh4_soc_dai_probe,
+ .remove = __devexit_p(sh4_soc_dai_remove),
+};
+
+static int __init snd_sh4_ssi_init(void)
+{
+ return platform_driver_register(&sh4_ssi_driver);
+}
+module_init(snd_sh4_ssi_init);
+
+static void __exit snd_sh4_ssi_exit(void)
+{
+ platform_driver_unregister(&sh4_ssi_driver);
+}
+module_exit(snd_sh4_ssi_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SuperH onchip SSI (I2S) audio driver");
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c
index adbc68c..d214f02 100644
--- a/sound/soc/soc-cache.c
+++ b/sound/soc/soc-cache.c
@@ -19,8 +19,15 @@
unsigned int reg)
{
u16 *cache = codec->reg_cache;
- if (reg >= codec->reg_cache_size)
- return -1;
+
+ if (reg >= codec->driver->reg_cache_size ||
+ snd_soc_codec_volatile_register(codec, reg)) {
+ if (codec->cache_only)
+ return -1;
+
+ return codec->hw_read(codec, reg);
+ }
+
return cache[reg];
}
@@ -31,13 +38,12 @@
u8 data[2];
int ret;
- BUG_ON(codec->volatile_register);
-
data[0] = (reg << 4) | ((value >> 8) & 0x000f);
data[1] = value & 0x00ff;
- if (reg < codec->reg_cache_size)
- cache[reg] = value;
+ if (!snd_soc_codec_volatile_register(codec, reg) &&
+ reg < codec->driver->reg_cache_size)
+ cache[reg] = value;
if (codec->cache_only) {
codec->cache_sync = 1;
@@ -89,8 +95,15 @@
unsigned int reg)
{
u16 *cache = codec->reg_cache;
- if (reg >= codec->reg_cache_size)
- return -1;
+
+ if (reg >= codec->driver->reg_cache_size ||
+ snd_soc_codec_volatile_register(codec, reg)) {
+ if (codec->cache_only)
+ return -1;
+
+ return codec->hw_read(codec, reg);
+ }
+
return cache[reg];
}
@@ -101,13 +114,12 @@
u8 data[2];
int ret;
- BUG_ON(codec->volatile_register);
-
data[0] = (reg << 1) | ((value >> 8) & 0x0001);
data[1] = value & 0x00ff;
- if (reg < codec->reg_cache_size)
- cache[reg] = value;
+ if (!snd_soc_codec_volatile_register(codec, reg) &&
+ reg < codec->driver->reg_cache_size)
+ cache[reg] = value;
if (codec->cache_only) {
codec->cache_sync = 1;
@@ -161,14 +173,13 @@
u8 *cache = codec->reg_cache;
u8 data[2];
- BUG_ON(codec->volatile_register);
-
reg &= 0xff;
data[0] = reg;
data[1] = value & 0xff;
- if (reg < codec->reg_cache_size)
- cache[reg] = value;
+ if (!snd_soc_codec_volatile_register(codec, reg) &&
+ reg < codec->driver->reg_cache_size)
+ cache[reg] = value;
if (codec->cache_only) {
codec->cache_sync = 1;
@@ -187,12 +198,49 @@
unsigned int reg)
{
u8 *cache = codec->reg_cache;
+
reg &= 0xff;
- if (reg >= codec->reg_cache_size)
- return -1;
+ if (reg >= codec->driver->reg_cache_size ||
+ snd_soc_codec_volatile_register(codec, reg)) {
+ if (codec->cache_only)
+ return -1;
+
+ return codec->hw_read(codec, reg);
+ }
+
return cache[reg];
}
+#if defined(CONFIG_SPI_MASTER)
+static int snd_soc_8_8_spi_write(void *control_data, const char *data,
+ int len)
+{
+ struct spi_device *spi = control_data;
+ struct spi_transfer t;
+ struct spi_message m;
+ u8 msg[2];
+
+ if (len <= 0)
+ return 0;
+
+ msg[0] = data[0];
+ msg[1] = data[1];
+
+ spi_message_init(&m);
+ memset(&t, 0, (sizeof t));
+
+ t.tx_buf = &msg[0];
+ t.len = len;
+
+ spi_message_add_tail(&t, &m);
+ spi_sync(spi, &m);
+
+ return len;
+}
+#else
+#define snd_soc_8_8_spi_write NULL
+#endif
+
static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
@@ -203,7 +251,8 @@
data[1] = (value >> 8) & 0xff;
data[2] = value & 0xff;
- if (!snd_soc_codec_volatile_register(codec, reg))
+ if (!snd_soc_codec_volatile_register(codec, reg) &&
+ reg < codec->driver->reg_cache_size)
reg_cache[reg] = value;
if (codec->cache_only) {
@@ -224,10 +273,10 @@
{
u16 *cache = codec->reg_cache;
- if (reg >= codec->reg_cache_size ||
+ if (reg >= codec->driver->reg_cache_size ||
snd_soc_codec_volatile_register(codec, reg)) {
if (codec->cache_only)
- return -EINVAL;
+ return -1;
return codec->hw_read(codec, reg);
} else {
@@ -235,6 +284,37 @@
}
}
+#if defined(CONFIG_SPI_MASTER)
+static int snd_soc_8_16_spi_write(void *control_data, const char *data,
+ int len)
+{
+ struct spi_device *spi = control_data;
+ struct spi_transfer t;
+ struct spi_message m;
+ u8 msg[3];
+
+ if (len <= 0)
+ return 0;
+
+ msg[0] = data[0];
+ msg[1] = data[1];
+ msg[2] = data[2];
+
+ spi_message_init(&m);
+ memset(&t, 0, (sizeof t));
+
+ t.tx_buf = &msg[0];
+ t.len = len;
+
+ spi_message_add_tail(&t, &m);
+ spi_sync(spi, &m);
+
+ return len;
+}
+#else
+#define snd_soc_8_16_spi_write NULL
+#endif
+
#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
unsigned int r)
@@ -343,8 +423,14 @@
u8 *cache = codec->reg_cache;
reg &= 0xff;
- if (reg >= codec->reg_cache_size)
- return -1;
+ if (reg >= codec->driver->reg_cache_size ||
+ snd_soc_codec_volatile_register(codec, reg)) {
+ if (codec->cache_only)
+ return -1;
+
+ return codec->hw_read(codec, reg);
+ }
+
return cache[reg];
}
@@ -355,15 +441,14 @@
u8 data[3];
int ret;
- BUG_ON(codec->volatile_register);
-
data[0] = (reg >> 8) & 0xff;
data[1] = reg & 0xff;
data[2] = value;
reg &= 0xff;
- if (reg < codec->reg_cache_size)
- cache[reg] = value;
+ if (!snd_soc_codec_volatile_register(codec, reg) &&
+ reg < codec->driver->reg_cache_size)
+ cache[reg] = value;
if (codec->cache_only) {
codec->cache_sync = 1;
@@ -451,10 +536,10 @@
{
u16 *cache = codec->reg_cache;
- if (reg >= codec->reg_cache_size ||
+ if (reg >= codec->driver->reg_cache_size ||
snd_soc_codec_volatile_register(codec, reg)) {
if (codec->cache_only)
- return -EINVAL;
+ return -1;
return codec->hw_read(codec, reg);
}
@@ -474,8 +559,9 @@
data[2] = (value >> 8) & 0xff;
data[3] = value & 0xff;
- if (reg < codec->reg_cache_size)
- cache[reg] = value;
+ if (!snd_soc_codec_volatile_register(codec, reg) &&
+ reg < codec->driver->reg_cache_size)
+ cache[reg] = value;
if (codec->cache_only) {
codec->cache_sync = 1;
@@ -493,6 +579,38 @@
return -EIO;
}
+#if defined(CONFIG_SPI_MASTER)
+static int snd_soc_16_16_spi_write(void *control_data, const char *data,
+ int len)
+{
+ struct spi_device *spi = control_data;
+ struct spi_transfer t;
+ struct spi_message m;
+ u8 msg[4];
+
+ if (len <= 0)
+ return 0;
+
+ msg[0] = data[0];
+ msg[1] = data[1];
+ msg[2] = data[2];
+ msg[3] = data[3];
+
+ spi_message_init(&m);
+ memset(&t, 0, (sizeof t));
+
+ t.tx_buf = &msg[0];
+ t.len = len;
+
+ spi_message_add_tail(&t, &m);
+ spi_sync(spi, &m);
+
+ return len;
+}
+#else
+#define snd_soc_16_16_spi_write NULL
+#endif
+
static struct {
int addr_bits;
int data_bits;
@@ -515,11 +633,13 @@
.addr_bits = 8, .data_bits = 8,
.write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
.i2c_read = snd_soc_8_8_read_i2c,
+ .spi_write = snd_soc_8_8_spi_write,
},
{
.addr_bits = 8, .data_bits = 16,
.write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
.i2c_read = snd_soc_8_16_read_i2c,
+ .spi_write = snd_soc_8_16_spi_write,
},
{
.addr_bits = 16, .data_bits = 8,
@@ -531,6 +651,7 @@
.addr_bits = 16, .data_bits = 16,
.write = snd_soc_16_16_write, .read = snd_soc_16_16_read,
.i2c_read = snd_soc_16_16_read_i2c,
+ .spi_write = snd_soc_16_16_spi_write,
},
};
@@ -571,8 +692,8 @@
return -EINVAL;
}
- codec->write = io_types[i].write;
- codec->read = io_types[i].read;
+ codec->driver->write = io_types[i].write;
+ codec->driver->read = io_types[i].read;
switch (control) {
case SND_SOC_CUSTOM:
@@ -584,11 +705,19 @@
#endif
if (io_types[i].i2c_read)
codec->hw_read = io_types[i].i2c_read;
+
+ codec->control_data = container_of(codec->dev,
+ struct i2c_client,
+ dev);
break;
case SND_SOC_SPI:
if (io_types[i].spi_write)
codec->hw_write = io_types[i].spi_write;
+
+ codec->control_data = container_of(codec->dev,
+ struct spi_device,
+ dev);
break;
}
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index acc91da..70d9a73 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3,6 +3,8 @@
*
* Copyright 2005 Wolfson Microelectronics PLC.
* Copyright 2005 Openedhand Ltd.
+ * Copyright (C) 2010 Slimlogic Ltd.
+ * Copyright (C) 2010 Texas Instruments Inc.
*
* Author: Liam Girdwood <lrg@slimlogic.co.uk>
* with code, comments and ideas from :-
@@ -37,6 +39,8 @@
#include <sound/soc-dapm.h>
#include <sound/initval.h>
+#define NAME_SIZE 32
+
static DEFINE_MUTEX(pcm_mutex);
static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq);
@@ -52,6 +56,7 @@
static int snd_soc_register_card(struct snd_soc_card *card);
static int snd_soc_unregister_card(struct snd_soc_card *card);
+static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num);
/*
* This is a timeout to do a DAPM powerdown after a stream is closed().
@@ -86,30 +91,30 @@
{
int ret, i, step = 1, count = 0;
- if (!codec->reg_cache_size)
+ if (!codec->driver->reg_cache_size)
return 0;
- if (codec->reg_cache_step)
- step = codec->reg_cache_step;
+ if (codec->driver->reg_cache_step)
+ step = codec->driver->reg_cache_step;
count += sprintf(buf, "%s registers\n", codec->name);
- for (i = 0; i < codec->reg_cache_size; i += step) {
- if (codec->readable_register && !codec->readable_register(i))
+ for (i = 0; i < codec->driver->reg_cache_size; i += step) {
+ if (codec->driver->readable_register && !codec->driver->readable_register(i))
continue;
count += sprintf(buf + count, "%2x: ", i);
if (count >= PAGE_SIZE - 1)
break;
- if (codec->display_register) {
- count += codec->display_register(codec, buf + count,
+ if (codec->driver->display_register) {
+ count += codec->driver->display_register(codec, buf + count,
PAGE_SIZE - count, i);
} else {
/* If the read fails it's almost certainly due to
* the register being volatile and the device being
* powered off.
*/
- ret = codec->read(codec, i);
+ ret = codec->driver->read(codec, i);
if (ret >= 0)
count += snprintf(buf + count,
PAGE_SIZE - count,
@@ -137,8 +142,10 @@
static ssize_t codec_reg_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct snd_soc_device *devdata = dev_get_drvdata(dev);
- return soc_codec_reg_show(devdata->card->codec, buf);
+ struct snd_soc_pcm_runtime *rtd =
+ container_of(dev, struct snd_soc_pcm_runtime, dev);
+
+ return soc_codec_reg_show(rtd->codec, buf);
}
static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL);
@@ -146,20 +153,20 @@
static ssize_t pmdown_time_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct snd_soc_device *socdev = dev_get_drvdata(dev);
- struct snd_soc_card *card = socdev->card;
+ struct snd_soc_pcm_runtime *rtd =
+ container_of(dev, struct snd_soc_pcm_runtime, dev);
- return sprintf(buf, "%ld\n", card->pmdown_time);
+ return sprintf(buf, "%ld\n", rtd->pmdown_time);
}
static ssize_t pmdown_time_set(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct snd_soc_device *socdev = dev_get_drvdata(dev);
- struct snd_soc_card *card = socdev->card;
+ struct snd_soc_pcm_runtime *rtd =
+ container_of(dev, struct snd_soc_pcm_runtime, dev);
- strict_strtol(buf, 10, &card->pmdown_time);
+ strict_strtol(buf, 10, &rtd->pmdown_time);
return count;
}
@@ -203,19 +210,19 @@
return -EFAULT;
buf[buf_size] = 0;
- if (codec->reg_cache_step)
- step = codec->reg_cache_step;
+ if (codec->driver->reg_cache_step)
+ step = codec->driver->reg_cache_step;
while (*start == ' ')
start++;
reg = simple_strtoul(start, &start, 16);
- if ((reg >= codec->reg_cache_size) || (reg % step))
+ if ((reg >= codec->driver->reg_cache_size) || (reg % step))
return -EINVAL;
while (*start == ' ')
start++;
if (strict_strtoul(start, 16, &value))
return -EINVAL;
- codec->write(codec, reg, value);
+ codec->driver->write(codec, reg, value);
return buf_size;
}
@@ -227,16 +234,7 @@
static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
{
- char codec_root[128];
-
- if (codec->dev)
- snprintf(codec_root, sizeof(codec_root),
- "%s.%s", codec->name, dev_name(codec->dev));
- else
- snprintf(codec_root, sizeof(codec_root),
- "%s", codec->name);
-
- codec->debugfs_codec_root = debugfs_create_dir(codec_root,
+ codec->debugfs_codec_root = debugfs_create_dir(codec->name ,
debugfs_root);
if (!codec->debugfs_codec_root) {
printk(KERN_WARNING
@@ -272,6 +270,106 @@
debugfs_remove_recursive(codec->debugfs_codec_root);
}
+static ssize_t codec_list_read_file(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ ssize_t len, ret = 0;
+ struct snd_soc_codec *codec;
+
+ if (!buf)
+ return -ENOMEM;
+
+ list_for_each_entry(codec, &codec_list, list) {
+ len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
+ codec->name);
+ if (len >= 0)
+ ret += len;
+ if (ret > PAGE_SIZE) {
+ ret = PAGE_SIZE;
+ break;
+ }
+ }
+
+ if (ret >= 0)
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+ kfree(buf);
+
+ return ret;
+}
+
+static const struct file_operations codec_list_fops = {
+ .read = codec_list_read_file,
+ .llseek = default_llseek,/* read accesses f_pos */
+};
+
+static ssize_t dai_list_read_file(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ ssize_t len, ret = 0;
+ struct snd_soc_dai *dai;
+
+ if (!buf)
+ return -ENOMEM;
+
+ list_for_each_entry(dai, &dai_list, list) {
+ len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", dai->name);
+ if (len >= 0)
+ ret += len;
+ if (ret > PAGE_SIZE) {
+ ret = PAGE_SIZE;
+ break;
+ }
+ }
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+ kfree(buf);
+
+ return ret;
+}
+
+static const struct file_operations dai_list_fops = {
+ .read = dai_list_read_file,
+ .llseek = default_llseek,/* read accesses f_pos */
+};
+
+static ssize_t platform_list_read_file(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ ssize_t len, ret = 0;
+ struct snd_soc_platform *platform;
+
+ if (!buf)
+ return -ENOMEM;
+
+ list_for_each_entry(platform, &platform_list, list) {
+ len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
+ platform->name);
+ if (len >= 0)
+ ret += len;
+ if (ret > PAGE_SIZE) {
+ ret = PAGE_SIZE;
+ break;
+ }
+ }
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+ kfree(buf);
+
+ return ret;
+}
+
+static const struct file_operations platform_list_fops = {
+ .read = platform_list_read_file,
+ .llseek = default_llseek,/* read accesses f_pos */
+};
+
#else
static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec)
@@ -305,7 +403,7 @@
codec->ac97->dev.release = soc_ac97_device_release;
dev_set_name(&codec->ac97->dev, "%d-%d:%s",
- codec->card->number, 0, codec->name);
+ codec->card->snd_card->number, 0, codec->name);
err = device_register(&codec->ac97->dev);
if (err < 0) {
snd_printk(KERN_ERR "Can't register ac97 bus\n");
@@ -319,24 +417,21 @@
static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_dai_link *machine = rtd->dai;
- struct snd_soc_dai *cpu_dai = machine->cpu_dai;
- struct snd_soc_dai *codec_dai = machine->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
- if (codec_dai->symmetric_rates || cpu_dai->symmetric_rates ||
- machine->symmetric_rates) {
- dev_dbg(card->dev, "Symmetry forces %dHz rate\n",
- machine->rate);
+ if (codec_dai->driver->symmetric_rates || cpu_dai->driver->symmetric_rates ||
+ rtd->dai_link->symmetric_rates) {
+ dev_dbg(&rtd->dev, "Symmetry forces %dHz rate\n",
+ rtd->rate);
ret = snd_pcm_hw_constraint_minmax(substream->runtime,
SNDRV_PCM_HW_PARAM_RATE,
- machine->rate,
- machine->rate);
+ rtd->rate,
+ rtd->rate);
if (ret < 0) {
- dev_err(card->dev,
+ dev_err(&rtd->dev,
"Unable to apply rate symmetry constraint: %d\n", ret);
return ret;
}
@@ -353,20 +448,19 @@
static int soc_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_card *card = socdev->card;
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_dai_link *machine = rtd->dai;
- struct snd_soc_platform *platform = card->platform;
- struct snd_soc_dai *cpu_dai = machine->cpu_dai;
- struct snd_soc_dai *codec_dai = machine->codec_dai;
+ struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
+ struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver;
int ret = 0;
mutex_lock(&pcm_mutex);
/* startup the audio subsystem */
- if (cpu_dai->ops->startup) {
- ret = cpu_dai->ops->startup(substream, cpu_dai);
+ if (cpu_dai->driver->ops->startup) {
+ ret = cpu_dai->driver->ops->startup(substream, cpu_dai);
if (ret < 0) {
printk(KERN_ERR "asoc: can't open interface %s\n",
cpu_dai->name);
@@ -374,16 +468,16 @@
}
}
- if (platform->pcm_ops->open) {
- ret = platform->pcm_ops->open(substream);
+ if (platform->driver->ops->open) {
+ ret = platform->driver->ops->open(substream);
if (ret < 0) {
printk(KERN_ERR "asoc: can't open platform %s\n", platform->name);
goto platform_err;
}
}
- if (codec_dai->ops->startup) {
- ret = codec_dai->ops->startup(substream, codec_dai);
+ if (codec_dai->driver->ops->startup) {
+ ret = codec_dai->driver->ops->startup(substream, codec_dai);
if (ret < 0) {
printk(KERN_ERR "asoc: can't open codec %s\n",
codec_dai->name);
@@ -391,10 +485,10 @@
}
}
- if (machine->ops && machine->ops->startup) {
- ret = machine->ops->startup(substream);
+ if (rtd->dai_link->ops && rtd->dai_link->ops->startup) {
+ ret = rtd->dai_link->ops->startup(substream);
if (ret < 0) {
- printk(KERN_ERR "asoc: %s startup failed\n", machine->name);
+ printk(KERN_ERR "asoc: %s startup failed\n", rtd->dai_link->name);
goto machine_err;
}
}
@@ -402,50 +496,50 @@
/* Check that the codec and cpu DAI's are compatible */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
runtime->hw.rate_min =
- max(codec_dai->playback.rate_min,
- cpu_dai->playback.rate_min);
+ max(codec_dai_drv->playback.rate_min,
+ cpu_dai_drv->playback.rate_min);
runtime->hw.rate_max =
- min(codec_dai->playback.rate_max,
- cpu_dai->playback.rate_max);
+ min(codec_dai_drv->playback.rate_max,
+ cpu_dai_drv->playback.rate_max);
runtime->hw.channels_min =
- max(codec_dai->playback.channels_min,
- cpu_dai->playback.channels_min);
+ max(codec_dai_drv->playback.channels_min,
+ cpu_dai_drv->playback.channels_min);
runtime->hw.channels_max =
- min(codec_dai->playback.channels_max,
- cpu_dai->playback.channels_max);
+ min(codec_dai_drv->playback.channels_max,
+ cpu_dai_drv->playback.channels_max);
runtime->hw.formats =
- codec_dai->playback.formats & cpu_dai->playback.formats;
+ codec_dai_drv->playback.formats & cpu_dai_drv->playback.formats;
runtime->hw.rates =
- codec_dai->playback.rates & cpu_dai->playback.rates;
- if (codec_dai->playback.rates
+ codec_dai_drv->playback.rates & cpu_dai_drv->playback.rates;
+ if (codec_dai_drv->playback.rates
& (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
- runtime->hw.rates |= cpu_dai->playback.rates;
- if (cpu_dai->playback.rates
+ runtime->hw.rates |= cpu_dai_drv->playback.rates;
+ if (cpu_dai_drv->playback.rates
& (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
- runtime->hw.rates |= codec_dai->playback.rates;
+ runtime->hw.rates |= codec_dai_drv->playback.rates;
} else {
runtime->hw.rate_min =
- max(codec_dai->capture.rate_min,
- cpu_dai->capture.rate_min);
+ max(codec_dai_drv->capture.rate_min,
+ cpu_dai_drv->capture.rate_min);
runtime->hw.rate_max =
- min(codec_dai->capture.rate_max,
- cpu_dai->capture.rate_max);
+ min(codec_dai_drv->capture.rate_max,
+ cpu_dai_drv->capture.rate_max);
runtime->hw.channels_min =
- max(codec_dai->capture.channels_min,
- cpu_dai->capture.channels_min);
+ max(codec_dai_drv->capture.channels_min,
+ cpu_dai_drv->capture.channels_min);
runtime->hw.channels_max =
- min(codec_dai->capture.channels_max,
- cpu_dai->capture.channels_max);
+ min(codec_dai_drv->capture.channels_max,
+ cpu_dai_drv->capture.channels_max);
runtime->hw.formats =
- codec_dai->capture.formats & cpu_dai->capture.formats;
+ codec_dai_drv->capture.formats & cpu_dai_drv->capture.formats;
runtime->hw.rates =
- codec_dai->capture.rates & cpu_dai->capture.rates;
- if (codec_dai->capture.rates
+ codec_dai_drv->capture.rates & cpu_dai_drv->capture.rates;
+ if (codec_dai_drv->capture.rates
& (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
- runtime->hw.rates |= cpu_dai->capture.rates;
- if (cpu_dai->capture.rates
+ runtime->hw.rates |= cpu_dai_drv->capture.rates;
+ if (cpu_dai_drv->capture.rates
& (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
- runtime->hw.rates |= codec_dai->capture.rates;
+ runtime->hw.rates |= codec_dai_drv->capture.rates;
}
snd_pcm_limit_hw_rates(runtime);
@@ -461,7 +555,7 @@
}
if (!runtime->hw.channels_min || !runtime->hw.channels_max) {
printk(KERN_ERR "asoc: %s <-> %s No matching channels\n",
- codec_dai->name, cpu_dai->name);
+ codec_dai->name, cpu_dai->name);
goto config_err;
}
@@ -472,7 +566,8 @@
goto config_err;
}
- pr_debug("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name);
+ pr_debug("asoc: %s <-> %s info:\n",
+ codec_dai->name, cpu_dai->name);
pr_debug("asoc: rate mask 0x%x\n", runtime->hw.rates);
pr_debug("asoc: min ch %d max ch %d\n", runtime->hw.channels_min,
runtime->hw.channels_max);
@@ -480,33 +575,33 @@
runtime->hw.rate_max);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- cpu_dai->playback.active++;
- codec_dai->playback.active++;
+ cpu_dai->playback_active++;
+ codec_dai->playback_active++;
} else {
- cpu_dai->capture.active++;
- codec_dai->capture.active++;
+ cpu_dai->capture_active++;
+ codec_dai->capture_active++;
}
cpu_dai->active++;
codec_dai->active++;
- card->codec->active++;
+ rtd->codec->active++;
mutex_unlock(&pcm_mutex);
return 0;
config_err:
- if (machine->ops && machine->ops->shutdown)
- machine->ops->shutdown(substream);
+ if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
+ rtd->dai_link->ops->shutdown(substream);
machine_err:
- if (codec_dai->ops->shutdown)
- codec_dai->ops->shutdown(substream, codec_dai);
+ if (codec_dai->driver->ops->shutdown)
+ codec_dai->driver->ops->shutdown(substream, codec_dai);
codec_dai_err:
- if (platform->pcm_ops->close)
- platform->pcm_ops->close(substream);
+ if (platform->driver->ops->close)
+ platform->driver->ops->close(substream);
platform_err:
- if (cpu_dai->ops->shutdown)
- cpu_dai->ops->shutdown(substream, cpu_dai);
+ if (cpu_dai->driver->ops->shutdown)
+ cpu_dai->driver->ops->shutdown(substream, cpu_dai);
out:
mutex_unlock(&pcm_mutex);
return ret;
@@ -519,29 +614,25 @@
*/
static void close_delayed_work(struct work_struct *work)
{
- struct snd_soc_card *card = container_of(work, struct snd_soc_card,
- delayed_work.work);
- struct snd_soc_codec *codec = card->codec;
- struct snd_soc_dai *codec_dai;
- int i;
+ struct snd_soc_pcm_runtime *rtd =
+ container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
mutex_lock(&pcm_mutex);
- for (i = 0; i < codec->num_dai; i++) {
- codec_dai = &codec->dai[i];
- pr_debug("pop wq checking: %s status: %s waiting: %s\n",
- codec_dai->playback.stream_name,
- codec_dai->playback.active ? "active" : "inactive",
- codec_dai->pop_wait ? "yes" : "no");
+ pr_debug("pop wq checking: %s status: %s waiting: %s\n",
+ codec_dai->driver->playback.stream_name,
+ codec_dai->playback_active ? "active" : "inactive",
+ codec_dai->pop_wait ? "yes" : "no");
- /* are we waiting on this codec DAI stream */
- if (codec_dai->pop_wait == 1) {
- codec_dai->pop_wait = 0;
- snd_soc_dapm_stream_event(codec,
- codec_dai->playback.stream_name,
- SND_SOC_DAPM_STREAM_STOP);
- }
+ /* are we waiting on this codec DAI stream */
+ if (codec_dai->pop_wait == 1) {
+ codec_dai->pop_wait = 0;
+ snd_soc_dapm_stream_event(rtd,
+ codec_dai->driver->playback.stream_name,
+ SND_SOC_DAPM_STREAM_STOP);
}
+
mutex_unlock(&pcm_mutex);
}
@@ -553,22 +644,19 @@
static int soc_codec_close(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_dai_link *machine = rtd->dai;
- struct snd_soc_platform *platform = card->platform;
- struct snd_soc_dai *cpu_dai = machine->cpu_dai;
- struct snd_soc_dai *codec_dai = machine->codec_dai;
- struct snd_soc_codec *codec = card->codec;
+ struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_codec *codec = rtd->codec;
mutex_lock(&pcm_mutex);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- cpu_dai->playback.active--;
- codec_dai->playback.active--;
+ cpu_dai->playback_active--;
+ codec_dai->playback_active--;
} else {
- cpu_dai->capture.active--;
- codec_dai->capture.active--;
+ cpu_dai->capture_active--;
+ codec_dai->capture_active--;
}
cpu_dai->active--;
@@ -581,27 +669,28 @@
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
snd_soc_dai_digital_mute(codec_dai, 1);
- if (cpu_dai->ops->shutdown)
- cpu_dai->ops->shutdown(substream, cpu_dai);
+ if (cpu_dai->driver->ops->shutdown)
+ cpu_dai->driver->ops->shutdown(substream, cpu_dai);
- if (codec_dai->ops->shutdown)
- codec_dai->ops->shutdown(substream, codec_dai);
+ if (codec_dai->driver->ops->shutdown)
+ codec_dai->driver->ops->shutdown(substream, codec_dai);
- if (machine->ops && machine->ops->shutdown)
- machine->ops->shutdown(substream);
+ if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
+ rtd->dai_link->ops->shutdown(substream);
- if (platform->pcm_ops->close)
- platform->pcm_ops->close(substream);
+ if (platform->driver->ops->close)
+ platform->driver->ops->close(substream);
+ cpu_dai->runtime = NULL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
/* start delayed pop wq here for playback streams */
codec_dai->pop_wait = 1;
- schedule_delayed_work(&card->delayed_work,
- msecs_to_jiffies(card->pmdown_time));
+ schedule_delayed_work(&rtd->delayed_work,
+ msecs_to_jiffies(rtd->pmdown_time));
} else {
/* capture streams can be powered down now */
- snd_soc_dapm_stream_event(codec,
- codec_dai->capture.stream_name,
+ snd_soc_dapm_stream_event(rtd,
+ codec_dai->driver->capture.stream_name,
SND_SOC_DAPM_STREAM_STOP);
}
@@ -617,43 +706,39 @@
static int soc_pcm_prepare(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_dai_link *machine = rtd->dai;
- struct snd_soc_platform *platform = card->platform;
- struct snd_soc_dai *cpu_dai = machine->cpu_dai;
- struct snd_soc_dai *codec_dai = machine->codec_dai;
- struct snd_soc_codec *codec = card->codec;
+ struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret = 0;
mutex_lock(&pcm_mutex);
- if (machine->ops && machine->ops->prepare) {
- ret = machine->ops->prepare(substream);
+ if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) {
+ ret = rtd->dai_link->ops->prepare(substream);
if (ret < 0) {
printk(KERN_ERR "asoc: machine prepare error\n");
goto out;
}
}
- if (platform->pcm_ops->prepare) {
- ret = platform->pcm_ops->prepare(substream);
+ if (platform->driver->ops->prepare) {
+ ret = platform->driver->ops->prepare(substream);
if (ret < 0) {
printk(KERN_ERR "asoc: platform prepare error\n");
goto out;
}
}
- if (codec_dai->ops->prepare) {
- ret = codec_dai->ops->prepare(substream, codec_dai);
+ if (codec_dai->driver->ops->prepare) {
+ ret = codec_dai->driver->ops->prepare(substream, codec_dai);
if (ret < 0) {
printk(KERN_ERR "asoc: codec DAI prepare error\n");
goto out;
}
}
- if (cpu_dai->ops->prepare) {
- ret = cpu_dai->ops->prepare(substream, cpu_dai);
+ if (cpu_dai->driver->ops->prepare) {
+ ret = cpu_dai->driver->ops->prepare(substream, cpu_dai);
if (ret < 0) {
printk(KERN_ERR "asoc: cpu DAI prepare error\n");
goto out;
@@ -664,16 +749,16 @@
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
codec_dai->pop_wait) {
codec_dai->pop_wait = 0;
- cancel_delayed_work(&card->delayed_work);
+ cancel_delayed_work(&rtd->delayed_work);
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- snd_soc_dapm_stream_event(codec,
- codec_dai->playback.stream_name,
+ snd_soc_dapm_stream_event(rtd,
+ codec_dai->driver->playback.stream_name,
SND_SOC_DAPM_STREAM_START);
else
- snd_soc_dapm_stream_event(codec,
- codec_dai->capture.stream_name,
+ snd_soc_dapm_stream_event(rtd,
+ codec_dai->driver->capture.stream_name,
SND_SOC_DAPM_STREAM_START);
snd_soc_dai_digital_mute(codec_dai, 0);
@@ -692,26 +777,23 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_dai_link *machine = rtd->dai;
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_platform *platform = card->platform;
- struct snd_soc_dai *cpu_dai = machine->cpu_dai;
- struct snd_soc_dai *codec_dai = machine->codec_dai;
+ struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret = 0;
mutex_lock(&pcm_mutex);
- if (machine->ops && machine->ops->hw_params) {
- ret = machine->ops->hw_params(substream, params);
+ if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) {
+ ret = rtd->dai_link->ops->hw_params(substream, params);
if (ret < 0) {
printk(KERN_ERR "asoc: machine hw_params failed\n");
goto out;
}
}
- if (codec_dai->ops->hw_params) {
- ret = codec_dai->ops->hw_params(substream, params, codec_dai);
+ if (codec_dai->driver->ops->hw_params) {
+ ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai);
if (ret < 0) {
printk(KERN_ERR "asoc: can't set codec %s hw params\n",
codec_dai->name);
@@ -719,8 +801,8 @@
}
}
- if (cpu_dai->ops->hw_params) {
- ret = cpu_dai->ops->hw_params(substream, params, cpu_dai);
+ if (cpu_dai->driver->ops->hw_params) {
+ ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai);
if (ret < 0) {
printk(KERN_ERR "asoc: interface %s hw params failed\n",
cpu_dai->name);
@@ -728,8 +810,8 @@
}
}
- if (platform->pcm_ops->hw_params) {
- ret = platform->pcm_ops->hw_params(substream, params);
+ if (platform->driver->ops->hw_params) {
+ ret = platform->driver->ops->hw_params(substream, params);
if (ret < 0) {
printk(KERN_ERR "asoc: platform %s hw params failed\n",
platform->name);
@@ -737,23 +819,23 @@
}
}
- machine->rate = params_rate(params);
+ rtd->rate = params_rate(params);
out:
mutex_unlock(&pcm_mutex);
return ret;
platform_err:
- if (cpu_dai->ops->hw_free)
- cpu_dai->ops->hw_free(substream, cpu_dai);
+ if (cpu_dai->driver->ops->hw_free)
+ cpu_dai->driver->ops->hw_free(substream, cpu_dai);
interface_err:
- if (codec_dai->ops->hw_free)
- codec_dai->ops->hw_free(substream, codec_dai);
+ if (codec_dai->driver->ops->hw_free)
+ codec_dai->driver->ops->hw_free(substream, codec_dai);
codec_err:
- if (machine->ops && machine->ops->hw_free)
- machine->ops->hw_free(substream);
+ if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
+ rtd->dai_link->ops->hw_free(substream);
mutex_unlock(&pcm_mutex);
return ret;
@@ -765,13 +847,10 @@
static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_dai_link *machine = rtd->dai;
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_platform *platform = card->platform;
- struct snd_soc_dai *cpu_dai = machine->cpu_dai;
- struct snd_soc_dai *codec_dai = machine->codec_dai;
- struct snd_soc_codec *codec = card->codec;
+ struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_codec *codec = rtd->codec;
mutex_lock(&pcm_mutex);
@@ -780,19 +859,19 @@
snd_soc_dai_digital_mute(codec_dai, 1);
/* free any machine hw params */
- if (machine->ops && machine->ops->hw_free)
- machine->ops->hw_free(substream);
+ if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
+ rtd->dai_link->ops->hw_free(substream);
/* free any DMA resources */
- if (platform->pcm_ops->hw_free)
- platform->pcm_ops->hw_free(substream);
+ if (platform->driver->ops->hw_free)
+ platform->driver->ops->hw_free(substream);
/* now free hw params for the DAI's */
- if (codec_dai->ops->hw_free)
- codec_dai->ops->hw_free(substream, codec_dai);
+ if (codec_dai->driver->ops->hw_free)
+ codec_dai->driver->ops->hw_free(substream, codec_dai);
- if (cpu_dai->ops->hw_free)
- cpu_dai->ops->hw_free(substream, cpu_dai);
+ if (cpu_dai->driver->ops->hw_free)
+ cpu_dai->driver->ops->hw_free(substream, cpu_dai);
mutex_unlock(&pcm_mutex);
return 0;
@@ -801,28 +880,25 @@
static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_card *card= socdev->card;
- struct snd_soc_dai_link *machine = rtd->dai;
- struct snd_soc_platform *platform = card->platform;
- struct snd_soc_dai *cpu_dai = machine->cpu_dai;
- struct snd_soc_dai *codec_dai = machine->codec_dai;
+ struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
- if (codec_dai->ops->trigger) {
- ret = codec_dai->ops->trigger(substream, cmd, codec_dai);
+ if (codec_dai->driver->ops->trigger) {
+ ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai);
if (ret < 0)
return ret;
}
- if (platform->pcm_ops->trigger) {
- ret = platform->pcm_ops->trigger(substream, cmd);
+ if (platform->driver->ops->trigger) {
+ ret = platform->driver->ops->trigger(substream, cmd);
if (ret < 0)
return ret;
}
- if (cpu_dai->ops->trigger) {
- ret = cpu_dai->ops->trigger(substream, cmd, cpu_dai);
+ if (cpu_dai->driver->ops->trigger) {
+ ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai);
if (ret < 0)
return ret;
}
@@ -837,27 +913,24 @@
static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_platform *platform = card->platform;
- struct snd_soc_dai_link *machine = rtd->dai;
- struct snd_soc_dai *cpu_dai = machine->cpu_dai;
- struct snd_soc_dai *codec_dai = machine->codec_dai;
+ struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t offset = 0;
snd_pcm_sframes_t delay = 0;
- if (platform->pcm_ops->pointer)
- offset = platform->pcm_ops->pointer(substream);
+ if (platform->driver->ops->pointer)
+ offset = platform->driver->ops->pointer(substream);
- if (cpu_dai->ops->delay)
- delay += cpu_dai->ops->delay(substream, cpu_dai);
+ if (cpu_dai->driver->ops->delay)
+ delay += cpu_dai->driver->ops->delay(substream, cpu_dai);
- if (codec_dai->ops->delay)
- delay += codec_dai->ops->delay(substream, codec_dai);
+ if (codec_dai->driver->ops->delay)
+ delay += codec_dai->driver->ops->delay(substream, codec_dai);
- if (platform->delay)
- delay += platform->delay(substream, codec_dai);
+ if (platform->driver->delay)
+ delay += platform->driver->delay(substream, codec_dai);
runtime->delay = delay;
@@ -880,104 +953,111 @@
static int soc_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_platform *platform = card->platform;
- struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
- struct snd_soc_codec *codec = card->codec;
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
int i;
/* If the initialization of this soc device failed, there is no codec
* associated with it. Just bail out in this case.
*/
- if (!codec)
+ if (list_empty(&card->codec_dev_list))
return 0;
/* Due to the resume being scheduled into a workqueue we could
* suspend before that's finished - wait for it to complete.
*/
- snd_power_lock(codec->card);
- snd_power_wait(codec->card, SNDRV_CTL_POWER_D0);
- snd_power_unlock(codec->card);
+ snd_power_lock(card->snd_card);
+ snd_power_wait(card->snd_card, SNDRV_CTL_POWER_D0);
+ snd_power_unlock(card->snd_card);
/* we're going to block userspace touching us until resume completes */
- snd_power_change_state(codec->card, SNDRV_CTL_POWER_D3hot);
+ snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot);
/* mute any active DAC's */
- for (i = 0; i < card->num_links; i++) {
- struct snd_soc_dai *dai = card->dai_link[i].codec_dai;
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_dai *dai = card->rtd[i].codec_dai;
+ struct snd_soc_dai_driver *drv = dai->driver;
- if (card->dai_link[i].ignore_suspend)
+ if (card->rtd[i].dai_link->ignore_suspend)
continue;
- if (dai->ops->digital_mute && dai->playback.active)
- dai->ops->digital_mute(dai, 1);
+ if (drv->ops->digital_mute && dai->playback_active)
+ drv->ops->digital_mute(dai, 1);
}
/* suspend all pcms */
- for (i = 0; i < card->num_links; i++) {
- if (card->dai_link[i].ignore_suspend)
+ for (i = 0; i < card->num_rtd; i++) {
+ if (card->rtd[i].dai_link->ignore_suspend)
continue;
- snd_pcm_suspend_all(card->dai_link[i].pcm);
+ snd_pcm_suspend_all(card->rtd[i].pcm);
}
if (card->suspend_pre)
card->suspend_pre(pdev, PMSG_SUSPEND);
- for (i = 0; i < card->num_links; i++) {
- struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+ struct snd_soc_platform *platform = card->rtd[i].platform;
- if (card->dai_link[i].ignore_suspend)
+ if (card->rtd[i].dai_link->ignore_suspend)
continue;
- if (cpu_dai->suspend && !cpu_dai->ac97_control)
- cpu_dai->suspend(cpu_dai);
- if (platform->suspend)
- platform->suspend(&card->dai_link[i]);
- }
-
- /* close any waiting streams and save state */
- run_delayed_work(&card->delayed_work);
- codec->suspend_bias_level = codec->bias_level;
-
- for (i = 0; i < codec->num_dai; i++) {
- char *stream = codec->dai[i].playback.stream_name;
-
- if (card->dai_link[i].ignore_suspend)
- continue;
-
- if (stream != NULL)
- snd_soc_dapm_stream_event(codec, stream,
- SND_SOC_DAPM_STREAM_SUSPEND);
- stream = codec->dai[i].capture.stream_name;
- if (stream != NULL)
- snd_soc_dapm_stream_event(codec, stream,
- SND_SOC_DAPM_STREAM_SUSPEND);
- }
-
- /* If there are paths active then the CODEC will be held with
- * bias _ON and should not be suspended. */
- if (codec_dev->suspend) {
- switch (codec->bias_level) {
- case SND_SOC_BIAS_STANDBY:
- case SND_SOC_BIAS_OFF:
- codec_dev->suspend(pdev, PMSG_SUSPEND);
- break;
- default:
- dev_dbg(socdev->dev, "CODEC is on over suspend\n");
- break;
+ if (cpu_dai->driver->suspend && !cpu_dai->driver->ac97_control)
+ cpu_dai->driver->suspend(cpu_dai);
+ if (platform->driver->suspend && !platform->suspended) {
+ platform->driver->suspend(cpu_dai);
+ platform->suspended = 1;
}
}
- for (i = 0; i < card->num_links; i++) {
- struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
+ /* close any waiting streams and save state */
+ for (i = 0; i < card->num_rtd; i++) {
+ run_delayed_work(&card->rtd[i].delayed_work);
+ card->rtd[i].codec->suspend_bias_level = card->rtd[i].codec->bias_level;
+ }
- if (card->dai_link[i].ignore_suspend)
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver;
+
+ if (card->rtd[i].dai_link->ignore_suspend)
continue;
- if (cpu_dai->suspend && cpu_dai->ac97_control)
- cpu_dai->suspend(cpu_dai);
+ if (driver->playback.stream_name != NULL)
+ snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name,
+ SND_SOC_DAPM_STREAM_SUSPEND);
+
+ if (driver->capture.stream_name != NULL)
+ snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name,
+ SND_SOC_DAPM_STREAM_SUSPEND);
+ }
+
+ /* suspend all CODECs */
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_codec *codec = card->rtd[i].codec;
+ /* If there are paths active then the CODEC will be held with
+ * bias _ON and should not be suspended. */
+ if (!codec->suspended && codec->driver->suspend) {
+ switch (codec->bias_level) {
+ case SND_SOC_BIAS_STANDBY:
+ case SND_SOC_BIAS_OFF:
+ codec->driver->suspend(codec, PMSG_SUSPEND);
+ codec->suspended = 1;
+ break;
+ default:
+ dev_dbg(codec->dev, "CODEC is on over suspend\n");
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+
+ if (card->rtd[i].dai_link->ignore_suspend)
+ continue;
+
+ if (cpu_dai->driver->suspend && cpu_dai->driver->ac97_control)
+ cpu_dai->driver->suspend(cpu_dai);
}
if (card->suspend_post)
@@ -991,127 +1071,127 @@
*/
static void soc_resume_deferred(struct work_struct *work)
{
- struct snd_soc_card *card = container_of(work,
- struct snd_soc_card,
- deferred_resume_work);
- struct snd_soc_device *socdev = card->socdev;
- struct snd_soc_platform *platform = card->platform;
- struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
- struct snd_soc_codec *codec = card->codec;
- struct platform_device *pdev = to_platform_device(socdev->dev);
+ struct snd_soc_card *card =
+ container_of(work, struct snd_soc_card, deferred_resume_work);
+ struct platform_device *pdev = to_platform_device(card->dev);
int i;
/* our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
* so userspace apps are blocked from touching us
*/
- dev_dbg(socdev->dev, "starting resume work\n");
+ dev_dbg(card->dev, "starting resume work\n");
/* Bring us up into D2 so that DAPM starts enabling things */
- snd_power_change_state(codec->card, SNDRV_CTL_POWER_D2);
+ snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D2);
if (card->resume_pre)
card->resume_pre(pdev);
- for (i = 0; i < card->num_links; i++) {
- struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
+ /* resume AC97 DAIs */
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
- if (card->dai_link[i].ignore_suspend)
+ if (card->rtd[i].dai_link->ignore_suspend)
continue;
- if (cpu_dai->resume && cpu_dai->ac97_control)
- cpu_dai->resume(cpu_dai);
+ if (cpu_dai->driver->resume && cpu_dai->driver->ac97_control)
+ cpu_dai->driver->resume(cpu_dai);
}
- /* If the CODEC was idle over suspend then it will have been
- * left with bias OFF or STANDBY and suspended so we must now
- * resume. Otherwise the suspend was suppressed.
- */
- if (codec_dev->resume) {
- switch (codec->bias_level) {
- case SND_SOC_BIAS_STANDBY:
- case SND_SOC_BIAS_OFF:
- codec_dev->resume(pdev);
- break;
- default:
- dev_dbg(socdev->dev, "CODEC was on over suspend\n");
- break;
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_codec *codec = card->rtd[i].codec;
+ /* If the CODEC was idle over suspend then it will have been
+ * left with bias OFF or STANDBY and suspended so we must now
+ * resume. Otherwise the suspend was suppressed.
+ */
+ if (codec->driver->resume && codec->suspended) {
+ switch (codec->bias_level) {
+ case SND_SOC_BIAS_STANDBY:
+ case SND_SOC_BIAS_OFF:
+ codec->driver->resume(codec);
+ codec->suspended = 0;
+ break;
+ default:
+ dev_dbg(codec->dev, "CODEC was on over suspend\n");
+ break;
+ }
}
}
- for (i = 0; i < codec->num_dai; i++) {
- char *stream = codec->dai[i].playback.stream_name;
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver;
- if (card->dai_link[i].ignore_suspend)
+ if (card->rtd[i].dai_link->ignore_suspend)
continue;
- if (stream != NULL)
- snd_soc_dapm_stream_event(codec, stream,
+ if (driver->playback.stream_name != NULL)
+ snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name,
SND_SOC_DAPM_STREAM_RESUME);
- stream = codec->dai[i].capture.stream_name;
- if (stream != NULL)
- snd_soc_dapm_stream_event(codec, stream,
+
+ if (driver->capture.stream_name != NULL)
+ snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name,
SND_SOC_DAPM_STREAM_RESUME);
}
/* unmute any active DACs */
- for (i = 0; i < card->num_links; i++) {
- struct snd_soc_dai *dai = card->dai_link[i].codec_dai;
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_dai *dai = card->rtd[i].codec_dai;
+ struct snd_soc_dai_driver *drv = dai->driver;
- if (card->dai_link[i].ignore_suspend)
+ if (card->rtd[i].dai_link->ignore_suspend)
continue;
- if (dai->ops->digital_mute && dai->playback.active)
- dai->ops->digital_mute(dai, 0);
+ if (drv->ops->digital_mute && dai->playback_active)
+ drv->ops->digital_mute(dai, 0);
}
- for (i = 0; i < card->num_links; i++) {
- struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+ struct snd_soc_platform *platform = card->rtd[i].platform;
- if (card->dai_link[i].ignore_suspend)
+ if (card->rtd[i].dai_link->ignore_suspend)
continue;
- if (cpu_dai->resume && !cpu_dai->ac97_control)
- cpu_dai->resume(cpu_dai);
- if (platform->resume)
- platform->resume(&card->dai_link[i]);
+ if (cpu_dai->driver->resume && !cpu_dai->driver->ac97_control)
+ cpu_dai->driver->resume(cpu_dai);
+ if (platform->driver->resume && platform->suspended) {
+ platform->driver->resume(cpu_dai);
+ platform->suspended = 0;
+ }
}
if (card->resume_post)
card->resume_post(pdev);
- dev_dbg(socdev->dev, "resume work completed\n");
+ dev_dbg(card->dev, "resume work completed\n");
/* userspace can access us now we are back as we were before */
- snd_power_change_state(codec->card, SNDRV_CTL_POWER_D0);
+ snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0);
}
/* powers up audio subsystem after a suspend */
static int soc_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_dai *cpu_dai = card->dai_link[0].cpu_dai;
-
- /* If the initialization of this soc device failed, there is no codec
- * associated with it. Just bail out in this case.
- */
- if (!card->codec)
- return 0;
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ int i;
/* AC97 devices might have other drivers hanging off them so
* need to resume immediately. Other drivers don't have that
* problem and may take a substantial amount of time to resume
* due to I/O costs and anti-pop so handle them out of line.
*/
- if (cpu_dai->ac97_control) {
- dev_dbg(socdev->dev, "Resuming AC97 immediately\n");
- soc_resume_deferred(&card->deferred_resume_work);
- } else {
- dev_dbg(socdev->dev, "Scheduling resume work\n");
- if (!schedule_work(&card->deferred_resume_work))
- dev_err(socdev->dev, "resume work item may be lost\n");
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+ if (cpu_dai->driver->ac97_control) {
+ dev_dbg(dev, "Resuming AC97 immediately\n");
+ soc_resume_deferred(&card->deferred_resume_work);
+ } else {
+ dev_dbg(dev, "Scheduling resume work\n");
+ if (!schedule_work(&card->deferred_resume_work))
+ dev_err(dev, "resume work item may be lost\n");
+ }
}
return 0;
@@ -1124,198 +1204,440 @@
static struct snd_soc_dai_ops null_dai_ops = {
};
-static void snd_soc_instantiate_card(struct snd_soc_card *card)
+static int soc_bind_dai_link(struct snd_soc_card *card, int num)
{
- struct platform_device *pdev = container_of(card->dev,
- struct platform_device,
- dev);
- struct snd_soc_codec_device *codec_dev = card->socdev->codec_dev;
+ struct snd_soc_dai_link *dai_link = &card->dai_link[num];
+ struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
struct snd_soc_codec *codec;
struct snd_soc_platform *platform;
- struct snd_soc_dai *dai;
- int i, found, ret, ac97;
+ struct snd_soc_dai *codec_dai, *cpu_dai;
- if (card->instantiated)
- return;
+ if (rtd->complete)
+ return 1;
+ dev_dbg(card->dev, "binding %s at idx %d\n", dai_link->name, num);
- found = 0;
- list_for_each_entry(platform, &platform_list, list)
- if (card->platform == platform) {
- found = 1;
- break;
+ /* do we already have the CPU DAI for this link ? */
+ if (rtd->cpu_dai) {
+ goto find_codec;
+ }
+ /* no, then find CPU DAI from registered DAIs*/
+ list_for_each_entry(cpu_dai, &dai_list, list) {
+ if (!strcmp(cpu_dai->name, dai_link->cpu_dai_name)) {
+
+ if (!try_module_get(cpu_dai->dev->driver->owner))
+ return -ENODEV;
+
+ rtd->cpu_dai = cpu_dai;
+ goto find_codec;
}
- if (!found) {
- dev_dbg(card->dev, "Platform %s not registered\n",
- card->platform->name);
- return;
+ }
+ dev_dbg(card->dev, "CPU DAI %s not registered\n",
+ dai_link->cpu_dai_name);
+
+find_codec:
+ /* do we already have the CODEC for this link ? */
+ if (rtd->codec) {
+ goto find_platform;
}
- ac97 = 0;
- for (i = 0; i < card->num_links; i++) {
- found = 0;
- list_for_each_entry(dai, &dai_list, list)
- if (card->dai_link[i].cpu_dai == dai) {
- found = 1;
- break;
- }
- if (!found) {
- dev_dbg(card->dev, "DAI %s not registered\n",
- card->dai_link[i].cpu_dai->name);
- return;
- }
+ /* no, then find CODEC from registered CODECs*/
+ list_for_each_entry(codec, &codec_list, list) {
+ if (!strcmp(codec->name, dai_link->codec_name)) {
+ rtd->codec = codec;
- if (card->dai_link[i].cpu_dai->ac97_control)
- ac97 = 1;
- }
+ if (!try_module_get(codec->dev->driver->owner))
+ return -ENODEV;
- for (i = 0; i < card->num_links; i++) {
- if (!card->dai_link[i].codec_dai->ops)
- card->dai_link[i].codec_dai->ops = &null_dai_ops;
- }
-
- /* If we have AC97 in the system then don't wait for the
- * codec. This will need revisiting if we have to handle
- * systems with mixed AC97 and non-AC97 parts. Only check for
- * DAIs currently; we can't do this per link since some AC97
- * codecs have non-AC97 DAIs.
- */
- if (!ac97)
- for (i = 0; i < card->num_links; i++) {
- found = 0;
- list_for_each_entry(dai, &dai_list, list)
- if (card->dai_link[i].codec_dai == dai) {
- found = 1;
- break;
+ /* CODEC found, so find CODEC DAI from registered DAIs from this CODEC*/
+ list_for_each_entry(codec_dai, &dai_list, list) {
+ if (codec->dev == codec_dai->dev &&
+ !strcmp(codec_dai->name, dai_link->codec_dai_name)) {
+ rtd->codec_dai = codec_dai;
+ goto find_platform;
}
- if (!found) {
- dev_dbg(card->dev, "DAI %s not registered\n",
- card->dai_link[i].codec_dai->name);
- return;
+ }
+ dev_dbg(card->dev, "CODEC DAI %s not registered\n",
+ dai_link->codec_dai_name);
+
+ goto find_platform;
+ }
+ }
+ dev_dbg(card->dev, "CODEC %s not registered\n",
+ dai_link->codec_name);
+
+find_platform:
+ /* do we already have the CODEC DAI for this link ? */
+ if (rtd->platform) {
+ goto out;
+ }
+ /* no, then find CPU DAI from registered DAIs*/
+ list_for_each_entry(platform, &platform_list, list) {
+ if (!strcmp(platform->name, dai_link->platform_name)) {
+
+ if (!try_module_get(platform->dev->driver->owner))
+ return -ENODEV;
+
+ rtd->platform = platform;
+ goto out;
+ }
+ }
+
+ dev_dbg(card->dev, "platform %s not registered\n",
+ dai_link->platform_name);
+ return 0;
+
+out:
+ /* mark rtd as complete if we found all 4 of our client devices */
+ if (rtd->codec && rtd->codec_dai && rtd->platform && rtd->cpu_dai) {
+ rtd->complete = 1;
+ card->num_rtd++;
+ }
+ return 1;
+}
+
+static void soc_remove_dai_link(struct snd_soc_card *card, int num)
+{
+ struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai;
+ int err;
+
+ /* unregister the rtd device */
+ if (rtd->dev_registered) {
+ device_remove_file(&rtd->dev, &dev_attr_pmdown_time);
+ device_unregister(&rtd->dev);
+ rtd->dev_registered = 0;
+ }
+
+ /* remove the CODEC DAI */
+ if (codec_dai && codec_dai->probed) {
+ if (codec_dai->driver->remove) {
+ err = codec_dai->driver->remove(codec_dai);
+ if (err < 0)
+ printk(KERN_ERR "asoc: failed to remove %s\n", codec_dai->name);
+ }
+ codec_dai->probed = 0;
+ list_del(&codec_dai->card_list);
+ }
+
+ /* remove the platform */
+ if (platform && platform->probed) {
+ if (platform->driver->remove) {
+ err = platform->driver->remove(platform);
+ if (err < 0)
+ printk(KERN_ERR "asoc: failed to remove %s\n", platform->name);
+ }
+ platform->probed = 0;
+ list_del(&platform->card_list);
+ module_put(platform->dev->driver->owner);
+ }
+
+ /* remove the CODEC */
+ if (codec && codec->probed) {
+ if (codec->driver->remove) {
+ err = codec->driver->remove(codec);
+ if (err < 0)
+ printk(KERN_ERR "asoc: failed to remove %s\n", codec->name);
+ }
+
+ /* Make sure all DAPM widgets are freed */
+ snd_soc_dapm_free(codec);
+
+ soc_cleanup_codec_debugfs(codec);
+ device_remove_file(&rtd->dev, &dev_attr_codec_reg);
+ codec->probed = 0;
+ list_del(&codec->card_list);
+ module_put(codec->dev->driver->owner);
+ }
+
+ /* remove the cpu_dai */
+ if (cpu_dai && cpu_dai->probed) {
+ if (cpu_dai->driver->remove) {
+ err = cpu_dai->driver->remove(cpu_dai);
+ if (err < 0)
+ printk(KERN_ERR "asoc: failed to remove %s\n", cpu_dai->name);
+ }
+ cpu_dai->probed = 0;
+ list_del(&cpu_dai->card_list);
+ module_put(cpu_dai->dev->driver->owner);
+ }
+}
+
+static void rtd_release(struct device *dev) {}
+
+static int soc_probe_dai_link(struct snd_soc_card *card, int num)
+{
+ struct snd_soc_dai_link *dai_link = &card->dai_link[num];
+ struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai;
+ int ret;
+
+ dev_dbg(card->dev, "probe %s dai link %d\n", card->name, num);
+
+ /* config components */
+ codec_dai->codec = codec;
+ codec->card = card;
+ cpu_dai->platform = platform;
+ rtd->card = card;
+ rtd->dev.parent = card->dev;
+ codec_dai->card = card;
+ cpu_dai->card = card;
+
+ /* set default power off timeout */
+ rtd->pmdown_time = pmdown_time;
+
+ /* probe the cpu_dai */
+ if (!cpu_dai->probed) {
+ if (cpu_dai->driver->probe) {
+ ret = cpu_dai->driver->probe(cpu_dai);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: failed to probe CPU DAI %s\n",
+ cpu_dai->name);
+ return ret;
+ }
+ }
+ cpu_dai->probed = 1;
+ /* mark cpu_dai as probed and add to card cpu_dai list */
+ list_add(&cpu_dai->card_list, &card->dai_dev_list);
+ }
+
+ /* probe the CODEC */
+ if (!codec->probed) {
+ if (codec->driver->probe) {
+ ret = codec->driver->probe(codec);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: failed to probe CODEC %s\n",
+ codec->name);
+ return ret;
}
}
- /* Note that we do not current check for codec components */
+ soc_init_codec_debugfs(codec);
- dev_dbg(card->dev, "All components present, instantiating\n");
-
- /* Found everything, bring it up */
- card->pmdown_time = pmdown_time;
-
- if (card->probe) {
- ret = card->probe(pdev);
- if (ret < 0)
- return;
+ /* mark codec as probed and add to card codec list */
+ codec->probed = 1;
+ list_add(&codec->card_list, &card->codec_dev_list);
}
- for (i = 0; i < card->num_links; i++) {
- struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
- if (cpu_dai->probe) {
- ret = cpu_dai->probe(pdev, cpu_dai);
- if (ret < 0)
- goto cpu_dai_err;
+ /* probe the platform */
+ if (!platform->probed) {
+ if (platform->driver->probe) {
+ ret = platform->driver->probe(platform);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: failed to probe platform %s\n",
+ platform->name);
+ return ret;
+ }
+ }
+ /* mark platform as probed and add to card platform list */
+ platform->probed = 1;
+ list_add(&platform->card_list, &card->platform_dev_list);
+ }
+
+ /* probe the CODEC DAI */
+ if (!codec_dai->probed) {
+ if (codec_dai->driver->probe) {
+ ret = codec_dai->driver->probe(codec_dai);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: failed to probe CODEC DAI %s\n",
+ codec_dai->name);
+ return ret;
+ }
+ }
+
+ /* mark cpu_dai as probed and add to card cpu_dai list */
+ codec_dai->probed = 1;
+ list_add(&codec_dai->card_list, &card->dai_dev_list);
+ }
+
+ /* DAPM dai link stream work */
+ INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
+
+ /* now that all clients have probed, initialise the DAI link */
+ if (dai_link->init) {
+ ret = dai_link->init(rtd);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: failed to init %s\n", dai_link->stream_name);
+ return ret;
}
}
- if (codec_dev->probe) {
- ret = codec_dev->probe(pdev);
- if (ret < 0)
- goto cpu_dai_err;
- }
- codec = card->codec;
+ /* Make sure all DAPM widgets are instantiated */
+ snd_soc_dapm_new_widgets(codec);
+ snd_soc_dapm_sync(codec);
- if (platform->probe) {
- ret = platform->probe(pdev);
- if (ret < 0)
- goto platform_err;
+ /* register the rtd device */
+ rtd->dev.release = rtd_release;
+ rtd->dev.init_name = dai_link->name;
+ ret = device_register(&rtd->dev);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: failed to register DAI runtime device %d\n", ret);
+ return ret;
}
- /* DAPM stream work */
- INIT_DELAYED_WORK(&card->delayed_work, close_delayed_work);
+ rtd->dev_registered = 1;
+ ret = device_create_file(&rtd->dev, &dev_attr_pmdown_time);
+ if (ret < 0)
+ printk(KERN_WARNING "asoc: failed to add pmdown_time sysfs\n");
+
+ /* add DAPM sysfs entries for this codec */
+ ret = snd_soc_dapm_sys_add(&rtd->dev);
+ if (ret < 0)
+ printk(KERN_WARNING "asoc: failed to add codec dapm sysfs entries\n");
+
+ /* add codec sysfs entries */
+ ret = device_create_file(&rtd->dev, &dev_attr_codec_reg);
+ if (ret < 0)
+ printk(KERN_WARNING "asoc: failed to add codec sysfs files\n");
+
+ /* create the pcm */
+ ret = soc_new_pcm(rtd, num);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: can't create pcm %s\n", dai_link->stream_name);
+ return ret;
+ }
+
+ /* add platform data for AC97 devices */
+ if (rtd->codec_dai->driver->ac97_control)
+ snd_ac97_dev_add_pdata(codec->ac97, rtd->cpu_dai->ac97_pdata);
+
+ return 0;
+}
+
+#ifdef CONFIG_SND_SOC_AC97_BUS
+static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret;
+
+ /* Only instantiate AC97 if not already done by the adaptor
+ * for the generic AC97 subsystem.
+ */
+ if (rtd->codec_dai->driver->ac97_control && !rtd->codec->ac97_registered) {
+ /*
+ * It is possible that the AC97 device is already registered to
+ * the device subsystem. This happens when the device is created
+ * via snd_ac97_mixer(). Currently only SoC codec that does so
+ * is the generic AC97 glue but others migh emerge.
+ *
+ * In those cases we don't try to register the device again.
+ */
+ if (!rtd->codec->ac97_created)
+ return 0;
+
+ ret = soc_ac97_dev_register(rtd->codec);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: AC97 device register failed\n");
+ return ret;
+ }
+
+ rtd->codec->ac97_registered = 1;
+ }
+ return 0;
+}
+
+static void soc_unregister_ac97_dai_link(struct snd_soc_codec *codec)
+{
+ if (codec->ac97_registered) {
+ soc_ac97_dev_unregister(codec);
+ codec->ac97_registered = 0;
+ }
+}
+#endif
+
+static void snd_soc_instantiate_card(struct snd_soc_card *card)
+{
+ struct platform_device *pdev = to_platform_device(card->dev);
+ int ret, i;
+
+ mutex_lock(&card->mutex);
+
+ if (card->instantiated) {
+ mutex_unlock(&card->mutex);
+ return;
+ }
+
+ /* bind DAIs */
+ for (i = 0; i < card->num_links; i++)
+ soc_bind_dai_link(card, i);
+
+ /* bind completed ? */
+ if (card->num_rtd != card->num_links) {
+ mutex_unlock(&card->mutex);
+ return;
+ }
+
+ /* card bind complete so register a sound card */
+ ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ card->owner, 0, &card->snd_card);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: can't create sound card for card %s\n",
+ card->name);
+ mutex_unlock(&card->mutex);
+ return;
+ }
+ card->snd_card->dev = card->dev;
+
#ifdef CONFIG_PM
/* deferred resume work */
INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
#endif
+ /* initialise the sound card only once */
+ if (card->probe) {
+ ret = card->probe(pdev);
+ if (ret < 0)
+ goto card_probe_error;
+ }
+
for (i = 0; i < card->num_links; i++) {
- if (card->dai_link[i].init) {
- ret = card->dai_link[i].init(codec);
+ ret = soc_probe_dai_link(card, i);
+ if (ret < 0) {
+ pr_err("asoc: failed to instantiate card %s: %d\n",
+ card->name, ret);
+ goto probe_dai_err;
+ }
+ }
+
+ snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
+ "%s", card->name);
+ snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
+ "%s", card->name);
+
+ ret = snd_card_register(card->snd_card);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: failed to register soundcard for %s\n", card->name);
+ goto probe_dai_err;
+ }
+
+#ifdef CONFIG_SND_SOC_AC97_BUS
+ /* register any AC97 codecs */
+ for (i = 0; i < card->num_rtd; i++) {
+ ret = soc_register_ac97_dai_link(&card->rtd[i]);
if (ret < 0) {
- printk(KERN_ERR "asoc: failed to init %s\n",
- card->dai_link[i].stream_name);
- continue;
+ printk(KERN_ERR "asoc: failed to register AC97 %s\n", card->name);
+ goto probe_dai_err;
}
}
- if (card->dai_link[i].codec_dai->ac97_control)
- ac97 = 1;
- }
-
- snprintf(codec->card->shortname, sizeof(codec->card->shortname),
- "%s", card->name);
- snprintf(codec->card->longname, sizeof(codec->card->longname),
- "%s (%s)", card->name, codec->name);
-
- /* Make sure all DAPM widgets are instantiated */
- snd_soc_dapm_new_widgets(codec);
-
- ret = snd_card_register(codec->card);
- if (ret < 0) {
- printk(KERN_ERR "asoc: failed to register soundcard for %s\n",
- codec->name);
- goto card_err;
- }
-
- mutex_lock(&codec->mutex);
-#ifdef CONFIG_SND_SOC_AC97_BUS
- /* Only instantiate AC97 if not already done by the adaptor
- * for the generic AC97 subsystem.
- */
- if (ac97 && strcmp(codec->name, "AC97") != 0) {
- ret = soc_ac97_dev_register(codec);
- if (ret < 0) {
- printk(KERN_ERR "asoc: AC97 device register failed\n");
- snd_card_free(codec->card);
- mutex_unlock(&codec->mutex);
- goto card_err;
- }
- }
#endif
- ret = snd_soc_dapm_sys_add(card->socdev->dev);
- if (ret < 0)
- printk(KERN_WARNING "asoc: failed to add dapm sysfs entries\n");
-
- ret = device_create_file(card->socdev->dev, &dev_attr_pmdown_time);
- if (ret < 0)
- printk(KERN_WARNING "asoc: failed to add pmdown_time sysfs\n");
-
- ret = device_create_file(card->socdev->dev, &dev_attr_codec_reg);
- if (ret < 0)
- printk(KERN_WARNING "asoc: failed to add codec sysfs files\n");
-
- soc_init_codec_debugfs(codec);
- mutex_unlock(&codec->mutex);
-
card->instantiated = 1;
-
+ mutex_unlock(&card->mutex);
return;
-card_err:
- if (platform->remove)
- platform->remove(pdev);
+probe_dai_err:
+ for (i = 0; i < card->num_links; i++)
+ soc_remove_dai_link(card, i);
-platform_err:
- if (codec_dev->remove)
- codec_dev->remove(pdev);
-
-cpu_dai_err:
- for (i--; i >= 0; i--) {
- struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
- if (cpu_dai->remove)
- cpu_dai->remove(pdev, cpu_dai);
- }
-
+card_probe_error:
if (card->remove)
card->remove(pdev);
+
+ snd_card_free(card->snd_card);
+
+ mutex_unlock(&card->mutex);
}
/*
@@ -1332,15 +1654,15 @@
/* probes a new socdev */
static int soc_probe(struct platform_device *pdev)
{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
int ret = 0;
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_card *card = socdev->card;
-
- /* Bodge while we push things out of socdev */
- card->socdev = socdev;
/* Bodge while we unpick instantiation */
card->dev = &pdev->dev;
+ INIT_LIST_HEAD(&card->dai_dev_list);
+ INIT_LIST_HEAD(&card->codec_dev_list);
+ INIT_LIST_HEAD(&card->platform_dev_list);
+
ret = snd_soc_register_card(card);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to register card\n");
@@ -1353,50 +1675,49 @@
/* removes a socdev */
static int soc_remove(struct platform_device *pdev)
{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
int i;
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_platform *platform = card->platform;
- struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
- if (card->instantiated) {
- run_delayed_work(&card->delayed_work);
+ if (card->instantiated) {
- if (platform->remove)
- platform->remove(pdev);
-
- if (codec_dev->remove)
- codec_dev->remove(pdev);
-
- for (i = 0; i < card->num_links; i++) {
- struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
- if (cpu_dai->remove)
- cpu_dai->remove(pdev, cpu_dai);
+ /* make sure any delayed work runs */
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+ run_delayed_work(&rtd->delayed_work);
}
+ /* remove and free each DAI */
+ for (i = 0; i < card->num_rtd; i++)
+ soc_remove_dai_link(card, i);
+
+ /* remove the card */
if (card->remove)
card->remove(pdev);
+
+ kfree(card->rtd);
+ snd_card_free(card->snd_card);
}
-
snd_soc_unregister_card(card);
-
return 0;
}
static int soc_poweroff(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_card *card = socdev->card;
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ int i;
if (!card->instantiated)
return 0;
/* Flush out pmdown_time work - we actually do want to run it
* now, we're shutting down so no imminent restart. */
- run_delayed_work(&card->delayed_work);
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+ run_delayed_work(&rtd->delayed_work);
+ }
- snd_soc_dapm_shutdown(socdev);
+ snd_soc_dapm_shutdown(card);
return 0;
}
@@ -1419,53 +1740,42 @@
};
/* create a new pcm */
-static int soc_new_pcm(struct snd_soc_device *socdev,
- struct snd_soc_dai_link *dai_link, int num)
+static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
{
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_codec *codec = card->codec;
- struct snd_soc_platform *platform = card->platform;
- struct snd_soc_dai *codec_dai = dai_link->codec_dai;
- struct snd_soc_dai *cpu_dai = dai_link->cpu_dai;
- struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_pcm *pcm;
char new_name[64];
int ret = 0, playback = 0, capture = 0;
- rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL);
- if (rtd == NULL)
- return -ENOMEM;
-
- rtd->dai = dai_link;
- rtd->socdev = socdev;
- codec_dai->codec = card->codec;
-
/* check client and interface hw capabilities */
snprintf(new_name, sizeof(new_name), "%s %s-%d",
- dai_link->stream_name, codec_dai->name, num);
+ rtd->dai_link->stream_name, codec_dai->name, num);
- if (codec_dai->playback.channels_min)
+ if (codec_dai->driver->playback.channels_min)
playback = 1;
- if (codec_dai->capture.channels_min)
+ if (codec_dai->driver->capture.channels_min)
capture = 1;
- ret = snd_pcm_new(codec->card, new_name, codec->pcm_devs++, playback,
- capture, &pcm);
+ dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num,new_name);
+ ret = snd_pcm_new(rtd->card->snd_card, new_name,
+ num, playback, capture, &pcm);
if (ret < 0) {
- printk(KERN_ERR "asoc: can't create pcm for codec %s\n",
- codec->name);
- kfree(rtd);
+ printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name);
return ret;
}
- dai_link->pcm = pcm;
+ rtd->pcm = pcm;
pcm->private_data = rtd;
- soc_pcm_ops.mmap = platform->pcm_ops->mmap;
- soc_pcm_ops.ioctl = platform->pcm_ops->ioctl;
- soc_pcm_ops.copy = platform->pcm_ops->copy;
- soc_pcm_ops.silence = platform->pcm_ops->silence;
- soc_pcm_ops.ack = platform->pcm_ops->ack;
- soc_pcm_ops.page = platform->pcm_ops->page;
+ soc_pcm_ops.mmap = platform->driver->ops->mmap;
+ soc_pcm_ops.pointer = platform->driver->ops->pointer;
+ soc_pcm_ops.ioctl = platform->driver->ops->ioctl;
+ soc_pcm_ops.copy = platform->driver->ops->copy;
+ soc_pcm_ops.silence = platform->driver->ops->silence;
+ soc_pcm_ops.ack = platform->driver->ops->ack;
+ soc_pcm_ops.page = platform->driver->ops->page;
if (playback)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops);
@@ -1473,14 +1783,13 @@
if (capture)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops);
- ret = platform->pcm_new(codec->card, codec_dai, pcm);
+ ret = platform->driver->pcm_new(rtd->card->snd_card, codec_dai, pcm);
if (ret < 0) {
printk(KERN_ERR "asoc: platform pcm constructor failed\n");
- kfree(rtd);
return ret;
}
- pcm->private_free = platform->pcm_free;
+ pcm->private_free = platform->driver->pcm_free;
printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name,
cpu_dai->name);
return ret;
@@ -1496,8 +1805,8 @@
*/
int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg)
{
- if (codec->volatile_register)
- return codec->volatile_register(reg);
+ if (codec->driver->volatile_register)
+ return codec->driver->volatile_register(reg);
else
return 0;
}
@@ -1532,7 +1841,13 @@
codec->ac97->bus->ops = ops;
codec->ac97->num = num;
- codec->dev = &codec->ac97->dev;
+
+ /*
+ * Mark the AC97 device to be created by us. This way we ensure that the
+ * device will be registered with the device subsystem later on.
+ */
+ codec->ac97_created = 1;
+
mutex_unlock(&codec->mutex);
return 0;
}
@@ -1547,9 +1862,13 @@
void snd_soc_free_ac97_codec(struct snd_soc_codec *codec)
{
mutex_lock(&codec->mutex);
+#ifdef CONFIG_SND_SOC_AC97_BUS
+ soc_unregister_ac97_dai_link(codec);
+#endif
kfree(codec->ac97->bus);
kfree(codec->ac97);
codec->ac97 = NULL;
+ codec->ac97_created = 0;
mutex_unlock(&codec->mutex);
}
EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);
@@ -1633,95 +1952,6 @@
EXPORT_SYMBOL_GPL(snd_soc_test_bits);
/**
- * snd_soc_new_pcms - create new sound card and pcms
- * @socdev: the SoC audio device
- * @idx: ALSA card index
- * @xid: card identification
- *
- * Create a new sound card based upon the codec and interface pcms.
- *
- * Returns 0 for success, else error.
- */
-int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid)
-{
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_codec *codec = card->codec;
- int ret, i;
-
- mutex_lock(&codec->mutex);
-
- /* register a sound card */
- ret = snd_card_create(idx, xid, codec->owner, 0, &codec->card);
- if (ret < 0) {
- printk(KERN_ERR "asoc: can't create sound card for codec %s\n",
- codec->name);
- mutex_unlock(&codec->mutex);
- return ret;
- }
-
- codec->socdev = socdev;
- codec->card->dev = socdev->dev;
- codec->card->private_data = codec;
- strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver));
-
- /* create the pcms */
- for (i = 0; i < card->num_links; i++) {
- ret = soc_new_pcm(socdev, &card->dai_link[i], i);
- if (ret < 0) {
- printk(KERN_ERR "asoc: can't create pcm %s\n",
- card->dai_link[i].stream_name);
- mutex_unlock(&codec->mutex);
- return ret;
- }
- /* Check for codec->ac97 to handle the ac97.c fun */
- if (card->dai_link[i].codec_dai->ac97_control && codec->ac97) {
- snd_ac97_dev_add_pdata(codec->ac97,
- card->dai_link[i].cpu_dai->ac97_pdata);
- }
- }
-
- mutex_unlock(&codec->mutex);
- return ret;
-}
-EXPORT_SYMBOL_GPL(snd_soc_new_pcms);
-
-/**
- * snd_soc_free_pcms - free sound card and pcms
- * @socdev: the SoC audio device
- *
- * Frees sound card and pcms associated with the socdev.
- * Also unregister the codec if it is an AC97 device.
- */
-void snd_soc_free_pcms(struct snd_soc_device *socdev)
-{
- struct snd_soc_codec *codec = socdev->card->codec;
-#ifdef CONFIG_SND_SOC_AC97_BUS
- struct snd_soc_dai *codec_dai;
- int i;
-#endif
-
- mutex_lock(&codec->mutex);
- soc_cleanup_codec_debugfs(codec);
-#ifdef CONFIG_SND_SOC_AC97_BUS
- for (i = 0; i < codec->num_dai; i++) {
- codec_dai = &codec->dai[i];
- if (codec_dai->ac97_control && codec->ac97 &&
- strcmp(codec->name, "AC97") != 0) {
- soc_ac97_dev_unregister(codec);
- goto free_card;
- }
- }
-free_card:
-#endif
-
- if (codec->card)
- snd_card_free(codec->card);
- device_remove_file(socdev->dev, &dev_attr_codec_reg);
- mutex_unlock(&codec->mutex);
-}
-EXPORT_SYMBOL_GPL(snd_soc_free_pcms);
-
-/**
* snd_soc_set_runtime_hwparams - set the runtime hardware parameters
* @substream: the pcm substream
* @hw: the hardware parameters
@@ -1782,15 +2012,15 @@
int snd_soc_add_controls(struct snd_soc_codec *codec,
const struct snd_kcontrol_new *controls, int num_controls)
{
- struct snd_card *card = codec->card;
+ struct snd_card *card = codec->card->snd_card;
int err, i;
for (i = 0; i < num_controls; i++) {
const struct snd_kcontrol_new *control = &controls[i];
err = snd_ctl_add(card, snd_soc_cnew(control, codec, NULL));
if (err < 0) {
- dev_err(codec->dev, "%s: Failed to add %s\n",
- codec->name, control->name);
+ dev_err(codec->dev, "%s: Failed to add %s: %d\n",
+ codec->name, control->name, err);
return err;
}
}
@@ -2337,7 +2567,7 @@
int snd_soc_limit_volume(struct snd_soc_codec *codec,
const char *name, int max)
{
- struct snd_card *card = codec->card;
+ struct snd_card *card = codec->card->snd_card;
struct snd_kcontrol *kctl;
struct soc_mixer_control *mc;
int found = 0;
@@ -2469,8 +2699,8 @@
int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned int freq, int dir)
{
- if (dai->ops && dai->ops->set_sysclk)
- return dai->ops->set_sysclk(dai, clk_id, freq, dir);
+ if (dai->driver && dai->driver->ops->set_sysclk)
+ return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
else
return -EINVAL;
}
@@ -2489,8 +2719,8 @@
int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
int div_id, int div)
{
- if (dai->ops && dai->ops->set_clkdiv)
- return dai->ops->set_clkdiv(dai, div_id, div);
+ if (dai->driver && dai->driver->ops->set_clkdiv)
+ return dai->driver->ops->set_clkdiv(dai, div_id, div);
else
return -EINVAL;
}
@@ -2509,8 +2739,8 @@
int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
unsigned int freq_in, unsigned int freq_out)
{
- if (dai->ops && dai->ops->set_pll)
- return dai->ops->set_pll(dai, pll_id, source,
+ if (dai->driver && dai->driver->ops->set_pll)
+ return dai->driver->ops->set_pll(dai, pll_id, source,
freq_in, freq_out);
else
return -EINVAL;
@@ -2526,8 +2756,8 @@
*/
int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
- if (dai->ops && dai->ops->set_fmt)
- return dai->ops->set_fmt(dai, fmt);
+ if (dai->driver && dai->driver->ops->set_fmt)
+ return dai->driver->ops->set_fmt(dai, fmt);
else
return -EINVAL;
}
@@ -2547,8 +2777,8 @@
int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
{
- if (dai->ops && dai->ops->set_tdm_slot)
- return dai->ops->set_tdm_slot(dai, tx_mask, rx_mask,
+ if (dai->driver && dai->driver->ops->set_tdm_slot)
+ return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
slots, slot_width);
else
return -EINVAL;
@@ -2571,8 +2801,8 @@
unsigned int tx_num, unsigned int *tx_slot,
unsigned int rx_num, unsigned int *rx_slot)
{
- if (dai->ops && dai->ops->set_channel_map)
- return dai->ops->set_channel_map(dai, tx_num, tx_slot,
+ if (dai->driver && dai->driver->ops->set_channel_map)
+ return dai->driver->ops->set_channel_map(dai, tx_num, tx_slot,
rx_num, rx_slot);
else
return -EINVAL;
@@ -2588,8 +2818,8 @@
*/
int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
{
- if (dai->ops && dai->ops->set_tristate)
- return dai->ops->set_tristate(dai, tristate);
+ if (dai->driver && dai->driver->ops->set_tristate)
+ return dai->driver->ops->set_tristate(dai, tristate);
else
return -EINVAL;
}
@@ -2604,8 +2834,8 @@
*/
int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute)
{
- if (dai->ops && dai->ops->digital_mute)
- return dai->ops->digital_mute(dai, mute);
+ if (dai->driver && dai->driver->ops->digital_mute)
+ return dai->driver->ops->digital_mute(dai, mute);
else
return -EINVAL;
}
@@ -2622,11 +2852,22 @@
*/
static int snd_soc_register_card(struct snd_soc_card *card)
{
+ int i;
+
if (!card->name || !card->dev)
return -EINVAL;
+ card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) * card->num_links,
+ GFP_KERNEL);
+ if (card->rtd == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < card->num_links; i++)
+ card->rtd[i].dai_link = &card->dai_link[i];
+
INIT_LIST_HEAD(&card->list);
card->instantiated = 0;
+ mutex_init(&card->mutex);
mutex_lock(&client_mutex);
list_add(&card->list, &card_list);
@@ -2652,30 +2893,97 @@
mutex_lock(&client_mutex);
list_del(&card->list);
mutex_unlock(&client_mutex);
-
dev_dbg(card->dev, "Unregistered card '%s'\n", card->name);
return 0;
}
+/*
+ * Simplify DAI link configuration by removing ".-1" from device names
+ * and sanitizing names.
+ */
+static inline char *fmt_single_name(struct device *dev, int *id)
+{
+ char *found, name[NAME_SIZE];
+ int id1, id2;
+
+ if (dev_name(dev) == NULL)
+ return NULL;
+
+ strncpy(name, dev_name(dev), NAME_SIZE);
+
+ /* are we a "%s.%d" name (platform and SPI components) */
+ found = strstr(name, dev->driver->name);
+ if (found) {
+ /* get ID */
+ if (sscanf(&found[strlen(dev->driver->name)], ".%d", id) == 1) {
+
+ /* discard ID from name if ID == -1 */
+ if (*id == -1)
+ found[strlen(dev->driver->name)] = '\0';
+ }
+
+ } else {
+ /* I2C component devices are named "bus-addr" */
+ if (sscanf(name, "%x-%x", &id1, &id2) == 2) {
+ char tmp[NAME_SIZE];
+
+ /* create unique ID number from I2C addr and bus */
+ *id = ((id1 & 0xffff) << 16) + id2;
+
+ /* sanitize component name for DAI link creation */
+ snprintf(tmp, NAME_SIZE, "%s.%s", dev->driver->name, name);
+ strncpy(name, tmp, NAME_SIZE);
+ } else
+ *id = 0;
+ }
+
+ return kstrdup(name, GFP_KERNEL);
+}
+
+/*
+ * Simplify DAI link naming for single devices with multiple DAIs by removing
+ * any ".-1" and using the DAI name (instead of device name).
+ */
+static inline char *fmt_multiple_name(struct device *dev,
+ struct snd_soc_dai_driver *dai_drv)
+{
+ if (dai_drv->name == NULL) {
+ printk(KERN_ERR "asoc: error - multiple DAI %s registered with no name\n",
+ dev_name(dev));
+ return NULL;
+ }
+
+ return kstrdup(dai_drv->name, GFP_KERNEL);
+}
+
/**
* snd_soc_register_dai - Register a DAI with the ASoC core
*
* @dai: DAI to register
*/
-int snd_soc_register_dai(struct snd_soc_dai *dai)
+int snd_soc_register_dai(struct device *dev,
+ struct snd_soc_dai_driver *dai_drv)
{
- if (!dai->name)
- return -EINVAL;
+ struct snd_soc_dai *dai;
- /* The device should become mandatory over time */
- if (!dai->dev)
- printk(KERN_WARNING "No device for DAI %s\n", dai->name);
+ dev_dbg(dev, "dai register %s\n", dev_name(dev));
- if (!dai->ops)
- dai->ops = &null_dai_ops;
+ dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
+ if (dai == NULL)
+ return -ENOMEM;
- INIT_LIST_HEAD(&dai->list);
+ /* create DAI component name */
+ dai->name = fmt_single_name(dev, &dai->id);
+ if (dai->name == NULL) {
+ kfree(dai);
+ return -ENOMEM;
+ }
+
+ dai->dev = dev;
+ dai->driver = dai_drv;
+ if (!dai->driver->ops)
+ dai->driver->ops = &null_dai_ops;
mutex_lock(&client_mutex);
list_add(&dai->list, &dai_list);
@@ -2693,13 +3001,24 @@
*
* @dai: DAI to unregister
*/
-void snd_soc_unregister_dai(struct snd_soc_dai *dai)
+void snd_soc_unregister_dai(struct device *dev)
{
+ struct snd_soc_dai *dai;
+
+ list_for_each_entry(dai, &dai_list, list) {
+ if (dev == dai->dev)
+ goto found;
+ }
+ return;
+
+found:
mutex_lock(&client_mutex);
list_del(&dai->list);
mutex_unlock(&client_mutex);
pr_debug("Unregistered DAI '%s'\n", dai->name);
+ kfree(dai->name);
+ kfree(dai);
}
EXPORT_SYMBOL_GPL(snd_soc_unregister_dai);
@@ -2709,21 +3028,50 @@
* @dai: Array of DAIs to register
* @count: Number of DAIs
*/
-int snd_soc_register_dais(struct snd_soc_dai *dai, size_t count)
+int snd_soc_register_dais(struct device *dev,
+ struct snd_soc_dai_driver *dai_drv, size_t count)
{
- int i, ret;
+ struct snd_soc_dai *dai;
+ int i, ret = 0;
+
+ dev_dbg(dev, "dai register %s #%Zu\n", dev_name(dev), count);
for (i = 0; i < count; i++) {
- ret = snd_soc_register_dai(&dai[i]);
- if (ret != 0)
+
+ dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
+ if (dai == NULL)
+ return -ENOMEM;
+
+ /* create DAI component name */
+ dai->name = fmt_multiple_name(dev, &dai_drv[i]);
+ if (dai->name == NULL) {
+ kfree(dai);
+ ret = -EINVAL;
goto err;
+ }
+
+ dai->dev = dev;
+ dai->driver = &dai_drv[i];
+ if (dai->driver->id)
+ dai->id = dai->driver->id;
+ else
+ dai->id = i;
+ if (!dai->driver->ops)
+ dai->driver->ops = &null_dai_ops;
+
+ mutex_lock(&client_mutex);
+ list_add(&dai->list, &dai_list);
+ mutex_unlock(&client_mutex);
+
+ pr_debug("Registered DAI '%s'\n", dai->name);
}
+ snd_soc_instantiate_cards();
return 0;
err:
for (i--; i >= 0; i--)
- snd_soc_unregister_dai(&dai[i]);
+ snd_soc_unregister_dai(dev);
return ret;
}
@@ -2735,12 +3083,12 @@
* @dai: Array of DAIs to unregister
* @count: Number of DAIs
*/
-void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count)
+void snd_soc_unregister_dais(struct device *dev, size_t count)
{
int i;
for (i = 0; i < count; i++)
- snd_soc_unregister_dai(&dai[i]);
+ snd_soc_unregister_dai(dev);
}
EXPORT_SYMBOL_GPL(snd_soc_unregister_dais);
@@ -2749,12 +3097,26 @@
*
* @platform: platform to register
*/
-int snd_soc_register_platform(struct snd_soc_platform *platform)
+int snd_soc_register_platform(struct device *dev,
+ struct snd_soc_platform_driver *platform_drv)
{
- if (!platform->name)
- return -EINVAL;
+ struct snd_soc_platform *platform;
- INIT_LIST_HEAD(&platform->list);
+ dev_dbg(dev, "platform register %s\n", dev_name(dev));
+
+ platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL);
+ if (platform == NULL)
+ return -ENOMEM;
+
+ /* create platform component name */
+ platform->name = fmt_single_name(dev, &platform->id);
+ if (platform->name == NULL) {
+ kfree(platform);
+ return -ENOMEM;
+ }
+
+ platform->dev = dev;
+ platform->driver = platform_drv;
mutex_lock(&client_mutex);
list_add(&platform->list, &platform_list);
@@ -2772,13 +3134,24 @@
*
* @platform: platform to unregister
*/
-void snd_soc_unregister_platform(struct snd_soc_platform *platform)
+void snd_soc_unregister_platform(struct device *dev)
{
+ struct snd_soc_platform *platform;
+
+ list_for_each_entry(platform, &platform_list, list) {
+ if (dev == platform->dev)
+ goto found;
+ }
+ return;
+
+found:
mutex_lock(&client_mutex);
list_del(&platform->list);
mutex_unlock(&client_mutex);
pr_debug("Unregistered platform '%s'\n", platform->name);
+ kfree(platform->name);
+ kfree(platform);
}
EXPORT_SYMBOL_GPL(snd_soc_unregister_platform);
@@ -2820,22 +3193,61 @@
*
* @codec: codec to register
*/
-int snd_soc_register_codec(struct snd_soc_codec *codec)
+int snd_soc_register_codec(struct device *dev,
+ struct snd_soc_codec_driver *codec_drv,
+ struct snd_soc_dai_driver *dai_drv, int num_dai)
{
- int i;
+ struct snd_soc_codec *codec;
+ int ret, i;
- if (!codec->name)
- return -EINVAL;
+ dev_dbg(dev, "codec register %s\n", dev_name(dev));
- /* The device should become mandatory over time */
- if (!codec->dev)
- printk(KERN_WARNING "No device for codec %s\n", codec->name);
+ codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+ if (codec == NULL)
+ return -ENOMEM;
- INIT_LIST_HEAD(&codec->list);
+ /* create CODEC component name */
+ codec->name = fmt_single_name(dev, &codec->id);
+ if (codec->name == NULL) {
+ kfree(codec);
+ return -ENOMEM;
+ }
- for (i = 0; i < codec->num_dai; i++) {
- fixup_codec_formats(&codec->dai[i].playback);
- fixup_codec_formats(&codec->dai[i].capture);
+ /* allocate CODEC register cache */
+ if (codec_drv->reg_cache_size && codec_drv->reg_word_size) {
+
+ if (codec_drv->reg_cache_default)
+ codec->reg_cache = kmemdup(codec_drv->reg_cache_default,
+ codec_drv->reg_cache_size * codec_drv->reg_word_size, GFP_KERNEL);
+ else
+ codec->reg_cache = kzalloc(codec_drv->reg_cache_size *
+ codec_drv->reg_word_size, GFP_KERNEL);
+
+ if (codec->reg_cache == NULL) {
+ kfree(codec->name);
+ kfree(codec);
+ return -ENOMEM;
+ }
+ }
+
+ codec->dev = dev;
+ codec->driver = codec_drv;
+ codec->bias_level = SND_SOC_BIAS_OFF;
+ codec->num_dai = num_dai;
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ for (i = 0; i < num_dai; i++) {
+ fixup_codec_formats(&dai_drv[i].playback);
+ fixup_codec_formats(&dai_drv[i].capture);
+ }
+
+ /* register any DAIs */
+ if (num_dai) {
+ ret = snd_soc_register_dais(dev, dai_drv, num_dai);
+ if (ret < 0)
+ goto error;
}
mutex_lock(&client_mutex);
@@ -2844,8 +3256,17 @@
mutex_unlock(&client_mutex);
pr_debug("Registered codec '%s'\n", codec->name);
-
return 0;
+
+error:
+ for (i--; i >= 0; i--)
+ snd_soc_unregister_dai(dev);
+
+ if (codec->reg_cache)
+ kfree(codec->reg_cache);
+ kfree(codec->name);
+ kfree(codec);
+ return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_register_codec);
@@ -2854,13 +3275,32 @@
*
* @codec: codec to unregister
*/
-void snd_soc_unregister_codec(struct snd_soc_codec *codec)
+void snd_soc_unregister_codec(struct device *dev)
{
+ struct snd_soc_codec *codec;
+ int i;
+
+ list_for_each_entry(codec, &codec_list, list) {
+ if (dev == codec->dev)
+ goto found;
+ }
+ return;
+
+found:
+ if (codec->num_dai)
+ for (i = 0; i < codec->num_dai; i++)
+ snd_soc_unregister_dai(dev);
+
mutex_lock(&client_mutex);
list_del(&codec->list);
mutex_unlock(&client_mutex);
pr_debug("Unregistered codec '%s'\n", codec->name);
+
+ if (codec->reg_cache)
+ kfree(codec->reg_cache);
+ kfree(codec->name);
+ kfree(codec);
}
EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);
@@ -2873,10 +3313,23 @@
"ASoC: Failed to create debugfs directory\n");
debugfs_root = NULL;
}
+
+ if (!debugfs_create_file("codecs", 0444, debugfs_root, NULL,
+ &codec_list_fops))
+ pr_warn("ASoC: Failed to create CODEC list debugfs file\n");
+
+ if (!debugfs_create_file("dais", 0444, debugfs_root, NULL,
+ &dai_list_fops))
+ pr_warn("ASoC: Failed to create DAI list debugfs file\n");
+
+ if (!debugfs_create_file("platforms", 0444, debugfs_root, NULL,
+ &platform_list_fops))
+ pr_warn("ASoC: Failed to create platform list debugfs file\n");
#endif
return platform_driver_register(&soc_driver);
}
+module_init(snd_soc_init);
static void __exit snd_soc_exit(void)
{
@@ -2885,8 +3338,6 @@
#endif
platform_driver_unregister(&soc_driver);
}
-
-module_init(snd_soc_init);
module_exit(snd_soc_exit);
/* Module information */
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 03cb7c0..035cab8 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -112,43 +112,41 @@
/**
* snd_soc_dapm_set_bias_level - set the bias level for the system
- * @socdev: audio device
+ * @card: audio device
* @level: level to configure
*
* Configure the bias (power) levels for the SoC audio device.
*
* Returns 0 for success else error.
*/
-static int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
- enum snd_soc_bias_level level)
+static int snd_soc_dapm_set_bias_level(struct snd_soc_card *card,
+ struct snd_soc_codec *codec, enum snd_soc_bias_level level)
{
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_codec *codec = socdev->card->codec;
int ret = 0;
switch (level) {
case SND_SOC_BIAS_ON:
- dev_dbg(socdev->dev, "Setting full bias\n");
+ dev_dbg(codec->dev, "Setting full bias\n");
break;
case SND_SOC_BIAS_PREPARE:
- dev_dbg(socdev->dev, "Setting bias prepare\n");
+ dev_dbg(codec->dev, "Setting bias prepare\n");
break;
case SND_SOC_BIAS_STANDBY:
- dev_dbg(socdev->dev, "Setting standby bias\n");
+ dev_dbg(codec->dev, "Setting standby bias\n");
break;
case SND_SOC_BIAS_OFF:
- dev_dbg(socdev->dev, "Setting bias off\n");
+ dev_dbg(codec->dev, "Setting bias off\n");
break;
default:
- dev_err(socdev->dev, "Setting invalid bias %d\n", level);
+ dev_err(codec->dev, "Setting invalid bias %d\n", level);
return -EINVAL;
}
- if (card->set_bias_level)
+ if (card && card->set_bias_level)
ret = card->set_bias_level(card, level);
if (ret == 0) {
- if (codec->set_bias_level)
- ret = codec->set_bias_level(codec, level);
+ if (codec->driver->set_bias_level)
+ ret = codec->driver->set_bias_level(codec, level);
else
codec->bias_level = level;
}
@@ -370,7 +368,7 @@
path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w,
path->long_name);
- ret = snd_ctl_add(codec->card, path->kcontrol);
+ ret = snd_ctl_add(codec->card->snd_card, path->kcontrol);
if (ret < 0) {
printk(KERN_ERR "asoc: failed to add dapm kcontrol %s: %d\n",
path->long_name,
@@ -398,7 +396,7 @@
}
kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name);
- ret = snd_ctl_add(codec->card, kcontrol);
+ ret = snd_ctl_add(codec->card->snd_card, kcontrol);
if (ret < 0)
goto err;
@@ -437,9 +435,9 @@
*/
static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
{
- struct snd_soc_codec *codec = widget->codec;
+ int level = snd_power_get_state(widget->codec->card->snd_card);
- switch (snd_power_get_state(codec->card)) {
+ switch (level) {
case SNDRV_CTL_POWER_D3hot:
case SNDRV_CTL_POWER_D3cold:
if (widget->ignore_suspend)
@@ -893,7 +891,7 @@
*/
static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
{
- struct snd_soc_device *socdev = codec->socdev;
+ struct snd_soc_card *card = codec->card;
struct snd_soc_dapm_widget *w;
LIST_HEAD(up_list);
LIST_HEAD(down_list);
@@ -966,7 +964,7 @@
}
if (sys_power && codec->bias_level == SND_SOC_BIAS_OFF) {
- ret = snd_soc_dapm_set_bias_level(socdev,
+ ret = snd_soc_dapm_set_bias_level(card, codec,
SND_SOC_BIAS_STANDBY);
if (ret != 0)
pr_err("Failed to turn on bias: %d\n", ret);
@@ -975,8 +973,7 @@
/* If we're changing to all on or all off then prepare */
if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) ||
(!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) {
- ret = snd_soc_dapm_set_bias_level(socdev,
- SND_SOC_BIAS_PREPARE);
+ ret = snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_PREPARE);
if (ret != 0)
pr_err("Failed to prepare bias: %d\n", ret);
}
@@ -989,8 +986,7 @@
/* If we just powered the last thing off drop to standby bias */
if (codec->bias_level == SND_SOC_BIAS_PREPARE && !sys_power) {
- ret = snd_soc_dapm_set_bias_level(socdev,
- SND_SOC_BIAS_STANDBY);
+ ret = snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_STANDBY);
if (ret != 0)
pr_err("Failed to apply standby bias: %d\n", ret);
}
@@ -998,15 +994,14 @@
/* If we're in standby and can support bias off then do that */
if (codec->bias_level == SND_SOC_BIAS_STANDBY &&
codec->idle_bias_off) {
- ret = snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_OFF);
+ ret = snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_OFF);
if (ret != 0)
pr_err("Failed to turn off bias: %d\n", ret);
}
/* If we just powered up then move to active bias */
if (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) {
- ret = snd_soc_dapm_set_bias_level(socdev,
- SND_SOC_BIAS_ON);
+ ret = snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_ON);
if (ret != 0)
pr_err("Failed to apply active bias: %d\n", ret);
}
@@ -1188,8 +1183,9 @@
static ssize_t dapm_widget_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct snd_soc_device *devdata = dev_get_drvdata(dev);
- struct snd_soc_codec *codec = devdata->card->codec;
+ struct snd_soc_pcm_runtime *rtd =
+ container_of(dev, struct snd_soc_pcm_runtime, dev);
+ struct snd_soc_codec *codec =rtd->codec;
struct snd_soc_dapm_widget *w;
int count = 0;
char *state = "not set";
@@ -1998,9 +1994,10 @@
*
* Returns 0 for success else error.
*/
-int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
- char *stream, int event)
+int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
+ const char *stream, int event)
{
+ struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_widget *w;
if (stream == NULL)
@@ -2168,25 +2165,19 @@
/**
* snd_soc_dapm_free - free dapm resources
- * @socdev: SoC device
+ * @card: SoC device
*
* Free all dapm widgets and resources.
*/
-void snd_soc_dapm_free(struct snd_soc_device *socdev)
+void snd_soc_dapm_free(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = socdev->card->codec;
-
- snd_soc_dapm_sys_remove(socdev->dev);
+ snd_soc_dapm_sys_remove(codec->dev);
dapm_free_widgets(codec);
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
-/*
- * snd_soc_dapm_shutdown - callback for system shutdown
- */
-void snd_soc_dapm_shutdown(struct snd_soc_device *socdev)
+static void soc_dapm_shutdown_codec(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = socdev->card->codec;
struct snd_soc_dapm_widget *w;
LIST_HEAD(down_list);
int powerdown = 0;
@@ -2203,12 +2194,23 @@
* standby.
*/
if (powerdown) {
- snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_PREPARE);
+ snd_soc_dapm_set_bias_level(NULL, codec, SND_SOC_BIAS_PREPARE);
dapm_seq_run(codec, &down_list, 0, dapm_down_seq);
- snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_STANDBY);
+ snd_soc_dapm_set_bias_level(NULL, codec, SND_SOC_BIAS_STANDBY);
}
+}
- snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_OFF);
+/*
+ * snd_soc_dapm_shutdown - callback for system shutdown
+ */
+void snd_soc_dapm_shutdown(struct snd_soc_card *card)
+{
+ struct snd_soc_codec *codec;
+
+ list_for_each_entry(codec, &card->codec_dev_list, list)
+ soc_dapm_shutdown_codec(codec);
+
+ snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_OFF);
}
/* Module information */
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index 29159e1..8a0a920 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -32,14 +32,14 @@
* Returns zero if successful, or a negative error code on failure.
* On success jack will be initialised.
*/
-int snd_soc_jack_new(struct snd_soc_card *card, const char *id, int type,
+int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
struct snd_soc_jack *jack)
{
- jack->card = card;
+ jack->codec = codec;
INIT_LIST_HEAD(&jack->pins);
BLOCKING_INIT_NOTIFIER_HEAD(&jack->notifier);
- return snd_jack_new(card->codec->card, id, type, &jack->jack);
+ return snd_jack_new(codec->card->snd_card, id, type, &jack->jack);
}
EXPORT_SYMBOL_GPL(snd_soc_jack_new);
@@ -67,7 +67,7 @@
if (!jack)
return;
- codec = jack->card->codec;
+ codec = jack->codec;
mutex_lock(&codec->mutex);
@@ -188,9 +188,6 @@
int enable;
int report;
- if (gpio->debounce_time > 0)
- mdelay(gpio->debounce_time);
-
enable = gpio_get_value(gpio->gpio);
if (gpio->invert)
enable = !enable;
@@ -211,7 +208,8 @@
{
struct snd_soc_jack_gpio *gpio = data;
- schedule_work(&gpio->work);
+ schedule_delayed_work(&gpio->work,
+ msecs_to_jiffies(gpio->debounce_time));
return IRQ_HANDLED;
}
@@ -221,7 +219,7 @@
{
struct snd_soc_jack_gpio *gpio;
- gpio = container_of(work, struct snd_soc_jack_gpio, work);
+ gpio = container_of(work, struct snd_soc_jack_gpio, work.work);
snd_soc_jack_gpio_detect(gpio);
}
@@ -262,13 +260,13 @@
if (ret)
goto err;
- INIT_WORK(&gpios[i].work, gpio_work);
+ INIT_DELAYED_WORK(&gpios[i].work, gpio_work);
gpios[i].jack = jack;
ret = request_irq(gpio_to_irq(gpios[i].gpio),
gpio_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- jack->card->dev->driver->name,
+ jack->codec->dev->driver->name,
&gpios[i]);
if (ret)
goto err;
@@ -312,6 +310,7 @@
gpio_unexport(gpios[i].gpio);
#endif
free_irq(gpio_to_irq(gpios[i].gpio), &gpios[i]);
+ cancel_delayed_work_sync(&gpios[i].work);
gpio_free(gpios[i].gpio);
gpios[i].jack = NULL;
}
diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c
index 0ec20b6..743d07b 100644
--- a/sound/soc/txx9/txx9aclc-ac97.c
+++ b/sound/soc/txx9/txx9aclc-ac97.c
@@ -36,13 +36,11 @@
static DECLARE_WAIT_QUEUE_HEAD(ac97_waitq);
-/* REVISIT: How to find txx9aclc_soc_device from snd_ac97? */
-static struct txx9aclc_soc_device *txx9aclc_soc_dev;
+/* REVISIT: How to find txx9aclc_drvdata from snd_ac97? */
+static struct txx9aclc_plat_drvdata *txx9aclc_drvdata;
-static int txx9aclc_regready(struct txx9aclc_soc_device *dev)
+static int txx9aclc_regready(struct txx9aclc_plat_drvdata *drvdata)
{
- struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
-
return __raw_readl(drvdata->base + ACINTSTS) & ACINT_REGACCRDY;
}
@@ -50,8 +48,7 @@
static unsigned short txx9aclc_ac97_read(struct snd_ac97 *ac97,
unsigned short reg)
{
- struct txx9aclc_soc_device *dev = txx9aclc_soc_dev;
- struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+ struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
void __iomem *base = drvdata->base;
u32 dat;
@@ -61,15 +58,15 @@
dat = (reg << ACREGACC_REG_SHIFT) | ACREGACC_READ;
__raw_writel(dat, base + ACREGACC);
__raw_writel(ACINT_REGACCRDY, base + ACINTEN);
- if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(dev), HZ)) {
+ if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(txx9aclc_drvdata), HZ)) {
__raw_writel(ACINT_REGACCRDY, base + ACINTDIS);
- dev_err(dev->soc_dev.dev, "ac97 read timeout (reg %#x)\n", reg);
+ printk(KERN_ERR "ac97 read timeout (reg %#x)\n", reg);
dat = 0xffff;
goto done;
}
dat = __raw_readl(base + ACREGACC);
if (((dat >> ACREGACC_REG_SHIFT) & 0xff) != reg) {
- dev_err(dev->soc_dev.dev, "reg mismatch %x with %x\n",
+ printk(KERN_ERR "reg mismatch %x with %x\n",
dat, reg);
dat = 0xffff;
goto done;
@@ -84,16 +81,15 @@
static void txx9aclc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
unsigned short val)
{
- struct txx9aclc_soc_device *dev = txx9aclc_soc_dev;
- struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+ struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
void __iomem *base = drvdata->base;
__raw_writel(((reg | (ac97->num << 7)) << ACREGACC_REG_SHIFT) |
(val << ACREGACC_DAT_SHIFT),
base + ACREGACC);
__raw_writel(ACINT_REGACCRDY, base + ACINTEN);
- if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(dev), HZ)) {
- dev_err(dev->soc_dev.dev,
+ if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(txx9aclc_drvdata), HZ)) {
+ printk(KERN_ERR
"ac97 write timeout (reg %#x)\n", reg);
}
__raw_writel(ACINT_REGACCRDY, base + ACINTDIS);
@@ -101,8 +97,7 @@
static void txx9aclc_ac97_cold_reset(struct snd_ac97 *ac97)
{
- struct txx9aclc_soc_device *dev = txx9aclc_soc_dev;
- struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+ struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
void __iomem *base = drvdata->base;
u32 ready = ACINT_CODECRDY(ac97->num) | ACINT_REGACCRDY;
@@ -141,31 +136,23 @@
return IRQ_HANDLED;
}
-static int txx9aclc_ac97_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int txx9aclc_ac97_probe(struct snd_soc_dai *dai)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct txx9aclc_soc_device *dev =
- container_of(socdev, struct txx9aclc_soc_device, soc_dev);
-
- dev->aclc_pdev = to_platform_device(dai->dev);
- txx9aclc_soc_dev = dev;
+ txx9aclc_drvdata = snd_soc_dai_get_drvdata(dai);
return 0;
}
-static void txx9aclc_ac97_remove(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int txx9aclc_ac97_remove(struct snd_soc_dai *dai)
{
- struct platform_device *aclc_pdev = to_platform_device(dai->dev);
- struct txx9aclc_plat_drvdata *drvdata = platform_get_drvdata(aclc_pdev);
+ struct txx9aclc_plat_drvdata *drvdata = snd_soc_dai_get_drvdata(dai);
/* disable AC-link */
__raw_writel(ACCTL_ENLINK, drvdata->base + ACCTLDIS);
- txx9aclc_soc_dev = NULL;
+ txx9aclc_drvdata = NULL;
+ return 0;
}
-struct snd_soc_dai txx9aclc_ac97_dai = {
- .name = "txx9aclc_ac97",
+static struct snd_soc_dai_driver txx9aclc_ac97_dai = {
.ac97_control = 1,
.probe = txx9aclc_ac97_probe,
.remove = txx9aclc_ac97_remove,
@@ -182,7 +169,6 @@
.channels_max = 2,
},
};
-EXPORT_SYMBOL_GPL(txx9aclc_ac97_dai);
static int __devinit txx9aclc_ac97_dev_probe(struct platform_device *pdev)
{
@@ -219,13 +205,12 @@
if (err < 0)
return err;
- txx9aclc_ac97_dai.dev = &pdev->dev;
- return snd_soc_register_dai(&txx9aclc_ac97_dai);
+ return snd_soc_register_dai(&pdev->dev, &txx9aclc_ac97_dai);
}
static int __devexit txx9aclc_ac97_dev_remove(struct platform_device *pdev)
{
- snd_soc_unregister_dai(&txx9aclc_ac97_dai);
+ snd_soc_unregister_dai(&pdev->dev);
return 0;
}
diff --git a/sound/soc/txx9/txx9aclc-generic.c b/sound/soc/txx9/txx9aclc-generic.c
index 95b17f7..6770e71 100644
--- a/sound/soc/txx9/txx9aclc-generic.c
+++ b/sound/soc/txx9/txx9aclc-generic.c
@@ -19,54 +19,44 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
-#include "../codecs/ac97.h"
#include "txx9aclc.h"
static struct snd_soc_dai_link txx9aclc_generic_dai = {
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &txx9aclc_ac97_dai,
- .codec_dai = &ac97_dai,
+ .cpu_dai_name = "txx9aclc-ac97",
+ .codec_dai_name = "ac97-hifi",
+ .platform_name = "txx9aclc-pcm-audio",
+ .codec_name = "ac97-codec",
};
static struct snd_soc_card txx9aclc_generic_card = {
.name = "Generic TXx9 ACLC Audio",
- .platform = &txx9aclc_soc_platform,
.dai_link = &txx9aclc_generic_dai,
.num_links = 1,
};
-static struct txx9aclc_soc_device txx9aclc_generic_soc_device = {
- .soc_dev = {
- .card = &txx9aclc_generic_card,
- .codec_dev = &soc_codec_dev_ac97,
- },
-};
+static struct platform_device *soc_pdev;
static int __init txx9aclc_generic_probe(struct platform_device *pdev)
{
- struct txx9aclc_soc_device *dev = &txx9aclc_generic_soc_device;
- struct platform_device *soc_pdev;
int ret;
soc_pdev = platform_device_alloc("soc-audio", -1);
if (!soc_pdev)
return -ENOMEM;
- platform_set_drvdata(soc_pdev, &dev->soc_dev);
- dev->soc_dev.dev = &soc_pdev->dev;
+ platform_set_drvdata(soc_pdev, &txx9aclc_generic_card);
ret = platform_device_add(soc_pdev);
if (ret) {
platform_device_put(soc_pdev);
return ret;
}
- platform_set_drvdata(pdev, soc_pdev);
+
return 0;
}
static int __exit txx9aclc_generic_remove(struct platform_device *pdev)
{
- struct platform_device *soc_pdev = platform_get_drvdata(pdev);
-
platform_device_unregister(soc_pdev);
return 0;
}
diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c
index 0e34523..f4aa4e0 100644
--- a/sound/soc/txx9/txx9aclc.c
+++ b/sound/soc/txx9/txx9aclc.c
@@ -22,6 +22,16 @@
#include <sound/soc.h>
#include "txx9aclc.h"
+static struct txx9aclc_soc_device {
+ struct txx9aclc_dmadata dmadata[2];
+} txx9aclc_soc_device;
+
+/* REVISIT: How to find txx9aclc_drvdata from snd_ac97? */
+static struct txx9aclc_plat_drvdata *txx9aclc_drvdata;
+
+static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
+ struct txx9aclc_dmadata *dmadata);
+
static const struct snd_pcm_hardware txx9aclc_pcm_hardware = {
/*
* REVISIT: SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID
@@ -46,7 +56,6 @@
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
- struct snd_soc_device *socdev = rtd->socdev;
struct snd_pcm_runtime *runtime = substream->runtime;
struct txx9aclc_dmadata *dmadata = runtime->private_data;
int ret;
@@ -55,13 +64,13 @@
if (ret < 0)
return ret;
- dev_dbg(socdev->dev,
+ dev_dbg(rtd->platform->dev,
"runtime->dma_area = %#lx dma_addr = %#lx dma_bytes = %zd "
"runtime->min_align %ld\n",
(unsigned long)runtime->dma_area,
(unsigned long)runtime->dma_addr, runtime->dma_bytes,
runtime->min_align);
- dev_dbg(socdev->dev,
+ dev_dbg(rtd->platform->dev,
"periods %d period_bytes %d stream %d\n",
params_periods(params), params_period_bytes(params),
substream->stream);
@@ -152,11 +161,7 @@
spin_lock_irqsave(&dmadata->dma_lock, flags);
if (dmadata->frag_count < 0) {
- struct txx9aclc_soc_device *dev =
- container_of(dmadata, struct txx9aclc_soc_device,
- dmadata[substream->stream]);
- struct txx9aclc_plat_drvdata *drvdata =
- txx9aclc_get_plat_drvdata(dev);
+ struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
void __iomem *base = drvdata->base;
spin_unlock_irqrestore(&dmadata->dma_lock, flags);
@@ -202,10 +207,7 @@
static int txx9aclc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct txx9aclc_dmadata *dmadata = substream->runtime->private_data;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct txx9aclc_soc_device *dev =
- container_of(rtd->socdev, struct txx9aclc_soc_device, soc_dev);
- struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+ struct txx9aclc_plat_drvdata *drvdata =txx9aclc_drvdata;
void __iomem *base = drvdata->base;
unsigned long flags;
int ret = 0;
@@ -244,9 +246,7 @@
static int txx9aclc_pcm_open(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct txx9aclc_soc_device *dev =
- container_of(rtd->socdev, struct txx9aclc_soc_device, soc_dev);
+ struct txx9aclc_soc_device *dev = &txx9aclc_soc_device;
struct txx9aclc_dmadata *dmadata = &dev->dmadata[substream->stream];
int ret;
@@ -291,8 +291,38 @@
static int txx9aclc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
struct snd_pcm *pcm)
{
+ struct platform_device *pdev = to_platform_device(dai->platform->dev);
+ struct txx9aclc_soc_device *dev;
+ struct resource *r;
+ int i;
+ int ret;
+
+ /* at this point onwards the AC97 component has probed and this will be valid */
+ dev = snd_soc_dai_get_drvdata(dai);
+
+ dev->dmadata[0].stream = SNDRV_PCM_STREAM_PLAYBACK;
+ dev->dmadata[1].stream = SNDRV_PCM_STREAM_CAPTURE;
+ for (i = 0; i < 2; i++) {
+ r = platform_get_resource(pdev, IORESOURCE_DMA, i);
+ if (!r) {
+ ret = -EBUSY;
+ goto exit;
+ }
+ dev->dmadata[i].dma_res = r;
+ ret = txx9aclc_dma_init(dev, &dev->dmadata[i]);
+ if (ret)
+ goto exit;
+ }
return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
card->dev, 64 * 1024, 4 * 1024 * 1024);
+
+exit:
+ for (i = 0; i < 2; i++) {
+ if (dev->dmadata[i].dma_chan)
+ dma_release_channel(dev->dmadata[i].dma_chan);
+ dev->dmadata[i].dma_chan = NULL;
+ }
+ return ret;
}
static bool filter(struct dma_chan *chan, void *param)
@@ -314,7 +344,7 @@
static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
struct txx9aclc_dmadata *dmadata)
{
- struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+ struct txx9aclc_plat_drvdata *drvdata =txx9aclc_drvdata;
struct txx9dmac_slave *ds = &dmadata->dma_slave;
dma_cap_mask_t mask;
@@ -334,7 +364,7 @@
dma_cap_set(DMA_SLAVE, mask);
dmadata->dma_chan = dma_request_channel(mask, filter, dmadata);
if (!dmadata->dma_chan) {
- dev_err(dev->soc_dev.dev,
+ printk(KERN_ERR
"DMA channel for %s is not available\n",
dmadata->stream == SNDRV_PCM_STREAM_PLAYBACK ?
"playback" : "capture");
@@ -345,45 +375,16 @@
return 0;
}
-static int txx9aclc_pcm_probe(struct platform_device *pdev)
+static int txx9aclc_pcm_probe(struct snd_soc_platform *platform)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct txx9aclc_soc_device *dev =
- container_of(socdev, struct txx9aclc_soc_device, soc_dev);
- struct resource *r;
- int i;
- int ret;
-
- dev->dmadata[0].stream = SNDRV_PCM_STREAM_PLAYBACK;
- dev->dmadata[1].stream = SNDRV_PCM_STREAM_CAPTURE;
- for (i = 0; i < 2; i++) {
- r = platform_get_resource(dev->aclc_pdev, IORESOURCE_DMA, i);
- if (!r) {
- ret = -EBUSY;
- goto exit;
- }
- dev->dmadata[i].dma_res = r;
- ret = txx9aclc_dma_init(dev, &dev->dmadata[i]);
- if (ret)
- goto exit;
- }
+ snd_soc_platform_set_drvdata(platform, &txx9aclc_soc_device);
return 0;
-
-exit:
- for (i = 0; i < 2; i++) {
- if (dev->dmadata[i].dma_chan)
- dma_release_channel(dev->dmadata[i].dma_chan);
- dev->dmadata[i].dma_chan = NULL;
- }
- return ret;
}
-static int txx9aclc_pcm_remove(struct platform_device *pdev)
+static int txx9aclc_pcm_remove(struct snd_soc_platform *platform)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct txx9aclc_soc_device *dev =
- container_of(socdev, struct txx9aclc_soc_device, soc_dev);
- struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+ struct txx9aclc_soc_device *dev = snd_soc_platform_get_drvdata(platform);
+ struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
void __iomem *base = drvdata->base;
int i;
@@ -406,28 +407,46 @@
return 0;
}
-struct snd_soc_platform txx9aclc_soc_platform = {
- .name = "txx9aclc-audio",
+static struct snd_soc_platform_driver txx9aclc_soc_platform = {
.probe = txx9aclc_pcm_probe,
.remove = txx9aclc_pcm_remove,
- .pcm_ops = &txx9aclc_pcm_ops,
+ .ops = &txx9aclc_pcm_ops,
.pcm_new = txx9aclc_pcm_new,
.pcm_free = txx9aclc_pcm_free_dma_buffers,
};
-EXPORT_SYMBOL_GPL(txx9aclc_soc_platform);
-static int __init txx9aclc_soc_platform_init(void)
+static int __devinit txx9aclc_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&txx9aclc_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &txx9aclc_soc_platform);
}
-static void __exit txx9aclc_soc_platform_exit(void)
+static int __devexit txx9aclc_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&txx9aclc_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
}
-module_init(txx9aclc_soc_platform_init);
-module_exit(txx9aclc_soc_platform_exit);
+static struct platform_driver txx9aclc_pcm_driver = {
+ .driver = {
+ .name = "txx9aclc-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = txx9aclc_soc_platform_probe,
+ .remove = __devexit_p(txx9aclc_soc_platform_remove),
+};
+
+static int __init snd_txx9aclc_pcm_init(void)
+{
+ return platform_driver_register(&txx9aclc_pcm_driver);
+}
+module_init(snd_txx9aclc_pcm_init);
+
+static void __exit snd_txx9aclc_pcm_exit(void)
+{
+ platform_driver_unregister(&txx9aclc_pcm_driver);
+}
+module_exit(snd_txx9aclc_pcm_exit);
MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
MODULE_DESCRIPTION("TXx9 ACLC Audio DMA driver");
diff --git a/sound/soc/txx9/txx9aclc.h b/sound/soc/txx9/txx9aclc.h
index 6769aab..9c2de84 100644
--- a/sound/soc/txx9/txx9aclc.h
+++ b/sound/soc/txx9/txx9aclc.h
@@ -65,19 +65,10 @@
u64 physbase;
};
-struct txx9aclc_soc_device {
- struct snd_soc_device soc_dev;
- struct platform_device *aclc_pdev; /* for ioresources, drvdata */
- struct txx9aclc_dmadata dmadata[2];
-};
-
static inline struct txx9aclc_plat_drvdata *txx9aclc_get_plat_drvdata(
- struct txx9aclc_soc_device *sdev)
+ struct snd_soc_dai *dai)
{
- return platform_get_drvdata(sdev->aclc_pdev);
+ return dev_get_drvdata(dai->dev);
}
-extern struct snd_soc_platform txx9aclc_soc_platform;
-extern struct snd_soc_dai txx9aclc_ac97_dai;
-
#endif /* __TXX9ACLC_H */
diff --git a/sound/synth/emux/emux_hwdep.c b/sound/synth/emux/emux_hwdep.c
index ff0b2a8..5ae1eae 100644
--- a/sound/synth/emux/emux_hwdep.c
+++ b/sound/synth/emux/emux_hwdep.c
@@ -128,6 +128,9 @@
strcpy(hw->name, SNDRV_EMUX_HWDEP_NAME);
hw->iface = SNDRV_HWDEP_IFACE_EMUX_WAVETABLE;
hw->ops.ioctl = snd_emux_hwdep_ioctl;
+ /* The ioctl parameter types are compatible between 32- and
+ * 64-bit architectures, so use the same function. */
+ hw->ops.ioctl_compat = snd_emux_hwdep_ioctl;
hw->exclusive = 1;
hw->private_data = emu;
if ((err = snd_card_register(emu->card)) < 0)
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig
index 44d6d2e..112984f 100644
--- a/sound/usb/Kconfig
+++ b/sound/usb/Kconfig
@@ -65,6 +65,7 @@
* Native Instruments Guitar Rig Session I/O
* Native Instruments Guitar Rig mobile
* Native Instruments Traktor Kontrol X1
+ * Native Instruments Traktor Kontrol S4
To compile this driver as a module, choose M here: the module
will be called snd-usb-caiaq.
@@ -82,6 +83,7 @@
* Native Instruments Kore Controller
* Native Instruments Kore Controller 2
* Native Instruments Audio Kontrol 1
+ * Native Instruments Traktor Kontrol S4
config SND_USB_US122L
tristate "Tascam US-122L USB driver"
diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c
index 4328cad..68b9747 100644
--- a/sound/usb/caiaq/audio.c
+++ b/sound/usb/caiaq/audio.c
@@ -111,7 +111,7 @@
memset(dev->sub_capture, 0, sizeof(dev->sub_capture));
dev->input_panic = 0;
dev->output_panic = 0;
- dev->first_packet = 1;
+ dev->first_packet = 4;
dev->streaming = 1;
dev->warned = 0;
@@ -169,7 +169,7 @@
}
static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub,
- struct snd_pcm_hw_params *hw_params)
+ struct snd_pcm_hw_params *hw_params)
{
debug("%s(%p)\n", __func__, sub);
return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params));
@@ -189,7 +189,7 @@
#endif
static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100,
- 48000, 64000, 88200, 96000, 176400, 192000 };
+ 48000, 64000, 88200, 96000, 176400, 192000 };
static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
{
@@ -201,12 +201,39 @@
debug("%s(%p)\n", __func__, substream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- dev->period_out_count[index] = BYTES_PER_SAMPLE + 1;
- dev->audio_out_buf_pos[index] = BYTES_PER_SAMPLE + 1;
+ int out_pos;
+
+ switch (dev->spec.data_alignment) {
+ case 0:
+ case 2:
+ out_pos = BYTES_PER_SAMPLE + 1;
+ break;
+ case 3:
+ default:
+ out_pos = 0;
+ break;
+ }
+
+ dev->period_out_count[index] = out_pos;
+ dev->audio_out_buf_pos[index] = out_pos;
} else {
- int in_pos = (dev->spec.data_alignment == 2) ? 0 : 2;
- dev->period_in_count[index] = BYTES_PER_SAMPLE + in_pos;
- dev->audio_in_buf_pos[index] = BYTES_PER_SAMPLE + in_pos;
+ int in_pos;
+
+ switch (dev->spec.data_alignment) {
+ case 0:
+ in_pos = BYTES_PER_SAMPLE + 2;
+ break;
+ case 2:
+ in_pos = BYTES_PER_SAMPLE;
+ break;
+ case 3:
+ default:
+ in_pos = 0;
+ break;
+ }
+
+ dev->period_in_count[index] = in_pos;
+ dev->audio_in_buf_pos[index] = in_pos;
}
if (dev->streaming)
@@ -221,7 +248,7 @@
snd_pcm_limit_hw_rates(runtime);
bytes_per_sample = BYTES_PER_SAMPLE;
- if (dev->spec.data_alignment == 2)
+ if (dev->spec.data_alignment >= 2)
bytes_per_sample++;
bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE)
@@ -253,6 +280,8 @@
{
struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub);
+ debug("%s(%p) cmd %d\n", __func__, sub, cmd);
+
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
@@ -402,6 +431,61 @@
}
}
+static void read_in_urb_mode3(struct snd_usb_caiaqdev *dev,
+ const struct urb *urb,
+ const struct usb_iso_packet_descriptor *iso)
+{
+ unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
+ int stream, i;
+
+ /* paranoia check */
+ if (iso->actual_length % (BYTES_PER_SAMPLE_USB * CHANNELS_PER_STREAM))
+ return;
+
+ for (i = 0; i < iso->actual_length;) {
+ for (stream = 0; stream < dev->n_streams; stream++) {
+ struct snd_pcm_substream *sub = dev->sub_capture[stream];
+ char *audio_buf = NULL;
+ int c, n, sz = 0;
+
+ if (sub && !dev->input_panic) {
+ struct snd_pcm_runtime *rt = sub->runtime;
+ audio_buf = rt->dma_area;
+ sz = frames_to_bytes(rt, rt->buffer_size);
+ }
+
+ for (c = 0; c < CHANNELS_PER_STREAM; c++) {
+ /* 3 audio data bytes, followed by 1 check byte */
+ if (audio_buf) {
+ for (n = 0; n < BYTES_PER_SAMPLE; n++) {
+ audio_buf[dev->audio_in_buf_pos[stream]++] = usb_buf[i+n];
+
+ if (dev->audio_in_buf_pos[stream] == sz)
+ dev->audio_in_buf_pos[stream] = 0;
+ }
+
+ dev->period_in_count[stream] += BYTES_PER_SAMPLE;
+ }
+
+ i += BYTES_PER_SAMPLE;
+
+ if (usb_buf[i] != ((stream << 1) | c) &&
+ !dev->first_packet) {
+ if (!dev->input_panic)
+ printk(" EXPECTED: %02x got %02x, c %d, stream %d, i %d\n",
+ ((stream << 1) | c), usb_buf[i], c, stream, i);
+ dev->input_panic = 1;
+ }
+
+ i++;
+ }
+ }
+ }
+
+ if (dev->first_packet > 0)
+ dev->first_packet--;
+}
+
static void read_in_urb(struct snd_usb_caiaqdev *dev,
const struct urb *urb,
const struct usb_iso_packet_descriptor *iso)
@@ -419,6 +503,9 @@
case 2:
read_in_urb_mode2(dev, urb, iso);
break;
+ case 3:
+ read_in_urb_mode3(dev, urb, iso);
+ break;
}
if ((dev->input_panic || dev->output_panic) && !dev->warned) {
@@ -429,9 +516,9 @@
}
}
-static void fill_out_urb(struct snd_usb_caiaqdev *dev,
- struct urb *urb,
- const struct usb_iso_packet_descriptor *iso)
+static void fill_out_urb_mode_0(struct snd_usb_caiaqdev *dev,
+ struct urb *urb,
+ const struct usb_iso_packet_descriptor *iso)
{
unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
struct snd_pcm_substream *sub;
@@ -457,9 +544,67 @@
/* fill in the check bytes */
if (dev->spec.data_alignment == 2 &&
i % (dev->n_streams * BYTES_PER_SAMPLE_USB) ==
- (dev->n_streams * CHANNELS_PER_STREAM))
- for (stream = 0; stream < dev->n_streams; stream++, i++)
- usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i);
+ (dev->n_streams * CHANNELS_PER_STREAM))
+ for (stream = 0; stream < dev->n_streams; stream++, i++)
+ usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i);
+ }
+}
+
+static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *dev,
+ struct urb *urb,
+ const struct usb_iso_packet_descriptor *iso)
+{
+ unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
+ int stream, i;
+
+ for (i = 0; i < iso->length;) {
+ for (stream = 0; stream < dev->n_streams; stream++) {
+ struct snd_pcm_substream *sub = dev->sub_playback[stream];
+ char *audio_buf = NULL;
+ int c, n, sz = 0;
+
+ if (sub) {
+ struct snd_pcm_runtime *rt = sub->runtime;
+ audio_buf = rt->dma_area;
+ sz = frames_to_bytes(rt, rt->buffer_size);
+ }
+
+ for (c = 0; c < CHANNELS_PER_STREAM; c++) {
+ for (n = 0; n < BYTES_PER_SAMPLE; n++) {
+ if (audio_buf) {
+ usb_buf[i+n] = audio_buf[dev->audio_out_buf_pos[stream]++];
+
+ if (dev->audio_out_buf_pos[stream] == sz)
+ dev->audio_out_buf_pos[stream] = 0;
+ } else {
+ usb_buf[i+n] = 0;
+ }
+ }
+
+ if (audio_buf)
+ dev->period_out_count[stream] += BYTES_PER_SAMPLE;
+
+ i += BYTES_PER_SAMPLE;
+
+ /* fill in the check byte pattern */
+ usb_buf[i++] = (stream << 1) | c;
+ }
+ }
+ }
+}
+
+static inline void fill_out_urb(struct snd_usb_caiaqdev *dev,
+ struct urb *urb,
+ const struct usb_iso_packet_descriptor *iso)
+{
+ switch (dev->spec.data_alignment) {
+ case 0:
+ case 2:
+ fill_out_urb_mode_0(dev, urb, iso);
+ break;
+ case 3:
+ fill_out_urb_mode_3(dev, urb, iso);
+ break;
}
}
diff --git a/sound/usb/caiaq/control.c b/sound/usb/caiaq/control.c
index 91c804c..00e5d0a 100644
--- a/sound/usb/caiaq/control.c
+++ b/sound/usb/caiaq/control.c
@@ -55,6 +55,10 @@
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
maxval = 127;
break;
+
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
+ maxval = 31;
+ break;
}
if (is_intval) {
@@ -93,6 +97,7 @@
struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol);
struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
int pos = kcontrol->private_value;
+ int v = ucontrol->value.integer.value[0];
unsigned char cmd = EP1_CMD_WRITE_IO;
if (dev->chip.usb_id ==
@@ -100,12 +105,27 @@
cmd = EP1_CMD_DIMM_LEDS;
if (pos & CNT_INTVAL) {
- dev->control_state[pos & ~CNT_INTVAL]
- = ucontrol->value.integer.value[0];
- snd_usb_caiaq_send_command(dev, cmd,
- dev->control_state, sizeof(dev->control_state));
+ int i = pos & ~CNT_INTVAL;
+
+ dev->control_state[i] = v;
+
+ if (dev->chip.usb_id ==
+ USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4)) {
+ int actual_len;
+
+ dev->ep8_out_buf[0] = i;
+ dev->ep8_out_buf[1] = v;
+
+ usb_bulk_msg(dev->chip.dev,
+ usb_sndbulkpipe(dev->chip.dev, 8),
+ dev->ep8_out_buf, sizeof(dev->ep8_out_buf),
+ &actual_len, 200);
+ } else {
+ snd_usb_caiaq_send_command(dev, cmd,
+ dev->control_state, sizeof(dev->control_state));
+ }
} else {
- if (ucontrol->value.integer.value[0])
+ if (v)
dev->control_state[pos / 8] |= 1 << (pos % 8);
else
dev->control_state[pos / 8] &= ~(1 << (pos % 8));
@@ -296,6 +316,179 @@
{ "LED Deck B: SYNC", 8 | CNT_INTVAL },
};
+static struct caiaq_controller kontrols4_controller[] = {
+ { "LED: Master: Quant", 10 | CNT_INTVAL },
+ { "LED: Master: Headphone", 11 | CNT_INTVAL },
+ { "LED: Master: Master", 12 | CNT_INTVAL },
+ { "LED: Master: Snap", 14 | CNT_INTVAL },
+ { "LED: Master: Warning", 15 | CNT_INTVAL },
+ { "LED: Master: Master button", 112 | CNT_INTVAL },
+ { "LED: Master: Snap button", 113 | CNT_INTVAL },
+ { "LED: Master: Rec", 118 | CNT_INTVAL },
+ { "LED: Master: Size", 119 | CNT_INTVAL },
+ { "LED: Master: Quant button", 120 | CNT_INTVAL },
+ { "LED: Master: Browser button", 121 | CNT_INTVAL },
+ { "LED: Master: Play button", 126 | CNT_INTVAL },
+ { "LED: Master: Undo button", 127 | CNT_INTVAL },
+
+ { "LED: Channel A: >", 4 | CNT_INTVAL },
+ { "LED: Channel A: <", 5 | CNT_INTVAL },
+ { "LED: Channel A: Meter 1", 97 | CNT_INTVAL },
+ { "LED: Channel A: Meter 2", 98 | CNT_INTVAL },
+ { "LED: Channel A: Meter 3", 99 | CNT_INTVAL },
+ { "LED: Channel A: Meter 4", 100 | CNT_INTVAL },
+ { "LED: Channel A: Meter 5", 101 | CNT_INTVAL },
+ { "LED: Channel A: Meter 6", 102 | CNT_INTVAL },
+ { "LED: Channel A: Meter clip", 103 | CNT_INTVAL },
+ { "LED: Channel A: Active", 114 | CNT_INTVAL },
+ { "LED: Channel A: Cue", 116 | CNT_INTVAL },
+ { "LED: Channel A: FX1", 149 | CNT_INTVAL },
+ { "LED: Channel A: FX2", 148 | CNT_INTVAL },
+
+ { "LED: Channel B: >", 2 | CNT_INTVAL },
+ { "LED: Channel B: <", 3 | CNT_INTVAL },
+ { "LED: Channel B: Meter 1", 89 | CNT_INTVAL },
+ { "LED: Channel B: Meter 2", 90 | CNT_INTVAL },
+ { "LED: Channel B: Meter 3", 91 | CNT_INTVAL },
+ { "LED: Channel B: Meter 4", 92 | CNT_INTVAL },
+ { "LED: Channel B: Meter 5", 93 | CNT_INTVAL },
+ { "LED: Channel B: Meter 6", 94 | CNT_INTVAL },
+ { "LED: Channel B: Meter clip", 95 | CNT_INTVAL },
+ { "LED: Channel B: Active", 122 | CNT_INTVAL },
+ { "LED: Channel B: Cue", 125 | CNT_INTVAL },
+ { "LED: Channel B: FX1", 147 | CNT_INTVAL },
+ { "LED: Channel B: FX2", 146 | CNT_INTVAL },
+
+ { "LED: Channel C: >", 6 | CNT_INTVAL },
+ { "LED: Channel C: <", 7 | CNT_INTVAL },
+ { "LED: Channel C: Meter 1", 105 | CNT_INTVAL },
+ { "LED: Channel C: Meter 2", 106 | CNT_INTVAL },
+ { "LED: Channel C: Meter 3", 107 | CNT_INTVAL },
+ { "LED: Channel C: Meter 4", 108 | CNT_INTVAL },
+ { "LED: Channel C: Meter 5", 109 | CNT_INTVAL },
+ { "LED: Channel C: Meter 6", 110 | CNT_INTVAL },
+ { "LED: Channel C: Meter clip", 111 | CNT_INTVAL },
+ { "LED: Channel C: Active", 115 | CNT_INTVAL },
+ { "LED: Channel C: Cue", 117 | CNT_INTVAL },
+ { "LED: Channel C: FX1", 151 | CNT_INTVAL },
+ { "LED: Channel C: FX2", 150 | CNT_INTVAL },
+
+ { "LED: Channel D: >", 0 | CNT_INTVAL },
+ { "LED: Channel D: <", 1 | CNT_INTVAL },
+ { "LED: Channel D: Meter 1", 81 | CNT_INTVAL },
+ { "LED: Channel D: Meter 2", 82 | CNT_INTVAL },
+ { "LED: Channel D: Meter 3", 83 | CNT_INTVAL },
+ { "LED: Channel D: Meter 4", 84 | CNT_INTVAL },
+ { "LED: Channel D: Meter 5", 85 | CNT_INTVAL },
+ { "LED: Channel D: Meter 6", 86 | CNT_INTVAL },
+ { "LED: Channel D: Meter clip", 87 | CNT_INTVAL },
+ { "LED: Channel D: Active", 123 | CNT_INTVAL },
+ { "LED: Channel D: Cue", 124 | CNT_INTVAL },
+ { "LED: Channel D: FX1", 145 | CNT_INTVAL },
+ { "LED: Channel D: FX2", 144 | CNT_INTVAL },
+
+ { "LED: Deck A: 1 (blue)", 22 | CNT_INTVAL },
+ { "LED: Deck A: 1 (green)", 23 | CNT_INTVAL },
+ { "LED: Deck A: 2 (blue)", 20 | CNT_INTVAL },
+ { "LED: Deck A: 2 (green)", 21 | CNT_INTVAL },
+ { "LED: Deck A: 3 (blue)", 18 | CNT_INTVAL },
+ { "LED: Deck A: 3 (green)", 19 | CNT_INTVAL },
+ { "LED: Deck A: 4 (blue)", 16 | CNT_INTVAL },
+ { "LED: Deck A: 4 (green)", 17 | CNT_INTVAL },
+ { "LED: Deck A: Load", 44 | CNT_INTVAL },
+ { "LED: Deck A: Deck C button", 45 | CNT_INTVAL },
+ { "LED: Deck A: In", 47 | CNT_INTVAL },
+ { "LED: Deck A: Out", 46 | CNT_INTVAL },
+ { "LED: Deck A: Shift", 24 | CNT_INTVAL },
+ { "LED: Deck A: Sync", 27 | CNT_INTVAL },
+ { "LED: Deck A: Cue", 26 | CNT_INTVAL },
+ { "LED: Deck A: Play", 25 | CNT_INTVAL },
+ { "LED: Deck A: Tempo up", 33 | CNT_INTVAL },
+ { "LED: Deck A: Tempo down", 32 | CNT_INTVAL },
+ { "LED: Deck A: Master", 34 | CNT_INTVAL },
+ { "LED: Deck A: Keylock", 35 | CNT_INTVAL },
+ { "LED: Deck A: Deck A", 37 | CNT_INTVAL },
+ { "LED: Deck A: Deck C", 36 | CNT_INTVAL },
+ { "LED: Deck A: Samples", 38 | CNT_INTVAL },
+ { "LED: Deck A: On Air", 39 | CNT_INTVAL },
+ { "LED: Deck A: Sample 1", 31 | CNT_INTVAL },
+ { "LED: Deck A: Sample 2", 30 | CNT_INTVAL },
+ { "LED: Deck A: Sample 3", 29 | CNT_INTVAL },
+ { "LED: Deck A: Sample 4", 28 | CNT_INTVAL },
+ { "LED: Deck A: Digit 1 - A", 55 | CNT_INTVAL },
+ { "LED: Deck A: Digit 1 - B", 54 | CNT_INTVAL },
+ { "LED: Deck A: Digit 1 - C", 53 | CNT_INTVAL },
+ { "LED: Deck A: Digit 1 - D", 52 | CNT_INTVAL },
+ { "LED: Deck A: Digit 1 - E", 51 | CNT_INTVAL },
+ { "LED: Deck A: Digit 1 - F", 50 | CNT_INTVAL },
+ { "LED: Deck A: Digit 1 - G", 49 | CNT_INTVAL },
+ { "LED: Deck A: Digit 1 - dot", 48 | CNT_INTVAL },
+ { "LED: Deck A: Digit 2 - A", 63 | CNT_INTVAL },
+ { "LED: Deck A: Digit 2 - B", 62 | CNT_INTVAL },
+ { "LED: Deck A: Digit 2 - C", 61 | CNT_INTVAL },
+ { "LED: Deck A: Digit 2 - D", 60 | CNT_INTVAL },
+ { "LED: Deck A: Digit 2 - E", 59 | CNT_INTVAL },
+ { "LED: Deck A: Digit 2 - F", 58 | CNT_INTVAL },
+ { "LED: Deck A: Digit 2 - G", 57 | CNT_INTVAL },
+ { "LED: Deck A: Digit 2 - dot", 56 | CNT_INTVAL },
+
+ { "LED: Deck B: 1 (blue)", 78 | CNT_INTVAL },
+ { "LED: Deck B: 1 (green)", 79 | CNT_INTVAL },
+ { "LED: Deck B: 2 (blue)", 76 | CNT_INTVAL },
+ { "LED: Deck B: 2 (green)", 77 | CNT_INTVAL },
+ { "LED: Deck B: 3 (blue)", 74 | CNT_INTVAL },
+ { "LED: Deck B: 3 (green)", 75 | CNT_INTVAL },
+ { "LED: Deck B: 4 (blue)", 72 | CNT_INTVAL },
+ { "LED: Deck B: 4 (green)", 73 | CNT_INTVAL },
+ { "LED: Deck B: Load", 180 | CNT_INTVAL },
+ { "LED: Deck B: Deck D button", 181 | CNT_INTVAL },
+ { "LED: Deck B: In", 183 | CNT_INTVAL },
+ { "LED: Deck B: Out", 182 | CNT_INTVAL },
+ { "LED: Deck B: Shift", 64 | CNT_INTVAL },
+ { "LED: Deck B: Sync", 67 | CNT_INTVAL },
+ { "LED: Deck B: Cue", 66 | CNT_INTVAL },
+ { "LED: Deck B: Play", 65 | CNT_INTVAL },
+ { "LED: Deck B: Tempo up", 185 | CNT_INTVAL },
+ { "LED: Deck B: Tempo down", 184 | CNT_INTVAL },
+ { "LED: Deck B: Master", 186 | CNT_INTVAL },
+ { "LED: Deck B: Keylock", 187 | CNT_INTVAL },
+ { "LED: Deck B: Deck B", 189 | CNT_INTVAL },
+ { "LED: Deck B: Deck D", 188 | CNT_INTVAL },
+ { "LED: Deck B: Samples", 190 | CNT_INTVAL },
+ { "LED: Deck B: On Air", 191 | CNT_INTVAL },
+ { "LED: Deck B: Sample 1", 71 | CNT_INTVAL },
+ { "LED: Deck B: Sample 2", 70 | CNT_INTVAL },
+ { "LED: Deck B: Sample 3", 69 | CNT_INTVAL },
+ { "LED: Deck B: Sample 4", 68 | CNT_INTVAL },
+ { "LED: Deck B: Digit 1 - A", 175 | CNT_INTVAL },
+ { "LED: Deck B: Digit 1 - B", 174 | CNT_INTVAL },
+ { "LED: Deck B: Digit 1 - C", 173 | CNT_INTVAL },
+ { "LED: Deck B: Digit 1 - D", 172 | CNT_INTVAL },
+ { "LED: Deck B: Digit 1 - E", 171 | CNT_INTVAL },
+ { "LED: Deck B: Digit 1 - F", 170 | CNT_INTVAL },
+ { "LED: Deck B: Digit 1 - G", 169 | CNT_INTVAL },
+ { "LED: Deck B: Digit 1 - dot", 168 | CNT_INTVAL },
+ { "LED: Deck B: Digit 2 - A", 167 | CNT_INTVAL },
+ { "LED: Deck B: Digit 2 - B", 166 | CNT_INTVAL },
+ { "LED: Deck B: Digit 2 - C", 165 | CNT_INTVAL },
+ { "LED: Deck B: Digit 2 - D", 164 | CNT_INTVAL },
+ { "LED: Deck B: Digit 2 - E", 163 | CNT_INTVAL },
+ { "LED: Deck B: Digit 2 - F", 162 | CNT_INTVAL },
+ { "LED: Deck B: Digit 2 - G", 161 | CNT_INTVAL },
+ { "LED: Deck B: Digit 2 - dot", 160 | CNT_INTVAL },
+
+ { "LED: FX1: dry/wet", 153 | CNT_INTVAL },
+ { "LED: FX1: 1", 154 | CNT_INTVAL },
+ { "LED: FX1: 2", 155 | CNT_INTVAL },
+ { "LED: FX1: 3", 156 | CNT_INTVAL },
+ { "LED: FX1: Mode", 157 | CNT_INTVAL },
+ { "LED: FX2: dry/wet", 129 | CNT_INTVAL },
+ { "LED: FX2: 1", 130 | CNT_INTVAL },
+ { "LED: FX2: 2", 131 | CNT_INTVAL },
+ { "LED: FX2: 3", 132 | CNT_INTVAL },
+ { "LED: FX2: Mode", 133 | CNT_INTVAL },
+};
+
static int __devinit add_controls(struct caiaq_controller *c, int num,
struct snd_usb_caiaqdev *dev)
{
@@ -354,6 +547,11 @@
ret = add_controls(kontrolx1_controller,
ARRAY_SIZE(kontrolx1_controller), dev);
break;
+
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
+ ret = add_controls(kontrols4_controller,
+ ARRAY_SIZE(kontrols4_controller), dev);
+ break;
}
return ret;
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
index cdfb856..6480c32 100644
--- a/sound/usb/caiaq/device.c
+++ b/sound/usb/caiaq/device.c
@@ -36,7 +36,7 @@
#include "input.h"
MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
-MODULE_DESCRIPTION("caiaq USB audio, version 1.3.21");
+MODULE_DESCRIPTION("caiaq USB audio");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
"{Native Instruments, RigKontrol3},"
@@ -48,7 +48,8 @@
"{Native Instruments, Audio 8 DJ},"
"{Native Instruments, Session I/O},"
"{Native Instruments, GuitarRig mobile}"
- "{Native Instruments, Traktor Kontrol X1}");
+ "{Native Instruments, Traktor Kontrol X1}"
+ "{Native Instruments, Traktor Kontrol S4}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
@@ -134,6 +135,11 @@
.idVendor = USB_VID_NATIVEINSTRUMENTS,
.idProduct = USB_PID_TRAKTORKONTROLX1
},
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+ .idVendor = USB_VID_NATIVEINSTRUMENTS,
+ .idProduct = USB_PID_TRAKTORKONTROLS4
+ },
{ /* terminator */ }
};
diff --git a/sound/usb/caiaq/device.h b/sound/usb/caiaq/device.h
index f1117ec..e3d8a3e 100644
--- a/sound/usb/caiaq/device.h
+++ b/sound/usb/caiaq/device.h
@@ -16,6 +16,7 @@
#define USB_PID_SESSIONIO 0x1915
#define USB_PID_GUITARRIGMOBILE 0x0d8d
#define USB_PID_TRAKTORKONTROLX1 0x2305
+#define USB_PID_TRAKTORKONTROLS4 0xbaff
#define EP1_BUFSIZE 64
#define EP4_BUFSIZE 512
@@ -99,13 +100,14 @@
struct snd_pcm_substream *sub_capture[MAX_STREAMS];
/* Controls */
- unsigned char control_state[64];
+ unsigned char control_state[256];
+ unsigned char ep8_out_buf[2];
/* Linux input */
#ifdef CONFIG_SND_USB_CAIAQ_INPUT
struct input_dev *input_dev;
char phys[64]; /* physical device path */
- unsigned short keycode[64];
+ unsigned short keycode[128];
struct urb *ep4_in_urb;
unsigned char ep4_in_buf[EP4_BUFSIZE];
#endif
diff --git a/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c
index dcb6207..4432ef7 100644
--- a/sound/usb/caiaq/input.c
+++ b/sound/usb/caiaq/input.c
@@ -67,7 +67,12 @@
KEY_BRL_DOT5
};
-#define KONTROLX1_INPUTS 40
+#define KONTROLX1_INPUTS (40)
+#define KONTROLS4_BUTTONS (12 * 8)
+#define KONTROLS4_AXIS (46)
+
+#define KONTROLS4_BUTTON(X) ((X) + BTN_MISC)
+#define KONTROLS4_ABS(X) ((X) + ABS_HAT0X)
#define DEG90 (range / 2)
#define DEG180 (range)
@@ -139,6 +144,13 @@
#undef HIGH_PEAK
#undef LOW_PEAK
+static inline void snd_caiaq_input_report_abs(struct snd_usb_caiaqdev *dev,
+ int axis, const unsigned char *buf,
+ int offset)
+{
+ input_report_abs(dev->input_dev, axis,
+ (buf[offset * 2] << 8) | buf[offset * 2 + 1]);
+}
static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev,
const unsigned char *buf,
@@ -148,36 +160,30 @@
switch (dev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):
- input_report_abs(input_dev, ABS_X, (buf[4] << 8) | buf[5]);
- input_report_abs(input_dev, ABS_Y, (buf[0] << 8) | buf[1]);
- input_report_abs(input_dev, ABS_Z, (buf[2] << 8) | buf[3]);
- input_sync(input_dev);
+ snd_caiaq_input_report_abs(dev, ABS_X, buf, 2);
+ snd_caiaq_input_report_abs(dev, ABS_Y, buf, 0);
+ snd_caiaq_input_report_abs(dev, ABS_Z, buf, 1);
break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
- input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]);
- input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]);
- input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]);
- input_sync(input_dev);
- break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
- input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]);
- input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]);
- input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]);
- input_sync(input_dev);
+ snd_caiaq_input_report_abs(dev, ABS_X, buf, 0);
+ snd_caiaq_input_report_abs(dev, ABS_Y, buf, 1);
+ snd_caiaq_input_report_abs(dev, ABS_Z, buf, 2);
break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
- input_report_abs(input_dev, ABS_HAT0X, (buf[8] << 8) | buf[9]);
- input_report_abs(input_dev, ABS_HAT0Y, (buf[4] << 8) | buf[5]);
- input_report_abs(input_dev, ABS_HAT1X, (buf[12] << 8) | buf[13]);
- input_report_abs(input_dev, ABS_HAT1Y, (buf[2] << 8) | buf[3]);
- input_report_abs(input_dev, ABS_HAT2X, (buf[14] << 8) | buf[15]);
- input_report_abs(input_dev, ABS_HAT2Y, (buf[0] << 8) | buf[1]);
- input_report_abs(input_dev, ABS_HAT3X, (buf[10] << 8) | buf[11]);
- input_report_abs(input_dev, ABS_HAT3Y, (buf[6] << 8) | buf[7]);
- input_sync(input_dev);
+ snd_caiaq_input_report_abs(dev, ABS_HAT0X, buf, 4);
+ snd_caiaq_input_report_abs(dev, ABS_HAT0Y, buf, 2);
+ snd_caiaq_input_report_abs(dev, ABS_HAT1X, buf, 6);
+ snd_caiaq_input_report_abs(dev, ABS_HAT1Y, buf, 1);
+ snd_caiaq_input_report_abs(dev, ABS_HAT2X, buf, 7);
+ snd_caiaq_input_report_abs(dev, ABS_HAT2Y, buf, 0);
+ snd_caiaq_input_report_abs(dev, ABS_HAT3X, buf, 5);
+ snd_caiaq_input_report_abs(dev, ABS_HAT3Y, buf, 3);
break;
}
+
+ input_sync(input_dev);
}
static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev,
@@ -250,6 +256,150 @@
input_sync(input_dev);
}
+#define TKS4_MSGBLOCK_SIZE 16
+
+static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *dev,
+ const unsigned char *buf,
+ unsigned int len)
+{
+ while (len) {
+ unsigned int i, block_id = (buf[0] << 8) | buf[1];
+
+ switch (block_id) {
+ case 0:
+ /* buttons */
+ for (i = 0; i < KONTROLS4_BUTTONS; i++)
+ input_report_key(dev->input_dev, KONTROLS4_BUTTON(i),
+ (buf[4 + (i / 8)] >> (i % 8)) & 1);
+ break;
+
+ case 1:
+ /* left wheel */
+ input_report_abs(dev->input_dev, KONTROLS4_ABS(36), buf[9] | ((buf[8] & 0x3) << 8));
+ /* right wheel */
+ input_report_abs(dev->input_dev, KONTROLS4_ABS(37), buf[13] | ((buf[12] & 0x3) << 8));
+
+ /* rotary encoders */
+ input_report_abs(dev->input_dev, KONTROLS4_ABS(38), buf[3] & 0xf);
+ input_report_abs(dev->input_dev, KONTROLS4_ABS(39), buf[4] >> 4);
+ input_report_abs(dev->input_dev, KONTROLS4_ABS(40), buf[4] & 0xf);
+ input_report_abs(dev->input_dev, KONTROLS4_ABS(41), buf[5] >> 4);
+ input_report_abs(dev->input_dev, KONTROLS4_ABS(42), buf[5] & 0xf);
+ input_report_abs(dev->input_dev, KONTROLS4_ABS(43), buf[6] >> 4);
+ input_report_abs(dev->input_dev, KONTROLS4_ABS(44), buf[6] & 0xf);
+ input_report_abs(dev->input_dev, KONTROLS4_ABS(45), buf[7] >> 4);
+ input_report_abs(dev->input_dev, KONTROLS4_ABS(46), buf[7] & 0xf);
+
+ break;
+ case 2:
+ /* Volume Fader Channel D */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(0), buf, 1);
+ /* Volume Fader Channel B */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(1), buf, 2);
+ /* Volume Fader Channel A */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(2), buf, 3);
+ /* Volume Fader Channel C */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(3), buf, 4);
+ /* Loop Volume */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(4), buf, 6);
+ /* Crossfader */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(7), buf, 7);
+
+ break;
+
+ case 3:
+ /* Tempo Fader R */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(6), buf, 3);
+ /* Tempo Fader L */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(5), buf, 4);
+ /* Mic Volume */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(8), buf, 6);
+ /* Cue Mix */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(9), buf, 7);
+
+ break;
+
+ case 4:
+ /* Wheel distance sensor L */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(10), buf, 1);
+ /* Wheel distance sensor R */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(11), buf, 2);
+ /* Channel D EQ - Filter */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(12), buf, 3);
+ /* Channel D EQ - Low */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(13), buf, 4);
+ /* Channel D EQ - Mid */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(14), buf, 5);
+ /* Channel D EQ - Hi */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(15), buf, 6);
+ /* FX2 - dry/wet */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(16), buf, 7);
+
+ break;
+
+ case 5:
+ /* FX2 - 1 */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(17), buf, 1);
+ /* FX2 - 2 */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(18), buf, 2);
+ /* FX2 - 3 */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(19), buf, 3);
+ /* Channel B EQ - Filter */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(20), buf, 4);
+ /* Channel B EQ - Low */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(21), buf, 5);
+ /* Channel B EQ - Mid */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(22), buf, 6);
+ /* Channel B EQ - Hi */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(23), buf, 7);
+
+ break;
+
+ case 6:
+ /* Channel A EQ - Filter */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(24), buf, 1);
+ /* Channel A EQ - Low */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(25), buf, 2);
+ /* Channel A EQ - Mid */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(26), buf, 3);
+ /* Channel A EQ - Hi */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(27), buf, 4);
+ /* Channel C EQ - Filter */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(28), buf, 5);
+ /* Channel C EQ - Low */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(29), buf, 6);
+ /* Channel C EQ - Mid */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(30), buf, 7);
+
+ break;
+
+ case 7:
+ /* Channel C EQ - Hi */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(31), buf, 1);
+ /* FX1 - wet/dry */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(32), buf, 2);
+ /* FX1 - 1 */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(33), buf, 3);
+ /* FX1 - 2 */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(34), buf, 4);
+ /* FX1 - 3 */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(35), buf, 5);
+
+ break;
+
+ default:
+ debug("%s(): bogus block (id %d)\n",
+ __func__, block_id);
+ return;
+ }
+
+ len -= TKS4_MSGBLOCK_SIZE;
+ buf += TKS4_MSGBLOCK_SIZE;
+ }
+
+ input_sync(dev->input_dev);
+}
+
static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb)
{
struct snd_usb_caiaqdev *dev = urb->context;
@@ -259,11 +409,11 @@
if (urb->status || !dev || urb != dev->ep4_in_urb)
return;
- if (urb->actual_length < 24)
- goto requeue;
-
switch (dev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+ if (urb->actual_length < 24)
+ goto requeue;
+
if (buf[0] & 0x3)
snd_caiaq_input_read_io(dev, buf + 1, 7);
@@ -271,6 +421,10 @@
snd_caiaq_input_read_analog(dev, buf + 8, 16);
break;
+
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
+ snd_usb_caiaq_tks4_dispatch(dev, buf, urb->actual_length);
+ break;
}
requeue:
@@ -289,6 +443,7 @@
switch (dev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
if (usb_submit_urb(dev->ep4_in_urb, GFP_KERNEL) != 0)
return -EIO;
break;
@@ -306,6 +461,7 @@
switch (dev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
usb_kill_urb(dev->ep4_in_urb);
break;
}
@@ -456,6 +612,46 @@
snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
break;
+
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
+ input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ BUILD_BUG_ON(sizeof(dev->keycode) < KONTROLS4_BUTTONS);
+ for (i = 0; i < KONTROLS4_BUTTONS; i++)
+ dev->keycode[i] = KONTROLS4_BUTTON(i);
+ input->keycodemax = KONTROLS4_BUTTONS;
+
+ for (i = 0; i < KONTROLS4_AXIS; i++) {
+ int axis = KONTROLS4_ABS(i);
+ input->absbit[BIT_WORD(axis)] |= BIT_MASK(axis);
+ }
+
+ /* 36 analog potentiometers and faders */
+ for (i = 0; i < 36; i++)
+ input_set_abs_params(input, KONTROLS4_ABS(i), 0, 0xfff, 0, 10);
+
+ /* 2 encoder wheels */
+ input_set_abs_params(input, KONTROLS4_ABS(36), 0, 0x3ff, 0, 1);
+ input_set_abs_params(input, KONTROLS4_ABS(37), 0, 0x3ff, 0, 1);
+
+ /* 9 rotary encoders */
+ for (i = 0; i < 9; i++)
+ input_set_abs_params(input, KONTROLS4_ABS(38+i), 0, 0xf, 0, 1);
+
+ dev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->ep4_in_urb) {
+ ret = -ENOMEM;
+ goto exit_free_idev;
+ }
+
+ usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev,
+ usb_rcvbulkpipe(usb_dev, 0x4),
+ dev->ep4_in_buf, EP4_BUFSIZE,
+ snd_usb_caiaq_ep4_reply_dispatch, dev);
+
+ snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
+
+ break;
+
default:
/* no input methods supported on this device */
goto exit_free_idev;
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 4eabafa..800f7cb 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -300,9 +300,13 @@
*rchip = NULL;
- if (snd_usb_get_speed(dev) != USB_SPEED_LOW &&
- snd_usb_get_speed(dev) != USB_SPEED_FULL &&
- snd_usb_get_speed(dev) != USB_SPEED_HIGH) {
+ switch (snd_usb_get_speed(dev)) {
+ case USB_SPEED_LOW:
+ case USB_SPEED_FULL:
+ case USB_SPEED_HIGH:
+ case USB_SPEED_SUPER:
+ break;
+ default:
snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev));
return -ENXIO;
}
@@ -378,11 +382,22 @@
if (len < sizeof(card->longname))
usb_make_path(dev, card->longname + len, sizeof(card->longname) - len);
- strlcat(card->longname,
- snd_usb_get_speed(dev) == USB_SPEED_LOW ? ", low speed" :
- snd_usb_get_speed(dev) == USB_SPEED_FULL ? ", full speed" :
- ", high speed",
- sizeof(card->longname));
+ switch (snd_usb_get_speed(dev)) {
+ case USB_SPEED_LOW:
+ strlcat(card->longname, ", low speed", sizeof(card->longname));
+ break;
+ case USB_SPEED_FULL:
+ strlcat(card->longname, ", full speed", sizeof(card->longname));
+ break;
+ case USB_SPEED_HIGH:
+ strlcat(card->longname, ", high speed", sizeof(card->longname));
+ break;
+ case USB_SPEED_SUPER:
+ strlcat(card->longname, ", super speed", sizeof(card->longname));
+ break;
+ default:
+ break;
+ }
snd_usb_audio_create_proc(chip);
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index ef0a07e..b0ef9f5 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -405,8 +405,6 @@
break;
case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */
case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
- case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra 8 */
- case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */
/* doesn't set the sample rate attribute, but supports it */
fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE;
break;
diff --git a/sound/usb/helper.c b/sound/usb/helper.c
index d48d6f8..f280c19 100644
--- a/sound/usb/helper.c
+++ b/sound/usb/helper.c
@@ -103,11 +103,16 @@
unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip,
struct usb_host_interface *alts)
{
- if (snd_usb_get_speed(chip->dev) == USB_SPEED_HIGH &&
- get_endpoint(alts, 0)->bInterval >= 1 &&
- get_endpoint(alts, 0)->bInterval <= 4)
- return get_endpoint(alts, 0)->bInterval - 1;
- else
- return 0;
+ switch (snd_usb_get_speed(chip->dev)) {
+ case USB_SPEED_HIGH:
+ case USB_SPEED_SUPER:
+ if (get_endpoint(alts, 0)->bInterval >= 1 &&
+ get_endpoint(alts, 0)->bInterval <= 4)
+ return get_endpoint(alts, 0)->bInterval - 1;
+ break;
+ default:
+ break;
+ }
+ return 0;
}
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index b9c2bc6..25bce7e 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -784,7 +784,7 @@
};
/*
- * "raw" protocol: used by the MOTU FastLane.
+ * "raw" protocol: just move raw MIDI bytes from/to the endpoint
*/
static void snd_usbmidi_raw_input(struct snd_usb_midi_in_endpoint* ep,
@@ -834,7 +834,14 @@
if (!ep->ports[0].active)
return;
- count = snd_usb_get_speed(ep->umidi->dev) == USB_SPEED_HIGH ? 1 : 2;
+ switch (snd_usb_get_speed(ep->umidi->dev)) {
+ case USB_SPEED_HIGH:
+ case USB_SPEED_SUPER:
+ count = 1;
+ break;
+ default:
+ count = 2;
+ }
count = snd_rawmidi_transmit(ep->ports[0].substream,
urb->transfer_buffer,
count);
@@ -2115,7 +2122,7 @@
umidi->usb_protocol_ops = &snd_usbmidi_novation_ops;
err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
break;
- case QUIRK_MIDI_FASTLANE:
+ case QUIRK_MIDI_RAW_BYTES:
umidi->usb_protocol_ops = &snd_usbmidi_raw_ops;
/*
* Interface 1 contains isochronous endpoints, but with the same
@@ -2126,7 +2133,8 @@
* interface 0, so we have to make sure that the USB core looks
* again at interface 0 by calling usb_set_interface() on it.
*/
- usb_set_interface(umidi->dev, 0, 0);
+ if (umidi->usb_id == USB_ID(0x07fd, 0x0001)) /* MOTU Fastlane */
+ usb_set_interface(umidi->dev, 0, 0);
err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
break;
case QUIRK_MIDI_EMAGIC:
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 3ed3901..f2d74d6 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -759,8 +759,6 @@
*/
static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
{
- struct snd_usb_audio *chip = cval->mixer->chip;
-
/* for failsafe */
cval->min = default_min;
cval->max = cval->min + 1;
@@ -783,7 +781,7 @@
if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 ||
get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) {
snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n",
- cval->id, snd_usb_ctrl_intf(chip), cval->control, cval->id);
+ cval->id, snd_usb_ctrl_intf(cval->mixer->chip), cval->control, cval->id);
return -EINVAL;
}
if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) {
@@ -1642,9 +1640,10 @@
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
uinfo->value.enumerated.items = cval->max;
- if ((int)uinfo->value.enumerated.item >= cval->max)
+ if (uinfo->value.enumerated.item >= cval->max)
uinfo->value.enumerated.item = cval->max - 1;
- strcpy(uinfo->value.enumerated.name, itemlist[uinfo->value.enumerated.item]);
+ strlcpy(uinfo->value.enumerated.name, itemlist[uinfo->value.enumerated.item],
+ sizeof(uinfo->value.enumerated.name));
return 0;
}
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index e7df1e5..7dae05d 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -60,6 +60,7 @@
{ USB_ID(0x041e, 0x3000), 0, 1, 2, 1, 18, 0x0013 }, /* Extigy */
{ USB_ID(0x041e, 0x3020), 2, 1, 6, 6, 18, 0x0013 }, /* Audigy 2 NX */
{ USB_ID(0x041e, 0x3040), 2, 2, 6, 6, 2, 0x6e91 }, /* Live! 24-bit */
+ { USB_ID(0x041e, 0x3042), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi */
{ USB_ID(0x041e, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */
};
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 3b5135c..f49756c 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -466,7 +466,7 @@
return 0;
}
/* check whether the period time is >= the data packet interval */
- if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) {
+ if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) {
ptime = 125 * (1 << fp->datainterval);
if (ptime > pt->max || (ptime == pt->max && pt->openmax)) {
hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max);
@@ -734,7 +734,7 @@
}
param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME;
- if (snd_usb_get_speed(subs->dev) != USB_SPEED_HIGH)
+ if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
/* full speed devices have fixed data packet interval */
ptmin = 1000;
if (ptmin == 1000)
diff --git a/sound/usb/proc.c b/sound/usb/proc.c
index f5e3f35..3c650ab 100644
--- a/sound/usb/proc.c
+++ b/sound/usb/proc.c
@@ -107,7 +107,7 @@
}
snd_iprintf(buffer, "\n");
}
- if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH)
+ if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL)
snd_iprintf(buffer, " Data packet interval: %d us\n",
125 * (1 << fp->datainterval));
// snd_iprintf(buffer, " Max Packet Size = %d\n", fp->maxpacksize);
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 2e8003f..ad7079d 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -240,9 +240,21 @@
YAMAHA_DEVICE(0x1050, NULL),
YAMAHA_DEVICE(0x1051, NULL),
YAMAHA_DEVICE(0x1052, NULL),
+YAMAHA_INTERFACE(0x1053, 0, NULL),
+YAMAHA_INTERFACE(0x1054, 0, NULL),
+YAMAHA_DEVICE(0x1055, NULL),
+YAMAHA_DEVICE(0x1056, NULL),
+YAMAHA_DEVICE(0x1057, NULL),
+YAMAHA_DEVICE(0x1058, NULL),
+YAMAHA_DEVICE(0x1059, NULL),
+YAMAHA_DEVICE(0x105a, NULL),
+YAMAHA_DEVICE(0x105b, NULL),
+YAMAHA_DEVICE(0x105c, NULL),
+YAMAHA_DEVICE(0x105d, NULL),
YAMAHA_DEVICE(0x2000, "DGP-7"),
YAMAHA_DEVICE(0x2001, "DGP-5"),
YAMAHA_DEVICE(0x2002, NULL),
+YAMAHA_DEVICE(0x2003, NULL),
YAMAHA_DEVICE(0x5000, "CS1D"),
YAMAHA_DEVICE(0x5001, "DSP1D"),
YAMAHA_DEVICE(0x5002, "DME32"),
@@ -1136,11 +1148,34 @@
}
},
{
+ /* has ID 0x0066 when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x0064),
+ .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+ /* .vendor_name = "EDIROL", */
+ /* .product_name = "PCR-1", */
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = (const struct snd_usb_audio_quirk[]) {
+ {
+ .ifnum = 1,
+ .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ },
+ {
+ .ifnum = 2,
+ .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ },
+ {
+ .ifnum = -1
+ }
+ }
+ }
+},
+{
/* has ID 0x0067 when not in "Advanced Driver" mode */
USB_DEVICE(0x0582, 0x0065),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- .vendor_name = "EDIROL",
- .product_name = "PCR-1",
+ /* .vendor_name = "EDIROL", */
+ /* .product_name = "PCR-1", */
.ifnum = 0,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const struct snd_usb_midi_endpoint_info) {
@@ -1525,6 +1560,50 @@
}
}
},
+{
+ /* has ID 0x0110 when not in Advanced Driver mode */
+ USB_DEVICE_VENDOR_SPEC(0x0582, 0x010f),
+ .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+ /* .vendor_name = "Roland", */
+ /* .product_name = "A-PRO", */
+ .ifnum = 1,
+ .type = QUIRK_MIDI_FIXED_ENDPOINT,
+ .data = & (const struct snd_usb_midi_endpoint_info) {
+ .out_cables = 0x0003,
+ .in_cables = 0x0007
+ }
+ }
+},
+{
+ USB_DEVICE(0x0582, 0x0113),
+ .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+ /* .vendor_name = "BOSS", */
+ /* .product_name = "ME-25", */
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = (const struct snd_usb_audio_quirk[]) {
+ {
+ .ifnum = 0,
+ .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ },
+ {
+ .ifnum = 2,
+ .type = QUIRK_MIDI_FIXED_ENDPOINT,
+ .data = & (const struct snd_usb_midi_endpoint_info) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+ },
+ {
+ .ifnum = -1
+ }
+ }
+ }
+},
/* Guillemot devices */
{
@@ -1830,7 +1909,7 @@
USB_DEVICE(0x0763, 0x2080),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
/* .vendor_name = "M-Audio", */
- /* .product_name = "Fast Track Ultra 8", */
+ /* .product_name = "Fast Track Ultra", */
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_COMPOSITE,
.data = & (const struct snd_usb_audio_quirk[]) {
@@ -1840,11 +1919,51 @@
},
{
.ifnum = 1,
- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = & (const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8,
+ .iface = 1,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+ .endpoint = 0x01,
+ .ep_attr = 0x09,
+ .rates = SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000,
+ .rate_min = 44100,
+ .rate_max = 96000,
+ .nr_rates = 4,
+ .rate_table = (unsigned int[]) {
+ 44100, 48000, 88200, 96000
+ }
+ }
},
{
.ifnum = 2,
- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = & (const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8,
+ .iface = 2,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+ .endpoint = 0x81,
+ .ep_attr = 0x05,
+ .rates = SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000,
+ .rate_min = 44100,
+ .rate_max = 96000,
+ .nr_rates = 4,
+ .rate_table = (unsigned int[]) {
+ 44100, 48000, 88200, 96000
+ }
+ }
},
/* interface 3 (MIDI) is standard compliant */
{
@@ -1867,11 +1986,51 @@
},
{
.ifnum = 1,
- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = & (const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8,
+ .iface = 1,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+ .endpoint = 0x01,
+ .ep_attr = 0x09,
+ .rates = SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000,
+ .rate_min = 44100,
+ .rate_max = 96000,
+ .nr_rates = 4,
+ .rate_table = (unsigned int[]) {
+ 44100, 48000, 88200, 96000
+ }
+ }
},
{
.ifnum = 2,
- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = & (const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8,
+ .iface = 2,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+ .endpoint = 0x81,
+ .ep_attr = 0x05,
+ .rates = SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000,
+ .rate_min = 44100,
+ .rate_max = 96000,
+ .nr_rates = 4,
+ .rate_table = (unsigned int[]) {
+ 44100, 48000, 88200, 96000
+ }
+ }
},
/* interface 3 (MIDI) is standard compliant */
{
@@ -1919,7 +2078,7 @@
.data = & (const struct snd_usb_audio_quirk[]) {
{
.ifnum = 0,
- .type = QUIRK_MIDI_FASTLANE
+ .type = QUIRK_MIDI_RAW_BYTES
},
{
.ifnum = 1,
@@ -2068,6 +2227,15 @@
}
},
{
+ USB_DEVICE(0x1235, 0x000e),
+ .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+ /* .vendor_name = "Novation", */
+ /* .product_name = "Launchpad", */
+ .ifnum = 0,
+ .type = QUIRK_MIDI_RAW_BYTES
+ }
+},
+{
USB_DEVICE_VENDOR_SPEC(0x1235, 0x4661),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
.vendor_name = "Novation",
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 9a9da09..cf8bf08 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -287,7 +287,7 @@
[QUIRK_MIDI_YAMAHA] = create_any_midi_quirk,
[QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk,
[QUIRK_MIDI_NOVATION] = create_any_midi_quirk,
- [QUIRK_MIDI_FASTLANE] = create_any_midi_quirk,
+ [QUIRK_MIDI_RAW_BYTES] = create_any_midi_quirk,
[QUIRK_MIDI_EMAGIC] = create_any_midi_quirk,
[QUIRK_MIDI_CME] = create_any_midi_quirk,
[QUIRK_MIDI_AKAI] = create_any_midi_quirk,
diff --git a/sound/usb/urb.c b/sound/usb/urb.c
index de607d4..8deeaad 100644
--- a/sound/usb/urb.c
+++ b/sound/usb/urb.c
@@ -244,7 +244,7 @@
else
subs->curpacksize = maxsize;
- if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH)
+ if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL)
packs_per_ms = 8 >> subs->datainterval;
else
packs_per_ms = 1;
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 24d3319..db3eb21 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -70,7 +70,7 @@
QUIRK_MIDI_YAMAHA,
QUIRK_MIDI_MIDIMAN,
QUIRK_MIDI_NOVATION,
- QUIRK_MIDI_FASTLANE,
+ QUIRK_MIDI_RAW_BYTES,
QUIRK_MIDI_EMAGIC,
QUIRK_MIDI_CME,
QUIRK_MIDI_AKAI,
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c
index 2a528e5..287ef73 100644
--- a/sound/usb/usx2y/usx2yhwdeppcm.c
+++ b/sound/usb/usx2y/usx2yhwdeppcm.c
@@ -36,9 +36,9 @@
plain usx2y alsa mode is able to achieve 64frames, 4periods, but only at the
cost of easier triggered i.e. aeolus xruns (128 or 256frames,
2periods works but is useless cause of crackling).
-
+
This is a first "proof of concept" implementation.
- Later, funcionalities should migrate to more apropriate places:
+ Later, functionalities should migrate to more apropriate places:
Userland:
- The jackd could mmap its float-pcm buffers directly from alsa-lib.
- alsa-lib could provide power of 2 period sized shaping combined with int/float
@@ -54,7 +54,7 @@
#include <linux/gfp.h>
#include "usbusx2yaudio.c"
-#if defined(USX2Y_NRPACKS_VARIABLE) || (!defined(USX2Y_NRPACKS_VARIABLE) && USX2Y_NRPACKS == 1)
+#if defined(USX2Y_NRPACKS_VARIABLE) || USX2Y_NRPACKS == 1
#include <sound/hwdep.h>
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 4f1fa77..1950e19 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -1017,7 +1017,7 @@
# we compile into subdirectories. if the target directory is not the source directory, they might not exists. So
# we depend the various files onto their directories.
DIRECTORY_DEPS = $(LIB_OBJS) $(BUILTIN_OBJS) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h
-$(DIRECTORY_DEPS): $(sort $(dir $(DIRECTORY_DEPS)))
+$(DIRECTORY_DEPS): | $(sort $(dir $(DIRECTORY_DEPS)))
# In the second step, we make a rule to actually create these directories
$(sort $(dir $(DIRECTORY_DEPS))):
$(QUIET_MKDIR)$(MKDIR) -p $@ 2>/dev/null
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index ef7aa0a..95aaf56 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -73,6 +73,18 @@
#define cpu_relax() asm volatile("":::"memory")
#endif
+#ifdef __mips__
+#include "../../arch/mips/include/asm/unistd.h"
+#define rmb() asm volatile( \
+ ".set mips2\n\t" \
+ "sync\n\t" \
+ ".set mips0" \
+ : /* no output */ \
+ : /* no input */ \
+ : "memory")
+#define cpu_relax() asm volatile("" ::: "memory")
+#endif
+
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
index 7ea983a..f7af2fc 100644
--- a/tools/perf/util/trace-event-scripting.c
+++ b/tools/perf/util/trace-event-scripting.c
@@ -97,7 +97,7 @@
register_python_scripting(&python_scripting_unsupported_ops);
}
#else
-struct scripting_ops python_scripting_ops;
+extern struct scripting_ops python_scripting_ops;
void setup_python_scripting(void)
{
@@ -158,7 +158,7 @@
register_perl_scripting(&perl_scripting_unsupported_ops);
}
#else
-struct scripting_ops perl_scripting_ops;
+extern struct scripting_ops perl_scripting_ops;
void setup_perl_scripting(void)
{
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index dafdf67..6866aa4 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -773,7 +773,7 @@
switch (key) {
case 'a':
- if (browser->selection->map == NULL &&
+ if (browser->selection->map == NULL ||
browser->selection->map->dso->annotate_warned)
continue;
goto do_annotate;
diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c
index 66cf65b..c1f1e3c 100644
--- a/virt/kvm/eventfd.c
+++ b/virt/kvm/eventfd.c
@@ -218,7 +218,6 @@
events = file->f_op->poll(file, &irqfd->pt);
list_add_tail(&irqfd->list, &kvm->irqfds.items);
- spin_unlock_irq(&kvm->irqfds.lock);
/*
* Check if there was an event already pending on the eventfd
@@ -227,6 +226,8 @@
if (events & POLLIN)
schedule_work(&irqfd->inject);
+ spin_unlock_irq(&kvm->irqfds.lock);
+
/*
* do not drop the file until the irqfd is fully initialized, otherwise
* we might race against the POLLHUP
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index d4853a5..5186e72 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1970,10 +1970,12 @@
asmlinkage void kvm_handle_fault_on_reboot(void)
{
- if (kvm_rebooting)
+ if (kvm_rebooting) {
/* spin while reset goes on */
+ local_irq_enable();
while (true)
;
+ }
/* Fault while not rebooting. We want the trace. */
BUG();
}